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/07/08 13:54:17 UTC

[1/2] git commit: [OLINGO-317] Integration into tecsvc

Repository: olingo-odata4
Updated Branches:
  refs/heads/master b3cfc3510 -> 45b7289f8


[OLINGO-317] Integration into tecsvc


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

Branch: refs/heads/master
Commit: 3ca91891bd1986c918a9c5418c0ae0b09d80687f
Parents: d860717
Author: Michael Bolz <mi...@sap.com>
Authored: Tue Jul 8 09:18:01 2014 +0200
Committer: Michael Bolz <mi...@sap.com>
Committed: Tue Jul 8 09:18:14 2014 +0200

----------------------------------------------------------------------
 .../core/serializer/json/JsonDataProvider.java  |  46 +++
 .../json/ODataJsonSerializerTest.java           |  28 +-
 .../olingo/server/tecsvc/TechnicalServlet.java  |  27 +-
 .../olingo/server/tecsvc/data/DataProvider.java |  25 +-
 .../server/tecsvc/data/JefDataProvider.java     | 349 +++++++++++++++++++
 .../tecsvc/processor/SampleJsonProcessor.java   | 229 ------------
 .../tecsvc/processor/TechnicalProcessor.java    | 132 ++++++-
 .../tecsvc/provider/PropertyProvider.java       |   3 +
 .../src/main/resources/ESAllPrim.json           |  56 +++
 .../src/main/resources/ESCollAllPrim.json       |  59 ++++
 .../src/main/resources/ESCompAllPrim.json       |  65 ++++
 .../src/main/resources/ESMixPrimCollComp.json   |  68 ++++
 .../src/main/resources/ESTwoPrim.json           |   1 +
 .../tecsvc/data/JsonDataProviderTest.java       | 186 ++++++++++
 .../olingo/server/tecsvc/data/StringHelper.java | 206 +++++++++++
 15 files changed, 1202 insertions(+), 278 deletions(-)
----------------------------------------------------------------------


http://git-wip-us.apache.org/repos/asf/olingo-odata4/blob/3ca91891/lib/server-core/src/test/java/org/apache/olingo/server/core/serializer/json/JsonDataProvider.java
----------------------------------------------------------------------
diff --git a/lib/server-core/src/test/java/org/apache/olingo/server/core/serializer/json/JsonDataProvider.java b/lib/server-core/src/test/java/org/apache/olingo/server/core/serializer/json/JsonDataProvider.java
new file mode 100644
index 0000000..0a4cf73
--- /dev/null
+++ b/lib/server-core/src/test/java/org/apache/olingo/server/core/serializer/json/JsonDataProvider.java
@@ -0,0 +1,46 @@
+/*
+ * 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.server.core.serializer.json;
+
+import org.apache.olingo.commons.api.data.Entity;
+import org.apache.olingo.commons.api.data.EntitySet;
+import org.apache.olingo.commons.api.data.ResWrap;
+import org.apache.olingo.commons.api.edm.constants.ODataServiceVersion;
+import org.apache.olingo.commons.api.serialization.ODataDeserializerException;
+import org.apache.olingo.commons.core.serialization.JsonDeserializer;
+import org.junit.Test;
+
+import java.io.FileInputStream;
+import java.io.FileNotFoundException;
+
+/**
+ */
+public class JsonDataProvider {
+  @Test
+  public void testMe() throws Exception {
+    FileInputStream fis = new FileInputStream("/tmp/ESAllPrim.json");
+    ResWrap<EntitySet> wrapper = new JsonDeserializer(ODataServiceVersion.V40, true).toEntitySet(fis);
+    EntitySet es = wrapper.getPayload();
+    for (Entity entity : es.getEntities()) {
+      System.out.println(entity);
+    }
+
+    ODataJsonSerializer serializer = new ODataJsonSerializer();
+  }
+}

http://git-wip-us.apache.org/repos/asf/olingo-odata4/blob/3ca91891/lib/server-core/src/test/java/org/apache/olingo/server/core/serializer/json/ODataJsonSerializerTest.java
----------------------------------------------------------------------
diff --git a/lib/server-core/src/test/java/org/apache/olingo/server/core/serializer/json/ODataJsonSerializerTest.java b/lib/server-core/src/test/java/org/apache/olingo/server/core/serializer/json/ODataJsonSerializerTest.java
index ec2619b..91e49b9 100644
--- a/lib/server-core/src/test/java/org/apache/olingo/server/core/serializer/json/ODataJsonSerializerTest.java
+++ b/lib/server-core/src/test/java/org/apache/olingo/server/core/serializer/json/ODataJsonSerializerTest.java
@@ -337,8 +337,8 @@ public class ODataJsonSerializerTest {
         "\"PropertyDecimal\":4711.1174," +
         "\"PropertyBinary\":\"BAcBAQ==\"," +
         "\"PropertyDate\":\"2014-03-19\"," +
-        "\"PropertyDateTimeOffset\":\"2014-03-19T10:12:00Z\"," +
-        "\"PropertyDuration\":\"P16148425DT0S\"," +
+        "\"PropertyDateTimeOffset\":\"2014-03-19T10:12:00+01:00\"," +
+        "\"PropertyDuration\":\"P16148383DT8H0S\"," +
         "\"PropertyGuid\":\"0000aaaa-00bb-00cc-00dd-000000ffffff\"," +
         "\"PropertyTimeOfDay\":\"10:12:00\"" +
         "}";
@@ -396,8 +396,8 @@ public class ODataJsonSerializerTest {
         "\"CollPropertyDecimal\":[4711.1174,1174.4711]," +
         "\"CollPropertyBinary\":[\"BAcBAQ==\",\"dGVzdA==\"]," +
         "\"CollPropertyDate\":[\"2014-03-19\",\"2014-07-02\"]," +
-        "\"CollPropertyDateTimeOffset\":[\"2014-03-19T10:12:00Z\",\"2014-07-02T13:30:00Z\"]," +
-        "\"CollPropertyDuration\":[\"P16148425DT0S\",\"P16253562DT12H0S\"]," +
+        "\"CollPropertyDateTimeOffset\":[\"2014-03-19T10:12:00+01:00\",\"2014-07-02T13:30:00+02:00\"]," +
+        "\"CollPropertyDuration\":[\"P16148383DT8H0S\",\"P16253479DT4H0S\"]," +
         "\"CollPropertyGuid\":[\"0000aaaa-00bb-00cc-00dd-000000ffffff\",\"0000ffff-00dd-00cc-00bb-000000aaaaaa\"]," +
         "\"CollPropertyTimeOfDay\":[\"10:12:00\",\"13:30:00\"]" +
         "}";
@@ -433,8 +433,8 @@ public class ODataJsonSerializerTest {
         "\"PropertyDecimal\":4711.1174," +
         "\"PropertyBinary\":\"BAcBAQ==\"," +
         "\"PropertyDate\":\"2014-03-19\"," +
-        "\"PropertyDateTimeOffset\":\"2014-03-19T10:12:00Z\"," +
-        "\"PropertyDuration\":\"P16148425DT0S\"," +
+        "\"PropertyDateTimeOffset\":\"2014-03-19T10:12:00+01:00\"," +
+        "\"PropertyDuration\":\"P16148383DT8H0S\"," +
         "\"PropertyGuid\":\"0000aaaa-00bb-00cc-00dd-000000ffffff\"," +
         "\"PropertyTimeOfDay\":\"10:12:00\"" +
         "}}";
@@ -455,10 +455,10 @@ public class ODataJsonSerializerTest {
 
   private Entity createETCollAllPrim(int id) {
     Entity entity = new EntityImpl();
-    Calendar date = createCalendarInstance();
+    Calendar date = Calendar.getInstance();
     date.set(2014, Calendar.MARCH, 19, 10, 12, 0);
     date.set(Calendar.MILLISECOND, 0);
-    Calendar date2 = createCalendarInstance();
+    Calendar date2 = Calendar.getInstance();
     date2.set(2014, Calendar.JULY, 2, 13, 30, 0);
     date2.set(Calendar.MILLISECOND, 0);
     //
@@ -489,7 +489,7 @@ public class ODataJsonSerializerTest {
     entity.addProperty(createProperty("Collection(Edm.Date)", TecSvcSimpleProperty.Collection_Date,
             ValueType.COLLECTION_PRIMITIVE, date, date2));
     entity.addProperty(createProperty("Collection(Edm.DateTimeOffset)", TecSvcSimpleProperty.Collection_DateTimeOffset,
-            ValueType.COLLECTION_PRIMITIVE, date, date2));
+            ValueType.COLLECTION_PRIMITIVE, date.getTime(), date2.getTime()));
     entity.addProperty(createProperty("Collection(Edm.Duration)", TecSvcSimpleProperty.Collection_Duration,
             ValueType.COLLECTION_PRIMITIVE, date.getTimeInMillis(), date2.getTimeInMillis()));
     entity.addProperty(createProperty("Collection(Edm.Guid)", TecSvcSimpleProperty.Collection_Guid,
@@ -503,7 +503,7 @@ public class ODataJsonSerializerTest {
 
   private Entity createETAllPrim(int id) {
     Entity entity = new EntityImpl();
-    Calendar date = createCalendarInstance();
+    Calendar date = Calendar.getInstance();
     date.set(2014, Calendar.MARCH, 19, 10, 12, 0);
     date.set(Calendar.MILLISECOND, 0);
     entity.addProperty(createProperty("Edm.Int16", TecSvcSimpleProperty.Int16, ValueType.PRIMITIVE, id));
@@ -522,7 +522,7 @@ public class ODataJsonSerializerTest {
         new byte[]{0x04, 0x07, 0x01, 0x01}));
     entity.addProperty(createProperty("Edm.Date", TecSvcSimpleProperty.Date, ValueType.PRIMITIVE, date));
     entity.addProperty(createProperty("Edm.DateTimeOffset", TecSvcSimpleProperty.DateTimeOffset, ValueType.PRIMITIVE,
-        date));
+        date.getTime()));
     entity.addProperty(createProperty("Edm.Duration", TecSvcSimpleProperty.Duration, ValueType.PRIMITIVE,
         date.getTimeInMillis()));
     entity.addProperty(createProperty("Edm.Guid", TecSvcSimpleProperty.Guid, ValueType.PRIMITIVE,
@@ -531,12 +531,6 @@ public class ODataJsonSerializerTest {
     return entity;
   }
 
-  private Calendar createCalendarInstance() {
-    Calendar cal = Calendar.getInstance(TimeZone.getTimeZone("GMT"), Locale.ENGLISH);
-    cal.set(Calendar.ZONE_OFFSET, 0);
-    return cal;
-  }
-
   private String streamToString(InputStream result) throws IOException {
     byte[] buffer = new byte[8192];
     StringBuilder sb = new StringBuilder();

http://git-wip-us.apache.org/repos/asf/olingo-odata4/blob/3ca91891/lib/server-tecsvc/src/main/java/org/apache/olingo/server/tecsvc/TechnicalServlet.java
----------------------------------------------------------------------
diff --git a/lib/server-tecsvc/src/main/java/org/apache/olingo/server/tecsvc/TechnicalServlet.java b/lib/server-tecsvc/src/main/java/org/apache/olingo/server/tecsvc/TechnicalServlet.java
index 5d4e463..ddddca8 100644
--- a/lib/server-tecsvc/src/main/java/org/apache/olingo/server/tecsvc/TechnicalServlet.java
+++ b/lib/server-tecsvc/src/main/java/org/apache/olingo/server/tecsvc/TechnicalServlet.java
@@ -18,22 +18,22 @@
  */
 package org.apache.olingo.server.tecsvc;
 
-import java.io.IOException;
-
-import javax.servlet.ServletException;
-import javax.servlet.http.HttpServlet;
-import javax.servlet.http.HttpServletRequest;
-import javax.servlet.http.HttpServletResponse;
-
 import org.apache.olingo.commons.api.edm.Edm;
 import org.apache.olingo.server.api.OData;
 import org.apache.olingo.server.api.ODataHttpHandler;
 import org.apache.olingo.server.tecsvc.data.DataProvider;
-import org.apache.olingo.server.tecsvc.processor.SampleJsonProcessor;
+import org.apache.olingo.server.tecsvc.data.JefDataProvider;
+import org.apache.olingo.server.tecsvc.processor.TechnicalProcessor;
 import org.apache.olingo.server.tecsvc.provider.EdmTechProvider;
 import org.slf4j.Logger;
 import org.slf4j.LoggerFactory;
 
+import javax.servlet.ServletException;
+import javax.servlet.http.HttpServlet;
+import javax.servlet.http.HttpServletRequest;
+import javax.servlet.http.HttpServletResponse;
+import java.io.IOException;
+
 public class TechnicalServlet extends HttpServlet {
 
   private static final long serialVersionUID = 1L;
@@ -45,19 +45,18 @@ public class TechnicalServlet extends HttpServlet {
   protected void service(final HttpServletRequest req, final HttpServletResponse resp) throws ServletException,
       IOException {
     try {
+      OData odata = OData.newInstance();
+      Edm edm = odata.createEdm(new EdmTechProvider());
+
       if (dataProvider == null) {
-        dataProvider = new DataProvider();
+        dataProvider = new JefDataProvider(edm);
       }
-
       dataProvider.reset();
 
-      OData odata = OData.newInstance();
-      Edm edm = odata.createEdm(new EdmTechProvider());
 
       ODataHttpHandler handler = odata.createHandler(edm);
 
-//    handler.register(new TechnicalProcessor(dataProvider));
-      handler.register(new SampleJsonProcessor());
+      handler.register(new TechnicalProcessor(dataProvider));
 
       handler.process(req, resp);
     } catch (Exception e) {

http://git-wip-us.apache.org/repos/asf/olingo-odata4/blob/3ca91891/lib/server-tecsvc/src/main/java/org/apache/olingo/server/tecsvc/data/DataProvider.java
----------------------------------------------------------------------
diff --git a/lib/server-tecsvc/src/main/java/org/apache/olingo/server/tecsvc/data/DataProvider.java b/lib/server-tecsvc/src/main/java/org/apache/olingo/server/tecsvc/data/DataProvider.java
index 2281ac7..820ae3a 100644
--- a/lib/server-tecsvc/src/main/java/org/apache/olingo/server/tecsvc/data/DataProvider.java
+++ b/lib/server-tecsvc/src/main/java/org/apache/olingo/server/tecsvc/data/DataProvider.java
@@ -6,9 +6,9 @@
  * 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
@@ -18,11 +18,24 @@
  */
 package org.apache.olingo.server.tecsvc.data;
 
-public class DataProvider {
+import org.apache.olingo.commons.api.data.Entity;
+import org.apache.olingo.commons.api.data.EntitySet;
 
-  public void reset() {
-    // TODO Auto-generated method stub
 
-  }
+public interface DataProvider {
+  void reset() throws DataProviderException;
+
+  EntitySet readAll(String entitySetName) throws DataProviderException;
+
+  Entity read(String entitySetName, Object ... keys) throws DataProviderException;
 
+  static class DataProviderException extends Exception {
+    public DataProviderException(String message, Throwable throwable) {
+      super(message, throwable);
+    }
+
+    public DataProviderException(String message) {
+      super(message);
+    }
+  }
 }

http://git-wip-us.apache.org/repos/asf/olingo-odata4/blob/3ca91891/lib/server-tecsvc/src/main/java/org/apache/olingo/server/tecsvc/data/JefDataProvider.java
----------------------------------------------------------------------
diff --git a/lib/server-tecsvc/src/main/java/org/apache/olingo/server/tecsvc/data/JefDataProvider.java b/lib/server-tecsvc/src/main/java/org/apache/olingo/server/tecsvc/data/JefDataProvider.java
new file mode 100644
index 0000000..18f4cb7
--- /dev/null
+++ b/lib/server-tecsvc/src/main/java/org/apache/olingo/server/tecsvc/data/JefDataProvider.java
@@ -0,0 +1,349 @@
+/*
+ * 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.server.tecsvc.data;
+
+import org.apache.olingo.commons.api.data.*;
+import org.apache.olingo.commons.api.edm.*;
+import org.apache.olingo.commons.api.edm.constants.ODataServiceVersion;
+import org.apache.olingo.commons.api.serialization.ODataDeserializerException;
+import org.apache.olingo.commons.core.data.EntityImpl;
+import org.apache.olingo.commons.core.data.EntitySetImpl;
+import org.apache.olingo.commons.core.data.LinkedComplexValueImpl;
+import org.apache.olingo.commons.core.data.PropertyImpl;
+import org.apache.olingo.commons.core.edm.primitivetype.EdmPrimitiveTypeFactory;
+import org.apache.olingo.commons.core.serialization.JsonDeserializer;
+import org.apache.olingo.server.tecsvc.provider.ContainerProvider;
+
+import java.io.InputStream;
+import java.util.ArrayList;
+import java.util.Arrays;
+import java.util.Collection;
+import java.util.Collections;
+import java.util.HashMap;
+import java.util.List;
+import java.util.Map;
+
+/**
+ */
+public class JefDataProvider implements DataProvider {
+
+  private final Edm edm;
+  private final Map<String, EntitySetContainer> esName2esContainer = new HashMap<String, EntitySetContainer>();
+
+  public JefDataProvider(Edm edm) {
+    this.edm = edm;
+  }
+
+  @Override
+  public void reset() throws DataProviderException {
+    initialize("ESAllPrim");
+    initialize("ESCompAllPrim");
+    initialize("ESCollAllPrim");
+    initialize("ESCollAllPrim");
+  }
+
+  @Override
+  public Entity read(String entitySetName, Object ... keys) throws DataProviderException {
+    EntitySetContainer container = esName2esContainer.get(entitySetName);
+    if(container == null) {
+      container = initialize(entitySetName);
+    }
+    return container.getEntity(keys);
+  }
+
+  @Override
+  public EntitySet readAll(String entitySetName) throws DataProviderException {
+    try {
+      EdmEntitySet edmEntitySet = edm.getEntityContainer(ContainerProvider.nameContainer).getEntitySet(entitySetName);
+      return createEntitySetContainer(edmEntitySet).getEntitySet();
+    } catch (ODataDeserializerException e) {
+      throw new DataProviderException("Failure during reset/createEntitySetContainer", e);
+    }
+  }
+
+  private EntitySetContainer initialize(String entitySetName) throws DataProviderException {
+    try {
+      EdmEntityContainer edmEntityContainer = edm.getEntityContainer(ContainerProvider.nameContainer);
+      EntitySetContainer entitySetContainer = createEntitySetContainer(edmEntityContainer.getEntitySet(entitySetName));
+      esName2esContainer.put(entitySetContainer.getEntitySetName(), entitySetContainer);
+      return entitySetContainer;
+    } catch (ODataDeserializerException e) {
+      throw new DataProviderException("Failure during reset/createEntitySetContainer", e);
+    }
+  }
+
+  private EntitySetContainer createEntitySetContainer(EdmEntitySet edmEntitySet)
+      throws ODataDeserializerException, DataProviderException {
+    String name = edmEntitySet.getName();
+    InputStream fis = Thread.currentThread().getContextClassLoader().getResourceAsStream(name + ".json");
+    if(fis == null) {
+      throw new DataProviderException("Failure during createEntitySetContainer, unable to load entity set [" +
+              name + "] from file.");
+    }
+
+    ResWrap<EntitySet> wrapper = new JsonDeserializer(ODataServiceVersion.V40, true).toEntitySet(fis);
+    EntitySet es = wrapper.getPayload();
+
+    EntitySetContainer container = new EntitySetContainer(edmEntitySet);
+    for (Entity entity : es.getEntities()) {
+      Entity norm = normalize(entity, edmEntitySet.getEntityType());
+      container.addEntity(norm);
+    }
+
+    return container;
+  }
+
+  private Entity normalize(Entity entity, EdmEntityType entityType) throws DataProviderException {
+    EntityImpl ei = new EntityImpl();
+
+    List<Property> propertyList = entity.getProperties();
+
+    try {
+      List<Property> normalized = normalizeProperties(propertyList, entityType);
+      ei.getProperties().addAll(normalized);
+      return ei;
+    } catch (Exception e) {
+      throw new DataProviderException("Failure during normalization of entity properties (for entity -> '" +
+              entity + "')", e);
+    }
+  }
+
+  private List<Property> normalizeProperties(Collection<Property> propertyList, EdmStructuredType entityType)
+      throws IllegalAccessException, DataProviderException, EdmPrimitiveTypeException {
+    List<Property> normalized = new ArrayList<Property>();
+
+    for (Property prop: propertyList) {
+      EdmElement element = entityType.getProperty(prop.getName());
+      // FIXME
+      if(element == null && prop.getName().contains("PropertyComp")) {
+        String fixedName = prop.getName().replace("PropertyComp", "PropertyComplex");
+        element = entityType.getProperty(fixedName);
+      }
+      //
+      Property result = normalizeProperty(prop, element);
+      normalized.add(result);
+    }
+
+    return normalized;
+  }
+
+  private Property normalizeProperty(Property prop, EdmElement element)
+      throws EdmPrimitiveTypeException, IllegalAccessException, DataProviderException {
+    return normalizeValue(prop.getValue(), element);
+  }
+
+  private Property normalizeValue(Object value, EdmElement element)
+      throws EdmPrimitiveTypeException, IllegalAccessException, DataProviderException {
+    if(element instanceof EdmProperty) {
+      EdmProperty property = (EdmProperty) element;
+      if(property.isPrimitive()) {
+        return PropBuilder.build(property).value(value);
+      } else {
+        // recursion
+        if(property.isCollection()) {
+          return normalizeComplexCollection((Collection<?>) value, property);
+        }
+
+        return normalizeComplexValue(value, property);
+      }
+    }
+    throw new DataProviderException("Unable to convert value [" + value + "] for property [" + element + "].");
+  }
+
+  private Property normalizeComplexCollection(Collection<?> values, EdmProperty property)
+      throws IllegalAccessException, DataProviderException, EdmPrimitiveTypeException {
+
+    List<Object> norm = new ArrayList<Object>();
+    boolean linkedComplex = false;
+    for (Object value : values) {
+      if(value instanceof Collection) {
+        Property r = normalizeComplexValue(value, property);
+        norm.add(r.getValue());
+      } else if(value instanceof LinkedComplexValue) {
+        LinkedComplexValue lcv = (LinkedComplexValue) value;
+        Property r = normalizeComplexValue(lcv, property);
+        linkedComplex = r.isLinkedComplex();
+        norm.add(r.getValue());
+      }
+    }
+
+    if(linkedComplex) {
+      return PropBuilder.build(property).linkedComplexCollection(norm);
+    }
+    return PropBuilder.build(property).complexCollection(norm);
+  }
+
+  private Property normalizeComplexValue(Object value, EdmProperty property)
+      throws IllegalAccessException, DataProviderException, EdmPrimitiveTypeException {
+    EdmComplexType complex = edm.getComplexType(property.getType().getFullQualifiedName());
+    if(value instanceof Collection) {
+      Collection<Property> norm = normalizeProperties((Collection<Property>) value, complex);
+      return PropBuilder.build(property).complex(norm);
+    } else if(value instanceof LinkedComplexValue) {
+      LinkedComplexValue lcv = (LinkedComplexValue) value;
+      Collection<Property> norm = normalizeProperties(lcv.getValue(), complex);
+      LinkedComplexValueImpl no = new LinkedComplexValueImpl();
+      no.getValue().addAll(norm);
+      return PropBuilder.build(property).linkedComplex(no);
+    }
+    throw new DataProviderException("Unable to convert value [" + value + "] for property [" + property + "].");
+  }
+
+  private static class EntitySetContainer {
+    final EdmEntitySet entitySet;
+    final Map<String, Entity> key2Entity;
+
+    public EntitySetContainer(EdmEntitySet entitySet) {
+      this.entitySet = entitySet;
+      key2Entity = new HashMap<String, Entity>();
+    }
+
+    public void addEntity(Entity entity) {
+      String key = createKey(entity, entitySet);
+      key2Entity.put(key, entity);
+    }
+
+    public EntitySet getEntitySet() {
+      EntitySetImpl resultEntitySet = new EntitySetImpl();
+      resultEntitySet.getEntities().addAll(key2Entity.values());
+      return resultEntitySet;
+    }
+
+    public String getEntitySetName() {
+      return entitySet.getName();
+    }
+
+    public Entity getEntity(Object ... keyValues) {
+      List<String> keyProperties = new ArrayList<String>();
+      Collections.sort(keyProperties);
+      for (Object keyValue : keyValues) {
+        keyProperties.add(String.valueOf(keyValue));
+      }
+      String key = keyProperties.toString();
+      return key2Entity.get(key);
+    }
+
+    private static String createKey(Entity entity, EdmEntitySet entitySet) {
+      List<String> keyPropertyValues = new ArrayList<String>();
+      List<EdmKeyPropertyRef> keyRefs = entitySet.getEntityType().getKeyPropertyRefs();
+      for (EdmKeyPropertyRef keyRef : keyRefs) {
+        Property keyProperty = entity.getProperty(keyRef.getKeyPropertyName());
+        keyPropertyValues.add(String.valueOf(keyProperty.getValue()));
+      }
+      Collections.sort(keyPropertyValues);
+      return keyPropertyValues.toString();
+    }
+  }
+
+
+  private static class PropBuilder {
+    final PropertyImpl property;
+    final EdmProperty edmProperty;
+
+    private PropBuilder(EdmProperty edmProperty) {
+      this.edmProperty = edmProperty;
+      property = new PropertyImpl(edmProperty.getType().getFullQualifiedName().getFullQualifiedNameAsString(),
+          edmProperty.getName());
+    }
+
+    public static PropBuilder build(EdmProperty edmProperty) {
+      return new PropBuilder(edmProperty);
+    }
+
+    public PropertyImpl primitive(Object ... value) {
+      if(edmProperty.isCollection()) {
+        property.setValue(ValueType.COLLECTION_PRIMITIVE, Arrays.asList(value));
+      } else {
+        if(value == null || value.length == 0) {
+          property.setValue(ValueType.PRIMITIVE, null);
+        } else {
+          property.setValue(ValueType.PRIMITIVE, value[0]);
+        }
+      }
+      return property;
+    }
+
+    public PropertyImpl complexCollection(Object value) {
+      if(edmProperty.isCollection()) {
+        property.setValue(ValueType.COLLECTION_COMPLEX, value);
+      } else {
+        throw new IllegalArgumentException("Property is no collection.");
+      }
+      return property;
+    }
+
+    public PropertyImpl complex(Object value) {
+      property.setValue(ValueType.COMPLEX, value);
+      return property;
+    }
+
+    public PropertyImpl linkedComplexCollection(Object value) {
+      if(edmProperty.isCollection()) {
+        property.setValue(ValueType.COLLECTION_LINKED_COMPLEX, value);
+      } else {
+        throw new IllegalArgumentException("Property is no collection.");
+      }
+      return property;
+    }
+
+    public PropertyImpl linkedComplex(Object value) {
+      property.setValue(ValueType.LINKED_COMPLEX, value);
+      return property;
+    }
+
+    public Property value(Object value) throws EdmPrimitiveTypeException {
+      FullQualifiedName fqn = edmProperty.getType().getFullQualifiedName();
+
+      try {
+        EdmPrimitiveTypeKind kind = EdmPrimitiveTypeKind.valueOfFQN(ODataServiceVersion.V40, fqn);
+        EdmPrimitiveType instance = EdmPrimitiveTypeFactory.getInstance(kind);
+
+        if(edmProperty.isCollection()) {
+          final Collection<?> values;
+          if(value.getClass().isArray()) {
+            values = Arrays.asList(value);
+          } else if(value instanceof Collection) {
+            values = (Collection<?>) value;
+          } else {
+            throw new EdmPrimitiveTypeException("Invalid collection value object class: " + value.getClass());
+          }
+          Collection<Object> result = new ArrayList<Object>(values.size());
+          for (Object v : values) {
+            String valueStr = String.valueOf(v);
+            result.add(instance.valueOfString(valueStr,
+                    edmProperty.isNullable(), edmProperty.getMaxLength(),
+                    edmProperty.getPrecision(), edmProperty.getScale(),
+                    true, instance.getDefaultType()));
+          }
+          property.setValue(ValueType.COLLECTION_PRIMITIVE, result);
+        } else {
+          String valueStr = String.valueOf(value);
+          Object result = instance.valueOfString(valueStr,
+                  edmProperty.isNullable(), edmProperty.getMaxLength(),
+                  edmProperty.getPrecision(), edmProperty.getScale(),
+                  true, instance.getDefaultType());
+          property.setValue(ValueType.PRIMITIVE, result);
+        }
+      } catch (IllegalArgumentException e) {
+        complex(value);
+      }
+      return property;
+    }
+  }
+}

http://git-wip-us.apache.org/repos/asf/olingo-odata4/blob/3ca91891/lib/server-tecsvc/src/main/java/org/apache/olingo/server/tecsvc/processor/SampleJsonProcessor.java
----------------------------------------------------------------------
diff --git a/lib/server-tecsvc/src/main/java/org/apache/olingo/server/tecsvc/processor/SampleJsonProcessor.java b/lib/server-tecsvc/src/main/java/org/apache/olingo/server/tecsvc/processor/SampleJsonProcessor.java
deleted file mode 100644
index e34fd42..0000000
--- a/lib/server-tecsvc/src/main/java/org/apache/olingo/server/tecsvc/processor/SampleJsonProcessor.java
+++ /dev/null
@@ -1,229 +0,0 @@
-/*
- * 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.server.tecsvc.processor;
-
-import java.net.URI;
-import java.util.*;
-
-import org.apache.olingo.commons.api.data.ContextURL;
-import org.apache.olingo.commons.api.data.Entity;
-import org.apache.olingo.commons.api.data.EntitySet;
-import org.apache.olingo.commons.api.data.Property;
-import org.apache.olingo.commons.api.data.ValueType;
-import org.apache.olingo.commons.api.edm.Edm;
-import org.apache.olingo.commons.api.edm.EdmEntitySet;
-import org.apache.olingo.commons.api.edm.EdmEntityType;
-import org.apache.olingo.commons.api.edm.FullQualifiedName;
-import org.apache.olingo.commons.api.format.ContentType;
-import org.apache.olingo.commons.api.format.ODataFormat;
-import org.apache.olingo.commons.api.http.HttpStatusCode;
-import org.apache.olingo.commons.core.data.EntityImpl;
-import org.apache.olingo.commons.core.data.EntitySetImpl;
-import org.apache.olingo.commons.core.data.PropertyImpl;
-import org.apache.olingo.server.api.OData;
-import org.apache.olingo.server.api.ODataRequest;
-import org.apache.olingo.server.api.ODataResponse;
-import org.apache.olingo.server.api.processor.CollectionProcessor;
-import org.apache.olingo.server.api.processor.EntityProcessor;
-import org.apache.olingo.server.api.serializer.ODataSerializer;
-import org.apache.olingo.server.api.uri.UriInfo;
-import org.apache.olingo.server.api.uri.UriResource;
-import org.slf4j.Logger;
-import org.slf4j.LoggerFactory;
-
-public class SampleJsonProcessor implements CollectionProcessor, EntityProcessor {
-  private static final Logger LOG = LoggerFactory.getLogger(SampleJsonProcessor.class);
-
-  private OData odata;
-  private Edm edm;
-
-  @Override
-  public void init(OData odata, Edm edm) {
-    this.odata = odata;
-    this.edm = edm;
-  }
-
-  @Override
-  public void readCollection(ODataRequest request, ODataResponse response, UriInfo uriInfo, String format) {
-    long time = System.nanoTime();
-
-    LOG.info((System.nanoTime() - time) / 1000 + " microseconds");
-    time = System.nanoTime();
-    ODataSerializer serializer = odata.createSerializer(ODataFormat.JSON);
-    EdmEntitySet edmEntitySet = getEntitySet(uriInfo);
-    ContextURL contextUrl = getContextUrl(request, edmEntitySet.getEntityType());
-    EntitySet entitySet = createEntitySet(edmEntitySet.getEntityType(), contextUrl.getURI().toASCIIString());
-    response.setContent(serializer.entitySet(edmEntitySet, entitySet, contextUrl));
-    LOG.info("Finished in " + (System.nanoTime() - time) / 1000 + " microseconds");
-
-    response.setStatusCode(HttpStatusCode.OK.getStatusCode());
-    response.setHeader("Content-Type", ContentType.APPLICATION_JSON.toContentTypeString());
-  }
-
-  @Override
-  public void readEntity(ODataRequest request, ODataResponse response, UriInfo uriInfo, String format) {
-    long time = System.nanoTime();
-
-    LOG.info((System.nanoTime() - time) / 1000 + " microseconds");
-    time = System.nanoTime();
-    ODataSerializer serializer = odata.createSerializer(ODataFormat.JSON);
-    EdmEntityType entityType = getEntityType(uriInfo);
-    Entity entity = createEntity(entityType);
-
-    response.setContent(serializer.entity(entityType, entity,
-            getContextUrl(request, entityType)));
-    LOG.info("Finished in " + (System.nanoTime() - time) / 1000 + " microseconds");
-
-    response.setStatusCode(HttpStatusCode.OK.getStatusCode());
-    response.setHeader("Content-Type", ContentType.APPLICATION_JSON.toContentTypeString());
-  }
-
-  private ContextURL getContextUrl(ODataRequest request, EdmEntityType entityType) {
-    return ContextURL.getInstance(URI.create(request.getRawBaseUri() + "/" + entityType.getName()));
-  }
-
-  public EdmEntityType getEntityType(UriInfo uriInfo) {
-    return getEntitySet(uriInfo).getEntityType();
-  }
-
-  public EdmEntitySet getEntitySet(UriInfo uriInfo) {
-    List<UriResource> resourcePaths = uriInfo.getUriResourceParts();
-    if(resourcePaths.isEmpty()) {
-      throw new RuntimeException("Invalid resource path.");
-    }
-    String entitySetName = resourcePaths.get(resourcePaths.size()-1).toString();
-    return edm.getEntityContainer(new FullQualifiedName("com.sap.odata.test1", "Container"))
-            .getEntitySet(entitySetName);
-  }
-
-  protected Entity createEntity(EdmEntityType entityType) {
-    boolean complex = (entityType.getName().contains("Comp"));
-    if(entityType.getName().contains("Coll")) {
-      return createEntityWithCollection(complex);
-    }
-    return createEntity(complex);
-  }
-
-  protected Entity createEntity(boolean complex) {
-    Entity entity = new EntityImpl();
-    Property property = new PropertyImpl();
-    property.setName("PropertyString");
-    property.setValue(ValueType.PRIMITIVE, "dummyValue");
-    entity.getProperties().add(property);
-    Property propertyInt = new PropertyImpl();
-    propertyInt.setName("PropertyInt16");
-    propertyInt.setValue(ValueType.PRIMITIVE, 42);
-    entity.getProperties().add(propertyInt);
-    Property propertyGuid = new PropertyImpl();
-    propertyGuid.setName("PropertyGuid");
-    propertyGuid.setValue(ValueType.PRIMITIVE, UUID.randomUUID());
-    entity.getProperties().add(propertyGuid);
-
-    if(complex) {
-      entity.addProperty(createComplexProperty());
-    }
-
-    return entity;
-  }
-
-  protected Entity createEntityWithCollection(boolean complex) {
-    Entity entity = new EntityImpl();
-    Property propertyInt = new PropertyImpl();
-    propertyInt.setName("PropertyInt16");
-    propertyInt.setValue(ValueType.PRIMITIVE, 42);
-    Property property = new PropertyImpl();
-    property.setName("CollPropertyString");
-    property.setValue(ValueType.COLLECTION_PRIMITIVE, Arrays.asList("dummyValue", "dummyValue_2"));
-    entity.getProperties().add(property);
-    entity.getProperties().add(propertyInt);
-    Property propertyGuid = new PropertyImpl();
-    propertyGuid.setName("CollPropertyGuid");
-    propertyGuid.setValue(ValueType.COLLECTION_PRIMITIVE, Arrays.asList(UUID.randomUUID(), UUID.randomUUID()));
-    entity.getProperties().add(propertyGuid);
-
-    if(complex) {
-      entity.addProperty(createCollectionOfComplexProperty());
-    }
-
-    return entity;
-  }
-
-  protected Property createComplexProperty() {
-    List<Property> properties = new ArrayList<Property>();
-    Property property = new PropertyImpl();
-    property.setName("PropertyString");
-    property.setValue(ValueType.PRIMITIVE, "dummyValue");
-    properties.add(property);
-    Property propertyInt = new PropertyImpl();
-    propertyInt.setName("PropertyInt16");
-    propertyInt.setValue(ValueType.PRIMITIVE, 42);
-    properties.add(propertyInt);
-    Property propertyGuid = new PropertyImpl();
-    propertyGuid.setName("PropertyGuid");
-    propertyGuid.setValue(ValueType.PRIMITIVE, UUID.randomUUID());
-    properties.add(propertyGuid);
-
-    return new PropertyImpl("com.sap.odata.test1.ETCompAllPrim", "PropertyComplex", ValueType.COMPLEX,
-            properties);
-  }
-
-  protected Property createCollectionOfComplexProperty() {
-    List<Property> properties = new ArrayList<Property>();
-    Property property = new PropertyImpl();
-    property.setName("PropertyString");
-    property.setValue(ValueType.PRIMITIVE, "dummyValue");
-    properties.add(property);
-    Property propertyInt = new PropertyImpl();
-    propertyInt.setName("PropertyInt16");
-    propertyInt.setValue(ValueType.PRIMITIVE, 42);
-    properties.add(propertyInt);
-    Property propertyGuid = new PropertyImpl();
-    propertyGuid.setName("PropertyGuid");
-    propertyGuid.setValue(ValueType.PRIMITIVE, UUID.randomUUID());
-    properties.add(propertyGuid);
-
-    List<Property> properties2 = new ArrayList<Property>();
-    Property property2 = new PropertyImpl();
-    property2.setName("PropertyString");
-    property2.setValue(ValueType.PRIMITIVE, "dummyValue2");
-    properties2.add(property2);
-    Property property2Int = new PropertyImpl();
-    property2Int.setName("PropertyInt16");
-    property2Int.setValue(ValueType.PRIMITIVE, 44);
-    properties2.add(property2Int);
-    Property property2Guid = new PropertyImpl();
-    property2Guid.setName("PropertyGuid");
-    property2Guid.setValue(ValueType.PRIMITIVE, UUID.randomUUID());
-    properties2.add(property2Guid);
-
-    return new PropertyImpl("com.sap.odata.test1.ETCompAllPrim", "PropertyComplex", ValueType.COMPLEX,
-            Arrays.asList(properties, properties2));
-  }
-
-  protected EntitySet createEntitySet(EdmEntityType edmEntityType, String baseUri) {
-    EntitySet entitySet = new EntitySetImpl();
-    int count = (int) ((Math.random() * 50) + 1);
-    entitySet.setCount(count);
-    entitySet.setNext(URI.create(baseUri + "nextLink"));
-    for (int i = 0; i < count; i++) {
-      entitySet.getEntities().add(createEntity(edmEntityType));
-    }
-    return entitySet;
-  }
-}

http://git-wip-us.apache.org/repos/asf/olingo-odata4/blob/3ca91891/lib/server-tecsvc/src/main/java/org/apache/olingo/server/tecsvc/processor/TechnicalProcessor.java
----------------------------------------------------------------------
diff --git a/lib/server-tecsvc/src/main/java/org/apache/olingo/server/tecsvc/processor/TechnicalProcessor.java b/lib/server-tecsvc/src/main/java/org/apache/olingo/server/tecsvc/processor/TechnicalProcessor.java
index b3c671c..0b2c6bd 100644
--- a/lib/server-tecsvc/src/main/java/org/apache/olingo/server/tecsvc/processor/TechnicalProcessor.java
+++ b/lib/server-tecsvc/src/main/java/org/apache/olingo/server/tecsvc/processor/TechnicalProcessor.java
@@ -18,35 +18,143 @@
  */
 package org.apache.olingo.server.tecsvc.processor;
 
-import java.io.ByteArrayInputStream;
-
+import org.apache.olingo.commons.api.data.ContextURL;
+import org.apache.olingo.commons.api.data.Entity;
+import org.apache.olingo.commons.api.data.EntitySet;
 import org.apache.olingo.commons.api.edm.Edm;
+import org.apache.olingo.commons.api.edm.EdmEntitySet;
+import org.apache.olingo.commons.api.edm.EdmEntityType;
+import org.apache.olingo.commons.api.format.ContentType;
+import org.apache.olingo.commons.api.format.ODataFormat;
+import org.apache.olingo.commons.api.http.HttpStatusCode;
 import org.apache.olingo.server.api.OData;
 import org.apache.olingo.server.api.ODataRequest;
 import org.apache.olingo.server.api.ODataResponse;
 import org.apache.olingo.server.api.processor.CollectionProcessor;
 import org.apache.olingo.server.api.processor.EntityProcessor;
+import org.apache.olingo.server.api.serializer.ODataSerializer;
 import org.apache.olingo.server.api.uri.UriInfo;
+import org.apache.olingo.server.api.uri.UriResource;
+import org.apache.olingo.server.api.uri.UriResourceEntitySet;
+import org.apache.olingo.server.api.uri.UriResourceKind;
 import org.apache.olingo.server.tecsvc.data.DataProvider;
+import org.apache.olingo.server.tecsvc.data.JefDataProvider;
+import org.apache.olingo.server.tecsvc.provider.ContainerProvider;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+
+import java.net.URI;
+import java.net.URISyntaxException;
+import java.util.List;
 
 public class TechnicalProcessor implements CollectionProcessor, EntityProcessor {
 
-  public TechnicalProcessor(final DataProvider dataProvider) {}
+
+  private static final Logger LOG = LoggerFactory.getLogger(TechnicalProcessor.class);
+
+  private OData odata;
+  private Edm edm;
+  private DataProvider dataProvider;
+
+  public TechnicalProcessor(final DataProvider dataProvider) {
+    this.dataProvider = dataProvider;
+  }
 
   @Override
-  public void init(final OData odata, final Edm edm) {}
+  public void init(OData odata, Edm edm) {
+    this.odata = odata;
+    this.edm = edm;
+    if(dataProvider == null) {
+      this.dataProvider = new JefDataProvider(edm);
+    }
+  }
 
   @Override
-  public void readEntity(final ODataRequest request, final ODataResponse response, final UriInfo uriInfo,
-      final String format) {
-    response.setContent(new ByteArrayInputStream("Entity".getBytes()));
-    response.setStatusCode(200);
+  public void readCollection(ODataRequest request, ODataResponse response, UriInfo uriInfo, String format) {
+    long time = System.nanoTime();
+
+    LOG.info((System.nanoTime() - time) / 1000 + " microseconds");
+    time = System.nanoTime();
+    ODataSerializer serializer = odata.createSerializer(ODataFormat.JSON);
+    EdmEntitySet edmEntitySet = getEdmEntitySet(uriInfo);
+    ContextURL contextUrl = getContextUrl(request, edmEntitySet.getEntityType());
+    try {
+      EntitySet entitySet = readEntitySetInternal(edmEntitySet, contextUrl);
+      if(entitySet == null) {
+        response.setStatusCode(HttpStatusCode.NOT_FOUND.getStatusCode());
+      } else {
+        response.setContent(serializer.entitySet(edmEntitySet, entitySet, contextUrl));
+        LOG.info("Finished in " + (System.nanoTime() - time) / 1000 + " microseconds");
+
+        response.setStatusCode(HttpStatusCode.OK.getStatusCode());
+        response.setHeader("Content-Type", ContentType.APPLICATION_JSON.toContentTypeString());
+      }
+    } catch (DataProvider.DataProviderException e) {
+      response.setStatusCode(HttpStatusCode.INTERNAL_SERVER_ERROR.getStatusCode());
+    }
   }
 
   @Override
-  public void readCollection(final ODataRequest request, final ODataResponse response, final UriInfo uriInfo,
-      final String format) {
-    response.setContent(new ByteArrayInputStream("EntitySet".getBytes()));
-    response.setStatusCode(200);
+  public void readEntity(ODataRequest request, ODataResponse response, UriInfo uriInfo, String format) {
+    long time = System.nanoTime();
+
+    LOG.info((System.nanoTime() - time) / 1000 + " microseconds");
+    time = System.nanoTime();
+    ODataSerializer serializer = odata.createSerializer(ODataFormat.JSON);
+    EdmEntitySet edmEntitySet = getEdmEntitySet(uriInfo);
+    try {
+      Entity entity = readEntityInternal(uriInfo, edmEntitySet);
+      if(entity == null) {
+        response.setStatusCode(HttpStatusCode.NOT_FOUND.getStatusCode());
+      } else {
+        response.setContent(serializer.entity(edmEntitySet.getEntityType(), entity,
+                getContextUrl(request, edmEntitySet.getEntityType())));
+        LOG.info("Finished in " + (System.nanoTime() - time) / 1000 + " microseconds");
+
+        response.setStatusCode(HttpStatusCode.OK.getStatusCode());
+        response.setHeader("Content-Type", ContentType.APPLICATION_JSON.toContentTypeString());
+      }
+    } catch (DataProvider.DataProviderException e) {
+      response.setStatusCode(HttpStatusCode.INTERNAL_SERVER_ERROR.getStatusCode());
+    }
+  }
+
+  private Entity readEntityInternal(UriInfo uriInfo, EdmEntitySet entitySet)
+          throws DataProvider.DataProviderException {
+    List<UriResource> resourcePaths = uriInfo.getUriResourceParts();
+    if(!resourcePaths.isEmpty()) {
+      UriResource res = resourcePaths.get(resourcePaths.size()-1);
+      if(res.getKind() == UriResourceKind.entitySet) {
+        UriResourceEntitySet resourceEntitySet = (UriResourceEntitySet) res;
+        String key = resourceEntitySet.getKeyPredicates().get(0).getText();
+        return dataProvider.read(entitySet.getName(), key);
+      }
+    }
+    throw new RuntimeException("Invalid resource paths.. " + resourcePaths);
+  }
+
+  private ContextURL getContextUrl(ODataRequest request, EdmEntityType entityType) {
+    return ContextURL.getInstance(URI.create(request.getRawBaseUri() + "/" + entityType.getName()));
+  }
+
+  private EntitySet readEntitySetInternal(EdmEntitySet edmEntitySet, ContextURL contextUrl)
+          throws DataProvider.DataProviderException {
+    EntitySet entitySet = dataProvider.readAll(edmEntitySet.getName());
+    try {
+      entitySet.setNext(new URI(contextUrl.getServiceRoot().toASCIIString() + "/" +
+              edmEntitySet.getEntityType().getName()));
+    } catch (URISyntaxException e) {
+      throw new RuntimeException("Invalid uri syntax.", e);
+    }
+    return entitySet;
+  }
+
+  private EdmEntitySet getEdmEntitySet(UriInfo uriInfo) {
+    List<UriResource> resourcePaths = uriInfo.getUriResourceParts();
+    if(resourcePaths.isEmpty()) {
+      throw new RuntimeException("Invalid resource path.");
+    }
+    String entitySetName = resourcePaths.get(resourcePaths.size()-1).toString();
+    return edm.getEntityContainer(ContainerProvider.nameContainer).getEntitySet(entitySetName);
   }
 }

http://git-wip-us.apache.org/repos/asf/olingo-odata4/blob/3ca91891/lib/server-tecsvc/src/main/java/org/apache/olingo/server/tecsvc/provider/PropertyProvider.java
----------------------------------------------------------------------
diff --git a/lib/server-tecsvc/src/main/java/org/apache/olingo/server/tecsvc/provider/PropertyProvider.java b/lib/server-tecsvc/src/main/java/org/apache/olingo/server/tecsvc/provider/PropertyProvider.java
index fe8c97c..491b6f3 100644
--- a/lib/server-tecsvc/src/main/java/org/apache/olingo/server/tecsvc/provider/PropertyProvider.java
+++ b/lib/server-tecsvc/src/main/java/org/apache/olingo/server/tecsvc/provider/PropertyProvider.java
@@ -284,6 +284,7 @@ public class PropertyProvider {
 
   public static final Property propertyDateTimeOffset = new Property()
       .setName("PropertyDateTimeOffset")
+      .setPrecision(20)
       .setType(nameDateTimeOffset);
 
   public static final Property propertyDateTimeOffset_NotNullable = new Property()
@@ -298,6 +299,7 @@ public class PropertyProvider {
 
   public static final Property propertyDecimal = new Property()
       .setName("PropertyDecimal")
+      .setScale(10)
       .setType(nameDecimal);
 
   public static final Property propertyDecimal_NotNullable = new Property()
@@ -438,6 +440,7 @@ public class PropertyProvider {
 
   public static final Property propertyTimeOfDay = new Property()
       .setName("PropertyTimeOfDay")
+      .setPrecision(10)
       .setType(nameTimeOfDay);
 
   public static final Property propertyTimeOfDay_NotNullable = new Property()

http://git-wip-us.apache.org/repos/asf/olingo-odata4/blob/3ca91891/lib/server-tecsvc/src/main/resources/ESAllPrim.json
----------------------------------------------------------------------
diff --git a/lib/server-tecsvc/src/main/resources/ESAllPrim.json b/lib/server-tecsvc/src/main/resources/ESAllPrim.json
new file mode 100644
index 0000000..0e0da29
--- /dev/null
+++ b/lib/server-tecsvc/src/main/resources/ESAllPrim.json
@@ -0,0 +1,56 @@
+{"@odata.context": "$metadata#ESAllPrim", "value": [
+    {
+        "PropertyInt16": 32767,
+        "PropertyString": "First Resource - positive values",
+        "PropertyBoolean": true,
+        "PropertyByte": 255,
+        "PropertySByte": 127,
+        "PropertyInt32": 2147483647,
+        "PropertyInt64": 9223372036854775807,
+        "PropertySingle": 1.79000000E+20,
+        "PropertyDouble": -1.7900000000000000E+19,
+        "PropertyDecimal": 34,
+        "PropertyBinary": "ASNFZ4mrze8=",
+        "PropertyDate": "2012-12-03",
+        "PropertyDateTimeOffset": "2012-12-03T07:16:23Z",
+        "PropertyDuration": "P0DT0H0M6S",
+        "PropertyGuid": "01234567-89ab-cdef-0123-456789abcdef",
+        "PropertyTimeOfDay": "03:26:05"
+    },
+    {
+        "PropertyInt16": -32768,
+        "PropertyString": "Second Resource - negative values",
+        "PropertyBoolean": false,
+        "PropertyByte": 0,
+        "PropertySByte": -128,
+        "PropertyInt32": -2147483648,
+        "PropertyInt64": -9223372036854775808,
+        "PropertySingle": -1.79000000E+08,
+        "PropertyDouble": -1.7900000000000000E+05,
+        "PropertyDecimal": -34,
+        "PropertyBinary": "ASNFZ4mrze8=",
+        "PropertyDate": "2015-11-05",
+        "PropertyDateTimeOffset": "2005-12-03T07:17:08Z",
+        "PropertyDuration": "P0DT0H0M9S",
+        "PropertyGuid": "76543201-23ab-cdef-0123-456789dddfff",
+        "PropertyTimeOfDay": "23:49:14"
+    },
+    {
+        "PropertyInt16": 0,
+        "PropertyString": "",
+        "PropertyBoolean": false,
+        "PropertyByte": 0,
+        "PropertySByte": 0,
+        "PropertyInt32": 0,
+        "PropertyInt64": 0,
+        "PropertySingle": 0.00000000E+00,
+        "PropertyDouble": 0.0000000000000000E+00,
+        "PropertyDecimal": 0,
+        "PropertyBinary": "",
+        "PropertyDate": "1970-01-01",
+        "PropertyDateTimeOffset": "2005-12-03T00:00:00Z",
+        "PropertyDuration": "P0DT0H0M0S",
+        "PropertyGuid": "76543201-23ab-cdef-0123-456789cccddd",
+        "PropertyTimeOfDay": "00:01:01"
+    }
+]}
\ No newline at end of file

http://git-wip-us.apache.org/repos/asf/olingo-odata4/blob/3ca91891/lib/server-tecsvc/src/main/resources/ESCollAllPrim.json
----------------------------------------------------------------------
diff --git a/lib/server-tecsvc/src/main/resources/ESCollAllPrim.json b/lib/server-tecsvc/src/main/resources/ESCollAllPrim.json
new file mode 100644
index 0000000..89471d4
--- /dev/null
+++ b/lib/server-tecsvc/src/main/resources/ESCollAllPrim.json
@@ -0,0 +1,59 @@
+{"@odata.context": "$metadata#ESCollAllPrim", "value": [
+    {
+        "PropertyInt16": 1,
+        "CollPropertyString": ["spiderman@comic.com", "spidermaus@comic.com", "spidergirl@comic.com"],
+        "CollPropertyBoolean": [true, false, true],
+        "CollPropertyByte": [50, 200, 249],
+        "CollPropertySByte": [-120, 120, 126],
+        "CollPropertyInt16": [1000, 2000, 30112],
+        "CollPropertyInt32": [23232323, 11223355, 10000001],
+        "CollPropertyInt64": [929292929292, 333333333333, 444444444444],
+        "CollPropertySingle": [1.79000000E+03, 2.66000000E+04, 3.21000000E+03],
+        "CollPropertyDouble": [-1.7900000000000000E+04, -2.7800000000000000E+07, 3.2100000000000000E+03],
+        "CollPropertyDecimal": [12, -2, 1234],
+        "CollPropertyBinary": ["q83v", "ASNF", "VGeJ"],
+        "CollPropertyDate": ["1958-12-03", "1999-08-05", "2013-06-25"],
+        "CollPropertyDateTimeOffset": ["2015-08-12T03:08:34Z", "1970-03-28T12:11:10Z", "1948-02-17T09:09:09Z"],
+        "CollPropertyDuration": ["P0DT0H0M13S", "P0DT5H28M20S", "P0DT1H0M0S"],
+        "CollPropertyGuid": ["ffffff67-89ab-cdef-0123-456789aaaaaa", "eeeeee67-89ab-cdef-0123-456789bbbbbb", "cccccc67-89ab-cdef-0123-456789cccccc"],
+        "CollPropertyTimeOfDay": ["04:14:13", "23:59:59", "01:12:33"]
+    },
+    {
+        "PropertyInt16": 2,
+        "CollPropertyString": ["spiderman@comic.com", "spidermaus@comic.com", "spidergirl@comic.com"],
+        "CollPropertyBoolean": [true, false, true],
+        "CollPropertyByte": [50, 200, 249],
+        "CollPropertySByte": [-120, 120, 126],
+        "CollPropertyInt16": [1000, 2000, 30112],
+        "CollPropertyInt32": [23232323, 11223355, 10000001],
+        "CollPropertyInt64": [929292929292, 333333333333, 444444444444],
+        "CollPropertySingle": [1.79000000E+03, 2.66000000E+04, 3.21000000E+03],
+        "CollPropertyDouble": [-1.7900000000000000E+04, -2.7800000000000000E+07, 3.2100000000000000E+03],
+        "CollPropertyDecimal": [12, -2, 1234],
+        "CollPropertyBinary": ["q83v", "ASNF", "VGeJ"],
+        "CollPropertyDate": ["1958-12-03", "1999-08-05", "2013-06-25"],
+        "CollPropertyDateTimeOffset": ["2015-08-12T03:08:34Z", "1970-03-28T12:11:10Z", "1948-02-17T09:09:09Z"],
+        "CollPropertyDuration": ["P0DT0H0M13S", "P0DT5H28M20S", "P0DT1H0M0S"],
+        "CollPropertyGuid": ["ffffff67-89ab-cdef-0123-456789aaaaaa", "eeeeee67-89ab-cdef-0123-456789bbbbbb", "cccccc67-89ab-cdef-0123-456789cccccc"],
+        "CollPropertyTimeOfDay": ["04:14:13", "23:59:59", "01:12:33"]
+    },
+    {
+        "PropertyInt16": 3,
+        "CollPropertyString": ["spiderman@comic.com", "spidermaus@comic.com", "spidergirl@comic.com"],
+        "CollPropertyBoolean": [true, false, true],
+        "CollPropertyByte": [50, 200, 249],
+        "CollPropertySByte": [-120, 120, 126],
+        "CollPropertyInt16": [1000, 2000, 30112],
+        "CollPropertyInt32": [23232323, 11223355, 10000001],
+        "CollPropertyInt64": [929292929292, 333333333333, 444444444444],
+        "CollPropertySingle": [1.79000000E+03, 2.66000000E+04, 3.21000000E+03],
+        "CollPropertyDouble": [-1.7900000000000000E+04, -2.7800000000000000E+07, 3.2100000000000000E+03],
+        "CollPropertyDecimal": [12, -2, 1234],
+        "CollPropertyBinary": ["q83v", "ASNF", "VGeJ"],
+        "CollPropertyDate": ["1958-12-03", "1999-08-05", "2013-06-25"],
+        "CollPropertyDateTimeOffset": ["2015-08-12T03:08:34Z", "1970-03-28T12:11:10Z", "1948-02-17T09:09:09Z"],
+        "CollPropertyDuration": ["P0DT0H0M13S", "P0DT5H28M20S", "P0DT1H0M0S"],
+        "CollPropertyGuid": ["ffffff67-89ab-cdef-0123-456789aaaaaa", "eeeeee67-89ab-cdef-0123-456789bbbbbb", "cccccc67-89ab-cdef-0123-456789cccccc"],
+        "CollPropertyTimeOfDay": ["04:14:13", "23:59:59", "01:12:33"]
+    }
+]}
\ No newline at end of file

http://git-wip-us.apache.org/repos/asf/olingo-odata4/blob/3ca91891/lib/server-tecsvc/src/main/resources/ESCompAllPrim.json
----------------------------------------------------------------------
diff --git a/lib/server-tecsvc/src/main/resources/ESCompAllPrim.json b/lib/server-tecsvc/src/main/resources/ESCompAllPrim.json
new file mode 100644
index 0000000..bd87bc3
--- /dev/null
+++ b/lib/server-tecsvc/src/main/resources/ESCompAllPrim.json
@@ -0,0 +1,65 @@
+{"@odata.context": "$metadata#ESCompAllPrim", "value": [
+    {
+        "PropertyInt16": 32767,
+        "PropertyComp": {
+            "PropertyString": "First Resource - first",
+            "PropertyBinary": "ASNFZ4mrze8=",
+            "PropertyBoolean": true,
+            "PropertyByte": 255,
+            "PropertyDate": "2012-10-03",
+            "PropertyDateTimeOffset": "2012-10-03T07:16:23.1234567Z",
+            "PropertyDecimal": 34.27,
+            "PropertySingle": 1.79000000E+20,
+            "PropertyDouble": -1.7900000000000000E+19,
+            "PropertyDuration": "P0DT0H0M6S",
+            "PropertyGuid": "01234567-89ab-cdef-0123-456789abcdef",
+            "PropertyInt16": 32767,
+            "PropertyInt32": 2147483647,
+            "PropertyInt64": 9223372036854775807,
+            "PropertySByte": 127,
+            "PropertyTimeOfDay": "01:00:01"
+        }
+    },
+    {
+        "PropertyInt16": 7,
+        "PropertyComp": {
+            "PropertyString": "Second Resource - second",
+            "PropertyBinary": "ASNFZ4mrze8=",
+            "PropertyBoolean": true,
+            "PropertyByte": 255,
+            "PropertyDate": "2013-11-04",
+            "PropertyDateTimeOffset": "2013-11-04T07:16:23Z",
+            "PropertyDecimal": 34.27,
+            "PropertySingle": 1.79000000E+20,
+            "PropertyDouble": -1.7900000000000000E+02,
+            "PropertyDuration": "P0DT0H0M6S",
+            "PropertyGuid": "01234567-89ab-cdef-0123-456789abcdef",
+            "PropertyInt16": 25,
+            "PropertyInt32": 2147483647,
+            "PropertyInt64": 9223372036854775807,
+            "PropertySByte": 127,
+            "PropertyTimeOfDay": "07:45:12.7654321"
+        }
+    },
+    {
+        "PropertyInt16": 0,
+        "PropertyComp": {
+            "PropertyString": "Third Resource - third",
+            "PropertyBinary": "ASNFZ4mrze8=",
+            "PropertyBoolean": true,
+            "PropertyByte": 255,
+            "PropertyDate": "2014-12-05",
+            "PropertyDateTimeOffset": "2014-12-05T08:17:45.1234567Z",
+            "PropertyDecimal": 17.98,
+            "PropertySingle": 1.79000000E+20,
+            "PropertyDouble": -1.7900000000000000E+02,
+            "PropertyDuration": "P0DT0H0M6S",
+            "PropertyGuid": "01234567-89ab-cdef-0123-456789abcdef",
+            "PropertyInt16": -25,
+            "PropertyInt32": 2147483647,
+            "PropertyInt64": 9223372036854775807,
+            "PropertySByte": 127,
+            "PropertyTimeOfDay": "13:27:45"
+        }
+    }
+]}
\ No newline at end of file

http://git-wip-us.apache.org/repos/asf/olingo-odata4/blob/3ca91891/lib/server-tecsvc/src/main/resources/ESMixPrimCollComp.json
----------------------------------------------------------------------
diff --git a/lib/server-tecsvc/src/main/resources/ESMixPrimCollComp.json b/lib/server-tecsvc/src/main/resources/ESMixPrimCollComp.json
new file mode 100644
index 0000000..a58c603
--- /dev/null
+++ b/lib/server-tecsvc/src/main/resources/ESMixPrimCollComp.json
@@ -0,0 +1,68 @@
+{"@odata.context": "$metadata#ESMixPrimCollComp", "value": [
+    {
+        "PropertyInt16": 32767,
+        "CollPropertyString": ["spiderman@comic.com", "spidermaus@comic.com", "spidergirl@comic.com"],
+        "PropertyComp": {
+            "PropertyInt16": 111,
+            "PropertyString": "TEST A"
+        },
+        "CollPropertyComp": [
+            {
+                "PropertyInt16": 123,
+                "PropertyString": "TEST 1"
+            },
+            {
+                "PropertyInt16": 456,
+                "PropertyString": "TEST 2"
+            },
+            {
+                "PropertyInt16": 789,
+                "PropertyString": "TEST 3"
+            }
+        ]
+    },
+    {
+        "PropertyInt16": 7,
+        "CollPropertyString": ["spiderman@comic.com", "spidermaus@comic.com", "spidergirl@comic.com"],
+        "PropertyComp": {
+            "PropertyInt16": 222,
+            "PropertyString": "TEST B"
+        },
+        "CollPropertyComp": [
+            {
+                "PropertyInt16": 123,
+                "PropertyString": "TEST 1"
+            },
+            {
+                "PropertyInt16": 456,
+                "PropertyString": "TEST 2"
+            },
+            {
+                "PropertyInt16": 789,
+                "PropertyString": "TEST 3"
+            }
+        ]
+    },
+    {
+        "PropertyInt16": 0,
+        "CollPropertyString": ["spiderman@comic.com", "spidermaus@comic.com", "spidergirl@comic.com"],
+        "PropertyComp": {
+            "PropertyInt16": 333,
+            "PropertyString": "TEST C"
+        },
+        "CollPropertyComp": [
+            {
+                "PropertyInt16": 123,
+                "PropertyString": "TEST 1"
+            },
+            {
+                "PropertyInt16": 456,
+                "PropertyString": "TEST 2"
+            },
+            {
+                "PropertyInt16": 789,
+                "PropertyString": "TEST 3"
+            }
+        ]
+    }
+]}
\ No newline at end of file

http://git-wip-us.apache.org/repos/asf/olingo-odata4/blob/3ca91891/lib/server-tecsvc/src/main/resources/ESTwoPrim.json
----------------------------------------------------------------------
diff --git a/lib/server-tecsvc/src/main/resources/ESTwoPrim.json b/lib/server-tecsvc/src/main/resources/ESTwoPrim.json
new file mode 100644
index 0000000..727c6a8
--- /dev/null
+++ b/lib/server-tecsvc/src/main/resources/ESTwoPrim.json
@@ -0,0 +1 @@
+{"@odata.context":"$metadata#ESTwoPrim","value":[{"PropertyInt16":32766,"PropertyString":"Test String1"},{"PropertyInt16":-365,"PropertyString":"Test String2"},{"PropertyInt16":-32766,"PropertyString":"Test String3"},{"PropertyInt16":32767,"PropertyString":"Test String4"}]}
\ No newline at end of file

http://git-wip-us.apache.org/repos/asf/olingo-odata4/blob/3ca91891/lib/server-tecsvc/src/test/java/org/apache/olingo/server/tecsvc/data/JsonDataProviderTest.java
----------------------------------------------------------------------
diff --git a/lib/server-tecsvc/src/test/java/org/apache/olingo/server/tecsvc/data/JsonDataProviderTest.java b/lib/server-tecsvc/src/test/java/org/apache/olingo/server/tecsvc/data/JsonDataProviderTest.java
new file mode 100644
index 0000000..9ac0be6
--- /dev/null
+++ b/lib/server-tecsvc/src/test/java/org/apache/olingo/server/tecsvc/data/JsonDataProviderTest.java
@@ -0,0 +1,186 @@
+/*
+ * 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.server.tecsvc.data;
+
+import org.apache.olingo.commons.api.data.ContextURL;
+import org.apache.olingo.commons.api.data.Entity;
+import org.apache.olingo.commons.api.data.EntitySet;
+import org.apache.olingo.commons.api.data.LinkedComplexValue;
+import org.apache.olingo.commons.api.data.Property;
+import org.apache.olingo.commons.api.edm.Edm;
+import org.apache.olingo.commons.api.edm.EdmComplexType;
+import org.apache.olingo.commons.api.edm.EdmElement;
+import org.apache.olingo.commons.api.edm.EdmEntitySet;
+import org.apache.olingo.commons.api.edm.EdmEntityType;
+import org.apache.olingo.commons.api.edm.EdmProperty;
+import org.apache.olingo.commons.api.edm.EdmStructuredType;
+import org.apache.olingo.server.api.OData;
+import org.apache.olingo.server.core.serializer.json.ODataJsonSerializer;
+import org.apache.olingo.server.tecsvc.provider.ContainerProvider;
+import org.apache.olingo.server.tecsvc.provider.EdmTechProvider;
+import org.junit.Assert;
+import org.junit.Test;
+
+import java.io.InputStream;
+import java.util.List;
+
+/**
+ */
+public class JsonDataProviderTest {
+
+  @Test
+  public void doRoundTrip() throws Exception {
+    doRoundTrip("ESAllPrim", 1405);
+    doRoundTrip("ESCompAllPrim", 1597);
+    doRoundTrip("ESCollAllPrim", 2858);
+    doRoundTrip("ESMixPrimCollComp", 1050);
+  }
+
+  @Test
+  public void esAllPrimEntity() throws Exception {
+    DataProvider jdp = getDataProvider();
+    jdp.reset();
+    Entity first = jdp.read("ESAllPrim", Integer.valueOf(0));
+
+    Assert.assertEquals(16, first.getProperties().size());
+  }
+
+  @Test
+  public void esAllPrim() throws Exception {
+    DataProvider jdp = getDataProvider();
+    EntitySet outSet = jdp.readAll("ESAllPrim");
+
+    Assert.assertEquals(3, outSet.getEntities().size());
+    Entity first = outSet.getEntities().get(0);
+    Assert.assertEquals(16, first.getProperties().size());
+    Assert.assertEquals(16, outSet.getEntities().get(1).getProperties().size());
+    Assert.assertEquals(16, outSet.getEntities().get(2).getProperties().size());
+  }
+
+  @Test
+  public void esCollAllPrim() throws Exception {
+    DataProvider jdp = getDataProvider();
+    EntitySet outSet = jdp.readAll("ESCollAllPrim");
+
+    Assert.assertEquals(3, outSet.getEntities().size());
+    Assert.assertEquals(17, outSet.getEntities().get(0).getProperties().size());
+    Property list = outSet.getEntities().get(0).getProperties().get(1);
+    Assert.assertTrue(list.isCollection());
+    Assert.assertEquals(3, list.asCollection().size());
+    Assert.assertEquals(17, outSet.getEntities().get(1).getProperties().size());
+    Assert.assertEquals(17, outSet.getEntities().get(2).getProperties().size());
+  }
+
+  @Test
+  public void esCompAllPrim() throws Exception {
+    DataProvider jdp = getDataProvider();
+    EntitySet outSet = jdp.readAll("ESCompAllPrim");
+
+    Assert.assertEquals(3, outSet.getEntities().size());
+    Assert.assertEquals(2, outSet.getEntities().get(0).getProperties().size());
+    Property complex = outSet.getEntities().get(0).getProperties().get(1);
+    Assert.assertTrue(complex.isLinkedComplex());
+    Assert.assertEquals(16, complex.asLinkedComplex().getValue().size());
+    Assert.assertEquals(2, outSet.getEntities().get(1).getProperties().size());
+    Assert.assertEquals(2, outSet.getEntities().get(2).getProperties().size());
+  }
+
+  @Test
+  public void esMixPrimCollComp() throws Exception {
+    DataProvider jdp = getDataProvider();
+    EntitySet outSet = jdp.readAll("ESMixPrimCollComp");
+
+    Assert.assertEquals(3, outSet.getEntities().size());
+    Assert.assertEquals(4, outSet.getEntities().get(0).getProperties().size());
+    Property complex = outSet.getEntities().get(0).getProperties().get(2);
+    Assert.assertTrue(complex.isLinkedComplex());
+    Assert.assertEquals(2, complex.asLinkedComplex().getValue().size());
+    Property complexCollection = outSet.getEntities().get(0).getProperties().get(3);
+    Assert.assertTrue(complexCollection.isCollection());
+    List<?> linkedComplexValues = complexCollection.asCollection();
+    Assert.assertEquals(3, linkedComplexValues.size());
+    LinkedComplexValue linkedComplexValue = (LinkedComplexValue) linkedComplexValues.get(0);
+    Assert.assertEquals(2, linkedComplexValue.getValue().size());
+    Property lcProp = linkedComplexValue.getValue().get(0);
+    Assert.assertFalse(lcProp.isCollection());
+    Assert.assertEquals(Short.valueOf("123"), lcProp.getValue());
+    //
+    Assert.assertEquals(4, outSet.getEntities().get(1).getProperties().size());
+    Assert.assertEquals(4, outSet.getEntities().get(2).getProperties().size());
+  }
+
+  private DataProvider getDataProvider() throws DataProvider.DataProviderException {
+    OData odata = OData.newInstance();
+    Edm edm = odata.createEdm(new EdmTechProvider());
+    return new JefDataProvider(edm);
+  }
+
+  @Test
+  public void edm() {
+    OData odata = OData.newInstance();
+    Edm edm = odata.createEdm(new EdmTechProvider());
+    EdmEntitySet edmEntitySet =
+        edm.getEntityContainer(ContainerProvider.nameContainer).getEntitySet("ESCompAllPrim");
+
+    EdmEntityType et = edmEntitySet.getEntityType();
+    printType(edm, et);
+  }
+
+  private void printType(Edm edm, EdmStructuredType type) {
+
+    List<String> propNames = type.getPropertyNames();
+
+    for (String propName : propNames) {
+      EdmElement element = type.getProperty(propName);
+      if(element instanceof EdmProperty) {
+        EdmProperty property = (EdmProperty) element;
+        if(property.isPrimitive()) {
+          System.out.println("Primitive name/type: " + property.getName() + "/" + property.getType());
+        } else {
+          // recursion
+          EdmComplexType complex = edm.getComplexType(property.getType().getFullQualifiedName());
+          System.out.println("Complex name/type [" + property.getName() + "/" + property.getType() + "]");
+          printType(edm, complex);
+        }
+      }
+    }
+  }
+
+  private void doRoundTrip(String name, int expectedLength) throws Exception {
+    OData odata = OData.newInstance();
+    Edm edm = odata.createEdm(new EdmTechProvider());
+    EdmEntitySet edmEntitySet = edm.getEntityContainer(ContainerProvider.nameContainer).getEntitySet(name);
+
+    DataProvider jdp = new JefDataProvider(edm);
+    EntitySet outSet = jdp.readAll(name);
+
+
+    ODataJsonSerializer serializer = new ODataJsonSerializer();
+    ContextURL contextUrl = null;
+    InputStream is = serializer.entitySet(edmEntitySet, outSet, contextUrl);
+
+    StringHelper.Stream stream = StringHelper.toStream(is);
+
+    System.out.println("========== " + name + " =================");
+    stream.print();
+    System.out.println("\n========== " + name + " =================");
+
+    Assert.assertEquals(expectedLength, stream.asString().length());
+  }
+}

http://git-wip-us.apache.org/repos/asf/olingo-odata4/blob/3ca91891/lib/server-tecsvc/src/test/java/org/apache/olingo/server/tecsvc/data/StringHelper.java
----------------------------------------------------------------------
diff --git a/lib/server-tecsvc/src/test/java/org/apache/olingo/server/tecsvc/data/StringHelper.java b/lib/server-tecsvc/src/test/java/org/apache/olingo/server/tecsvc/data/StringHelper.java
new file mode 100644
index 0000000..52c4599
--- /dev/null
+++ b/lib/server-tecsvc/src/test/java/org/apache/olingo/server/tecsvc/data/StringHelper.java
@@ -0,0 +1,206 @@
+/*******************************************************************************
+ * 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.server.tecsvc.data;
+
+import java.io.BufferedReader;
+import java.io.ByteArrayInputStream;
+import java.io.IOException;
+import java.io.InputStream;
+import java.io.InputStreamReader;
+import java.io.OutputStream;
+import java.io.UnsupportedEncodingException;
+import java.nio.charset.Charset;
+import java.util.Random;
+
+/**
+ *  
+ */
+public class StringHelper {
+
+  public static class Stream {
+    private final byte[] data;
+
+    private Stream(final byte[] data) {
+      this.data = data;
+    }
+
+    public Stream(final String content, final String charset) throws UnsupportedEncodingException {
+      this(content.getBytes(charset));
+    }
+
+    public InputStream asStream() {
+      return new ByteArrayInputStream(data);
+    }
+
+    public byte[] asArray() {
+      return data;
+    }
+
+    public String asString() {
+      return asString("UTF-8");
+    }
+
+    public String asString(final String charsetName) {
+      return new String(data, Charset.forName(charsetName));
+    }
+
+    public Stream print(final OutputStream out) throws IOException {
+      out.write(data);
+      return this;
+    }
+
+    public Stream print() throws IOException {
+      return print(System.out);
+    }
+
+    /**
+     * Number of lines separated by line breaks (<code>CRLF</code>).
+     * A content string like <code>text\r\nmoreText</code> will result in
+     * a line count of <code>2</code>.
+     * 
+     * @return lines count
+     */
+    public int linesCount() {
+      return StringHelper.countLines(asString(), "\r\n");
+    }
+  }
+
+  public static Stream toStream(final InputStream stream) throws IOException {
+    byte[] result = new byte[0];
+    byte[] tmp = new byte[8192];
+    int readCount = stream.read(tmp);
+    while (readCount >= 0) {
+      byte[] innerTmp = new byte[result.length + readCount];
+      System.arraycopy(result, 0, innerTmp, 0, result.length);
+      System.arraycopy(tmp, 0, innerTmp, result.length, readCount);
+      result = innerTmp;
+      readCount = stream.read(tmp);
+    }
+    stream.close();
+    return new Stream(result);
+  }
+
+  public static Stream toStream(final String content) {
+    try {
+      return new Stream(content, "UTF-8");
+    } catch (UnsupportedEncodingException e) {
+      throw new RuntimeException("UTF-8 should be supported on each system.");
+    }
+  }
+
+  public static String inputStreamToString(final InputStream in, final boolean preserveLineBreaks) throws IOException {
+    final BufferedReader bufferedReader = new BufferedReader(new InputStreamReader(in, Charset.forName("UTF-8")));
+    final StringBuilder stringBuilder = new StringBuilder();
+    String line = null;
+
+    while ((line = bufferedReader.readLine()) != null) {
+      stringBuilder.append(line);
+      if (preserveLineBreaks) {
+        stringBuilder.append("\n");
+      }
+    }
+
+    bufferedReader.close();
+
+    final String result = stringBuilder.toString();
+
+    return result;
+  }
+
+  public static int countLines(final String content) {
+    return countLines(content, "\r\n");
+  }
+
+  public static int countLines(final String content, final String lineBreak) {
+    if (content == null) {
+      return -1;
+    }
+
+    int lastPos = content.indexOf(lineBreak);
+    int count = 1;
+
+    while (lastPos >= 0) {
+      lastPos = content.indexOf(lineBreak, lastPos + 1);
+      count++;
+    }
+    return count;
+  }
+
+  public static String inputStreamToString(final InputStream in) throws IOException {
+    return inputStreamToString(in, false);
+  }
+
+  /**
+   * Encapsulate given content in an {@link InputStream} with charset <code>UTF-8</code>.
+   * 
+   * @param content to encapsulate content
+   * @return content as stream
+   */
+  public static InputStream encapsulate(final String content) {
+    try {
+      return encapsulate(content, "UTF-8");
+    } catch (UnsupportedEncodingException e) {
+      // we know that UTF-8 is supported
+      throw new TestUtilRuntimeException("UTF-8 MUST be supported.", e);
+    }
+  }
+
+  /**
+   * Encapsulate given content in an {@link InputStream} with given charset.
+   * 
+   * @param content to encapsulate content
+   * @param charset to be used charset
+   * @return content as stream
+   * @throws UnsupportedEncodingException if charset is not supported
+   */
+  public static InputStream encapsulate(final String content, final String charset)
+      throws UnsupportedEncodingException {
+    return new ByteArrayInputStream(content.getBytes(charset));
+  }
+
+  /**
+   * Generate a string with given length containing random upper case characters ([A-Z]).
+   * 
+   * @param len length of to generated string
+   * @return random upper case characters ([A-Z]).
+   */
+  public static InputStream generateDataStream(final int len) {
+    return encapsulate(generateData(len));
+  }
+
+  /**
+   * Generates a string with given length containing random upper case characters ([A-Z]).
+   * @param len length of the generated string
+   * @return random upper case characters ([A-Z])
+   */
+  public static String generateData(final int len) {
+    Random random = new Random();
+    StringBuilder b = new StringBuilder(len);
+    for (int j = 0; j < len; j++) {
+      final char c = (char) ('A' + random.nextInt('Z' - 'A' + 1));
+      b.append(c);
+    }
+    return b.toString();
+  }
+
+  private static class TestUtilRuntimeException extends RuntimeException {
+    public TestUtilRuntimeException(String message, Throwable cause) {
+    }
+  }
+}


[2/2] git commit: [OLINGO-317] Merge feature branch into master

Posted by mi...@apache.org.
[OLINGO-317] Merge feature branch into master


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

Branch: refs/heads/master
Commit: 45b7289f88da120e6911c60bf52ed64d753183bf
Parents: b3cfc35 3ca9189
Author: Michael Bolz <mi...@sap.com>
Authored: Tue Jul 8 13:53:58 2014 +0200
Committer: Michael Bolz <mi...@sap.com>
Committed: Tue Jul 8 13:53:58 2014 +0200

----------------------------------------------------------------------
 .../core/serializer/json/JsonDataProvider.java  |  46 +++
 .../json/ODataJsonSerializerTest.java           |  28 +-
 .../olingo/server/tecsvc/TechnicalServlet.java  |  27 +-
 .../olingo/server/tecsvc/data/DataProvider.java |  25 +-
 .../server/tecsvc/data/JefDataProvider.java     | 349 +++++++++++++++++++
 .../tecsvc/processor/SampleJsonProcessor.java   | 232 ------------
 .../tecsvc/processor/TechnicalProcessor.java    | 131 ++++++-
 .../tecsvc/provider/PropertyProvider.java       |   3 +
 .../src/main/resources/ESAllPrim.json           |  56 +++
 .../src/main/resources/ESCollAllPrim.json       |  59 ++++
 .../src/main/resources/ESCompAllPrim.json       |  65 ++++
 .../src/main/resources/ESMixPrimCollComp.json   |  68 ++++
 .../src/main/resources/ESTwoPrim.json           |   1 +
 .../tecsvc/data/JsonDataProviderTest.java       | 186 ++++++++++
 .../olingo/server/tecsvc/data/StringHelper.java | 206 +++++++++++
 15 files changed, 1198 insertions(+), 284 deletions(-)
----------------------------------------------------------------------


http://git-wip-us.apache.org/repos/asf/olingo-odata4/blob/45b7289f/lib/server-tecsvc/src/main/java/org/apache/olingo/server/tecsvc/processor/TechnicalProcessor.java
----------------------------------------------------------------------
diff --cc lib/server-tecsvc/src/main/java/org/apache/olingo/server/tecsvc/processor/TechnicalProcessor.java
index 7c5a267,0b2c6bd..775d96e
--- a/lib/server-tecsvc/src/main/java/org/apache/olingo/server/tecsvc/processor/TechnicalProcessor.java
+++ b/lib/server-tecsvc/src/main/java/org/apache/olingo/server/tecsvc/processor/TechnicalProcessor.java
@@@ -28,29 -32,129 +32,126 @@@ import org.apache.olingo.server.api.ODa
  import org.apache.olingo.server.api.ODataResponse;
  import org.apache.olingo.server.api.processor.CollectionProcessor;
  import org.apache.olingo.server.api.processor.EntityProcessor;
+ import org.apache.olingo.server.api.serializer.ODataSerializer;
  import org.apache.olingo.server.api.uri.UriInfo;
+ import org.apache.olingo.server.api.uri.UriResource;
+ import org.apache.olingo.server.api.uri.UriResourceEntitySet;
+ import org.apache.olingo.server.api.uri.UriResourceKind;
  import org.apache.olingo.server.tecsvc.data.DataProvider;
 -import org.apache.olingo.server.tecsvc.data.JefDataProvider;
+ import org.apache.olingo.server.tecsvc.provider.ContainerProvider;
+ import org.slf4j.Logger;
+ import org.slf4j.LoggerFactory;
+ 
+ import java.net.URI;
+ import java.net.URISyntaxException;
+ import java.util.List;
  
  public class TechnicalProcessor implements CollectionProcessor, EntityProcessor {
  
-   public TechnicalProcessor(final DataProvider dataProvider) {}
 -
+   private static final Logger LOG = LoggerFactory.getLogger(TechnicalProcessor.class);
  
-   @Override
-   public void init(final OData odata, final Edm edm) {}
+   private OData odata;
+   private Edm edm;
+   private DataProvider dataProvider;
+ 
+   public TechnicalProcessor(final DataProvider dataProvider) {
+     this.dataProvider = dataProvider;
+   }
  
    @Override
-   public void readEntity(final ODataRequest request, final ODataResponse response, final UriInfo uriInfo,
-       final ContentType requestedContentType) {
-     response.setContent(new ByteArrayInputStream("Entity".getBytes()));
-     response.setStatusCode(200);
-     response.setHeader(HttpHeader.CONTENT_TYPE, requestedContentType.toContentTypeString());
+   public void init(OData odata, Edm edm) {
+     this.odata = odata;
+     this.edm = edm;
    }
  
    @Override
 -  public void readCollection(ODataRequest request, ODataResponse response, UriInfo uriInfo, String format) {
 +  public void readCollection(final ODataRequest request, final ODataResponse response, final UriInfo uriInfo,
-       final ContentType requestedContentType) {
-     response.setContent(new ByteArrayInputStream("EntitySet".getBytes()));
-     response.setStatusCode(200);
-     response.setHeader(HttpHeader.CONTENT_TYPE, requestedContentType.toContentTypeString());
++                             final ContentType requestedContentType) {
+     long time = System.nanoTime();
+ 
+     LOG.info((System.nanoTime() - time) / 1000 + " microseconds");
+     time = System.nanoTime();
+     ODataSerializer serializer = odata.createSerializer(ODataFormat.JSON);
+     EdmEntitySet edmEntitySet = getEdmEntitySet(uriInfo);
+     ContextURL contextUrl = getContextUrl(request, edmEntitySet.getEntityType());
+     try {
+       EntitySet entitySet = readEntitySetInternal(edmEntitySet, contextUrl);
+       if(entitySet == null) {
+         response.setStatusCode(HttpStatusCode.NOT_FOUND.getStatusCode());
+       } else {
+         response.setContent(serializer.entitySet(edmEntitySet, entitySet, contextUrl));
+         LOG.info("Finished in " + (System.nanoTime() - time) / 1000 + " microseconds");
+ 
+         response.setStatusCode(HttpStatusCode.OK.getStatusCode());
+         response.setHeader("Content-Type", ContentType.APPLICATION_JSON.toContentTypeString());
+       }
+     } catch (DataProvider.DataProviderException e) {
+       response.setStatusCode(HttpStatusCode.INTERNAL_SERVER_ERROR.getStatusCode());
+     }
+   }
+ 
+   @Override
 -  public void readEntity(ODataRequest request, ODataResponse response, UriInfo uriInfo, String format) {
++  public void readEntity(final ODataRequest request, final ODataResponse response, final UriInfo uriInfo,
++                         final ContentType requestedContentType) {
+     long time = System.nanoTime();
+ 
+     LOG.info((System.nanoTime() - time) / 1000 + " microseconds");
+     time = System.nanoTime();
+     ODataSerializer serializer = odata.createSerializer(ODataFormat.JSON);
+     EdmEntitySet edmEntitySet = getEdmEntitySet(uriInfo);
+     try {
+       Entity entity = readEntityInternal(uriInfo, edmEntitySet);
+       if(entity == null) {
+         response.setStatusCode(HttpStatusCode.NOT_FOUND.getStatusCode());
+       } else {
+         response.setContent(serializer.entity(edmEntitySet.getEntityType(), entity,
+                 getContextUrl(request, edmEntitySet.getEntityType())));
+         LOG.info("Finished in " + (System.nanoTime() - time) / 1000 + " microseconds");
+ 
+         response.setStatusCode(HttpStatusCode.OK.getStatusCode());
+         response.setHeader("Content-Type", ContentType.APPLICATION_JSON.toContentTypeString());
+       }
+     } catch (DataProvider.DataProviderException e) {
+       response.setStatusCode(HttpStatusCode.INTERNAL_SERVER_ERROR.getStatusCode());
+     }
+   }
+ 
+   private Entity readEntityInternal(UriInfo uriInfo, EdmEntitySet entitySet)
+           throws DataProvider.DataProviderException {
+     List<UriResource> resourcePaths = uriInfo.getUriResourceParts();
+     if(!resourcePaths.isEmpty()) {
+       UriResource res = resourcePaths.get(resourcePaths.size()-1);
+       if(res.getKind() == UriResourceKind.entitySet) {
+         UriResourceEntitySet resourceEntitySet = (UriResourceEntitySet) res;
+         String key = resourceEntitySet.getKeyPredicates().get(0).getText();
+         return dataProvider.read(entitySet.getName(), key);
+       }
+     }
+     throw new RuntimeException("Invalid resource paths.. " + resourcePaths);
+   }
+ 
+   private ContextURL getContextUrl(ODataRequest request, EdmEntityType entityType) {
+     return ContextURL.getInstance(URI.create(request.getRawBaseUri() + "/" + entityType.getName()));
+   }
+ 
+   private EntitySet readEntitySetInternal(EdmEntitySet edmEntitySet, ContextURL contextUrl)
+           throws DataProvider.DataProviderException {
+     EntitySet entitySet = dataProvider.readAll(edmEntitySet.getName());
+     try {
+       entitySet.setNext(new URI(contextUrl.getServiceRoot().toASCIIString() + "/" +
+               edmEntitySet.getEntityType().getName()));
+     } catch (URISyntaxException e) {
+       throw new RuntimeException("Invalid uri syntax.", e);
+     }
+     return entitySet;
+   }
+ 
+   private EdmEntitySet getEdmEntitySet(UriInfo uriInfo) {
+     List<UriResource> resourcePaths = uriInfo.getUriResourceParts();
+     if(resourcePaths.isEmpty()) {
+       throw new RuntimeException("Invalid resource path.");
+     }
+     String entitySetName = resourcePaths.get(resourcePaths.size()-1).toString();
+     return edm.getEntityContainer(ContainerProvider.nameContainer).getEntitySet(entitySetName);
    }
  }