001// ***************************************************************************************************************************
002// * Licensed to the Apache Software Foundation (ASF) under one or more contributor license agreements.  See the NOTICE file *
003// * distributed with this work for additional information regarding copyright ownership.  The ASF licenses this file        *
004// * to you under the Apache License, Version 2.0 (the "License"); you may not use this file except in compliance            *
005// * with the License.  You may obtain a copy of the License at                                                              *
006// *                                                                                                                         *
007// *  http://www.apache.org/licenses/LICENSE-2.0                                                                             *
008// *                                                                                                                         *
009// * Unless required by applicable law or agreed to in writing, software distributed under the License is distributed on an  *
010// * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.  See the License for the        *
011// * specific language governing permissions and limitations under the License.                                              *
012// ***************************************************************************************************************************
013package org.apache.juneau.objecttools;
014
015import static java.util.Arrays.*;
016
017import java.lang.reflect.*;
018import java.util.*;
019
020import org.apache.juneau.*;
021
022/**
023 * POJO model paginator.
024 *
025 * <p>
026 *    This class is designed to extract sublists from arrays/collections of maps or beans.
027 * </p>
028 *
029 * <h5 class='section'>Example:</h5>
030 * <p class='bjava'>
031 *    MyBean[] <jv>arrayOfBeans</jv> = ...;
032 *    ObjectPaginator <jv>paginator</jv> = ObjectPaginator.<jsm>create</jsm>();
033 *
034 *    <jc>// Returns all rows from 100 to 110.</jc>
035 *    List&lt;MyBean&gt; <jv>result</jv> = <jv>paginator</jv>.run(<jv>arrayOfBeans</jv>, 100, 10);
036 * </p>
037 * <p>
038 *    The tool can be used against the following data types:
039 * </p>
040 * <ul>
041 *    <li>Arrays/collections of maps or beans.
042 * </ul>
043 *
044 * <h5 class='section'>See Also:</h5><ul>
045 *    <li class='link'><a class="doclink" href="../../../../index.html#jm.ObjectTools">Overview &gt; juneau-marshall &gt; Object Tools</a>
046
047 * </ul>
048 */
049public final class ObjectPaginator implements ObjectTool<PageArgs> {
050
051   //-----------------------------------------------------------------------------------------------------------------
052   // Static
053   //-----------------------------------------------------------------------------------------------------------------
054
055   /**
056    * Static creator.
057    * @return A new {@link ObjectPaginator} object.
058    */
059   public static ObjectPaginator create() {
060      return new ObjectPaginator();
061   }
062
063   //-----------------------------------------------------------------------------------------------------------------
064   // Instance
065   //-----------------------------------------------------------------------------------------------------------------
066
067   /**
068    * Convenience method for executing the paginator.
069    *
070    * @param <R> The collection element type.
071    * @param input The input.  Must be a collection or array of objects.
072    * @param pos The zero-index position to start from.
073    * @param limit The max number of entries to retrieve.
074    * @return A sublist of representing the entries from the position with the specified limit.
075    */
076   @SuppressWarnings("unchecked")
077   public <R> List<R> run(Object input, int pos, int limit) {
078      BeanSession bs = BeanContext.DEFAULT_SESSION;
079      Object r = run(BeanContext.DEFAULT_SESSION, input, PageArgs.create(pos, limit));
080      if (r instanceof List)
081         return (List<R>)r;
082      return bs.convertToType(r, List.class);
083   }
084
085   @Override /* ObjectTool */
086   @SuppressWarnings({ "rawtypes", "unchecked" })
087   public Object run(BeanSession session, Object input, PageArgs args) {
088
089      if (input == null)
090         return null;
091
092      ClassMeta type = session.getClassMetaForObject(input);
093
094      if (! type.isCollectionOrArray())
095         return input;
096
097      int pos = args.getPosition();
098      int limit = args.getLimit();
099
100      if (type.isArray()) {
101         int size = Array.getLength(input);
102         int end = (limit+pos >= size) ? size : limit + pos;
103         pos = Math.min(pos, size);
104         ClassMeta<?> et = type.getElementType();
105         if (! et.isPrimitive())
106            return copyOfRange((Object[])input, pos, end);
107         if (et.is(boolean.class))
108            return copyOfRange((boolean[])input, pos, end);
109         if (et.is(byte.class))
110            return copyOfRange((byte[])input, pos, end);
111         if (et.is(char.class))
112            return copyOfRange((char[])input, pos, end);
113         if (et.is(double.class))
114            return copyOfRange((double[])input, pos, end);
115         if (et.is(float.class))
116            return copyOfRange((float[])input, pos, end);
117         if (et.is(int.class))
118            return copyOfRange((int[])input, pos, end);
119         if (et.is(long.class))
120            return copyOfRange((long[])input, pos, end);
121         return copyOfRange((short[])input, pos, end);
122      }
123
124      List l = type.isList() ? (List)input : new ArrayList((Collection)input);
125      int end = (limit+pos >= l.size()) ? l.size() : limit + pos;
126      pos = Math.min(pos, l.size());
127      return l.subList(pos, end);
128   }
129}