[Logo] Mentawai Forum - Mentawai Web Framework
  [Search] Search   [Recent Topics] Recent Topics   [Members]  Member Listing   [Groups] Back to home page 
[Register] Register / 
[Login] Login 

Forum Read-Only! Check the new site and forum here!

PaginatorFilter  XML
Forum Index -> General Comments Go to Page: 1, 2 Next 
Author Message
Sven



Joined: 20/01/2008 05:53:15
Messages: 24
Offline

Hi everyone,

first of all I must say that I really like the Mentawai framework. It's incredible how fast you receive results with it. This really is rapid development! Also the concept of Actions, Filters and Consequences is very well thought out!

I've written a filter which some others might find useful to: the PaginatorFilter.

The PaginatorFilter can be used to page data, for example search results. It works with arrays and the Collection framework. I know there's a PaginatorTag but the PaginatorFilter is very useful in conjunction with Ajax, when you return XML or JSON data. I use the PaginatorFilter for an Ajax search request along with JSON data.

The PaginatorFilter consists of the PaginatorFilter class itself and a Paginator POJO class, which contains the paged data and some other useful information.

For more details please read the JavaDoc.

PaginatorFilter.java

Code:
package de.sven-jacobs.mentawai;
 
 import java.util.Arrays;
 import java.util.Collection;
 import org.mentawai.core.Action;
 import org.mentawai.core.Filter;
 import org.mentawai.core.Input;
 import org.mentawai.core.InvocationChain;
 import org.mentawai.core.Output;
 
 /**
  * <p>
  *   This filter easily enables paging of data on top of your
  *   current structure. The data which should be paged must be
  *   placed in the output stack with the specified key (see constructor).
  *   Only arrays or <code>Collections</code> can be paged, other data will be
  *   silently ignored.
  * </p>
  * <p>
  *   The data with the specified key will be replaced by an instance of the
  *   <code>Paginator</code> class which contains the paged data and some other
  *   useful information.
  * </p>
  * <p>
  *   Let's say you want paged search results: Add this filter to the
  *   <code>ActionConfig</config> of your search action and don't forget to
  *   pass the page parameter to the query string:
  * </p>
  * <p>
  *   <code>http://example.com/search.mtw?q=keywords&p=0</code>
  * </p>
  *   The page parameter (which can be modified, see constructor) is zero based.
  *   Use the other properties of the <code>Paginator</code> class to obtain
  *   information about the amount of all data, current page, maximum page and
  *   so on. With these information you can create links to the previous and
  *   next pages of your paged data.
  * </p>
  *
  * @author Sven Jacobs <sven.jacobs@web.de>
  * @see Paginator
  * @version 0.1
  */
 public class PaginatorFilter implements Filter {
   public final static String DEFAULT_PAGE_PARAM     = "p";
   public final static int    DEFAULT_ITEMS_PER_PAGE = 20;
 
   private int itemsPerPage;
   private String key;
   private String pageParam;
 
   @Override
   public void destroy() {
   }
 
   /**
    * Instantiate a PaginatorFilter with the specified key
    * pointing to the data in the output stack which should be
    * paged.
    *
    * @param key Key of the data from the output stack to page
    */
   public PaginatorFilter( String key ) {
     this( key, DEFAULT_ITEMS_PER_PAGE, DEFAULT_PAGE_PARAM );
   }
 
   /**
    * Instantiate a PaginatorFilter with the specified key
    * and amount of items per page.
    *
    * @param key Key of the data from the output stack to page
    * @param itemsPerPage Amount of items per page
    */
   public PaginatorFilter( String key, int itemsPerPage ) {
     this( key, itemsPerPage, DEFAULT_PAGE_PARAM );
   }
 
   /**
    * Instantiate a PaginatorFilter with the specified key,
    * amount of items per page and name of the page parameter.
    *
    * @param key Key of the data from the output stack to page
    * @param itemsPerPage Amount of items per page
    * @param pageParam Name of the page parameter
    */
   public PaginatorFilter( String key, int itemsPerPage, String pageParam ) {
     this.key          = key;
     this.itemsPerPage = itemsPerPage;
     this.pageParam    = pageParam;
   }
 
   /**
    * The filter replaces the specified data with an instance of
    * <code>Paginator</code> which contains the paged data and some other
    * useful information.
    *
    * Note: Only arrays and <code>Collections</code> can be paged.
    *
    * @see Paginator
    */
   @Override
   public String filter( InvocationChain chain ) throws Exception {
     Action action = chain.getAction();
 
     String result = chain.invoke();
 
     Output output = action.getOutput();
     Object value = output.getValue( key );
 
     if ( value != null ) {
       Object[] arr;
 
       if ( value.getClass().isArray() ) {
         arr = (Object[])value;
       } else if ( value instanceof Collection ) {
         Collection<?> coll = (Collection<?>)value;
         arr = coll.toArray();
       } else {
         return result;
       }
 
       Input input = action.getInput();
       int page    = input.getIntValue( pageParam );
 
       if ( page < 0 ) { page = 0; }
 
       int startIndex = page * itemsPerPage;
       if ( startIndex >= arr.length ) { startIndex = 0; }
 
       int endIndex = startIndex + itemsPerPage;
       if ( endIndex > arr.length ) { endIndex = arr.length; }
 
       Object[] newArr = Arrays.copyOfRange( arr, startIndex, endIndex ); // endIndex is NOT inclusive!
 
       Paginator p = new Paginator( newArr, startIndex / itemsPerPage,
           arr.length / itemsPerPage, itemsPerPage, arr.length );
 
       output.setValue( key, p );
     }
 
     return result;
   }
 
 }

Paginator.java

Code:
package de.sven-jacobs.mentawai;
 
 /**
  * Paginator POJO which contains paged data and
  * other useful information.
  *
  * The class should only be instantiated and used by the
  * <code>PaginatorFilter</code>!
  *
  * @author Sven Jacobs <sven.jacobs@web.de>
  * @version 0.1
  * @see PaginatorFilter
  */
 public class Paginator {
   private Object[] data;
   private int currentPage;
   private int maxPage;
   private int itemsPerPage;
   private int count;
 
   public Paginator() {
   }
 
   /**
    * Instantiate a Paginator with all required data.
    *
    * @param data Paged data
    * @param currentPage Index of the current page
    * @param maxPage Index of the last page
    * @param itemsPerPage Amount of items per page
    * @param count Amount of all data (all pages)
    */
   public Paginator( Object[] data, int currentPage, int maxPage,
       int itemsPerPage, int count ) {
     this.data         = data;
     this.currentPage  = currentPage;
     this.maxPage      = maxPage;
     this.itemsPerPage = itemsPerPage;
     this.count        = count;
   }
 
   /**
    * Sets the paged data.
    *
    * @param data Paged data
    */
   public void setData( Object[] data ) {
     this.data = data;
   }
 
   /**
    * Returns the paged data.
    *
    * @return Paged data
    */
   public Object[] getData() {
     return data;
   }
 
   /**
    * Set current page index.
    *
    * @param currentPage Current page index
    */
   public void setCurrentPage( int currentPage ) {
     this.currentPage = currentPage;
   }
 
   /**
    * Gets current page index.
    *
    * @return Current page index
    */
   public int getCurrentPage() {
     return currentPage;
   }
 
   /**
    * Sets max page index.
    *
    * @param maxPage Max page index
    */
   public void setMaxPage( int maxPage ) {
     this.maxPage = maxPage;
   }
 
   /**
    * Gets max page index.
    *
    * @return Max page index
    */
   public int getMaxPage() {
     return maxPage;
   }
 
   /**
    * Sets items per page.
    *
    * <p>
    *   This value reflects the <code>itemsPerPage</code> property of
    *   the <code>PaginatorFilter</code> and not the actual amount of items
    *   of the current page.
    * </p>
    *
    * @param itemsPerPage Items per page
    * @see PaginatorFilter
    */
   public void setItemsPerPage( int itemsPerPage ) {
     this.itemsPerPage = itemsPerPage;
   }
 
   /**
    * Gets items per page.
    *
    * <p>
    *   This value reflects the <code>itemsPerPage</code> property of
    *   the <code>PaginatorFilter</code> and not the actual amount of items
    *   of the current page.
    * </p>
    *
    * @return Items per page
    * @see PaginatorFilter
    */
   public int getItemsPerPage() {
     return itemsPerPage;
   }
 
   /**
    * Sets the count (amount of all data over all pages)
    *
    * @param count Amount of all data
    */
   public void setCount( int count ) {
     this.count = count;
   }
 
   /**
    * Gets the count (amount of all data over all pages)
    *
    * @return Amount of all data
    */
   public int getCount() {
     return count;
   }
 }

Feel free to use and modify it or to include it in the Mentawai framework, which I would enjoy

 Filename Paginator.java [Disk] Download
 Description
 Filesize 3 Kbytes
 Downloaded:  411 time(s)

 Filename PaginatorFilter.java [Disk] Download
 Description
 Filesize 4 Kbytes
 Downloaded:  394 time(s)

saoj



Joined: 01/07/2005 09:59:17
Messages: 2846
Location: Rio de Janeiro, RJ
Offline


Hi Sven,

You really seems to have gotten the idea about Mentawai. Your filter is very well though of and implemented. Like you said, i see it helping a lot with pagination through Ajax.

We will take a look and include your filter in the framework. Your name will be there!

I would like to ask you a couple of questions. We we are now trying harder to spread the world about Mentawai in the US and other international markets and your feedback may help!

- How did you hear about Mentawai?

- Do you know about the Mentawai Online Book?

- Do you know about the Mentawai Recipes website?

- How long have you been using Mentawai?

- Do you know other people that uses it?

- What do you think it is the best and the worst (or not so good) about Mentawai?

- How do you compare it with other web frameworks you have used in the past ? (you can be brief here)

Mentawai has acquired a solid reputation in Brazil. We have many people and many companies, some very big, using Mentawai to all sorts of projects. Now we would like to focus more outside Brazil.

Unfortunately, due to time constraints and because most of the Mentawai team speaks only Portuguese, the English documentation fell behind the Portuguese one. We hope to catch up soon, and the online book plus the recipes site are all in english.

Anyways, it was very nice to see this message from you. Let's keep in touch an feel free to ask any questions and to suggest any improvements for Mentawai.

And don't forget to help us spread the word about it!

Thanks,

Sergio Oliveira

Sergio Oliveira

Sven



Joined: 20/01/2008 05:53:15
Messages: 24
Offline

Hi Sergio,

saoj wrote:

Hi Sven,

You really seems to have gotten the idea about Mentawai. Your filter is very well though of and implemented. Like you said, i see it helping a lot with pagination through Ajax.

We will take a look and include your filter in the framework. Your name will be there!
 


Great!

saoj wrote:

I would like to ask you a couple of questions. We we are now trying harder to spread the world about Mentawai in the US and other international markets and your feedback may help!

- How did you hear about Mentawai?
 


A friend of mine pointed me to Mentawai when we were talking about web frameworks for Java.

saoj wrote:

- Do you know about the Mentawai Online Book?
 


No, didn't know about that but I have a suggestions: Wouldn't it be better to use a wiki like MediaWiki for an online documentation/book? A wiki is great for collaborative work and many (software-related) online books have been created using a wiki. Think about it

saoj wrote:

- Do you know about the Mentawai Recipes website?
 


Yes, did look at it. As above I think a wiki would be better suited for recipes than a forum.

saoj wrote:

- How long have you been using Mentawai?
 


Just about two weeks! I've started a new web project and this is the first time I'm using a web framework. Also this is my first real Java based web project.

saoj wrote:

- Do you know other people that uses it?
 


No, not yet.

saoj wrote:

- What do you think it is the best and the worst (or not so good) about Mentawai?
 


Good: As mentioned before I like the concept of Actions, Filters and Consequences which makes the system pretty modular. Also I like that you don't have to manage several (XML based and maybe complicated) configuration files.

Not so good: The english documentation could be improved, but you know that. Maybe a more in depth beginner tutorial? Like to see more real life examples.

saoj wrote:

- How do you compare it with other web frameworks you have used in the past ? (you can be brief here)
 


I've programmed a couple of web based applications (in other languages than Java) but this is the first time I'm really using a framework. Before it was traditional web programming where you code almost all yourself.

Thus I can't compare Mentawai to other frameworks.
saoj



Joined: 01/07/2005 09:59:17
Messages: 2846
Location: Rio de Janeiro, RJ
Offline


Thanks for the valuable feedback, Sven!

And keep in touch!

-Sergio

Sergio Oliveira

robertwgil


[Avatar]
Joined: 23/02/2007 17:22:13
Messages: 745
Location: São Paulo - SP - Brasil
Offline

Hi Sven, I dont know how to write english very well yet, but let go..

I sow your code and like it.. its facility de pagination of objects...

But, after what you do with de Paginator object on JSP?
sorry but i don't understood.. you use other tag, or renderer?

Can you put one example to me? some look like recipes? =)

Welcome...

Robert Gil
Coordenador de Desenvolvimento / Administrador de Redes.

Twitter
[Email] [MSN]
saoj



Joined: 01/07/2005 09:59:17
Messages: 2846
Location: Rio de Janeiro, RJ
Offline

I think all he is doing is returning the Paginator object through AJAX.

Just one curiosity. Why a filter and not an action? Isn't this an ajax request? To what actions are you applying this filter?

Thanks!

-Sergio


Sergio Oliveira

Sven



Joined: 20/01/2008 05:53:15
Messages: 24
Offline

robertwgil wrote:
Hi Sven, I dont know how to write english very well yet, but let go..

I sow your code and like it.. its facility de pagination of objects...

But, after what you do with de Paginator object on JSP?
sorry but i don't understood.. you use other tag, or renderer?

Can you put one example to me? some look like recipes? =) 

Hello Robert,

of course you can use the PaginatorFilter for JSP, too. I haven't done much JSP yet but I try.

Let's say you wrote a search action which fetches some data from a database. The action puts the array of data into the output stack with the key results. In the ApplicationManager you add the PaginatorFilter for this search action:

Code:
 ActionConfig ac = new ActionConfig( "search", SearchAction.class );
 ac.addConsequence( SearchAction.SUCCESS, new Forward("results.jsp") );
 ac.addFilter( new PaginatorFilter( "results" ) );

Instead of your data, after the filter has been processed, you will find a Paginator instance under results in the output stack.

You can use this instance in results.jsp as follows:

Code:
 <div>{$results.count} results, page {$results.currentPage} of {$results.maxPage}</div>
 
 <c:forEach items="{$results.data}" var="current">
   <!-- output your results here -->
 </c:forEach>
 
 <div>
   <a href="search.mtw?q={$querystring}&p={$results.currentPage - 1}">prev</a>
   <a href="search.mtw?q={$querystring}&p={$results.currentPage + 1}">next</a>
 </div>
 

Of course querystring needs to be passed by your search action, too.

saoj wrote:
I think all he is doing is returning the Paginator object through AJAX.
 

Correct! My search action returns an array of data which is converted to the Paginator instance by the Filter. The Paginator instance is then encoded to JSON by the Consequence. Afterwards I use the Paginator properties, similar as above but within JavaScript, to render the results.

saoj wrote:

Just one curiosity. Why a filter and not an action? Isn't this an ajax request? To what actions are you applying this filter?
 


Well I chose a Filter to separate the pagination logic from the "retrieve data" logic. That way my search action just needs to retrieve the data.

Since the search action always retrieves the whole data which then is being "cropped" by the PaginatorFilter, this may be a performance issue. A solution would be to implement some kind of caching logic in the search action (or maybe in the PaginatorFilter??).
 
robertwgil


[Avatar]
Joined: 23/02/2007 17:22:13
Messages: 745
Location: São Paulo - SP - Brasil
Offline

Great.... now I understood... Good idea.. congratulations...

What renderer are you using?

You already use it with MentaAjax?

I have a idea now... after when I have time, I"ll do one paginator using
MentaAjax with your filter... =)


Robert Gil
Coordenador de Desenvolvimento / Administrador de Redes.

Twitter
[Email] [MSN]
Sven



Joined: 20/01/2008 05:53:15
Messages: 24
Offline

robertwgil wrote:
Great.... now I understood... Good idea.. congratulations...

What renderer are you using?

You already use it with MentaAjax?

I have a idea now... after when I have time, I"ll do one paginator using
MentaAjax with your filter... =)

 


I've written my own JSONAjaxRenderer which utilizes the JSON Tools library.

For the client side Ajax stuff I'm using the great Prototype JavaScript framework, because of personal preferences
saoj



Joined: 01/07/2005 09:59:17
Messages: 2846
Location: Rio de Janeiro, RJ
Offline

Sven wrote:

Well I chose a Filter to separate the pagination logic from the "retrieve data" logic. That way my search action just needs to retrieve the data.
 


Yeah, makes total sense. I noticed now that your filter is taking action AFTER the action has being executed. So your idea is very simple and powerful: load any list with any data and the filter will paginate it for your. Cool!


Since the search action always retrieves the whole data which then is being "cropped" by the PaginatorFilter, this may be a performance issue. A solution would be to implement some kind of caching logic in the search action (or maybe in the PaginatorFilter??).
 


There is no much escape from this. I once had a very fat User object, so I created a small version of my User object just for the pagination (UserHeader). So I would load a list of UserHeaders instead of Users.

Not sure (I did not think much about it yet) if you want to place a cache logic inside the paginator filter. They look separate matters to me but I may be missing something.


I've written my own JSONAjaxRenderer which utilizes the JSON Tools library.
 


Mentawai comes out-of-the-box with a JSONGenericRenderer that you may want to use. Your can always implement your own renderers, no problem. Did you implement the Renderer interface and used the AjaxConsequence?


For the client side Ajax stuff I'm using the great Prototype JavaScript framework, because of personal preferences
 


Robert developed a client-side solution for Mentawai called MentaAjax. In the first versions it was using prototype under the hood, but that was causing problems for people that wanted to use JQuery. So in the next Mentawai release, MentaAjax will not use prototype anymore. It will be pure javascript and the user can choose whatever javascript framework it wants to use with MentaAjax.

You don't need to use MentaAjax if you know prototype or jquery. This is for people that don't know these frameworks and want an easy way to do ajax in the client-side.

One major difference between Mentawai and other Java frameworks is that it is a full-stack solution. With other frameworks you have to constantly look somewhere else to solve common problems like sending email, connection pooling, ioc, di, etc. This has lead Java to the (in)famous problem of "The Java Framework Salad".

Great stuff! We will include your filter in the next release! Thanks!

Sergio Oliveira

Sven



Joined: 20/01/2008 05:53:15
Messages: 24
Offline

saoj wrote:

Not sure (I did not think much about it yet) if you want to place a cache logic inside the paginator filter. They look separate matters to me but I may be missing something.
 

After thinking about it again I believe that a caching logic should be implement in the corresponding action, if desired.

saoj wrote:

Mentawai comes out-of-the-box with a JSONGenericRenderer that you may want to use. Your can always implement your own renderers, no problem. Did you implement the Renderer interface and used the AjaxConsequence?
 

I know that Mentawai already has JSON renderers. I chose to use the JSON Tools library because it has a very simple interface for converting POJOs to JSON:

Code:
JSONMapper.toJSON( pojo ).render();

That's it!

And yes, I'm using AjaxConsequence and my renderer implements the Renderer interface.

saoj wrote:

Robert developed a client-side solution for Mentawai called MentaAjax. In the first versions it was using prototype under the hood, but that was causing problems for people that wanted to use JQuery. So in the next Mentawai release, MentaAjax will not use prototype anymore. It will be pure javascript and the user can choose whatever javascript framework it wants to use with MentaAjax.

You don't need to use MentaAjax if you know prototype or jquery. This is for people that don't know these frameworks and want an easy way to do ajax in the client-side.
 

Sounds interesting! I will have a look!
saoj



Joined: 01/07/2005 09:59:17
Messages: 2846
Location: Rio de Janeiro, RJ
Offline

Sven,

I have just added the PaginatorFilter + Paginator to the mentawai beta jar. I did just one modification, i hope you don't mind.

I changed the page parameter to start at 1 instead of 0. This is good because you will be displaying the page number as well as passing the next and previous page to the next and previous URL and you don't want to have two different values. I the page parameter starts at 1 then you have:

You are int page 4!

Current Page = 4 (page parameter)
Next page = 5 (page parameter)
Prev page = 3 (page parameter)


I have also added some extra functions to Paginator. Feel free to share your commens and suggestions. I hope it will be easy for your to addapt your application to the page parameter starting at one. Also don't forget to check the new recipe I just posted for this filter:

Mentawai Beta Jar: http://www.mentaframework.org/beta/mentawai.jar

Recipe: http://recipes.mentaframework.org/posts/list/22.page

Code:
 package org.mentawai.filter;
 
 import java.util.Collection;
 
 import org.mentawai.core.Action;
 import org.mentawai.core.Filter;
 import org.mentawai.core.Input;
 import org.mentawai.core.InvocationChain;
 import org.mentawai.core.Output;
 
 /**
  * <p>
  * This filter easily enables paging of data on top of your current structure.
  * The data that should be paged must be placed in the output stack with the
  * specified key (see constructor). Only arrays or <code>Collections</code>
  * can be paged, other data will be silently ignored.
  * </p>
  * <p>
  * The data with the specified key will be replaced by an instance of the
  * <code>Paginator</code> class which contains the paged data and some other
  * useful information.
  * </p>
  * <p>
  * Let's say you want paged search results: Add this filter to the
  * <code>ActionConfig</config> of your search action and don't forget to
  *   pass the page parameter to the query string:
  * </p>
  * <p>
  *   <code>http://example.com/search.mtw?q=keywords&p=0</code>
  * </p>
  *   The page parameter (which can be modified, see constructor) starts at 1.
  *   Use the other properties of the <code>Paginator</code> class to obtain
  *   information about the amount of all data, current page, maximum page and
  *   so on. With these information you can create links to the previous and
  *   next pages of your paged data.
  * </p>
  * <p>
  *  Mentawai provides the PaginatorTag, but this filter can be more useful for
  *  Ajax requests or any other situation when you don't want or cannot use the 
  *  PaginatorTag.
  *  </p>
  *
  * @author Sven Jacobs <sven.jacobs@web.de>
  * @see Paginator
  */
 public class PaginatorFilter implements Filter {
 	
 	public final static String DEFAULT_PAGE_PARAM = "p";
 	public final static int DEFAULT_ITEMS_PER_PAGE = 20;
 	
 	private int itemsPerPage;
 	private String key;
 	private String pageParam;
 
 	/**
 	 * Instantiate a PaginatorFilter with the specified key pointing to the data
 	 * in the output stack which should be paged.
 	 * 
 	 * @param key Key of the data from the output stack to page
 	 */
 	public PaginatorFilter(String key) {
 		this(key, DEFAULT_ITEMS_PER_PAGE, DEFAULT_PAGE_PARAM);
 	}
 
 	/**
 	 * Instantiate a PaginatorFilter with the specified key and amount of items
 	 * per page.
 	 * 
 	 * @param key Key of the data from the output stack to page
 	 * @param itemsPerPage Amount of items per page
 	 */
 	public PaginatorFilter(String key, int itemsPerPage) {
 		this(key, itemsPerPage, DEFAULT_PAGE_PARAM);
 	}
 
 	/**
 	 * Instantiate a PaginatorFilter with the specified key, amount of items per
 	 * page and name of the page parameter.
 	 * 
 	 * @param key Key of the data from the output stack to page
 	 * @param itemsPerPage Amount of items per page
 	 * @param pageParam Name of the page parameter
 	 */
 	public PaginatorFilter(String key, int itemsPerPage, String pageParam) {
 		this.key = key;
 		this.itemsPerPage = itemsPerPage;
 		this.pageParam = pageParam;
 	}
 
 	/**
 	 * The filter replaces the specified data with an instance of
 	 * <code>Paginator</code> which contains the paged data and some other
 	 * useful information.
 	 * 
 	 * Note: Only arrays and <code>Collections</code> can be paged.
 	 * 
 	 * @see Paginator
 	 */
 	public String filter(InvocationChain chain) throws Exception {
 		
 		Action action = chain.getAction();
 
 		String result = chain.invoke();
 
 		Output output = action.getOutput();
 		
 		Object value = output.getValue(key);
 
 		if (value != null) {
 			
 			Object[] arr;
 
 			if (value.getClass().isArray()) {
 				
 				arr = (Object[]) value;
 				
 			} else if (value instanceof Collection) {
 				
 				Collection<?> coll = (Collection<?>) value;
 				
 				arr = coll.toArray();
 				
 			} else {
 				
 				return result;
 				
 			}
 
 			Input input = action.getInput();
 			
 			int page = input.getIntValue(pageParam);
 
 			if (page <= 0) page = 1;
 
 			int startIndex = (page - 1) * itemsPerPage;
 			
 			if (startIndex >= arr.length) {
 				startIndex = 0;
 			}
 
 			int endIndex = startIndex + itemsPerPage;
 			
 			if (endIndex > arr.length) {
 				endIndex = arr.length;
 			}
 
 			// endIndex is NOT inclusive
 			Object[] newArr = copyOfRange(arr, startIndex, endIndex);
 			
 			// pages start with 1 not zero...
 			
 			int currentPage = (startIndex / itemsPerPage) + 1;
 			
 			int lastPage;
 			
 			if (arr.length % itemsPerPage == 0) {
 				
 				// 30 / 30 = 3 pages
 				// 20 / 20 = 2 pages
 				
 				lastPage = arr.length / itemsPerPage;
 				
 			} else {
 				
 				// 33 / 30 = 4 pages
 				// 28 / 30 = 3 pages
 				
 				lastPage = (arr.length / itemsPerPage) + 1;
 			}
 			
 			Paginator p = new Paginator(newArr, currentPage, lastPage, itemsPerPage, arr.length);
 
 			output.setValue(key, p);
 		}
 
 		return result;
 	}
 	
 	public static Object[] copyOfRange(Object[] original, int from, int to) {
 		
         int newLength = to - from;
         
         if (newLength < 0) throw new IllegalArgumentException(from + " > " + to);
         
         Object[] copy = new Object[newLength];
         
         System.arraycopy(original, from, copy, 0, Math.min(original.length - from, newLength));
         
         return copy;
     }
 	
 	public void destroy() {	}
 
 }
 


Code:
 package org.mentawai.filter;
 
 /**
  * Paginator POJO which contains paged data and other useful information.
  * 
  * The class should only be instantiated and used by the
  * <code>PaginatorFilter</code>!
  * 
  * @author Sven Jacobs <sven.jacobs@web.de>
  * @see PaginatorFilter
  */
 public class Paginator {
 	
 	private Object[] data;
 	private int currentPage;
 	private int lastPage;
 	private int itemsPerPage;
 	private int count;
 
 	Paginator() { }
 
 	/**
 	 * Instantiate a Paginator with all required data.
 	 * 
 	 * @param data Paged data
 	 * @param currentPage Index of the current page
 	 * @param lastPage Index of the last page
 	 * @param itemsPerPage Amount of items per page
 	 * @param count Amount of all data (all pages)
 	 */
 	Paginator(Object[] data, int currentPage, int lastPage, int itemsPerPage, int count) {
 		
 		this.data = data;
 		this.currentPage = currentPage;
 		this.lastPage = lastPage;
 		this.itemsPerPage = itemsPerPage;
 		this.count = count;
 	}
 	
 	public boolean hasNext() {
 		
 		return currentPage != lastPage;
 	}
 	
 	public boolean hasPrevious() {
 		
 		return currentPage > 1;
 	}
 	
 	public int getNextPage() {
 		
 		if (hasNext()) {
 			
 			return currentPage + 1;
 			
 		} else {
 			
 			return lastPage;
 		}
 	}
 	
 	public int getPreviousPage() {
 		
 		if (hasPrevious()) {
 			
 			return currentPage - 1;
 			
 		} else {
 			
 			return 1;
 		}
 	}
 
 	/**
 	 * Sets the paged data.
 	 * 
 	 * @param data Paged data
 	 */
 	public void setData(Object[] data) {
 		this.data = data;
 	}
 
 	/**
 	 * Returns the paged data.
 	 * 
 	 * @return Paged data
 	 */
 	public Object[] getData() {
 		return data;
 	}
 
 	/**
 	 * Set current page index.
 	 * 
 	 * @param currentPage Current page index
 	 */
 	public void setCurrentPage(int currentPage) {
 		this.currentPage = currentPage;
 	}
 
 	/**
 	 * Gets current page index.
 	 * 
 	 * @return Current page index
 	 */
 	public int getCurrentPage() {
 		return currentPage;
 	}
 
 	/**
 	 * Sets max page index.
 	 * 
 	 * @param maxPage Max page index
 	 */
 	public void setMaxPage(int maxPage) {
 		this.lastPage = maxPage;
 	}
 
 	/**
 	 * Gets max page index.
 	 * 
 	 * @return Max page index
 	 */
 	public int getMaxPage() {
 		return lastPage;
 	}
 
 	/**
 	 * Sets items per page.
 	 * 
 	 * <p>
 	 * This value reflects the <code>itemsPerPage</code> property of the
 	 * <code>PaginatorFilter</code> and not the actual amount of items of the
 	 * current page.
 	 * </p>
 	 * 
 	 * @param itemsPerPage Items per page
 	 * @see PaginatorFilter
 	 */
 	public void setItemsPerPage(int itemsPerPage) {
 		this.itemsPerPage = itemsPerPage;
 	}
 
 	/**
 	 * Gets items per page.
 	 * 
 	 * <p>
 	 * This value reflects the <code>itemsPerPage</code> property of the
 	 * <code>PaginatorFilter</code> and not the actual amount of items of the
 	 * current page.
 	 * </p>
 	 * 
 	 * @return Items per page
 	 * @see PaginatorFilter
 	 */
 	public int getItemsPerPage() {
 		return itemsPerPage;
 	}
 	
 	/**
 	 * Return the number of items in this page.
 	 * 
 	 * This may be less than what this page can display,
 	 * for example, you may be displaying 10 items per page
 	 * but your collecion has only 15 items. So the last page
 	 * will have 5 items only.
 	 * 
 	 * @return The number of items in this page
 	 */
 	public int getNumberOfItems() {
 		
 		if (data != null) return data.length;
 		
 		return 0;
 	}
 
 	/**
 	 * Sets the count (amount of all data over all pages)
 	 * 
 	 * @param count Amount of all data
 	 */
 	public void setCount(int count) {
 		this.count = count;
 	}
 
 	/**
 	 * Gets the count (amount of all data over all pages)
 	 * 
 	 * @return Amount of all data
 	 */
 	public int getCount() {
 		return count;
 	}
 }
 



Sergio Oliveira

Sven



Joined: 20/01/2008 05:53:15
Messages: 24
Offline

saoj wrote:
Sven,

I have just added the PaginatorFilter + Paginator to the mentawai beta jar. I did just one modification, i hope you don't mind. 


Hello Sergio,

I have a question. Why do you use System.arraycopy() instead of Arrays.copyOfRange()?
saoj



Joined: 01/07/2005 09:59:17
Messages: 2846
Location: Rio de Janeiro, RJ
Offline

Sven wrote:

I have a question. Why do you use System.arraycopy() instead of Arrays.copyOfRange()


Mentawai is compiled under Java 1.5, so it can run in the many 5.x tomcats out there.

Arrays.copyOfRange is 1.6, that's why I switched for System.arraycopy.

What did you think about the recipe? http://recipes.mentaframework.org/posts/list/22.page

Sergio Oliveira

Sven



Joined: 20/01/2008 05:53:15
Messages: 24
Offline

saoj wrote:

What did you think about the recipe? http://recipes.mentaframework.org/posts/list/22.page 


It's fine! I would also show an example of the PaginatorFilter with Ajax (and JSON).

For example in the JavaScript callback function of the Ajax request the Paginator can be used like this:

Code:
 function ajaxCallback( jsonData ) {
   var paginator = eval( jsonData );
 
   for( var i = 0; i < paginator.data.length; i++ ) {
     // render the data to the DOM tree somehow
   }
 
   // use the other paginator properties to render links to prev and next page
 }


Also several PaginatorFilters can be used at once for the same action if more than one dataset should be paginated - which is kinda cool (and was not intentionally planned)

Code:
   action(UserAction.class, "listAll")  
     .filter(new PaginatorFilter("users", 15, "p1"))  
     .filter(new PaginatorFilter("news", 5, "p2"))  
     .on(SUCCESS, fwd("/users/list.jsp"));
 
Forum Index -> General Comments Go to Page: 1, 2 Next 
Go to:   
Powered by JForum 2.1.6 © JForum Team