Repository: olingo-odata4
Updated Branches:
  refs/heads/master 69ef9f519 -> 8674a1f29


[OLINGO-568] improved search in technical service

Signed-off-by: Christian Amend <[email protected]>


Project: http://git-wip-us.apache.org/repos/asf/olingo-odata4/repo
Commit: http://git-wip-us.apache.org/repos/asf/olingo-odata4/commit/8674a1f2
Tree: http://git-wip-us.apache.org/repos/asf/olingo-odata4/tree/8674a1f2
Diff: http://git-wip-us.apache.org/repos/asf/olingo-odata4/diff/8674a1f2

Branch: refs/heads/master
Commit: 8674a1f29919a9f2fe472cf4aa892344bb65e73f
Parents: 69ef9f5
Author: Klaus Straubinger <[email protected]>
Authored: Fri Nov 20 16:43:25 2015 +0100
Committer: Christian Amend <[email protected]>
Committed: Tue Nov 24 09:21:02 2015 +0100

----------------------------------------------------------------------
 .../tecsvc/client/SystemQueryOptionITCase.java  | 48 +++++-----
 .../processor/TechnicalEntityProcessor.java     |  7 +-
 .../TechnicalPrimitiveComplexProcessor.java     |  5 +-
 .../queryoptions/options/SearchHandler.java     | 97 +++++++++++++-------
 4 files changed, 94 insertions(+), 63 deletions(-)
----------------------------------------------------------------------


http://git-wip-us.apache.org/repos/asf/olingo-odata4/blob/8674a1f2/fit/src/test/java/org/apache/olingo/fit/tecsvc/client/SystemQueryOptionITCase.java
----------------------------------------------------------------------
diff --git 
a/fit/src/test/java/org/apache/olingo/fit/tecsvc/client/SystemQueryOptionITCase.java
 
b/fit/src/test/java/org/apache/olingo/fit/tecsvc/client/SystemQueryOptionITCase.java
index b330038..7ffa8a9 100644
--- 
a/fit/src/test/java/org/apache/olingo/fit/tecsvc/client/SystemQueryOptionITCase.java
+++ 
b/fit/src/test/java/org/apache/olingo/fit/tecsvc/client/SystemQueryOptionITCase.java
@@ -19,10 +19,11 @@
 package org.apache.olingo.fit.tecsvc.client;
 
 import static org.junit.Assert.assertEquals;
+import static org.junit.Assert.assertNull;
+import static org.junit.Assert.assertTrue;
 import static org.junit.Assert.fail;
 
 import java.net.URI;
-import java.util.List;
 
 import org.apache.olingo.client.api.communication.ODataClientErrorException;
 import 
org.apache.olingo.client.api.communication.request.retrieve.ODataEntitySetRequest;
@@ -83,7 +84,7 @@ public class SystemQueryOptionITCase extends 
AbstractParamTecSvcITCase {
 
     for (int i = 0; i < 5; i++) {
       ClientEntity entity = response.getBody().getEntities().get(i);
-      assertEquals(new Integer(i + 1).toString(), 
entity.getProperty(PROPERTY_INT16).getValue().toString());
+      assertShortOrInt(i + 1, 
entity.getProperty(PROPERTY_INT16).getPrimitiveValue().toValue());
     }
   }
 
@@ -102,7 +103,7 @@ public class SystemQueryOptionITCase extends 
AbstractParamTecSvcITCase {
 
     for (int i = 0; i < 10; i++) {
       ClientEntity entity = response.getBody().getEntities().get(i);
-      assertEquals(new Integer(i + 6).toString(), 
entity.getProperty(PROPERTY_INT16).getValue().toString());
+      assertShortOrInt(i + 6, 
entity.getProperty(PROPERTY_INT16).getPrimitiveValue().toValue());
     }
   }
 
@@ -118,7 +119,7 @@ public class SystemQueryOptionITCase extends 
AbstractParamTecSvcITCase {
     ODataRetrieveResponse<ClientEntitySet> response = request.execute();
     saveCookieHeader(response);
 
-    assertEquals(0, response.getBody().getEntities().size());
+    assertTrue(response.getBody().getEntities().isEmpty());
   }
 
   @Test
@@ -132,15 +133,16 @@ public class SystemQueryOptionITCase extends 
AbstractParamTecSvcITCase {
     ODataRetrieveResponse<ClientEntitySet> response = request.execute();
     saveCookieHeader(response);
 
-    assertEquals(0, response.getBody().getEntities().size());
+    assertTrue(response.getBody().getEntities().isEmpty());
   }
 
   @Test
-  public void filterWithTopSkipOrderByAndServerSidePaging() {
+  public void searchAndFilterWithTopSkipOrderByAndServerSidePaging() {
     ODataEntitySetRequest<ClientEntitySet> request = 
getClient().getRetrieveRequestFactory()
         .getEntitySetRequest(getClient().newURIBuilder(SERVICE_URI)
             .appendEntitySetSegment(ES_SERVER_SIDE_PAGING)
-            .filter("PropertyInt16 le 105") // 1, 2, ... , 105
+            .search("\"Number:\" AND NOT \"106\"") // 1, 2, ..., 105, 107, ...
+            .filter("PropertyInt16 le 106") // 1, 2, ..., 105
             .orderBy("PropertyInt16 desc") // 105, 104, ..., 2, 1
             .count(true) // 105
             .skip(3) // 102, 101, ..., 2, 1
@@ -155,14 +157,14 @@ public class SystemQueryOptionITCase extends 
AbstractParamTecSvcITCase {
 
     int id = 102;
 
-    // Check first 10 entities
+    // Check first 10 entities.
     for (int i = 0; i < 10; i++) {
       ClientEntity entity = response.getBody().getEntities().get(i);
-      assertEquals(new Integer(id).toString(), 
entity.getProperty(PROPERTY_INT16).getValue().toString());
+      assertShortOrInt(id, 
entity.getProperty(PROPERTY_INT16).getPrimitiveValue().toValue());
       id--;
     }
 
-    // Get 3 * 10 = 30 Entities and check the key
+    // Get 3 * 10 = 30 Entities and check the key.
     for (int j = 0; j < 3; j++) {
       request = 
getClient().getRetrieveRequestFactory().getEntitySetRequest(response.getBody().getNext());
       setCookieHeader(request);
@@ -172,12 +174,12 @@ public class SystemQueryOptionITCase extends 
AbstractParamTecSvcITCase {
       assertEquals(10, response.getBody().getEntities().size());
       for (int i = 0; i < 10; i++) {
         ClientEntity entity = response.getBody().getEntities().get(i);
-        assertEquals(new Integer(id).toString(), 
entity.getProperty(PROPERTY_INT16).getValue().toString());
+        assertShortOrInt(id, 
entity.getProperty(PROPERTY_INT16).getPrimitiveValue().toValue());
         id--;
       }
     }
 
-    // Get the last 3 items
+    // Get the last 3 items.
     request = 
getClient().getRetrieveRequestFactory().getEntitySetRequest(response.getBody().getNext());
     setCookieHeader(request);
     response = request.execute();
@@ -186,12 +188,12 @@ public class SystemQueryOptionITCase extends 
AbstractParamTecSvcITCase {
     assertEquals(3, response.getBody().getEntities().size());
     for (int i = 0; i < 3; i++) {
       ClientEntity entity = response.getBody().getEntities().get(i);
-      assertEquals(new Integer(id).toString(), 
entity.getProperty(PROPERTY_INT16).getValue().toString());
+      assertShortOrInt(id, 
entity.getProperty(PROPERTY_INT16).getPrimitiveValue().toValue());
       id--;
     }
 
     // Make sure that the body no not contain a next link
-    assertEquals(null, response.getBody().getNext());
+    assertNull(response.getBody().getNext());
   }
 
   @Test
@@ -299,7 +301,7 @@ public class SystemQueryOptionITCase extends 
AbstractParamTecSvcITCase {
       assertEquals(HttpStatusCode.BAD_REQUEST.getStatusCode(), 
e.getStatusLine().getStatusCode());
     }
   }
-  
+
   @Test
   public void basicSearch() {
     ODataEntitySetRequest<ClientEntitySet> request = 
getClient().getRetrieveRequestFactory()
@@ -308,9 +310,9 @@ public class SystemQueryOptionITCase extends 
AbstractParamTecSvcITCase {
             .search("Second")
             .build());
     setCookieHeader(request);
-    ODataRetrieveResponse<ClientEntitySet> response = request.execute();
-    List<ClientEntity> entities = response.getBody().getEntities();
-    assertEquals(1, entities.size());
+    final ODataRetrieveResponse<ClientEntitySet> response = request.execute();
+    saveCookieHeader(response);
+    assertEquals(1, response.getBody().getEntities().size());
   }
 
   @Test
@@ -321,9 +323,9 @@ public class SystemQueryOptionITCase extends 
AbstractParamTecSvcITCase {
             .search("Second AND positive")
             .build());
     setCookieHeader(request);
-    ODataRetrieveResponse<ClientEntitySet> response = request.execute();
-    List<ClientEntity> entities = response.getBody().getEntities();
-    assertEquals(0, entities.size());
+    final ODataRetrieveResponse<ClientEntitySet> response = request.execute();
+    saveCookieHeader(response);
+    assertTrue(response.getBody().getEntities().isEmpty());
   }
 
   @Test
@@ -335,7 +337,7 @@ public class SystemQueryOptionITCase extends 
AbstractParamTecSvcITCase {
             .build());
     setCookieHeader(request);
     ODataRetrieveResponse<ClientEntitySet> response = request.execute();
-    List<ClientEntity> entities = response.getBody().getEntities();
-    assertEquals(2, entities.size());
+    saveCookieHeader(response);
+    assertEquals(2, response.getBody().getEntities().size());
   }
 }

http://git-wip-us.apache.org/repos/asf/olingo-odata4/blob/8674a1f2/lib/server-tecsvc/src/main/java/org/apache/olingo/server/tecsvc/processor/TechnicalEntityProcessor.java
----------------------------------------------------------------------
diff --git 
a/lib/server-tecsvc/src/main/java/org/apache/olingo/server/tecsvc/processor/TechnicalEntityProcessor.java
 
b/lib/server-tecsvc/src/main/java/org/apache/olingo/server/tecsvc/processor/TechnicalEntityProcessor.java
index 923bf29..6d7c41e 100644
--- 
a/lib/server-tecsvc/src/main/java/org/apache/olingo/server/tecsvc/processor/TechnicalEntityProcessor.java
+++ 
b/lib/server-tecsvc/src/main/java/org/apache/olingo/server/tecsvc/processor/TechnicalEntityProcessor.java
@@ -471,23 +471,22 @@ public class TechnicalEntityProcessor extends 
TechnicalProcessor
         edmEntitySet.getEntityType();
 
     EntityCollection entitySetInitial = readEntityCollection(uriInfo);
-
     if (entitySetInitial == null) {
       entitySetInitial = new EntityCollection();
     }
 
     // Modifying the original entitySet means modifying the "database", so we 
have to make a shallow
-    // copy of the entity set (new EntitySet, but exactly the same data)
+    // copy of the entity set (new EntitySet, but exactly the same data).
     EntityCollection entitySet = new EntityCollection();
     entitySet.getEntities().addAll(entitySetInitial.getEntities());
 
-    // Apply system query options
+    // Apply system query options.
+    SearchHandler.applySearchSystemQueryOption(uriInfo.getSearchOption(), 
entitySet);
     FilterHandler.applyFilterSystemQuery(uriInfo.getFilterOption(), entitySet, 
uriInfo, serviceMetadata.getEdm());
     CountHandler.applyCountSystemQueryOption(uriInfo.getCountOption(), 
entitySet);
     OrderByHandler.applyOrderByOption(uriInfo.getOrderByOption(), entitySet, 
uriInfo, serviceMetadata.getEdm());
     SkipHandler.applySkipSystemQueryHandler(uriInfo.getSkipOption(), 
entitySet);
     TopHandler.applyTopSystemQueryOption(uriInfo.getTopOption(), entitySet);
-    SearchHandler.applySearchSystemQueryOption(uriInfo.getSearchOption(), 
entitySet);
 
     final Integer pageSize = 
odata.createPreferences(request.getHeaders(HttpHeader.PREFER)).getMaxPageSize();
     final Integer serverPageSize = 
ServerSidePagingHandler.applyServerSidePaging(uriInfo.getSkipTokenOption(),

http://git-wip-us.apache.org/repos/asf/olingo-odata4/blob/8674a1f2/lib/server-tecsvc/src/main/java/org/apache/olingo/server/tecsvc/processor/TechnicalPrimitiveComplexProcessor.java
----------------------------------------------------------------------
diff --git 
a/lib/server-tecsvc/src/main/java/org/apache/olingo/server/tecsvc/processor/TechnicalPrimitiveComplexProcessor.java
 
b/lib/server-tecsvc/src/main/java/org/apache/olingo/server/tecsvc/processor/TechnicalPrimitiveComplexProcessor.java
index 87fbf00..f97b7eb 100644
--- 
a/lib/server-tecsvc/src/main/java/org/apache/olingo/server/tecsvc/processor/TechnicalPrimitiveComplexProcessor.java
+++ 
b/lib/server-tecsvc/src/main/java/org/apache/olingo/server/tecsvc/processor/TechnicalPrimitiveComplexProcessor.java
@@ -47,8 +47,8 @@ import org.apache.olingo.server.api.ODataRequest;
 import org.apache.olingo.server.api.ODataResponse;
 import org.apache.olingo.server.api.ServiceMetadata;
 import org.apache.olingo.server.api.deserializer.FixedFormatDeserializer;
-import org.apache.olingo.server.api.prefer.PreferencesApplied;
 import org.apache.olingo.server.api.prefer.Preferences.Return;
+import org.apache.olingo.server.api.prefer.PreferencesApplied;
 import org.apache.olingo.server.api.processor.ComplexCollectionProcessor;
 import org.apache.olingo.server.api.processor.ComplexProcessor;
 import org.apache.olingo.server.api.processor.CountComplexCollectionProcessor;
@@ -226,6 +226,9 @@ public class TechnicalPrimitiveComplexProcessor extends 
TechnicalProcessor
             ((UriResourceFunction) resourceParts.get(0)).getParameters(), 
resource), path) :
         getPropertyData(entity, path);
 
+    // TODO: implement filter on collection properties (on a shallow copy of 
the values)
+    // FilterHandler.applyFilterSystemQuery(uriInfo.getFilterOption(), 
property, uriInfo, serviceMetadata.getEdm());
+
     if (property == null && representationType != RepresentationType.COUNT) {
       if (representationType == RepresentationType.VALUE) {
         response.setStatusCode(HttpStatusCode.NO_CONTENT.getStatusCode());

http://git-wip-us.apache.org/repos/asf/olingo-odata4/blob/8674a1f2/lib/server-tecsvc/src/main/java/org/apache/olingo/server/tecsvc/processor/queryoptions/options/SearchHandler.java
----------------------------------------------------------------------
diff --git 
a/lib/server-tecsvc/src/main/java/org/apache/olingo/server/tecsvc/processor/queryoptions/options/SearchHandler.java
 
b/lib/server-tecsvc/src/main/java/org/apache/olingo/server/tecsvc/processor/queryoptions/options/SearchHandler.java
index ccc1658..78b6a3b 100644
--- 
a/lib/server-tecsvc/src/main/java/org/apache/olingo/server/tecsvc/processor/queryoptions/options/SearchHandler.java
+++ 
b/lib/server-tecsvc/src/main/java/org/apache/olingo/server/tecsvc/processor/queryoptions/options/SearchHandler.java
@@ -18,6 +18,13 @@
  */
 package org.apache.olingo.server.tecsvc.processor.queryoptions.options;
 
+import java.util.Calendar;
+import java.util.Iterator;
+import java.util.ListIterator;
+import java.util.Locale;
+
+import javax.xml.bind.DatatypeConverter;
+
 import org.apache.olingo.commons.api.data.Entity;
 import org.apache.olingo.commons.api.data.EntityCollection;
 import org.apache.olingo.commons.api.data.Property;
@@ -29,64 +36,83 @@ import 
org.apache.olingo.server.api.uri.queryoption.search.SearchBinaryOperatorK
 import org.apache.olingo.server.api.uri.queryoption.search.SearchExpression;
 import org.apache.olingo.server.api.uri.queryoption.search.SearchTerm;
 
-import javax.xml.bind.DatatypeConverter;
-import java.text.SimpleDateFormat;
-import java.util.Calendar;
-import java.util.Date;
-import java.util.Iterator;
-import java.util.ListIterator;
-import java.util.Locale;
-
 public class SearchHandler {
-  private static SimpleDateFormat SIMPLE_DATE_FORMAT = new 
SimpleDateFormat("yyyy-MM-dd'T'HH:mm:ss.SSSZ");
 
-  public static void applySearchSystemQueryOption(final SearchOption 
searchOption, final EntityCollection entitySet)
+  public static void applySearchSystemQueryOption(final SearchOption 
searchOption, EntityCollection entitySet)
       throws ODataApplicationException {
-
     if (searchOption != null) {
       SearchExpression se = searchOption.getSearchExpression();
       Iterator<Entity> it = entitySet.getEntities().iterator();
-      while(it.hasNext()) {
+      while (it.hasNext()) {
         boolean keep = false;
         Entity entity = it.next();
         ListIterator<Property> properties = 
entity.getProperties().listIterator();
-        while(properties.hasNext() && !keep) {
+        while (properties.hasNext() && !keep) {
           keep = isTrue(se, properties.next());
         }
-        if(!keep) {
+        if (!keep) {
           it.remove();
         }
       }
     }
   }
 
-  private static boolean isTrue(SearchTerm term, Property property) {
-    if(property.isPrimitive() && !property.isNull()) {
-      String propertyString = asString(property);
-      return propertyString != null && 
propertyString.contains(term.getSearchTerm());
+  private static boolean isTrue(final SearchTerm term, final Property 
property) {
+    if (property.isNull()) {
+      return false;
+    } else if (property.isPrimitive()) {
+      if (property.isCollection()) {
+        for (final Object primitive : property.asCollection()) {
+          final String propertyString = asString(primitive);
+          if (propertyString != null && 
propertyString.contains(term.getSearchTerm())) {
+            return true;
+          }
+        }
+        return false;
+      } else {
+        final String propertyString = asString(property.asPrimitive());
+        return propertyString != null && 
propertyString.contains(term.getSearchTerm());
+      }
+    } else if (property.isComplex()) {
+      if (property.isCollection()) {
+        for (final Object member : property.asCollection()) {
+          if (isTrue(term, (Property) member)) {
+            return true;
+          }
+        }
+        return false;
+      } else {
+        for (final Property innerProperty : property.asComplex().getValue()) {
+          if (isTrue(term, innerProperty)) {
+            return true;
+          }
+        }
+        return false;
+      }
+    } else {
+      return false;
     }
-    return false;
   }
 
-  private static String asString(Property property) {
-    // TODO: mibo(151117): improve 'string' conversion
-    Object primitive = property.asPrimitive();
-    if(primitive instanceof Calendar) {
-      return SIMPLE_DATE_FORMAT.format(((Calendar) primitive).getTime());
-    } else if(primitive instanceof Date) {
-      return SIMPLE_DATE_FORMAT.format((Date) primitive);
-    } else if(primitive instanceof byte[]) {
+  private static String asString(final Object primitive) {
+    // TODO: improve 'string' conversion; maybe consider only String properties
+    if (primitive instanceof String) {
+      return (String) primitive;
+    } else if (primitive instanceof Calendar) {
+      return DatatypeConverter.printDateTime((Calendar) primitive);
+    } else if (primitive instanceof byte[]) {
       return DatatypeConverter.printBase64Binary((byte[]) primitive);
+    } else {
+      return primitive.toString();
     }
-    return primitive.toString();
   }
 
-  private static boolean isTrue(SearchBinary binary, Property property) throws 
ODataApplicationException {
+  private static boolean isTrue(final SearchBinary binary, final Property 
property) throws ODataApplicationException {
     SearchExpression left = binary.getLeftOperand();
     SearchExpression right = binary.getRightOperand();
-    if(binary.getOperator() == SearchBinaryOperatorKind.AND) {
+    if (binary.getOperator() == SearchBinaryOperatorKind.AND) {
       return isTrue(left, property) && isTrue(right, property);
-    } else if(binary.getOperator() == SearchBinaryOperatorKind.OR) {
+    } else if (binary.getOperator() == SearchBinaryOperatorKind.OR) {
       return isTrue(left, property) || isTrue(right, property);
     } else {
       throw new ODataApplicationException("Found unknown 
SearchBinaryOperatorKind: " + binary.getOperator(),
@@ -94,12 +120,13 @@ public class SearchHandler {
     }
   }
 
-  private static boolean isTrue(SearchExpression searchExpression, Property 
property) throws ODataApplicationException {
-    if(searchExpression.isSearchBinary()) {
+  private static boolean isTrue(final SearchExpression searchExpression, final 
Property property)
+      throws ODataApplicationException {
+    if (searchExpression.isSearchBinary()) {
       return isTrue(searchExpression.asSearchBinary(), property);
-    } else if(searchExpression.isSearchTerm()) {
+    } else if (searchExpression.isSearchTerm()) {
       return isTrue(searchExpression.asSearchTerm(), property);
-    } else if(searchExpression.isSearchUnary()) {
+    } else if (searchExpression.isSearchUnary()) {
       return !isTrue(searchExpression.asSearchUnary().getOperand(), property);
     }
     throw new ODataApplicationException("Found unknown SearchExpression: " + 
searchExpression,

Reply via email to