Repository: olingo-odata2
Updated Branches:
  refs/heads/master bb2517adb -> 6c7a67425


[ODATAJAVA-1147]Entity read is not working due to normalization in 
JPAQueryBuilder


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

Branch: refs/heads/master
Commit: 6c7a67425af35bbaac7c4e9a7c0066d9a9463cc2
Parents: bb2517a
Author: Archana Rai <[email protected]>
Authored: Wed Jul 26 14:40:53 2017 +0530
Committer: Archana Rai <[email protected]>
Committed: Wed Jul 26 14:40:53 2017 +0530

----------------------------------------------------------------------
 .../core/access/data/JPAQueryBuilder.java       | 60 ++++++++++----
 .../core/access/data/JPAQueryBuilderTest.java   | 82 ++++++++++++++++++++
 .../core/mock/ODataJPAContextMock.java          | 18 ++++-
 3 files changed, 140 insertions(+), 20 deletions(-)
----------------------------------------------------------------------


http://git-wip-us.apache.org/repos/asf/olingo-odata2/blob/6c7a6742/odata2-jpa-processor/jpa-core/src/main/java/org/apache/olingo/odata2/jpa/processor/core/access/data/JPAQueryBuilder.java
----------------------------------------------------------------------
diff --git 
a/odata2-jpa-processor/jpa-core/src/main/java/org/apache/olingo/odata2/jpa/processor/core/access/data/JPAQueryBuilder.java
 
b/odata2-jpa-processor/jpa-core/src/main/java/org/apache/olingo/odata2/jpa/processor/core/access/data/JPAQueryBuilder.java
index 6852a17..6f66af9 100644
--- 
a/odata2-jpa-processor/jpa-core/src/main/java/org/apache/olingo/odata2/jpa/processor/core/access/data/JPAQueryBuilder.java
+++ 
b/odata2-jpa-processor/jpa-core/src/main/java/org/apache/olingo/odata2/jpa/processor/core/access/data/JPAQueryBuilder.java
@@ -18,6 +18,17 @@
  
******************************************************************************/
 package org.apache.olingo.odata2.jpa.processor.core.access.data;
 
+import java.util.HashMap;
+import java.util.Map;
+import java.util.Set;
+import java.util.regex.Matcher;
+import java.util.regex.Pattern;
+
+import javax.persistence.EntityManager;
+import javax.persistence.Query;
+import javax.persistence.metamodel.Attribute;
+import javax.persistence.metamodel.EntityType;
+
 import org.apache.olingo.odata2.api.edm.EdmException;
 import org.apache.olingo.odata2.api.uri.UriInfo;
 import org.apache.olingo.odata2.api.uri.info.DeleteUriInfo;
@@ -36,16 +47,6 @@ 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.api.model.JPAEdmMapping;
 
-import javax.persistence.EntityManager;
-import javax.persistence.Query;
-import javax.persistence.metamodel.Attribute;
-import javax.persistence.metamodel.EntityType;
-import java.util.HashMap;
-import java.util.Map;
-import java.util.Set;
-import java.util.regex.Matcher;
-import java.util.regex.Pattern;
-
 public class JPAQueryBuilder {
 
   enum UriInfoType {
@@ -238,12 +239,17 @@ public class JPAQueryBuilder {
   }
 
   private static final Pattern NORMALIZATION_NEEDED_PATTERN = 
Pattern.compile(".*[\\s(](\\S+\\.\\S+\\.\\S+).*");
+  private static final Pattern VALUE_NORM_PATTERN = 
Pattern.compile("(?:^|\\s)'([^'](\\S+\\.\\S+\\.\\S+)')");
   private static final Pattern JOIN_ALIAS_PATTERN = 
Pattern.compile(".*\\sJOIN\\s(\\S*\\s\\S*).*");
 
-  private static String normalizeMembers(EntityManager em, String jpqlQuery) {
+  private static String normalizeMembers(EntityManager em, String jpqlQuery) { 
 
+    
+    //check if clause values are string with x.y.z format
+    //starting with quotes;
+    String query = checkConditionValues(jpqlQuery);
     // check if normalization is needed (if query contains "x.y.z" elements
     // starting with space or parenthesis)
-    Matcher normalizationNeededMatcher = 
NORMALIZATION_NEEDED_PATTERN.matcher(jpqlQuery);
+    Matcher normalizationNeededMatcher = 
NORMALIZATION_NEEDED_PATTERN.matcher(query);
     if (!normalizationNeededMatcher.find()) {
       return jpqlQuery;
     }
@@ -251,7 +257,7 @@ public class JPAQueryBuilder {
     if (containsEmbeddedAttributes(em, jpqlQuery)) {
       return jpqlQuery;
     }
-
+    
     String normalizedJpqlQuery = jpqlQuery;
     Map<String, String> joinAliases = new HashMap<String, String>();
 
@@ -263,7 +269,6 @@ public class JPAQueryBuilder {
         joinAliases.put(joinAlias[0], joinAlias[1]);
       }
     }
-
     // normalize query
     boolean normalizationNeeded = true;
     while (normalizationNeeded) {
@@ -295,12 +300,13 @@ public class JPAQueryBuilder {
       // use alias
       normalizedJpqlQuery = normalizedJpqlQuery.replaceAll(memberInfo + "\\" + 
JPQLStatement.DELIMITER.PERIOD,
           alias + JPQLStatement.DELIMITER.PERIOD);
-
+      //check for values like "x.y.z"
+      query = checkConditionValues(normalizedJpqlQuery);
       // check if further normalization is needed
-      normalizationNeededMatcher = 
NORMALIZATION_NEEDED_PATTERN.matcher(normalizedJpqlQuery);
+      normalizationNeededMatcher = NORMALIZATION_NEEDED_PATTERN.matcher(query);
       normalizationNeeded = normalizationNeededMatcher.find();
     }
-
+    
     // add distinct to avoid duplicates in result set
     return normalizedJpqlQuery.replaceFirst(
         JPQLStatement.KEYWORD.SELECT + JPQLStatement.DELIMITER.SPACE,
@@ -308,6 +314,26 @@ public class JPAQueryBuilder {
   }
 
   /**
+   * Check if the statement contains string values having x.y.z kind of format
+   * It will replace those values with parameters before checking for 
normalization 
+   * and later added back
+   * */
+  private static String checkConditionValues(String jpqlQuery) {
+    int i=0;
+    StringBuffer query= new StringBuffer();
+    query.append(jpqlQuery);
+    Matcher valueMatcher = VALUE_NORM_PATTERN.matcher(query);
+    while (valueMatcher.find()) {
+      String val = valueMatcher.group();
+      int index = query.indexOf(val);
+      String var = "["+ ++i +"] ";
+      query.replace(index, index + val.length(), var);
+      valueMatcher = VALUE_NORM_PATTERN.matcher(query);
+    }
+    return query.toString();
+  }
+
+  /**
    * Verify via {@link EntityManager} if one of the attributes of the selected 
entity
    * contains a embedded attribute.
    * Return true if at least one embedded attribute is found or false if non 
embedded

http://git-wip-us.apache.org/repos/asf/olingo-odata2/blob/6c7a6742/odata2-jpa-processor/jpa-core/src/test/java/org/apache/olingo/odata2/jpa/processor/core/access/data/JPAQueryBuilderTest.java
----------------------------------------------------------------------
diff --git 
a/odata2-jpa-processor/jpa-core/src/test/java/org/apache/olingo/odata2/jpa/processor/core/access/data/JPAQueryBuilderTest.java
 
b/odata2-jpa-processor/jpa-core/src/test/java/org/apache/olingo/odata2/jpa/processor/core/access/data/JPAQueryBuilderTest.java
index 4c9fbaa..7d35ed6 100644
--- 
a/odata2-jpa-processor/jpa-core/src/test/java/org/apache/olingo/odata2/jpa/processor/core/access/data/JPAQueryBuilderTest.java
+++ 
b/odata2-jpa-processor/jpa-core/src/test/java/org/apache/olingo/odata2/jpa/processor/core/access/data/JPAQueryBuilderTest.java
@@ -23,6 +23,7 @@ import static org.junit.Assert.assertNotNull;
 import static org.junit.Assert.fail;
 
 import java.util.ArrayList;
+import java.util.Iterator;
 import java.util.List;
 
 import javax.persistence.EntityManager;
@@ -32,8 +33,10 @@ import org.apache.olingo.odata2.api.edm.EdmEntitySet;
 import org.apache.olingo.odata2.api.edm.EdmEntityType;
 import org.apache.olingo.odata2.api.edm.EdmException;
 import org.apache.olingo.odata2.api.edm.EdmMapping;
+import org.apache.olingo.odata2.api.edm.EdmProperty;
 import org.apache.olingo.odata2.api.exception.ODataException;
 import org.apache.olingo.odata2.api.processor.ODataContext;
+import org.apache.olingo.odata2.api.uri.KeyPredicate;
 import org.apache.olingo.odata2.api.uri.NavigationSegment;
 import org.apache.olingo.odata2.api.uri.UriInfo;
 import org.apache.olingo.odata2.api.uri.info.DeleteUriInfo;
@@ -188,6 +191,36 @@ public class JPAQueryBuilderTest {
     }
   }
 
+  @Test
+  public void buildQueryGetEntityTest() {
+    EdmMapping mapping = (EdmMapping) mockMapping();
+    try {
+      assertNotNull(builder.build((GetEntityUriInfo) mockURIInfo(mapping)));
+    } catch (ODataException e) {
+      fail(ODataJPATestConstants.EXCEPTION_MSG_PART_1 + e.getMessage() + 
ODataJPATestConstants.EXCEPTION_MSG_PART_2);
+    }
+  }
+
+  @Test
+  public void buildQueryValueNormalizeTest() {
+    EdmMapping mapping = (EdmMapping) mockNormalizedValueMapping();
+    try {
+      assertNotNull(builder.build((GetEntityUriInfo) mockURIInfo(mapping)));
+    } catch (ODataException e) {
+      fail(ODataJPATestConstants.EXCEPTION_MSG_PART_1 + e.getMessage() + 
ODataJPATestConstants.EXCEPTION_MSG_PART_2);
+    }
+  }
+
+  @Test
+  public void buildQueryNormalizeTest() {
+    EdmMapping mapping = (EdmMapping) mockNormalizedMapping();
+    try {
+      assertNotNull(builder.build((GetEntityUriInfo) mockURIInfo(mapping)));
+    } catch (ODataException e) {
+      fail(ODataJPATestConstants.EXCEPTION_MSG_PART_1 + e.getMessage() + 
ODataJPATestConstants.EXCEPTION_MSG_PART_2);
+    }
+  }
+  
   private UriInfo mockURIInfoWithListener(boolean isNavigationEnabled) throws 
EdmException {
     UriInfo uriInfo = EasyMock.createMock(UriInfo.class);
     if (isNavigationEnabled) {
@@ -206,13 +239,62 @@ public class JPAQueryBuilderTest {
     return uriInfo;
 
   }
+  
+  @SuppressWarnings("unchecked")
+  private UriInfo mockURIInfo(EdmMapping mapping) throws EdmException {
+    
+    UriInfo uriInfo = EasyMock.createMock(UriInfo.class);
+    List<NavigationSegment> navSegments = new ArrayList<NavigationSegment>();
+    
EasyMock.expect(uriInfo.getNavigationSegments()).andStubReturn(navSegments);
+    EdmEntityType edmEntityType = EasyMock.createMock(EdmEntityType.class);
+    EasyMock.expect(edmEntityType.getMapping()).andStubReturn(mapping);
+    EdmEntitySet edmEntitySet = EasyMock.createMock(EdmEntitySet.class);
+    EasyMock.expect(edmEntitySet.getEntityType()).andStubReturn(edmEntityType);
+    EasyMock.expect(uriInfo.getTargetEntitySet()).andStubReturn(edmEntitySet);
+    List<KeyPredicate> keyPreds =EasyMock.createMock(ArrayList.class);
+    EdmProperty edmProperty = EasyMock.createMock(EdmProperty.class);
+    EasyMock.expect(edmProperty.getMapping()).andStubReturn(mapping);
+    KeyPredicate keyPredicate = EasyMock.createMock(KeyPredicate.class);
+    EasyMock.expect(keyPredicate.getLiteral()).andReturn("Id").anyTimes();
+    
EasyMock.expect(keyPredicate.getProperty()).andReturn(edmProperty).anyTimes();
+    EasyMock.expect(keyPreds.size()).andStubReturn(1);
+    Iterator<KeyPredicate> keyPredicateitr =  
EasyMock.createMock(Iterator.class);
+    EasyMock.expect(keyPredicateitr.next()).andStubReturn(keyPredicate);
+    EasyMock.expect(keyPredicateitr.hasNext()).andStubReturn(true);
+    EasyMock.expect(keyPreds.iterator()).andStubReturn(keyPredicateitr);
+    EasyMock.expect(keyPreds.isEmpty()).andStubReturn(false);
+    EasyMock.expect(keyPreds.get(0)).andStubReturn(keyPredicate);
+    EasyMock.expect(uriInfo.getKeyPredicates()).andStubReturn(keyPreds); 
+    EasyMock.replay(edmEntityType, edmEntitySet, uriInfo, keyPredicate, 
keyPreds, edmProperty);
+    return uriInfo;
+
+  }
 
   private JPAEdmMapping mockEdmMapping() {
     JPAEdmMappingImpl mockedEdmMapping = new JPAEdmMappingImpl();
     
mockedEdmMapping.setODataJPATombstoneEntityListener(JPAQueryExtensionMock.class);
     return mockedEdmMapping;
   }
+  
+  private JPAEdmMapping mockMapping() {
+    JPAEdmMappingImpl mockedEdmMapping = new JPAEdmMappingImpl();
+    mockedEdmMapping.setInternalName("Customer");
+    return mockedEdmMapping;
+  }
+  
 
+  private JPAEdmMapping mockNormalizedMapping() {
+    JPAEdmMappingImpl mockedEdmMapping = new JPAEdmMappingImpl();
+    mockedEdmMapping.setInternalName("C1.Customer.Name");
+    return mockedEdmMapping;
+  }
+  
+  private JPAEdmMapping mockNormalizedValueMapping() {
+    JPAEdmMappingImpl mockedEdmMapping = new JPAEdmMappingImpl();
+    mockedEdmMapping.setInternalName("'C1.Customer.Name'");
+    return mockedEdmMapping;
+  }
+  
   public static final class JPAQueryExtensionMock extends 
ODataJPAQueryExtensionEntityListener {
     Query query = EasyMock.createMock(Query.class);
 

http://git-wip-us.apache.org/repos/asf/olingo-odata2/blob/6c7a6742/odata2-jpa-processor/jpa-core/src/test/java/org/apache/olingo/odata2/jpa/processor/core/mock/ODataJPAContextMock.java
----------------------------------------------------------------------
diff --git 
a/odata2-jpa-processor/jpa-core/src/test/java/org/apache/olingo/odata2/jpa/processor/core/mock/ODataJPAContextMock.java
 
b/odata2-jpa-processor/jpa-core/src/test/java/org/apache/olingo/odata2/jpa/processor/core/mock/ODataJPAContextMock.java
index 83cb0d3..cb59b6f 100644
--- 
a/odata2-jpa-processor/jpa-core/src/test/java/org/apache/olingo/odata2/jpa/processor/core/mock/ODataJPAContextMock.java
+++ 
b/odata2-jpa-processor/jpa-core/src/test/java/org/apache/olingo/odata2/jpa/processor/core/mock/ODataJPAContextMock.java
@@ -18,12 +18,18 @@
  
******************************************************************************/
 package org.apache.olingo.odata2.jpa.processor.core.mock;
 
+import java.util.HashSet;
+import java.util.Set;
+
 import javax.persistence.EntityManager;
 import javax.persistence.EntityManagerFactory;
+import javax.persistence.Query;
+import javax.persistence.metamodel.EntityType;
 import javax.persistence.metamodel.Metamodel;
 
 import org.apache.olingo.odata2.api.processor.ODataContext;
 import org.apache.olingo.odata2.jpa.processor.api.ODataJPAContext;
+import org.easymock.Capture;
 import org.easymock.EasyMock;
 
 public abstract class ODataJPAContextMock {
@@ -49,7 +55,7 @@ public abstract class ODataJPAContextMock {
     ODataJPAContext odataJPAContext = 
EasyMock.createMock(ODataJPAContext.class);
     
EasyMock.expect(odataJPAContext.getPersistenceUnitName()).andStubReturn(NAMESPACE);
     
EasyMock.expect(odataJPAContext.getEntityManagerFactory()).andReturn(mockEntityManagerFactory());
-    
EasyMock.expect(odataJPAContext.getEntityManager()).andReturn(mockEntityManager());
+    
EasyMock.expect(odataJPAContext.getEntityManager()).andStubReturn(mockEntityManager());
     
EasyMock.expect(odataJPAContext.getJPAEdmMappingModel()).andReturn(MAPPING_MODEL);
     EasyMock.expect(odataJPAContext.getJPAEdmExtension()).andReturn(null);
     EasyMock.expect(odataJPAContext.getDefaultNaming()).andReturn(true);
@@ -62,9 +68,15 @@ public abstract class ODataJPAContextMock {
 
   private static EntityManager mockEntityManager() {
     EntityManager em = EasyMock.createMock(EntityManager.class);
-    EasyMock.expect(em.getMetamodel()).andReturn(null);
+    Metamodel mm = EasyMock.createMock(Metamodel.class);
+    EasyMock.expect(em.getMetamodel()).andReturn(mm).anyTimes();
+    Set<EntityType<?>> et = new HashSet<EntityType<?>>();
+    EasyMock.expect(mm.getEntities()).andReturn(et).anyTimes();
     EasyMock.expect(em.isOpen()).andReturn(true).anyTimes();
-    EasyMock.replay(em);
+    Query jpqlquery = EasyMock.createMock(Query.class);
+    Capture<String> capturedArgument = new Capture<String>();
+    
EasyMock.expect(em.createQuery(EasyMock.capture(capturedArgument))).andReturn(jpqlquery);
+    EasyMock.replay(em,mm);
     return em;
 
   }

Reply via email to