You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@olingo.apache.org by mi...@apache.org on 2014/03/16 10:06:13 UTC

[24/50] [abbrv] git commit: [OLINGO-27] - Implement Server side paging in OData2 JPA Processor - Enhance the reference scenario to illustrate server side paging

[OLINGO-27] - Implement Server side paging in OData2 JPA Processor
- Enhance the reference scenario to illustrate server side paging


Signed-off-by: Chandan V A <ch...@sap.com>

Project: http://git-wip-us.apache.org/repos/asf/incubator-olingo-odata2/repo
Commit: http://git-wip-us.apache.org/repos/asf/incubator-olingo-odata2/commit/4aad349f
Tree: http://git-wip-us.apache.org/repos/asf/incubator-olingo-odata2/tree/4aad349f
Diff: http://git-wip-us.apache.org/repos/asf/incubator-olingo-odata2/diff/4aad349f

Branch: refs/heads/Olingo-129_PocJpaDataStore
Commit: 4aad349f8ea260abb7e6f38bab072ccfd9c5300c
Parents: 6b9a4e6
Author: Chandan V A <ch...@sap.com>
Authored: Sun Feb 16 13:05:04 2014 +0530
Committer: Chandan V A <ch...@sap.com>
Committed: Sun Feb 16 13:05:04 2014 +0530

----------------------------------------------------------------------
 .../jpa/processor/api/ODataJPAContext.java      |  24 +
 .../jpa/processor/api/access/JPAPaging.java     |  32 ++
 .../jpa/processor/api/jpql/JPQLContext.java     |  34 +-
 .../jpa/processor/core/ODataJPAContextImpl.java |  23 +
 .../core/ODataJPAResponseBuilderDefault.java    |  28 +-
 .../jpa/processor/core/access/data/JPAPage.java | 168 ++++++
 .../core/access/data/JPAProcessorImpl.java      |  55 +-
 .../core/jpql/JPQLJoinSelectContext.java        |   4 +
 .../processor/core/jpql/JPQLSelectContext.java  |   8 +-
 .../core/ODataJPAResponseBuilderTest.java       |  41 ++
 .../core/access/data/JPAPageBuilderTest.java    | 541 +++++++++++++++++++
 .../core/access/data/JPAProcessorImplTest.java  | 187 ++++++-
 .../ref/web/JPAReferenceServiceFactory.java     |   3 +-
 .../jpa-web/src/main/webapp/index.jsp           |  15 +-
 14 files changed, 1129 insertions(+), 34 deletions(-)
----------------------------------------------------------------------


http://git-wip-us.apache.org/repos/asf/incubator-olingo-odata2/blob/4aad349f/odata2-jpa-processor/jpa-api/src/main/java/org/apache/olingo/odata2/jpa/processor/api/ODataJPAContext.java
----------------------------------------------------------------------
diff --git a/odata2-jpa-processor/jpa-api/src/main/java/org/apache/olingo/odata2/jpa/processor/api/ODataJPAContext.java b/odata2-jpa-processor/jpa-api/src/main/java/org/apache/olingo/odata2/jpa/processor/api/ODataJPAContext.java
index f1e529c..9a57bf3 100644
--- a/odata2-jpa-processor/jpa-api/src/main/java/org/apache/olingo/odata2/jpa/processor/api/ODataJPAContext.java
+++ b/odata2-jpa-processor/jpa-api/src/main/java/org/apache/olingo/odata2/jpa/processor/api/ODataJPAContext.java
@@ -24,6 +24,7 @@ import javax.persistence.EntityManagerFactory;
 import org.apache.olingo.odata2.api.edm.provider.EdmProvider;
 import org.apache.olingo.odata2.api.processor.ODataContext;
 import org.apache.olingo.odata2.api.processor.ODataProcessor;
+import org.apache.olingo.odata2.jpa.processor.api.access.JPAPaging;
 import org.apache.olingo.odata2.jpa.processor.api.model.JPAEdmExtension;
 
 /**
@@ -203,4 +204,27 @@ public interface ODataJPAContext {
    */
   public boolean getDefaultNaming();
 
+  /**
+   * The method gets the server side page size to the context
+   * @return the page size
+   */
+  public int getPageSize();
+
+  /**
+   * The method sets the server side page size to the context
+   * @param size
+   */
+  public void setPageSize(int size);
+
+  /**
+   * The method sets the server side paging object
+   * @param an instance of type {@link org.apache.olingo.odata2.jpa.processor.api.access.JPAPaging}
+   */
+  public void setPaging(JPAPaging paging);
+
+  /**
+   * The method returns the server side paging object
+   * @return an instance of type {@link org.apache.olingo.odata2.jpa.processor.api.access.JPAPaging}
+   */
+  public JPAPaging getPaging();
 }

http://git-wip-us.apache.org/repos/asf/incubator-olingo-odata2/blob/4aad349f/odata2-jpa-processor/jpa-api/src/main/java/org/apache/olingo/odata2/jpa/processor/api/access/JPAPaging.java
----------------------------------------------------------------------
diff --git a/odata2-jpa-processor/jpa-api/src/main/java/org/apache/olingo/odata2/jpa/processor/api/access/JPAPaging.java b/odata2-jpa-processor/jpa-api/src/main/java/org/apache/olingo/odata2/jpa/processor/api/access/JPAPaging.java
new file mode 100644
index 0000000..2e3881f
--- /dev/null
+++ b/odata2-jpa-processor/jpa-api/src/main/java/org/apache/olingo/odata2/jpa/processor/api/access/JPAPaging.java
@@ -0,0 +1,32 @@
+/*******************************************************************************
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License. You may obtain a copy of the License at
+ * 
+ * http://www.apache.org/licenses/LICENSE-2.0
+ * 
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied. See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ ******************************************************************************/
+package org.apache.olingo.odata2.jpa.processor.api.access;
+
+import java.util.List;
+
+public interface JPAPaging {
+  public int getPageSize();
+
+  public List<Object> getPagedEntities();
+
+  public int getNextPage();
+
+  public int getStartPage();
+
+}

http://git-wip-us.apache.org/repos/asf/incubator-olingo-odata2/blob/4aad349f/odata2-jpa-processor/jpa-api/src/main/java/org/apache/olingo/odata2/jpa/processor/api/jpql/JPQLContext.java
----------------------------------------------------------------------
diff --git a/odata2-jpa-processor/jpa-api/src/main/java/org/apache/olingo/odata2/jpa/processor/api/jpql/JPQLContext.java b/odata2-jpa-processor/jpa-api/src/main/java/org/apache/olingo/odata2/jpa/processor/api/jpql/JPQLContext.java
index 0226300..a6230ad 100644
--- a/odata2-jpa-processor/jpa-api/src/main/java/org/apache/olingo/odata2/jpa/processor/api/jpql/JPQLContext.java
+++ b/odata2-jpa-processor/jpa-api/src/main/java/org/apache/olingo/odata2/jpa/processor/api/jpql/JPQLContext.java
@@ -52,6 +52,7 @@ public abstract class JPQLContext implements JPQLContextView {
    * The type of JPQL context. Based on the type JPQL statements can be built.
    */
   protected JPQLContextType type;
+  protected boolean pagingRequested = false;
 
   /**
    * sets JPA Entity Name into the context
@@ -107,6 +108,10 @@ public abstract class JPQLContext implements JPQLContextView {
     return type;
   }
 
+  protected void isPagingRequested(final boolean pagingRequested) {
+    this.pagingRequested = pagingRequested;
+  }
+
   /**
    * the method returns an instance of type
    * {@link org.apache.olingo.odata2.jpa.processor.api.jpql.JPQLContext.JPQLContextBuilder} based on the
@@ -122,7 +127,28 @@ public abstract class JPQLContext implements JPQLContextView {
    */
   public final static JPQLContextBuilder createBuilder(final JPQLContextType contextType, final Object resultsView)
       throws ODataJPARuntimeException {
-    return JPQLContextBuilder.create(contextType, resultsView);
+    return JPQLContextBuilder.create(contextType, resultsView, false);
+  }
+
+  /**
+   * the method returns an instance of type
+   * {@link org.apache.olingo.odata2.jpa.processor.api.jpql.JPQLContext.JPQLContextBuilder} based on the
+   * JPQLContextType. The context builder can be used for
+   * building different JPQL contexts.
+   * 
+   * @param contextType
+   * is the JPQLContextType
+   * @param resultsView
+   * is the OData request view
+   * @param withPaging
+   * indicates whether to build the context with paging
+   * @return an instance of type {@link org.apache.olingo.odata2.jpa.processor.api.jpql.JPQLContext.JPQLContextBuilder}
+   * @throws ODataJPARuntimeException
+   */
+  public final static JPQLContextBuilder createBuilder(final JPQLContextType contextType, final Object resultsView,
+      final boolean withPaging)
+      throws ODataJPARuntimeException {
+    return JPQLContextBuilder.create(contextType, resultsView, withPaging);
   }
 
   /**
@@ -140,6 +166,8 @@ public abstract class JPQLContext implements JPQLContextView {
      */
     protected int aliasCounter = 0;
 
+    protected boolean withPaging = false;
+
     protected JPQLContextBuilder() {}
 
     /**
@@ -153,7 +181,8 @@ public abstract class JPQLContext implements JPQLContextView {
      * {@link org.apache.olingo.odata2.jpa.processor.api.jpql.JPQLContext.JPQLContextBuilder}
      * @throws ODataJPARuntimeException
      */
-    private static JPQLContextBuilder create(final JPQLContextType contextType, final Object resultsView)
+    private static JPQLContextBuilder create(final JPQLContextType contextType, final Object resultsView,
+        final boolean withPaging)
         throws ODataJPARuntimeException {
       JPQLContextBuilder contextBuilder =
           ODataJPAFactory.createFactory().getJPQLBuilderFactory().getContextBuilder(contextType);
@@ -161,6 +190,7 @@ public abstract class JPQLContext implements JPQLContextView {
         throw ODataJPARuntimeException.throwException(ODataJPARuntimeException.ERROR_JPQLCTXBLDR_CREATE, null);
       }
       contextBuilder.setResultsView(resultsView);
+      contextBuilder.withPaging = withPaging;
       return contextBuilder;
     }
 

http://git-wip-us.apache.org/repos/asf/incubator-olingo-odata2/blob/4aad349f/odata2-jpa-processor/jpa-core/src/main/java/org/apache/olingo/odata2/jpa/processor/core/ODataJPAContextImpl.java
----------------------------------------------------------------------
diff --git a/odata2-jpa-processor/jpa-core/src/main/java/org/apache/olingo/odata2/jpa/processor/core/ODataJPAContextImpl.java b/odata2-jpa-processor/jpa-core/src/main/java/org/apache/olingo/odata2/jpa/processor/core/ODataJPAContextImpl.java
index fe8c45f..43f1850 100644
--- a/odata2-jpa-processor/jpa-core/src/main/java/org/apache/olingo/odata2/jpa/processor/core/ODataJPAContextImpl.java
+++ b/odata2-jpa-processor/jpa-core/src/main/java/org/apache/olingo/odata2/jpa/processor/core/ODataJPAContextImpl.java
@@ -25,6 +25,7 @@ import org.apache.olingo.odata2.api.edm.provider.EdmProvider;
 import org.apache.olingo.odata2.api.processor.ODataContext;
 import org.apache.olingo.odata2.api.processor.ODataProcessor;
 import org.apache.olingo.odata2.jpa.processor.api.ODataJPAContext;
+import org.apache.olingo.odata2.jpa.processor.api.access.JPAPaging;
 import org.apache.olingo.odata2.jpa.processor.api.model.JPAEdmExtension;
 
 public class ODataJPAContextImpl implements ODataJPAContext {
@@ -37,6 +38,8 @@ public class ODataJPAContextImpl implements ODataJPAContext {
   private EdmProvider edmProvider;
   private String jpaEdmMappingModelName;
   private JPAEdmExtension jpaEdmExtension;
+  private int pageSize = 0;
+  private JPAPaging jpaPaging;
   private static final ThreadLocal<ODataContext> oDataContextThreadLocal = new ThreadLocal<ODataContext>();
   private boolean defaultNaming = true;
 
@@ -143,4 +146,24 @@ public class ODataJPAContextImpl implements ODataJPAContext {
   public boolean getDefaultNaming() {
     return defaultNaming;
   }
+
+  @Override
+  public int getPageSize() {
+    return pageSize;
+  }
+
+  @Override
+  public void setPageSize(final int size) {
+    pageSize = size;
+  }
+
+  @Override
+  public void setPaging(final JPAPaging paging) {
+    jpaPaging = paging;
+  }
+
+  @Override
+  public JPAPaging getPaging() {
+    return jpaPaging;
+  }
 }

http://git-wip-us.apache.org/repos/asf/incubator-olingo-odata2/blob/4aad349f/odata2-jpa-processor/jpa-core/src/main/java/org/apache/olingo/odata2/jpa/processor/core/ODataJPAResponseBuilderDefault.java
----------------------------------------------------------------------
diff --git a/odata2-jpa-processor/jpa-core/src/main/java/org/apache/olingo/odata2/jpa/processor/core/ODataJPAResponseBuilderDefault.java b/odata2-jpa-processor/jpa-core/src/main/java/org/apache/olingo/odata2/jpa/processor/core/ODataJPAResponseBuilderDefault.java
index bc01eec..c49d017 100644
--- a/odata2-jpa-processor/jpa-core/src/main/java/org/apache/olingo/odata2/jpa/processor/core/ODataJPAResponseBuilderDefault.java
+++ b/odata2-jpa-processor/jpa-core/src/main/java/org/apache/olingo/odata2/jpa/processor/core/ODataJPAResponseBuilderDefault.java
@@ -48,6 +48,7 @@ import org.apache.olingo.odata2.api.processor.ODataContext;
 import org.apache.olingo.odata2.api.processor.ODataResponse;
 import org.apache.olingo.odata2.api.uri.ExpandSelectTreeNode;
 import org.apache.olingo.odata2.api.uri.NavigationPropertySegment;
+import org.apache.olingo.odata2.api.uri.PathInfo;
 import org.apache.olingo.odata2.api.uri.SelectItem;
 import org.apache.olingo.odata2.api.uri.UriParser;
 import org.apache.olingo.odata2.api.uri.info.DeleteUriInfo;
@@ -470,6 +471,7 @@ public final class ODataJPAResponseBuilderDefault implements ODataJPAResponseBui
       final GetEntitySetUriInfo resultsView, final List<Map<String, Object>> edmEntityList)
       throws ODataJPARuntimeException {
     ODataEntityProviderPropertiesBuilder entityFeedPropertiesBuilder = null;
+    ODataContext context = odataJPAContext.getODataContext();
 
     Integer count = null;
     if (resultsView.getInlineCount() != null) {
@@ -483,13 +485,22 @@ public final class ODataJPAResponseBuilderDefault implements ODataJPAResponseBui
     }
 
     try {
+      PathInfo pathInfo = context.getPathInfo();
       entityFeedPropertiesBuilder =
-          EntityProviderWriteProperties.serviceRoot(odataJPAContext.getODataContext().getPathInfo().getServiceRoot());
+          EntityProviderWriteProperties.serviceRoot(pathInfo.getServiceRoot());
+      if (odataJPAContext.getPageSize() > 0 && odataJPAContext.getPaging().getNextPage() > 0) {
+        String nextLink =
+            pathInfo.getServiceRoot().relativize(context.getPathInfo().getRequestUri()).toString();
+        nextLink = percentEncodeNextLink(nextLink);
+        nextLink += (nextLink.contains("?") ? "&" : "?")
+            + "$skiptoken=" + odataJPAContext.getPaging().getNextPage();
+        entityFeedPropertiesBuilder.nextLink(nextLink);
+      }
       entityFeedPropertiesBuilder.inlineCount(count);
       entityFeedPropertiesBuilder.inlineCountType(resultsView.getInlineCount());
       ExpandSelectTreeNode expandSelectTree =
           UriParser.createExpandSelectTree(resultsView.getSelect(), resultsView.getExpand());
-      entityFeedPropertiesBuilder.callbacks(JPAExpandCallBack.getCallbacks(odataJPAContext.getODataContext()
+      entityFeedPropertiesBuilder.callbacks(JPAExpandCallBack.getCallbacks(context
           .getPathInfo().getServiceRoot(), expandSelectTree, resultsView.getExpand()));
       entityFeedPropertiesBuilder.expandSelectTree(expandSelectTree);
 
@@ -500,6 +511,16 @@ public final class ODataJPAResponseBuilderDefault implements ODataJPAResponseBui
     return entityFeedPropertiesBuilder.build();
   }
 
+  private static String percentEncodeNextLink(final String link) {
+    if (link == null) {
+      return null;
+    }
+
+    return link.replaceAll("\\$skiptoken=.+?(?:&|$)", "")
+        .replaceAll("\\$skip=.+?(?:&|$)", "")
+        .replaceFirst("(?:\\?|&)$", ""); // Remove potentially trailing "?" or "&" left over from remove actions
+  }
+
   /*
    * This method handles $inlinecount request. It also modifies the list of results in case of
    * $inlinecount and $top/$skip combinations. Specific to Entity Set.
@@ -602,7 +623,8 @@ public final class ODataJPAResponseBuilderDefault implements ODataJPAResponseBui
     return navigationPropertyList;
   }
 
-  private static List<EdmProperty> getEdmProperties(EdmStructuralType structuralType) throws ODataJPARuntimeException {
+  private static List<EdmProperty> getEdmProperties(final EdmStructuralType structuralType)
+      throws ODataJPARuntimeException {
     List<EdmProperty> edmProperties = new ArrayList<EdmProperty>();
     try {
       for (String propertyName : structuralType.getPropertyNames()) {

http://git-wip-us.apache.org/repos/asf/incubator-olingo-odata2/blob/4aad349f/odata2-jpa-processor/jpa-core/src/main/java/org/apache/olingo/odata2/jpa/processor/core/access/data/JPAPage.java
----------------------------------------------------------------------
diff --git a/odata2-jpa-processor/jpa-core/src/main/java/org/apache/olingo/odata2/jpa/processor/core/access/data/JPAPage.java b/odata2-jpa-processor/jpa-core/src/main/java/org/apache/olingo/odata2/jpa/processor/core/access/data/JPAPage.java
new file mode 100644
index 0000000..3161d8d
--- /dev/null
+++ b/odata2-jpa-processor/jpa-core/src/main/java/org/apache/olingo/odata2/jpa/processor/core/access/data/JPAPage.java
@@ -0,0 +1,168 @@
+/*******************************************************************************
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License. You may obtain a copy of the License at
+ * 
+ * http://www.apache.org/licenses/LICENSE-2.0
+ * 
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied. See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ ******************************************************************************/
+package org.apache.olingo.odata2.jpa.processor.core.access.data;
+
+import java.util.ArrayList;
+import java.util.List;
+
+import javax.persistence.Query;
+
+import org.apache.olingo.odata2.jpa.processor.api.access.JPAPaging;
+
+public class JPAPage implements JPAPaging {
+
+  private int pageSize;
+  private int startPage;
+  private int nextPage;
+  private List<Object> pagedEntries;
+
+  protected JPAPage(final int startPage, final int nextPage, final List<Object> pagedEntities, final int pageSize) {
+    this.pageSize = pageSize;
+    this.startPage = startPage;
+    this.nextPage = nextPage;
+    pagedEntries = pagedEntities;
+  }
+
+  @Override
+  public int getPageSize() {
+    return pageSize;
+  }
+
+  @Override
+  public List<Object> getPagedEntities() {
+    return pagedEntries;
+  }
+
+  @Override
+  public int getNextPage() {
+    return nextPage;
+  }
+
+  @Override
+  public int getStartPage() {
+    return startPage;
+  }
+
+  public static class JPAPageBuilder {
+
+    private int pageSize;
+    private int startPage;
+    private int nextPage;
+    private int top = -1;
+    private int skip;
+    private int skipToken;
+    private Query query;
+
+    public JPAPageBuilder() {}
+
+    public JPAPageBuilder pageSize(final int pageSize) {
+      this.pageSize = pageSize;
+      return this;
+    }
+
+    public JPAPageBuilder query(final Query query) {
+      this.query = query;
+      return this;
+    }
+
+    @SuppressWarnings("unchecked")
+    public JPAPage build() {
+
+      List<Object> entities = new ArrayList<Object>();
+      int size = 0;
+      if (pageSize <= 0) {
+        if (skip > 0) {
+          query.setFirstResult(skip);
+        }
+        if (top > 0) {
+          query.setMaxResults(top);
+        }
+        entities = query.getResultList();
+      } else {
+        if (skip >= pageSize) { // No Records to fetch
+          startPage = skipToken;
+          nextPage = 0;
+        } else {
+          // Max Results
+          size = top + skip;
+          if (size > pageSize) {
+            if (skip == 0) {
+              query.setMaxResults(pageSize);
+            } else {
+              query.setMaxResults(pageSize - skip);
+            }
+          } else {
+            if (top > 0) {
+              query.setMaxResults(top);
+            } else {
+              query.setMaxResults(pageSize);
+            }
+          }
+
+          startPage = skipToken;
+          if (skip > 0) {
+            query.setFirstResult(startPage + skip);
+          } else {
+            query.setFirstResult(startPage);
+          }
+
+          entities = query.getResultList();
+          if (entities.size() == 0) {
+            nextPage = 0;
+          } else {
+            nextPage = startPage + pageSize;
+          }
+        }
+      }
+      return new JPAPage(startPage, nextPage, entities, pageSize);
+    }
+
+    public JPAPageBuilder skip(final int skip) {
+      this.skip = skip;
+      if (skip < 0) {
+        this.skip = 0;
+      } else {
+        this.skip = skip;
+      }
+      return this;
+    }
+
+    public JPAPageBuilder skipToken(final String skipToken) throws NumberFormatException {
+      if (skipToken == null) {
+        this.skipToken = 0;
+      } else {
+        this.skipToken = new Integer(skipToken).intValue();
+        if (this.skipToken < 0) {
+          this.skipToken = 0;
+        }
+      }
+
+      return this;
+    }
+
+    public JPAPageBuilder top(final int top) {
+      if (top < 0) {
+        this.top = 0;
+      } else {
+        this.top = top;
+      }
+      return this;
+    }
+  }
+}

http://git-wip-us.apache.org/repos/asf/incubator-olingo-odata2/blob/4aad349f/odata2-jpa-processor/jpa-core/src/main/java/org/apache/olingo/odata2/jpa/processor/core/access/data/JPAProcessorImpl.java
----------------------------------------------------------------------
diff --git a/odata2-jpa-processor/jpa-core/src/main/java/org/apache/olingo/odata2/jpa/processor/core/access/data/JPAProcessorImpl.java b/odata2-jpa-processor/jpa-core/src/main/java/org/apache/olingo/odata2/jpa/processor/core/access/data/JPAProcessorImpl.java
index 219f5b7..c018c00 100644
--- a/odata2-jpa-processor/jpa-core/src/main/java/org/apache/olingo/odata2/jpa/processor/core/access/data/JPAProcessorImpl.java
+++ b/odata2-jpa-processor/jpa-core/src/main/java/org/apache/olingo/odata2/jpa/processor/core/access/data/JPAProcessorImpl.java
@@ -54,6 +54,7 @@ import org.apache.olingo.odata2.jpa.processor.api.jpql.JPQLContext;
 import org.apache.olingo.odata2.jpa.processor.api.jpql.JPQLContextType;
 import org.apache.olingo.odata2.jpa.processor.api.jpql.JPQLStatement;
 import org.apache.olingo.odata2.jpa.processor.core.ODataEntityParser;
+import org.apache.olingo.odata2.jpa.processor.core.access.data.JPAPage.JPAPageBuilder;
 
 public class JPAProcessorImpl implements JPAProcessor {
 
@@ -117,13 +118,12 @@ public class JPAProcessorImpl implements JPAProcessor {
   }
 
   /* Process Get Entity Set Request (Query) */
-  @SuppressWarnings("unchecked")
   @Override
-  public <T> List<T> process(final GetEntitySetUriInfo uriParserResultView)
+  public List<Object> process(final GetEntitySetUriInfo uriParserResultView)
       throws ODataJPAModelException, ODataJPARuntimeException {
 
     if (uriParserResultView.getFunctionImport() != null) {
-      return (List<T>) process((GetFunctionImportUriInfo) uriParserResultView);
+      return (List<Object>) process((GetFunctionImportUriInfo) uriParserResultView);
     }
     JPQLContextType contextType = null;
     try {
@@ -139,28 +139,21 @@ public class JPAProcessorImpl implements JPAProcessor {
           ODataJPARuntimeException.GENERAL, e);
     }
 
-    JPQLContext jpqlContext = JPQLContext.createBuilder(contextType,
-        uriParserResultView).build();
+    JPQLContext jpqlContext = null;
+    if (oDataJPAContext.getPageSize() > 0) {
+      jpqlContext = JPQLContext.createBuilder(contextType,
+          uriParserResultView, true).build();
+    } else {
+      jpqlContext = JPQLContext.createBuilder(contextType,
+          uriParserResultView).build();
+    }
 
     JPQLStatement jpqlStatement = JPQLStatement.createBuilder(jpqlContext)
         .build();
     Query query = null;
     try {
       query = em.createQuery(jpqlStatement.toString());
-      // $top/$skip with $inlinecount case handled in response builder to avoid multiple DB call
-      if (uriParserResultView.getSkip() != null && uriParserResultView.getInlineCount() == null) {
-        query.setFirstResult(uriParserResultView.getSkip());
-      }
-
-      if (uriParserResultView.getTop() != null && uriParserResultView.getInlineCount() == null) {
-        if (uriParserResultView.getTop() == 0) {
-          List<T> resultList = new ArrayList<T>();
-          return resultList;
-        } else {
-          query.setMaxResults(uriParserResultView.getTop());
-        }
-      }
-      return query.getResultList();
+      return handlePaging(query, uriParserResultView);
     } catch (Exception e) {
       throw ODataJPARuntimeException.throwException(
           ODataJPARuntimeException.ERROR_JPQL_QUERY_CREATE, e);
@@ -168,6 +161,28 @@ public class JPAProcessorImpl implements JPAProcessor {
     }
   }
 
+  private List<Object> handlePaging(final Query query, final GetEntitySetUriInfo uriParserResultView) {
+
+    JPAPageBuilder pageBuilder = new JPAPageBuilder();
+    pageBuilder.pageSize(oDataJPAContext.getPageSize())
+        .query(query)
+        .skipToken(uriParserResultView.getSkipToken());
+
+    // $top/$skip with $inlinecount case handled in response builder to avoid multiple DB call
+    if (uriParserResultView.getSkip() != null && uriParserResultView.getInlineCount() == null) {
+      pageBuilder.skip(uriParserResultView.getSkip().intValue());
+    }
+
+    if (uriParserResultView.getTop() != null && uriParserResultView.getInlineCount() == null) {
+      pageBuilder.top(uriParserResultView.getTop().intValue());
+    }
+
+    JPAPage page = pageBuilder.build();
+    oDataJPAContext.setPaging(page);
+    return page.getPagedEntities();
+
+  }
+
   /* Process Get Entity Request (Read) */
   @Override
   public <T> Object process(GetEntityUriInfo uriParserResultView)
@@ -439,7 +454,7 @@ public class JPAProcessorImpl implements JPAProcessor {
 
   /* Process Get Entity Set Link Request */
   @Override
-  public <T> List<T> process(final GetEntitySetLinksUriInfo uriParserResultView)
+  public List<Object> process(final GetEntitySetLinksUriInfo uriParserResultView)
       throws ODataJPAModelException, ODataJPARuntimeException {
     return this.process((GetEntitySetUriInfo) uriParserResultView);
   }

http://git-wip-us.apache.org/repos/asf/incubator-olingo-odata2/blob/4aad349f/odata2-jpa-processor/jpa-core/src/main/java/org/apache/olingo/odata2/jpa/processor/core/jpql/JPQLJoinSelectContext.java
----------------------------------------------------------------------
diff --git a/odata2-jpa-processor/jpa-core/src/main/java/org/apache/olingo/odata2/jpa/processor/core/jpql/JPQLJoinSelectContext.java b/odata2-jpa-processor/jpa-core/src/main/java/org/apache/olingo/odata2/jpa/processor/core/jpql/JPQLJoinSelectContext.java
index e69a2d6..e5d9df8 100644
--- a/odata2-jpa-processor/jpa-core/src/main/java/org/apache/olingo/odata2/jpa/processor/core/jpql/JPQLJoinSelectContext.java
+++ b/odata2-jpa-processor/jpa-core/src/main/java/org/apache/olingo/odata2/jpa/processor/core/jpql/JPQLJoinSelectContext.java
@@ -62,6 +62,10 @@ public class JPQLJoinSelectContext extends JPQLSelectContext implements JPQLJoin
           setType(JPQLContextType.JOIN);
         }
 
+        if (withPaging) {
+          isPagingRequested(withPaging);
+        }
+
         setJPAOuterJoinClause(generateJoinClauses());
 
         if (!jpaJoinClauses.isEmpty()) {

http://git-wip-us.apache.org/repos/asf/incubator-olingo-odata2/blob/4aad349f/odata2-jpa-processor/jpa-core/src/main/java/org/apache/olingo/odata2/jpa/processor/core/jpql/JPQLSelectContext.java
----------------------------------------------------------------------
diff --git a/odata2-jpa-processor/jpa-core/src/main/java/org/apache/olingo/odata2/jpa/processor/core/jpql/JPQLSelectContext.java b/odata2-jpa-processor/jpa-core/src/main/java/org/apache/olingo/odata2/jpa/processor/core/jpql/JPQLSelectContext.java
index 61d2801..4668b7d 100644
--- a/odata2-jpa-processor/jpa-core/src/main/java/org/apache/olingo/odata2/jpa/processor/core/jpql/JPQLSelectContext.java
+++ b/odata2-jpa-processor/jpa-core/src/main/java/org/apache/olingo/odata2/jpa/processor/core/jpql/JPQLSelectContext.java
@@ -87,6 +87,11 @@ public class JPQLSelectContext extends JPQLContext implements JPQLSelectContextV
           } else {
             setType(JPQLContextType.SELECT);
           }
+
+          if (withPaging) {
+            isPagingRequested(withPaging);
+          }
+
           EdmEntityType entityType = entitySetView.getTargetEntitySet().getEntityType();
           EdmMapping mapping = entityType.getMapping();
           if (mapping != null) {
@@ -135,7 +140,8 @@ public class JPQLSelectContext extends JPQLContext implements JPQLSelectContextV
 
         return ODataExpressionParser.parseToJPAOrderByExpression(entitySetView.getOrderBy(), getJPAEntityAlias());
 
-      } else if (entitySetView.getTop() != null || entitySetView.getSkip() != null) {
+      } else if (entitySetView.getTop() != null || entitySetView.getSkip() != null ||
+          pagingRequested == true) {
 
         return ODataExpressionParser.parseKeyPropertiesToJPAOrderByExpression(entitySetView.getTargetEntitySet()
             .getEntityType().getKeyProperties(), getJPAEntityAlias());

http://git-wip-us.apache.org/repos/asf/incubator-olingo-odata2/blob/4aad349f/odata2-jpa-processor/jpa-core/src/test/java/org/apache/olingo/odata2/jpa/processor/core/ODataJPAResponseBuilderTest.java
----------------------------------------------------------------------
diff --git a/odata2-jpa-processor/jpa-core/src/test/java/org/apache/olingo/odata2/jpa/processor/core/ODataJPAResponseBuilderTest.java b/odata2-jpa-processor/jpa-core/src/test/java/org/apache/olingo/odata2/jpa/processor/core/ODataJPAResponseBuilderTest.java
index 19d3d01..1345260 100644
--- a/odata2-jpa-processor/jpa-core/src/test/java/org/apache/olingo/odata2/jpa/processor/core/ODataJPAResponseBuilderTest.java
+++ b/odata2-jpa-processor/jpa-core/src/test/java/org/apache/olingo/odata2/jpa/processor/core/ODataJPAResponseBuilderTest.java
@@ -59,6 +59,7 @@ import org.apache.olingo.odata2.api.uri.info.GetEntitySetUriInfo;
 import org.apache.olingo.odata2.api.uri.info.GetEntityUriInfo;
 import org.apache.olingo.odata2.jpa.processor.api.ODataJPAContext;
 import org.apache.olingo.odata2.jpa.processor.api.ODataJPAResponseBuilder;
+import org.apache.olingo.odata2.jpa.processor.api.access.JPAPaging;
 import org.apache.olingo.odata2.jpa.processor.api.exception.ODataJPARuntimeException;
 import org.apache.olingo.odata2.jpa.processor.core.common.ODataJPATestConstants;
 import org.apache.olingo.odata2.jpa.processor.core.model.JPAEdmTestModelView;
@@ -246,6 +247,8 @@ public class ODataJPAResponseBuilderTest extends JPAEdmTestModelView {
   private ODataJPAContext getODataJPAContext() {
     ODataJPAContext objODataJPAContext = EasyMock.createMock(ODataJPAContext.class);
     EasyMock.expect(objODataJPAContext.getODataContext()).andStubReturn(getLocalODataContext());
+    EasyMock.expect(objODataJPAContext.getPageSize()).andReturn(10);
+    EasyMock.expect(objODataJPAContext.getPaging()).andReturn(mockJPAPaging()).anyTimes();
     EasyMock.replay(objODataJPAContext);
     return objODataJPAContext;
   }
@@ -261,13 +264,51 @@ public class ODataJPAResponseBuilderTest extends JPAEdmTestModelView {
     return objODataContext;
   }
 
+  private JPAPaging mockJPAPaging() {
+    JPAPaging paging = new JPAPaging() {
+
+      @Override
+      public int getStartPage() {
+        return 0;
+      }
+
+      @Override
+      public List<Object> getPagedEntities() {
+        return null;
+      }
+
+      @Override
+      public int getPageSize() {
+        return 10;
+      }
+
+      @Override
+      public int getNextPage() {
+        return 10;
+      }
+    };
+
+    return paging;
+  }
+
   private PathInfo getLocalPathInfo() {
     PathInfo pathInfo = EasyMock.createMock(PathInfo.class);
     EasyMock.expect(pathInfo.getServiceRoot()).andStubReturn(getLocalURI());
+    EasyMock.expect(pathInfo.getRequestUri()).andStubReturn(getRequestURI());
     EasyMock.replay(pathInfo);
     return pathInfo;
   }
 
+  private URI getRequestURI() {
+    URI uri = null;
+    try {
+      uri = new URI("SalesOrders");
+    } catch (URISyntaxException e) {
+      fail(ODataJPATestConstants.EXCEPTION_MSG_PART_1 + e.getMessage() + ODataJPATestConstants.EXCEPTION_MSG_PART_2);
+    }
+    return uri;
+  }
+
   private URI getLocalURI() {
     URI uri = null;
     try {

http://git-wip-us.apache.org/repos/asf/incubator-olingo-odata2/blob/4aad349f/odata2-jpa-processor/jpa-core/src/test/java/org/apache/olingo/odata2/jpa/processor/core/access/data/JPAPageBuilderTest.java
----------------------------------------------------------------------
diff --git a/odata2-jpa-processor/jpa-core/src/test/java/org/apache/olingo/odata2/jpa/processor/core/access/data/JPAPageBuilderTest.java b/odata2-jpa-processor/jpa-core/src/test/java/org/apache/olingo/odata2/jpa/processor/core/access/data/JPAPageBuilderTest.java
new file mode 100644
index 0000000..2013045
--- /dev/null
+++ b/odata2-jpa-processor/jpa-core/src/test/java/org/apache/olingo/odata2/jpa/processor/core/access/data/JPAPageBuilderTest.java
@@ -0,0 +1,541 @@
+package org.apache.olingo.odata2.jpa.processor.core.access.data;
+
+import static org.junit.Assert.assertEquals;
+import static org.junit.Assert.assertNotNull;
+import static org.junit.Assert.fail;
+
+import java.util.ArrayList;
+import java.util.Calendar;
+import java.util.Date;
+import java.util.List;
+import java.util.Map;
+import java.util.Set;
+
+import javax.persistence.FlushModeType;
+import javax.persistence.LockModeType;
+import javax.persistence.Parameter;
+import javax.persistence.Query;
+import javax.persistence.TemporalType;
+
+import org.apache.olingo.odata2.jpa.processor.core.access.data.JPAPage.JPAPageBuilder;
+import org.junit.Test;
+
+public class JPAPageBuilderTest {
+
+  private static final int PAGE_SIZE = 10;
+
+  @Test
+  public void testBuildDefault() {
+    JPAPageBuilder pageBuilder = new JPAPageBuilder();
+    Query query = mockQuery(false);
+
+    JPAPage page = pageBuilder.query(query)
+        .pageSize(PAGE_SIZE)
+        .skipToken("10")
+        .build();
+
+    assertEquals(20, page.getNextPage());
+    assertEquals(10, page.getStartPage());
+    assertEquals(PAGE_SIZE, page.getPageSize());
+    assertNotNull(page.getPagedEntities());
+    assertEquals(1, page.getPagedEntities().size());
+
+    assertEquals(10, query.getFirstResult());
+    assertEquals(10, query.getMaxResults());
+  }
+
+  @Test
+  public void testBuildDefaultZeroPage() {
+    JPAPageBuilder pageBuilder = new JPAPageBuilder();
+    Query query = mockQuery(false);
+
+    JPAPage page = pageBuilder.query(query)
+        .pageSize(0)
+        .skipToken("10")
+        .build();
+
+    assertEquals(0, page.getNextPage());
+    assertEquals(0, page.getStartPage());
+    assertEquals(0, page.getPageSize());
+    assertNotNull(page.getPagedEntities());
+    assertEquals(0, page.getPagedEntities().size());
+
+    assertEquals(0, query.getFirstResult());
+    assertEquals(0, query.getMaxResults());
+  }
+
+  @Test
+  public void testBuildWithNoSkipToken() {
+    JPAPageBuilder pageBuilder = new JPAPageBuilder();
+    Query query = mockQuery(false);
+
+    JPAPage page = pageBuilder.query(query)
+        .pageSize(PAGE_SIZE)
+        .skipToken("0")
+        .build();
+
+    assertEquals(10, page.getNextPage());
+    assertEquals(0, page.getStartPage());
+    assertEquals(PAGE_SIZE, page.getPageSize());
+    assertNotNull(page.getPagedEntities());
+    assertEquals(1, page.getPagedEntities().size());
+
+    assertEquals(0, query.getFirstResult());
+    assertEquals(10, query.getMaxResults());
+  }
+
+  @Test
+  public void testBuildWithNullSkipToken() {
+    JPAPageBuilder pageBuilder = new JPAPageBuilder();
+    Query query = mockQuery(false);
+
+    JPAPage page = pageBuilder.query(query)
+        .pageSize(PAGE_SIZE)
+        .skipToken(null)
+        .build();
+
+    assertEquals(10, page.getNextPage());
+    assertEquals(0, page.getStartPage());
+    assertEquals(PAGE_SIZE, page.getPageSize());
+    assertNotNull(page.getPagedEntities());
+
+    assertEquals(0, query.getFirstResult());
+    assertEquals(10, query.getMaxResults());
+  }
+
+  @Test
+  public void testBuildWithInvalidSkipToken() {
+    JPAPageBuilder pageBuilder = new JPAPageBuilder();
+    Query query = mockQuery(false);
+
+    try {
+      pageBuilder.query(query)
+          .skipToken("AB");
+    } catch (NumberFormatException e) {
+      return;
+    }
+    fail("Exception Expected");
+  }
+
+  @Test
+  public void testBuildWithTop() {
+    JPAPageBuilder pageBuilder = new JPAPageBuilder();
+    Query query = mockQuery(false);
+
+    JPAPage page = pageBuilder.query(query)
+        .pageSize(PAGE_SIZE)
+        .skipToken("10")
+        .top(5)
+        .build();
+
+    assertEquals(20, page.getNextPage());
+    assertEquals(10, page.getStartPage());
+    assertEquals(PAGE_SIZE, page.getPageSize());
+    assertNotNull(page.getPagedEntities());
+
+    assertEquals(10, query.getFirstResult());
+    assertEquals(5, query.getMaxResults());
+  }
+
+  @Test
+  public void testBuildWithTopZeroPage() {
+    JPAPageBuilder pageBuilder = new JPAPageBuilder();
+    Query query = mockQuery(false);
+
+    JPAPage page = pageBuilder.query(query)
+        .pageSize(0)
+        .skipToken("10")
+        .top(5)
+        .build();
+
+    assertEquals(0, page.getNextPage());
+    assertEquals(0, page.getStartPage());
+    assertEquals(0, page.getPageSize());
+    assertNotNull(page.getPagedEntities());
+
+    assertEquals(0, query.getFirstResult());
+    assertEquals(5, query.getMaxResults());
+  }
+
+  @Test
+  public void testBuildWithSkipZeroPage() {
+    JPAPageBuilder pageBuilder = new JPAPageBuilder();
+    Query query = mockQuery(false);
+
+    JPAPage page = pageBuilder.query(query)
+        .pageSize(0)
+        .skipToken("10")
+        .skip(5)
+        .build();
+
+    assertEquals(0, page.getNextPage());
+    assertEquals(0, page.getStartPage());
+    assertEquals(0, page.getPageSize());
+    assertNotNull(page.getPagedEntities());
+
+    assertEquals(5, query.getFirstResult());
+    assertEquals(0, query.getMaxResults());
+  }
+
+  @Test
+  public void testBuildWithTopSkipZeroPage() {
+    JPAPageBuilder pageBuilder = new JPAPageBuilder();
+    Query query = mockQuery(false);
+
+    JPAPage page = pageBuilder.query(query)
+        .pageSize(0)
+        .skipToken("10")
+        .skip(5)
+        .top(5)
+        .build();
+
+    assertEquals(0, page.getNextPage());
+    assertEquals(0, page.getStartPage());
+    assertEquals(0, page.getPageSize());
+    assertNotNull(page.getPagedEntities());
+
+    assertEquals(5, query.getFirstResult());
+    assertEquals(5, query.getMaxResults());
+  }
+
+  @Test
+  public void testBuildWithTopExceeds() {
+    JPAPageBuilder pageBuilder = new JPAPageBuilder();
+    Query query = mockQuery(false);
+
+    JPAPage page = pageBuilder.query(query)
+        .pageSize(PAGE_SIZE)
+        .skipToken("10")
+        .top(15)
+        .build();
+
+    assertEquals(20, page.getNextPage());
+    assertEquals(10, page.getStartPage());
+    assertEquals(PAGE_SIZE, page.getPageSize());
+    assertNotNull(page.getPagedEntities());
+
+    assertEquals(10, query.getFirstResult());
+    assertEquals(10, query.getMaxResults());
+  }
+
+  @Test
+  public void testBuildWithTopSkipExceeds() {
+    JPAPageBuilder pageBuilder = new JPAPageBuilder();
+    Query query = mockQuery(false);
+
+    JPAPage page = pageBuilder.query(query)
+        .pageSize(PAGE_SIZE)
+        .skipToken("10")
+        .top(5)
+        .skip(10)
+        .build();
+
+    assertEquals(0, page.getNextPage());
+    assertEquals(10, page.getStartPage());
+    assertEquals(PAGE_SIZE, page.getPageSize());
+    assertEquals(0, page.getPagedEntities().size());
+
+    assertEquals(0, query.getFirstResult());
+    assertEquals(0, query.getMaxResults());
+  }
+
+  @Test
+  public void testBuildWithTopSkipMore() {
+    JPAPageBuilder pageBuilder = new JPAPageBuilder();
+    Query query = mockQuery(false);
+
+    JPAPage page = pageBuilder.query(query)
+        .pageSize(PAGE_SIZE)
+        .skipToken("10")
+        .top(5)
+        .skip(9)
+        .build();
+
+    assertEquals(20, page.getNextPage());
+    assertEquals(10, page.getStartPage());
+    assertEquals(PAGE_SIZE, page.getPageSize());
+    assertNotNull(page.getPagedEntities());
+
+    assertEquals(19, query.getFirstResult());
+    assertEquals(1, query.getMaxResults());
+  }
+
+  @Test
+  public void testBuildWithTopMoreSkip() {
+    JPAPageBuilder pageBuilder = new JPAPageBuilder();
+    Query query = mockQuery(false);
+
+    JPAPage page = pageBuilder.query(query)
+        .pageSize(PAGE_SIZE)
+        .skipToken("10")
+        .top(15)
+        .skip(9)
+        .build();
+
+    assertEquals(20, page.getNextPage());
+    assertEquals(10, page.getStartPage());
+    assertEquals(PAGE_SIZE, page.getPageSize());
+    assertNotNull(page.getPagedEntities());
+
+    assertEquals(19, query.getFirstResult());
+    assertEquals(1, query.getMaxResults());
+  }
+
+  @Test
+  public void testBuildWithTopXSkipX() {
+    JPAPageBuilder pageBuilder = new JPAPageBuilder();
+    Query query = mockQuery(false);
+
+    JPAPage page = pageBuilder.query(query)
+        .pageSize(PAGE_SIZE)
+        .skipToken("10")
+        .top(15)
+        .skip(15)
+        .build();
+
+    assertEquals(0, page.getNextPage());
+    assertEquals(10, page.getStartPage());
+    assertEquals(PAGE_SIZE, page.getPageSize());
+    assertNotNull(page.getPagedEntities());
+
+    assertEquals(0, query.getFirstResult());
+    assertEquals(0, query.getMaxResults());
+  }
+
+  @Test
+  public void testBuildWithNegativeTop() {
+    JPAPageBuilder pageBuilder = new JPAPageBuilder();
+    Query query = mockQuery(false);
+
+    JPAPage page = pageBuilder.query(query)
+        .pageSize(PAGE_SIZE)
+        .skipToken("10")
+        .top(-5)
+        .build();
+
+    assertEquals(20, page.getNextPage());
+    assertEquals(10, page.getStartPage());
+    assertEquals(PAGE_SIZE, page.getPageSize());
+    assertNotNull(page.getPagedEntities());
+
+    assertEquals(10, query.getFirstResult());
+    assertEquals(10, query.getMaxResults());
+  }
+
+  @Test
+  public void testBuildWithNegativeTopSkipToken() {
+    JPAPageBuilder pageBuilder = new JPAPageBuilder();
+    Query query = mockQuery(false);
+
+    JPAPage page = pageBuilder.query(query)
+        .pageSize(PAGE_SIZE)
+        .skipToken("-10")
+        .top(-5)
+        .skip(-1)
+        .build();
+
+    assertEquals(10, page.getNextPage());
+    assertEquals(0, page.getStartPage());
+    assertEquals(PAGE_SIZE, page.getPageSize());
+    assertNotNull(page.getPagedEntities());
+
+    assertEquals(0, query.getFirstResult());
+    assertEquals(10, query.getMaxResults());
+  }
+
+  @Test
+  public void testBuildWithNoRecords() {
+    JPAPageBuilder pageBuilder = new JPAPageBuilder();
+    Query query = mockQuery(true);
+
+    JPAPage page = pageBuilder.query(query)
+        .pageSize(PAGE_SIZE)
+        .skipToken("10")
+        .top(1)
+        .skip(1)
+        .build();
+
+    assertEquals(0, page.getNextPage());
+    assertEquals(10, page.getStartPage());
+    assertEquals(PAGE_SIZE, page.getPageSize());
+    assertNotNull(page.getPagedEntities());
+
+    assertEquals(11, query.getFirstResult());
+    assertEquals(1, query.getMaxResults());
+  }
+
+  private Query mockQuery(final boolean setNoRecords) {
+
+    return new Query() {
+
+      private int maxResults;
+      private int firstResult;
+
+      @Override
+      public Query setFirstResult(final int arg0) {
+        firstResult = arg0;
+        return this;
+      }
+
+      @Override
+      public Query setMaxResults(final int arg0) {
+        maxResults = arg0;
+        return this;
+      }
+
+      @Override
+      public int getMaxResults() {
+        return maxResults;
+      }
+
+      @Override
+      public int getFirstResult() {
+        return firstResult;
+      }
+
+      @Override
+      public List<Object> getResultList() {
+        List<Object> list = new ArrayList<Object>();
+        if (maxResults > 0 && setNoRecords == false) {
+          list.add(new Integer(1));
+        }
+        return list;
+      }
+
+      @Override
+      public <T> T unwrap(final Class<T> arg0) {
+        return null;
+      }
+
+      @Override
+      public Query setParameter(final int arg0, final Date arg1, final TemporalType arg2) {
+        return null;
+      }
+
+      @Override
+      public Query setParameter(final int arg0, final Calendar arg1, final TemporalType arg2) {
+        return null;
+      }
+
+      @Override
+      public Query setParameter(final String arg0, final Date arg1, final TemporalType arg2) {
+        return null;
+      }
+
+      @Override
+      public Query setParameter(final String arg0, final Calendar arg1, final TemporalType arg2) {
+        return null;
+      }
+
+      @Override
+      public Query setParameter(final Parameter<Date> arg0, final Date arg1, final TemporalType arg2) {
+        return null;
+      }
+
+      @Override
+      public Query setParameter(final Parameter<Calendar> arg0, final Calendar arg1, final TemporalType arg2) {
+        return null;
+      }
+
+      @Override
+      public Query setParameter(final int arg0, final Object arg1) {
+        return null;
+      }
+
+      @Override
+      public Query setParameter(final String arg0, final Object arg1) {
+        return null;
+      }
+
+      @Override
+      public <T> Query setParameter(final Parameter<T> arg0, final T arg1) {
+        return null;
+      }
+
+      @Override
+      public Query setLockMode(final LockModeType arg0) {
+        return null;
+      }
+
+      @Override
+      public Query setHint(final String arg0, final Object arg1) {
+        return null;
+      }
+
+      @Override
+      public Query setFlushMode(final FlushModeType arg0) {
+        return null;
+      }
+
+      @Override
+      public boolean isBound(final Parameter<?> arg0) {
+        return false;
+      }
+
+      @Override
+      public Object getSingleResult() {
+        return null;
+      }
+
+      @Override
+      public Set<Parameter<?>> getParameters() {
+        return null;
+      }
+
+      @Override
+      public Object getParameterValue(final int arg0) {
+        return null;
+      }
+
+      @Override
+      public Object getParameterValue(final String arg0) {
+        return null;
+      }
+
+      @Override
+      public <T> T getParameterValue(final Parameter<T> arg0) {
+        return null;
+      }
+
+      @Override
+      public <T> Parameter<T> getParameter(final int arg0, final Class<T> arg1) {
+        return null;
+      }
+
+      @Override
+      public <T> Parameter<T> getParameter(final String arg0, final Class<T> arg1) {
+        return null;
+      }
+
+      @Override
+      public Parameter<?> getParameter(final int arg0) {
+        return null;
+      }
+
+      @Override
+      public Parameter<?> getParameter(final String arg0) {
+        return null;
+      }
+
+      @Override
+      public LockModeType getLockMode() {
+        return null;
+      }
+
+      @Override
+      public Map<String, Object> getHints() {
+        return null;
+      }
+
+      @Override
+      public FlushModeType getFlushMode() {
+        return null;
+      }
+
+      @Override
+      public int executeUpdate() {
+        return 0;
+      }
+    };
+  }
+}

http://git-wip-us.apache.org/repos/asf/incubator-olingo-odata2/blob/4aad349f/odata2-jpa-processor/jpa-core/src/test/java/org/apache/olingo/odata2/jpa/processor/core/access/data/JPAProcessorImplTest.java
----------------------------------------------------------------------
diff --git a/odata2-jpa-processor/jpa-core/src/test/java/org/apache/olingo/odata2/jpa/processor/core/access/data/JPAProcessorImplTest.java b/odata2-jpa-processor/jpa-core/src/test/java/org/apache/olingo/odata2/jpa/processor/core/access/data/JPAProcessorImplTest.java
index bafef01..23fe91c 100644
--- a/odata2-jpa-processor/jpa-core/src/test/java/org/apache/olingo/odata2/jpa/processor/core/access/data/JPAProcessorImplTest.java
+++ b/odata2-jpa-processor/jpa-core/src/test/java/org/apache/olingo/odata2/jpa/processor/core/access/data/JPAProcessorImplTest.java
@@ -23,12 +23,20 @@ import static org.junit.Assert.fail;
 import java.net.URI;
 import java.net.URISyntaxException;
 import java.util.ArrayList;
+import java.util.Calendar;
+import java.util.Date;
 import java.util.List;
+import java.util.Map;
+import java.util.Set;
 
 import javax.persistence.EntityManager;
 import javax.persistence.EntityManagerFactory;
 import javax.persistence.EntityTransaction;
+import javax.persistence.FlushModeType;
+import javax.persistence.LockModeType;
+import javax.persistence.Parameter;
 import javax.persistence.Query;
+import javax.persistence.TemporalType;
 import javax.persistence.metamodel.Metamodel;
 
 import junit.framework.Assert;
@@ -57,6 +65,7 @@ import org.apache.olingo.odata2.api.uri.info.GetEntityCountUriInfo;
 import org.apache.olingo.odata2.api.uri.info.GetEntitySetCountUriInfo;
 import org.apache.olingo.odata2.api.uri.info.GetEntitySetUriInfo;
 import org.apache.olingo.odata2.jpa.processor.api.ODataJPAContext;
+import org.apache.olingo.odata2.jpa.processor.api.access.JPAPaging;
 import org.apache.olingo.odata2.jpa.processor.api.exception.ODataJPAModelException;
 import org.apache.olingo.odata2.jpa.processor.api.exception.ODataJPARuntimeException;
 import org.apache.olingo.odata2.jpa.processor.core.common.ODataJPATestConstants;
@@ -180,6 +189,7 @@ public class JPAProcessorImplTest {
     EasyMock.expect(objUriInfo.getOrderBy()).andStubReturn(getOrderByExpression());
     EasyMock.expect(objUriInfo.getTop()).andStubReturn(getTop());
     EasyMock.expect(objUriInfo.getSkip()).andStubReturn(getSkip());
+    EasyMock.expect(objUriInfo.getSkipToken()).andReturn("5");
     EasyMock.expect(objUriInfo.getInlineCount()).andStubReturn(getInlineCount());
     EasyMock.expect(objUriInfo.getFilter()).andStubReturn(getFilter());
     // EasyMock.expect(objUriInfo.getFunctionImport()).andStubReturn(getFunctionImport());
@@ -273,6 +283,9 @@ public class JPAProcessorImplTest {
     EasyMock.expect(odataJPAContext.getEntityManagerFactory()).andStubReturn(mockEntityManagerFactory());
     EasyMock.expect(odataJPAContext.getODataContext()).andStubReturn(getLocalODataContext());
     EasyMock.expect(odataJPAContext.getEntityManager()).andStubReturn(getLocalEntityManager());
+    EasyMock.expect(odataJPAContext.getPageSize()).andReturn(10).anyTimes();
+    odataJPAContext.setPaging(EasyMock.isA(JPAPaging.class));
+    EasyMock.expectLastCall();
     EasyMock.replay(odataJPAContext);
     return odataJPAContext;
   }
@@ -311,10 +324,174 @@ public class JPAProcessorImplTest {
   }
 
   private Query getQuery() {
-    Query query = EasyMock.createMock(Query.class);
-    EasyMock.expect(query.getResultList()).andStubReturn(getResultList());
-    EasyMock.replay(query);
-    return query;
+    return new Query() {
+
+      private int maxResults;
+      private int firstResult;
+
+      @Override
+      public Query setFirstResult(final int arg0) {
+        firstResult = arg0;
+        return this;
+      }
+
+      @Override
+      public Query setMaxResults(final int arg0) {
+        maxResults = arg0;
+        return this;
+      }
+
+      @Override
+      public int getMaxResults() {
+        return maxResults;
+      }
+
+      @Override
+      public int getFirstResult() {
+        return firstResult;
+      }
+
+      @SuppressWarnings("unchecked")
+      @Override
+      public List<Object> getResultList() {
+        return (List<Object>) getResultListL();
+      }
+
+      @Override
+      public <T> T unwrap(final Class<T> arg0) {
+        return null;
+      }
+
+      @Override
+      public Query setParameter(final int arg0, final Date arg1, final TemporalType arg2) {
+        return null;
+      }
+
+      @Override
+      public Query setParameter(final int arg0, final Calendar arg1, final TemporalType arg2) {
+        return null;
+      }
+
+      @Override
+      public Query setParameter(final String arg0, final Date arg1, final TemporalType arg2) {
+        return null;
+      }
+
+      @Override
+      public Query setParameter(final String arg0, final Calendar arg1, final TemporalType arg2) {
+        return null;
+      }
+
+      @Override
+      public Query setParameter(final Parameter<Date> arg0, final Date arg1, final TemporalType arg2) {
+        return null;
+      }
+
+      @Override
+      public Query setParameter(final Parameter<Calendar> arg0, final Calendar arg1, final TemporalType arg2) {
+        return null;
+      }
+
+      @Override
+      public Query setParameter(final int arg0, final Object arg1) {
+        return null;
+      }
+
+      @Override
+      public Query setParameter(final String arg0, final Object arg1) {
+        return null;
+      }
+
+      @Override
+      public <T> Query setParameter(final Parameter<T> arg0, final T arg1) {
+        return null;
+      }
+
+      @Override
+      public Query setLockMode(final LockModeType arg0) {
+        return null;
+      }
+
+      @Override
+      public Query setHint(final String arg0, final Object arg1) {
+        return null;
+      }
+
+      @Override
+      public Query setFlushMode(final FlushModeType arg0) {
+        return null;
+      }
+
+      @Override
+      public boolean isBound(final Parameter<?> arg0) {
+        return false;
+      }
+
+      @Override
+      public Object getSingleResult() {
+        return null;
+      }
+
+      @Override
+      public Set<Parameter<?>> getParameters() {
+        return null;
+      }
+
+      @Override
+      public Object getParameterValue(final int arg0) {
+        return null;
+      }
+
+      @Override
+      public Object getParameterValue(final String arg0) {
+        return null;
+      }
+
+      @Override
+      public <T> T getParameterValue(final Parameter<T> arg0) {
+        return null;
+      }
+
+      @Override
+      public <T> Parameter<T> getParameter(final int arg0, final Class<T> arg1) {
+        return null;
+      }
+
+      @Override
+      public <T> Parameter<T> getParameter(final String arg0, final Class<T> arg1) {
+        return null;
+      }
+
+      @Override
+      public Parameter<?> getParameter(final int arg0) {
+        return null;
+      }
+
+      @Override
+      public Parameter<?> getParameter(final String arg0) {
+        return null;
+      }
+
+      @Override
+      public LockModeType getLockMode() {
+        return null;
+      }
+
+      @Override
+      public Map<String, Object> getHints() {
+        return null;
+      }
+
+      @Override
+      public FlushModeType getFlushMode() {
+        return null;
+      }
+
+      @Override
+      public int executeUpdate() {
+        return 0;
+      }
+    };
   }
 
   private Query getQueryForSelectCount() {
@@ -324,7 +501,7 @@ public class JPAProcessorImplTest {
     return query;
   }
 
-  private List<?> getResultList() {
+  private List<?> getResultListL() {
     List<Object> list = new ArrayList<Object>();
     list.add(new Address());
     return list;

http://git-wip-us.apache.org/repos/asf/incubator-olingo-odata2/blob/4aad349f/odata2-jpa-processor/jpa-web/src/main/java/org/apache/olingo/odata2/jpa/processor/ref/web/JPAReferenceServiceFactory.java
----------------------------------------------------------------------
diff --git a/odata2-jpa-processor/jpa-web/src/main/java/org/apache/olingo/odata2/jpa/processor/ref/web/JPAReferenceServiceFactory.java b/odata2-jpa-processor/jpa-web/src/main/java/org/apache/olingo/odata2/jpa/processor/ref/web/JPAReferenceServiceFactory.java
index 63d9c4a..f21d565 100644
--- a/odata2-jpa-processor/jpa-web/src/main/java/org/apache/olingo/odata2/jpa/processor/ref/web/JPAReferenceServiceFactory.java
+++ b/odata2-jpa-processor/jpa-web/src/main/java/org/apache/olingo/odata2/jpa/processor/ref/web/JPAReferenceServiceFactory.java
@@ -32,6 +32,7 @@ public class JPAReferenceServiceFactory extends ODataJPAServiceFactory {
   private static final String MAPPING_MODEL = "SalesOrderProcessingMappingModel.xml";
   private static final String CONFIG = "serviceConfig";
   private static final String SHOW_DETAIL_ERROR = "showDetailError";
+  private static final int PAGE_SIZE = 5;
 
   @Override
   public ODataJPAContext initializeODataJPAContext()
@@ -42,7 +43,7 @@ public class JPAReferenceServiceFactory extends ODataJPAServiceFactory {
     oDataJPAContext.setJPAEdmMappingModel(MAPPING_MODEL);
     oDataJPAContext
         .setJPAEdmExtension((JPAEdmExtension) new SalesOrderProcessingExtension());
-
+    oDataJPAContext.setPageSize(PAGE_SIZE);
     setErrorLevel();
 
     return oDataJPAContext;

http://git-wip-us.apache.org/repos/asf/incubator-olingo-odata2/blob/4aad349f/odata2-jpa-processor/jpa-web/src/main/webapp/index.jsp
----------------------------------------------------------------------
diff --git a/odata2-jpa-processor/jpa-web/src/main/webapp/index.jsp b/odata2-jpa-processor/jpa-web/src/main/webapp/index.jsp
index f897cbb..db37577 100644
--- a/odata2-jpa-processor/jpa-web/src/main/webapp/index.jsp
+++ b/odata2-jpa-processor/jpa-web/src/main/webapp/index.jsp
@@ -290,10 +290,21 @@ th,td {
 					<li><a
 						href="SalesOrderProcessing.svc/FindAllSalesOrders?DeliveryStatusCode='01'"
 						target="_blank">SalesOrderProcessing.svc/FindAllSalesOrders?DeliveryStatusCode='01'</a></li>
-					<li><a
-						href="SalesOrderProcessing.svc/orderValue?SoId=2L"
+					<li><a href="SalesOrderProcessing.svc/orderValue?SoId=2L"
 						target="_blank">SalesOrderProcessing.svc/orderValue?SoId=2L</a></li>
 				</ul>
+				<h3>Paging</h3>
+				<ul>
+					<li><a
+						href="SalesOrderProcessing.svc/SalesOrders?$top=1&$inlinecount=allpages"
+						target="_blank">SalesOrderProcessing.svc/SalesOrders?$top=1&$inlinecount=allpages"</a></li>
+					<li><a
+						href="SalesOrderProcessing.svc/SalesOrders?$top=1&$inlinecount=allpages&$skiptoken=5"
+						target="_blank">SalesOrderProcessing.svc/SalesOrders?$top=1&$inlinecount=allpages&$skiptoken=5</a></li>
+					<li><a
+						href="SalesOrderProcessing.svc/SalesOrders?$top=1&$skip=4&$inlinecount=allpages&$skiptoken=5"
+						target="_blank">SalesOrderProcessing.svc/SalesOrders?$top=1&$skip=4&$inlinecount=allpages&$skiptoken=5</a></li>
+				</ul>
 			</td>
 			<td valign="top">&nbsp;</td>
 			<td valign="bottom">