You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@olingo.apache.org by tb...@apache.org on 2013/12/20 16:18:03 UTC

[01/12] git commit: [OLINGO-95] Introduce ExpandSelectTreeBuilder

Updated Branches:
  refs/heads/ODataServlet 6ac9c5222 -> 80379ec10


[OLINGO-95] Introduce ExpandSelectTreeBuilder

Tests for builder and serialization are done


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

Branch: refs/heads/ODataServlet
Commit: bb73dadd3f1e575cf8a781fb785fbacd8af134ca
Parents: 96e9d9e
Author: Christian Amend <ch...@apache.org>
Authored: Fri Dec 20 13:53:00 2013 +0100
Committer: Christian Amend <ch...@apache.org>
Committed: Fri Dec 20 13:53:00 2013 +0100

----------------------------------------------------------------------
 .../olingo/odata2/api/edm/EdmException.java     |   7 +
 .../olingo/odata2/api/rt/RuntimeDelegate.java   |   7 +
 .../odata2/api/uri/ExpandSelectTreeNode.java    |  91 +++++-
 .../odata2/core/rt/RuntimeDelegateImpl.java     |   8 +
 .../core/uri/ExpandSelectTreeNodeImpl.java      | 112 +++++++-
 .../src/main/resources/i18n.properties          |   4 +
 .../ExpandSelectProducerWithBuilderTest.java    | 204 ++++++++++++++
 .../core/ep/producer/XmlExpandProducerTest.java |  24 ++
 .../uri/ExpandSelectTreeNodeBuilderTest.java    | 282 +++++++++++++++++++
 9 files changed, 733 insertions(+), 6 deletions(-)
----------------------------------------------------------------------


http://git-wip-us.apache.org/repos/asf/incubator-olingo-odata2/blob/bb73dadd/odata2-lib/odata-api/src/main/java/org/apache/olingo/odata2/api/edm/EdmException.java
----------------------------------------------------------------------
diff --git a/odata2-lib/odata-api/src/main/java/org/apache/olingo/odata2/api/edm/EdmException.java b/odata2-lib/odata-api/src/main/java/org/apache/olingo/odata2/api/edm/EdmException.java
index 5c828cc..7e6f6fb 100644
--- a/odata2-lib/odata-api/src/main/java/org/apache/olingo/odata2/api/edm/EdmException.java
+++ b/odata2-lib/odata-api/src/main/java/org/apache/olingo/odata2/api/edm/EdmException.java
@@ -32,6 +32,13 @@ public class EdmException extends ODataMessageException {
 
   public static final MessageReference COMMON = createMessageReference(EdmException.class, "COMMON");
   public static final MessageReference PROVIDERPROBLEM = createMessageReference(EdmException.class, "PROVIDERPROBLEM");
+  public static final MessageReference PROPERTYNOTFOUND =
+      createMessageReference(EdmException.class, "PROPERTYNOTFOUND");
+  public static final MessageReference NAVIGATIONPROPERTYNOTFOUND =
+      createMessageReference(EdmException.class, "NAVIGATIONPROPERTYNOTFOUND");
+  public static final MessageReference MUSTBENAVIGATIONPROPERTY =
+      createMessageReference(EdmException.class, "MUSTBENAVIGATIONPROPERTY");
+  public static final MessageReference MUSTBEPROPERTY = createMessageReference(EdmException.class, "MUSTBEPROPERTY");
 
   public EdmException(final MessageReference messageReference) {
     super(messageReference);

http://git-wip-us.apache.org/repos/asf/incubator-olingo-odata2/blob/bb73dadd/odata2-lib/odata-api/src/main/java/org/apache/olingo/odata2/api/rt/RuntimeDelegate.java
----------------------------------------------------------------------
diff --git a/odata2-lib/odata-api/src/main/java/org/apache/olingo/odata2/api/rt/RuntimeDelegate.java b/odata2-lib/odata-api/src/main/java/org/apache/olingo/odata2/api/rt/RuntimeDelegate.java
index e385c62..f0c1fc3 100644
--- a/odata2-lib/odata-api/src/main/java/org/apache/olingo/odata2/api/rt/RuntimeDelegate.java
+++ b/odata2-lib/odata-api/src/main/java/org/apache/olingo/odata2/api/rt/RuntimeDelegate.java
@@ -35,6 +35,7 @@ import org.apache.olingo.odata2.api.ep.EntityProviderException;
 import org.apache.olingo.odata2.api.processor.ODataRequest.ODataRequestBuilder;
 import org.apache.olingo.odata2.api.processor.ODataResponse.ODataResponseBuilder;
 import org.apache.olingo.odata2.api.processor.ODataSingleProcessor;
+import org.apache.olingo.odata2.api.uri.ExpandSelectTreeNode.ExpandSelectTreeNodeBuilder;
 import org.apache.olingo.odata2.api.uri.UriParser;
 
 /**
@@ -107,6 +108,8 @@ public abstract class RuntimeDelegate {
 
     protected abstract BatchChangeSetPartBuilder createBatchChangeSetRequest();
 
+    public abstract ExpandSelectTreeNodeBuilder createExpandSelectTreeNodeBuilder();
+
   }
 
   /**
@@ -210,4 +213,8 @@ public abstract class RuntimeDelegate {
   public static BatchChangeSetPartBuilder createBatchChangeSetPartBuilder() {
     return RuntimeDelegate.getInstance().createBatchChangeSetRequest();
   }
+
+  public static ExpandSelectTreeNodeBuilder createExpandSelectTreeNodeBuilder() {
+    return RuntimeDelegate.getInstance().createExpandSelectTreeNodeBuilder();
+  }
 }

http://git-wip-us.apache.org/repos/asf/incubator-olingo-odata2/blob/bb73dadd/odata2-lib/odata-api/src/main/java/org/apache/olingo/odata2/api/uri/ExpandSelectTreeNode.java
----------------------------------------------------------------------
diff --git a/odata2-lib/odata-api/src/main/java/org/apache/olingo/odata2/api/uri/ExpandSelectTreeNode.java b/odata2-lib/odata-api/src/main/java/org/apache/olingo/odata2/api/uri/ExpandSelectTreeNode.java
index aa99a50..b12eb43 100644
--- a/odata2-lib/odata-api/src/main/java/org/apache/olingo/odata2/api/uri/ExpandSelectTreeNode.java
+++ b/odata2-lib/odata-api/src/main/java/org/apache/olingo/odata2/api/uri/ExpandSelectTreeNode.java
@@ -21,19 +21,22 @@ package org.apache.olingo.odata2.api.uri;
 import java.util.List;
 import java.util.Map;
 
+import org.apache.olingo.odata2.api.edm.EdmEntitySet;
+import org.apache.olingo.odata2.api.edm.EdmException;
 import org.apache.olingo.odata2.api.edm.EdmProperty;
+import org.apache.olingo.odata2.api.rt.RuntimeDelegate;
 
 /**
  * Expression tree node with information about selected properties and to be expanded links.
  * @org.apache.olingo.odata2.DoNotImplement
  * 
  */
-public interface ExpandSelectTreeNode {
+public abstract class ExpandSelectTreeNode {
 
   /**
    * Determines whether all properties (including navigation properties) have been selected.
    */
-  public boolean isAll();
+  public abstract boolean isAll();
 
   /**
    * <p>Gets the list of explicitly selected {@link EdmProperty properties}.</p>
@@ -41,7 +44,7 @@ public interface ExpandSelectTreeNode {
    * It is empty if {@link #isAll()} returns <code>true</code>.</p>
    * @return List of selected properties
    */
-  public List<EdmProperty> getProperties();
+  public abstract List<EdmProperty> getProperties();
 
   /**
    * Gets the links that have to be included or expanded.
@@ -49,5 +52,83 @@ public interface ExpandSelectTreeNode {
    * if that node is <code>null</code>, a deferred link has been requested,
    * otherwise the link must be expanded with information found in that node
    */
-  public Map<String, ExpandSelectTreeNode> getLinks();
-}
+  public abstract Map<String, ExpandSelectTreeNode> getLinks();
+
+  /**
+   * Creates a builder instance and sets the entitySet for this node.
+   * @param entitySet on which this node is based
+   * @return {@link ExpandSelectTreeNodeBuilder} to build the node
+   */
+  public static ExpandSelectTreeNodeBuilder entitySet(final EdmEntitySet entitySet) {
+    return ExpandSelectTreeNodeBuilder.newInstance().entitySet(entitySet);
+  }
+
+  /**
+   * Builder interface
+   */
+  public static abstract class ExpandSelectTreeNodeBuilder {
+
+    /**
+     * Uses the runtime delegate to create a new instance
+     * @return instance of {@link ExpandSelectTreeNodeBuilder}
+     */
+    private static ExpandSelectTreeNodeBuilder newInstance() {
+      return RuntimeDelegate.createExpandSelectTreeNodeBuilder();
+    }
+
+    /**
+     * Sets the entitySet for this node.
+     * @param entitySet must not be null
+     * @return {@link ExpandSelectTreeNodeBuilder} for method chaining.
+     */
+    public abstract ExpandSelectTreeNodeBuilder entitySet(EdmEntitySet entitySet);
+
+    /**
+     * Will close this builder and return an {@link ExpandSelectTreeNode}. All properties and navigation properties will
+     * be validated if they exist for the entity set.
+     * @return {@link ExpandSelectTreeNodeBuilder} for method chaining.
+     * @throws EdmException in case property or navigation property validation fails.
+     */
+    public abstract ExpandSelectTreeNode build() throws EdmException;
+
+    /**
+     * A list of properties which are selected. Selected means that they appear in the payload during serialization.
+     * MUST NOT CONTAIN navigation properties.
+     * @param selectedPropertyNames
+     * @return {@link ExpandSelectTreeNodeBuilder} for method chaining.
+     */
+    public abstract ExpandSelectTreeNodeBuilder selectedProperties(List<String> selectedPropertyNames);
+
+    /**
+     * A list of selected links. Selected means they appear as links in the payload. If a link should be
+     * expanded they navigation property does not need to appear here but can. Expanded links will win over selected
+     * links.
+     * @param selectedNavigationPropertyNames
+     * @return {@link ExpandSelectTreeNodeBuilder} for method chaining.
+     */
+    public abstract ExpandSelectTreeNodeBuilder selectedLinks(List<String> selectedNavigationPropertyNames);
+
+    /**
+     * Sets a link to be expanded with a custom node. With this the inline content can either also be expanded or
+     * selected. Custom nodes for a navigation properties will win over navigation properties which are also specified
+     * in the expanded links list. Example: if a link A is set with a custom node and A appears in the expanded link
+     * list it will be expanded with the custom node.
+     * @param navigationPropertyName
+     * @param expandNode must not be null
+     * @return {@link ExpandSelectTreeNodeBuilder} for method chaining.
+     */
+    public abstract ExpandSelectTreeNodeBuilder customExpandedLink(String navigationPropertyName,
+        ExpandSelectTreeNode expandNode);
+
+    /**
+     * A list of expanded links. Expanded means their content will be shown as inline entry or feed in the payload but a
+     * callback MUST BE registered to get the content for the inline content. The inline content will appear with all
+     * properties and links. If this is not needed use the customExpandedLink method to set a custom node for this
+     * expanded link. Expanded links will win over selected links. If a custom node was set for a particular link it
+     * will win over a link that is specified in this list.
+     * @param navigationPropertyNames
+     * @return {@link ExpandSelectTreeNodeBuilder} for method chaining.
+     */
+    public abstract ExpandSelectTreeNodeBuilder expandedLinks(List<String> navigationPropertyNames);
+  }
+}
\ No newline at end of file

http://git-wip-us.apache.org/repos/asf/incubator-olingo-odata2/blob/bb73dadd/odata2-lib/odata-core/src/main/java/org/apache/olingo/odata2/core/rt/RuntimeDelegateImpl.java
----------------------------------------------------------------------
diff --git a/odata2-lib/odata-core/src/main/java/org/apache/olingo/odata2/core/rt/RuntimeDelegateImpl.java b/odata2-lib/odata-core/src/main/java/org/apache/olingo/odata2/core/rt/RuntimeDelegateImpl.java
index cc1c6e7..f37b590 100644
--- a/odata2-lib/odata-core/src/main/java/org/apache/olingo/odata2/core/rt/RuntimeDelegateImpl.java
+++ b/odata2-lib/odata-core/src/main/java/org/apache/olingo/odata2/core/rt/RuntimeDelegateImpl.java
@@ -36,6 +36,7 @@ import org.apache.olingo.odata2.api.processor.ODataRequest.ODataRequestBuilder;
 import org.apache.olingo.odata2.api.processor.ODataResponse.ODataResponseBuilder;
 import org.apache.olingo.odata2.api.processor.ODataSingleProcessor;
 import org.apache.olingo.odata2.api.rt.RuntimeDelegate.RuntimeDelegateInstance;
+import org.apache.olingo.odata2.api.uri.ExpandSelectTreeNode.ExpandSelectTreeNodeBuilder;
 import org.apache.olingo.odata2.api.uri.UriParser;
 import org.apache.olingo.odata2.core.ODataRequestImpl;
 import org.apache.olingo.odata2.core.ODataResponseImpl;
@@ -48,6 +49,7 @@ import org.apache.olingo.odata2.core.edm.provider.EdmImplProv;
 import org.apache.olingo.odata2.core.edm.provider.EdmxProvider;
 import org.apache.olingo.odata2.core.ep.ProviderFacadeImpl;
 import org.apache.olingo.odata2.core.processor.ODataSingleProcessorService;
+import org.apache.olingo.odata2.core.uri.ExpandSelectTreeNodeImpl;
 import org.apache.olingo.odata2.core.uri.UriParserImpl;
 
 /**
@@ -129,4 +131,10 @@ public class RuntimeDelegateImpl extends RuntimeDelegateInstance {
     return batchChangeSetRequest.new BatchChangeSetRequestBuilderImpl();
   }
 
+  @Override
+  public ExpandSelectTreeNodeBuilder createExpandSelectTreeNodeBuilder() {
+    ExpandSelectTreeNodeImpl expandSelectTreeNode = new ExpandSelectTreeNodeImpl();
+    return expandSelectTreeNode.new ExpandSelectTreeNodeBuilderImpl();
+  }
+
 }

http://git-wip-us.apache.org/repos/asf/incubator-olingo-odata2/blob/bb73dadd/odata2-lib/odata-core/src/main/java/org/apache/olingo/odata2/core/uri/ExpandSelectTreeNodeImpl.java
----------------------------------------------------------------------
diff --git a/odata2-lib/odata-core/src/main/java/org/apache/olingo/odata2/core/uri/ExpandSelectTreeNodeImpl.java b/odata2-lib/odata-core/src/main/java/org/apache/olingo/odata2/core/uri/ExpandSelectTreeNodeImpl.java
index d14e1bb..ba3f624 100644
--- a/odata2-lib/odata-core/src/main/java/org/apache/olingo/odata2/core/uri/ExpandSelectTreeNodeImpl.java
+++ b/odata2-lib/odata-core/src/main/java/org/apache/olingo/odata2/core/uri/ExpandSelectTreeNodeImpl.java
@@ -26,8 +26,12 @@ import java.util.HashMap;
 import java.util.List;
 import java.util.Map;
 
+import org.apache.olingo.odata2.api.edm.EdmEntitySet;
+import org.apache.olingo.odata2.api.edm.EdmEntityType;
 import org.apache.olingo.odata2.api.edm.EdmException;
+import org.apache.olingo.odata2.api.edm.EdmNavigationProperty;
 import org.apache.olingo.odata2.api.edm.EdmProperty;
+import org.apache.olingo.odata2.api.edm.EdmTyped;
 import org.apache.olingo.odata2.api.uri.ExpandSelectTreeNode;
 import org.apache.olingo.odata2.core.ep.util.JsonStreamWriter;
 import org.apache.olingo.odata2.core.exception.ODataRuntimeException;
@@ -35,7 +39,7 @@ import org.apache.olingo.odata2.core.exception.ODataRuntimeException;
 /**
  *  
  */
-public class ExpandSelectTreeNodeImpl implements ExpandSelectTreeNode {
+public class ExpandSelectTreeNodeImpl extends ExpandSelectTreeNode {
 
   public enum AllKinds {
     IMPLICITLYTRUE(true), EXPLICITLYTRUE(true), FALSE(false);
@@ -161,4 +165,110 @@ public class ExpandSelectTreeNodeImpl implements ExpandSelectTreeNode {
       throw new ODataRuntimeException("EdmException: ", e);
     }
   }
+
+  public class ExpandSelectTreeNodeBuilderImpl extends ExpandSelectTreeNodeBuilder {
+
+    EdmEntitySet entitySet;
+    private List<String> selectedPropertyNames;
+    private List<String> selectedNavigationPropertyNames;
+    private Map<String, ExpandSelectTreeNode> customExpandedNavigationProperties;
+    private List<String> expandedNavigationPropertyNames;
+
+    @Override
+    public ExpandSelectTreeNodeBuilder entitySet(final EdmEntitySet entitySet) {
+      this.entitySet = entitySet;
+      return this;
+    }
+
+    @Override
+    public ExpandSelectTreeNode build() throws EdmException {
+      EdmEntityType entityType = entitySet.getEntityType();
+      if (selectedPropertyNames != null) {
+        for (String propertyName : selectedPropertyNames) {
+          EdmTyped property = entityType.getProperty(propertyName);
+          if (property == null) {
+            throw new EdmException(EdmException.PROPERTYNOTFOUND.addContent(propertyName));
+          } else if (!(property instanceof EdmProperty)) {
+            throw new EdmException(EdmException.MUSTBEPROPERTY.addContent(propertyName));
+          }
+          addProperty((EdmProperty) property);
+        }
+      }
+
+      if (selectedNavigationPropertyNames != null) {
+        setAllKindFalse();
+        for (String navigationPropertyName : selectedNavigationPropertyNames) {
+          EdmTyped navigationProperty = entityType.getProperty(navigationPropertyName);
+          if (navigationProperty == null) {
+            throw new EdmException(EdmException.NAVIGATIONPROPERTYNOTFOUND.addContent(navigationPropertyName));
+          } else if (!(navigationProperty instanceof EdmNavigationProperty)) {
+            throw new EdmException(EdmException.MUSTBENAVIGATIONPROPERTY.addContent(navigationPropertyName));
+          }
+          putLink(navigationPropertyName, null);
+        }
+      }
+
+      if (expandedNavigationPropertyNames != null) {
+        ExpandSelectTreeNodeImpl subNode = new ExpandSelectTreeNodeImpl();
+        subNode.setExplicitlySelected();
+        for (String navigationPropertyName : expandedNavigationPropertyNames) {
+          EdmTyped navigationProperty = entityType.getProperty(navigationPropertyName);
+          if (navigationProperty == null) {
+            throw new EdmException(EdmException.NAVIGATIONPROPERTYNOTFOUND.addContent(navigationPropertyName));
+          } else if (!(navigationProperty instanceof EdmNavigationProperty)) {
+            throw new EdmException(EdmException.MUSTBENAVIGATIONPROPERTY.addContent(navigationPropertyName));
+          }
+          putLink(navigationPropertyName, subNode);
+        }
+      }
+
+      if (customExpandedNavigationProperties != null) {
+        for (Map.Entry<String, ExpandSelectTreeNode> entry : customExpandedNavigationProperties.entrySet()) {
+          EdmTyped navigationProperty = entityType.getProperty(entry.getKey());
+          if (navigationProperty == null) {
+            throw new EdmException(EdmException.NAVIGATIONPROPERTYNOTFOUND.addContent(entry.getKey()));
+          }
+          if (!(navigationProperty instanceof EdmNavigationProperty)) {
+            throw new EdmException(EdmException.MUSTBENAVIGATIONPROPERTY.addContent(entry.getKey()));
+          }
+          putLink(entry.getKey(), (ExpandSelectTreeNodeImpl) entry.getValue());
+        }
+      }
+
+      return ExpandSelectTreeNodeImpl.this;
+    }
+
+    @Override
+    public ExpandSelectTreeNodeBuilder selectedProperties(final List<String> selectedPropertyNames) {
+      this.selectedPropertyNames = selectedPropertyNames;
+      return this;
+    }
+
+    @Override
+    public ExpandSelectTreeNodeBuilder selectedLinks(final List<String> selectedNavigationPropertyNames) {
+      this.selectedNavigationPropertyNames = selectedNavigationPropertyNames;
+      return this;
+    }
+
+    @Override
+    public ExpandSelectTreeNodeBuilder
+        customExpandedLink(final String navigationPropertyName, final ExpandSelectTreeNode expandNode) {
+      if (expandNode == null) {
+        throw new ODataRuntimeException("ExpandNode must not be null");
+      }
+      if (customExpandedNavigationProperties == null) {
+        customExpandedNavigationProperties = new HashMap<String, ExpandSelectTreeNode>();
+      }
+      customExpandedNavigationProperties.put(navigationPropertyName, expandNode);
+      return this;
+    }
+
+    @Override
+    public ExpandSelectTreeNodeBuilder expandedLinks(final List<String> navigationPropertyNames) {
+      expandedNavigationPropertyNames = navigationPropertyNames;
+      return this;
+    }
+
+  }
+
 }

http://git-wip-us.apache.org/repos/asf/incubator-olingo-odata2/blob/bb73dadd/odata2-lib/odata-core/src/main/resources/i18n.properties
----------------------------------------------------------------------
diff --git a/odata2-lib/odata-core/src/main/resources/i18n.properties b/odata2-lib/odata-core/src/main/resources/i18n.properties
index b28bf50..08c08a1 100644
--- a/odata2-lib/odata-core/src/main/resources/i18n.properties
+++ b/odata2-lib/odata-core/src/main/resources/i18n.properties
@@ -67,6 +67,10 @@ org.apache.olingo.odata2.api.edm.EdmLiteralException.UNKNOWNLITERAL=Unknown lite
 
 org.apache.olingo.odata2.api.edm.EdmException.COMMON=An exception occurred.
 org.apache.olingo.odata2.api.edm.EdmException.PROVIDERPROBLEM=A problem has been detected in the metadata provided by the EDM provider.
+org.apache.olingo.odata2.api.edm.EdmException.PROPERTYNOTFOUND=Invalid property with name '%1$s'
+org.apache.olingo.odata2.api.edm.EdmException.NAVIGATIONPROPERTYNOTFOUND=Invalid navigation property with name '%1$s'
+org.apache.olingo.odata2.api.edm.EdmException.MUSTBENAVIGATIONPROPERTY=The found typed value for '%1$s' must be a navigation property but is not.
+org.apache.olingo.odata2.api.edm.EdmException.MUSTBEPROPERTY=The found typed value for '%1$s' must be a property but is not.
 
 org.apache.olingo.odata2.api.edm.EdmSimpleTypeException.COMMON=An exception occurred.
 org.apache.olingo.odata2.api.edm.EdmSimpleTypeException.LITERAL_KIND_MISSING=The literal kind is missing.

http://git-wip-us.apache.org/repos/asf/incubator-olingo-odata2/blob/bb73dadd/odata2-lib/odata-core/src/test/java/org/apache/olingo/odata2/core/ep/producer/ExpandSelectProducerWithBuilderTest.java
----------------------------------------------------------------------
diff --git a/odata2-lib/odata-core/src/test/java/org/apache/olingo/odata2/core/ep/producer/ExpandSelectProducerWithBuilderTest.java b/odata2-lib/odata-core/src/test/java/org/apache/olingo/odata2/core/ep/producer/ExpandSelectProducerWithBuilderTest.java
new file mode 100644
index 0000000..6eabdfc
--- /dev/null
+++ b/odata2-lib/odata-core/src/test/java/org/apache/olingo/odata2/core/ep/producer/ExpandSelectProducerWithBuilderTest.java
@@ -0,0 +1,204 @@
+/*******************************************************************************
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License. You may obtain a copy of the License at
+ * 
+ * http://www.apache.org/licenses/LICENSE-2.0
+ * 
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied. See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ ******************************************************************************/
+package org.apache.olingo.odata2.core.ep.producer;
+
+import static org.custommonkey.xmlunit.XMLAssert.assertXpathExists;
+import static org.custommonkey.xmlunit.XMLAssert.assertXpathNotExists;
+
+import java.io.InputStream;
+import java.util.ArrayList;
+import java.util.HashMap;
+import java.util.List;
+import java.util.Map;
+
+import org.apache.olingo.odata2.api.ODataCallback;
+import org.apache.olingo.odata2.api.edm.EdmEntitySet;
+import org.apache.olingo.odata2.api.edm.EdmNavigationProperty;
+import org.apache.olingo.odata2.api.ep.EntityProvider;
+import org.apache.olingo.odata2.api.ep.EntityProviderWriteProperties;
+import org.apache.olingo.odata2.api.ep.callback.OnWriteEntryContent;
+import org.apache.olingo.odata2.api.ep.callback.WriteEntryCallbackContext;
+import org.apache.olingo.odata2.api.ep.callback.WriteEntryCallbackResult;
+import org.apache.olingo.odata2.api.exception.ODataApplicationException;
+import org.apache.olingo.odata2.api.processor.ODataResponse;
+import org.apache.olingo.odata2.api.uri.ExpandSelectTreeNode;
+import org.apache.olingo.odata2.core.ep.AbstractProviderTest;
+import org.apache.olingo.odata2.testutil.helper.StringHelper;
+import org.apache.olingo.odata2.testutil.mock.MockFacade;
+import org.junit.Test;
+
+public class ExpandSelectProducerWithBuilderTest extends AbstractProviderTest {
+
+  public class LocalCallback implements OnWriteEntryContent {
+
+    @Override
+    public WriteEntryCallbackResult retrieveEntryResult(final WriteEntryCallbackContext context)
+        throws ODataApplicationException {
+      WriteEntryCallbackResult writeEntryCallbackResult = new WriteEntryCallbackResult();
+      EntityProviderWriteProperties inlineProperties =
+          EntityProviderWriteProperties.fromProperties(DEFAULT_PROPERTIES).expandSelectTree(
+              context.getCurrentExpandSelectTreeNode()).build();
+      writeEntryCallbackResult.setInlineProperties(inlineProperties);
+      Map<String, Object> buildingData = new HashMap<String, Object>();
+      buildingData.put("Id", "1");
+      buildingData.put("Name", "BuildingName");
+      writeEntryCallbackResult.setEntryData(buildingData);
+      return writeEntryCallbackResult;
+    }
+
+  }
+
+  public ExpandSelectProducerWithBuilderTest(final StreamWriterImplType type) {
+    super(type);
+  }
+
+  @Test
+  public void selectOnlyProperties() throws Exception {
+    EdmEntitySet roomsSet = MockFacade.getMockEdm().getDefaultEntityContainer().getEntitySet("Rooms");
+    List<String> selectedProperties = new ArrayList<String>(roomData.keySet());
+
+    ExpandSelectTreeNode expandSelectTree =
+        ExpandSelectTreeNode.entitySet(roomsSet).selectedProperties(selectedProperties).build();
+
+    EntityProviderWriteProperties properties =
+        EntityProviderWriteProperties.fromProperties(DEFAULT_PROPERTIES).expandSelectTree(expandSelectTree).build();
+    ODataResponse entry = EntityProvider.writeEntry("application/xml", roomsSet, roomData, properties);
+
+    String xml = StringHelper.inputStreamToString((InputStream) entry.getEntity());
+    assertXpathExists("/a:entry/a:content/m:properties", xml);
+    assertXpathNotExists("/a:entry/a:link[@type]", xml);
+  }
+
+  @Test
+  public void selectOnlyLinks() throws Exception {
+    EdmEntitySet roomsSet = MockFacade.getMockEdm().getDefaultEntityContainer().getEntitySet("Rooms");
+    List<String> selectedNavigationProperties = new ArrayList<String>();
+    selectedNavigationProperties.add("nr_Building");
+    selectedNavigationProperties.add("nr_Employees");
+
+    ExpandSelectTreeNode expandSelectTree =
+        ExpandSelectTreeNode.entitySet(roomsSet).selectedLinks(selectedNavigationProperties).build();
+
+    EntityProviderWriteProperties properties =
+        EntityProviderWriteProperties.fromProperties(DEFAULT_PROPERTIES).expandSelectTree(expandSelectTree).build();
+    ODataResponse entry = EntityProvider.writeEntry("application/xml", roomsSet, roomData, properties);
+
+    String xml = StringHelper.inputStreamToString((InputStream) entry.getEntity());
+    assertXpathNotExists("/a:entry/a:content/m:properties", xml);
+    assertXpathExists("/a:entry/a:link[@type]", xml);
+  }
+
+  @Test
+  public void selectIdAndBuildingLink() throws Exception {
+    EdmEntitySet roomsSet = MockFacade.getMockEdm().getDefaultEntityContainer().getEntitySet("Rooms");
+    List<String> selectedNavigationProperties = new ArrayList<String>();
+    selectedNavigationProperties.add("nr_Building");
+
+    List<String> selectedProperties = new ArrayList<String>();
+    selectedProperties.add("Id");
+
+    ExpandSelectTreeNode expandSelectTree =
+        ExpandSelectTreeNode.entitySet(roomsSet).selectedProperties(selectedProperties).selectedLinks(
+            selectedNavigationProperties).build();
+
+    EntityProviderWriteProperties properties =
+        EntityProviderWriteProperties.fromProperties(DEFAULT_PROPERTIES).expandSelectTree(expandSelectTree).build();
+    ODataResponse entry = EntityProvider.writeEntry("application/xml", roomsSet, roomData, properties);
+
+    String xml = StringHelper.inputStreamToString((InputStream) entry.getEntity());
+    assertXpathExists("/a:entry/a:content/m:properties", xml);
+    assertXpathExists("/a:entry/a:link[@type]", xml);
+  }
+
+  @Test
+  public void expandBuilding() throws Exception {
+    EdmEntitySet roomsSet = MockFacade.getMockEdm().getDefaultEntityContainer().getEntitySet("Rooms");
+    List<String> expandedNavigationProperties = new ArrayList<String>();
+    expandedNavigationProperties.add("nr_Building");
+
+    ExpandSelectTreeNode expandSelectTree =
+        ExpandSelectTreeNode.entitySet(roomsSet).expandedLinks(expandedNavigationProperties).build();
+
+    Map<String, ODataCallback> callbacks = new HashMap<String, ODataCallback>();
+    callbacks.put("nr_Building", new LocalCallback());
+    EntityProviderWriteProperties properties =
+        EntityProviderWriteProperties.fromProperties(DEFAULT_PROPERTIES).callbacks(callbacks).expandSelectTree(
+            expandSelectTree).build();
+    ODataResponse entry = EntityProvider.writeEntry("application/xml", roomsSet, roomData, properties);
+
+    String xml = StringHelper.inputStreamToString((InputStream) entry.getEntity());
+    assertXpathExists("/a:entry/a:content/m:properties", xml);
+    assertXpathExists("/a:entry/a:link[@type]/m:inline", xml);
+  }
+
+  @Test
+  public void expandBuildingAndSelectIdFromRoom() throws Exception {
+    EdmEntitySet roomsSet = MockFacade.getMockEdm().getDefaultEntityContainer().getEntitySet("Rooms");
+    List<String> expandedNavigationProperties = new ArrayList<String>();
+    expandedNavigationProperties.add("nr_Building");
+
+    List<String> selectedProperties = new ArrayList<String>();
+    selectedProperties.add("Id");
+
+    ExpandSelectTreeNode expandSelectTree =
+        ExpandSelectTreeNode.entitySet(roomsSet).selectedProperties(selectedProperties).expandedLinks(
+            expandedNavigationProperties).build();
+
+    Map<String, ODataCallback> callbacks = new HashMap<String, ODataCallback>();
+    callbacks.put("nr_Building", new LocalCallback());
+    EntityProviderWriteProperties properties =
+        EntityProviderWriteProperties.fromProperties(DEFAULT_PROPERTIES).callbacks(callbacks).expandSelectTree(
+            expandSelectTree).build();
+    ODataResponse entry = EntityProvider.writeEntry("application/xml", roomsSet, roomData, properties);
+
+    String xml = StringHelper.inputStreamToString((InputStream) entry.getEntity());
+    assertXpathExists("/a:entry/a:content/m:properties/d:Id", xml);
+    assertXpathNotExists("/a:entry/a:content/m:properties/d:Name", xml);
+    assertXpathExists("/a:entry/a:link[@type]/m:inline", xml);
+  }
+
+  @Test
+  public void customExpandBuildingAndSelectIdFromCustomNode() throws Exception {
+    EdmEntitySet roomsSet = MockFacade.getMockEdm().getDefaultEntityContainer().getEntitySet("Rooms");
+
+    List<String> selectedPropertiesAtCustomProperties = new ArrayList<String>();
+    selectedPropertiesAtCustomProperties.add("Id");
+    EdmEntitySet buildingsSet =
+        roomsSet.getRelatedEntitySet((EdmNavigationProperty) roomsSet.getEntityType().getProperty("nr_Building"));
+    ExpandSelectTreeNode customNode =
+        ExpandSelectTreeNode.entitySet(buildingsSet).selectedProperties(selectedPropertiesAtCustomProperties).build();
+
+    ExpandSelectTreeNode expandSelectTree =
+        ExpandSelectTreeNode.entitySet(roomsSet).customExpandedLink("nr_Building", customNode).build();
+
+    Map<String, ODataCallback> callbacks = new HashMap<String, ODataCallback>();
+    callbacks.put("nr_Building", new LocalCallback());
+    EntityProviderWriteProperties properties =
+        EntityProviderWriteProperties.fromProperties(DEFAULT_PROPERTIES).callbacks(callbacks).expandSelectTree(
+            expandSelectTree).build();
+    ODataResponse entry = EntityProvider.writeEntry("application/xml", roomsSet, roomData, properties);
+
+    String xml = StringHelper.inputStreamToString((InputStream) entry.getEntity());
+    assertXpathExists("/a:entry/a:content/m:properties", xml);
+    assertXpathExists("/a:entry/a:link[@type]/m:inline", xml);
+    assertXpathExists("/a:entry/a:link[@type]/m:inline/a:entry/a:content/m:properties/d:Id", xml);
+    assertXpathNotExists("/a:entry/a:link[@type]/m:inline/a:entry/a:content/m:properties/d:Name", xml);
+  }
+
+}

http://git-wip-us.apache.org/repos/asf/incubator-olingo-odata2/blob/bb73dadd/odata2-lib/odata-core/src/test/java/org/apache/olingo/odata2/core/ep/producer/XmlExpandProducerTest.java
----------------------------------------------------------------------
diff --git a/odata2-lib/odata-core/src/test/java/org/apache/olingo/odata2/core/ep/producer/XmlExpandProducerTest.java b/odata2-lib/odata-core/src/test/java/org/apache/olingo/odata2/core/ep/producer/XmlExpandProducerTest.java
index c9ff16a..c4ba63c 100644
--- a/odata2-lib/odata-core/src/test/java/org/apache/olingo/odata2/core/ep/producer/XmlExpandProducerTest.java
+++ b/odata2-lib/odata-core/src/test/java/org/apache/olingo/odata2/core/ep/producer/XmlExpandProducerTest.java
@@ -34,6 +34,7 @@ import java.util.Map;
 
 import org.apache.olingo.odata2.api.ODataCallback;
 import org.apache.olingo.odata2.api.edm.Edm;
+import org.apache.olingo.odata2.api.edm.EdmEntitySet;
 import org.apache.olingo.odata2.api.edm.EdmException;
 import org.apache.olingo.odata2.api.ep.EntityProviderException;
 import org.apache.olingo.odata2.api.ep.EntityProviderWriteProperties;
@@ -104,6 +105,29 @@ public class XmlExpandProducerTest extends AbstractProviderTest {
   }
 
   @Test
+  public void expandSelectedEmployeesWithBuilder() throws Exception {
+    EdmEntitySet entitySet = MockFacade.getMockEdm().getDefaultEntityContainer().getEntitySet("Rooms");
+    List<String> navigationPropertyNames = new ArrayList<String>();
+    navigationPropertyNames.add("nr_Employees");
+    ExpandSelectTreeNode selectTree =
+        ExpandSelectTreeNode.entitySet(entitySet).expandedLinks(navigationPropertyNames).build();
+
+    HashMap<String, ODataCallback> callbacksRoom = createCallbacks("Rooms");
+    EntityProviderWriteProperties properties =
+        EntityProviderWriteProperties.serviceRoot(BASE_URI).expandSelectTree(selectTree).callbacks(callbacksRoom)
+            .build();
+    AtomEntityProvider provider = createAtomEntityProvider();
+    ODataResponse response =
+        provider.writeEntry(entitySet, roomData,
+            properties);
+
+    String xmlString = verifyResponse(response);
+    assertXpathNotExists("/a:entry/m:properties", xmlString);
+    assertXpathExists("/a:entry/a:link", xmlString);
+    verifyEmployees(employeeXPathString, xmlString);
+  }
+
+  @Test
   public void expandSelectedEmployeesNull() throws Exception {
     ExpandSelectTreeNode selectTree = getSelectExpandTree("Rooms('1')", "nr_Employees", "nr_Employees");
 

http://git-wip-us.apache.org/repos/asf/incubator-olingo-odata2/blob/bb73dadd/odata2-lib/odata-core/src/test/java/org/apache/olingo/odata2/core/uri/ExpandSelectTreeNodeBuilderTest.java
----------------------------------------------------------------------
diff --git a/odata2-lib/odata-core/src/test/java/org/apache/olingo/odata2/core/uri/ExpandSelectTreeNodeBuilderTest.java b/odata2-lib/odata-core/src/test/java/org/apache/olingo/odata2/core/uri/ExpandSelectTreeNodeBuilderTest.java
new file mode 100644
index 0000000..ec9b3fd
--- /dev/null
+++ b/odata2-lib/odata-core/src/test/java/org/apache/olingo/odata2/core/uri/ExpandSelectTreeNodeBuilderTest.java
@@ -0,0 +1,282 @@
+/*******************************************************************************
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License. You may obtain a copy of the License at
+ * 
+ * http://www.apache.org/licenses/LICENSE-2.0
+ * 
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied. See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ ******************************************************************************/
+package org.apache.olingo.odata2.core.uri;
+
+import static org.junit.Assert.assertEquals;
+import static org.junit.Assert.assertFalse;
+import static org.junit.Assert.assertNotNull;
+import static org.junit.Assert.assertNull;
+import static org.junit.Assert.assertTrue;
+import static org.mockito.Mockito.mock;
+
+import java.util.ArrayList;
+import java.util.List;
+
+import org.apache.olingo.odata2.api.edm.Edm;
+import org.apache.olingo.odata2.api.edm.EdmEntitySet;
+import org.apache.olingo.odata2.api.edm.EdmException;
+import org.apache.olingo.odata2.api.uri.ExpandSelectTreeNode;
+import org.apache.olingo.odata2.core.exception.ODataRuntimeException;
+import org.apache.olingo.odata2.testutil.fit.BaseTest;
+import org.apache.olingo.odata2.testutil.mock.MockFacade;
+import org.junit.Before;
+import org.junit.Test;
+
+public class ExpandSelectTreeNodeBuilderTest extends BaseTest {
+
+  Edm edm;
+
+  @Before
+  public void setupEdm() throws Exception {
+    edm = MockFacade.getMockEdm();
+  }
+
+  @Test
+  public void initialBuildWithOnlyEntitySet() throws Exception {
+    ExpandSelectTreeNode node = ExpandSelectTreeNode.entitySet(mock(EdmEntitySet.class)).build();
+    assertNotNull(node);
+    assertTrue(node.isAll());
+    assertTrue(node.getProperties().isEmpty());
+    assertTrue(node.getLinks().isEmpty());
+  }
+
+  @Test
+  public void buildWithRightSelectedPropertiesOnly() throws Exception {
+    EdmEntitySet roomsSet = edm.getDefaultEntityContainer().getEntitySet("Rooms");
+    List<String> selectedPropertyNames = new ArrayList<String>();
+    selectedPropertyNames.add("Id");
+    ExpandSelectTreeNode node =
+        ExpandSelectTreeNode.entitySet(roomsSet).selectedProperties(selectedPropertyNames).build();
+    assertNotNull(node);
+    assertFalse(node.isAll());
+    assertFalse(node.getProperties().isEmpty());
+    assertTrue(node.getLinks().isEmpty());
+
+    assertEquals(1, node.getProperties().size());
+    assertEquals("Id", node.getProperties().get(0).getName());
+  }
+
+  @Test
+  public void buildWithRightSelectedNavigationPropertiesOnly() throws Exception {
+    EdmEntitySet roomsSet = edm.getDefaultEntityContainer().getEntitySet("Rooms");
+    List<String> selectedNavigationPropertyNames = new ArrayList<String>();
+    selectedNavigationPropertyNames.add("nr_Employees");
+    ExpandSelectTreeNode node =
+        ExpandSelectTreeNode.entitySet(roomsSet).selectedLinks(selectedNavigationPropertyNames).build();
+    assertNotNull(node);
+    assertFalse(node.isAll());
+    assertTrue(node.getProperties().isEmpty());
+    assertFalse(node.getLinks().isEmpty());
+
+    assertEquals(1, node.getLinks().size());
+    assertTrue(node.getLinks().containsKey("nr_Employees"));
+    assertNull(node.getLinks().get("nr_Employees"));
+  }
+
+  @Test
+  public void buildWithRightExpandedNavigationPropertiesOnly() throws Exception {
+    EdmEntitySet roomsSet = edm.getDefaultEntityContainer().getEntitySet("Rooms");
+    String navigationPropertyName = "nr_Employees";
+    List<String> navigationPropertyNames = new ArrayList<String>();
+    navigationPropertyNames.add(navigationPropertyName);
+
+    ExpandSelectTreeNode node =
+        ExpandSelectTreeNode.entitySet(roomsSet).expandedLinks(navigationPropertyNames).build();
+    assertExpandedNode(node);
+
+    assertLinksWithOneNavigationProperty(navigationPropertyName, node);
+  }
+
+  @Test
+  public void buildWithRightCustomExpandedNavigationPropertyOnly() throws Exception {
+    EdmEntitySet roomsSet = edm.getDefaultEntityContainer().getEntitySet("Rooms");
+    ExpandSelectTreeNode expandNode = ExpandSelectTreeNode.entitySet(mock(EdmEntitySet.class)).build();
+    String navigationPropertyName = "nr_Employees";
+
+    ExpandSelectTreeNode node =
+        ExpandSelectTreeNode.entitySet(roomsSet).customExpandedLink(navigationPropertyName, expandNode).build();
+    assertExpandedNode(node);
+
+    assertLinksWithOneNavigationProperty(navigationPropertyName, node);
+  }
+
+  @Test
+  public void expandedAndCustomExpandedNavPropCustomMustWin() throws Exception {
+    EdmEntitySet roomsSet = edm.getDefaultEntityContainer().getEntitySet("Rooms");
+    ExpandSelectTreeNode expandNode = ExpandSelectTreeNode.entitySet(mock(EdmEntitySet.class)).build();
+    String navigationPropertyName = "nr_Employees";
+    List<String> navigationPropertyNames = new ArrayList<String>();
+    navigationPropertyNames.add(navigationPropertyName);
+
+    ExpandSelectTreeNode node = ExpandSelectTreeNode.entitySet(roomsSet)
+        .customExpandedLink(navigationPropertyName, expandNode).expandedLinks(navigationPropertyNames).build();
+    assertExpandedNode(node);
+
+    assertLinksWithOneNavigationProperty(navigationPropertyName, node);
+    assertEquals(expandNode, node.getLinks().get(navigationPropertyName));
+  }
+
+  @Test
+  public void selectedPropertiesAndExpandedNavigationProperties() throws Exception {
+    EdmEntitySet roomsSet = edm.getDefaultEntityContainer().getEntitySet("Rooms");
+    List<String> selectedPropertyNames = new ArrayList<String>();
+    selectedPropertyNames.add("Id");
+    List<String> navigationPropertyNames = new ArrayList<String>();
+    navigationPropertyNames.add("nr_Employees");
+    ExpandSelectTreeNode node = ExpandSelectTreeNode.entitySet(roomsSet).selectedProperties(selectedPropertyNames)
+        .expandedLinks(navigationPropertyNames).build();
+    assertNotNull(node);
+    assertFalse(node.isAll());
+    assertFalse(node.getProperties().isEmpty());
+    assertFalse(node.getLinks().isEmpty());
+
+    assertEquals(1, node.getProperties().size());
+    assertEquals("Id", node.getProperties().get(0).getName());
+
+    assertLinksWithOneNavigationProperty("nr_Employees", node);
+  }
+
+  @Test
+  public void selectedNavPropsAndExpandedNavPropsExpandedMustNotBeNull() throws Exception {
+    EdmEntitySet roomsSet = edm.getDefaultEntityContainer().getEntitySet("Rooms");
+    String navigationPropertyName = "nr_Employees";
+    List<String> navigationPropertyNames = new ArrayList<String>();
+    navigationPropertyNames.add(navigationPropertyName);
+
+    ExpandSelectTreeNode node = ExpandSelectTreeNode.entitySet(roomsSet).selectedLinks(navigationPropertyNames)
+        .expandedLinks(navigationPropertyNames).build();
+    assertNotNull(node);
+    assertFalse(node.isAll());
+    assertTrue(node.getProperties().isEmpty());
+    assertFalse(node.getLinks().isEmpty());
+
+    assertLinksWithOneNavigationProperty(navigationPropertyName, node);
+  }
+
+  @Test
+  public void selectedExpandedAndCustomExpanded() throws Exception {
+    EdmEntitySet roomsSet = edm.getDefaultEntityContainer().getEntitySet("Rooms");
+    List<String> selectedPropertyNames = new ArrayList<String>();
+    selectedPropertyNames.add("Id");
+    List<String> navigationPropertyNames = new ArrayList<String>();
+    navigationPropertyNames.add("nr_Employees");
+    ExpandSelectTreeNode expandNode = ExpandSelectTreeNode.entitySet(mock(EdmEntitySet.class)).build();
+
+    ExpandSelectTreeNode node =
+        ExpandSelectTreeNode.entitySet(roomsSet).selectedProperties(selectedPropertyNames).expandedLinks(
+            navigationPropertyNames).customExpandedLink("nr_Building", expandNode).build();
+
+    assertNotNull(node);
+    assertFalse(node.isAll());
+    assertFalse(node.getProperties().isEmpty());
+    assertFalse(node.getLinks().isEmpty());
+
+    assertEquals(1, node.getProperties().size());
+    assertEquals("Id", node.getProperties().get(0).getName());
+
+    assertEquals(2, node.getLinks().size());
+    assertTrue(node.getLinks().containsKey("nr_Employees"));
+    assertNotNull(node.getLinks().get("nr_Employees"));
+
+    assertTrue(node.getLinks().containsKey("nr_Building"));
+    assertNotNull(node.getLinks().get("nr_Building"));
+    assertEquals(expandNode, node.getLinks().get("nr_Building"));
+  }
+
+  @Test(expected = EdmException.class)
+  public void buildWithWrongSelectedPropertiesOnly() throws Exception {
+    EdmEntitySet roomsSet = edm.getDefaultEntityContainer().getEntitySet("Rooms");
+    List<String> selectedPropertyNames = new ArrayList<String>();
+    selectedPropertyNames.add("WrongProperty");
+    ExpandSelectTreeNode.entitySet(roomsSet).selectedProperties(selectedPropertyNames).build();
+  }
+
+  @Test(expected = EdmException.class)
+  public void buildWithWrongSelectedNavigationPropertiesOnly() throws Exception {
+    EdmEntitySet roomsSet = edm.getDefaultEntityContainer().getEntitySet("Rooms");
+    List<String> selectedNavigationPropertyNames = new ArrayList<String>();
+    selectedNavigationPropertyNames.add("WrongProperty");
+    ExpandSelectTreeNode.entitySet(roomsSet).selectedLinks(selectedNavigationPropertyNames).build();
+  }
+
+  @Test(expected = EdmException.class)
+  public void propertyInNavigationPropertiesList() throws Exception {
+    EdmEntitySet roomsSet = edm.getDefaultEntityContainer().getEntitySet("Rooms");
+    List<String> selectedNavigationPropertyNames = new ArrayList<String>();
+    selectedNavigationPropertyNames.add("Id");
+    ExpandSelectTreeNode.entitySet(roomsSet).selectedLinks(selectedNavigationPropertyNames).build();
+  }
+
+  @Test(expected = EdmException.class)
+  public void navigationPropertyInPropertiesList() throws Exception {
+    EdmEntitySet roomsSet = edm.getDefaultEntityContainer().getEntitySet("Rooms");
+    List<String> selectedPropertyNames = new ArrayList<String>();
+    selectedPropertyNames.add("nr_Building");
+    ExpandSelectTreeNode.entitySet(roomsSet).selectedProperties(selectedPropertyNames).build();
+  }
+
+  @Test(expected = EdmException.class)
+  public void propertyInExpandedNavigationPropertyList() throws Exception {
+    EdmEntitySet roomsSet = edm.getDefaultEntityContainer().getEntitySet("Rooms");
+    List<String> expandedNavigationPropertyNames = new ArrayList<String>();
+    expandedNavigationPropertyNames.add("Id");
+    ExpandSelectTreeNode.entitySet(roomsSet).expandedLinks(expandedNavigationPropertyNames).build();
+  }
+
+  @Test(expected = EdmException.class)
+  public void propertyInCustomExpandedNavigationPropertyList() throws Exception {
+    EdmEntitySet roomsSet = edm.getDefaultEntityContainer().getEntitySet("Rooms");
+    ExpandSelectTreeNode.entitySet(roomsSet).customExpandedLink("Id", mock(ExpandSelectTreeNode.class)).build();
+  }
+
+  @Test(expected = ODataRuntimeException.class)
+  public void nullNodeInCustomExpandedProperty() throws Exception {
+    EdmEntitySet roomsSet = edm.getDefaultEntityContainer().getEntitySet("Rooms");
+    ExpandSelectTreeNode.entitySet(roomsSet).customExpandedLink("nr_Building", null).build();
+  }
+
+  @Test(expected = EdmException.class)
+  public void wrongNavigationPropertyInCustomExpand() throws Exception {
+    EdmEntitySet roomsSet = edm.getDefaultEntityContainer().getEntitySet("Rooms");
+    ExpandSelectTreeNode.entitySet(roomsSet).customExpandedLink("Wrong", mock(ExpandSelectTreeNode.class)).build();
+  }
+
+  @Test(expected = EdmException.class)
+  public void wrongNavigationPropertyInExpandedList() throws Exception {
+    EdmEntitySet roomsSet = edm.getDefaultEntityContainer().getEntitySet("Rooms");
+    List<String> expandedNavigationPropertyNames = new ArrayList<String>();
+    expandedNavigationPropertyNames.add("Wrong");
+    ExpandSelectTreeNode.entitySet(roomsSet).expandedLinks(expandedNavigationPropertyNames).build();
+  }
+
+  private void
+      assertLinksWithOneNavigationProperty(final String navigationPropertyName, final ExpandSelectTreeNode node) {
+    assertEquals(1, node.getLinks().size());
+    assertTrue(node.getLinks().containsKey(navigationPropertyName));
+    assertNotNull(node.getLinks().get(navigationPropertyName));
+  }
+
+  private void assertExpandedNode(final ExpandSelectTreeNode node) {
+    assertNotNull(node);
+    assertTrue(node.isAll());
+    assertTrue(node.getProperties().isEmpty());
+    assertFalse(node.getLinks().isEmpty());
+  }
+
+}


[09/12] git commit: [OLINGO-83] Refactoring of 'annotation-processor-*' modules

Posted by tb...@apache.org.
[OLINGO-83] Refactoring of 'annotation-processor-*' modules


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

Branch: refs/heads/ODataServlet
Commit: 3bd59050f2697c8d67a7e104e4791bb91406d762
Parents: bb73dad
Author: Michael Bolz <mi...@apache.org>
Authored: Fri Dec 20 10:42:08 2013 +0100
Committer: Michael Bolz <mi...@apache.org>
Committed: Fri Dec 20 14:10:03 2013 +0100

----------------------------------------------------------------------
 .../processor/api/AnnotationServiceFactory.java |  118 ++
 .../olingo/odata2/api/data/DataSource.java      |  200 ---
 .../odata2/api/data/DataSourceProcessor.java    |   47 -
 .../olingo/odata2/api/data/ValueAccess.java     |   69 -
 .../core/AnnotationServiceFactoryImpl.java      |   73 +
 .../processor/core/DataSourceProcessor.java     |   49 +
 .../processor/core/ListsProcessor.java          | 1640 +++++++++++++++++
 .../core/datasource/AnnotationInMemoryDs.java   |  384 ++++
 .../core/datasource/AnnotationValueAccess.java  |  108 ++
 .../core/datasource/BeanPropertyAccess.java     |  185 ++
 .../processor/core/datasource/DataSource.java   |  200 +++
 .../processor/core/datasource/DataStore.java    |  294 ++++
 .../processor/core/datasource/ValueAccess.java  |   69 +
 .../core/edm/AnnotationEdmProvider.java         |  769 ++++++++
 .../processor/core/util/AnnotationHelper.java   |  777 +++++++++
 .../processor/core/util/ClassHelper.java        |  140 ++
 .../annotation/data/AnnotationInMemoryDs.java   |  376 ----
 .../annotation/data/AnnotationValueAccess.java  |  109 --
 .../annotation/data/BeanPropertyAccess.java     |  186 --
 .../odata2/core/annotation/data/DataStore.java  |  294 ----
 .../annotation/edm/AnnotationEdmProvider.java   |  769 --------
 .../annotation/processor/ListsProcessor.java    | 1641 ------------------
 .../core/annotation/util/AnnotationHelper.java  |  777 ---------
 .../core/annotation/util/ClassHelper.java       |  140 --
 .../data/AnnotationsInMemoryDsTest.java         |   10 +-
 .../edm/AnnotationEdmProviderTest.java          |    1 +
 .../ref/AnnotationRefServiceFactory.java        |  215 +++
 .../processor/ref/model/Building.java           |   97 ++
 .../annotation/processor/ref/model/City.java    |   61 +
 .../processor/ref/model/Employee.java           |  192 ++
 .../processor/ref/model/Location.java           |   60 +
 .../annotation/processor/ref/model/Manager.java |   43 +
 .../ref/model/ModelSharedConstants.java         |   25 +
 .../annotation/processor/ref/model/Photo.java   |  128 ++
 .../annotation/processor/ref/model/RefBase.java |   78 +
 .../processor/ref/model/ResourceHelper.java     |   96 +
 .../annotation/processor/ref/model/Room.java    |   88 +
 .../annotation/processor/ref/model/Team.java    |   73 +
 .../odata2/ref/annotation/model/Building.java   |   97 --
 .../odata2/ref/annotation/model/City.java       |   61 -
 .../odata2/ref/annotation/model/Employee.java   |  192 --
 .../odata2/ref/annotation/model/Location.java   |   60 -
 .../odata2/ref/annotation/model/Manager.java    |   43 -
 .../annotation/model/ModelSharedConstants.java  |   25 -
 .../odata2/ref/annotation/model/Photo.java      |  128 --
 .../odata2/ref/annotation/model/RefBase.java    |   78 -
 .../ref/annotation/model/ResourceHelper.java    |   96 -
 .../odata2/ref/annotation/model/Room.java       |   88 -
 .../odata2/ref/annotation/model/Team.java       |   73 -
 .../processor/AnnotationServiceFactory.java     |  215 ---
 .../src/main/webapp/WEB-INF/web.xml             |    2 +-
 .../olingo/odata2/fit/ref/AbstractRefTest.java  |    4 +-
 .../odata2/fit/ref/EntryXmlReadOnlyTest.java    |    2 +-
 .../AbstractContentNegotiationTest.java         |    4 +-
 .../ref/processor/ScenarioDataSource.java       |    2 +-
 .../ref/processor/ScenarioServiceFactory.java   |    4 +-
 .../olingo/odata2/ref/read/EntitySetTest.java   |    4 +-
 .../olingo/odata2/ref/read/EntityTest.java      |    4 +-
 58 files changed, 5982 insertions(+), 5781 deletions(-)
----------------------------------------------------------------------


http://git-wip-us.apache.org/repos/asf/incubator-olingo-odata2/blob/3bd59050/odata2-annotation-processor/annotation-processor-api/src/main/java/org/apache/olingo/odata2/annotation/processor/api/AnnotationServiceFactory.java
----------------------------------------------------------------------
diff --git a/odata2-annotation-processor/annotation-processor-api/src/main/java/org/apache/olingo/odata2/annotation/processor/api/AnnotationServiceFactory.java b/odata2-annotation-processor/annotation-processor-api/src/main/java/org/apache/olingo/odata2/annotation/processor/api/AnnotationServiceFactory.java
new file mode 100644
index 0000000..38fe73a
--- /dev/null
+++ b/odata2-annotation-processor/annotation-processor-api/src/main/java/org/apache/olingo/odata2/annotation/processor/api/AnnotationServiceFactory.java
@@ -0,0 +1,118 @@
+/*******************************************************************************
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License. You may obtain a copy of the License at
+ * 
+ * http://www.apache.org/licenses/LICENSE-2.0
+ * 
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied. See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ ******************************************************************************/
+package org.apache.olingo.odata2.annotation.processor.api;
+
+import java.util.Collection;
+
+import org.apache.olingo.odata2.api.ODataService;
+import org.apache.olingo.odata2.api.exception.ODataException;
+
+/**
+ * AnnotationServiceFactory which provides an AnnotationService which handles java beans (classes)
+ * annotated with annotation from <code>org.apache.olingo.olingo-odata2-api-annotation</code> module
+ * (see package <code>org.apache.olingo.odata2.api.annotation.edm</code>).
+ */
+public abstract class AnnotationServiceFactory {
+
+  private static final String IMPLEMENTATION = 
+      "org.apache.olingo.odata2.annotation.processor.core.AnnotationServiceFactoryImpl";
+
+  /**
+   * Create a runtime delegate instance from the core library. The core
+   * library (org.apache.olingo.odata2.annotation.processor.core) needs to be included into the classpath
+   * of the using application.
+   * @return implementation instance
+   */
+  private static AnnotationServiceFactoryInstance getInstance() {
+    AnnotationServiceFactoryInstance delegate;
+
+    try {
+      final Class<?> clazz = Class.forName(IMPLEMENTATION);
+      /*
+       * We explicitly do not use the singleton pattern to keep the server state free
+       * and avoid class loading issues also during hot deployment.
+       */
+      final Object object = clazz.newInstance();
+      delegate = (AnnotationServiceFactoryInstance) object;
+
+    } catch (final Exception e) {
+      throw new RuntimeException(e);
+    }
+    return delegate;
+  }
+
+  /**
+   * Interface to be implemented for an instance of a {@link AnnotationServiceFactoryInstance} which
+   * provides an {@link ODataService} based on annotation from 
+   * <code>org.apache.olingo.olingo-odata2-api-annotation</code> module
+   * (see package <code>org.apache.olingo.odata2.api.annotation.edm</code>).
+   */
+  public interface AnnotationServiceFactoryInstance {
+    /**
+     * Create an {@link ODataService} which is based on an EDM and Processor which are using the annotations from 
+     * <code>org.apache.olingo.olingo-odata2-api-annotation</code> module
+     * (see package <code>org.apache.olingo.odata2.api.annotation.edm</code>) to define the model and access the data.
+     * 
+     * @param modelPackage package name which is scanned for annotated classes
+     * @return service an {@link ODataService} based on on an EDM and Processor which are using annotations 
+     *            for model definition and data access.
+     * @throws ODataException if an error during initialization occurs
+     */
+    public ODataService createAnnotationService(String modelPackage) throws ODataException;
+    /**
+     * Create an {@link ODataService} which is based on an EDM and Processor which are using the annotations from 
+     * <code>org.apache.olingo.olingo-odata2-api-annotation</code> module
+     * (see package <code>org.apache.olingo.odata2.api.annotation.edm</code>) to define the model and access the data.
+     * 
+     * @param modelPackage classes (which are annotated) which will be used for EDM definition and data access.
+     * @return service an {@link ODataService} based on on an EDM and Processor which are using annotations 
+     *            for model definition and data access.
+     * @throws ODataException if an error during initialization occurs
+     */
+    public ODataService createAnnotationService(Collection<Class<?>> annotatedClasses) throws ODataException;
+  }
+
+  /**
+   * Create an {@link ODataService} which is based on an EDM and Processor which are using the annotations from 
+   * <code>org.apache.olingo.olingo-odata2-api-annotation</code> module
+   * (see package <code>org.apache.olingo.odata2.api.annotation.edm</code>) to define the model and access the data.
+   * 
+   * @param modelPackage package name which is scanned for annotated classes
+   * @return service an {@link ODataService} based on on an EDM and Processor which are using annotations 
+   *            for model definition and data access.
+   * @throws ODataException if an error during initialization occurs
+   */
+  public static ODataService createAnnotationService(String modelPackage) throws ODataException {
+    return getInstance().createAnnotationService(modelPackage);
+  }
+  
+  /**
+   * Create an {@link ODataService} which is based on an EDM and Processor which are using the annotations from 
+   * <code>org.apache.olingo.olingo-odata2-api-annotation</code> module
+   * (see package <code>org.apache.olingo.odata2.api.annotation.edm</code>) to define the model and access the data.
+   * 
+   * @param modelPackage classes (which are annotated) which will be used for EDM definition and data access.
+   * @return service an {@link ODataService} based on on an EDM and Processor which are using annotations 
+   *            for model definition and data access.
+   * @throws ODataException if an error during initialization occurs
+   */
+  public static ODataService createAnnotationService(Collection<Class<?>> annotatedClasses) throws ODataException {
+    return getInstance().createAnnotationService(annotatedClasses);
+  }
+}

http://git-wip-us.apache.org/repos/asf/incubator-olingo-odata2/blob/3bd59050/odata2-annotation-processor/annotation-processor-api/src/main/java/org/apache/olingo/odata2/api/data/DataSource.java
----------------------------------------------------------------------
diff --git a/odata2-annotation-processor/annotation-processor-api/src/main/java/org/apache/olingo/odata2/api/data/DataSource.java b/odata2-annotation-processor/annotation-processor-api/src/main/java/org/apache/olingo/odata2/api/data/DataSource.java
deleted file mode 100644
index 694f199..0000000
--- a/odata2-annotation-processor/annotation-processor-api/src/main/java/org/apache/olingo/odata2/api/data/DataSource.java
+++ /dev/null
@@ -1,200 +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.odata2.api.data;
-
-import java.util.Arrays;
-import java.util.List;
-import java.util.Map;
-
-import org.apache.olingo.odata2.api.edm.EdmEntitySet;
-import org.apache.olingo.odata2.api.edm.EdmException;
-import org.apache.olingo.odata2.api.edm.EdmFunctionImport;
-import org.apache.olingo.odata2.api.exception.ODataApplicationException;
-import org.apache.olingo.odata2.api.exception.ODataNotFoundException;
-import org.apache.olingo.odata2.api.exception.ODataNotImplementedException;
-
-/**
- * <p>This interface is intended to make it easier to implement an OData
- * service in cases where all data for each entity set can be provided as a {@link List} of objects from which all
- * properties described in the
- * Entity Data Model can be retrieved and set.</p>
- * <p>By obeying these restrictions, data-source implementations get the
- * following advantages:
- * <ul>
- * <li>All system query options can be handled centrally.</li>
- * <li>Following navigation paths must only be done step by step.</li>
- * </ul>
- * </p>
- * 
- */
-public interface DataSource {
-
-  /**
-   * Retrieves the whole data list for the specified entity set.
-   * @param entitySet the requested {@link EdmEntitySet}
-   * @return the requested data list
-   */
-  List<?> readData(EdmEntitySet entitySet) throws ODataNotImplementedException, ODataNotFoundException, EdmException,
-      ODataApplicationException;
-
-  /**
-   * Retrieves a single data object for the specified entity set and key.
-   * @param entitySet the requested {@link EdmEntitySet}
-   * @param keys the entity key as map of key names to key values
-   * @return the requested data object
-   */
-  Object readData(EdmEntitySet entitySet, Map<String, Object> keys) throws ODataNotImplementedException,
-      ODataNotFoundException, EdmException, ODataApplicationException;
-
-  /**
-   * <p>Retrieves data for the specified function import and key.</p>
-   * <p>This method is called also for function imports that have defined in
-   * their metadata an other HTTP method than <code>GET</code>.</p>
-   * @param function the requested {@link EdmFunctionImport}
-   * @param parameters the parameters of the function import
-   * as map of parameter names to parameter values
-   * @param keys the key of the returned entity set, as map of key names to key values,
-   * if the return type of the function import is a collection of entities
-   * (optional)
-   * @return the requested data object, either a list or a single object;
-   * if the function import's return type is of type <code>Binary</code>,
-   * the returned object(s) must be of type {@link BinaryData}
-   */
-  Object readData(EdmFunctionImport function, Map<String, Object> parameters, Map<String, Object> keys)
-      throws ODataNotImplementedException, ODataNotFoundException, EdmException, ODataApplicationException;
-
-  /**
-   * <p>Retrieves related data for the specified source data, entity set, and key.</p>
-   * <p>If the underlying association of the EDM is specified to have target
-   * multiplicity '*' and no target key is given, this method returns a list of
-   * related data, otherwise it returns a single data object.</p>
-   * @param sourceEntitySet the {@link EdmEntitySet} of the source entity
-   * @param sourceData the data object of the source entity
-   * @param targetEntitySet the requested target {@link EdmEntitySet}
-   * @param targetKeys the key of the target entity as map of key names to key values
-   * (optional)
-   * @return the requested releated data object, either a list or a single object
-   */
-  Object readRelatedData(EdmEntitySet sourceEntitySet, Object sourceData, EdmEntitySet targetEntitySet,
-      Map<String, Object> targetKeys) throws ODataNotImplementedException, ODataNotFoundException, EdmException,
-      ODataApplicationException;
-
-  /**
-   * Retrieves the binary data and the MIME type for the media resource
-   * associated to the specified media-link entry.
-   * @param entitySet the {@link EdmEntitySet} of the media-link entry
-   * @param mediaLinkEntryData the data object of the media-link entry
-   * @return the binary data and the MIME type of the media resource
-   */
-  BinaryData readBinaryData(EdmEntitySet entitySet, Object mediaLinkEntryData) throws ODataNotImplementedException,
-      ODataNotFoundException, EdmException, ODataApplicationException;
-
-  /**
-   * <p>Creates and returns a new instance of the requested data-object type.</p>
-   * <p>This instance must not be part of the corresponding list and should
-   * have empty content, apart from the key and other mandatory properties.
-   * However, intermediate objects to access complex properties must not be
-   * <code>null</code>.</p>
-   * @param entitySet the {@link EdmEntitySet} the object must correspond to
-   * @return the new data object
-   */
-  Object newDataObject(EdmEntitySet entitySet) throws ODataNotImplementedException, EdmException,
-      ODataApplicationException;
-
-  /**
-   * Writes the binary data for the media resource associated to the
-   * specified media-link entry.
-   * @param entitySet the {@link EdmEntitySet} of the media-link entry
-   * @param mediaLinkEntryData the data object of the media-link entry
-   * @param binaryData the binary data of the media resource along with
-   * the MIME type of the binary data
-   */
-  void writeBinaryData(EdmEntitySet entitySet, Object mediaLinkEntryData, BinaryData binaryData)
-      throws ODataNotImplementedException, ODataNotFoundException, EdmException, ODataApplicationException;
-
-  /**
-   * Deletes a single data object identified by the specified entity set and key.
-   * @param entitySet the {@link EdmEntitySet} of the entity to be deleted
-   * @param keys the entity key as map of key names to key values
-   */
-  void deleteData(EdmEntitySet entitySet, Map<String, Object> keys) throws ODataNotImplementedException,
-      ODataNotFoundException, EdmException, ODataApplicationException;
-
-  /**
-   * <p>Inserts an instance into the entity list of the specified entity set.</p>
-   * <p>If {@link #newDataObject} has not set the key and other mandatory
-   * properties already, this method must set them before inserting the
-   * instance into the list.</p>
-   * @param entitySet the {@link EdmEntitySet} the object must correspond to
-   * @param data the data object of the new entity
-   */
-  void createData(EdmEntitySet entitySet, Object data) throws ODataNotImplementedException, EdmException,
-      ODataApplicationException;
-
-  /**
-   * Deletes the relation from the specified source data to a target entity
-   * specified by entity set and key.
-   * @param sourceEntitySet the {@link EdmEntitySet} of the source entity
-   * @param sourceData the data object of the source entity
-   * @param targetEntitySet the {@link EdmEntitySet} of the target entity
-   * @param targetKeys the key of the target entity as map of key names to key values
-   * (optional)
-   */
-  void deleteRelation(EdmEntitySet sourceEntitySet, Object sourceData, EdmEntitySet targetEntitySet,
-      Map<String, Object> targetKeys) throws ODataNotImplementedException, ODataNotFoundException, EdmException,
-      ODataApplicationException;
-
-  /**
-   * Writes a relation from the specified source data to a target entity
-   * specified by entity set and key.
-   * @param sourceEntitySet the {@link EdmEntitySet} of the source entity
-   * @param sourceData the data object of the source entity
-   * @param targetEntitySet the {@link EdmEntitySet} of the relation target
-   * @param targetKeys the key of the target entity as map of key names to key values
-   */
-  void writeRelation(EdmEntitySet sourceEntitySet, Object sourceData, EdmEntitySet targetEntitySet,
-      Map<String, Object> targetKeys) throws ODataNotImplementedException, ODataNotFoundException, EdmException,
-      ODataApplicationException;
-
-  /**
-   * Container to store binary data (as byte array) and the associated MIME type.
-   */
-  public class BinaryData {
-    private final byte[] data;
-    private final String mimeType;
-
-    public BinaryData(final byte[] data, final String mimeType) {
-      this.data = data;
-      this.mimeType = mimeType;
-    }
-
-    public byte[] getData() {
-      return data;
-    }
-
-    public String getMimeType() {
-      return mimeType;
-    }
-
-    @Override
-    public String toString() {
-      return "data=" + Arrays.toString(data) + ", mimeType=" + mimeType;
-    }
-  }
-}

http://git-wip-us.apache.org/repos/asf/incubator-olingo-odata2/blob/3bd59050/odata2-annotation-processor/annotation-processor-api/src/main/java/org/apache/olingo/odata2/api/data/DataSourceProcessor.java
----------------------------------------------------------------------
diff --git a/odata2-annotation-processor/annotation-processor-api/src/main/java/org/apache/olingo/odata2/api/data/DataSourceProcessor.java b/odata2-annotation-processor/annotation-processor-api/src/main/java/org/apache/olingo/odata2/api/data/DataSourceProcessor.java
deleted file mode 100644
index dc89970..0000000
--- a/odata2-annotation-processor/annotation-processor-api/src/main/java/org/apache/olingo/odata2/api/data/DataSourceProcessor.java
+++ /dev/null
@@ -1,47 +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.odata2.api.data;
-
-import org.apache.olingo.odata2.api.processor.ODataSingleProcessor;
-
-/**
- * Abstract class for implementation of the centralized parts of OData processing,
- * allowing to use the simplified {@link DataSource} and {@link ValueAccess} for the
- * actual data handling.
- * <br/>
- * Extend this class and implement a DataSourceProcessor if the default implementation
- * (<code>ListProcessor</code> found in <code>annotation-processor-core module</code>) has to be overwritten.
- */
-public abstract class DataSourceProcessor extends ODataSingleProcessor {
-
-  protected final DataSource dataSource;
-  protected final ValueAccess valueAccess;
-
-  /**
-   * Initialize a {@link DataSourceProcessor} in combination with given {@link DataSource} (providing data objects)
-   * and {@link ValueAccess} (accessing values of data objects).
-   * 
-   * @param dataSource used for accessing the data objects
-   * @param valueAccess for accessing the values provided by the data objects
-   */
-  public DataSourceProcessor(final DataSource dataSource, final ValueAccess valueAccess) {
-    this.dataSource = dataSource;
-    this.valueAccess = valueAccess;
-  }
-}

http://git-wip-us.apache.org/repos/asf/incubator-olingo-odata2/blob/3bd59050/odata2-annotation-processor/annotation-processor-api/src/main/java/org/apache/olingo/odata2/api/data/ValueAccess.java
----------------------------------------------------------------------
diff --git a/odata2-annotation-processor/annotation-processor-api/src/main/java/org/apache/olingo/odata2/api/data/ValueAccess.java b/odata2-annotation-processor/annotation-processor-api/src/main/java/org/apache/olingo/odata2/api/data/ValueAccess.java
deleted file mode 100644
index 633ca37..0000000
--- a/odata2-annotation-processor/annotation-processor-api/src/main/java/org/apache/olingo/odata2/api/data/ValueAccess.java
+++ /dev/null
@@ -1,69 +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.odata2.api.data;
-
-import org.apache.olingo.odata2.api.edm.EdmMapping;
-import org.apache.olingo.odata2.api.edm.EdmProperty;
-import org.apache.olingo.odata2.api.exception.ODataException;
-
-/**
- * This interface is intended to access values in a Java object.
- */
-public interface ValueAccess {
-
-  /**
-   * Retrieves the value of an EDM property for the given data object.
-   * @param data the Java data object
-   * @param property the requested {@link EdmProperty}
-   * @return the requested property value
-   */
-  public <T> Object getPropertyValue(final T data, final EdmProperty property) throws ODataException;
-
-  /**
-   * Sets the value of an EDM property for the given data object.
-   * @param data the Java data object
-   * @param property the {@link EdmProperty}
-   * @param value the new value of the property
-   */
-  public <T, V> void setPropertyValue(T data, final EdmProperty property, final V value) throws ODataException;
-
-  /**
-   * Retrieves the Java type of an EDM property for the given data object.
-   * @param data the Java data object
-   * @param property the requested {@link EdmProperty}
-   * @return the requested Java type
-   */
-  public <T> Class<?> getPropertyType(final T data, final EdmProperty property) throws ODataException;
-
-  /**
-   * Retrieves the value defined by a mapping object for the given data object.
-   * @param data the Java data object
-   * @param mapping the requested {@link EdmMapping}
-   * @return the requested value
-   */
-  public <T> Object getMappingValue(final T data, final EdmMapping mapping) throws ODataException;
-
-  /**
-   * Sets the value defined by a mapping object for the given data object.
-   * @param data the Java data object
-   * @param mapping the {@link EdmMapping}
-   * @param value the new value
-   */
-  public <T, V> void setMappingValue(T data, final EdmMapping mapping, final V value) throws ODataException;
-}

http://git-wip-us.apache.org/repos/asf/incubator-olingo-odata2/blob/3bd59050/odata2-annotation-processor/annotation-processor-core/src/main/java/org/apache/olingo/odata2/annotation/processor/core/AnnotationServiceFactoryImpl.java
----------------------------------------------------------------------
diff --git a/odata2-annotation-processor/annotation-processor-core/src/main/java/org/apache/olingo/odata2/annotation/processor/core/AnnotationServiceFactoryImpl.java b/odata2-annotation-processor/annotation-processor-core/src/main/java/org/apache/olingo/odata2/annotation/processor/core/AnnotationServiceFactoryImpl.java
new file mode 100644
index 0000000..9c673a3
--- /dev/null
+++ b/odata2-annotation-processor/annotation-processor-core/src/main/java/org/apache/olingo/odata2/annotation/processor/core/AnnotationServiceFactoryImpl.java
@@ -0,0 +1,73 @@
+/*******************************************************************************
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License. You may obtain a copy of the License at
+ * 
+ * http://www.apache.org/licenses/LICENSE-2.0
+ * 
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied. See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ ******************************************************************************/
+package org.apache.olingo.odata2.annotation.processor.core;
+
+import java.util.Collection;
+
+import org.apache.olingo.odata2.annotation.processor.api.AnnotationServiceFactory.AnnotationServiceFactoryInstance;
+import org.apache.olingo.odata2.annotation.processor.core.datasource.AnnotationInMemoryDs;
+import org.apache.olingo.odata2.annotation.processor.core.datasource.AnnotationValueAccess;
+import org.apache.olingo.odata2.annotation.processor.core.edm.AnnotationEdmProvider;
+import org.apache.olingo.odata2.api.ODataService;
+import org.apache.olingo.odata2.api.exception.ODataException;
+import org.apache.olingo.odata2.api.rt.RuntimeDelegate;
+
+/**
+ * ODataServiceFactory implementation based on ListProcessor
+ * in combination with Annotation-Support-Classes for EdmProvider, DataSource and ValueAccess.
+ */
+public class AnnotationServiceFactoryImpl implements AnnotationServiceFactoryInstance {
+
+  /**
+   * Create an instance which further can create an {@link ODataService}.
+   * 
+   * @return instance which further can create an {@link ODataService}.
+   */
+  public AnnotationServiceFactoryInstance createInstance() {
+    return new AnnotationServiceFactoryImpl();
+  }
+
+  /**
+   * {@inheritDoc}
+   */
+  @Override
+  public ODataService createAnnotationService(String modelPackage) throws ODataException {
+    AnnotationEdmProvider edmProvider = new AnnotationEdmProvider(modelPackage);
+    AnnotationInMemoryDs dataSource = new AnnotationInMemoryDs(modelPackage);
+    AnnotationValueAccess valueAccess = new AnnotationValueAccess();
+
+    // Edm via Annotations and ListProcessor via AnnotationDS with AnnotationsValueAccess
+    return RuntimeDelegate.createODataSingleProcessorService(edmProvider,
+        new ListsProcessor(dataSource, valueAccess));
+  }
+
+  /**
+   * {@inheritDoc}
+   */
+  @Override
+  public ODataService createAnnotationService(Collection<Class<?>> annotatedClasses) throws ODataException {
+    AnnotationEdmProvider edmProvider = new AnnotationEdmProvider(annotatedClasses);
+    AnnotationInMemoryDs dataSource = new AnnotationInMemoryDs(annotatedClasses);
+    AnnotationValueAccess valueAccess = new AnnotationValueAccess();
+
+    // Edm via Annotations and ListProcessor via AnnotationDS with AnnotationsValueAccess
+    return RuntimeDelegate.createODataSingleProcessorService(edmProvider,
+        new ListsProcessor(dataSource, valueAccess));
+  }
+}

http://git-wip-us.apache.org/repos/asf/incubator-olingo-odata2/blob/3bd59050/odata2-annotation-processor/annotation-processor-core/src/main/java/org/apache/olingo/odata2/annotation/processor/core/DataSourceProcessor.java
----------------------------------------------------------------------
diff --git a/odata2-annotation-processor/annotation-processor-core/src/main/java/org/apache/olingo/odata2/annotation/processor/core/DataSourceProcessor.java b/odata2-annotation-processor/annotation-processor-core/src/main/java/org/apache/olingo/odata2/annotation/processor/core/DataSourceProcessor.java
new file mode 100644
index 0000000..b08bfea
--- /dev/null
+++ b/odata2-annotation-processor/annotation-processor-core/src/main/java/org/apache/olingo/odata2/annotation/processor/core/DataSourceProcessor.java
@@ -0,0 +1,49 @@
+/*******************************************************************************
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License. You may obtain a copy of the License at
+ * 
+ * http://www.apache.org/licenses/LICENSE-2.0
+ * 
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied. See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ ******************************************************************************/
+package org.apache.olingo.odata2.annotation.processor.core;
+
+import org.apache.olingo.odata2.annotation.processor.core.datasource.DataSource;
+import org.apache.olingo.odata2.annotation.processor.core.datasource.ValueAccess;
+import org.apache.olingo.odata2.api.processor.ODataSingleProcessor;
+
+/**
+ * Abstract class for implementation of the centralized parts of OData processing,
+ * allowing to use the simplified {@link DataSource} and {@link ValueAccess} for the
+ * actual data handling.
+ * <br/>
+ * Extend this class and implement a DataSourceProcessor if the default implementation
+ * (<code>ListProcessor</code> found in <code>annotation-processor-core module</code>) has to be overwritten.
+ */
+public abstract class DataSourceProcessor extends ODataSingleProcessor {
+
+  protected final DataSource dataSource;
+  protected final ValueAccess valueAccess;
+
+  /**
+   * Initialize a {@link DataSourceProcessor} in combination with given {@link DataSource} (providing data objects)
+   * and {@link ValueAccess} (accessing values of data objects).
+   * 
+   * @param dataSource used for accessing the data objects
+   * @param valueAccess for accessing the values provided by the data objects
+   */
+  public DataSourceProcessor(final DataSource dataSource, final ValueAccess valueAccess) {
+    this.dataSource = dataSource;
+    this.valueAccess = valueAccess;
+  }
+}


[11/12] git commit: [OLINGO-67] refactoring

Posted by tb...@apache.org.
[OLINGO-67] refactoring


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

Branch: refs/heads/ODataServlet
Commit: 22e54c485ef3ac2247ed9f7556c3fb3add1be79f
Parents: 6ac9c52
Author: Tamara Boehm <ta...@sap.com>
Authored: Fri Dec 20 16:14:08 2013 +0100
Committer: Tamara Boehm <ta...@sap.com>
Committed: Fri Dec 20 16:14:08 2013 +0100

----------------------------------------------------------------------
 .../odata2/core/servlet/ODataServlet.java       |  34 ++--
 .../olingo/odata2/core/servlet/RestUtil.java    | 177 ++++++++++++-------
 2 files changed, 126 insertions(+), 85 deletions(-)
----------------------------------------------------------------------


http://git-wip-us.apache.org/repos/asf/incubator-olingo-odata2/blob/22e54c48/odata2-lib/odata-core/src/main/java/org/apache/olingo/odata2/core/servlet/ODataServlet.java
----------------------------------------------------------------------
diff --git a/odata2-lib/odata-core/src/main/java/org/apache/olingo/odata2/core/servlet/ODataServlet.java b/odata2-lib/odata-core/src/main/java/org/apache/olingo/odata2/core/servlet/ODataServlet.java
index e5c9760..6115fb5 100644
--- a/odata2-lib/odata-core/src/main/java/org/apache/olingo/odata2/core/servlet/ODataServlet.java
+++ b/odata2-lib/odata-core/src/main/java/org/apache/olingo/odata2/core/servlet/ODataServlet.java
@@ -29,6 +29,8 @@ import org.apache.olingo.odata2.core.exception.ODataRuntimeException;
 
 public class ODataServlet extends HttpServlet {
 
+  private static final String HTTP_METHOD_OPTIONS = "OPTIONS";
+  private static final String HTTP_METHOD_HEAD = "HEAD";
   /**
    * 
    */
@@ -78,13 +80,13 @@ public class ODataServlet extends HttpServlet {
         handleRequest(req, ODataHttpMethod.POST, resp);
       } else if (xHttpMethod == null && xHttpMethodOverride != null) {
         /* tunneling */
-        boolean methodHandled = methodForTunneling(req, resp, xHttpMethodOverride);
+        boolean methodHandled = handleHttpTunneling(req, resp, xHttpMethodOverride);
         if (!methodHandled) {
           createMethodNotAllowedResponse(req, ODataHttpException.COMMON, resp);
         }
       } else {
         /* tunneling */
-        boolean methodHandled = methodForTunneling(req, resp, xHttpMethod);
+        boolean methodHandled = handleHttpTunneling(req, resp, xHttpMethod);
         if (!methodHandled) {
           createNotImplementedResponse(req, ODataNotImplementedException.TUNNELING, resp);
         }
@@ -98,37 +100,29 @@ public class ODataServlet extends HttpServlet {
       handleRequest(req, ODataHttpMethod.PATCH, resp);
     } else if (ODataHttpMethod.MERGE.name().equals(method)) {
       handleRequest(req, ODataHttpMethod.MERGE, resp);
-    } else if ("HEAD".equals(method) || "OPTIONS".equals(method)) {
+    } else if (HTTP_METHOD_HEAD.equals(method) || HTTP_METHOD_OPTIONS.equals(method)) {
       createNotImplementedResponse(req, ODataNotImplementedException.COMMON, resp);
     } else {
       createMethodNotAllowedResponse(req, ODataHttpException.COMMON, resp);
     }
   }
 
-  private boolean methodForTunneling(final HttpServletRequest req, final HttpServletResponse resp,
+  private boolean handleHttpTunneling(final HttpServletRequest req, final HttpServletResponse resp,
       final String xHttpMethod) throws IOException {
-    /* tunneling */
     if (ODataHttpMethod.MERGE.name().equals(xHttpMethod)) {
       handleRequest(req, ODataHttpMethod.MERGE, resp);
-
     } else if (ODataHttpMethod.PATCH.name().equals(xHttpMethod)) {
       handleRequest(req, ODataHttpMethod.PATCH, resp);
-
     } else if (ODataHttpMethod.DELETE.name().equals(xHttpMethod)) {
       handleRequest(req, ODataHttpMethod.DELETE, resp);
-
     } else if (ODataHttpMethod.PUT.name().equals(xHttpMethod)) {
       handleRequest(req, ODataHttpMethod.PUT, resp);
-
     } else if (ODataHttpMethod.GET.name().equals(xHttpMethod)) {
       handleRequest(req, ODataHttpMethod.GET, resp);
-
     } else if (ODataHttpMethod.POST.name().equals(xHttpMethod)) {
       handleRequest(req, ODataHttpMethod.POST, resp);
-
-    } else if ("HEAD".equals(xHttpMethod) || "OPTIONS".equals(xHttpMethod)) {
+    } else if (HTTP_METHOD_HEAD.equals(xHttpMethod) || HTTP_METHOD_OPTIONS.equals(xHttpMethod)) {
       createNotImplementedResponse(req, ODataNotImplementedException.COMMON, resp);
-
     } else {
       return false;
     }
@@ -141,7 +135,7 @@ public class ODataServlet extends HttpServlet {
       if (req.getHeader(HttpHeaders.ACCEPT) != null && req.getHeader(HttpHeaders.ACCEPT).isEmpty()) {
         createNotAcceptableResponse(req, ODataNotAcceptableException.COMMON, resp);
       }
-      ODataRequest request = ODataRequest.method(method)
+      ODataRequest odataRequest = ODataRequest.method(method)
           .contentType(RestUtil.extractRequestContentType(req.getContentType()).toContentTypeString())
           .acceptHeaders(RestUtil.extractAcceptHeaders(req.getHeader(HttpHeaders.ACCEPT)))
           .acceptableLanguages(RestUtil.extractAcceptableLanguage(req.getHeader(HttpHeaders.ACCEPT_LANGUAGE)))
@@ -150,13 +144,13 @@ public class ODataServlet extends HttpServlet {
           .requestHeaders(RestUtil.extractHeaders(req))
           .body(req.getInputStream())
           .build();
-      ODataContextImpl context = new ODataContextImpl(request, serviceFactory);
+      ODataContextImpl context = new ODataContextImpl(odataRequest, serviceFactory);
       ODataService service = serviceFactory.createService(context);
       context.setService(service);
       context.setParameter(ODataContext.HTTP_SERVLET_REQUEST_OBJECT, req);
       service.getProcessor().setContext(context);
       ODataRequestHandler requestHandler = new ODataRequestHandler(serviceFactory, service, context);
-      final ODataResponse odataResponse = requestHandler.handle(request);
+      final ODataResponse odataResponse = requestHandler.handle(odataRequest);
       createResponse(resp, odataResponse);
     } catch (ODataException e) {
       ODataExceptionWrapper wrapper = new ODataExceptionWrapper(req);
@@ -172,8 +166,8 @@ public class ODataServlet extends HttpServlet {
         ODataHttpMethod.DELETE.name().equals(method) ||
         ODataHttpMethod.PATCH.name().equals(method) ||
         ODataHttpMethod.MERGE.name().equals(method) ||
-        "HEAD".equals(method) ||
-        "OPTIONS".equals(method)) {
+        HTTP_METHOD_HEAD.equals(method) ||
+        HTTP_METHOD_OPTIONS.equals(method)) {
       ODataResponse odataResponse = ODataResponse.status(HttpStatusCodes.TEMPORARY_REDIRECT)
           .header(HttpHeaders.LOCATION, "/")
           .build();
@@ -185,7 +179,6 @@ public class ODataServlet extends HttpServlet {
   }
 
   private void createResponse(final HttpServletResponse resp, final ODataResponse response) throws IOException {
-
     resp.setStatus(response.getStatus().getStatusCode());
     resp.setContentType(response.getContentHeader());
     for (String headerName : response.getHeaderNames()) {
@@ -203,8 +196,7 @@ public class ODataServlet extends HttpServlet {
         ((InputStream) entity).close();
       } else if (entity instanceof String) {
         String body = (String) entity;
-        byte[] byteArray = body.getBytes("utf-8");
-        out.write(byteArray);
+        out.write(body.getBytes("utf-8"));
       }
 
       out.flush();

http://git-wip-us.apache.org/repos/asf/incubator-olingo-odata2/blob/22e54c48/odata2-lib/odata-core/src/main/java/org/apache/olingo/odata2/core/servlet/RestUtil.java
----------------------------------------------------------------------
diff --git a/odata2-lib/odata-core/src/main/java/org/apache/olingo/odata2/core/servlet/RestUtil.java b/odata2-lib/odata-core/src/main/java/org/apache/olingo/odata2/core/servlet/RestUtil.java
index ede0a88..ab1499e 100644
--- a/odata2-lib/odata-core/src/main/java/org/apache/olingo/odata2/core/servlet/RestUtil.java
+++ b/odata2-lib/odata-core/src/main/java/org/apache/olingo/odata2/core/servlet/RestUtil.java
@@ -5,12 +5,14 @@ import java.net.URISyntaxException;
 import java.util.ArrayList;
 import java.util.Arrays;
 import java.util.Collections;
+import java.util.Comparator;
 import java.util.Enumeration;
 import java.util.HashMap;
 import java.util.List;
 import java.util.Locale;
 import java.util.Map;
 import java.util.Scanner;
+import java.util.TreeSet;
 import java.util.regex.MatchResult;
 import java.util.regex.Matcher;
 import java.util.regex.Pattern;
@@ -31,7 +33,10 @@ import org.apache.olingo.odata2.core.commons.Decoder;
 public class RestUtil {
   private static final String REG_EX_QUALITY_FACTOR = "q=((?:1\\.0{0,3})|(?:0\\.[0-9]{0,2}[1-9]))";
   private static final String REG_EX_OPTIONAL_WHITESPACE = "\\s?";
-  private static final Pattern REG_EX_ACCEPT = Pattern.compile("((?:\\*)|(?:[a-z\\*\\s]+/[a-zA-Z0-9\\+\\*\\-=;\\s]+))");
+  private static final Pattern REG_EX_ACCEPT = Pattern.compile("((?:[a-z\\*\\s]+/[a-zA-Z\\+\\*\\-=\\s]+"
+      + "(?:;\\s*[a-pr-zA-PR-Z][a-zA-Z0-9\\-\\s]*=[a-zA-Z0-9\\-\\s]+)*))");
+  //  private static final Pattern REG_EX_ACCEPT_WITH_Q_FACTOR = Pattern.compile(REG_EX_ACCEPT + "(?:;"
+  //      + REG_EX_OPTIONAL_WHITESPACE + "q=([0-9]\\.?[0-9]{0,3}))?");
   private static final Pattern REG_EX_ACCEPT_WITH_Q_FACTOR = Pattern.compile(REG_EX_ACCEPT + "(?:;"
       + REG_EX_OPTIONAL_WHITESPACE + REG_EX_QUALITY_FACTOR + ")?");
   private static final Pattern REG_EX_ACCEPT_LANGUAGES = Pattern
@@ -40,18 +45,84 @@ public class RestUtil {
       + REG_EX_OPTIONAL_WHITESPACE + REG_EX_QUALITY_FACTOR + ")?");
   private static final Pattern REG_EX_MATRIX_PARAMETER = Pattern.compile("([^=]*)(?:=(.*))?");
 
+  public static ContentType extractRequestContentType(final String contentType)
+      throws ODataUnsupportedMediaTypeException {
+    if (contentType == null || contentType.isEmpty()) {
+      // RFC 2616, 7.2.1:
+      // "Any HTTP/1.1 message containing an entity-body SHOULD include a
+      // Content-Type header field defining the media type of that body. [...]
+      // If the media type remains unknown, the recipient SHOULD treat it
+      // as type "application/octet-stream"."
+      return ContentType.APPLICATION_OCTET_STREAM;
+    } else if (ContentType.isParseable(contentType)) {
+      return ContentType.create(contentType);
+    } else {
+      throw new ODataUnsupportedMediaTypeException(
+          ODataUnsupportedMediaTypeException.NOT_SUPPORTED_CONTENT_TYPE.addContent(contentType));
+    }
+  }
+
+  public static Map<String, String> extractQueryParameters(final String queryString) {
+    Map<String, String> queryParametersMap = new HashMap<String, String>();
+    if (queryString != null) {
+      List<String> queryParameters = Arrays.asList(Decoder.decode(queryString).split("\\&"));
+      for (String param : queryParameters) {
+        int indexOfEq = param.indexOf("=");
+        if (indexOfEq < 0) {
+          queryParametersMap.put(param, "");
+        } else {
+          queryParametersMap.put(param.substring(0, indexOfEq), param.substring(indexOfEq + 1));
+        }
+      }
+    }
+    return queryParametersMap;
+  }
+
+  public static List<Locale> extractAcceptableLanguage(final String acceptableLanguageHeader) {
+    List<Locale> acceptLanguages = new ArrayList<Locale>();
+    if (acceptableLanguageHeader != null) {
+      Scanner acceptLanguageScanner = new Scanner(acceptableLanguageHeader).useDelimiter(",\\s?");
+      while (acceptLanguageScanner.hasNext()) {
+        if (acceptLanguageScanner.hasNext(REG_EX_ACCEPT_LANGUAGES_WITH_Q_FACTOR)) {
+          acceptLanguageScanner.next(REG_EX_ACCEPT_LANGUAGES_WITH_Q_FACTOR);
+          MatchResult result = acceptLanguageScanner.match();
+          String language = result.group(1);
+          String country = result.group(2);
+          //        //double qualityFactor = result.group(2) != null ? Double.parseDouble(result.group(2)) : 1d;
+          if (country == null) {
+            acceptLanguages.add(new Locale(language));
+          } else {
+            acceptLanguages.add(new Locale(language, country));
+          }
+        }
+      }
+      acceptLanguageScanner.close();
+    }
+    return acceptLanguages;
+  }
+
   public static List<String> extractAcceptHeaders(final String header) {
+    TreeSet<Accept> acceptTree = getAcceptTree();
     List<String> acceptHeaders = new ArrayList<String>();
     if (header != null && !header.isEmpty()) {
-      Scanner acceptHeaderScanner = new Scanner(header).useDelimiter(",\\s?");
-      while (acceptHeaderScanner.hasNext()) {
-        if (acceptHeaderScanner.hasNext(REG_EX_ACCEPT_WITH_Q_FACTOR)) {
-          acceptHeaderScanner.next(REG_EX_ACCEPT_WITH_Q_FACTOR);
-          MatchResult result = acceptHeaderScanner.match();
-          acceptHeaders.add(result.group(1));
+      List<String> list = Arrays.asList(header.split(",\\s?"));
+      for (String el : list) {
+        Matcher matcher = REG_EX_ACCEPT_WITH_Q_FACTOR.matcher(el);
+        if (matcher.find()) {
+          String headerValue = matcher.group(1);
+          double qualityFactor = matcher.group(2) != null ? Double.parseDouble(matcher.group(2)) : 1d;
+          //double qualityFactor = Double.parseDouble(matcher.group(2));
+          //if(!matcher.group(2).matches(REG_EX_QUALITY_FACTOR)){
+          //  throw new ODataBadRequestException(ODataBadRequestException.INVALID_HEADER);
+          //}
+          Accept acceptHeader = new Accept(headerValue, qualityFactor);
+          acceptTree.add(acceptHeader);
         }
       }
     }
+    for (Accept accept : acceptTree) {
+      acceptHeaders.add(accept.getValue());
+    }
     return acceptHeaders;
   }
 
@@ -62,8 +133,8 @@ public class RestUtil {
       String headerName = headerNames.nextElement();
       List<String> headerValues = new ArrayList<String>();
       for (Enumeration<String> headers = req.getHeaders(headerName); headers.hasMoreElements();) {
-        String val = headers.nextElement();
-        headerValues.add(val);
+        String value = headers.nextElement();
+        headerValues.add(value);
       }
       if (requestHeaders.containsKey(headerName)) {
         requestHeaders.get(headerName).addAll(headerValues);
@@ -85,6 +156,7 @@ public class RestUtil {
   private static URI buildBaseUri(final HttpServletRequest req, final List<PathSegment> precedingPathSegments)
       throws ODataException {
     try {
+      URI baseUri;
       StringBuilder stringBuilder = new StringBuilder();
       stringBuilder.append(req.getContextPath()).append(req.getServletPath());
       for (final PathSegment ps : precedingPathSegments) {
@@ -103,7 +175,8 @@ public class RestUtil {
       if (!path.endsWith("/")) {
         path = path + "/";
       }
-      return new URI(req.getScheme(), null, req.getServerName(), req.getServerPort(), path, null, null);
+      baseUri = new URI(req.getScheme(), null, req.getServerName(), req.getServerPort(), path, null, null);
+      return baseUri;
     } catch (final URISyntaxException e) {
       throw new ODataException(e);
     }
@@ -111,17 +184,15 @@ public class RestUtil {
 
   private static URI buildRequestUri(final HttpServletRequest servletRequest) {
     URI requestUri;
-
-    StringBuffer buf = servletRequest.getRequestURL();
+    StringBuilder stringBuilder = new StringBuilder();
+    stringBuilder.append(servletRequest.getRequestURL());
     String queryString = servletRequest.getQueryString();
 
     if (queryString != null) {
-      buf.append("?");
-      buf.append(queryString);
+      stringBuilder.append("?").append(queryString);
     }
 
-    String requestUriString = buf.toString();
-
+    String requestUriString = stringBuilder.toString();
     requestUri = URI.create(requestUriString);
     return requestUri;
   }
@@ -164,9 +235,6 @@ public class RestUtil {
       } else {
         String path = segment.substring(0, index);
         Map<String, List<String>> parameterMap = extractMatrixParameter(segment, index);
-        if (!parameterMap.get("matrix").isEmpty()) {
-          System.out.println(parameterMap.get("matrix"));
-        }
         throw new ODataNotFoundException(ODataNotFoundException.MATRIX.addContent(parameterMap.keySet(), path));
       }
     }
@@ -227,56 +295,37 @@ public class RestUtil {
     return pathInfoString;
   }
 
-  public static ContentType extractRequestContentType(final String contentType)
-      throws ODataUnsupportedMediaTypeException {
-    if (contentType == null || contentType.isEmpty()) {
-      // RFC 2616, 7.2.1:
-      // "Any HTTP/1.1 message containing an entity-body SHOULD include a
-      // Content-Type header field defining the media type of that body. [...]
-      // If the media type remains unknown, the recipient SHOULD treat it
-      // as type "application/octet-stream"."
-      return ContentType.APPLICATION_OCTET_STREAM;
-    } else if (ContentType.isParseable(contentType)) {
-      return ContentType.create(contentType);
-    } else {
-      throw new ODataUnsupportedMediaTypeException(
-          ODataUnsupportedMediaTypeException.NOT_SUPPORTED_CONTENT_TYPE.addContent(contentType));
-    }
+  private static TreeSet<Accept> getAcceptTree() {
+    TreeSet<Accept> treeSet = new TreeSet<Accept>(new Comparator<Accept>() {
+      @Override
+      public int compare(final Accept o1, final Accept o2) {
+        if (o1.getQuality() <= o2.getQuality()) {
+          return 1;
+        } else {
+          return -1;
+        }
+      }
+    });
+    return treeSet;
   }
 
-  public static Map<String, String> extractQueryParameters(final String queryString) {
-    Map<String, String> queryParametersMap = new HashMap<String, String>();
-    if (queryString != null) {
-      List<String> qParameters = Arrays.asList(Decoder.decode(queryString).split("\\&"));
-      for (String param : qParameters) {
-        String[] p = param.split("=");
-        queryParametersMap.put(p[0], p[1]);
-      }
+  private static class Accept {
+    private double quality;
+    private String value;
+
+    public Accept(final String headerValue, final double qualityFactor) {
+      value = headerValue;
+      quality = qualityFactor;
     }
-    return queryParametersMap;
-  }
 
-  public static List<Locale> extractAcceptableLanguage(final String acceptableLanguageHeader) {
-    List<Locale> acceptLanguages = new ArrayList<Locale>();
-    if (acceptableLanguageHeader != null) {
-      Scanner acceptLanguageScanner = new Scanner(acceptableLanguageHeader).useDelimiter(",\\s?");
-      while (acceptLanguageScanner.hasNext()) {
-        if (acceptLanguageScanner.hasNext(REG_EX_ACCEPT_LANGUAGES_WITH_Q_FACTOR)) {
-          acceptLanguageScanner.next(REG_EX_ACCEPT_LANGUAGES_WITH_Q_FACTOR);
-          MatchResult result = acceptLanguageScanner.match();
-          String language = result.group(1);
-          String country = result.group(2);
-          //        //double qualityFactor = result.group(2) != null ? Double.parseDouble(result.group(2)) : 1d;
-          if (country == null) {
-            acceptLanguages.add(new Locale(language));
-          } else {
-            acceptLanguages.add(new Locale(language, country));
-          }
-        }
-      }
-      acceptLanguageScanner.close();
+    public String getValue() {
+      return value;
     }
-    return acceptLanguages;
+
+    public double getQuality() {
+      return quality;
+    }
+
   }
 
 }


[05/12] [OLINGO-83] Refactoring of 'annotation-processor-*' modules

Posted by tb...@apache.org.
http://git-wip-us.apache.org/repos/asf/incubator-olingo-odata2/blob/3bd59050/odata2-annotation-processor/annotation-processor-core/src/main/java/org/apache/olingo/odata2/core/annotation/edm/AnnotationEdmProvider.java
----------------------------------------------------------------------
diff --git a/odata2-annotation-processor/annotation-processor-core/src/main/java/org/apache/olingo/odata2/core/annotation/edm/AnnotationEdmProvider.java b/odata2-annotation-processor/annotation-processor-core/src/main/java/org/apache/olingo/odata2/core/annotation/edm/AnnotationEdmProvider.java
deleted file mode 100644
index e35e128..0000000
--- a/odata2-annotation-processor/annotation-processor-core/src/main/java/org/apache/olingo/odata2/core/annotation/edm/AnnotationEdmProvider.java
+++ /dev/null
@@ -1,769 +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.odata2.core.annotation.edm;
-
-import java.lang.reflect.Field;
-import java.lang.reflect.Modifier;
-import java.math.BigDecimal;
-import java.math.BigInteger;
-import java.util.ArrayList;
-import java.util.Calendar;
-import java.util.Collection;
-import java.util.Collections;
-import java.util.Date;
-import java.util.HashMap;
-import java.util.List;
-import java.util.Map;
-import java.util.UUID;
-
-import org.apache.olingo.odata2.api.annotation.edm.EdmComplexType;
-import org.apache.olingo.odata2.api.annotation.edm.EdmEntitySet;
-import org.apache.olingo.odata2.api.annotation.edm.EdmEntityType;
-import org.apache.olingo.odata2.api.annotation.edm.EdmKey;
-import org.apache.olingo.odata2.api.annotation.edm.EdmMediaResourceContent;
-import org.apache.olingo.odata2.api.annotation.edm.EdmNavigationProperty;
-import org.apache.olingo.odata2.api.annotation.edm.EdmProperty;
-import org.apache.olingo.odata2.api.annotation.edm.EdmType;
-import org.apache.olingo.odata2.api.edm.EdmMultiplicity;
-import org.apache.olingo.odata2.api.edm.FullQualifiedName;
-import org.apache.olingo.odata2.api.edm.provider.AnnotationAttribute;
-import org.apache.olingo.odata2.api.edm.provider.AnnotationElement;
-import org.apache.olingo.odata2.api.edm.provider.Association;
-import org.apache.olingo.odata2.api.edm.provider.AssociationEnd;
-import org.apache.olingo.odata2.api.edm.provider.AssociationSet;
-import org.apache.olingo.odata2.api.edm.provider.AssociationSetEnd;
-import org.apache.olingo.odata2.api.edm.provider.ComplexProperty;
-import org.apache.olingo.odata2.api.edm.provider.ComplexType;
-import org.apache.olingo.odata2.api.edm.provider.EdmProvider;
-import org.apache.olingo.odata2.api.edm.provider.EntityContainer;
-import org.apache.olingo.odata2.api.edm.provider.EntityContainerInfo;
-import org.apache.olingo.odata2.api.edm.provider.EntitySet;
-import org.apache.olingo.odata2.api.edm.provider.EntityType;
-import org.apache.olingo.odata2.api.edm.provider.FunctionImport;
-import org.apache.olingo.odata2.api.edm.provider.Key;
-import org.apache.olingo.odata2.api.edm.provider.NavigationProperty;
-import org.apache.olingo.odata2.api.edm.provider.Property;
-import org.apache.olingo.odata2.api.edm.provider.PropertyRef;
-import org.apache.olingo.odata2.api.edm.provider.Schema;
-import org.apache.olingo.odata2.api.edm.provider.SimpleProperty;
-import org.apache.olingo.odata2.api.edm.provider.Using;
-import org.apache.olingo.odata2.api.exception.ODataException;
-import org.apache.olingo.odata2.core.annotation.util.AnnotationHelper;
-import org.apache.olingo.odata2.core.annotation.util.ClassHelper;
-import org.apache.olingo.odata2.core.exception.ODataRuntimeException;
-
-/**
- * Provider for the entity data model used in the reference scenario
- * 
- */
-public class AnnotationEdmProvider extends EdmProvider {
-
-  private static final AnnotationHelper ANNOTATION_HELPER = new AnnotationHelper();
-
-  private final List<Class<?>> annotatedClasses;
-  private final Map<String, EntityContainer> name2Container = new HashMap<String, EntityContainer>();
-  private final Map<String, ContainerBuilder> containerName2ContainerBuilder = new HashMap<String, ContainerBuilder>();
-  private final Map<String, Schema> namespace2Schema = new HashMap<String, Schema>();
-  private EntityContainer defaultContainer;
-
-  public AnnotationEdmProvider(final Collection<Class<?>> annotatedClasses) {
-
-    this.annotatedClasses = new ArrayList<Class<?>>(annotatedClasses.size());
-    for (Class<?> aClass : annotatedClasses) {
-      if (ANNOTATION_HELPER.isEdmAnnotated(aClass)) {
-        this.annotatedClasses.add(aClass);
-      }
-    }
-
-    init();
-  }
-
-  public AnnotationEdmProvider(final String packageToScan) {
-    annotatedClasses = ClassHelper.loadClasses(packageToScan, new ClassHelper.ClassValidator() {
-      @Override
-      public boolean isClassValid(final Class<?> c) {
-        return ANNOTATION_HELPER.isEdmAnnotated(c);
-      }
-    });
-
-    init();
-  }
-
-  private void init() {
-    for (Class<?> aClass : annotatedClasses) {
-      updateSchema(aClass);
-      handleEntityContainer(aClass);
-    }
-
-    finish();
-  }
-
-  @Override
-  public Association getAssociation(final FullQualifiedName edmFQName) throws ODataException {
-    Schema schema = namespace2Schema.get(edmFQName.getNamespace());
-    if (schema != null) {
-      List<Association> associations = schema.getAssociations();
-      for (Association association : associations) {
-        if (association.getName().equals(edmFQName.getName())) {
-          return association;
-        }
-      }
-    }
-    return null;
-  }
-
-  @Override
-  public AssociationSet getAssociationSet(final String entityContainer, final FullQualifiedName association,
-      final String sourceEntitySetName, final String sourceEntitySetRole) throws ODataException {
-    EntityContainer container = name2Container.get(entityContainer);
-    if (container != null) {
-      List<AssociationSet> associations = container.getAssociationSets();
-      for (AssociationSet associationSet : associations) {
-        if (associationSet.getAssociation().equals(association)) {
-          final AssociationSetEnd endOne = associationSet.getEnd1();
-          if (endOne.getRole().equals(sourceEntitySetRole)
-              && endOne.getEntitySet().equals(sourceEntitySetName)) {
-            return associationSet;
-          }
-          final AssociationSetEnd endTwo = associationSet.getEnd2();
-          if (endTwo.getRole().equals(sourceEntitySetRole)
-              && endTwo.getEntitySet().equals(sourceEntitySetName)) {
-            return associationSet;
-          }
-        }
-      }
-    }
-    return null;
-  }
-
-  @Override
-  public ComplexType getComplexType(final FullQualifiedName edmFQName) throws ODataException {
-    Schema schema = namespace2Schema.get(edmFQName.getNamespace());
-    if (schema != null) {
-      List<ComplexType> complexTypes = schema.getComplexTypes();
-      for (ComplexType complexType : complexTypes) {
-        if (complexType.getName().equals(edmFQName.getName())) {
-          return complexType;
-        }
-      }
-    }
-    return null;
-  }
-
-  @Override
-  public EntityContainerInfo getEntityContainerInfo(final String name) throws ODataException {
-    EntityContainer container = name2Container.get(name);
-    if (container == null) {
-      // use default container (if set)
-      container = defaultContainer;
-    }
-    if (container != null) {
-      EntityContainerInfo info = new EntityContainerInfo();
-      info.setName(container.getName());
-      info.setDefaultEntityContainer(container.isDefaultEntityContainer());
-      info.setExtendz(container.getExtendz());
-      info.setAnnotationAttributes(container.getAnnotationAttributes());
-      info.setAnnotationElements(container.getAnnotationElements());
-
-      return info;
-    }
-
-    return null;
-  }
-
-  @Override
-  public EntitySet getEntitySet(final String entityContainer, final String name) throws ODataException {
-    EntityContainer container = name2Container.get(entityContainer);
-    if (container != null) {
-      List<EntitySet> entitySets = container.getEntitySets();
-      for (EntitySet entitySet : entitySets) {
-        if (entitySet.getName().equals(name)) {
-          return entitySet;
-        }
-      }
-    }
-
-    return null;
-  }
-
-  @Override
-  public EntityType getEntityType(final FullQualifiedName edmFQName) throws ODataException {
-    Schema schema = namespace2Schema.get(edmFQName.getNamespace());
-    if (schema != null) {
-      List<EntityType> complexTypes = schema.getEntityTypes();
-      for (EntityType complexType : complexTypes) {
-        if (complexType.getName().equals(edmFQName.getName())) {
-          return complexType;
-        }
-      }
-    }
-    return null;
-  }
-
-  @Override
-  public FunctionImport getFunctionImport(final String entityContainer, final String name) throws ODataException {
-    EntityContainer container = name2Container.get(entityContainer);
-    if (container != null) {
-      List<FunctionImport> functionImports = container.getFunctionImports();
-      for (FunctionImport functionImport : functionImports) {
-        if (functionImport.getName().equals(name)) {
-          return functionImport;
-        }
-      }
-    }
-    return null;
-  }
-
-  @Override
-  public List<Schema> getSchemas() throws ODataException {
-    return new ArrayList<Schema>(namespace2Schema.values());
-  }
-
-  //
-  //
-  //
-  private Map<String, SchemaBuilder> namespace2SchemaBuilder = new HashMap<String, SchemaBuilder>();
-
-  private void updateSchema(final Class<?> aClass) {
-    EdmEntityType et = aClass.getAnnotation(EdmEntityType.class);
-    if (et != null) {
-      updateSchema(aClass, et);
-    }
-    EdmComplexType ect = aClass.getAnnotation(EdmComplexType.class);
-    if (ect != null) {
-      updateSchema(aClass, ect);
-    }
-  }
-
-  private void updateSchema(final Class<?> aClass, final EdmEntityType et) {
-    SchemaBuilder b = getSchemaBuilder(et.namespace(), aClass);
-    TypeBuilder typeBuilder = TypeBuilder.init(et, aClass);
-    b.addEntityType(typeBuilder.buildEntityType());
-    b.addAssociations(typeBuilder.buildAssociations());
-  }
-
-  private SchemaBuilder getSchemaBuilder(final String namespace, final Class<?> aClass) {
-    String usedNamespace = namespace;
-    if (usedNamespace.isEmpty()) {
-      usedNamespace = ANNOTATION_HELPER.getCanonicalNamespace(aClass);
-    }
-    SchemaBuilder builder = namespace2SchemaBuilder.get(usedNamespace);
-    if (builder == null) {
-      builder = SchemaBuilder.init(usedNamespace);
-      namespace2SchemaBuilder.put(usedNamespace, builder);
-    }
-    return builder;
-  }
-
-  private void updateSchema(final Class<?> aClass, final EdmComplexType et) {
-    SchemaBuilder b = getSchemaBuilder(et.namespace(), aClass);
-    TypeBuilder typeBuilder = TypeBuilder.init(et, aClass);
-    b.addComplexType(typeBuilder.buildComplexType());
-  }
-
-  private void handleEntityContainer(final Class<?> aClass) {
-    EdmEntityType entityType = aClass.getAnnotation(EdmEntityType.class);
-    if (entityType != null) {
-      FullQualifiedName typeName = createFqnForEntityType(aClass, entityType);
-      String containerName = ANNOTATION_HELPER.extractContainerName(aClass);
-      ContainerBuilder builder = containerName2ContainerBuilder.get(containerName);
-      if (builder == null) {
-        builder = ContainerBuilder.init(typeName.getNamespace(), containerName);
-        containerName2ContainerBuilder.put(containerName, builder);
-      }
-      EdmEntitySet entitySet = aClass.getAnnotation(EdmEntitySet.class);
-      if (entitySet != null) {
-        builder.addEntitySet(createEntitySet(typeName, aClass));
-      }
-    }
-  }
-
-  private EntitySet createEntitySet(final FullQualifiedName typeName, final Class<?> entitySetClass) {
-    String entitySetName = ANNOTATION_HELPER.extractEntitySetName(entitySetClass);
-    return new EntitySet().setName(entitySetName).setEntityType(typeName);
-  }
-
-  private FullQualifiedName createFqnForEntityType(final Class<?> annotatedClass, final EdmEntityType entityType) {
-    return ANNOTATION_HELPER.extractEntityTypeFqn(annotatedClass);
-  }
-
-  private void finish() {
-    //
-    Collection<ContainerBuilder> containers = containerName2ContainerBuilder.values();
-    for (ContainerBuilder containerBuilder : containers) {
-      SchemaBuilder schemaBuilder = namespace2SchemaBuilder.get(containerBuilder.getNamespace());
-      containerBuilder.addAssociationSets(schemaBuilder.name2Associations.values());
-      final EntityContainer container = containerBuilder.build();
-      schemaBuilder.addEntityContainer(container);
-      name2Container.put(container.getName(), container);
-      if (container.isDefaultEntityContainer()) {
-        defaultContainer = container;
-      }
-    }
-    //
-    Collection<SchemaBuilder> schemaBuilders = namespace2SchemaBuilder.values();
-    for (SchemaBuilder schemaBuilder : schemaBuilders) {
-      final Schema schema = schemaBuilder.build();
-      namespace2Schema.put(schema.getNamespace(), schema);
-    }
-  }
-
-  //
-  //
-  //
-  static class TypeBuilder {
-
-    final private String namespace;
-    final private String name;
-    private boolean isAbstract = false;
-    private boolean isMediaResource = false;
-    private FullQualifiedName baseEntityType = null;
-    private final List<PropertyRef> keyProperties = new ArrayList<PropertyRef>();
-    private final List<Property> properties = new ArrayList<Property>();
-    private final List<NavigationProperty> navProperties = new ArrayList<NavigationProperty>();
-    private final List<Association> associations = new ArrayList<Association>();
-
-    public TypeBuilder(final FullQualifiedName fqn) {
-      namespace = fqn.getNamespace();
-      name = fqn.getName();
-    }
-
-    public static TypeBuilder init(final EdmEntityType entity, final Class<?> aClass) {
-      return new TypeBuilder(ANNOTATION_HELPER.extractEntityTypeFqn(entity, aClass)).withClass(aClass);
-    }
-
-    public static TypeBuilder init(final EdmComplexType entity, final Class<?> aClass) {
-      return new TypeBuilder(ANNOTATION_HELPER.extractComplexTypeFqn(entity, aClass)).withClass(aClass);
-    }
-
-    private TypeBuilder withClass(final Class<?> aClass) {
-      baseEntityType = createBaseEntityFqn(aClass);
-
-      if (Modifier.isAbstract(aClass.getModifiers())) {
-        isAbstract = true;
-      }
-
-      Field[] fields = aClass.getDeclaredFields();
-      for (Field field : fields) {
-        EdmProperty ep = field.getAnnotation(EdmProperty.class);
-        if (ep != null) {
-          properties.add(createProperty(ep, field, namespace));
-          EdmKey eti = field.getAnnotation(EdmKey.class);
-          if (eti != null) {
-            keyProperties.add(createKeyProperty(ep, field));
-          }
-        }
-        EdmNavigationProperty enp = field.getAnnotation(EdmNavigationProperty.class);
-        if (enp != null) {
-          final NavigationProperty navProperty = createNavigationProperty(namespace, enp, field);
-          navProperties.add(navProperty);
-          Association association = createAssociation(field, navProperty);
-          associations.add(association);
-        }
-        EdmMediaResourceContent emrc = field.getAnnotation(EdmMediaResourceContent.class);
-        if (emrc != null) {
-          isMediaResource = true;
-        }
-      }
-
-      return this;
-    }
-
-    public TypeBuilder addProperty(final PropertyRef property) {
-      keyProperties.add(property);
-      return this;
-    }
-
-    public TypeBuilder addProperty(final Property property) {
-      properties.add(property);
-      return this;
-    }
-
-    public TypeBuilder addNavigationProperty(final NavigationProperty property) {
-      navProperties.add(property);
-      return this;
-    }
-
-    public TypeBuilder setAbstract(final boolean isAbstract) {
-      this.isAbstract = isAbstract;
-      return this;
-    }
-
-    public ComplexType buildComplexType() {
-      ComplexType complexType = new ComplexType();
-      if (baseEntityType != null) {
-        complexType.setBaseType(baseEntityType);
-      }
-      return complexType.setName(name).setProperties(properties);
-    }
-
-    public EntityType buildEntityType() {
-      EntityType entityType = new EntityType();
-      if (baseEntityType != null) {
-        entityType.setBaseType(baseEntityType);
-      }
-      if (!keyProperties.isEmpty()) {
-        entityType.setKey(new Key().setKeys(keyProperties));
-      }
-      if (!navProperties.isEmpty()) {
-        entityType.setNavigationProperties(navProperties);
-      }
-      return entityType.setName(name)
-          .setAbstract(isAbstract)
-          .setHasStream(isMediaResource)
-          .setProperties(properties);
-    }
-
-    public Collection<Association> buildAssociations() {
-      return Collections.unmodifiableCollection(associations);
-    }
-
-    private PropertyRef createKeyProperty(final EdmProperty et, final Field field) {
-      PropertyRef keyProperty = new PropertyRef();
-      String entityName = et.name();
-      if (entityName.isEmpty()) {
-        entityName = getCanonicalName(field);
-      }
-      return keyProperty.setName(entityName);
-    }
-
-    private Property createProperty(final EdmProperty ep, final Field field, final String defaultNamespace) {
-      if (isAnnotatedEntity(field.getType())) {
-        return createComplexProperty(field, defaultNamespace);
-      } else {
-        return createSimpleProperty(ep, field);
-      }
-    }
-
-    private Property createSimpleProperty(final EdmProperty ep, final Field field) {
-      SimpleProperty sp = new SimpleProperty();
-      String entityName = ANNOTATION_HELPER.getPropertyName(field);
-      sp.setName(entityName);
-      //
-      EdmType type = ep.type();
-      if (type == EdmType.NULL) {
-        type = getEdmType(field.getType());
-      }
-      sp.setType(ANNOTATION_HELPER.mapTypeKind(type));
-
-      return sp;
-    }
-
-    private Property createComplexProperty(final Field field, final String defaultNamespace) {
-      ComplexProperty cp = new ComplexProperty();
-      // settings from property
-      String entityName = ANNOTATION_HELPER.getPropertyName(field);
-      cp.setName(entityName);
-
-      // settings from related complex entity
-      EdmComplexType ece = field.getType().getAnnotation(EdmComplexType.class);
-      String complexEntityNamespace = ece.namespace();
-      if (complexEntityNamespace.isEmpty()) {
-        complexEntityNamespace = defaultNamespace;
-      }
-      cp.setType(new FullQualifiedName(complexEntityNamespace, ece.name()));
-
-      return cp;
-    }
-
-    private NavigationProperty createNavigationProperty(final String namespace, final EdmNavigationProperty enp,
-        final Field field) {
-      NavigationProperty navProp = new NavigationProperty();
-      navProp.setName(ANNOTATION_HELPER.getPropertyName(field));
-      String fromRole = ANNOTATION_HELPER.extractFromRoleName(enp, field);
-      navProp.setFromRole(fromRole);
-
-      String toRole = ANNOTATION_HELPER.extractToRoleName(enp, field);
-      navProp.setToRole(toRole);
-
-      String relationshipName = ANNOTATION_HELPER.extractRelationshipName(enp, field);
-      navProp.setRelationship(new FullQualifiedName(namespace, relationshipName));
-
-      return navProp;
-    }
-
-//    private EdmSimpleTypeKind getEdmSimpleType(Class<?> type) {
-//      if (type == String.class) {
-//        return EdmType.String;
-//      } else if (type == boolean.class || type == Boolean.class) {
-//        return EdmType.Boolean;
-//      } else if (type == byte.class || type == Byte.class) {
-//        return EdmType.SByte;
-//      } else if (type == short.class || type == Short.class) {
-//        return EdmType.Int16;
-//      } else if (type == int.class || type == Integer.class) {
-//        return EdmType.Int32;
-//      } else if (type == long.class || type == Long.class) {
-//        return EdmType.Int64;
-//      } else if (type == double.class || type == Double.class) {
-//        return EdmType.Double;
-//      } else if (type == float.class || type == Float.class) {
-//        return EdmType.Single;
-//      } else if (type == BigInteger.class || type == BigDecimal.class) {
-//        return EdmType.Decimal;
-//      } else if (type == Byte[].class || type == byte[].class) {
-//        return EdmType.Binary;
-//      } else if (type == Date.class) {
-//        return EdmType.DateTime;
-//      } else if (type == Calendar.class) {
-//        return EdmType.DateTimeOffset;
-//      } else if (type == UUID.class) {
-//        return EdmType.Guid;
-//      } else {
-//        throw new UnsupportedOperationException("Not yet supported type '" + type + "'.");
-//      }
-//    }
-
-    private EdmType getEdmType(final Class<?> type) {
-      if (type == String.class) {
-        return EdmType.STRING;
-      } else if (type == boolean.class || type == Boolean.class) {
-        return EdmType.BOOLEAN;
-      } else if (type == byte.class || type == Byte.class) {
-        return EdmType.SBYTE;
-      } else if (type == short.class || type == Short.class) {
-        return EdmType.INT16;
-      } else if (type == int.class || type == Integer.class) {
-        return EdmType.INT32;
-      } else if (type == long.class || type == Long.class) {
-        return EdmType.INT64;
-      } else if (type == double.class || type == Double.class) {
-        return EdmType.DOUBLE;
-      } else if (type == float.class || type == Float.class) {
-        return EdmType.SINGLE;
-      } else if (type == BigInteger.class || type == BigDecimal.class) {
-        return EdmType.DECIMAL;
-      } else if (type == Byte[].class || type == byte[].class) {
-        return EdmType.BINARY;
-      } else if (type == Date.class) {
-        return EdmType.DATE_TIME;
-      } else if (type == Calendar.class) {
-        return EdmType.DATE_TIME_OFFSET;
-      } else if (type == UUID.class) {
-        return EdmType.GUID;
-      } else {
-        throw new UnsupportedOperationException("Not yet supported type '" + type + "'.");
-      }
-    }
-
-    private Class<?> checkForBaseEntityClass(final Class<?> aClass) {
-      Class<?> superClass = aClass.getSuperclass();
-      if (superClass == Object.class) {
-        return null;
-      } else {
-        EdmEntityType edmEntity = superClass.getAnnotation(EdmEntityType.class);
-        if (edmEntity == null) {
-          return checkForBaseEntityClass(superClass);
-        } else {
-          return superClass;
-        }
-      }
-    }
-
-    private FullQualifiedName createBaseEntityFqn(final Class<?> aClass) {
-      Class<?> baseEntityClass = checkForBaseEntityClass(aClass);
-      if (baseEntityClass == null) {
-        return null;
-      }
-      return ANNOTATION_HELPER.extractEntityTypeFqn(baseEntityClass);
-    }
-
-    private Association createAssociation(final Field field, final NavigationProperty navProperty) {
-      Association association = new Association();
-      EdmNavigationProperty navigation = field.getAnnotation(EdmNavigationProperty.class);
-
-      AssociationEnd fromEnd = new AssociationEnd();
-      fromEnd.setRole(navProperty.getFromRole());
-      String typeName = ANNOTATION_HELPER.extractEntityTypeName(field.getDeclaringClass());
-      fromEnd.setType(new FullQualifiedName(namespace, typeName));
-      fromEnd.setMultiplicity(EdmMultiplicity.ONE);
-      association.setEnd1(fromEnd);
-
-      AssociationEnd toEnd = new AssociationEnd();
-      toEnd.setRole(navProperty.getToRole());
-      String toTypeName = ANNOTATION_HELPER.extractEntitTypeName(navigation, field);
-      toEnd.setType(new FullQualifiedName(namespace, toTypeName));
-      toEnd.setMultiplicity(ANNOTATION_HELPER.getMultiplicity(navigation, field));
-      association.setEnd2(toEnd);
-
-      String associationName = navProperty.getRelationship().getName();
-      association.setName(associationName);
-      return association;
-    }
-
-    private String getCanonicalName(final Field field) {
-      return ANNOTATION_HELPER.getCanonicalName(field);
-    }
-
-    private boolean isAnnotatedEntity(final Class<?> clazz) {
-      return ANNOTATION_HELPER.isEdmTypeAnnotated(clazz);
-    }
-  }
-
-  static class SchemaBuilder {
-
-    final private String namespace;
-    // private String alias;
-    private final List<Using> usings = new ArrayList<Using>();
-    private final List<EntityType> entityTypes = new ArrayList<EntityType>();
-    private final List<ComplexType> complexTypes = new ArrayList<ComplexType>();
-    private final Map<String, Association> name2Associations = new HashMap<String, Association>();
-    private final List<EntityContainer> entityContainers = new ArrayList<EntityContainer>();
-    private final List<AnnotationAttribute> annotationAttributes = new ArrayList<AnnotationAttribute>();
-    private final List<AnnotationElement> annotationElements = new ArrayList<AnnotationElement>();
-
-    private SchemaBuilder(final String namespace) {
-      this.namespace = namespace;
-    }
-
-    public static SchemaBuilder init(final String namespace) {
-      return new SchemaBuilder(namespace);
-    }
-
-    public SchemaBuilder addEntityType(final EntityType type) {
-      entityTypes.add(type);
-      return this;
-    }
-
-    public SchemaBuilder addEntityContainer(final EntityContainer container) {
-      entityContainers.add(container);
-      return this;
-    }
-
-    public SchemaBuilder addComplexType(final ComplexType createEntityType) {
-      complexTypes.add(createEntityType);
-      return this;
-    }
-
-    public void addAssociations(final Collection<Association> associations) {
-      for (Association association : associations) {
-        final String relationshipName = association.getName();
-        if (name2Associations.containsKey(relationshipName)) {
-          association = mergeAssociations(name2Associations.get(relationshipName), association);
-        }
-        name2Associations.put(relationshipName, association);
-      }
-    }
-
-    private Association mergeAssociations(final Association associationOne, final Association associationTwo) {
-      AssociationEnd oneEnd1 = associationOne.getEnd1();
-      AssociationEnd oneEnd2 = associationOne.getEnd2();
-      AssociationEnd twoEnd1 = associationTwo.getEnd1();
-      AssociationEnd twoEnd2 = associationTwo.getEnd2();
-      AssociationEnd[] oneEnds = new AssociationEnd[] { oneEnd1, oneEnd2 };
-
-      for (AssociationEnd associationEnd : oneEnds) {
-        if (associationEnd.getRole().equals(twoEnd1.getRole())) {
-          if (twoEnd1.getMultiplicity() == EdmMultiplicity.MANY) {
-            associationEnd.setMultiplicity(EdmMultiplicity.MANY);
-          }
-        } else if (associationEnd.getRole().equals(twoEnd2.getRole())) {
-          if (twoEnd2.getMultiplicity() == EdmMultiplicity.MANY) {
-            associationEnd.setMultiplicity(EdmMultiplicity.MANY);
-          }
-        }
-      }
-
-      return associationOne;
-    }
-
-    public Schema build() {
-      Schema s = new Schema();
-      s.setUsings(usings);
-      s.setEntityTypes(entityTypes);
-      s.setComplexTypes(complexTypes);
-      s.setAssociations(new ArrayList<Association>(name2Associations.values()));
-      s.setEntityContainers(entityContainers);
-      s.setAnnotationAttributes(annotationAttributes);
-      s.setAnnotationElements(annotationElements);
-      s.setNamespace(namespace);
-      return s;
-    }
-  }
-
-  private static class ContainerBuilder {
-
-    final private String name;
-    final private String namespace;
-    private boolean defaultContainer = true;
-    private final List<EntitySet> entitySets = new ArrayList<EntitySet>();
-    private final List<AssociationSet> associationSets = new ArrayList<AssociationSet>();
-    private final List<FunctionImport> functionImports = new ArrayList<FunctionImport>();
-
-    // private Documentation documentation;
-
-    private ContainerBuilder(final String namespace, final String containerName) {
-      this.namespace = namespace;
-      name = containerName;
-    }
-
-    public String getNamespace() {
-      return namespace;
-    }
-
-    public static ContainerBuilder init(final String namespace, final String containerName) {
-      return new ContainerBuilder(namespace, containerName);
-    }
-
-    public ContainerBuilder addEntitySet(final EntitySet entitySet) {
-      entitySets.add(entitySet);
-      return this;
-    }
-
-    public void addAssociationSets(final Collection<Association> associations) {
-      for (Association association : associations) {
-        AssociationSet as = new AssociationSet();
-        as.setName(association.getName());
-        FullQualifiedName asAssociationFqn = new FullQualifiedName(namespace, association.getName());
-        as.setAssociation(asAssociationFqn);
-
-        AssociationSetEnd asEnd1 = new AssociationSetEnd();
-        asEnd1.setEntitySet(getEntitySetName(association.getEnd1()));
-        asEnd1.setRole(association.getEnd1().getRole());
-        as.setEnd1(asEnd1);
-
-        AssociationSetEnd asEnd2 = new AssociationSetEnd();
-        asEnd2.setEntitySet(getEntitySetName(association.getEnd2()));
-        asEnd2.setRole(association.getEnd2().getRole());
-        as.setEnd2(asEnd2);
-
-        associationSets.add(as);
-      }
-    }
-
-    public EntityContainer build() {
-      EntityContainer ec = new EntityContainer();
-      ec.setName(name);
-      ec.setDefaultEntityContainer(defaultContainer);
-      ec.setEntitySets(entitySets);
-      ec.setAssociationSets(associationSets);
-      ec.setFunctionImports(functionImports);
-      return ec;
-    }
-
-    private String getEntitySetName(final AssociationEnd end) {
-      for (EntitySet entitySet : entitySets) {
-        if (entitySet.getEntityType().equals(end.getType())) {
-          return entitySet.getName();
-        }
-      }
-      throw new ODataRuntimeException("No entity set found for " + end.getType());
-    }
-  }
-}


[12/12] git commit: [OLINGO-67] Merge remote-tracking branch 'origin/master' into ODataServlet

Posted by tb...@apache.org.
[OLINGO-67] Merge remote-tracking branch 'origin/master' into ODataServlet


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

Branch: refs/heads/ODataServlet
Commit: 80379ec10a99080b8b012814216107dbaf6951e6
Parents: 22e54c4 33aaa3a
Author: Tamara Boehm <ta...@sap.com>
Authored: Fri Dec 20 16:14:58 2013 +0100
Committer: Tamara Boehm <ta...@sap.com>
Committed: Fri Dec 20 16:14:58 2013 +0100

----------------------------------------------------------------------
 .../processor/api/AnnotationServiceFactory.java |  118 ++
 .../olingo/odata2/api/data/DataSource.java      |  200 ---
 .../odata2/api/data/DataSourceProcessor.java    |   47 -
 .../olingo/odata2/api/data/ValueAccess.java     |   69 -
 .../core/AnnotationServiceFactoryImpl.java      |   73 +
 .../processor/core/DataSourceProcessor.java     |   49 +
 .../processor/core/ListsProcessor.java          | 1640 +++++++++++++++++
 .../core/datasource/AnnotationInMemoryDs.java   |  384 ++++
 .../core/datasource/AnnotationValueAccess.java  |  108 ++
 .../core/datasource/BeanPropertyAccess.java     |  185 ++
 .../processor/core/datasource/DataSource.java   |  200 +++
 .../processor/core/datasource/DataStore.java    |  294 ++++
 .../processor/core/datasource/ValueAccess.java  |   69 +
 .../core/edm/AnnotationEdmProvider.java         |  769 ++++++++
 .../processor/core/util/AnnotationHelper.java   |  777 +++++++++
 .../processor/core/util/ClassHelper.java        |  140 ++
 .../annotation/data/AnnotationInMemoryDs.java   |  376 ----
 .../annotation/data/AnnotationValueAccess.java  |  109 --
 .../annotation/data/BeanPropertyAccess.java     |  186 --
 .../odata2/core/annotation/data/DataStore.java  |  294 ----
 .../annotation/edm/AnnotationEdmProvider.java   |  769 --------
 .../annotation/processor/ListsProcessor.java    | 1641 ------------------
 .../core/annotation/util/AnnotationHelper.java  |  777 ---------
 .../core/annotation/util/ClassHelper.java       |  140 --
 .../data/AnnotationsInMemoryDsTest.java         |   10 +-
 .../edm/AnnotationEdmProviderTest.java          |    1 +
 .../ref/AnnotationRefServiceFactory.java        |  215 +++
 .../processor/ref/model/Building.java           |   97 ++
 .../annotation/processor/ref/model/City.java    |   61 +
 .../processor/ref/model/Employee.java           |  192 ++
 .../processor/ref/model/Location.java           |   60 +
 .../annotation/processor/ref/model/Manager.java |   43 +
 .../ref/model/ModelSharedConstants.java         |   25 +
 .../annotation/processor/ref/model/Photo.java   |  128 ++
 .../annotation/processor/ref/model/RefBase.java |   78 +
 .../processor/ref/model/ResourceHelper.java     |   96 +
 .../annotation/processor/ref/model/Room.java    |   88 +
 .../annotation/processor/ref/model/Team.java    |   73 +
 .../odata2/ref/annotation/model/Building.java   |   97 --
 .../odata2/ref/annotation/model/City.java       |   61 -
 .../odata2/ref/annotation/model/Employee.java   |  192 --
 .../odata2/ref/annotation/model/Location.java   |   60 -
 .../odata2/ref/annotation/model/Manager.java    |   43 -
 .../annotation/model/ModelSharedConstants.java  |   25 -
 .../odata2/ref/annotation/model/Photo.java      |  128 --
 .../odata2/ref/annotation/model/RefBase.java    |   78 -
 .../ref/annotation/model/ResourceHelper.java    |   96 -
 .../odata2/ref/annotation/model/Room.java       |   88 -
 .../odata2/ref/annotation/model/Team.java       |   73 -
 .../processor/AnnotationServiceFactory.java     |  215 ---
 .../src/main/webapp/WEB-INF/web.xml             |    2 +-
 .../olingo/odata2/api/edm/EdmException.java     |    7 +
 .../olingo/odata2/api/rt/RuntimeDelegate.java   |    7 +
 .../odata2/api/uri/ExpandSelectTreeNode.java    |   91 +-
 .../odata2/core/rt/RuntimeDelegateImpl.java     |    8 +
 .../core/uri/ExpandSelectTreeNodeImpl.java      |  117 +-
 .../src/main/resources/i18n.properties          |    4 +
 .../ExpandSelectProducerWithBuilderTest.java    |  204 +++
 .../core/ep/producer/XmlExpandProducerTest.java |   24 +
 .../uri/ExpandSelectTreeNodeBuilderTest.java    |  282 +++
 .../olingo/odata2/fit/ref/AbstractRefTest.java  |    4 +-
 .../odata2/fit/ref/EntryXmlReadOnlyTest.java    |    2 +-
 .../AbstractContentNegotiationTest.java         |    4 +-
 .../ref/processor/ScenarioDataSource.java       |    2 +-
 .../ref/processor/ScenarioServiceFactory.java   |    4 +-
 .../olingo/odata2/ref/read/EntitySetTest.java   |    4 +-
 .../olingo/odata2/ref/read/EntityTest.java      |    4 +-
 67 files changed, 6720 insertions(+), 5787 deletions(-)
----------------------------------------------------------------------


http://git-wip-us.apache.org/repos/asf/incubator-olingo-odata2/blob/80379ec1/odata2-annotation-processor/annotation-processor-core/src/main/java/org/apache/olingo/odata2/annotation/processor/core/ListsProcessor.java
----------------------------------------------------------------------
diff --cc odata2-annotation-processor/annotation-processor-core/src/main/java/org/apache/olingo/odata2/annotation/processor/core/ListsProcessor.java
index 0000000,85e011c..de0a2da
mode 000000,100644..100644
--- a/odata2-annotation-processor/annotation-processor-core/src/main/java/org/apache/olingo/odata2/annotation/processor/core/ListsProcessor.java
+++ b/odata2-annotation-processor/annotation-processor-core/src/main/java/org/apache/olingo/odata2/annotation/processor/core/ListsProcessor.java
@@@ -1,0 -1,1640 +1,1640 @@@
+ /*******************************************************************************
+  * Licensed to the Apache Software Foundation (ASF) under one
+  * or more contributor license agreements. See the NOTICE file
+  * distributed with this work for additional information
+  * regarding copyright ownership. The ASF licenses this file
+  * to you under the Apache License, Version 2.0 (the
+  * "License"); you may not use this file except in compliance
+  * with the License. You may obtain a copy of the License at
+  * 
+  * http://www.apache.org/licenses/LICENSE-2.0
+  * 
+  * Unless required by applicable law or agreed to in writing,
+  * software distributed under the License is distributed on an
+  * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+  * KIND, either express or implied. See the License for the
+  * specific language governing permissions and limitations
+  * under the License.
+  ******************************************************************************/
+ package org.apache.olingo.odata2.annotation.processor.core;
+ 
+ import java.io.InputStream;
+ import java.util.ArrayList;
+ import java.util.Arrays;
+ import java.util.Collections;
+ import java.util.Comparator;
+ import java.util.HashMap;
+ import java.util.Iterator;
+ import java.util.List;
+ import java.util.Locale;
+ import java.util.Map;
+ 
+ import org.apache.olingo.odata2.annotation.processor.core.datasource.DataSource;
+ import org.apache.olingo.odata2.annotation.processor.core.datasource.ValueAccess;
+ import org.apache.olingo.odata2.annotation.processor.core.datasource.DataSource.BinaryData;
+ import org.apache.olingo.odata2.api.ODataCallback;
+ import org.apache.olingo.odata2.api.batch.BatchHandler;
+ import org.apache.olingo.odata2.api.batch.BatchRequestPart;
+ import org.apache.olingo.odata2.api.batch.BatchResponsePart;
+ import org.apache.olingo.odata2.api.commons.HttpContentType;
+ import org.apache.olingo.odata2.api.commons.HttpStatusCodes;
+ import org.apache.olingo.odata2.api.commons.InlineCount;
+ import org.apache.olingo.odata2.api.edm.Edm;
+ import org.apache.olingo.odata2.api.edm.EdmConcurrencyMode;
+ import org.apache.olingo.odata2.api.edm.EdmEntitySet;
+ import org.apache.olingo.odata2.api.edm.EdmEntityType;
+ import org.apache.olingo.odata2.api.edm.EdmException;
+ import org.apache.olingo.odata2.api.edm.EdmFunctionImport;
+ import org.apache.olingo.odata2.api.edm.EdmLiteral;
+ import org.apache.olingo.odata2.api.edm.EdmLiteralKind;
+ import org.apache.olingo.odata2.api.edm.EdmMapping;
+ import org.apache.olingo.odata2.api.edm.EdmMultiplicity;
+ import org.apache.olingo.odata2.api.edm.EdmNavigationProperty;
+ import org.apache.olingo.odata2.api.edm.EdmProperty;
+ import org.apache.olingo.odata2.api.edm.EdmSimpleType;
+ import org.apache.olingo.odata2.api.edm.EdmSimpleTypeException;
+ import org.apache.olingo.odata2.api.edm.EdmSimpleTypeKind;
+ import org.apache.olingo.odata2.api.edm.EdmStructuralType;
+ import org.apache.olingo.odata2.api.edm.EdmType;
+ import org.apache.olingo.odata2.api.edm.EdmTypeKind;
+ import org.apache.olingo.odata2.api.edm.EdmTyped;
+ import org.apache.olingo.odata2.api.ep.EntityProvider;
+ import org.apache.olingo.odata2.api.ep.EntityProviderBatchProperties;
+ import org.apache.olingo.odata2.api.ep.EntityProviderException;
+ import org.apache.olingo.odata2.api.ep.EntityProviderReadProperties;
+ import org.apache.olingo.odata2.api.ep.EntityProviderWriteProperties;
+ import org.apache.olingo.odata2.api.ep.callback.OnWriteEntryContent;
+ import org.apache.olingo.odata2.api.ep.callback.OnWriteFeedContent;
+ import org.apache.olingo.odata2.api.ep.callback.WriteCallbackContext;
+ import org.apache.olingo.odata2.api.ep.callback.WriteEntryCallbackContext;
+ import org.apache.olingo.odata2.api.ep.callback.WriteEntryCallbackResult;
+ import org.apache.olingo.odata2.api.ep.callback.WriteFeedCallbackContext;
+ import org.apache.olingo.odata2.api.ep.callback.WriteFeedCallbackResult;
+ import org.apache.olingo.odata2.api.ep.entry.ODataEntry;
+ import org.apache.olingo.odata2.api.ep.feed.ODataFeed;
+ import org.apache.olingo.odata2.api.exception.ODataApplicationException;
+ import org.apache.olingo.odata2.api.exception.ODataBadRequestException;
+ import org.apache.olingo.odata2.api.exception.ODataException;
+ import org.apache.olingo.odata2.api.exception.ODataHttpException;
+ import org.apache.olingo.odata2.api.exception.ODataNotFoundException;
+ import org.apache.olingo.odata2.api.exception.ODataNotImplementedException;
+ import org.apache.olingo.odata2.api.processor.ODataContext;
+ import org.apache.olingo.odata2.api.processor.ODataRequest;
+ import org.apache.olingo.odata2.api.processor.ODataResponse;
+ import org.apache.olingo.odata2.api.uri.ExpandSelectTreeNode;
+ import org.apache.olingo.odata2.api.uri.KeyPredicate;
+ import org.apache.olingo.odata2.api.uri.NavigationSegment;
+ import org.apache.olingo.odata2.api.uri.PathInfo;
+ import org.apache.olingo.odata2.api.uri.UriParser;
+ import org.apache.olingo.odata2.api.uri.expression.BinaryExpression;
+ import org.apache.olingo.odata2.api.uri.expression.CommonExpression;
+ import org.apache.olingo.odata2.api.uri.expression.ExpressionKind;
+ import org.apache.olingo.odata2.api.uri.expression.FilterExpression;
+ import org.apache.olingo.odata2.api.uri.expression.LiteralExpression;
+ import org.apache.olingo.odata2.api.uri.expression.MemberExpression;
+ import org.apache.olingo.odata2.api.uri.expression.MethodExpression;
+ import org.apache.olingo.odata2.api.uri.expression.OrderByExpression;
+ import org.apache.olingo.odata2.api.uri.expression.OrderExpression;
+ import org.apache.olingo.odata2.api.uri.expression.PropertyExpression;
+ import org.apache.olingo.odata2.api.uri.expression.SortOrder;
+ import org.apache.olingo.odata2.api.uri.expression.UnaryExpression;
+ import org.apache.olingo.odata2.api.uri.info.DeleteUriInfo;
+ import org.apache.olingo.odata2.api.uri.info.GetComplexPropertyUriInfo;
+ import org.apache.olingo.odata2.api.uri.info.GetEntityCountUriInfo;
+ import org.apache.olingo.odata2.api.uri.info.GetEntityLinkCountUriInfo;
+ import org.apache.olingo.odata2.api.uri.info.GetEntityLinkUriInfo;
+ import org.apache.olingo.odata2.api.uri.info.GetEntitySetCountUriInfo;
+ import org.apache.olingo.odata2.api.uri.info.GetEntitySetLinksCountUriInfo;
+ import org.apache.olingo.odata2.api.uri.info.GetEntitySetLinksUriInfo;
+ import org.apache.olingo.odata2.api.uri.info.GetEntitySetUriInfo;
+ import org.apache.olingo.odata2.api.uri.info.GetEntityUriInfo;
+ import org.apache.olingo.odata2.api.uri.info.GetFunctionImportUriInfo;
+ import org.apache.olingo.odata2.api.uri.info.GetMediaResourceUriInfo;
+ import org.apache.olingo.odata2.api.uri.info.GetSimplePropertyUriInfo;
+ import org.apache.olingo.odata2.api.uri.info.PostUriInfo;
+ import org.apache.olingo.odata2.api.uri.info.PutMergePatchUriInfo;
+ 
+ /**
+  * Implementation of the centralized parts of OData processing,
+  * allowing to use the simplified {@link DataSource} for the
+  * actual data handling.
+  * 
+  */
+ public class ListsProcessor extends DataSourceProcessor {
+ 
+   // TODO: Paging size should be configurable.
+   private static final int SERVER_PAGING_SIZE = 100;
+ 
+   public ListsProcessor(final DataSource dataSource, final ValueAccess valueAccess) {
+     super(dataSource, valueAccess);
+   }
+ 
+   @Override
+   public ODataResponse readEntitySet(final GetEntitySetUriInfo uriInfo, final String contentType)
+       throws ODataException {
+     ArrayList<Object> data = new ArrayList<Object>();
+     try {
+       data.addAll((List<?>) retrieveData(
+           uriInfo.getStartEntitySet(),
+           uriInfo.getKeyPredicates(),
+           uriInfo.getFunctionImport(),
+           mapFunctionParameters(uriInfo.getFunctionImportParameters()),
+           uriInfo.getNavigationSegments()));
+     } catch (final ODataNotFoundException e) {
+       data.clear();
+     }
+ 
+     final EdmEntitySet entitySet = uriInfo.getTargetEntitySet();
+     final InlineCount inlineCountType = uriInfo.getInlineCount();
+     final Integer count = applySystemQueryOptions(
+         entitySet,
+         data,
+         uriInfo.getFilter(),
+         inlineCountType,
+         uriInfo.getOrderBy(),
+         uriInfo.getSkipToken(),
+         uriInfo.getSkip(),
+         uriInfo.getTop());
+ 
+     ODataContext context = getContext();
+     String nextLink = null;
+ 
+     // Limit the number of returned entities and provide a "next" link
+     // if there are further entities.
+     // Almost all system query options in the current request must be carried
+     // over to the URI for the "next" link, with the exception of $skiptoken
+     // and $skip.
+     if (data.size() > SERVER_PAGING_SIZE) {
+       if (uriInfo.getOrderBy() == null
+           && uriInfo.getSkipToken() == null
+           && uriInfo.getSkip() == null
+           && uriInfo.getTop() == null) {
+         sortInDefaultOrder(entitySet, data);
+       }
+ 
+       // TODO: Percent-encode "next" link.
+       nextLink = context.getPathInfo().getServiceRoot().relativize(context.getPathInfo().getRequestUri()).toString()
+           .replaceAll("\\$skiptoken=.+?&?", "")
+           .replaceAll("\\$skip=.+?&?", "")
+           .replaceFirst("(?:\\?|&)$", ""); // Remove potentially trailing "?" or "&" left over from remove actions
+                                            // above.
+       nextLink += (nextLink.contains("?") ? "&" : "?")
+           + "$skiptoken=" + getSkipToken(entitySet, data.get(SERVER_PAGING_SIZE));
+ 
+       while (data.size() > SERVER_PAGING_SIZE) {
+         data.remove(SERVER_PAGING_SIZE);
+       }
+     }
+ 
+     final EdmEntityType entityType = entitySet.getEntityType();
+     List<Map<String, Object>> values = new ArrayList<Map<String, Object>>();
+     for (final Object entryData : data) {
+       values.add(getStructuralTypeValueMap(entryData, entityType));
+     }
+ 
+     final EntityProviderWriteProperties feedProperties = EntityProviderWriteProperties
+         .serviceRoot(context.getPathInfo().getServiceRoot())
+         .inlineCountType(inlineCountType)
+         .inlineCount(count)
+         .expandSelectTree(UriParser.createExpandSelectTree(uriInfo.getSelect(), uriInfo.getExpand()))
+         .callbacks(getCallbacks(data, entityType))
+         .nextLink(nextLink)
+         .build();
+ 
+     final int timingHandle = context.startRuntimeMeasurement("EntityProvider", "writeFeed");
+     final ODataResponse response = EntityProvider.writeFeed(contentType, entitySet, values, feedProperties);
+ 
+     context.stopRuntimeMeasurement(timingHandle);
+ 
+     return ODataResponse.fromResponse(response).build();
+   }
+ 
+   @Override
+   public ODataResponse countEntitySet(final GetEntitySetCountUriInfo uriInfo, final String contentType)
+       throws ODataException {
+     ArrayList<Object> data = new ArrayList<Object>();
+     try {
+       data.addAll((List<?>) retrieveData(
+           uriInfo.getStartEntitySet(),
+           uriInfo.getKeyPredicates(),
+           uriInfo.getFunctionImport(),
+           mapFunctionParameters(uriInfo.getFunctionImportParameters()),
+           uriInfo.getNavigationSegments()));
+     } catch (final ODataNotFoundException e) {
+       data.clear();
+     }
+ 
+     applySystemQueryOptions(
+         uriInfo.getTargetEntitySet(),
+         data,
+         uriInfo.getFilter(),
+         null,
+         null,
+         null,
+         uriInfo.getSkip(),
+         uriInfo.getTop());
+ 
+     return ODataResponse.fromResponse(EntityProvider.writeText(String.valueOf(data.size()))).build();
+   }
+ 
+   @Override
+   public ODataResponse readEntityLinks(final GetEntitySetLinksUriInfo uriInfo, final String contentType)
+       throws ODataException {
+     ArrayList<Object> data = new ArrayList<Object>();
+     try {
+       data.addAll((List<?>) retrieveData(
+           uriInfo.getStartEntitySet(),
+           uriInfo.getKeyPredicates(),
+           uriInfo.getFunctionImport(),
+           mapFunctionParameters(uriInfo.getFunctionImportParameters()),
+           uriInfo.getNavigationSegments()));
+     } catch (final ODataNotFoundException e) {
+       data.clear();
+     }
+ 
+     final Integer count = applySystemQueryOptions(
+         uriInfo.getTargetEntitySet(),
+         data,
+         uriInfo.getFilter(),
+         uriInfo.getInlineCount(),
+         null, // uriInfo.getOrderBy(),
+         uriInfo.getSkipToken(),
+         uriInfo.getSkip(),
+         uriInfo.getTop());
+ 
+     final EdmEntitySet entitySet = uriInfo.getTargetEntitySet();
+ 
+     List<Map<String, Object>> values = new ArrayList<Map<String, Object>>();
+     for (final Object entryData : data) {
+       Map<String, Object> entryValues = new HashMap<String, Object>();
+       for (final EdmProperty property : entitySet.getEntityType().getKeyProperties()) {
+         entryValues.put(property.getName(), valueAccess.getPropertyValue(entryData, property));
+       }
+       values.add(entryValues);
+     }
+ 
+     ODataContext context = getContext();
+     final EntityProviderWriteProperties entryProperties = EntityProviderWriteProperties
+         .serviceRoot(context.getPathInfo().getServiceRoot())
+         .inlineCountType(uriInfo.getInlineCount())
+         .inlineCount(count)
+         .build();
+ 
+     final int timingHandle = context.startRuntimeMeasurement("EntityProvider", "writeLinks");
+ 
+     final ODataResponse response = EntityProvider.writeLinks(contentType, entitySet, values, entryProperties);
+ 
+     context.stopRuntimeMeasurement(timingHandle);
+ 
+     return ODataResponse.fromResponse(response).build();
+   }
+ 
+   @Override
+   public ODataResponse countEntityLinks(final GetEntitySetLinksCountUriInfo uriInfo, final String contentType)
+       throws ODataException {
+     return countEntitySet((GetEntitySetCountUriInfo) uriInfo, contentType);
+   }
+ 
+   @Override
+   public ODataResponse readEntity(final GetEntityUriInfo uriInfo, final String contentType) throws ODataException {
+     final Object data = retrieveData(
+         uriInfo.getStartEntitySet(),
+         uriInfo.getKeyPredicates(),
+         uriInfo.getFunctionImport(),
+         mapFunctionParameters(uriInfo.getFunctionImportParameters()),
+         uriInfo.getNavigationSegments());
+ 
+     if (!appliesFilter(data, uriInfo.getFilter())) {
+       throw new ODataNotFoundException(ODataNotFoundException.ENTITY);
+     }
+ 
+     final ExpandSelectTreeNode expandSelectTreeNode =
+         UriParser.createExpandSelectTree(uriInfo.getSelect(), uriInfo.getExpand());
+     ODataResponse odr =
+         ODataResponse.fromResponse(writeEntry(uriInfo.getTargetEntitySet(), expandSelectTreeNode, data, contentType))
+             .build();
+ 
+     return odr;
+   }
+ 
+   @Override
+   public ODataResponse existsEntity(final GetEntityCountUriInfo uriInfo, final String contentType)
+       throws ODataException {
+     final Object data = retrieveData(
+         uriInfo.getStartEntitySet(),
+         uriInfo.getKeyPredicates(),
+         uriInfo.getFunctionImport(),
+         mapFunctionParameters(uriInfo.getFunctionImportParameters()),
+         uriInfo.getNavigationSegments());
+ 
+     return ODataResponse.fromResponse(EntityProvider.writeText(appliesFilter(data, uriInfo.getFilter()) ? "1" : "0"))
+         .build();
+   }
+ 
+   @Override
+   public ODataResponse deleteEntity(final DeleteUriInfo uriInfo, final String contentType) throws ODataException {
+     dataSource.deleteData(
+         uriInfo.getStartEntitySet(),
+         mapKey(uriInfo.getKeyPredicates()));
+     return ODataResponse.newBuilder().build();
+   }
+ 
+   @Override
+   public ODataResponse createEntity(final PostUriInfo uriInfo, final InputStream content,
+       final String requestContentType, final String contentType) throws ODataException {
+     final EdmEntitySet entitySet = uriInfo.getTargetEntitySet();
+     final EdmEntityType entityType = entitySet.getEntityType();
+ 
+     Object data = dataSource.newDataObject(entitySet);
+     ExpandSelectTreeNode expandSelectTree = null;
+ 
+     if (entityType.hasStream()) {
+       dataSource.createData(entitySet, data);
+       dataSource.writeBinaryData(entitySet, data,
+           new BinaryData(EntityProvider.readBinary(content), requestContentType));
+ 
+     } else {
+       final EntityProviderReadProperties properties = EntityProviderReadProperties.init()
+           .mergeSemantic(false)
+           .addTypeMappings(getStructuralTypeTypeMap(data, entityType))
+           .build();
+       final ODataEntry entryValues = parseEntry(entitySet, content, requestContentType, properties);
+ 
+       setStructuralTypeValuesFromMap(data, entityType, entryValues.getProperties(), false);
+ 
+       dataSource.createData(entitySet, data);
+ 
+       createInlinedEntities(entitySet, data, entryValues);
+ 
+       expandSelectTree = entryValues.getExpandSelectTree();
+     }
+ 
+     // Link back to the entity the target entity set is related to, if any.
+     final List<NavigationSegment> navigationSegments = uriInfo.getNavigationSegments();
+     if (!navigationSegments.isEmpty()) {
+       final List<NavigationSegment> previousSegments = navigationSegments.subList(0, navigationSegments.size() - 1);
+       final Object sourceData = retrieveData(
+           uriInfo.getStartEntitySet(),
+           uriInfo.getKeyPredicates(),
+           uriInfo.getFunctionImport(),
+           mapFunctionParameters(uriInfo.getFunctionImportParameters()),
+           previousSegments);
+       final EdmEntitySet previousEntitySet = previousSegments.isEmpty() ?
+           uriInfo.getStartEntitySet() : previousSegments.get(previousSegments.size() - 1).getEntitySet();
+       dataSource.writeRelation(previousEntitySet, sourceData, entitySet, getStructuralTypeValueMap(data, entityType));
+     }
+ 
+     return ODataResponse.fromResponse(writeEntry(uriInfo.getTargetEntitySet(), expandSelectTree, data, contentType))
+         .eTag(constructETag(entitySet, data)).build();
+   }
+ 
+   @Override
+   public ODataResponse updateEntity(final PutMergePatchUriInfo uriInfo, final InputStream content,
+       final String requestContentType, final boolean merge, final String contentType) throws ODataException {
+     Object data = retrieveData(
+         uriInfo.getStartEntitySet(),
+         uriInfo.getKeyPredicates(),
+         uriInfo.getFunctionImport(),
+         mapFunctionParameters(uriInfo.getFunctionImportParameters()),
+         uriInfo.getNavigationSegments());
+ 
+     if (!appliesFilter(data, uriInfo.getFilter())) {
+       throw new ODataNotFoundException(ODataNotFoundException.ENTITY);
+     }
+ 
+     final EdmEntitySet entitySet = uriInfo.getTargetEntitySet();
+     final EdmEntityType entityType = entitySet.getEntityType();
+     final EntityProviderReadProperties properties = EntityProviderReadProperties.init()
+         .mergeSemantic(merge)
+         .addTypeMappings(getStructuralTypeTypeMap(data, entityType))
+         .build();
+     final ODataEntry entryValues = parseEntry(entitySet, content, requestContentType, properties);
+ 
+     setStructuralTypeValuesFromMap(data, entityType, entryValues.getProperties(), merge);
+ 
+     return ODataResponse.newBuilder().eTag(constructETag(entitySet, data)).build();
+   }
+ 
+   @Override
+   public ODataResponse readEntityLink(final GetEntityLinkUriInfo uriInfo, final String contentType)
+       throws ODataException {
+     final Object data = retrieveData(
+         uriInfo.getStartEntitySet(),
+         uriInfo.getKeyPredicates(),
+         uriInfo.getFunctionImport(),
+         mapFunctionParameters(uriInfo.getFunctionImportParameters()),
+         uriInfo.getNavigationSegments());
+ 
+     // if (!appliesFilter(data, uriInfo.getFilter()))
+     if (data == null) {
+       throw new ODataNotFoundException(ODataNotFoundException.ENTITY);
+     }
+ 
+     final EdmEntitySet entitySet = uriInfo.getTargetEntitySet();
+ 
+     Map<String, Object> values = new HashMap<String, Object>();
+     for (final EdmProperty property : entitySet.getEntityType().getKeyProperties()) {
+       values.put(property.getName(), valueAccess.getPropertyValue(data, property));
+     }
+ 
+     ODataContext context = getContext();
+     final EntityProviderWriteProperties entryProperties = EntityProviderWriteProperties
+         .serviceRoot(context.getPathInfo().getServiceRoot())
+         .build();
+ 
+     final int timingHandle = context.startRuntimeMeasurement("EntityProvider", "writeLink");
+ 
+     final ODataResponse response = EntityProvider.writeLink(contentType, entitySet, values, entryProperties);
+ 
+     context.stopRuntimeMeasurement(timingHandle);
+ 
+     return ODataResponse.fromResponse(response).build();
+   }
+ 
+   @Override
+   public ODataResponse existsEntityLink(final GetEntityLinkCountUriInfo uriInfo, final String contentType)
+       throws ODataException {
+     return existsEntity((GetEntityCountUriInfo) uriInfo, contentType);
+   }
+ 
+   @Override
+   public ODataResponse deleteEntityLink(final DeleteUriInfo uriInfo, final String contentType) throws ODataException {
+     final List<NavigationSegment> navigationSegments = uriInfo.getNavigationSegments();
+     final List<NavigationSegment> previousSegments = navigationSegments.subList(0, navigationSegments.size() - 1);
+ 
+     final Object sourceData = retrieveData(
+         uriInfo.getStartEntitySet(),
+         uriInfo.getKeyPredicates(),
+         uriInfo.getFunctionImport(),
+         mapFunctionParameters(uriInfo.getFunctionImportParameters()),
+         previousSegments);
+ 
+     final EdmEntitySet entitySet = previousSegments.isEmpty() ?
+         uriInfo.getStartEntitySet() : previousSegments.get(previousSegments.size() - 1).getEntitySet();
+     final EdmEntitySet targetEntitySet = uriInfo.getTargetEntitySet();
+     final Map<String, Object> keys = mapKey(uriInfo.getTargetKeyPredicates());
+ 
+     final Object targetData = dataSource.readRelatedData(entitySet, sourceData, targetEntitySet, keys);
+ 
+     // if (!appliesFilter(targetData, uriInfo.getFilter()))
+     if (targetData == null) {
+       throw new ODataNotFoundException(ODataNotFoundException.ENTITY);
+     }
+ 
+     dataSource.deleteRelation(entitySet, sourceData, targetEntitySet, keys);
+ 
+     return ODataResponse.newBuilder().build();
+   }
+ 
+   @Override
+   public ODataResponse createEntityLink(final PostUriInfo uriInfo, final InputStream content,
+       final String requestContentType, final String contentType) throws ODataException {
+     final List<NavigationSegment> navigationSegments = uriInfo.getNavigationSegments();
+     final List<NavigationSegment> previousSegments = navigationSegments.subList(0, navigationSegments.size() - 1);
+ 
+     final Object sourceData = retrieveData(
+         uriInfo.getStartEntitySet(),
+         uriInfo.getKeyPredicates(),
+         uriInfo.getFunctionImport(),
+         mapFunctionParameters(uriInfo.getFunctionImportParameters()),
+         previousSegments);
+ 
+     final EdmEntitySet entitySet = previousSegments.isEmpty() ?
+         uriInfo.getStartEntitySet() : previousSegments.get(previousSegments.size() - 1).getEntitySet();
+     final EdmEntitySet targetEntitySet = uriInfo.getTargetEntitySet();
+ 
+     final Map<String, Object> targetKeys = parseLink(targetEntitySet, content, requestContentType);
+ 
+     dataSource.writeRelation(entitySet, sourceData, targetEntitySet, targetKeys);
+ 
+     return ODataResponse.newBuilder().build();
+   }
+ 
+   @Override
+   public ODataResponse updateEntityLink(final PutMergePatchUriInfo uriInfo, final InputStream content,
+       final String requestContentType, final String contentType) throws ODataException {
+     final List<NavigationSegment> navigationSegments = uriInfo.getNavigationSegments();
+     final List<NavigationSegment> previousSegments = navigationSegments.subList(0, navigationSegments.size() - 1);
+ 
+     final Object sourceData = retrieveData(
+         uriInfo.getStartEntitySet(),
+         uriInfo.getKeyPredicates(),
+         uriInfo.getFunctionImport(),
+         mapFunctionParameters(uriInfo.getFunctionImportParameters()),
+         previousSegments);
+ 
+     final EdmEntitySet entitySet = previousSegments.isEmpty() ?
+         uriInfo.getStartEntitySet() : previousSegments.get(previousSegments.size() - 1).getEntitySet();
+     final EdmEntitySet targetEntitySet = uriInfo.getTargetEntitySet();
+     final Map<String, Object> keys = mapKey(uriInfo.getTargetKeyPredicates());
+ 
+     final Object targetData = dataSource.readRelatedData(entitySet, sourceData, targetEntitySet, keys);
+ 
+     if (!appliesFilter(targetData, uriInfo.getFilter())) {
+       throw new ODataNotFoundException(ODataNotFoundException.ENTITY);
+     }
+ 
+     dataSource.deleteRelation(entitySet, sourceData, targetEntitySet, keys);
+ 
+     final Map<String, Object> newKeys = parseLink(targetEntitySet, content, requestContentType);
+ 
+     dataSource.writeRelation(entitySet, sourceData, targetEntitySet, newKeys);
+ 
+     return ODataResponse.newBuilder().build();
+   }
+ 
+   @Override
+   public ODataResponse readEntityComplexProperty(final GetComplexPropertyUriInfo uriInfo, final String contentType)
+       throws ODataException {
+     Object data = retrieveData(
+         uriInfo.getStartEntitySet(),
+         uriInfo.getKeyPredicates(),
+         uriInfo.getFunctionImport(),
+         mapFunctionParameters(uriInfo.getFunctionImportParameters()),
+         uriInfo.getNavigationSegments());
+ 
+     // if (!appliesFilter(data, uriInfo.getFilter()))
+     if (data == null) {
+       throw new ODataNotFoundException(ODataNotFoundException.ENTITY);
+     }
+ 
+     final List<EdmProperty> propertyPath = uriInfo.getPropertyPath();
+     final EdmProperty property = propertyPath.get(propertyPath.size() - 1);
+     final Object value = property.isSimple() ?
+         property.getMapping() == null || property.getMapping().getMimeType() == null ?
+             getPropertyValue(data, propertyPath) : getSimpleTypeValueMap(data, propertyPath) :
+         getStructuralTypeValueMap(getPropertyValue(data, propertyPath), (EdmStructuralType) property.getType());
+ 
+     ODataContext context = getContext();
+     final int timingHandle = context.startRuntimeMeasurement("EntityProvider", "writeProperty");
+ 
+     final ODataResponse response = EntityProvider.writeProperty(contentType, property, value);
+ 
+     context.stopRuntimeMeasurement(timingHandle);
+ 
+     return ODataResponse.fromResponse(response).eTag(constructETag(uriInfo.getTargetEntitySet(), data)).build();
+   }
+ 
+   @Override
+   public ODataResponse readEntitySimpleProperty(final GetSimplePropertyUriInfo uriInfo, final String contentType)
+       throws ODataException {
+     return readEntityComplexProperty((GetComplexPropertyUriInfo) uriInfo, contentType);
+   }
+ 
+   @Override
+   public ODataResponse readEntitySimplePropertyValue(final GetSimplePropertyUriInfo uriInfo, final String contentType)
+       throws ODataException {
+     Object data = retrieveData(
+         uriInfo.getStartEntitySet(),
+         uriInfo.getKeyPredicates(),
+         uriInfo.getFunctionImport(),
+         mapFunctionParameters(uriInfo.getFunctionImportParameters()),
+         uriInfo.getNavigationSegments());
+ 
+     // if (!appliesFilter(data, uriInfo.getFilter()))
+     if (data == null) {
+       throw new ODataNotFoundException(ODataNotFoundException.ENTITY);
+     }
+ 
+     final List<EdmProperty> propertyPath = uriInfo.getPropertyPath();
+     final EdmProperty property = propertyPath.get(propertyPath.size() - 1);
+     final Object value = property.getMapping() == null || property.getMapping().getMimeType() == null ?
+         getPropertyValue(data, propertyPath) : getSimpleTypeValueMap(data, propertyPath);
+ 
+     return ODataResponse.fromResponse(EntityProvider.writePropertyValue(property, value)).eTag(
+         constructETag(uriInfo.getTargetEntitySet(), data)).build();
+   }
+ 
+   @Override
+   public ODataResponse deleteEntitySimplePropertyValue(final DeleteUriInfo uriInfo, final String contentType)
+       throws ODataException {
+     Object data = retrieveData(
+         uriInfo.getStartEntitySet(),
+         uriInfo.getKeyPredicates(),
+         uriInfo.getFunctionImport(),
+         mapFunctionParameters(uriInfo.getFunctionImportParameters()),
+         uriInfo.getNavigationSegments());
+ 
+     if (data == null) {
+       throw new ODataNotFoundException(ODataNotFoundException.ENTITY);
+     }
+ 
+     final List<EdmProperty> propertyPath = uriInfo.getPropertyPath();
+     final EdmProperty property = propertyPath.get(propertyPath.size() - 1);
+ 
+     data = getPropertyValue(data, propertyPath.subList(0, propertyPath.size() - 1));
+     valueAccess.setPropertyValue(data, property, null);
+     valueAccess.setMappingValue(data, property.getMapping(), null);
+ 
+     return ODataResponse.newBuilder().build();
+   }
+ 
+   @Override
+   public ODataResponse updateEntityComplexProperty(final PutMergePatchUriInfo uriInfo, final InputStream content,
+       final String requestContentType, final boolean merge, final String contentType) throws ODataException {
+     Object data = retrieveData(
+         uriInfo.getStartEntitySet(),
+         uriInfo.getKeyPredicates(),
+         uriInfo.getFunctionImport(),
+         mapFunctionParameters(uriInfo.getFunctionImportParameters()),
+         uriInfo.getNavigationSegments());
+ 
+     if (!appliesFilter(data, uriInfo.getFilter())) {
+       throw new ODataNotFoundException(ODataNotFoundException.ENTITY);
+     }
+ 
+     final List<EdmProperty> propertyPath = uriInfo.getPropertyPath();
+     final EdmProperty property = propertyPath.get(propertyPath.size() - 1);
+ 
+     data = getPropertyValue(data, propertyPath.subList(0, propertyPath.size() - 1));
+ 
+     ODataContext context = getContext();
+     int timingHandle = context.startRuntimeMeasurement("EntityConsumer", "readProperty");
+ 
+     Map<String, Object> values;
+     try {
+       values =
+           EntityProvider.readProperty(requestContentType, property, content, EntityProviderReadProperties.init()
+               .mergeSemantic(merge).build());
+     } catch (final EntityProviderException e) {
+       throw new ODataBadRequestException(ODataBadRequestException.BODY, e);
+     }
+ 
+     context.stopRuntimeMeasurement(timingHandle);
+ 
+     final Object value = values.get(property.getName());
+     if (property.isSimple()) {
+       valueAccess.setPropertyValue(data, property, value);
+     } else {
+       @SuppressWarnings("unchecked")
+       final Map<String, Object> propertyValue = (Map<String, Object>) value;
+       setStructuralTypeValuesFromMap(valueAccess.getPropertyValue(data, property),
+           (EdmStructuralType) property.getType(), propertyValue, merge);
+     }
+ 
+     return ODataResponse.newBuilder().eTag(constructETag(uriInfo.getTargetEntitySet(), data)).build();
+   }
+ 
+   @Override
+   public ODataResponse updateEntitySimpleProperty(final PutMergePatchUriInfo uriInfo, final InputStream content,
+       final String requestContentType, final String contentType) throws ODataException {
+     return updateEntityComplexProperty(uriInfo, content, requestContentType, false, contentType);
+   }
+ 
+   @Override
+   public ODataResponse updateEntitySimplePropertyValue(final PutMergePatchUriInfo uriInfo, final InputStream content,
+       final String requestContentType, final String contentType) throws ODataException {
+     Object data = retrieveData(
+         uriInfo.getStartEntitySet(),
+         uriInfo.getKeyPredicates(),
+         uriInfo.getFunctionImport(),
+         mapFunctionParameters(uriInfo.getFunctionImportParameters()),
+         uriInfo.getNavigationSegments());
+ 
+     if (!appliesFilter(data, uriInfo.getFilter())) {
+       throw new ODataNotFoundException(ODataNotFoundException.ENTITY);
+     }
+ 
+     final List<EdmProperty> propertyPath = uriInfo.getPropertyPath();
+     final EdmProperty property = propertyPath.get(propertyPath.size() - 1);
+ 
+     data = getPropertyValue(data, propertyPath.subList(0, propertyPath.size() - 1));
+ 
+     ODataContext context = getContext();
+     int timingHandle = context.startRuntimeMeasurement("EntityConsumer", "readPropertyValue");
+ 
+     Object value;
+     try {
+       value = EntityProvider.readPropertyValue(property, content);
+     } catch (final EntityProviderException e) {
+       throw new ODataBadRequestException(ODataBadRequestException.BODY, e);
+     }
+ 
+     context.stopRuntimeMeasurement(timingHandle);
+ 
+     valueAccess.setPropertyValue(data, property, value);
+     valueAccess.setMappingValue(data, property.getMapping(), requestContentType);
+ 
+     return ODataResponse.newBuilder().eTag(constructETag(uriInfo.getTargetEntitySet(), data)).build();
+   }
+ 
+   @Override
+   public ODataResponse readEntityMedia(final GetMediaResourceUriInfo uriInfo, final String contentType)
+       throws ODataException {
+     final Object data = retrieveData(
+         uriInfo.getStartEntitySet(),
+         uriInfo.getKeyPredicates(),
+         uriInfo.getFunctionImport(),
+         mapFunctionParameters(uriInfo.getFunctionImportParameters()),
+         uriInfo.getNavigationSegments());
+ 
+     if (!appliesFilter(data, uriInfo.getFilter())) {
+       throw new ODataNotFoundException(ODataNotFoundException.ENTITY);
+     }
+ 
+     final EdmEntitySet entitySet = uriInfo.getTargetEntitySet();
+     final BinaryData binaryData = dataSource.readBinaryData(entitySet, data);
+     if (binaryData == null) {
+       throw new ODataNotFoundException(ODataNotFoundException.ENTITY);
+     }
+ 
+     final String mimeType = binaryData.getMimeType() == null ?
+         HttpContentType.APPLICATION_OCTET_STREAM : binaryData.getMimeType();
+ 
+     return ODataResponse.fromResponse(EntityProvider.writeBinary(mimeType, binaryData.getData())).eTag(
+         constructETag(entitySet, data)).build();
+   }
+ 
+   @Override
+   public ODataResponse deleteEntityMedia(final DeleteUriInfo uriInfo, final String contentType) throws ODataException {
+     final Object data = retrieveData(
+         uriInfo.getStartEntitySet(),
+         uriInfo.getKeyPredicates(),
+         uriInfo.getFunctionImport(),
+         mapFunctionParameters(uriInfo.getFunctionImportParameters()),
+         uriInfo.getNavigationSegments());
+ 
+     if (data == null) {
+       throw new ODataNotFoundException(ODataNotFoundException.ENTITY);
+     }
+ 
+     dataSource.writeBinaryData(uriInfo.getTargetEntitySet(), data, new BinaryData(null, null));
+ 
+     return ODataResponse.newBuilder().build();
+   }
+ 
+   @Override
+   public ODataResponse updateEntityMedia(final PutMergePatchUriInfo uriInfo, final InputStream content,
+       final String requestContentType, final String contentType) throws ODataException {
+     final Object data = retrieveData(
+         uriInfo.getStartEntitySet(),
+         uriInfo.getKeyPredicates(),
+         uriInfo.getFunctionImport(),
+         mapFunctionParameters(uriInfo.getFunctionImportParameters()),
+         uriInfo.getNavigationSegments());
+ 
+     if (!appliesFilter(data, uriInfo.getFilter())) {
+       throw new ODataNotFoundException(ODataNotFoundException.ENTITY);
+     }
+ 
+     ODataContext context = getContext();
+     final int timingHandle = context.startRuntimeMeasurement("EntityProvider", "readBinary");
+ 
+     final byte[] value = EntityProvider.readBinary(content);
+ 
+     context.stopRuntimeMeasurement(timingHandle);
+ 
+     final EdmEntitySet entitySet = uriInfo.getTargetEntitySet();
+     dataSource.writeBinaryData(entitySet, data, new BinaryData(value, requestContentType));
+ 
+     return ODataResponse.newBuilder().eTag(constructETag(entitySet, data)).build();
+   }
+ 
+   @Override
+   public ODataResponse executeFunctionImport(final GetFunctionImportUriInfo uriInfo, final String contentType)
+       throws ODataException {
+     final EdmFunctionImport functionImport = uriInfo.getFunctionImport();
+     final EdmType type = functionImport.getReturnType().getType();
+ 
+     final Object data = dataSource.readData(
+         functionImport,
+         mapFunctionParameters(uriInfo.getFunctionImportParameters()),
+         null);
+ 
+     if (data == null) {
+       throw new ODataNotFoundException(ODataHttpException.COMMON);
+     }
+ 
+     Object value;
+     if (type.getKind() == EdmTypeKind.SIMPLE) {
+       value = type == EdmSimpleTypeKind.Binary.getEdmSimpleTypeInstance() ?
+           ((BinaryData) data).getData() : data;
+     } else if (functionImport.getReturnType().getMultiplicity() == EdmMultiplicity.MANY) {
+       List<Map<String, Object>> values = new ArrayList<Map<String, Object>>();
+       for (final Object typeData : (List<?>) data) {
+         values.add(getStructuralTypeValueMap(typeData, (EdmStructuralType) type));
+       }
+       value = values;
+     } else {
+       value = getStructuralTypeValueMap(data, (EdmStructuralType) type);
+     }
+ 
+     ODataContext context = getContext();
+ 
+     final EntityProviderWriteProperties entryProperties = EntityProviderWriteProperties
+         .serviceRoot(context.getPathInfo().getServiceRoot()).build();
+ 
+     final int timingHandle = context.startRuntimeMeasurement("EntityProvider", "writeFunctionImport");
+ 
+     final ODataResponse response =
+         EntityProvider.writeFunctionImport(contentType, functionImport, value, entryProperties);
+ 
+     context.stopRuntimeMeasurement(timingHandle);
+ 
+     return ODataResponse.fromResponse(response).build();
+   }
+ 
+   @Override
+   public ODataResponse executeFunctionImportValue(final GetFunctionImportUriInfo uriInfo, final String contentType)
+       throws ODataException {
+     final EdmFunctionImport functionImport = uriInfo.getFunctionImport();
+     final EdmSimpleType type = (EdmSimpleType) functionImport.getReturnType().getType();
+ 
+     final Object data = dataSource.readData(
+         functionImport,
+         mapFunctionParameters(uriInfo.getFunctionImportParameters()),
+         null);
+ 
+     if (data == null) {
+       throw new ODataNotFoundException(ODataHttpException.COMMON);
+     }
+ 
+     ODataResponse response;
+     if (type == EdmSimpleTypeKind.Binary.getEdmSimpleTypeInstance()) {
+       response = EntityProvider.writeBinary(((BinaryData) data).getMimeType(), ((BinaryData) data).getData());
+     } else {
+       final String value = type.valueToString(data, EdmLiteralKind.DEFAULT, null);
+       response = EntityProvider.writeText(value == null ? "" : value);
+     }
+     return ODataResponse.fromResponse(response).build();
+   }
+ 
+   private static Map<String, Object> mapKey(final List<KeyPredicate> keys) throws EdmException {
+     Map<String, Object> keyMap = new HashMap<String, Object>();
+     for (final KeyPredicate key : keys) {
+       final EdmProperty property = key.getProperty();
+       final EdmSimpleType type = (EdmSimpleType) property.getType();
+       keyMap.put(property.getName(), type.valueOfString(key.getLiteral(), EdmLiteralKind.DEFAULT, property.getFacets(),
+           type.getDefaultType()));
+     }
+     return keyMap;
+   }
+ 
+   private static Map<String, Object> mapFunctionParameters(final Map<String, EdmLiteral> functionImportParameters)
+       throws EdmSimpleTypeException {
+     if (functionImportParameters == null) {
+       return Collections.emptyMap();
+     } else {
+       Map<String, Object> parameterMap = new HashMap<String, Object>();
+       for (final String parameterName : functionImportParameters.keySet()) {
+         final EdmLiteral literal = functionImportParameters.get(parameterName);
+         final EdmSimpleType type = literal.getType();
+         parameterMap.put(parameterName, type.valueOfString(literal.getLiteral(), EdmLiteralKind.DEFAULT, null, type
+             .getDefaultType()));
+       }
+       return parameterMap;
+     }
+   }
+ 
+   private Object retrieveData(final EdmEntitySet startEntitySet, final List<KeyPredicate> keyPredicates,
+       final EdmFunctionImport functionImport, final Map<String, Object> functionImportParameters,
+       final List<NavigationSegment> navigationSegments) throws ODataException {
+     Object data;
+     final Map<String, Object> keys = mapKey(keyPredicates);
+ 
+     ODataContext context = getContext();
+     final int timingHandle = context.startRuntimeMeasurement(getClass().getSimpleName(), "retrieveData");
+ 
+     try {
+       data = functionImport == null ?
+           keys.isEmpty() ?
+               dataSource.readData(startEntitySet) : dataSource.readData(startEntitySet, keys) :
+           dataSource.readData(functionImport, functionImportParameters, keys);
+   
+       EdmEntitySet currentEntitySet =
+           functionImport == null ? startEntitySet : functionImport.getEntitySet();
+       for (NavigationSegment navigationSegment : navigationSegments) {
+         data = dataSource.readRelatedData(
+             currentEntitySet,
+             data,
+             navigationSegment.getEntitySet(),
+             mapKey(navigationSegment.getKeyPredicates()));
+         currentEntitySet = navigationSegment.getEntitySet();
+       }
+     } finally {
+       context.stopRuntimeMeasurement(timingHandle);
+     }
+     return data;
+   }
+ 
+   private <T> String constructETag(final EdmEntitySet entitySet, final T data) throws ODataException {
+     final EdmEntityType entityType = entitySet.getEntityType();
+     String eTag = null;
+     for (final String propertyName : entityType.getPropertyNames()) {
+       final EdmProperty property = (EdmProperty) entityType.getProperty(propertyName);
+       if (property.getFacets() != null && property.getFacets().getConcurrencyMode() == EdmConcurrencyMode.Fixed) {
+         final EdmSimpleType type = (EdmSimpleType) property.getType();
+         final String component = type.valueToString(valueAccess.getPropertyValue(data, property),
+             EdmLiteralKind.DEFAULT, property.getFacets());
+         eTag = eTag == null ? component : eTag + Edm.DELIMITER + component;
+       }
+     }
+     return eTag == null ? null : "W/\"" + eTag + "\"";
+   }
+ 
+   private <T> Map<String, ODataCallback> getCallbacks(final T data, final EdmEntityType entityType)
+       throws EdmException {
+     final List<String> navigationPropertyNames = entityType.getNavigationPropertyNames();
+     if (navigationPropertyNames.isEmpty()) {
+       return null;
+     } else {
+       final WriteCallback callback = new WriteCallback(data);
+       Map<String, ODataCallback> callbacks = new HashMap<String, ODataCallback>();
+       for (final String name : navigationPropertyNames) {
+         callbacks.put(name, callback);
+       }
+       return callbacks;
+     }
+   }
+ 
+   private class WriteCallback implements OnWriteEntryContent, OnWriteFeedContent {
+     private final Object data;
+ 
+     private <T> WriteCallback(final T data) {
+       this.data = data;
+     }
+ 
+     @Override
+     public WriteFeedCallbackResult retrieveFeedResult(final WriteFeedCallbackContext context)
+         throws ODataApplicationException {
+       try {
+         final EdmEntityType entityType =
+             context.getSourceEntitySet().getRelatedEntitySet(context.getNavigationProperty()).getEntityType();
+         List<Map<String, Object>> values = new ArrayList<Map<String, Object>>();
+         Object relatedData = null;
+         try {
+           relatedData = readRelatedData(context);
+           for (final Object entryData : (List<?>) relatedData) {
+             values.add(getStructuralTypeValueMap(entryData, entityType));
+           }
+         } catch (final ODataNotFoundException e) {
+           values.clear();
+         }
+         WriteFeedCallbackResult result = new WriteFeedCallbackResult();
+         result.setFeedData(values);
+         EntityProviderWriteProperties inlineProperties =
+             EntityProviderWriteProperties.serviceRoot(getContext().getPathInfo().getServiceRoot()).callbacks(
+                 getCallbacks(relatedData, entityType)).expandSelectTree(context.getCurrentExpandSelectTreeNode())
+                 .selfLink(context.getSelfLink()).build();
+         result.setInlineProperties(inlineProperties);
+         return result;
+       } catch (final ODataException e) {
+         throw new ODataApplicationException(e.getLocalizedMessage(), Locale.ROOT, e);
+       }
+     }
+ 
+     @Override
+     public WriteEntryCallbackResult retrieveEntryResult(final WriteEntryCallbackContext context)
+         throws ODataApplicationException {
+       try {
+         final EdmEntityType entityType =
+             context.getSourceEntitySet().getRelatedEntitySet(context.getNavigationProperty()).getEntityType();
+         WriteEntryCallbackResult result = new WriteEntryCallbackResult();
+         Object relatedData;
+         try {
+           relatedData = readRelatedData(context);
+         } catch (final ODataNotFoundException e) {
+           relatedData = null;
+         }
+ 
+         if (relatedData == null) {
+           result.setEntryData(Collections.<String, Object> emptyMap());
+         } else {
+           result.setEntryData(getStructuralTypeValueMap(relatedData, entityType));
+ 
+           EntityProviderWriteProperties inlineProperties =
+               EntityProviderWriteProperties.serviceRoot(getContext().getPathInfo().getServiceRoot()).callbacks(
+                   getCallbacks(relatedData, entityType)).expandSelectTree(context.getCurrentExpandSelectTreeNode())
+                   .build();
+           result.setInlineProperties(inlineProperties);
+         }
+         return result;
+       } catch (final ODataException e) {
+         throw new ODataApplicationException(e.getLocalizedMessage(), Locale.ROOT, e);
+       }
+     }
+ 
+     private Object readRelatedData(final WriteCallbackContext context) throws ODataException {
+       final EdmEntitySet entitySet = context.getSourceEntitySet();
+       return dataSource.readRelatedData(
+           entitySet,
+           data instanceof List ? readEntryData((List<?>) data, entitySet.getEntityType(), context
+               .extractKeyFromEntryData()) : data,
+           entitySet.getRelatedEntitySet(context.getNavigationProperty()),
+           Collections.<String, Object> emptyMap());
+     }
+ 
+     private <T> T readEntryData(final List<T> data, final EdmEntityType entityType, final Map<String, Object> key)
+         throws ODataException {
+       for (final T entryData : data) {
+         boolean found = true;
+         for (final EdmProperty keyProperty : entityType.getKeyProperties()) {
+           if (!valueAccess.getPropertyValue(entryData, keyProperty).equals(key.get(keyProperty.getName()))) {
+             found = false;
+             break;
+           }
+         }
+         if (found) {
+           return entryData;
+         }
+       }
+       return null;
+     }
+   }
+ 
+   private <T> ODataResponse writeEntry(final EdmEntitySet entitySet, final ExpandSelectTreeNode expandSelectTree,
+       final T data, final String contentType) throws ODataException, EntityProviderException {
+     final EdmEntityType entityType = entitySet.getEntityType();
+     final Map<String, Object> values = getStructuralTypeValueMap(data, entityType);
+ 
+     ODataContext context = getContext();
+     EntityProviderWriteProperties writeProperties = EntityProviderWriteProperties
+         .serviceRoot(context.getPathInfo().getServiceRoot())
+         .expandSelectTree(expandSelectTree)
+         .callbacks(getCallbacks(data, entityType))
+         .build();
+ 
+     final int timingHandle = context.startRuntimeMeasurement("EntityProvider", "writeEntry");
+ 
+     final ODataResponse response = EntityProvider.writeEntry(contentType, entitySet, values, writeProperties);
+ 
+     context.stopRuntimeMeasurement(timingHandle);
+ 
+     return response;
+   }
+ 
+   private ODataEntry parseEntry(final EdmEntitySet entitySet, final InputStream content,
+       final String requestContentType, final EntityProviderReadProperties properties) throws ODataBadRequestException {
+     ODataContext context = getContext();
+     final int timingHandle = context.startRuntimeMeasurement("EntityConsumer", "readEntry");
+ 
+     ODataEntry entryValues;
+     try {
+       entryValues = EntityProvider.readEntry(requestContentType, entitySet, content, properties);
+     } catch (final EntityProviderException e) {
+       throw new ODataBadRequestException(ODataBadRequestException.BODY, e);
+     }
+ 
+     context.stopRuntimeMeasurement(timingHandle);
+ 
+     return entryValues;
+   }
+ 
+   private Map<String, Object> parseLink(final EdmEntitySet entitySet, final InputStream content,
+       final String contentType) throws ODataException {
+     ODataContext context = getContext();
+     final int timingHandle = context.startRuntimeMeasurement("EntityProvider", "readLink");
+ 
+     final String uriString = EntityProvider.readLink(contentType, entitySet, content);
+ 
+     context.stopRuntimeMeasurement(timingHandle);
+ 
+     final Map<String, Object> targetKeys = parseLinkUri(entitySet, uriString);
+     if (targetKeys == null) {
+       throw new ODataBadRequestException(ODataBadRequestException.BODY);
+     }
+     return targetKeys;
+   }
+ 
+   private Map<String, Object> parseLinkUri(final EdmEntitySet targetEntitySet, final String uriString)
+       throws EdmException {
+     ODataContext context = getContext();
+     final int timingHandle = context.startRuntimeMeasurement("UriParser", "getKeyPredicatesFromEntityLink");
+ 
+     List<KeyPredicate> key = null;
+     try {
+       key = UriParser.getKeyPredicatesFromEntityLink(targetEntitySet, uriString,
+           context.getPathInfo().getServiceRoot());
+     } catch (ODataException e) {
+       // We don't understand the link target. This could also be seen as an error.
+     }
+ 
+     context.stopRuntimeMeasurement(timingHandle);
+ 
+     return key == null ? null : mapKey(key);
+   }
+ 
+   private <T> void createInlinedEntities(final EdmEntitySet entitySet, final T data, final ODataEntry entryValues)
+       throws ODataException {
+     final EdmEntityType entityType = entitySet.getEntityType();
+     for (final String navigationPropertyName : entityType.getNavigationPropertyNames()) {
+ 
+       final EdmNavigationProperty navigationProperty =
+           (EdmNavigationProperty) entityType.getProperty(navigationPropertyName);
+       final EdmEntitySet relatedEntitySet = entitySet.getRelatedEntitySet(navigationProperty);
+       final EdmEntityType relatedEntityType = relatedEntitySet.getEntityType();
+ 
+       final Object relatedValue = entryValues.getProperties().get(navigationPropertyName);
+       if (relatedValue == null) {
+         for (final String uriString : entryValues.getMetadata().getAssociationUris(navigationPropertyName)) {
+           final Map<String, Object> key = parseLinkUri(relatedEntitySet, uriString);
+           if (key != null) {
+             dataSource.writeRelation(entitySet, data, relatedEntitySet, key);
+           }
+         }
+ 
+       } else {
+         if (relatedValue instanceof ODataFeed) {
+           ODataFeed feed = (ODataFeed) relatedValue;
+           final List<ODataEntry> relatedValueList = feed.getEntries();
+           for (final ODataEntry relatedValues : relatedValueList) {
+             Object relatedData = dataSource.newDataObject(relatedEntitySet);
+             setStructuralTypeValuesFromMap(relatedData, relatedEntityType, relatedValues.getProperties(), false);
+             dataSource.createData(relatedEntitySet, relatedData);
+             dataSource.writeRelation(entitySet, data, relatedEntitySet, getStructuralTypeValueMap(relatedData,
+                 relatedEntityType));
+             createInlinedEntities(relatedEntitySet, relatedData, relatedValues);
+           }
+         } else if (relatedValue instanceof ODataEntry) {
+           final ODataEntry relatedValueEntry = (ODataEntry) relatedValue;
+           Object relatedData = dataSource.newDataObject(relatedEntitySet);
+           setStructuralTypeValuesFromMap(relatedData, relatedEntityType, relatedValueEntry.getProperties(), false);
+           dataSource.createData(relatedEntitySet, relatedData);
+           dataSource.writeRelation(entitySet, data, relatedEntitySet, getStructuralTypeValueMap(relatedData,
+               relatedEntityType));
+           createInlinedEntities(relatedEntitySet, relatedData, relatedValueEntry);
+         } else {
+           throw new ODataException("Unexpected class for a related value: " + relatedValue.getClass().getSimpleName());
+         }
+ 
+       }
+     }
+   }
+ 
+   private <T> Integer applySystemQueryOptions(final EdmEntitySet entitySet, final List<T> data,
+       final FilterExpression filter, final InlineCount inlineCount, final OrderByExpression orderBy,
+       final String skipToken, final Integer skip, final Integer top) throws ODataException {
+     ODataContext context = getContext();
+     final int timingHandle = context.startRuntimeMeasurement(getClass().getSimpleName(), "applySystemQueryOptions");
+ 
+     if (filter != null) {
+       // Remove all elements the filter does not apply for.
+       // A for-each loop would not work with "remove", see Java documentation.
+       for (Iterator<T> iterator = data.iterator(); iterator.hasNext();) {
+         if (!appliesFilter(iterator.next(), filter)) {
+           iterator.remove();
+         }
+       }
+     }
+ 
+     final Integer count = inlineCount == InlineCount.ALLPAGES ? data.size() : null;
+ 
+     if (orderBy != null) {
+       sort(data, orderBy);
+     } else if (skipToken != null || skip != null || top != null) {
+       sortInDefaultOrder(entitySet, data);
+     }
+ 
+     if (skipToken != null) {
+       while (!data.isEmpty() && !getSkipToken(entitySet, data.get(0)).equals(skipToken)) {
+         data.remove(0);
+       }
+     }
+ 
+     if (skip != null) {
+       if (skip >= data.size()) {
+         data.clear();
+       } else {
+         for (int i = 0; i < skip; i++) {
+           data.remove(0);
+         }
+       }
+     }
+ 
+     if (top != null) {
+       while (data.size() > top) {
+         data.remove(top.intValue());
+       }
+     }
+ 
+     context.stopRuntimeMeasurement(timingHandle);
+ 
+     return count;
+   }
+ 
+   private <T> void sort(final List<T> data, final OrderByExpression orderBy) {
+     Collections.sort(data, new Comparator<T>() {
+       @Override
+       public int compare(final T entity1, final T entity2) {
+         try {
+           int result = 0;
+           for (final OrderExpression expression : orderBy.getOrders()) {
+             String first = evaluateExpression(entity1, expression.getExpression());
+             String second = evaluateExpression(entity2, expression.getExpression());
+ 
+             if (first != null && second != null) {
+               result = first.compareTo(second);
+             } else if (first == null && second != null) {
+               result = 1;
+             } else if (first != null && second == null) {
+               result = -1;
+             }
+ 
+             if (expression.getSortOrder() == SortOrder.desc) {
+               result = -result;
+             }
+ 
+             if (result != 0) {
+               break;
+             }
+           }
+           return result;
+         } catch (final ODataException e) {
+           return 0;
+         }
+       }
+     });
+   }
+ 
+   private <T> void sortInDefaultOrder(final EdmEntitySet entitySet, final List<T> data) {
+     Collections.sort(data, new Comparator<T>() {
+       @Override
+       public int compare(final T entity1, final T entity2) {
+         try {
+           return getSkipToken(entitySet, entity1).compareTo(getSkipToken(entitySet, entity2));
+         } catch (final ODataException e) {
+           return 0;
+         }
+       }
+     });
+   }
+ 
+   private <T> boolean appliesFilter(final T data, final FilterExpression filter) throws ODataException {
+     ODataContext context = getContext();
+     final int timingHandle = context.startRuntimeMeasurement(getClass().getSimpleName(), "appliesFilter");
+ 
+     try {
+       return data != null && (filter == null || evaluateExpression(data, filter.getExpression()).equals("true"));
+     } catch (final RuntimeException e) {
+       return false;
+     } finally {
+       context.stopRuntimeMeasurement(timingHandle);
+     }
+   }
+ 
+   private <T> String evaluateExpression(final T data, final CommonExpression expression) throws ODataException {
+     switch (expression.getKind()) {
+     case UNARY:
+       final UnaryExpression unaryExpression = (UnaryExpression) expression;
+       final String operand = evaluateExpression(data, unaryExpression.getOperand());
+ 
+       switch (unaryExpression.getOperator()) {
+       case NOT:
+         return Boolean.toString(!Boolean.parseBoolean(operand));
+       case MINUS:
+         return operand.startsWith("-") ? operand.substring(1) : "-" + operand;
+       default:
+         throw new ODataNotImplementedException();
+       }
+ 
+     case BINARY:
+       final BinaryExpression binaryExpression = (BinaryExpression) expression;
+       final EdmSimpleType type = (EdmSimpleType) binaryExpression.getLeftOperand().getEdmType();
+       final String left = evaluateExpression(data, binaryExpression.getLeftOperand());
+       final String right = evaluateExpression(data, binaryExpression.getRightOperand());
+ 
+       switch (binaryExpression.getOperator()) {
+       case ADD:
+         if (binaryExpression.getEdmType() == EdmSimpleTypeKind.Decimal.getEdmSimpleTypeInstance()
+             || binaryExpression.getEdmType() == EdmSimpleTypeKind.Double.getEdmSimpleTypeInstance()
+             || binaryExpression.getEdmType() == EdmSimpleTypeKind.Single.getEdmSimpleTypeInstance()) {
+           return Double.toString(Double.valueOf(left) + Double.valueOf(right));
+         } else {
+           return Long.toString(Long.valueOf(left) + Long.valueOf(right));
+         }
+       case SUB:
+         if (binaryExpression.getEdmType() == EdmSimpleTypeKind.Decimal.getEdmSimpleTypeInstance()
+             || binaryExpression.getEdmType() == EdmSimpleTypeKind.Double.getEdmSimpleTypeInstance()
+             || binaryExpression.getEdmType() == EdmSimpleTypeKind.Single.getEdmSimpleTypeInstance()) {
+           return Double.toString(Double.valueOf(left) - Double.valueOf(right));
+         } else {
+           return Long.toString(Long.valueOf(left) - Long.valueOf(right));
+         }
+       case MUL:
+         if (binaryExpression.getEdmType() == EdmSimpleTypeKind.Decimal.getEdmSimpleTypeInstance()
+             || binaryExpression.getEdmType() == EdmSimpleTypeKind.Double.getEdmSimpleTypeInstance()
+             || binaryExpression.getEdmType() == EdmSimpleTypeKind.Single.getEdmSimpleTypeInstance()) {
+           return Double.toString(Double.valueOf(left) * Double.valueOf(right));
+         } else {
+           return Long.toString(Long.valueOf(left) * Long.valueOf(right));
+         }
+       case DIV:
+         final String number = Double.toString(Double.valueOf(left) / Double.valueOf(right));
+         return number.endsWith(".0") ? number.replace(".0", "") : number;
+       case MODULO:
+         if (binaryExpression.getEdmType() == EdmSimpleTypeKind.Decimal.getEdmSimpleTypeInstance()
+             || binaryExpression.getEdmType() == EdmSimpleTypeKind.Double.getEdmSimpleTypeInstance()
+             || binaryExpression.getEdmType() == EdmSimpleTypeKind.Single.getEdmSimpleTypeInstance()) {
+           return Double.toString(Double.valueOf(left) % Double.valueOf(right));
+         } else {
+           return Long.toString(Long.valueOf(left) % Long.valueOf(right));
+         }
+       case AND:
+         return Boolean.toString(left.equals("true") && right.equals("true"));
+       case OR:
+         return Boolean.toString(left.equals("true") || right.equals("true"));
+       case EQ:
+         return Boolean.toString(left.equals(right));
+       case NE:
+         return Boolean.toString(!left.equals(right));
+       case LT:
+         if (type == EdmSimpleTypeKind.String.getEdmSimpleTypeInstance()
+             || type == EdmSimpleTypeKind.DateTime.getEdmSimpleTypeInstance()
+             || type == EdmSimpleTypeKind.DateTimeOffset.getEdmSimpleTypeInstance()
+             || type == EdmSimpleTypeKind.Guid.getEdmSimpleTypeInstance()
+             || type == EdmSimpleTypeKind.Time.getEdmSimpleTypeInstance()) {
+           return Boolean.toString(left.compareTo(right) < 0);
+         } else {
+           return Boolean.toString(Double.valueOf(left) < Double.valueOf(right));
+         }
+       case LE:
+         if (type == EdmSimpleTypeKind.String.getEdmSimpleTypeInstance()
+             || type == EdmSimpleTypeKind.DateTime.getEdmSimpleTypeInstance()
+             || type == EdmSimpleTypeKind.DateTimeOffset.getEdmSimpleTypeInstance()
+             || type == EdmSimpleTypeKind.Guid.getEdmSimpleTypeInstance()
+             || type == EdmSimpleTypeKind.Time.getEdmSimpleTypeInstance()) {
+           return Boolean.toString(left.compareTo(right) <= 0);
+         } else {
+           return Boolean.toString(Double.valueOf(left) <= Double.valueOf(right));
+         }
+       case GT:
+         if (type == EdmSimpleTypeKind.String.getEdmSimpleTypeInstance()
+             || type == EdmSimpleTypeKind.DateTime.getEdmSimpleTypeInstance()
+             || type == EdmSimpleTypeKind.DateTimeOffset.getEdmSimpleTypeInstance()
+             || type == EdmSimpleTypeKind.Guid.getEdmSimpleTypeInstance()
+             || type == EdmSimpleTypeKind.Time.getEdmSimpleTypeInstance()) {
+           return Boolean.toString(left.compareTo(right) > 0);
+         } else {
+           return Boolean.toString(Double.valueOf(left) > Double.valueOf(right));
+         }
+       case GE:
+         if (type == EdmSimpleTypeKind.String.getEdmSimpleTypeInstance()
+             || type == EdmSimpleTypeKind.DateTime.getEdmSimpleTypeInstance()
+             || type == EdmSimpleTypeKind.DateTimeOffset.getEdmSimpleTypeInstance()
+             || type == EdmSimpleTypeKind.Guid.getEdmSimpleTypeInstance()
+             || type == EdmSimpleTypeKind.Time.getEdmSimpleTypeInstance()) {
+           return Boolean.toString(left.compareTo(right) >= 0);
+         } else {
+           return Boolean.toString(Double.valueOf(left) >= Double.valueOf(right));
+         }
+       case PROPERTY_ACCESS:
+         throw new ODataNotImplementedException();
+       default:
+         throw new ODataNotImplementedException();
+       }
+ 
+     case PROPERTY:
+       final EdmProperty property = (EdmProperty) ((PropertyExpression) expression).getEdmProperty();
+       final EdmSimpleType propertyType = (EdmSimpleType) property.getType();
+       return propertyType.valueToString(valueAccess.getPropertyValue(data, property), EdmLiteralKind.DEFAULT,
+           property.getFacets());
+ 
+     case MEMBER:
+       final MemberExpression memberExpression = (MemberExpression) expression;
+       final PropertyExpression propertyExpression = (PropertyExpression) memberExpression.getProperty();
+       final EdmProperty memberProperty = (EdmProperty) propertyExpression.getEdmProperty();
+       final EdmSimpleType memberType = (EdmSimpleType) memberExpression.getEdmType();
+       List<EdmProperty> propertyPath = new ArrayList<EdmProperty>();
+       CommonExpression currentExpression = memberExpression;
+       while (currentExpression != null) {
+         final PropertyExpression currentPropertyExpression =
+             (PropertyExpression) (currentExpression.getKind() == ExpressionKind.MEMBER ?
+                 ((MemberExpression) currentExpression).getProperty() : currentExpression);
+         final EdmTyped currentProperty = currentPropertyExpression.getEdmProperty();
+         final EdmTypeKind kind = currentProperty.getType().getKind();
+         if (kind == EdmTypeKind.SIMPLE || kind == EdmTypeKind.COMPLEX) {
+           propertyPath.add(0, (EdmProperty) currentProperty);
+         } else {
+           throw new ODataNotImplementedException();
+         }
+         currentExpression =
+             currentExpression.getKind() == ExpressionKind.MEMBER ? ((MemberExpression) currentExpression).getPath()
+                 : null;
+       }
+       return memberType.valueToString(getPropertyValue(data, propertyPath), EdmLiteralKind.DEFAULT, memberProperty
+           .getFacets());
+ 
+     case LITERAL:
+       final LiteralExpression literal = (LiteralExpression) expression;
+       final EdmSimpleType literalType = (EdmSimpleType) literal.getEdmType();
+       return literalType.valueToString(literalType.valueOfString(literal.getUriLiteral(), EdmLiteralKind.URI, null,
+           literalType.getDefaultType()),
+           EdmLiteralKind.DEFAULT, null);
+ 
+     case METHOD:
+       final MethodExpression methodExpression = (MethodExpression) expression;
+       final String first = evaluateExpression(data, methodExpression.getParameters().get(0));
+       final String second = methodExpression.getParameterCount() > 1 ?
+           evaluateExpression(data, methodExpression.getParameters().get(1)) : null;
+       final String third = methodExpression.getParameterCount() > 2 ?
+           evaluateExpression(data, methodExpression.getParameters().get(2)) : null;
+ 
+       switch (methodExpression.getMethod()) {
+       case ENDSWITH:
+         return Boolean.toString(first.endsWith(second));
+       case INDEXOF:
+         return Integer.toString(first.indexOf(second));
+       case STARTSWITH:
+         return Boolean.toString(first.startsWith(second));
+       case TOLOWER:
+         return first.toLowerCase(Locale.ROOT);
+       case TOUPPER:
+         return first.toUpperCase(Locale.ROOT);
+       case TRIM:
+         return first.trim();
+       case SUBSTRING:
+         final int offset = Integer.parseInt(second);
+         return first.substring(offset, offset + Integer.parseInt(third));
+       case SUBSTRINGOF:
+         return Boolean.toString(second.contains(first));
+       case CONCAT:
+         return first + second;
+       case LENGTH:
+         return Integer.toString(first.length());
+       case YEAR:
+         return String.valueOf(Integer.parseInt(first.substring(0, 4)));
+       case MONTH:
+         return String.valueOf(Integer.parseInt(first.substring(5, 7)));
+       case DAY:
+         return String.valueOf(Integer.parseInt(first.substring(8, 10)));
+       case HOUR:
+         return String.valueOf(Integer.parseInt(first.substring(11, 13)));
+       case MINUTE:
+         return String.valueOf(Integer.parseInt(first.substring(14, 16)));
+       case SECOND:
+         return String.valueOf(Integer.parseInt(first.substring(17, 19)));
+       case ROUND:
+         return Long.toString(Math.round(Double.valueOf(first)));
+       case FLOOR:
+         return Long.toString(Math.round(Math.floor(Double.valueOf(first))));
+       case CEILING:
+         return Long.toString(Math.round(Math.ceil(Double.valueOf(first))));
+       default:
+         throw new ODataNotImplementedException();
+       }
+ 
+     default:
+       throw new ODataNotImplementedException();
+     }
+   }
+ 
+   private <T> String getSkipToken(final EdmEntitySet entitySet, final T data) throws ODataException {
+     String skipToken = "";
+     for (final EdmProperty property : entitySet.getEntityType().getKeyProperties()) {
+       final EdmSimpleType type = (EdmSimpleType) property.getType();
+       skipToken = skipToken.concat(type.valueToString(valueAccess.getPropertyValue(data, property),
+           EdmLiteralKind.DEFAULT, property.getFacets()));
+     }
+     return skipToken;
+   }
+ 
+   private <T> Object getPropertyValue(final T data, final List<EdmProperty> propertyPath) throws ODataException {
+     Object dataObject = data;
+     for (final EdmProperty property : propertyPath) {
+       if (dataObject != null) {
+         dataObject = valueAccess.getPropertyValue(dataObject, property);
+       }
+     }
+     return dataObject;
+   }
+ 
+   private void handleMimeType(final Object data, final EdmMapping mapping, final Map<String, Object> valueMap)
+       throws ODataException {
+     final String mimeTypeName = mapping.getMimeType();
+     if (mimeTypeName != null) {
+       Object value = valueAccess.getMappingValue(data, mapping);
+       valueMap.put(mimeTypeName, value);
+       if (mapping.getMediaResourceMimeTypeKey() != null) {
+         valueMap.put(mapping.getMediaResourceMimeTypeKey(), value);
+       }
+     }
+   }
+ 
++
+   private <T> Map<String, Object> getSimpleTypeValueMap(final T data, final List<EdmProperty> propertyPath)
+       throws ODataException {
+     final EdmProperty property = propertyPath.get(propertyPath.size() - 1);
+     Map<String, Object> valueWithMimeType = new HashMap<String, Object>();
+     valueWithMimeType.put(property.getName(), getPropertyValue(data, propertyPath));
+ 
+     handleMimeType(data, property.getMapping(), valueWithMimeType);
 -
+     return valueWithMimeType;
+   }
+ 
+   private <T> Map<String, Object> getStructuralTypeValueMap(final T data, final EdmStructuralType type)
+       throws ODataException {
+     ODataContext context = getContext();
+     final int timingHandle = context.startRuntimeMeasurement(getClass().getSimpleName(), "getStructuralTypeValueMap");
+ 
+     Map<String, Object> valueMap = new HashMap<String, Object>();
+ 
+     EdmMapping mapping = type.getMapping();
+     if (mapping != null) {
+       handleMimeType(data, mapping, valueMap);
+     }
+ 
+     for (final String propertyName : type.getPropertyNames()) {
+       final EdmProperty property = (EdmProperty) type.getProperty(propertyName);
+       final Object value = valueAccess.getPropertyValue(data, property);
+ 
+       if (property.isSimple()) {
+         if (property.getMapping() == null || property.getMapping().getMimeType() == null) {
+           valueMap.put(propertyName, value);
+         } else {
+           // TODO: enable MIME type mapping outside the current subtree
+           valueMap.put(propertyName, getSimpleTypeValueMap(data, Arrays.asList(property)));
+         }
+       } else {
+         valueMap.put(propertyName, getStructuralTypeValueMap(value, (EdmStructuralType) property.getType()));
+       }
+     }
+ 
+     context.stopRuntimeMeasurement(timingHandle);
+ 
+     return valueMap;
+   }
+ 
+   private <T> Map<String, Object> getStructuralTypeTypeMap(final T data, final EdmStructuralType type)
+       throws ODataException {
+     ODataContext context = getContext();
+     final int timingHandle = context.startRuntimeMeasurement(getClass().getSimpleName(), "getStructuralTypeTypeMap");
+ 
+     Map<String, Object> typeMap = new HashMap<String, Object>();
+     for (final String propertyName : type.getPropertyNames()) {
+       final EdmProperty property = (EdmProperty) type.getProperty(propertyName);
+       if (property.isSimple()) {
+         typeMap.put(propertyName, valueAccess.getPropertyType(data, property));
+       } else {
+         typeMap.put(propertyName, getStructuralTypeTypeMap(valueAccess.getPropertyValue(data, property),
+             (EdmStructuralType) property.getType()));
+       }
+     }
+ 
+     context.stopRuntimeMeasurement(timingHandle);
+ 
+     return typeMap;
+   }
+ 
+   private <T> void setStructuralTypeValuesFromMap(final T data, final EdmStructuralType type,
+       final Map<String, Object> valueMap, final boolean merge) throws ODataException {
+     ODataContext context = getContext();
+     final int timingHandle =
+         context.startRuntimeMeasurement(getClass().getSimpleName(), "setStructuralTypeValuesFromMap");
+ 
+     for (final String propertyName : type.getPropertyNames()) {
+       final EdmProperty property = (EdmProperty) type.getProperty(propertyName);
+       if (type instanceof EdmEntityType && ((EdmEntityType) type).getKeyProperties().contains(property)) {
+         Object v = valueAccess.getPropertyValue(data, property);
+         if (v != null) {
+           continue;
+         }
+       }
+ 
+       if (!merge || valueMap != null && valueMap.containsKey(propertyName)) {
+         final Object value = valueMap == null ? null : valueMap.get(propertyName);
+         if (property.isSimple()) {
+           valueAccess.setPropertyValue(data, property, value);
+         } else {
+           @SuppressWarnings("unchecked")
+           final Map<String, Object> values = (Map<String, Object>) value;
+           setStructuralTypeValuesFromMap(valueAccess.getPropertyValue(data, property),
+               (EdmStructuralType) property.getType(), values, merge);
+         }
+       }
+     }
+ 
+     context.stopRuntimeMeasurement(timingHandle);
+   }
+ 
+   @Override
+   public ODataResponse executeBatch(final BatchHandler handler, final String contentType, final InputStream content)
+       throws ODataException {
+     ODataResponse batchResponse;
+     List<BatchResponsePart> batchResponseParts = new ArrayList<BatchResponsePart>();
+     PathInfo pathInfo = getContext().getPathInfo();
+     EntityProviderBatchProperties batchProperties = EntityProviderBatchProperties.init().pathInfo(pathInfo).build();
+     List<BatchRequestPart> batchParts = EntityProvider.parseBatchRequest(contentType, content, batchProperties);
+     for (BatchRequestPart batchPart : batchParts) {
+       batchResponseParts.add(handler.handleBatchPart(batchPart));
+     }
+     batchResponse = EntityProvider.writeBatchResponse(batchResponseParts);
+     return batchResponse;
+   }
+ 
+   @Override
+   public BatchResponsePart executeChangeSet(final BatchHandler handler, final List<ODataRequest> requests)
+       throws ODataException {
+     List<ODataResponse> responses = new ArrayList<ODataResponse>();
+     for (ODataRequest request : requests) {
+       ODataResponse response = handler.handleRequest(request);
+       if (response.getStatus().getStatusCode() >= HttpStatusCodes.BAD_REQUEST.getStatusCode()) {
+         // Rollback
+         List<ODataResponse> errorResponses = new ArrayList<ODataResponse>(1);
+         errorResponses.add(response);
+         return BatchResponsePart.responses(errorResponses).changeSet(false).build();
+       }
+       responses.add(response);
+     }
+     return BatchResponsePart.responses(responses).changeSet(true).build();
+   }
+ }

http://git-wip-us.apache.org/repos/asf/incubator-olingo-odata2/blob/80379ec1/odata2-lib/odata-fit/src/test/java/org/apache/olingo/odata2/fit/ref/AbstractRefTest.java
----------------------------------------------------------------------


[02/12] [OLINGO-83] Refactoring of 'annotation-processor-*' modules

Posted by tb...@apache.org.
http://git-wip-us.apache.org/repos/asf/incubator-olingo-odata2/blob/3bd59050/odata2-annotation-processor/annotation-processor-webref/src/main/java/org/apache/olingo/odata2/ref/annotation/model/Building.java
----------------------------------------------------------------------
diff --git a/odata2-annotation-processor/annotation-processor-webref/src/main/java/org/apache/olingo/odata2/ref/annotation/model/Building.java b/odata2-annotation-processor/annotation-processor-webref/src/main/java/org/apache/olingo/odata2/ref/annotation/model/Building.java
deleted file mode 100644
index 5183195..0000000
--- a/odata2-annotation-processor/annotation-processor-webref/src/main/java/org/apache/olingo/odata2/ref/annotation/model/Building.java
+++ /dev/null
@@ -1,97 +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.odata2.ref.annotation.model;
-
-import java.util.ArrayList;
-import java.util.Arrays;
-import java.util.List;
-
-import org.apache.olingo.odata2.api.annotation.edm.EdmEntitySet;
-import org.apache.olingo.odata2.api.annotation.edm.EdmEntityType;
-import org.apache.olingo.odata2.api.annotation.edm.EdmKey;
-import org.apache.olingo.odata2.api.annotation.edm.EdmNavigationProperty;
-import org.apache.olingo.odata2.api.annotation.edm.EdmNavigationProperty.Multiplicity;
-import org.apache.olingo.odata2.api.annotation.edm.EdmProperty;
-import org.apache.olingo.odata2.api.annotation.edm.EdmType;
-
-/**
- *  
- */
-@EdmEntityType(name = "Building", namespace = ModelSharedConstants.NAMESPACE_1)
-@EdmEntitySet(name = "Buildings")
-public class Building {
-  @EdmKey
-  @EdmProperty(type = EdmType.INT32)
-  private int id;
-  @EdmProperty
-  private String name;
-  @EdmProperty(name = "Image", type = EdmType.BINARY)
-  private byte[] image;
-  @EdmNavigationProperty(name = "nb_Rooms", toType = Room.class,
-      association = "BuildingRooms", toMultiplicity = Multiplicity.MANY)
-  private List<Room> rooms = new ArrayList<Room>();
-
-  public String getId() {
-    return Integer.toString(id);
-  }
-
-  public void setName(final String name) {
-    this.name = name;
-  }
-
-  public String getName() {
-    return name;
-  }
-
-  public void setImage(final byte[] byteArray) {
-    image = byteArray;
-  }
-
-  public byte[] getImage() {
-    if (image == null) {
-      return null;
-    } else {
-      return image.clone();
-    }
-  }
-
-  public void addRoom(final Room room) {
-    rooms.add(room);
-  }
-
-  public List<Room> getRooms() {
-    return rooms;
-  }
-
-  @Override
-  public int hashCode() {
-    return id;
-  }
-
-  @Override
-  public boolean equals(final Object obj) {
-    return this == obj
-        || obj != null && getClass() == obj.getClass() && id == ((Building) obj).id;
-  }
-
-  @Override
-  public String toString() {
-    return "{\"Id\":\"" + id + "\",\"Name\":\"" + name + "\",\"Image\":\"" + Arrays.toString(image) + "\"}";
-  }
-}

http://git-wip-us.apache.org/repos/asf/incubator-olingo-odata2/blob/3bd59050/odata2-annotation-processor/annotation-processor-webref/src/main/java/org/apache/olingo/odata2/ref/annotation/model/City.java
----------------------------------------------------------------------
diff --git a/odata2-annotation-processor/annotation-processor-webref/src/main/java/org/apache/olingo/odata2/ref/annotation/model/City.java b/odata2-annotation-processor/annotation-processor-webref/src/main/java/org/apache/olingo/odata2/ref/annotation/model/City.java
deleted file mode 100644
index 8ec87b6..0000000
--- a/odata2-annotation-processor/annotation-processor-webref/src/main/java/org/apache/olingo/odata2/ref/annotation/model/City.java
+++ /dev/null
@@ -1,61 +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.odata2.ref.annotation.model;
-
-import org.apache.olingo.odata2.api.annotation.edm.EdmComplexType;
-import org.apache.olingo.odata2.api.annotation.edm.EdmProperty;
-
-/**
- *  
- */
-@EdmComplexType(name = "c_City", namespace = ModelSharedConstants.NAMESPACE_1)
-public class City {
-
-  @EdmProperty
-  private String postalCode;
-  @EdmProperty
-  private String cityName;
-
-  public City(final String postalCode, final String name) {
-    this.postalCode = postalCode;
-    cityName = name;
-  }
-
-  public void setPostalCode(final String postalCode) {
-    this.postalCode = postalCode;
-  }
-
-  public String getPostalCode() {
-    return postalCode;
-  }
-
-  public void setCityName(final String cityName) {
-    this.cityName = cityName;
-  }
-
-  public String getCityName() {
-    return cityName;
-  }
-
-  @Override
-  public String toString() {
-    return String.format("%s, %s", cityName, postalCode);
-  }
-
-}

http://git-wip-us.apache.org/repos/asf/incubator-olingo-odata2/blob/3bd59050/odata2-annotation-processor/annotation-processor-webref/src/main/java/org/apache/olingo/odata2/ref/annotation/model/Employee.java
----------------------------------------------------------------------
diff --git a/odata2-annotation-processor/annotation-processor-webref/src/main/java/org/apache/olingo/odata2/ref/annotation/model/Employee.java b/odata2-annotation-processor/annotation-processor-webref/src/main/java/org/apache/olingo/odata2/ref/annotation/model/Employee.java
deleted file mode 100644
index 2204ee8..0000000
--- a/odata2-annotation-processor/annotation-processor-webref/src/main/java/org/apache/olingo/odata2/ref/annotation/model/Employee.java
+++ /dev/null
@@ -1,192 +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.odata2.ref.annotation.model;
-
-import java.text.DateFormat;
-import java.util.Calendar;
-
-import org.apache.olingo.odata2.api.annotation.edm.EdmEntitySet;
-import org.apache.olingo.odata2.api.annotation.edm.EdmEntityType;
-import org.apache.olingo.odata2.api.annotation.edm.EdmFacets;
-import org.apache.olingo.odata2.api.annotation.edm.EdmKey;
-import org.apache.olingo.odata2.api.annotation.edm.EdmMediaResourceContent;
-import org.apache.olingo.odata2.api.annotation.edm.EdmMediaResourceMimeType;
-import org.apache.olingo.odata2.api.annotation.edm.EdmNavigationProperty;
-import org.apache.olingo.odata2.api.annotation.edm.EdmProperty;
-import org.apache.olingo.odata2.api.annotation.edm.EdmType;
-
-/**
- *  
- */
-@EdmEntityType(name = "Employee", namespace = ModelSharedConstants.NAMESPACE_1)
-@EdmEntitySet(name = "Employees")
-public class Employee {
-  @EdmKey
-  @EdmProperty(name = "EmployeeId", type = EdmType.STRING)
-  private String employeeId;
-  @EdmProperty(name = "EmployeeName")
-  private String employeeName;
-  @EdmProperty
-  private int age;
-  @EdmNavigationProperty(name = "ne_Manager", association = "ManagerEmployees")
-  private Manager manager;
-  @EdmNavigationProperty(name = "ne_Team", association = "TeamEmployees")
-  private Team team;
-  @EdmNavigationProperty(name = "ne_Room")
-  private Room room;
-  @EdmMediaResourceMimeType
-  private String imageType;
-  @EdmMediaResourceContent
-  private byte[] image;
-  @EdmProperty(name = "ImageUrl")
-  private String imageUrl;
-  @EdmProperty(name = "EntryDate", type = EdmType.DATE_TIME,
-      facets = @EdmFacets(nullable = true))
-  private Calendar entryDate;
-  @EdmProperty(name = "Location", facets = @EdmFacets(nullable = false))
-  private Location location;
-
-  public String getId() {
-    return employeeId;
-  }
-
-  public void setEmployeeName(final String employeeName) {
-    this.employeeName = employeeName;
-  }
-
-  public String getEmployeeName() {
-    return employeeName;
-  }
-
-  public void setAge(final int age) {
-    this.age = age;
-  }
-
-  public int getAge() {
-    return age;
-  }
-
-  public void setManager(final Manager manager) {
-    this.manager = manager;
-  }
-
-  public Manager getManager() {
-    return manager;
-  }
-
-  public void setTeam(final Team team) {
-    this.team = team;
-  }
-
-  public Team getTeam() {
-    return team;
-  }
-
-  public void setRoom(final Room room) {
-    this.room = room;
-  }
-
-  public Room getRoom() {
-    return room;
-  }
-
-  public void setImageUri(final String imageUri) {
-    imageUrl = imageUri;
-  }
-
-  public String getImageUri() {
-    return imageUrl;
-  }
-
-  public void setLocation(final Location location) {
-    this.location = location;
-  }
-
-  public Location getLocation() {
-    return location;
-  }
-
-  public void setEntryDate(final Calendar date) {
-    entryDate = date;
-  }
-
-  public Calendar getEntryDate() {
-    return entryDate;
-  }
-
-  public void setImageType(final String imageType) {
-    this.imageType = imageType;
-  }
-
-  public String getImageType() {
-    return imageType;
-  }
-
-  public void setImage(final byte[] image) {
-    this.image = image;
-  }
-
-  public void setImage(final String imageUrl) {
-    image = loadImage(imageUrl);
-  }
-
-  private static byte[] loadImage(final String imageUrl) {
-    return ResourceHelper.loadAsByte(imageUrl);
-  }
-
-  public byte[] getImage() {
-    if (image == null) {
-      return null;
-    }
-    return image.clone();
-  }
-
-  @Override
-  public int hashCode() {
-    if (employeeId == null) {
-      return 0;
-    }
-    return employeeId.hashCode();
-  }
-
-  @Override
-  public boolean equals(final Object obj) {
-    return this == obj
-        || obj != null && getClass() == obj.getClass() && employeeId == ((Employee) obj).employeeId;
-  }
-
-  @Override
-  public String toString() {
-    return "{\"EmployeeId\":\"" + employeeId + "\","
-        + "\"EmployeeName\":\"" + employeeName + "\","
-        + "\"ManagerId\":" + (manager == null ? "null" : "\"" + manager.getId() + "\"") + ","
-        + "\"RoomId\":" + (room == null ? "null" : "\"" + room.getId() + "\"") + ","
-        + "\"TeamId\":" + (team == null ? "null" : "\"" + team.getId() + "\"") + ","
-        + "\"Location\":"
-        + (location == null ? "null" :
-            "{\"City\":" + (location.getCity() == null ? "null" :
-                "{\"PostalCode\":\"" + location.getCity().getPostalCode() + "\","
-                    + "\"CityName\":\"" + location.getCity().getCityName() + "\"}") + ","
-                + "\"Country\":\"" + location.getCountry() + "\"}") + ","
-        + "\"Age\":" + age + ","
-        + "\"EntryDate\":"
-        + (entryDate == null ? "null" : "\"" + DateFormat.getInstance().format(entryDate.getTime()) + "\"") + ","
-        + "\"ImageUrl\":\"" + imageUrl + "\"}";
-  }
-}

http://git-wip-us.apache.org/repos/asf/incubator-olingo-odata2/blob/3bd59050/odata2-annotation-processor/annotation-processor-webref/src/main/java/org/apache/olingo/odata2/ref/annotation/model/Location.java
----------------------------------------------------------------------
diff --git a/odata2-annotation-processor/annotation-processor-webref/src/main/java/org/apache/olingo/odata2/ref/annotation/model/Location.java b/odata2-annotation-processor/annotation-processor-webref/src/main/java/org/apache/olingo/odata2/ref/annotation/model/Location.java
deleted file mode 100644
index 9b0785c..0000000
--- a/odata2-annotation-processor/annotation-processor-webref/src/main/java/org/apache/olingo/odata2/ref/annotation/model/Location.java
+++ /dev/null
@@ -1,60 +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.odata2.ref.annotation.model;
-
-import org.apache.olingo.odata2.api.annotation.edm.EdmComplexType;
-import org.apache.olingo.odata2.api.annotation.edm.EdmProperty;
-
-/**
- *  
- */
-@EdmComplexType(name = "c_Location", namespace = ModelSharedConstants.NAMESPACE_1)
-public class Location {
-  @EdmProperty
-  private String country;
-  @EdmProperty
-  private City city;
-
-  public Location(final String country, final String postalCode, final String cityName) {
-    this.country = country;
-    city = new City(postalCode, cityName);
-  }
-
-  public void setCountry(final String country) {
-    this.country = country;
-  }
-
-  public String getCountry() {
-    return country;
-  }
-
-  public void setCity(final City city) {
-    this.city = city;
-  }
-
-  public City getCity() {
-    return city;
-  }
-
-  @Override
-  public String toString() {
-    return String.format("%s, %s", country, city.toString());
-  }
-
-}

http://git-wip-us.apache.org/repos/asf/incubator-olingo-odata2/blob/3bd59050/odata2-annotation-processor/annotation-processor-webref/src/main/java/org/apache/olingo/odata2/ref/annotation/model/Manager.java
----------------------------------------------------------------------
diff --git a/odata2-annotation-processor/annotation-processor-webref/src/main/java/org/apache/olingo/odata2/ref/annotation/model/Manager.java b/odata2-annotation-processor/annotation-processor-webref/src/main/java/org/apache/olingo/odata2/ref/annotation/model/Manager.java
deleted file mode 100644
index 57e6d78..0000000
--- a/odata2-annotation-processor/annotation-processor-webref/src/main/java/org/apache/olingo/odata2/ref/annotation/model/Manager.java
+++ /dev/null
@@ -1,43 +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.odata2.ref.annotation.model;
-
-import java.util.ArrayList;
-import java.util.List;
-
-import org.apache.olingo.odata2.api.annotation.edm.EdmEntitySet;
-import org.apache.olingo.odata2.api.annotation.edm.EdmEntityType;
-import org.apache.olingo.odata2.api.annotation.edm.EdmNavigationProperty;
-import org.apache.olingo.odata2.api.annotation.edm.EdmNavigationProperty.Multiplicity;
-
-/**
- *
- */
-@EdmEntityType(name = "Manager", namespace = ModelSharedConstants.NAMESPACE_1)
-@EdmEntitySet(name = "Managers")
-public class Manager extends Employee {
-
-  @EdmNavigationProperty(name = "nm_Employees", association = "ManagerEmployees",
-      toMultiplicity = Multiplicity.MANY)
-  private List<Employee> employees = new ArrayList<Employee>();
-
-  public List<Employee> getEmployees() {
-    return employees;
-  }
-}

http://git-wip-us.apache.org/repos/asf/incubator-olingo-odata2/blob/3bd59050/odata2-annotation-processor/annotation-processor-webref/src/main/java/org/apache/olingo/odata2/ref/annotation/model/ModelSharedConstants.java
----------------------------------------------------------------------
diff --git a/odata2-annotation-processor/annotation-processor-webref/src/main/java/org/apache/olingo/odata2/ref/annotation/model/ModelSharedConstants.java b/odata2-annotation-processor/annotation-processor-webref/src/main/java/org/apache/olingo/odata2/ref/annotation/model/ModelSharedConstants.java
deleted file mode 100644
index ab17fbb..0000000
--- a/odata2-annotation-processor/annotation-processor-webref/src/main/java/org/apache/olingo/odata2/ref/annotation/model/ModelSharedConstants.java
+++ /dev/null
@@ -1,25 +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.odata2.ref.annotation.model;
-
-public interface ModelSharedConstants {
-
-  String NAMESPACE_1 = "RefScenario";
-  String CONTAINER_1 = "Container1";
-}

http://git-wip-us.apache.org/repos/asf/incubator-olingo-odata2/blob/3bd59050/odata2-annotation-processor/annotation-processor-webref/src/main/java/org/apache/olingo/odata2/ref/annotation/model/Photo.java
----------------------------------------------------------------------
diff --git a/odata2-annotation-processor/annotation-processor-webref/src/main/java/org/apache/olingo/odata2/ref/annotation/model/Photo.java b/odata2-annotation-processor/annotation-processor-webref/src/main/java/org/apache/olingo/odata2/ref/annotation/model/Photo.java
deleted file mode 100644
index b098db5..0000000
--- a/odata2-annotation-processor/annotation-processor-webref/src/main/java/org/apache/olingo/odata2/ref/annotation/model/Photo.java
+++ /dev/null
@@ -1,128 +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.odata2.ref.annotation.model;
-
-import java.util.Arrays;
-
-import org.apache.olingo.odata2.api.annotation.edm.EdmEntitySet;
-import org.apache.olingo.odata2.api.annotation.edm.EdmEntityType;
-import org.apache.olingo.odata2.api.annotation.edm.EdmKey;
-import org.apache.olingo.odata2.api.annotation.edm.EdmMediaResourceContent;
-import org.apache.olingo.odata2.api.annotation.edm.EdmMediaResourceMimeType;
-import org.apache.olingo.odata2.api.annotation.edm.EdmMediaResourceSource;
-import org.apache.olingo.odata2.api.annotation.edm.EdmProperty;
-import org.apache.olingo.odata2.api.annotation.edm.EdmType;
-
-/**
- *  
- */
-@EdmEntityType(name = "Photo", namespace = ModelSharedConstants.NAMESPACE_1)
-@EdmEntitySet(name = "Photos")
-public class Photo {
-  @EdmKey
-  @EdmProperty
-  private String name;
-  @EdmKey
-  @EdmProperty
-  private String type;
-  @EdmProperty
-  @EdmMediaResourceMimeType
-  private String mimeType;
-  @EdmProperty
-  @EdmMediaResourceSource
-  private String imageUrl = "http://localhost/someResource.png";
-  @EdmProperty(type = EdmType.BINARY)
-  @EdmMediaResourceContent
-  private byte[] image = ResourceHelper.generateImage();
-
-  public String getName() {
-    return name;
-  }
-
-  public void setName(final String name) {
-    this.name = name;
-  }
-
-  public String getType() {
-    return type;
-  }
-
-  public void setType(final String type) {
-    this.type = type;
-  }
-
-  public String getImageUri() {
-    return imageUrl;
-  }
-
-  public void setImageUri(final String uri) {
-    imageUrl = uri;
-  }
-
-  public byte[] getImage() {
-    return image.clone();
-  }
-
-  public void setImage(final byte[] image) {
-    this.image = image;
-  }
-
-  public String getImageType() {
-    return mimeType;
-  }
-
-  public void setImageType(final String imageType) {
-    mimeType = imageType;
-  }
-
-  @Override
-  public int hashCode() {
-    int hash = 5;
-    hash = 83 * hash + (name != null ? name.hashCode() : 0);
-    hash = 83 * hash + (type != null ? type.hashCode() : 0);
-    return hash;
-  }
-
-  @Override
-  public boolean equals(final Object obj) {
-    if (obj == null) {
-      return false;
-    }
-    if (getClass() != obj.getClass()) {
-      return false;
-    }
-    final Photo other = (Photo) obj;
-    if ((name == null) ? (other.name != null) : !name.equals(other.name)) {
-      return false;
-    }
-    if ((type == null) ? (other.type != null) : !type.equals(other.type)) {
-      return false;
-    }
-    return true;
-  }
-
-  @Override
-  public String toString() {
-    return "{\"Name\":\"" + name + "\","
-        + "\"Type\":\"" + type + "\","
-        + "\"ImageUrl\":\"" + imageUrl + "\","
-        + "\"Image\":\"" + Arrays.toString(image) + "\","
-        + "\"MimeType\":\"" + mimeType + "\"";
-  }
-}

http://git-wip-us.apache.org/repos/asf/incubator-olingo-odata2/blob/3bd59050/odata2-annotation-processor/annotation-processor-webref/src/main/java/org/apache/olingo/odata2/ref/annotation/model/RefBase.java
----------------------------------------------------------------------
diff --git a/odata2-annotation-processor/annotation-processor-webref/src/main/java/org/apache/olingo/odata2/ref/annotation/model/RefBase.java b/odata2-annotation-processor/annotation-processor-webref/src/main/java/org/apache/olingo/odata2/ref/annotation/model/RefBase.java
deleted file mode 100644
index 6424e0a..0000000
--- a/odata2-annotation-processor/annotation-processor-webref/src/main/java/org/apache/olingo/odata2/ref/annotation/model/RefBase.java
+++ /dev/null
@@ -1,78 +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.odata2.ref.annotation.model;
-
-import org.apache.olingo.odata2.api.annotation.edm.EdmEntityType;
-import org.apache.olingo.odata2.api.annotation.edm.EdmKey;
-import org.apache.olingo.odata2.api.annotation.edm.EdmProperty;
-import org.apache.olingo.odata2.api.annotation.edm.EdmType;
-
-/**
- *
- */
-@EdmEntityType(name = "Base", namespace = ModelSharedConstants.NAMESPACE_1)
-public abstract class RefBase {
-  @EdmProperty(name = "Name")
-  protected String name;
-  @EdmProperty(name = "Id", type = EdmType.STRING)
-  @EdmKey
-  protected String id;
-
-  public String getName() {
-    return name;
-  }
-
-  public String getId() {
-    return id;
-  }
-
-  public void setName(final String name) {
-    this.name = name;
-  }
-
-  public void setId(final int id) {
-    this.id = String.valueOf(id);
-  }
-
-  @Override
-  public int hashCode() {
-    if (id == null) {
-      return -1;
-    }
-    return id.hashCode();
-  }
-
-  @Override
-  public boolean equals(final Object obj) {
-    if (obj == null) {
-      return false;
-    }
-    if (getClass() != obj.getClass()) {
-      return false;
-    }
-    final RefBase other = (RefBase) obj;
-    if ((name == null) ? (other.name != null) : !name.equals(other.name)) {
-      return false;
-    }
-    if ((id == null) ? (other.id != null) : !id.equals(other.id)) {
-      return false;
-    }
-    return true;
-  }
-}

http://git-wip-us.apache.org/repos/asf/incubator-olingo-odata2/blob/3bd59050/odata2-annotation-processor/annotation-processor-webref/src/main/java/org/apache/olingo/odata2/ref/annotation/model/ResourceHelper.java
----------------------------------------------------------------------
diff --git a/odata2-annotation-processor/annotation-processor-webref/src/main/java/org/apache/olingo/odata2/ref/annotation/model/ResourceHelper.java b/odata2-annotation-processor/annotation-processor-webref/src/main/java/org/apache/olingo/odata2/ref/annotation/model/ResourceHelper.java
deleted file mode 100644
index 80da2f3..0000000
--- a/odata2-annotation-processor/annotation-processor-webref/src/main/java/org/apache/olingo/odata2/ref/annotation/model/ResourceHelper.java
+++ /dev/null
@@ -1,96 +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.odata2.ref.annotation.model;
-
-import java.awt.image.BufferedImage;
-import java.awt.image.WritableRaster;
-import java.io.ByteArrayOutputStream;
-import java.io.IOException;
-import java.io.InputStream;
-
-import javax.imageio.ImageIO;
-
-/**
- *
- */
-public class ResourceHelper {
-
-  public static byte[] loadAsByte(final String resource) {
-    return load(resource, new byte[0]);
-  }
-
-  public static byte[] load(final String resource, final byte[] defaultResult) {
-    InputStream instream = null;
-    try {
-      instream = Thread.currentThread().getContextClassLoader().getResourceAsStream(resource);
-      if (instream == null) {
-        return defaultResult;
-      }
-      ByteArrayOutputStream stream = new ByteArrayOutputStream();
-      int b = 0;
-      while ((b = instream.read()) != -1) {
-        stream.write(b);
-      }
-
-      return stream.toByteArray();
-    } catch (IOException e) {
-      throw new RuntimeException(e);
-    } finally {
-      if (instream != null) {
-        try {
-          instream.close();
-        } catch (IOException ex) {}
-      }
-    }
-  }
-
-  public enum Format {
-    BMP, JPEG, PNG, GIF
-  };
-
-  public static byte[] generateImage() {
-    return generateImage(Format.PNG);
-  }
-
-  public static byte[] generateImage(final Format format) {
-    try {
-      int width = 320;
-      int height = 320;
-      BufferedImage image = new BufferedImage(width, height, BufferedImage.TYPE_BYTE_BINARY);
-      WritableRaster raster = image.getRaster();
-
-      int mod = format.ordinal() + 2;
-      for (int h = 0; h < height; h++) {
-        for (int w = 0; w < width; w++) {
-          if (((h / 32) + (w / 32)) % mod == 0) {
-            raster.setSample(w, h, 0, 0);
-          } else {
-            raster.setSample(w, h, 0, 1);
-          }
-        }
-      }
-
-      ByteArrayOutputStream out = new ByteArrayOutputStream(1024);
-      ImageIO.write(image, format.name(), out);
-      return out.toByteArray();
-    } catch (IOException ex) {
-      return new byte[0];
-    }
-  }
-}

http://git-wip-us.apache.org/repos/asf/incubator-olingo-odata2/blob/3bd59050/odata2-annotation-processor/annotation-processor-webref/src/main/java/org/apache/olingo/odata2/ref/annotation/model/Room.java
----------------------------------------------------------------------
diff --git a/odata2-annotation-processor/annotation-processor-webref/src/main/java/org/apache/olingo/odata2/ref/annotation/model/Room.java b/odata2-annotation-processor/annotation-processor-webref/src/main/java/org/apache/olingo/odata2/ref/annotation/model/Room.java
deleted file mode 100644
index 2d9f48e..0000000
--- a/odata2-annotation-processor/annotation-processor-webref/src/main/java/org/apache/olingo/odata2/ref/annotation/model/Room.java
+++ /dev/null
@@ -1,88 +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.odata2.ref.annotation.model;
-
-import java.util.ArrayList;
-import java.util.List;
-
-import org.apache.olingo.odata2.api.annotation.edm.EdmEntitySet;
-import org.apache.olingo.odata2.api.annotation.edm.EdmEntityType;
-import org.apache.olingo.odata2.api.annotation.edm.EdmNavigationProperty;
-import org.apache.olingo.odata2.api.annotation.edm.EdmProperty;
-
-/**
- *
- */
-@EdmEntityType(name = "Room", namespace = ModelSharedConstants.NAMESPACE_1)
-@EdmEntitySet(name = "Rooms")
-public class Room extends RefBase {
-
-  @EdmProperty
-  private Integer seats;
-  @EdmProperty
-  private Integer version;
-  @EdmNavigationProperty(name = "nr_Building", association = "BuildingRooms")
-  private Building building;
-  @EdmNavigationProperty(name = "nr_Employees")
-  private List<Employee> employees = new ArrayList<Employee>();
-
-  public void setSeats(final int seats) {
-    this.seats = seats;
-  }
-
-  public int getSeats() {
-    return seats;
-  }
-
-  public void setVersion(final int version) {
-    this.version = version;
-  }
-
-  public int getVersion() {
-    return version;
-  }
-
-  public void setBuilding(final Building building) {
-    this.building = building;
-  }
-
-  public Building getBuilding() {
-    return building;
-  }
-
-  public List<Employee> getEmployees() {
-    return employees;
-  }
-
-  @Override
-  public int hashCode() {
-    return super.hashCode();
-  }
-
-  @Override
-  public boolean equals(final Object obj) {
-    return this == obj
-        || obj != null && getClass() == obj.getClass() && id == ((Room) obj).id;
-  }
-
-  @Override
-  public String toString() {
-    return "{\"Id\":\"" + id + "\",\"Name\":\"" + name + "\",\"Seats\":" + seats + ",\"Version\":" + version + "}";
-  }
-}

http://git-wip-us.apache.org/repos/asf/incubator-olingo-odata2/blob/3bd59050/odata2-annotation-processor/annotation-processor-webref/src/main/java/org/apache/olingo/odata2/ref/annotation/model/Team.java
----------------------------------------------------------------------
diff --git a/odata2-annotation-processor/annotation-processor-webref/src/main/java/org/apache/olingo/odata2/ref/annotation/model/Team.java b/odata2-annotation-processor/annotation-processor-webref/src/main/java/org/apache/olingo/odata2/ref/annotation/model/Team.java
deleted file mode 100644
index 4767d29..0000000
--- a/odata2-annotation-processor/annotation-processor-webref/src/main/java/org/apache/olingo/odata2/ref/annotation/model/Team.java
+++ /dev/null
@@ -1,73 +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.odata2.ref.annotation.model;
-
-import java.util.ArrayList;
-import java.util.List;
-
-import org.apache.olingo.odata2.api.annotation.edm.EdmEntitySet;
-import org.apache.olingo.odata2.api.annotation.edm.EdmEntityType;
-import org.apache.olingo.odata2.api.annotation.edm.EdmNavigationProperty;
-import org.apache.olingo.odata2.api.annotation.edm.EdmNavigationProperty.Multiplicity;
-import org.apache.olingo.odata2.api.annotation.edm.EdmProperty;
-import org.apache.olingo.odata2.api.annotation.edm.EdmType;
-
-/**
-*  
-*/
-@EdmEntityType(name = "Team", namespace = ModelSharedConstants.NAMESPACE_1)
-@EdmEntitySet(name = "Teams")
-public class Team extends RefBase {
-  @EdmProperty(type = EdmType.BOOLEAN)
-  private Boolean isScrumTeam;
-  @EdmNavigationProperty(name = "nt_Employees", association = "TeamEmployees", toMultiplicity = Multiplicity.MANY)
-  private List<Employee> employees = new ArrayList<Employee>();
-
-  public Boolean isScrumTeam() {
-    return isScrumTeam;
-  }
-
-  public void setScrumTeam(final Boolean isScrumTeam) {
-    this.isScrumTeam = isScrumTeam;
-  }
-
-  public void addEmployee(final Employee e) {
-    employees.add(e);
-  }
-
-  public List<Employee> getEmployees() {
-    return employees;
-  }
-
-  @Override
-  public int hashCode() {
-    return super.hashCode();
-  }
-
-  @Override
-  public boolean equals(final Object obj) {
-    return this == obj
-        || obj != null && getClass() == obj.getClass() && id == ((Team) obj).id;
-  }
-
-  @Override
-  public String toString() {
-    return "{\"Id\":\"" + id + "\",\"Name\":\"" + name + "\",\"IsScrumTeam\":" + isScrumTeam + "}";
-  }
-}
\ No newline at end of file

http://git-wip-us.apache.org/repos/asf/incubator-olingo-odata2/blob/3bd59050/odata2-annotation-processor/annotation-processor-webref/src/main/java/org/apache/olingo/odata2/ref/annotation/processor/AnnotationServiceFactory.java
----------------------------------------------------------------------
diff --git a/odata2-annotation-processor/annotation-processor-webref/src/main/java/org/apache/olingo/odata2/ref/annotation/processor/AnnotationServiceFactory.java b/odata2-annotation-processor/annotation-processor-webref/src/main/java/org/apache/olingo/odata2/ref/annotation/processor/AnnotationServiceFactory.java
deleted file mode 100644
index efc0635..0000000
--- a/odata2-annotation-processor/annotation-processor-webref/src/main/java/org/apache/olingo/odata2/ref/annotation/processor/AnnotationServiceFactory.java
+++ /dev/null
@@ -1,215 +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.odata2.ref.annotation.processor;
-
-import java.util.Calendar;
-
-import org.apache.olingo.odata2.api.ODataCallback;
-import org.apache.olingo.odata2.api.ODataDebugCallback;
-import org.apache.olingo.odata2.api.ODataService;
-import org.apache.olingo.odata2.api.ODataServiceFactory;
-import org.apache.olingo.odata2.api.commons.HttpStatusCodes;
-import org.apache.olingo.odata2.api.ep.EntityProvider;
-import org.apache.olingo.odata2.api.exception.ODataApplicationException;
-import org.apache.olingo.odata2.api.exception.ODataException;
-import org.apache.olingo.odata2.api.processor.ODataContext;
-import org.apache.olingo.odata2.api.processor.ODataErrorCallback;
-import org.apache.olingo.odata2.api.processor.ODataErrorContext;
-import org.apache.olingo.odata2.api.processor.ODataResponse;
-import org.apache.olingo.odata2.core.annotation.data.AnnotationInMemoryDs;
-import org.apache.olingo.odata2.core.annotation.data.AnnotationValueAccess;
-import org.apache.olingo.odata2.core.annotation.data.DataStore;
-import org.apache.olingo.odata2.core.annotation.edm.AnnotationEdmProvider;
-import org.apache.olingo.odata2.core.annotation.processor.ListsProcessor;
-import org.apache.olingo.odata2.ref.annotation.model.Building;
-import org.apache.olingo.odata2.ref.annotation.model.Employee;
-import org.apache.olingo.odata2.ref.annotation.model.Location;
-import org.apache.olingo.odata2.ref.annotation.model.Manager;
-import org.apache.olingo.odata2.ref.annotation.model.Photo;
-import org.apache.olingo.odata2.ref.annotation.model.ResourceHelper;
-import org.apache.olingo.odata2.ref.annotation.model.Room;
-import org.apache.olingo.odata2.ref.annotation.model.Team;
-import org.slf4j.Logger;
-import org.slf4j.LoggerFactory;
-
-/**
- * ODataServiceFactory implemantion based on ListProcessor
- * in combination with Annotation-Support-Classes for EdmProvider, DataSource and ValueAccess.
- */
-public class AnnotationServiceFactory extends ODataServiceFactory {
-
-  /**
-   * Instance holder for all annotation relevant instances which should be used as singleton
-   * instances within the ODataApplication (ODataService)
-   */
-  private static class AnnotationInstances {
-    final static String MODEL_PACKAGE = "org.apache.olingo.odata2.ref.annotation.model";
-    final static AnnotationEdmProvider EDM_PROVIDER;
-    final static AnnotationInMemoryDs DATA_SOURCE;
-    final static AnnotationValueAccess VALUE_ACCESS;
-
-    static {
-      try {
-        EDM_PROVIDER = new AnnotationEdmProvider(MODEL_PACKAGE);
-        DATA_SOURCE = new AnnotationInMemoryDs(MODEL_PACKAGE);
-        VALUE_ACCESS = new AnnotationValueAccess();
-
-        initializeSampleData(DATA_SOURCE);
-      } catch (ODataApplicationException ex) {
-        throw new RuntimeException("Exception during sample data generation.", ex);
-      } catch (ODataException ex) {
-        throw new RuntimeException("Exception during data source initialization generation.", ex);
-      }
-    }
-  }
-
-  @Override
-  public ODataService createService(final ODataContext context) throws ODataException {
-    // Edm via Annotations and ListProcessor via AnnotationDS with AnnotationsValueAccess
-    return createODataSingleProcessorService(AnnotationInstances.EDM_PROVIDER,
-        new ListsProcessor(AnnotationInstances.DATA_SOURCE, AnnotationInstances.VALUE_ACCESS));
-  }
-
-  @SuppressWarnings("unchecked")
-  @Override
-  public <T extends ODataCallback> T getCallback(final Class<? extends ODataCallback> callbackInterface) {
-    return (T) (callbackInterface.isAssignableFrom(ScenarioErrorCallback.class)
-        ? new ScenarioErrorCallback() : callbackInterface.isAssignableFrom(ODataDebugCallback.class)
-            ? new ScenarioDebugCallback() : super.getCallback(callbackInterface));
-  }
-
-  /*
-   * Helper classes and methods
-   */
-
-  /**
-   * 
-   */
-  private final class ScenarioDebugCallback implements ODataDebugCallback {
-
-    @Override
-    public boolean isDebugEnabled() {
-      return true;
-    }
-  }
-
-  private class ScenarioErrorCallback implements ODataErrorCallback {
-
-    private final Logger LOG = LoggerFactory.getLogger(ScenarioErrorCallback.class);
-
-    @Override
-    public ODataResponse handleError(final ODataErrorContext context) throws ODataApplicationException {
-      if (context.getHttpStatus() == HttpStatusCodes.INTERNAL_SERVER_ERROR) {
-        LOG.error("Internal Server Error", context.getException());
-      }
-
-      return EntityProvider.writeErrorDocument(context);
-    }
-
-  }
-
-  private static void initializeSampleData(final AnnotationInMemoryDs dataSource) throws ODataApplicationException {
-    DataStore<Team> teamDs = dataSource.getDataStore(Team.class);
-    teamDs.create(createTeam("Team Alpha", true));
-    teamDs.create(createTeam("Team Beta", false));
-    teamDs.create(createTeam("Team Gamma", false));
-    teamDs.create(createTeam("Team Omega", true));
-    teamDs.create(createTeam("Team Zeta", true));
-
-    DataStore<Building> buildingsDs = dataSource.getDataStore(Building.class);
-    Building redBuilding = createBuilding("Red Building");
-    buildingsDs.create(redBuilding);
-    Building greenBuilding = createBuilding("Green Building");
-    buildingsDs.create(greenBuilding);
-    Building blueBuilding = createBuilding("Blue Building");
-    buildingsDs.create(blueBuilding);
-    Building yellowBuilding = createBuilding("Yellow Building");
-    buildingsDs.create(yellowBuilding);
-
-    DataStore<Photo> photoDs = dataSource.getDataStore(Photo.class);
-    photoDs.create(createPhoto("Small picture", ResourceHelper.Format.GIF));
-    photoDs.create(createPhoto("Medium picture", ResourceHelper.Format.PNG));
-    photoDs.create(createPhoto("Big picture", ResourceHelper.Format.JPEG));
-    photoDs.create(createPhoto("Huge picture", ResourceHelper.Format.BMP));
-
-    DataStore<Room> roomDs = dataSource.getDataStore(Room.class);
-    roomDs.create(createRoom("Tiny red room", 5, 1, redBuilding));
-    roomDs.create(createRoom("Small red room", 20, 1, redBuilding));
-    roomDs.create(createRoom("Small green room", 20, 1, greenBuilding));
-    roomDs.create(createRoom("Big blue room", 40, 1, blueBuilding));
-    roomDs.create(createRoom("Huge blue room", 120, 1, blueBuilding));
-    roomDs.create(createRoom("Huge yellow room", 120, 1, yellowBuilding));
-
-    DataStore<Employee> employeeDataStore = dataSource.getDataStore(Employee.class);
-    employeeDataStore.create(createEmployee("first Employee",
-        new Location("Norge", "8392", "Ä"), 42, null,
-        photoDs.read().iterator().next().getImage(), photoDs.read().iterator().next().getImageType(),
-        "http://localhost/image/first.png",
-        null, teamDs.read().iterator().next(), roomDs.read().iterator().next()));
-  }
-
-  private static Employee createEmployee(final String name,
-      final Location location, final int age, final Calendar date,
-      final byte[] image, final String imageType, final String imageUrl,
-      final Manager manager, final Team team, final Room room) {
-    Employee employee = new Employee();
-    employee.setEmployeeName(name);
-    employee.setLocation(location);
-    employee.setAge(age);
-    employee.setEntryDate(date);
-    employee.setImage(image);
-    employee.setImageType(imageType);
-    employee.setImageUri(imageUrl);
-    employee.setManager(manager);
-    employee.setTeam(team);
-    employee.setRoom(room);
-    return employee;
-  }
-
-  private static Team createTeam(final String teamName, final boolean isScrumTeam) {
-    Team team = new Team();
-    team.setName(teamName);
-    team.setScrumTeam(isScrumTeam);
-    return team;
-  }
-
-  private static Building createBuilding(final String buildingName) {
-    Building b = new Building();
-    b.setName(buildingName);
-    return b;
-  }
-
-  private static Photo createPhoto(final String name, final ResourceHelper.Format format) {
-    Photo p = new Photo();
-    p.setName(name);
-    p.setImageUri("http://localhost/image/" + name);
-    p.setType(format.name());
-    p.setImageType("image/" + format.name().toLowerCase());
-    p.setImage(ResourceHelper.generateImage(format));
-    return p;
-  }
-
-  private static Room createRoom(final String name, final int seats, final int version, final Building building) {
-    Room r = new Room();
-    r.setName(name);
-    r.setSeats(seats);
-    r.setVersion(version);
-    r.setBuilding(building);
-
-    building.addRoom(r);
-
-    return r;
-  }
-}

http://git-wip-us.apache.org/repos/asf/incubator-olingo-odata2/blob/3bd59050/odata2-annotation-processor/annotation-processor-webref/src/main/webapp/WEB-INF/web.xml
----------------------------------------------------------------------
diff --git a/odata2-annotation-processor/annotation-processor-webref/src/main/webapp/WEB-INF/web.xml b/odata2-annotation-processor/annotation-processor-webref/src/main/webapp/WEB-INF/web.xml
index ba2b7bb..2e4635e 100644
--- a/odata2-annotation-processor/annotation-processor-webref/src/main/webapp/WEB-INF/web.xml
+++ b/odata2-annotation-processor/annotation-processor-webref/src/main/webapp/WEB-INF/web.xml
@@ -35,7 +35,7 @@
 		</init-param>
 		<init-param>
 			<param-name>org.apache.olingo.odata2.service.factory</param-name>
-			<param-value>org.apache.olingo.odata2.ref.annotation.processor.AnnotationServiceFactory</param-value>
+			<param-value>org.apache.olingo.odata2.annotation.processor.ref.AnnotationRefServiceFactory</param-value>
 		</init-param>
 		<load-on-startup>1</load-on-startup>
 	</servlet>

http://git-wip-us.apache.org/repos/asf/incubator-olingo-odata2/blob/3bd59050/odata2-lib/odata-fit/src/test/java/org/apache/olingo/odata2/fit/ref/AbstractRefTest.java
----------------------------------------------------------------------
diff --git a/odata2-lib/odata-fit/src/test/java/org/apache/olingo/odata2/fit/ref/AbstractRefTest.java b/odata2-lib/odata-fit/src/test/java/org/apache/olingo/odata2/fit/ref/AbstractRefTest.java
index de5f99e..d316b7f 100644
--- a/odata2-lib/odata-fit/src/test/java/org/apache/olingo/odata2/fit/ref/AbstractRefTest.java
+++ b/odata2-lib/odata-fit/src/test/java/org/apache/olingo/odata2/fit/ref/AbstractRefTest.java
@@ -35,12 +35,12 @@ import org.apache.http.client.methods.HttpPost;
 import org.apache.http.client.methods.HttpPut;
 import org.apache.http.client.methods.HttpRequestBase;
 import org.apache.http.entity.StringEntity;
+import org.apache.olingo.odata2.annotation.processor.core.ListsProcessor;
+import org.apache.olingo.odata2.annotation.processor.core.datasource.BeanPropertyAccess;
 import org.apache.olingo.odata2.api.commons.HttpStatusCodes;
 import org.apache.olingo.odata2.api.commons.ODataHttpMethod;
 import org.apache.olingo.odata2.api.edm.provider.EdmProvider;
 import org.apache.olingo.odata2.api.processor.ODataSingleProcessor;
-import org.apache.olingo.odata2.core.annotation.data.BeanPropertyAccess;
-import org.apache.olingo.odata2.core.annotation.processor.ListsProcessor;
 import org.apache.olingo.odata2.core.processor.ODataSingleProcessorService;
 import org.apache.olingo.odata2.ref.edm.ScenarioEdmProvider;
 import org.apache.olingo.odata2.ref.model.DataContainer;

http://git-wip-us.apache.org/repos/asf/incubator-olingo-odata2/blob/3bd59050/odata2-lib/odata-fit/src/test/java/org/apache/olingo/odata2/fit/ref/EntryXmlReadOnlyTest.java
----------------------------------------------------------------------
diff --git a/odata2-lib/odata-fit/src/test/java/org/apache/olingo/odata2/fit/ref/EntryXmlReadOnlyTest.java b/odata2-lib/odata-fit/src/test/java/org/apache/olingo/odata2/fit/ref/EntryXmlReadOnlyTest.java
index ab107ac..79cf938 100644
--- a/odata2-lib/odata-fit/src/test/java/org/apache/olingo/odata2/fit/ref/EntryXmlReadOnlyTest.java
+++ b/odata2-lib/odata-fit/src/test/java/org/apache/olingo/odata2/fit/ref/EntryXmlReadOnlyTest.java
@@ -28,9 +28,9 @@ import java.lang.reflect.Field;
 
 import org.apache.http.HttpHeaders;
 import org.apache.http.HttpResponse;
+import org.apache.olingo.odata2.annotation.processor.core.ListsProcessor;
 import org.apache.olingo.odata2.api.commons.HttpContentType;
 import org.apache.olingo.odata2.api.commons.HttpStatusCodes;
-import org.apache.olingo.odata2.core.annotation.processor.ListsProcessor;
 import org.apache.olingo.odata2.ref.model.DataContainer;
 import org.apache.olingo.odata2.ref.model.Photo;
 import org.apache.olingo.odata2.ref.processor.ScenarioDataSource;

http://git-wip-us.apache.org/repos/asf/incubator-olingo-odata2/blob/3bd59050/odata2-lib/odata-fit/src/test/java/org/apache/olingo/odata2/fit/ref/contentnegotiation/AbstractContentNegotiationTest.java
----------------------------------------------------------------------
diff --git a/odata2-lib/odata-fit/src/test/java/org/apache/olingo/odata2/fit/ref/contentnegotiation/AbstractContentNegotiationTest.java b/odata2-lib/odata-fit/src/test/java/org/apache/olingo/odata2/fit/ref/contentnegotiation/AbstractContentNegotiationTest.java
index 688532d..0a19c7f 100644
--- a/odata2-lib/odata-fit/src/test/java/org/apache/olingo/odata2/fit/ref/contentnegotiation/AbstractContentNegotiationTest.java
+++ b/odata2-lib/odata-fit/src/test/java/org/apache/olingo/odata2/fit/ref/contentnegotiation/AbstractContentNegotiationTest.java
@@ -42,6 +42,8 @@ import org.apache.http.client.methods.HttpPut;
 import org.apache.http.client.methods.HttpRequestBase;
 import org.apache.http.entity.StringEntity;
 import org.apache.http.impl.client.DefaultHttpClient;
+import org.apache.olingo.odata2.annotation.processor.core.ListsProcessor;
+import org.apache.olingo.odata2.annotation.processor.core.datasource.BeanPropertyAccess;
 import org.apache.olingo.odata2.api.ODataService;
 import org.apache.olingo.odata2.api.commons.HttpContentType;
 import org.apache.olingo.odata2.api.commons.HttpHeaders;
@@ -49,8 +51,6 @@ import org.apache.olingo.odata2.api.commons.HttpStatusCodes;
 import org.apache.olingo.odata2.api.edm.provider.EdmProvider;
 import org.apache.olingo.odata2.api.exception.ODataException;
 import org.apache.olingo.odata2.api.processor.ODataSingleProcessor;
-import org.apache.olingo.odata2.core.annotation.data.BeanPropertyAccess;
-import org.apache.olingo.odata2.core.annotation.processor.ListsProcessor;
 import org.apache.olingo.odata2.core.commons.ContentType;
 import org.apache.olingo.odata2.core.processor.ODataSingleProcessorService;
 import org.apache.olingo.odata2.core.uri.UriType;

http://git-wip-us.apache.org/repos/asf/incubator-olingo-odata2/blob/3bd59050/odata2-lib/odata-ref/src/main/java/org/apache/olingo/odata2/ref/processor/ScenarioDataSource.java
----------------------------------------------------------------------
diff --git a/odata2-lib/odata-ref/src/main/java/org/apache/olingo/odata2/ref/processor/ScenarioDataSource.java b/odata2-lib/odata-ref/src/main/java/org/apache/olingo/odata2/ref/processor/ScenarioDataSource.java
index cc70639..bba87b2 100644
--- a/odata2-lib/odata-ref/src/main/java/org/apache/olingo/odata2/ref/processor/ScenarioDataSource.java
+++ b/odata2-lib/odata-ref/src/main/java/org/apache/olingo/odata2/ref/processor/ScenarioDataSource.java
@@ -27,8 +27,8 @@ import java.util.List;
 import java.util.Map;
 import java.util.Map.Entry;
 
+import org.apache.olingo.odata2.annotation.processor.core.datasource.DataSource;
 import org.apache.olingo.odata2.api.commons.HttpContentType;
-import org.apache.olingo.odata2.api.data.DataSource;
 import org.apache.olingo.odata2.api.edm.EdmEntitySet;
 import org.apache.olingo.odata2.api.edm.EdmException;
 import org.apache.olingo.odata2.api.edm.EdmFunctionImport;

http://git-wip-us.apache.org/repos/asf/incubator-olingo-odata2/blob/3bd59050/odata2-lib/odata-ref/src/main/java/org/apache/olingo/odata2/ref/processor/ScenarioServiceFactory.java
----------------------------------------------------------------------
diff --git a/odata2-lib/odata-ref/src/main/java/org/apache/olingo/odata2/ref/processor/ScenarioServiceFactory.java b/odata2-lib/odata-ref/src/main/java/org/apache/olingo/odata2/ref/processor/ScenarioServiceFactory.java
index 08d6e16..f205aa2 100644
--- a/odata2-lib/odata-ref/src/main/java/org/apache/olingo/odata2/ref/processor/ScenarioServiceFactory.java
+++ b/odata2-lib/odata-ref/src/main/java/org/apache/olingo/odata2/ref/processor/ScenarioServiceFactory.java
@@ -18,14 +18,14 @@
  ******************************************************************************/
 package org.apache.olingo.odata2.ref.processor;
 
+import org.apache.olingo.odata2.annotation.processor.core.ListsProcessor;
+import org.apache.olingo.odata2.annotation.processor.core.datasource.BeanPropertyAccess;
 import org.apache.olingo.odata2.api.ODataCallback;
 import org.apache.olingo.odata2.api.ODataDebugCallback;
 import org.apache.olingo.odata2.api.ODataService;
 import org.apache.olingo.odata2.api.ODataServiceFactory;
 import org.apache.olingo.odata2.api.exception.ODataException;
 import org.apache.olingo.odata2.api.processor.ODataContext;
-import org.apache.olingo.odata2.core.annotation.data.BeanPropertyAccess;
-import org.apache.olingo.odata2.core.annotation.processor.ListsProcessor;
 import org.apache.olingo.odata2.ref.edm.ScenarioEdmProvider;
 import org.apache.olingo.odata2.ref.model.DataContainer;
 

http://git-wip-us.apache.org/repos/asf/incubator-olingo-odata2/blob/3bd59050/odata2-lib/odata-ref/src/test/java/org/apache/olingo/odata2/ref/read/EntitySetTest.java
----------------------------------------------------------------------
diff --git a/odata2-lib/odata-ref/src/test/java/org/apache/olingo/odata2/ref/read/EntitySetTest.java b/odata2-lib/odata-ref/src/test/java/org/apache/olingo/odata2/ref/read/EntitySetTest.java
index d07473d..0dadc30 100644
--- a/odata2-lib/odata-ref/src/test/java/org/apache/olingo/odata2/ref/read/EntitySetTest.java
+++ b/odata2-lib/odata-ref/src/test/java/org/apache/olingo/odata2/ref/read/EntitySetTest.java
@@ -30,6 +30,8 @@ import java.net.URI;
 import java.net.URISyntaxException;
 import java.nio.CharBuffer;
 
+import org.apache.olingo.odata2.annotation.processor.core.ListsProcessor;
+import org.apache.olingo.odata2.annotation.processor.core.datasource.BeanPropertyAccess;
 import org.apache.olingo.odata2.api.edm.EdmEntityContainer;
 import org.apache.olingo.odata2.api.edm.EdmEntitySet;
 import org.apache.olingo.odata2.api.edm.EdmEntityType;
@@ -38,8 +40,6 @@ import org.apache.olingo.odata2.api.processor.ODataContext;
 import org.apache.olingo.odata2.api.processor.ODataResponse;
 import org.apache.olingo.odata2.api.uri.PathInfo;
 import org.apache.olingo.odata2.api.uri.UriInfo;
-import org.apache.olingo.odata2.core.annotation.data.BeanPropertyAccess;
-import org.apache.olingo.odata2.core.annotation.processor.ListsProcessor;
 import org.apache.olingo.odata2.core.commons.ContentType;
 import org.apache.olingo.odata2.ref.model.DataContainer;
 import org.apache.olingo.odata2.ref.processor.ScenarioDataSource;

http://git-wip-us.apache.org/repos/asf/incubator-olingo-odata2/blob/3bd59050/odata2-lib/odata-ref/src/test/java/org/apache/olingo/odata2/ref/read/EntityTest.java
----------------------------------------------------------------------
diff --git a/odata2-lib/odata-ref/src/test/java/org/apache/olingo/odata2/ref/read/EntityTest.java b/odata2-lib/odata-ref/src/test/java/org/apache/olingo/odata2/ref/read/EntityTest.java
index be55778..28827d1 100644
--- a/odata2-lib/odata-ref/src/test/java/org/apache/olingo/odata2/ref/read/EntityTest.java
+++ b/odata2-lib/odata-ref/src/test/java/org/apache/olingo/odata2/ref/read/EntityTest.java
@@ -31,6 +31,8 @@ import java.nio.CharBuffer;
 import java.util.ArrayList;
 import java.util.Arrays;
 
+import org.apache.olingo.odata2.annotation.processor.core.ListsProcessor;
+import org.apache.olingo.odata2.annotation.processor.core.datasource.BeanPropertyAccess;
 import org.apache.olingo.odata2.api.edm.EdmEntityContainer;
 import org.apache.olingo.odata2.api.edm.EdmEntitySet;
 import org.apache.olingo.odata2.api.edm.EdmEntityType;
@@ -43,8 +45,6 @@ import org.apache.olingo.odata2.api.processor.ODataResponse;
 import org.apache.olingo.odata2.api.uri.KeyPredicate;
 import org.apache.olingo.odata2.api.uri.PathInfo;
 import org.apache.olingo.odata2.api.uri.UriInfo;
-import org.apache.olingo.odata2.core.annotation.data.BeanPropertyAccess;
-import org.apache.olingo.odata2.core.annotation.processor.ListsProcessor;
 import org.apache.olingo.odata2.core.commons.ContentType;
 import org.apache.olingo.odata2.ref.model.DataContainer;
 import org.apache.olingo.odata2.ref.processor.ScenarioDataSource;


[08/12] [OLINGO-83] Refactoring of 'annotation-processor-*' modules

Posted by tb...@apache.org.
http://git-wip-us.apache.org/repos/asf/incubator-olingo-odata2/blob/3bd59050/odata2-annotation-processor/annotation-processor-core/src/main/java/org/apache/olingo/odata2/annotation/processor/core/ListsProcessor.java
----------------------------------------------------------------------
diff --git a/odata2-annotation-processor/annotation-processor-core/src/main/java/org/apache/olingo/odata2/annotation/processor/core/ListsProcessor.java b/odata2-annotation-processor/annotation-processor-core/src/main/java/org/apache/olingo/odata2/annotation/processor/core/ListsProcessor.java
new file mode 100644
index 0000000..85e011c
--- /dev/null
+++ b/odata2-annotation-processor/annotation-processor-core/src/main/java/org/apache/olingo/odata2/annotation/processor/core/ListsProcessor.java
@@ -0,0 +1,1640 @@
+/*******************************************************************************
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License. You may obtain a copy of the License at
+ * 
+ * http://www.apache.org/licenses/LICENSE-2.0
+ * 
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied. See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ ******************************************************************************/
+package org.apache.olingo.odata2.annotation.processor.core;
+
+import java.io.InputStream;
+import java.util.ArrayList;
+import java.util.Arrays;
+import java.util.Collections;
+import java.util.Comparator;
+import java.util.HashMap;
+import java.util.Iterator;
+import java.util.List;
+import java.util.Locale;
+import java.util.Map;
+
+import org.apache.olingo.odata2.annotation.processor.core.datasource.DataSource;
+import org.apache.olingo.odata2.annotation.processor.core.datasource.ValueAccess;
+import org.apache.olingo.odata2.annotation.processor.core.datasource.DataSource.BinaryData;
+import org.apache.olingo.odata2.api.ODataCallback;
+import org.apache.olingo.odata2.api.batch.BatchHandler;
+import org.apache.olingo.odata2.api.batch.BatchRequestPart;
+import org.apache.olingo.odata2.api.batch.BatchResponsePart;
+import org.apache.olingo.odata2.api.commons.HttpContentType;
+import org.apache.olingo.odata2.api.commons.HttpStatusCodes;
+import org.apache.olingo.odata2.api.commons.InlineCount;
+import org.apache.olingo.odata2.api.edm.Edm;
+import org.apache.olingo.odata2.api.edm.EdmConcurrencyMode;
+import org.apache.olingo.odata2.api.edm.EdmEntitySet;
+import org.apache.olingo.odata2.api.edm.EdmEntityType;
+import org.apache.olingo.odata2.api.edm.EdmException;
+import org.apache.olingo.odata2.api.edm.EdmFunctionImport;
+import org.apache.olingo.odata2.api.edm.EdmLiteral;
+import org.apache.olingo.odata2.api.edm.EdmLiteralKind;
+import org.apache.olingo.odata2.api.edm.EdmMapping;
+import org.apache.olingo.odata2.api.edm.EdmMultiplicity;
+import org.apache.olingo.odata2.api.edm.EdmNavigationProperty;
+import org.apache.olingo.odata2.api.edm.EdmProperty;
+import org.apache.olingo.odata2.api.edm.EdmSimpleType;
+import org.apache.olingo.odata2.api.edm.EdmSimpleTypeException;
+import org.apache.olingo.odata2.api.edm.EdmSimpleTypeKind;
+import org.apache.olingo.odata2.api.edm.EdmStructuralType;
+import org.apache.olingo.odata2.api.edm.EdmType;
+import org.apache.olingo.odata2.api.edm.EdmTypeKind;
+import org.apache.olingo.odata2.api.edm.EdmTyped;
+import org.apache.olingo.odata2.api.ep.EntityProvider;
+import org.apache.olingo.odata2.api.ep.EntityProviderBatchProperties;
+import org.apache.olingo.odata2.api.ep.EntityProviderException;
+import org.apache.olingo.odata2.api.ep.EntityProviderReadProperties;
+import org.apache.olingo.odata2.api.ep.EntityProviderWriteProperties;
+import org.apache.olingo.odata2.api.ep.callback.OnWriteEntryContent;
+import org.apache.olingo.odata2.api.ep.callback.OnWriteFeedContent;
+import org.apache.olingo.odata2.api.ep.callback.WriteCallbackContext;
+import org.apache.olingo.odata2.api.ep.callback.WriteEntryCallbackContext;
+import org.apache.olingo.odata2.api.ep.callback.WriteEntryCallbackResult;
+import org.apache.olingo.odata2.api.ep.callback.WriteFeedCallbackContext;
+import org.apache.olingo.odata2.api.ep.callback.WriteFeedCallbackResult;
+import org.apache.olingo.odata2.api.ep.entry.ODataEntry;
+import org.apache.olingo.odata2.api.ep.feed.ODataFeed;
+import org.apache.olingo.odata2.api.exception.ODataApplicationException;
+import org.apache.olingo.odata2.api.exception.ODataBadRequestException;
+import org.apache.olingo.odata2.api.exception.ODataException;
+import org.apache.olingo.odata2.api.exception.ODataHttpException;
+import org.apache.olingo.odata2.api.exception.ODataNotFoundException;
+import org.apache.olingo.odata2.api.exception.ODataNotImplementedException;
+import org.apache.olingo.odata2.api.processor.ODataContext;
+import org.apache.olingo.odata2.api.processor.ODataRequest;
+import org.apache.olingo.odata2.api.processor.ODataResponse;
+import org.apache.olingo.odata2.api.uri.ExpandSelectTreeNode;
+import org.apache.olingo.odata2.api.uri.KeyPredicate;
+import org.apache.olingo.odata2.api.uri.NavigationSegment;
+import org.apache.olingo.odata2.api.uri.PathInfo;
+import org.apache.olingo.odata2.api.uri.UriParser;
+import org.apache.olingo.odata2.api.uri.expression.BinaryExpression;
+import org.apache.olingo.odata2.api.uri.expression.CommonExpression;
+import org.apache.olingo.odata2.api.uri.expression.ExpressionKind;
+import org.apache.olingo.odata2.api.uri.expression.FilterExpression;
+import org.apache.olingo.odata2.api.uri.expression.LiteralExpression;
+import org.apache.olingo.odata2.api.uri.expression.MemberExpression;
+import org.apache.olingo.odata2.api.uri.expression.MethodExpression;
+import org.apache.olingo.odata2.api.uri.expression.OrderByExpression;
+import org.apache.olingo.odata2.api.uri.expression.OrderExpression;
+import org.apache.olingo.odata2.api.uri.expression.PropertyExpression;
+import org.apache.olingo.odata2.api.uri.expression.SortOrder;
+import org.apache.olingo.odata2.api.uri.expression.UnaryExpression;
+import org.apache.olingo.odata2.api.uri.info.DeleteUriInfo;
+import org.apache.olingo.odata2.api.uri.info.GetComplexPropertyUriInfo;
+import org.apache.olingo.odata2.api.uri.info.GetEntityCountUriInfo;
+import org.apache.olingo.odata2.api.uri.info.GetEntityLinkCountUriInfo;
+import org.apache.olingo.odata2.api.uri.info.GetEntityLinkUriInfo;
+import org.apache.olingo.odata2.api.uri.info.GetEntitySetCountUriInfo;
+import org.apache.olingo.odata2.api.uri.info.GetEntitySetLinksCountUriInfo;
+import org.apache.olingo.odata2.api.uri.info.GetEntitySetLinksUriInfo;
+import org.apache.olingo.odata2.api.uri.info.GetEntitySetUriInfo;
+import org.apache.olingo.odata2.api.uri.info.GetEntityUriInfo;
+import org.apache.olingo.odata2.api.uri.info.GetFunctionImportUriInfo;
+import org.apache.olingo.odata2.api.uri.info.GetMediaResourceUriInfo;
+import org.apache.olingo.odata2.api.uri.info.GetSimplePropertyUriInfo;
+import org.apache.olingo.odata2.api.uri.info.PostUriInfo;
+import org.apache.olingo.odata2.api.uri.info.PutMergePatchUriInfo;
+
+/**
+ * Implementation of the centralized parts of OData processing,
+ * allowing to use the simplified {@link DataSource} for the
+ * actual data handling.
+ * 
+ */
+public class ListsProcessor extends DataSourceProcessor {
+
+  // TODO: Paging size should be configurable.
+  private static final int SERVER_PAGING_SIZE = 100;
+
+  public ListsProcessor(final DataSource dataSource, final ValueAccess valueAccess) {
+    super(dataSource, valueAccess);
+  }
+
+  @Override
+  public ODataResponse readEntitySet(final GetEntitySetUriInfo uriInfo, final String contentType)
+      throws ODataException {
+    ArrayList<Object> data = new ArrayList<Object>();
+    try {
+      data.addAll((List<?>) retrieveData(
+          uriInfo.getStartEntitySet(),
+          uriInfo.getKeyPredicates(),
+          uriInfo.getFunctionImport(),
+          mapFunctionParameters(uriInfo.getFunctionImportParameters()),
+          uriInfo.getNavigationSegments()));
+    } catch (final ODataNotFoundException e) {
+      data.clear();
+    }
+
+    final EdmEntitySet entitySet = uriInfo.getTargetEntitySet();
+    final InlineCount inlineCountType = uriInfo.getInlineCount();
+    final Integer count = applySystemQueryOptions(
+        entitySet,
+        data,
+        uriInfo.getFilter(),
+        inlineCountType,
+        uriInfo.getOrderBy(),
+        uriInfo.getSkipToken(),
+        uriInfo.getSkip(),
+        uriInfo.getTop());
+
+    ODataContext context = getContext();
+    String nextLink = null;
+
+    // Limit the number of returned entities and provide a "next" link
+    // if there are further entities.
+    // Almost all system query options in the current request must be carried
+    // over to the URI for the "next" link, with the exception of $skiptoken
+    // and $skip.
+    if (data.size() > SERVER_PAGING_SIZE) {
+      if (uriInfo.getOrderBy() == null
+          && uriInfo.getSkipToken() == null
+          && uriInfo.getSkip() == null
+          && uriInfo.getTop() == null) {
+        sortInDefaultOrder(entitySet, data);
+      }
+
+      // TODO: Percent-encode "next" link.
+      nextLink = context.getPathInfo().getServiceRoot().relativize(context.getPathInfo().getRequestUri()).toString()
+          .replaceAll("\\$skiptoken=.+?&?", "")
+          .replaceAll("\\$skip=.+?&?", "")
+          .replaceFirst("(?:\\?|&)$", ""); // Remove potentially trailing "?" or "&" left over from remove actions
+                                           // above.
+      nextLink += (nextLink.contains("?") ? "&" : "?")
+          + "$skiptoken=" + getSkipToken(entitySet, data.get(SERVER_PAGING_SIZE));
+
+      while (data.size() > SERVER_PAGING_SIZE) {
+        data.remove(SERVER_PAGING_SIZE);
+      }
+    }
+
+    final EdmEntityType entityType = entitySet.getEntityType();
+    List<Map<String, Object>> values = new ArrayList<Map<String, Object>>();
+    for (final Object entryData : data) {
+      values.add(getStructuralTypeValueMap(entryData, entityType));
+    }
+
+    final EntityProviderWriteProperties feedProperties = EntityProviderWriteProperties
+        .serviceRoot(context.getPathInfo().getServiceRoot())
+        .inlineCountType(inlineCountType)
+        .inlineCount(count)
+        .expandSelectTree(UriParser.createExpandSelectTree(uriInfo.getSelect(), uriInfo.getExpand()))
+        .callbacks(getCallbacks(data, entityType))
+        .nextLink(nextLink)
+        .build();
+
+    final int timingHandle = context.startRuntimeMeasurement("EntityProvider", "writeFeed");
+    final ODataResponse response = EntityProvider.writeFeed(contentType, entitySet, values, feedProperties);
+
+    context.stopRuntimeMeasurement(timingHandle);
+
+    return ODataResponse.fromResponse(response).build();
+  }
+
+  @Override
+  public ODataResponse countEntitySet(final GetEntitySetCountUriInfo uriInfo, final String contentType)
+      throws ODataException {
+    ArrayList<Object> data = new ArrayList<Object>();
+    try {
+      data.addAll((List<?>) retrieveData(
+          uriInfo.getStartEntitySet(),
+          uriInfo.getKeyPredicates(),
+          uriInfo.getFunctionImport(),
+          mapFunctionParameters(uriInfo.getFunctionImportParameters()),
+          uriInfo.getNavigationSegments()));
+    } catch (final ODataNotFoundException e) {
+      data.clear();
+    }
+
+    applySystemQueryOptions(
+        uriInfo.getTargetEntitySet(),
+        data,
+        uriInfo.getFilter(),
+        null,
+        null,
+        null,
+        uriInfo.getSkip(),
+        uriInfo.getTop());
+
+    return ODataResponse.fromResponse(EntityProvider.writeText(String.valueOf(data.size()))).build();
+  }
+
+  @Override
+  public ODataResponse readEntityLinks(final GetEntitySetLinksUriInfo uriInfo, final String contentType)
+      throws ODataException {
+    ArrayList<Object> data = new ArrayList<Object>();
+    try {
+      data.addAll((List<?>) retrieveData(
+          uriInfo.getStartEntitySet(),
+          uriInfo.getKeyPredicates(),
+          uriInfo.getFunctionImport(),
+          mapFunctionParameters(uriInfo.getFunctionImportParameters()),
+          uriInfo.getNavigationSegments()));
+    } catch (final ODataNotFoundException e) {
+      data.clear();
+    }
+
+    final Integer count = applySystemQueryOptions(
+        uriInfo.getTargetEntitySet(),
+        data,
+        uriInfo.getFilter(),
+        uriInfo.getInlineCount(),
+        null, // uriInfo.getOrderBy(),
+        uriInfo.getSkipToken(),
+        uriInfo.getSkip(),
+        uriInfo.getTop());
+
+    final EdmEntitySet entitySet = uriInfo.getTargetEntitySet();
+
+    List<Map<String, Object>> values = new ArrayList<Map<String, Object>>();
+    for (final Object entryData : data) {
+      Map<String, Object> entryValues = new HashMap<String, Object>();
+      for (final EdmProperty property : entitySet.getEntityType().getKeyProperties()) {
+        entryValues.put(property.getName(), valueAccess.getPropertyValue(entryData, property));
+      }
+      values.add(entryValues);
+    }
+
+    ODataContext context = getContext();
+    final EntityProviderWriteProperties entryProperties = EntityProviderWriteProperties
+        .serviceRoot(context.getPathInfo().getServiceRoot())
+        .inlineCountType(uriInfo.getInlineCount())
+        .inlineCount(count)
+        .build();
+
+    final int timingHandle = context.startRuntimeMeasurement("EntityProvider", "writeLinks");
+
+    final ODataResponse response = EntityProvider.writeLinks(contentType, entitySet, values, entryProperties);
+
+    context.stopRuntimeMeasurement(timingHandle);
+
+    return ODataResponse.fromResponse(response).build();
+  }
+
+  @Override
+  public ODataResponse countEntityLinks(final GetEntitySetLinksCountUriInfo uriInfo, final String contentType)
+      throws ODataException {
+    return countEntitySet((GetEntitySetCountUriInfo) uriInfo, contentType);
+  }
+
+  @Override
+  public ODataResponse readEntity(final GetEntityUriInfo uriInfo, final String contentType) throws ODataException {
+    final Object data = retrieveData(
+        uriInfo.getStartEntitySet(),
+        uriInfo.getKeyPredicates(),
+        uriInfo.getFunctionImport(),
+        mapFunctionParameters(uriInfo.getFunctionImportParameters()),
+        uriInfo.getNavigationSegments());
+
+    if (!appliesFilter(data, uriInfo.getFilter())) {
+      throw new ODataNotFoundException(ODataNotFoundException.ENTITY);
+    }
+
+    final ExpandSelectTreeNode expandSelectTreeNode =
+        UriParser.createExpandSelectTree(uriInfo.getSelect(), uriInfo.getExpand());
+    ODataResponse odr =
+        ODataResponse.fromResponse(writeEntry(uriInfo.getTargetEntitySet(), expandSelectTreeNode, data, contentType))
+            .build();
+
+    return odr;
+  }
+
+  @Override
+  public ODataResponse existsEntity(final GetEntityCountUriInfo uriInfo, final String contentType)
+      throws ODataException {
+    final Object data = retrieveData(
+        uriInfo.getStartEntitySet(),
+        uriInfo.getKeyPredicates(),
+        uriInfo.getFunctionImport(),
+        mapFunctionParameters(uriInfo.getFunctionImportParameters()),
+        uriInfo.getNavigationSegments());
+
+    return ODataResponse.fromResponse(EntityProvider.writeText(appliesFilter(data, uriInfo.getFilter()) ? "1" : "0"))
+        .build();
+  }
+
+  @Override
+  public ODataResponse deleteEntity(final DeleteUriInfo uriInfo, final String contentType) throws ODataException {
+    dataSource.deleteData(
+        uriInfo.getStartEntitySet(),
+        mapKey(uriInfo.getKeyPredicates()));
+    return ODataResponse.newBuilder().build();
+  }
+
+  @Override
+  public ODataResponse createEntity(final PostUriInfo uriInfo, final InputStream content,
+      final String requestContentType, final String contentType) throws ODataException {
+    final EdmEntitySet entitySet = uriInfo.getTargetEntitySet();
+    final EdmEntityType entityType = entitySet.getEntityType();
+
+    Object data = dataSource.newDataObject(entitySet);
+    ExpandSelectTreeNode expandSelectTree = null;
+
+    if (entityType.hasStream()) {
+      dataSource.createData(entitySet, data);
+      dataSource.writeBinaryData(entitySet, data,
+          new BinaryData(EntityProvider.readBinary(content), requestContentType));
+
+    } else {
+      final EntityProviderReadProperties properties = EntityProviderReadProperties.init()
+          .mergeSemantic(false)
+          .addTypeMappings(getStructuralTypeTypeMap(data, entityType))
+          .build();
+      final ODataEntry entryValues = parseEntry(entitySet, content, requestContentType, properties);
+
+      setStructuralTypeValuesFromMap(data, entityType, entryValues.getProperties(), false);
+
+      dataSource.createData(entitySet, data);
+
+      createInlinedEntities(entitySet, data, entryValues);
+
+      expandSelectTree = entryValues.getExpandSelectTree();
+    }
+
+    // Link back to the entity the target entity set is related to, if any.
+    final List<NavigationSegment> navigationSegments = uriInfo.getNavigationSegments();
+    if (!navigationSegments.isEmpty()) {
+      final List<NavigationSegment> previousSegments = navigationSegments.subList(0, navigationSegments.size() - 1);
+      final Object sourceData = retrieveData(
+          uriInfo.getStartEntitySet(),
+          uriInfo.getKeyPredicates(),
+          uriInfo.getFunctionImport(),
+          mapFunctionParameters(uriInfo.getFunctionImportParameters()),
+          previousSegments);
+      final EdmEntitySet previousEntitySet = previousSegments.isEmpty() ?
+          uriInfo.getStartEntitySet() : previousSegments.get(previousSegments.size() - 1).getEntitySet();
+      dataSource.writeRelation(previousEntitySet, sourceData, entitySet, getStructuralTypeValueMap(data, entityType));
+    }
+
+    return ODataResponse.fromResponse(writeEntry(uriInfo.getTargetEntitySet(), expandSelectTree, data, contentType))
+        .eTag(constructETag(entitySet, data)).build();
+  }
+
+  @Override
+  public ODataResponse updateEntity(final PutMergePatchUriInfo uriInfo, final InputStream content,
+      final String requestContentType, final boolean merge, final String contentType) throws ODataException {
+    Object data = retrieveData(
+        uriInfo.getStartEntitySet(),
+        uriInfo.getKeyPredicates(),
+        uriInfo.getFunctionImport(),
+        mapFunctionParameters(uriInfo.getFunctionImportParameters()),
+        uriInfo.getNavigationSegments());
+
+    if (!appliesFilter(data, uriInfo.getFilter())) {
+      throw new ODataNotFoundException(ODataNotFoundException.ENTITY);
+    }
+
+    final EdmEntitySet entitySet = uriInfo.getTargetEntitySet();
+    final EdmEntityType entityType = entitySet.getEntityType();
+    final EntityProviderReadProperties properties = EntityProviderReadProperties.init()
+        .mergeSemantic(merge)
+        .addTypeMappings(getStructuralTypeTypeMap(data, entityType))
+        .build();
+    final ODataEntry entryValues = parseEntry(entitySet, content, requestContentType, properties);
+
+    setStructuralTypeValuesFromMap(data, entityType, entryValues.getProperties(), merge);
+
+    return ODataResponse.newBuilder().eTag(constructETag(entitySet, data)).build();
+  }
+
+  @Override
+  public ODataResponse readEntityLink(final GetEntityLinkUriInfo uriInfo, final String contentType)
+      throws ODataException {
+    final Object data = retrieveData(
+        uriInfo.getStartEntitySet(),
+        uriInfo.getKeyPredicates(),
+        uriInfo.getFunctionImport(),
+        mapFunctionParameters(uriInfo.getFunctionImportParameters()),
+        uriInfo.getNavigationSegments());
+
+    // if (!appliesFilter(data, uriInfo.getFilter()))
+    if (data == null) {
+      throw new ODataNotFoundException(ODataNotFoundException.ENTITY);
+    }
+
+    final EdmEntitySet entitySet = uriInfo.getTargetEntitySet();
+
+    Map<String, Object> values = new HashMap<String, Object>();
+    for (final EdmProperty property : entitySet.getEntityType().getKeyProperties()) {
+      values.put(property.getName(), valueAccess.getPropertyValue(data, property));
+    }
+
+    ODataContext context = getContext();
+    final EntityProviderWriteProperties entryProperties = EntityProviderWriteProperties
+        .serviceRoot(context.getPathInfo().getServiceRoot())
+        .build();
+
+    final int timingHandle = context.startRuntimeMeasurement("EntityProvider", "writeLink");
+
+    final ODataResponse response = EntityProvider.writeLink(contentType, entitySet, values, entryProperties);
+
+    context.stopRuntimeMeasurement(timingHandle);
+
+    return ODataResponse.fromResponse(response).build();
+  }
+
+  @Override
+  public ODataResponse existsEntityLink(final GetEntityLinkCountUriInfo uriInfo, final String contentType)
+      throws ODataException {
+    return existsEntity((GetEntityCountUriInfo) uriInfo, contentType);
+  }
+
+  @Override
+  public ODataResponse deleteEntityLink(final DeleteUriInfo uriInfo, final String contentType) throws ODataException {
+    final List<NavigationSegment> navigationSegments = uriInfo.getNavigationSegments();
+    final List<NavigationSegment> previousSegments = navigationSegments.subList(0, navigationSegments.size() - 1);
+
+    final Object sourceData = retrieveData(
+        uriInfo.getStartEntitySet(),
+        uriInfo.getKeyPredicates(),
+        uriInfo.getFunctionImport(),
+        mapFunctionParameters(uriInfo.getFunctionImportParameters()),
+        previousSegments);
+
+    final EdmEntitySet entitySet = previousSegments.isEmpty() ?
+        uriInfo.getStartEntitySet() : previousSegments.get(previousSegments.size() - 1).getEntitySet();
+    final EdmEntitySet targetEntitySet = uriInfo.getTargetEntitySet();
+    final Map<String, Object> keys = mapKey(uriInfo.getTargetKeyPredicates());
+
+    final Object targetData = dataSource.readRelatedData(entitySet, sourceData, targetEntitySet, keys);
+
+    // if (!appliesFilter(targetData, uriInfo.getFilter()))
+    if (targetData == null) {
+      throw new ODataNotFoundException(ODataNotFoundException.ENTITY);
+    }
+
+    dataSource.deleteRelation(entitySet, sourceData, targetEntitySet, keys);
+
+    return ODataResponse.newBuilder().build();
+  }
+
+  @Override
+  public ODataResponse createEntityLink(final PostUriInfo uriInfo, final InputStream content,
+      final String requestContentType, final String contentType) throws ODataException {
+    final List<NavigationSegment> navigationSegments = uriInfo.getNavigationSegments();
+    final List<NavigationSegment> previousSegments = navigationSegments.subList(0, navigationSegments.size() - 1);
+
+    final Object sourceData = retrieveData(
+        uriInfo.getStartEntitySet(),
+        uriInfo.getKeyPredicates(),
+        uriInfo.getFunctionImport(),
+        mapFunctionParameters(uriInfo.getFunctionImportParameters()),
+        previousSegments);
+
+    final EdmEntitySet entitySet = previousSegments.isEmpty() ?
+        uriInfo.getStartEntitySet() : previousSegments.get(previousSegments.size() - 1).getEntitySet();
+    final EdmEntitySet targetEntitySet = uriInfo.getTargetEntitySet();
+
+    final Map<String, Object> targetKeys = parseLink(targetEntitySet, content, requestContentType);
+
+    dataSource.writeRelation(entitySet, sourceData, targetEntitySet, targetKeys);
+
+    return ODataResponse.newBuilder().build();
+  }
+
+  @Override
+  public ODataResponse updateEntityLink(final PutMergePatchUriInfo uriInfo, final InputStream content,
+      final String requestContentType, final String contentType) throws ODataException {
+    final List<NavigationSegment> navigationSegments = uriInfo.getNavigationSegments();
+    final List<NavigationSegment> previousSegments = navigationSegments.subList(0, navigationSegments.size() - 1);
+
+    final Object sourceData = retrieveData(
+        uriInfo.getStartEntitySet(),
+        uriInfo.getKeyPredicates(),
+        uriInfo.getFunctionImport(),
+        mapFunctionParameters(uriInfo.getFunctionImportParameters()),
+        previousSegments);
+
+    final EdmEntitySet entitySet = previousSegments.isEmpty() ?
+        uriInfo.getStartEntitySet() : previousSegments.get(previousSegments.size() - 1).getEntitySet();
+    final EdmEntitySet targetEntitySet = uriInfo.getTargetEntitySet();
+    final Map<String, Object> keys = mapKey(uriInfo.getTargetKeyPredicates());
+
+    final Object targetData = dataSource.readRelatedData(entitySet, sourceData, targetEntitySet, keys);
+
+    if (!appliesFilter(targetData, uriInfo.getFilter())) {
+      throw new ODataNotFoundException(ODataNotFoundException.ENTITY);
+    }
+
+    dataSource.deleteRelation(entitySet, sourceData, targetEntitySet, keys);
+
+    final Map<String, Object> newKeys = parseLink(targetEntitySet, content, requestContentType);
+
+    dataSource.writeRelation(entitySet, sourceData, targetEntitySet, newKeys);
+
+    return ODataResponse.newBuilder().build();
+  }
+
+  @Override
+  public ODataResponse readEntityComplexProperty(final GetComplexPropertyUriInfo uriInfo, final String contentType)
+      throws ODataException {
+    Object data = retrieveData(
+        uriInfo.getStartEntitySet(),
+        uriInfo.getKeyPredicates(),
+        uriInfo.getFunctionImport(),
+        mapFunctionParameters(uriInfo.getFunctionImportParameters()),
+        uriInfo.getNavigationSegments());
+
+    // if (!appliesFilter(data, uriInfo.getFilter()))
+    if (data == null) {
+      throw new ODataNotFoundException(ODataNotFoundException.ENTITY);
+    }
+
+    final List<EdmProperty> propertyPath = uriInfo.getPropertyPath();
+    final EdmProperty property = propertyPath.get(propertyPath.size() - 1);
+    final Object value = property.isSimple() ?
+        property.getMapping() == null || property.getMapping().getMimeType() == null ?
+            getPropertyValue(data, propertyPath) : getSimpleTypeValueMap(data, propertyPath) :
+        getStructuralTypeValueMap(getPropertyValue(data, propertyPath), (EdmStructuralType) property.getType());
+
+    ODataContext context = getContext();
+    final int timingHandle = context.startRuntimeMeasurement("EntityProvider", "writeProperty");
+
+    final ODataResponse response = EntityProvider.writeProperty(contentType, property, value);
+
+    context.stopRuntimeMeasurement(timingHandle);
+
+    return ODataResponse.fromResponse(response).eTag(constructETag(uriInfo.getTargetEntitySet(), data)).build();
+  }
+
+  @Override
+  public ODataResponse readEntitySimpleProperty(final GetSimplePropertyUriInfo uriInfo, final String contentType)
+      throws ODataException {
+    return readEntityComplexProperty((GetComplexPropertyUriInfo) uriInfo, contentType);
+  }
+
+  @Override
+  public ODataResponse readEntitySimplePropertyValue(final GetSimplePropertyUriInfo uriInfo, final String contentType)
+      throws ODataException {
+    Object data = retrieveData(
+        uriInfo.getStartEntitySet(),
+        uriInfo.getKeyPredicates(),
+        uriInfo.getFunctionImport(),
+        mapFunctionParameters(uriInfo.getFunctionImportParameters()),
+        uriInfo.getNavigationSegments());
+
+    // if (!appliesFilter(data, uriInfo.getFilter()))
+    if (data == null) {
+      throw new ODataNotFoundException(ODataNotFoundException.ENTITY);
+    }
+
+    final List<EdmProperty> propertyPath = uriInfo.getPropertyPath();
+    final EdmProperty property = propertyPath.get(propertyPath.size() - 1);
+    final Object value = property.getMapping() == null || property.getMapping().getMimeType() == null ?
+        getPropertyValue(data, propertyPath) : getSimpleTypeValueMap(data, propertyPath);
+
+    return ODataResponse.fromResponse(EntityProvider.writePropertyValue(property, value)).eTag(
+        constructETag(uriInfo.getTargetEntitySet(), data)).build();
+  }
+
+  @Override
+  public ODataResponse deleteEntitySimplePropertyValue(final DeleteUriInfo uriInfo, final String contentType)
+      throws ODataException {
+    Object data = retrieveData(
+        uriInfo.getStartEntitySet(),
+        uriInfo.getKeyPredicates(),
+        uriInfo.getFunctionImport(),
+        mapFunctionParameters(uriInfo.getFunctionImportParameters()),
+        uriInfo.getNavigationSegments());
+
+    if (data == null) {
+      throw new ODataNotFoundException(ODataNotFoundException.ENTITY);
+    }
+
+    final List<EdmProperty> propertyPath = uriInfo.getPropertyPath();
+    final EdmProperty property = propertyPath.get(propertyPath.size() - 1);
+
+    data = getPropertyValue(data, propertyPath.subList(0, propertyPath.size() - 1));
+    valueAccess.setPropertyValue(data, property, null);
+    valueAccess.setMappingValue(data, property.getMapping(), null);
+
+    return ODataResponse.newBuilder().build();
+  }
+
+  @Override
+  public ODataResponse updateEntityComplexProperty(final PutMergePatchUriInfo uriInfo, final InputStream content,
+      final String requestContentType, final boolean merge, final String contentType) throws ODataException {
+    Object data = retrieveData(
+        uriInfo.getStartEntitySet(),
+        uriInfo.getKeyPredicates(),
+        uriInfo.getFunctionImport(),
+        mapFunctionParameters(uriInfo.getFunctionImportParameters()),
+        uriInfo.getNavigationSegments());
+
+    if (!appliesFilter(data, uriInfo.getFilter())) {
+      throw new ODataNotFoundException(ODataNotFoundException.ENTITY);
+    }
+
+    final List<EdmProperty> propertyPath = uriInfo.getPropertyPath();
+    final EdmProperty property = propertyPath.get(propertyPath.size() - 1);
+
+    data = getPropertyValue(data, propertyPath.subList(0, propertyPath.size() - 1));
+
+    ODataContext context = getContext();
+    int timingHandle = context.startRuntimeMeasurement("EntityConsumer", "readProperty");
+
+    Map<String, Object> values;
+    try {
+      values =
+          EntityProvider.readProperty(requestContentType, property, content, EntityProviderReadProperties.init()
+              .mergeSemantic(merge).build());
+    } catch (final EntityProviderException e) {
+      throw new ODataBadRequestException(ODataBadRequestException.BODY, e);
+    }
+
+    context.stopRuntimeMeasurement(timingHandle);
+
+    final Object value = values.get(property.getName());
+    if (property.isSimple()) {
+      valueAccess.setPropertyValue(data, property, value);
+    } else {
+      @SuppressWarnings("unchecked")
+      final Map<String, Object> propertyValue = (Map<String, Object>) value;
+      setStructuralTypeValuesFromMap(valueAccess.getPropertyValue(data, property),
+          (EdmStructuralType) property.getType(), propertyValue, merge);
+    }
+
+    return ODataResponse.newBuilder().eTag(constructETag(uriInfo.getTargetEntitySet(), data)).build();
+  }
+
+  @Override
+  public ODataResponse updateEntitySimpleProperty(final PutMergePatchUriInfo uriInfo, final InputStream content,
+      final String requestContentType, final String contentType) throws ODataException {
+    return updateEntityComplexProperty(uriInfo, content, requestContentType, false, contentType);
+  }
+
+  @Override
+  public ODataResponse updateEntitySimplePropertyValue(final PutMergePatchUriInfo uriInfo, final InputStream content,
+      final String requestContentType, final String contentType) throws ODataException {
+    Object data = retrieveData(
+        uriInfo.getStartEntitySet(),
+        uriInfo.getKeyPredicates(),
+        uriInfo.getFunctionImport(),
+        mapFunctionParameters(uriInfo.getFunctionImportParameters()),
+        uriInfo.getNavigationSegments());
+
+    if (!appliesFilter(data, uriInfo.getFilter())) {
+      throw new ODataNotFoundException(ODataNotFoundException.ENTITY);
+    }
+
+    final List<EdmProperty> propertyPath = uriInfo.getPropertyPath();
+    final EdmProperty property = propertyPath.get(propertyPath.size() - 1);
+
+    data = getPropertyValue(data, propertyPath.subList(0, propertyPath.size() - 1));
+
+    ODataContext context = getContext();
+    int timingHandle = context.startRuntimeMeasurement("EntityConsumer", "readPropertyValue");
+
+    Object value;
+    try {
+      value = EntityProvider.readPropertyValue(property, content);
+    } catch (final EntityProviderException e) {
+      throw new ODataBadRequestException(ODataBadRequestException.BODY, e);
+    }
+
+    context.stopRuntimeMeasurement(timingHandle);
+
+    valueAccess.setPropertyValue(data, property, value);
+    valueAccess.setMappingValue(data, property.getMapping(), requestContentType);
+
+    return ODataResponse.newBuilder().eTag(constructETag(uriInfo.getTargetEntitySet(), data)).build();
+  }
+
+  @Override
+  public ODataResponse readEntityMedia(final GetMediaResourceUriInfo uriInfo, final String contentType)
+      throws ODataException {
+    final Object data = retrieveData(
+        uriInfo.getStartEntitySet(),
+        uriInfo.getKeyPredicates(),
+        uriInfo.getFunctionImport(),
+        mapFunctionParameters(uriInfo.getFunctionImportParameters()),
+        uriInfo.getNavigationSegments());
+
+    if (!appliesFilter(data, uriInfo.getFilter())) {
+      throw new ODataNotFoundException(ODataNotFoundException.ENTITY);
+    }
+
+    final EdmEntitySet entitySet = uriInfo.getTargetEntitySet();
+    final BinaryData binaryData = dataSource.readBinaryData(entitySet, data);
+    if (binaryData == null) {
+      throw new ODataNotFoundException(ODataNotFoundException.ENTITY);
+    }
+
+    final String mimeType = binaryData.getMimeType() == null ?
+        HttpContentType.APPLICATION_OCTET_STREAM : binaryData.getMimeType();
+
+    return ODataResponse.fromResponse(EntityProvider.writeBinary(mimeType, binaryData.getData())).eTag(
+        constructETag(entitySet, data)).build();
+  }
+
+  @Override
+  public ODataResponse deleteEntityMedia(final DeleteUriInfo uriInfo, final String contentType) throws ODataException {
+    final Object data = retrieveData(
+        uriInfo.getStartEntitySet(),
+        uriInfo.getKeyPredicates(),
+        uriInfo.getFunctionImport(),
+        mapFunctionParameters(uriInfo.getFunctionImportParameters()),
+        uriInfo.getNavigationSegments());
+
+    if (data == null) {
+      throw new ODataNotFoundException(ODataNotFoundException.ENTITY);
+    }
+
+    dataSource.writeBinaryData(uriInfo.getTargetEntitySet(), data, new BinaryData(null, null));
+
+    return ODataResponse.newBuilder().build();
+  }
+
+  @Override
+  public ODataResponse updateEntityMedia(final PutMergePatchUriInfo uriInfo, final InputStream content,
+      final String requestContentType, final String contentType) throws ODataException {
+    final Object data = retrieveData(
+        uriInfo.getStartEntitySet(),
+        uriInfo.getKeyPredicates(),
+        uriInfo.getFunctionImport(),
+        mapFunctionParameters(uriInfo.getFunctionImportParameters()),
+        uriInfo.getNavigationSegments());
+
+    if (!appliesFilter(data, uriInfo.getFilter())) {
+      throw new ODataNotFoundException(ODataNotFoundException.ENTITY);
+    }
+
+    ODataContext context = getContext();
+    final int timingHandle = context.startRuntimeMeasurement("EntityProvider", "readBinary");
+
+    final byte[] value = EntityProvider.readBinary(content);
+
+    context.stopRuntimeMeasurement(timingHandle);
+
+    final EdmEntitySet entitySet = uriInfo.getTargetEntitySet();
+    dataSource.writeBinaryData(entitySet, data, new BinaryData(value, requestContentType));
+
+    return ODataResponse.newBuilder().eTag(constructETag(entitySet, data)).build();
+  }
+
+  @Override
+  public ODataResponse executeFunctionImport(final GetFunctionImportUriInfo uriInfo, final String contentType)
+      throws ODataException {
+    final EdmFunctionImport functionImport = uriInfo.getFunctionImport();
+    final EdmType type = functionImport.getReturnType().getType();
+
+    final Object data = dataSource.readData(
+        functionImport,
+        mapFunctionParameters(uriInfo.getFunctionImportParameters()),
+        null);
+
+    if (data == null) {
+      throw new ODataNotFoundException(ODataHttpException.COMMON);
+    }
+
+    Object value;
+    if (type.getKind() == EdmTypeKind.SIMPLE) {
+      value = type == EdmSimpleTypeKind.Binary.getEdmSimpleTypeInstance() ?
+          ((BinaryData) data).getData() : data;
+    } else if (functionImport.getReturnType().getMultiplicity() == EdmMultiplicity.MANY) {
+      List<Map<String, Object>> values = new ArrayList<Map<String, Object>>();
+      for (final Object typeData : (List<?>) data) {
+        values.add(getStructuralTypeValueMap(typeData, (EdmStructuralType) type));
+      }
+      value = values;
+    } else {
+      value = getStructuralTypeValueMap(data, (EdmStructuralType) type);
+    }
+
+    ODataContext context = getContext();
+
+    final EntityProviderWriteProperties entryProperties = EntityProviderWriteProperties
+        .serviceRoot(context.getPathInfo().getServiceRoot()).build();
+
+    final int timingHandle = context.startRuntimeMeasurement("EntityProvider", "writeFunctionImport");
+
+    final ODataResponse response =
+        EntityProvider.writeFunctionImport(contentType, functionImport, value, entryProperties);
+
+    context.stopRuntimeMeasurement(timingHandle);
+
+    return ODataResponse.fromResponse(response).build();
+  }
+
+  @Override
+  public ODataResponse executeFunctionImportValue(final GetFunctionImportUriInfo uriInfo, final String contentType)
+      throws ODataException {
+    final EdmFunctionImport functionImport = uriInfo.getFunctionImport();
+    final EdmSimpleType type = (EdmSimpleType) functionImport.getReturnType().getType();
+
+    final Object data = dataSource.readData(
+        functionImport,
+        mapFunctionParameters(uriInfo.getFunctionImportParameters()),
+        null);
+
+    if (data == null) {
+      throw new ODataNotFoundException(ODataHttpException.COMMON);
+    }
+
+    ODataResponse response;
+    if (type == EdmSimpleTypeKind.Binary.getEdmSimpleTypeInstance()) {
+      response = EntityProvider.writeBinary(((BinaryData) data).getMimeType(), ((BinaryData) data).getData());
+    } else {
+      final String value = type.valueToString(data, EdmLiteralKind.DEFAULT, null);
+      response = EntityProvider.writeText(value == null ? "" : value);
+    }
+    return ODataResponse.fromResponse(response).build();
+  }
+
+  private static Map<String, Object> mapKey(final List<KeyPredicate> keys) throws EdmException {
+    Map<String, Object> keyMap = new HashMap<String, Object>();
+    for (final KeyPredicate key : keys) {
+      final EdmProperty property = key.getProperty();
+      final EdmSimpleType type = (EdmSimpleType) property.getType();
+      keyMap.put(property.getName(), type.valueOfString(key.getLiteral(), EdmLiteralKind.DEFAULT, property.getFacets(),
+          type.getDefaultType()));
+    }
+    return keyMap;
+  }
+
+  private static Map<String, Object> mapFunctionParameters(final Map<String, EdmLiteral> functionImportParameters)
+      throws EdmSimpleTypeException {
+    if (functionImportParameters == null) {
+      return Collections.emptyMap();
+    } else {
+      Map<String, Object> parameterMap = new HashMap<String, Object>();
+      for (final String parameterName : functionImportParameters.keySet()) {
+        final EdmLiteral literal = functionImportParameters.get(parameterName);
+        final EdmSimpleType type = literal.getType();
+        parameterMap.put(parameterName, type.valueOfString(literal.getLiteral(), EdmLiteralKind.DEFAULT, null, type
+            .getDefaultType()));
+      }
+      return parameterMap;
+    }
+  }
+
+  private Object retrieveData(final EdmEntitySet startEntitySet, final List<KeyPredicate> keyPredicates,
+      final EdmFunctionImport functionImport, final Map<String, Object> functionImportParameters,
+      final List<NavigationSegment> navigationSegments) throws ODataException {
+    Object data;
+    final Map<String, Object> keys = mapKey(keyPredicates);
+
+    ODataContext context = getContext();
+    final int timingHandle = context.startRuntimeMeasurement(getClass().getSimpleName(), "retrieveData");
+
+    try {
+      data = functionImport == null ?
+          keys.isEmpty() ?
+              dataSource.readData(startEntitySet) : dataSource.readData(startEntitySet, keys) :
+          dataSource.readData(functionImport, functionImportParameters, keys);
+  
+      EdmEntitySet currentEntitySet =
+          functionImport == null ? startEntitySet : functionImport.getEntitySet();
+      for (NavigationSegment navigationSegment : navigationSegments) {
+        data = dataSource.readRelatedData(
+            currentEntitySet,
+            data,
+            navigationSegment.getEntitySet(),
+            mapKey(navigationSegment.getKeyPredicates()));
+        currentEntitySet = navigationSegment.getEntitySet();
+      }
+    } finally {
+      context.stopRuntimeMeasurement(timingHandle);
+    }
+    return data;
+  }
+
+  private <T> String constructETag(final EdmEntitySet entitySet, final T data) throws ODataException {
+    final EdmEntityType entityType = entitySet.getEntityType();
+    String eTag = null;
+    for (final String propertyName : entityType.getPropertyNames()) {
+      final EdmProperty property = (EdmProperty) entityType.getProperty(propertyName);
+      if (property.getFacets() != null && property.getFacets().getConcurrencyMode() == EdmConcurrencyMode.Fixed) {
+        final EdmSimpleType type = (EdmSimpleType) property.getType();
+        final String component = type.valueToString(valueAccess.getPropertyValue(data, property),
+            EdmLiteralKind.DEFAULT, property.getFacets());
+        eTag = eTag == null ? component : eTag + Edm.DELIMITER + component;
+      }
+    }
+    return eTag == null ? null : "W/\"" + eTag + "\"";
+  }
+
+  private <T> Map<String, ODataCallback> getCallbacks(final T data, final EdmEntityType entityType)
+      throws EdmException {
+    final List<String> navigationPropertyNames = entityType.getNavigationPropertyNames();
+    if (navigationPropertyNames.isEmpty()) {
+      return null;
+    } else {
+      final WriteCallback callback = new WriteCallback(data);
+      Map<String, ODataCallback> callbacks = new HashMap<String, ODataCallback>();
+      for (final String name : navigationPropertyNames) {
+        callbacks.put(name, callback);
+      }
+      return callbacks;
+    }
+  }
+
+  private class WriteCallback implements OnWriteEntryContent, OnWriteFeedContent {
+    private final Object data;
+
+    private <T> WriteCallback(final T data) {
+      this.data = data;
+    }
+
+    @Override
+    public WriteFeedCallbackResult retrieveFeedResult(final WriteFeedCallbackContext context)
+        throws ODataApplicationException {
+      try {
+        final EdmEntityType entityType =
+            context.getSourceEntitySet().getRelatedEntitySet(context.getNavigationProperty()).getEntityType();
+        List<Map<String, Object>> values = new ArrayList<Map<String, Object>>();
+        Object relatedData = null;
+        try {
+          relatedData = readRelatedData(context);
+          for (final Object entryData : (List<?>) relatedData) {
+            values.add(getStructuralTypeValueMap(entryData, entityType));
+          }
+        } catch (final ODataNotFoundException e) {
+          values.clear();
+        }
+        WriteFeedCallbackResult result = new WriteFeedCallbackResult();
+        result.setFeedData(values);
+        EntityProviderWriteProperties inlineProperties =
+            EntityProviderWriteProperties.serviceRoot(getContext().getPathInfo().getServiceRoot()).callbacks(
+                getCallbacks(relatedData, entityType)).expandSelectTree(context.getCurrentExpandSelectTreeNode())
+                .selfLink(context.getSelfLink()).build();
+        result.setInlineProperties(inlineProperties);
+        return result;
+      } catch (final ODataException e) {
+        throw new ODataApplicationException(e.getLocalizedMessage(), Locale.ROOT, e);
+      }
+    }
+
+    @Override
+    public WriteEntryCallbackResult retrieveEntryResult(final WriteEntryCallbackContext context)
+        throws ODataApplicationException {
+      try {
+        final EdmEntityType entityType =
+            context.getSourceEntitySet().getRelatedEntitySet(context.getNavigationProperty()).getEntityType();
+        WriteEntryCallbackResult result = new WriteEntryCallbackResult();
+        Object relatedData;
+        try {
+          relatedData = readRelatedData(context);
+        } catch (final ODataNotFoundException e) {
+          relatedData = null;
+        }
+
+        if (relatedData == null) {
+          result.setEntryData(Collections.<String, Object> emptyMap());
+        } else {
+          result.setEntryData(getStructuralTypeValueMap(relatedData, entityType));
+
+          EntityProviderWriteProperties inlineProperties =
+              EntityProviderWriteProperties.serviceRoot(getContext().getPathInfo().getServiceRoot()).callbacks(
+                  getCallbacks(relatedData, entityType)).expandSelectTree(context.getCurrentExpandSelectTreeNode())
+                  .build();
+          result.setInlineProperties(inlineProperties);
+        }
+        return result;
+      } catch (final ODataException e) {
+        throw new ODataApplicationException(e.getLocalizedMessage(), Locale.ROOT, e);
+      }
+    }
+
+    private Object readRelatedData(final WriteCallbackContext context) throws ODataException {
+      final EdmEntitySet entitySet = context.getSourceEntitySet();
+      return dataSource.readRelatedData(
+          entitySet,
+          data instanceof List ? readEntryData((List<?>) data, entitySet.getEntityType(), context
+              .extractKeyFromEntryData()) : data,
+          entitySet.getRelatedEntitySet(context.getNavigationProperty()),
+          Collections.<String, Object> emptyMap());
+    }
+
+    private <T> T readEntryData(final List<T> data, final EdmEntityType entityType, final Map<String, Object> key)
+        throws ODataException {
+      for (final T entryData : data) {
+        boolean found = true;
+        for (final EdmProperty keyProperty : entityType.getKeyProperties()) {
+          if (!valueAccess.getPropertyValue(entryData, keyProperty).equals(key.get(keyProperty.getName()))) {
+            found = false;
+            break;
+          }
+        }
+        if (found) {
+          return entryData;
+        }
+      }
+      return null;
+    }
+  }
+
+  private <T> ODataResponse writeEntry(final EdmEntitySet entitySet, final ExpandSelectTreeNode expandSelectTree,
+      final T data, final String contentType) throws ODataException, EntityProviderException {
+    final EdmEntityType entityType = entitySet.getEntityType();
+    final Map<String, Object> values = getStructuralTypeValueMap(data, entityType);
+
+    ODataContext context = getContext();
+    EntityProviderWriteProperties writeProperties = EntityProviderWriteProperties
+        .serviceRoot(context.getPathInfo().getServiceRoot())
+        .expandSelectTree(expandSelectTree)
+        .callbacks(getCallbacks(data, entityType))
+        .build();
+
+    final int timingHandle = context.startRuntimeMeasurement("EntityProvider", "writeEntry");
+
+    final ODataResponse response = EntityProvider.writeEntry(contentType, entitySet, values, writeProperties);
+
+    context.stopRuntimeMeasurement(timingHandle);
+
+    return response;
+  }
+
+  private ODataEntry parseEntry(final EdmEntitySet entitySet, final InputStream content,
+      final String requestContentType, final EntityProviderReadProperties properties) throws ODataBadRequestException {
+    ODataContext context = getContext();
+    final int timingHandle = context.startRuntimeMeasurement("EntityConsumer", "readEntry");
+
+    ODataEntry entryValues;
+    try {
+      entryValues = EntityProvider.readEntry(requestContentType, entitySet, content, properties);
+    } catch (final EntityProviderException e) {
+      throw new ODataBadRequestException(ODataBadRequestException.BODY, e);
+    }
+
+    context.stopRuntimeMeasurement(timingHandle);
+
+    return entryValues;
+  }
+
+  private Map<String, Object> parseLink(final EdmEntitySet entitySet, final InputStream content,
+      final String contentType) throws ODataException {
+    ODataContext context = getContext();
+    final int timingHandle = context.startRuntimeMeasurement("EntityProvider", "readLink");
+
+    final String uriString = EntityProvider.readLink(contentType, entitySet, content);
+
+    context.stopRuntimeMeasurement(timingHandle);
+
+    final Map<String, Object> targetKeys = parseLinkUri(entitySet, uriString);
+    if (targetKeys == null) {
+      throw new ODataBadRequestException(ODataBadRequestException.BODY);
+    }
+    return targetKeys;
+  }
+
+  private Map<String, Object> parseLinkUri(final EdmEntitySet targetEntitySet, final String uriString)
+      throws EdmException {
+    ODataContext context = getContext();
+    final int timingHandle = context.startRuntimeMeasurement("UriParser", "getKeyPredicatesFromEntityLink");
+
+    List<KeyPredicate> key = null;
+    try {
+      key = UriParser.getKeyPredicatesFromEntityLink(targetEntitySet, uriString,
+          context.getPathInfo().getServiceRoot());
+    } catch (ODataException e) {
+      // We don't understand the link target. This could also be seen as an error.
+    }
+
+    context.stopRuntimeMeasurement(timingHandle);
+
+    return key == null ? null : mapKey(key);
+  }
+
+  private <T> void createInlinedEntities(final EdmEntitySet entitySet, final T data, final ODataEntry entryValues)
+      throws ODataException {
+    final EdmEntityType entityType = entitySet.getEntityType();
+    for (final String navigationPropertyName : entityType.getNavigationPropertyNames()) {
+
+      final EdmNavigationProperty navigationProperty =
+          (EdmNavigationProperty) entityType.getProperty(navigationPropertyName);
+      final EdmEntitySet relatedEntitySet = entitySet.getRelatedEntitySet(navigationProperty);
+      final EdmEntityType relatedEntityType = relatedEntitySet.getEntityType();
+
+      final Object relatedValue = entryValues.getProperties().get(navigationPropertyName);
+      if (relatedValue == null) {
+        for (final String uriString : entryValues.getMetadata().getAssociationUris(navigationPropertyName)) {
+          final Map<String, Object> key = parseLinkUri(relatedEntitySet, uriString);
+          if (key != null) {
+            dataSource.writeRelation(entitySet, data, relatedEntitySet, key);
+          }
+        }
+
+      } else {
+        if (relatedValue instanceof ODataFeed) {
+          ODataFeed feed = (ODataFeed) relatedValue;
+          final List<ODataEntry> relatedValueList = feed.getEntries();
+          for (final ODataEntry relatedValues : relatedValueList) {
+            Object relatedData = dataSource.newDataObject(relatedEntitySet);
+            setStructuralTypeValuesFromMap(relatedData, relatedEntityType, relatedValues.getProperties(), false);
+            dataSource.createData(relatedEntitySet, relatedData);
+            dataSource.writeRelation(entitySet, data, relatedEntitySet, getStructuralTypeValueMap(relatedData,
+                relatedEntityType));
+            createInlinedEntities(relatedEntitySet, relatedData, relatedValues);
+          }
+        } else if (relatedValue instanceof ODataEntry) {
+          final ODataEntry relatedValueEntry = (ODataEntry) relatedValue;
+          Object relatedData = dataSource.newDataObject(relatedEntitySet);
+          setStructuralTypeValuesFromMap(relatedData, relatedEntityType, relatedValueEntry.getProperties(), false);
+          dataSource.createData(relatedEntitySet, relatedData);
+          dataSource.writeRelation(entitySet, data, relatedEntitySet, getStructuralTypeValueMap(relatedData,
+              relatedEntityType));
+          createInlinedEntities(relatedEntitySet, relatedData, relatedValueEntry);
+        } else {
+          throw new ODataException("Unexpected class for a related value: " + relatedValue.getClass().getSimpleName());
+        }
+
+      }
+    }
+  }
+
+  private <T> Integer applySystemQueryOptions(final EdmEntitySet entitySet, final List<T> data,
+      final FilterExpression filter, final InlineCount inlineCount, final OrderByExpression orderBy,
+      final String skipToken, final Integer skip, final Integer top) throws ODataException {
+    ODataContext context = getContext();
+    final int timingHandle = context.startRuntimeMeasurement(getClass().getSimpleName(), "applySystemQueryOptions");
+
+    if (filter != null) {
+      // Remove all elements the filter does not apply for.
+      // A for-each loop would not work with "remove", see Java documentation.
+      for (Iterator<T> iterator = data.iterator(); iterator.hasNext();) {
+        if (!appliesFilter(iterator.next(), filter)) {
+          iterator.remove();
+        }
+      }
+    }
+
+    final Integer count = inlineCount == InlineCount.ALLPAGES ? data.size() : null;
+
+    if (orderBy != null) {
+      sort(data, orderBy);
+    } else if (skipToken != null || skip != null || top != null) {
+      sortInDefaultOrder(entitySet, data);
+    }
+
+    if (skipToken != null) {
+      while (!data.isEmpty() && !getSkipToken(entitySet, data.get(0)).equals(skipToken)) {
+        data.remove(0);
+      }
+    }
+
+    if (skip != null) {
+      if (skip >= data.size()) {
+        data.clear();
+      } else {
+        for (int i = 0; i < skip; i++) {
+          data.remove(0);
+        }
+      }
+    }
+
+    if (top != null) {
+      while (data.size() > top) {
+        data.remove(top.intValue());
+      }
+    }
+
+    context.stopRuntimeMeasurement(timingHandle);
+
+    return count;
+  }
+
+  private <T> void sort(final List<T> data, final OrderByExpression orderBy) {
+    Collections.sort(data, new Comparator<T>() {
+      @Override
+      public int compare(final T entity1, final T entity2) {
+        try {
+          int result = 0;
+          for (final OrderExpression expression : orderBy.getOrders()) {
+            String first = evaluateExpression(entity1, expression.getExpression());
+            String second = evaluateExpression(entity2, expression.getExpression());
+
+            if (first != null && second != null) {
+              result = first.compareTo(second);
+            } else if (first == null && second != null) {
+              result = 1;
+            } else if (first != null && second == null) {
+              result = -1;
+            }
+
+            if (expression.getSortOrder() == SortOrder.desc) {
+              result = -result;
+            }
+
+            if (result != 0) {
+              break;
+            }
+          }
+          return result;
+        } catch (final ODataException e) {
+          return 0;
+        }
+      }
+    });
+  }
+
+  private <T> void sortInDefaultOrder(final EdmEntitySet entitySet, final List<T> data) {
+    Collections.sort(data, new Comparator<T>() {
+      @Override
+      public int compare(final T entity1, final T entity2) {
+        try {
+          return getSkipToken(entitySet, entity1).compareTo(getSkipToken(entitySet, entity2));
+        } catch (final ODataException e) {
+          return 0;
+        }
+      }
+    });
+  }
+
+  private <T> boolean appliesFilter(final T data, final FilterExpression filter) throws ODataException {
+    ODataContext context = getContext();
+    final int timingHandle = context.startRuntimeMeasurement(getClass().getSimpleName(), "appliesFilter");
+
+    try {
+      return data != null && (filter == null || evaluateExpression(data, filter.getExpression()).equals("true"));
+    } catch (final RuntimeException e) {
+      return false;
+    } finally {
+      context.stopRuntimeMeasurement(timingHandle);
+    }
+  }
+
+  private <T> String evaluateExpression(final T data, final CommonExpression expression) throws ODataException {
+    switch (expression.getKind()) {
+    case UNARY:
+      final UnaryExpression unaryExpression = (UnaryExpression) expression;
+      final String operand = evaluateExpression(data, unaryExpression.getOperand());
+
+      switch (unaryExpression.getOperator()) {
+      case NOT:
+        return Boolean.toString(!Boolean.parseBoolean(operand));
+      case MINUS:
+        return operand.startsWith("-") ? operand.substring(1) : "-" + operand;
+      default:
+        throw new ODataNotImplementedException();
+      }
+
+    case BINARY:
+      final BinaryExpression binaryExpression = (BinaryExpression) expression;
+      final EdmSimpleType type = (EdmSimpleType) binaryExpression.getLeftOperand().getEdmType();
+      final String left = evaluateExpression(data, binaryExpression.getLeftOperand());
+      final String right = evaluateExpression(data, binaryExpression.getRightOperand());
+
+      switch (binaryExpression.getOperator()) {
+      case ADD:
+        if (binaryExpression.getEdmType() == EdmSimpleTypeKind.Decimal.getEdmSimpleTypeInstance()
+            || binaryExpression.getEdmType() == EdmSimpleTypeKind.Double.getEdmSimpleTypeInstance()
+            || binaryExpression.getEdmType() == EdmSimpleTypeKind.Single.getEdmSimpleTypeInstance()) {
+          return Double.toString(Double.valueOf(left) + Double.valueOf(right));
+        } else {
+          return Long.toString(Long.valueOf(left) + Long.valueOf(right));
+        }
+      case SUB:
+        if (binaryExpression.getEdmType() == EdmSimpleTypeKind.Decimal.getEdmSimpleTypeInstance()
+            || binaryExpression.getEdmType() == EdmSimpleTypeKind.Double.getEdmSimpleTypeInstance()
+            || binaryExpression.getEdmType() == EdmSimpleTypeKind.Single.getEdmSimpleTypeInstance()) {
+          return Double.toString(Double.valueOf(left) - Double.valueOf(right));
+        } else {
+          return Long.toString(Long.valueOf(left) - Long.valueOf(right));
+        }
+      case MUL:
+        if (binaryExpression.getEdmType() == EdmSimpleTypeKind.Decimal.getEdmSimpleTypeInstance()
+            || binaryExpression.getEdmType() == EdmSimpleTypeKind.Double.getEdmSimpleTypeInstance()
+            || binaryExpression.getEdmType() == EdmSimpleTypeKind.Single.getEdmSimpleTypeInstance()) {
+          return Double.toString(Double.valueOf(left) * Double.valueOf(right));
+        } else {
+          return Long.toString(Long.valueOf(left) * Long.valueOf(right));
+        }
+      case DIV:
+        final String number = Double.toString(Double.valueOf(left) / Double.valueOf(right));
+        return number.endsWith(".0") ? number.replace(".0", "") : number;
+      case MODULO:
+        if (binaryExpression.getEdmType() == EdmSimpleTypeKind.Decimal.getEdmSimpleTypeInstance()
+            || binaryExpression.getEdmType() == EdmSimpleTypeKind.Double.getEdmSimpleTypeInstance()
+            || binaryExpression.getEdmType() == EdmSimpleTypeKind.Single.getEdmSimpleTypeInstance()) {
+          return Double.toString(Double.valueOf(left) % Double.valueOf(right));
+        } else {
+          return Long.toString(Long.valueOf(left) % Long.valueOf(right));
+        }
+      case AND:
+        return Boolean.toString(left.equals("true") && right.equals("true"));
+      case OR:
+        return Boolean.toString(left.equals("true") || right.equals("true"));
+      case EQ:
+        return Boolean.toString(left.equals(right));
+      case NE:
+        return Boolean.toString(!left.equals(right));
+      case LT:
+        if (type == EdmSimpleTypeKind.String.getEdmSimpleTypeInstance()
+            || type == EdmSimpleTypeKind.DateTime.getEdmSimpleTypeInstance()
+            || type == EdmSimpleTypeKind.DateTimeOffset.getEdmSimpleTypeInstance()
+            || type == EdmSimpleTypeKind.Guid.getEdmSimpleTypeInstance()
+            || type == EdmSimpleTypeKind.Time.getEdmSimpleTypeInstance()) {
+          return Boolean.toString(left.compareTo(right) < 0);
+        } else {
+          return Boolean.toString(Double.valueOf(left) < Double.valueOf(right));
+        }
+      case LE:
+        if (type == EdmSimpleTypeKind.String.getEdmSimpleTypeInstance()
+            || type == EdmSimpleTypeKind.DateTime.getEdmSimpleTypeInstance()
+            || type == EdmSimpleTypeKind.DateTimeOffset.getEdmSimpleTypeInstance()
+            || type == EdmSimpleTypeKind.Guid.getEdmSimpleTypeInstance()
+            || type == EdmSimpleTypeKind.Time.getEdmSimpleTypeInstance()) {
+          return Boolean.toString(left.compareTo(right) <= 0);
+        } else {
+          return Boolean.toString(Double.valueOf(left) <= Double.valueOf(right));
+        }
+      case GT:
+        if (type == EdmSimpleTypeKind.String.getEdmSimpleTypeInstance()
+            || type == EdmSimpleTypeKind.DateTime.getEdmSimpleTypeInstance()
+            || type == EdmSimpleTypeKind.DateTimeOffset.getEdmSimpleTypeInstance()
+            || type == EdmSimpleTypeKind.Guid.getEdmSimpleTypeInstance()
+            || type == EdmSimpleTypeKind.Time.getEdmSimpleTypeInstance()) {
+          return Boolean.toString(left.compareTo(right) > 0);
+        } else {
+          return Boolean.toString(Double.valueOf(left) > Double.valueOf(right));
+        }
+      case GE:
+        if (type == EdmSimpleTypeKind.String.getEdmSimpleTypeInstance()
+            || type == EdmSimpleTypeKind.DateTime.getEdmSimpleTypeInstance()
+            || type == EdmSimpleTypeKind.DateTimeOffset.getEdmSimpleTypeInstance()
+            || type == EdmSimpleTypeKind.Guid.getEdmSimpleTypeInstance()
+            || type == EdmSimpleTypeKind.Time.getEdmSimpleTypeInstance()) {
+          return Boolean.toString(left.compareTo(right) >= 0);
+        } else {
+          return Boolean.toString(Double.valueOf(left) >= Double.valueOf(right));
+        }
+      case PROPERTY_ACCESS:
+        throw new ODataNotImplementedException();
+      default:
+        throw new ODataNotImplementedException();
+      }
+
+    case PROPERTY:
+      final EdmProperty property = (EdmProperty) ((PropertyExpression) expression).getEdmProperty();
+      final EdmSimpleType propertyType = (EdmSimpleType) property.getType();
+      return propertyType.valueToString(valueAccess.getPropertyValue(data, property), EdmLiteralKind.DEFAULT,
+          property.getFacets());
+
+    case MEMBER:
+      final MemberExpression memberExpression = (MemberExpression) expression;
+      final PropertyExpression propertyExpression = (PropertyExpression) memberExpression.getProperty();
+      final EdmProperty memberProperty = (EdmProperty) propertyExpression.getEdmProperty();
+      final EdmSimpleType memberType = (EdmSimpleType) memberExpression.getEdmType();
+      List<EdmProperty> propertyPath = new ArrayList<EdmProperty>();
+      CommonExpression currentExpression = memberExpression;
+      while (currentExpression != null) {
+        final PropertyExpression currentPropertyExpression =
+            (PropertyExpression) (currentExpression.getKind() == ExpressionKind.MEMBER ?
+                ((MemberExpression) currentExpression).getProperty() : currentExpression);
+        final EdmTyped currentProperty = currentPropertyExpression.getEdmProperty();
+        final EdmTypeKind kind = currentProperty.getType().getKind();
+        if (kind == EdmTypeKind.SIMPLE || kind == EdmTypeKind.COMPLEX) {
+          propertyPath.add(0, (EdmProperty) currentProperty);
+        } else {
+          throw new ODataNotImplementedException();
+        }
+        currentExpression =
+            currentExpression.getKind() == ExpressionKind.MEMBER ? ((MemberExpression) currentExpression).getPath()
+                : null;
+      }
+      return memberType.valueToString(getPropertyValue(data, propertyPath), EdmLiteralKind.DEFAULT, memberProperty
+          .getFacets());
+
+    case LITERAL:
+      final LiteralExpression literal = (LiteralExpression) expression;
+      final EdmSimpleType literalType = (EdmSimpleType) literal.getEdmType();
+      return literalType.valueToString(literalType.valueOfString(literal.getUriLiteral(), EdmLiteralKind.URI, null,
+          literalType.getDefaultType()),
+          EdmLiteralKind.DEFAULT, null);
+
+    case METHOD:
+      final MethodExpression methodExpression = (MethodExpression) expression;
+      final String first = evaluateExpression(data, methodExpression.getParameters().get(0));
+      final String second = methodExpression.getParameterCount() > 1 ?
+          evaluateExpression(data, methodExpression.getParameters().get(1)) : null;
+      final String third = methodExpression.getParameterCount() > 2 ?
+          evaluateExpression(data, methodExpression.getParameters().get(2)) : null;
+
+      switch (methodExpression.getMethod()) {
+      case ENDSWITH:
+        return Boolean.toString(first.endsWith(second));
+      case INDEXOF:
+        return Integer.toString(first.indexOf(second));
+      case STARTSWITH:
+        return Boolean.toString(first.startsWith(second));
+      case TOLOWER:
+        return first.toLowerCase(Locale.ROOT);
+      case TOUPPER:
+        return first.toUpperCase(Locale.ROOT);
+      case TRIM:
+        return first.trim();
+      case SUBSTRING:
+        final int offset = Integer.parseInt(second);
+        return first.substring(offset, offset + Integer.parseInt(third));
+      case SUBSTRINGOF:
+        return Boolean.toString(second.contains(first));
+      case CONCAT:
+        return first + second;
+      case LENGTH:
+        return Integer.toString(first.length());
+      case YEAR:
+        return String.valueOf(Integer.parseInt(first.substring(0, 4)));
+      case MONTH:
+        return String.valueOf(Integer.parseInt(first.substring(5, 7)));
+      case DAY:
+        return String.valueOf(Integer.parseInt(first.substring(8, 10)));
+      case HOUR:
+        return String.valueOf(Integer.parseInt(first.substring(11, 13)));
+      case MINUTE:
+        return String.valueOf(Integer.parseInt(first.substring(14, 16)));
+      case SECOND:
+        return String.valueOf(Integer.parseInt(first.substring(17, 19)));
+      case ROUND:
+        return Long.toString(Math.round(Double.valueOf(first)));
+      case FLOOR:
+        return Long.toString(Math.round(Math.floor(Double.valueOf(first))));
+      case CEILING:
+        return Long.toString(Math.round(Math.ceil(Double.valueOf(first))));
+      default:
+        throw new ODataNotImplementedException();
+      }
+
+    default:
+      throw new ODataNotImplementedException();
+    }
+  }
+
+  private <T> String getSkipToken(final EdmEntitySet entitySet, final T data) throws ODataException {
+    String skipToken = "";
+    for (final EdmProperty property : entitySet.getEntityType().getKeyProperties()) {
+      final EdmSimpleType type = (EdmSimpleType) property.getType();
+      skipToken = skipToken.concat(type.valueToString(valueAccess.getPropertyValue(data, property),
+          EdmLiteralKind.DEFAULT, property.getFacets()));
+    }
+    return skipToken;
+  }
+
+  private <T> Object getPropertyValue(final T data, final List<EdmProperty> propertyPath) throws ODataException {
+    Object dataObject = data;
+    for (final EdmProperty property : propertyPath) {
+      if (dataObject != null) {
+        dataObject = valueAccess.getPropertyValue(dataObject, property);
+      }
+    }
+    return dataObject;
+  }
+
+  private void handleMimeType(final Object data, final EdmMapping mapping, final Map<String, Object> valueMap)
+      throws ODataException {
+    final String mimeTypeName = mapping.getMimeType();
+    if (mimeTypeName != null) {
+      Object value = valueAccess.getMappingValue(data, mapping);
+      valueMap.put(mimeTypeName, value);
+      if (mapping.getMediaResourceMimeTypeKey() != null) {
+        valueMap.put(mapping.getMediaResourceMimeTypeKey(), value);
+      }
+    }
+  }
+
+  private <T> Map<String, Object> getSimpleTypeValueMap(final T data, final List<EdmProperty> propertyPath)
+      throws ODataException {
+    final EdmProperty property = propertyPath.get(propertyPath.size() - 1);
+    Map<String, Object> valueWithMimeType = new HashMap<String, Object>();
+    valueWithMimeType.put(property.getName(), getPropertyValue(data, propertyPath));
+
+    handleMimeType(data, property.getMapping(), valueWithMimeType);
+
+    return valueWithMimeType;
+  }
+
+  private <T> Map<String, Object> getStructuralTypeValueMap(final T data, final EdmStructuralType type)
+      throws ODataException {
+    ODataContext context = getContext();
+    final int timingHandle = context.startRuntimeMeasurement(getClass().getSimpleName(), "getStructuralTypeValueMap");
+
+    Map<String, Object> valueMap = new HashMap<String, Object>();
+
+    EdmMapping mapping = type.getMapping();
+    if (mapping != null) {
+      handleMimeType(data, mapping, valueMap);
+    }
+
+    for (final String propertyName : type.getPropertyNames()) {
+      final EdmProperty property = (EdmProperty) type.getProperty(propertyName);
+      final Object value = valueAccess.getPropertyValue(data, property);
+
+      if (property.isSimple()) {
+        if (property.getMapping() == null || property.getMapping().getMimeType() == null) {
+          valueMap.put(propertyName, value);
+        } else {
+          // TODO: enable MIME type mapping outside the current subtree
+          valueMap.put(propertyName, getSimpleTypeValueMap(data, Arrays.asList(property)));
+        }
+      } else {
+        valueMap.put(propertyName, getStructuralTypeValueMap(value, (EdmStructuralType) property.getType()));
+      }
+    }
+
+    context.stopRuntimeMeasurement(timingHandle);
+
+    return valueMap;
+  }
+
+  private <T> Map<String, Object> getStructuralTypeTypeMap(final T data, final EdmStructuralType type)
+      throws ODataException {
+    ODataContext context = getContext();
+    final int timingHandle = context.startRuntimeMeasurement(getClass().getSimpleName(), "getStructuralTypeTypeMap");
+
+    Map<String, Object> typeMap = new HashMap<String, Object>();
+    for (final String propertyName : type.getPropertyNames()) {
+      final EdmProperty property = (EdmProperty) type.getProperty(propertyName);
+      if (property.isSimple()) {
+        typeMap.put(propertyName, valueAccess.getPropertyType(data, property));
+      } else {
+        typeMap.put(propertyName, getStructuralTypeTypeMap(valueAccess.getPropertyValue(data, property),
+            (EdmStructuralType) property.getType()));
+      }
+    }
+
+    context.stopRuntimeMeasurement(timingHandle);
+
+    return typeMap;
+  }
+
+  private <T> void setStructuralTypeValuesFromMap(final T data, final EdmStructuralType type,
+      final Map<String, Object> valueMap, final boolean merge) throws ODataException {
+    ODataContext context = getContext();
+    final int timingHandle =
+        context.startRuntimeMeasurement(getClass().getSimpleName(), "setStructuralTypeValuesFromMap");
+
+    for (final String propertyName : type.getPropertyNames()) {
+      final EdmProperty property = (EdmProperty) type.getProperty(propertyName);
+      if (type instanceof EdmEntityType && ((EdmEntityType) type).getKeyProperties().contains(property)) {
+        Object v = valueAccess.getPropertyValue(data, property);
+        if (v != null) {
+          continue;
+        }
+      }
+
+      if (!merge || valueMap != null && valueMap.containsKey(propertyName)) {
+        final Object value = valueMap == null ? null : valueMap.get(propertyName);
+        if (property.isSimple()) {
+          valueAccess.setPropertyValue(data, property, value);
+        } else {
+          @SuppressWarnings("unchecked")
+          final Map<String, Object> values = (Map<String, Object>) value;
+          setStructuralTypeValuesFromMap(valueAccess.getPropertyValue(data, property),
+              (EdmStructuralType) property.getType(), values, merge);
+        }
+      }
+    }
+
+    context.stopRuntimeMeasurement(timingHandle);
+  }
+
+  @Override
+  public ODataResponse executeBatch(final BatchHandler handler, final String contentType, final InputStream content)
+      throws ODataException {
+    ODataResponse batchResponse;
+    List<BatchResponsePart> batchResponseParts = new ArrayList<BatchResponsePart>();
+    PathInfo pathInfo = getContext().getPathInfo();
+    EntityProviderBatchProperties batchProperties = EntityProviderBatchProperties.init().pathInfo(pathInfo).build();
+    List<BatchRequestPart> batchParts = EntityProvider.parseBatchRequest(contentType, content, batchProperties);
+    for (BatchRequestPart batchPart : batchParts) {
+      batchResponseParts.add(handler.handleBatchPart(batchPart));
+    }
+    batchResponse = EntityProvider.writeBatchResponse(batchResponseParts);
+    return batchResponse;
+  }
+
+  @Override
+  public BatchResponsePart executeChangeSet(final BatchHandler handler, final List<ODataRequest> requests)
+      throws ODataException {
+    List<ODataResponse> responses = new ArrayList<ODataResponse>();
+    for (ODataRequest request : requests) {
+      ODataResponse response = handler.handleRequest(request);
+      if (response.getStatus().getStatusCode() >= HttpStatusCodes.BAD_REQUEST.getStatusCode()) {
+        // Rollback
+        List<ODataResponse> errorResponses = new ArrayList<ODataResponse>(1);
+        errorResponses.add(response);
+        return BatchResponsePart.responses(errorResponses).changeSet(false).build();
+      }
+      responses.add(response);
+    }
+    return BatchResponsePart.responses(responses).changeSet(true).build();
+  }
+}


[03/12] [OLINGO-83] Refactoring of 'annotation-processor-*' modules

Posted by tb...@apache.org.
http://git-wip-us.apache.org/repos/asf/incubator-olingo-odata2/blob/3bd59050/odata2-annotation-processor/annotation-processor-core/src/main/java/org/apache/olingo/odata2/core/annotation/util/AnnotationHelper.java
----------------------------------------------------------------------
diff --git a/odata2-annotation-processor/annotation-processor-core/src/main/java/org/apache/olingo/odata2/core/annotation/util/AnnotationHelper.java b/odata2-annotation-processor/annotation-processor-core/src/main/java/org/apache/olingo/odata2/core/annotation/util/AnnotationHelper.java
deleted file mode 100644
index f2157a0..0000000
--- a/odata2-annotation-processor/annotation-processor-core/src/main/java/org/apache/olingo/odata2/core/annotation/util/AnnotationHelper.java
+++ /dev/null
@@ -1,777 +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.odata2.core.annotation.util;
-
-import java.lang.annotation.Annotation;
-import java.lang.reflect.Field;
-import java.lang.reflect.ParameterizedType;
-import java.util.ArrayList;
-import java.util.Collection;
-import java.util.HashMap;
-import java.util.List;
-import java.util.Locale;
-import java.util.Map;
-import java.util.Set;
-
-import org.apache.olingo.odata2.api.annotation.edm.EdmComplexType;
-import org.apache.olingo.odata2.api.annotation.edm.EdmEntitySet;
-import org.apache.olingo.odata2.api.annotation.edm.EdmEntityType;
-import org.apache.olingo.odata2.api.annotation.edm.EdmKey;
-import org.apache.olingo.odata2.api.annotation.edm.EdmNavigationProperty;
-import org.apache.olingo.odata2.api.annotation.edm.EdmNavigationProperty.Multiplicity;
-import org.apache.olingo.odata2.api.annotation.edm.EdmProperty;
-import org.apache.olingo.odata2.api.edm.EdmLiteralKind;
-import org.apache.olingo.odata2.api.edm.EdmMultiplicity;
-import org.apache.olingo.odata2.api.edm.EdmSimpleTypeException;
-import org.apache.olingo.odata2.api.edm.EdmSimpleTypeKind;
-import org.apache.olingo.odata2.api.edm.FullQualifiedName;
-import org.apache.olingo.odata2.api.exception.ODataException;
-import org.apache.olingo.odata2.core.exception.ODataRuntimeException;
-
-/**
- *
- */
-public class AnnotationHelper {
-
-  public static final String DEFAULT_CONTAINER_NAME = "DefaultContainer";
-
-  /**
-   * Compare keys of both instances.
-   * 
-   * @param firstInstance
-   * @param secondInstance
-   * @return
-   */
-  public boolean keyMatch(final Object firstInstance, final Object secondInstance) {
-    if (firstInstance == null || secondInstance == null) {
-      return false;
-    } else if (firstInstance.getClass() != secondInstance.getClass()) {
-      return false;
-    }
-
-    Map<String, Object> firstKeyFields = getValueForAnnotatedFields(firstInstance, EdmKey.class);
-    Map<String, Object> secondKeyFields = getValueForAnnotatedFields(secondInstance, EdmKey.class);
-
-    return keyValuesMatch(firstKeyFields, secondKeyFields);
-  }
-
-  /**
-   * Compare keys of instance with key values in map.
-   * 
-   * @param instance
-   * @param keyName2Value
-   * @return
-   */
-  public boolean keyMatch(final Object instance, final Map<String, Object> keyName2Value) {
-    Map<String, Object> instanceKeyFields = getValueForAnnotatedFields(instance, EdmKey.class);
-    return keyValuesMatch(instanceKeyFields, keyName2Value);
-  }
-
-  private boolean keyValuesMatch(final Map<String, Object> firstKeyValues, final Map<String, Object> secondKeyValues) {
-    if (firstKeyValues.size() != secondKeyValues.size()) {
-      return false;
-    } else {
-      Set<Map.Entry<String, Object>> entries = firstKeyValues.entrySet();
-      for (Map.Entry<String, Object> entry : entries) {
-        Object firstKey = entry.getValue();
-        Object secondKey = secondKeyValues.get(entry.getKey());
-        if (!isEqual(firstKey, secondKey)) {
-          return false;
-        }
-      }
-      return true;
-    }
-  }
-
-  private boolean isEqual(final Object firstKey, final Object secondKey) {
-    if (firstKey == null) {
-      if (secondKey == null) {
-        return true;
-      } else {
-        return secondKey.equals(firstKey);
-      }
-    } else {
-      return firstKey.equals(secondKey);
-    }
-  }
-
-  public String extractEntitTypeName(final EdmNavigationProperty enp, final Class<?> fallbackClass) {
-    Class<?> entityTypeClass = enp.toType();
-    return extractEntityTypeName(entityTypeClass == Object.class ? fallbackClass : entityTypeClass);
-  }
-
-  public String extractEntitTypeName(final EdmNavigationProperty enp, final Field field) {
-    Class<?> entityTypeClass = enp.toType();
-    if (entityTypeClass == Object.class) {
-      Class<?> toClass = field.getType();
-      return extractEntityTypeName((toClass.isArray() || Collection.class.isAssignableFrom(toClass) ?
-          (Class<?>) ((ParameterizedType) field.getGenericType()).getActualTypeArguments()[0] : toClass));
-    } else {
-      return extractEntityTypeName(entityTypeClass);
-    }
-  }
-
-  /**
-   * Returns <code>NULL</code> if given class is not annotated. If annotated the set entity type name is returned and if
-   * no name is set the default name is generated from the simple class name.
-   * 
-   * @param annotatedClass
-   * @return
-   */
-  public String extractEntityTypeName(final Class<?> annotatedClass) {
-    return extractTypeName(annotatedClass, EdmEntityType.class);
-  }
-
-  /**
-   * Returns <code>NULL</code> if given class is not annotated.
-   * If annotated the entity set name is returned and if
-   * no name is set a default name is generated based on the simple class name.
-   * 
-   * @param annotatedClass
-   * @return
-   */
-  public String extractEntitySetName(final Class<?> annotatedClass) {
-    if (annotatedClass == Object.class) {
-      return null;
-    }
-    EdmEntitySet entitySet = annotatedClass.getAnnotation(EdmEntitySet.class);
-    if (entitySet == null) {
-      return null;
-    }
-
-    String name = entitySet.name();
-    if (name.isEmpty()) {
-      return getCanonicalName(annotatedClass) + "Set";
-    }
-    return name;
-  }
-
-  public FullQualifiedName extractEntityTypeFqn(final EdmEntityType type, final Class<?> annotatedClass) {
-    if (type.namespace().isEmpty()) {
-      return new FullQualifiedName(generateNamespace(annotatedClass), extractEntityTypeName(annotatedClass));
-    }
-    return new FullQualifiedName(type.namespace(), extractEntityTypeName(annotatedClass));
-  }
-
-  public FullQualifiedName extractEntityTypeFqn(final Class<?> annotatedClass) {
-    EdmEntityType type = annotatedClass.getAnnotation(EdmEntityType.class);
-    if (type == null) {
-      return null;
-    }
-    return extractEntityTypeFqn(type, annotatedClass);
-  }
-
-  public FullQualifiedName extractComplexTypeFqn(final Class<?> annotatedClass) {
-    EdmComplexType type = annotatedClass.getAnnotation(EdmComplexType.class);
-    if (type == null) {
-      return null;
-    }
-    return extractComplexTypeFqn(type, annotatedClass);
-  }
-
-  public FullQualifiedName extractComplexTypeFqn(final EdmComplexType type, final Class<?> annotatedClass) {
-    if (type.namespace().isEmpty()) {
-      return new FullQualifiedName(generateNamespace(annotatedClass), extractComplexTypeName(annotatedClass));
-    }
-    return new FullQualifiedName(type.namespace(), extractComplexTypeName(annotatedClass));
-  }
-
-  public String extractComplexTypeName(final Class<?> annotatedClass) {
-    return extractTypeName(annotatedClass, EdmComplexType.class);
-  }
-
-  public String generateNamespace(final Class<?> annotatedClass) {
-    String packageName = annotatedClass.getPackage().getName();
-    return packageName;
-  }
-
-  /**
-   * 
-   * 
-   * @param <T> must be EdmEntityType or EdmComplexType annotation
-   * @param annotatedClass
-   * @param typeAnnotation
-   * @return null if annotatedClass is not annotated or name set via annotation or generated via
-   * {@link #getCanonicalName(java.lang.Class)}
-   */
-  private <T extends Annotation> String extractTypeName(final Class<?> annotatedClass, final Class<T> typeAnnotation) {
-    if (annotatedClass == Object.class) {
-      return null;
-    }
-    T type = annotatedClass.getAnnotation(typeAnnotation);
-    if (type == null) {
-      return null;
-    }
-
-    String name;
-    if (typeAnnotation == EdmEntityType.class) {
-      name = ((EdmEntityType) type).name();
-    } else if (typeAnnotation == EdmComplexType.class) {
-      name = ((EdmComplexType) type).name();
-    } else {
-      return null;
-    }
-
-    if (name.isEmpty()) {
-      return getCanonicalName(annotatedClass);
-    }
-    return name;
-  }
-
-  /**
-   * Get the set property name from an EdmProperty or EdmNavigationProperty annotation.
-   * 
-   * @param field
-   * @return
-   */
-  public String getPropertyNameFromAnnotation(final Field field) {
-    EdmProperty property = field.getAnnotation(EdmProperty.class);
-    if (property == null) {
-      EdmNavigationProperty navProperty = field.getAnnotation(EdmNavigationProperty.class);
-      if (navProperty == null) {
-        throw new EdmAnnotationException("Given field '" + field
-            + "' has no EdmProperty or EdmNavigationProperty annotation.");
-      }
-      return navProperty.name();
-    }
-    return property.name();
-  }
-
-  public String getPropertyName(final Field field) {
-    String propertyName = getPropertyNameFromAnnotation(field);
-    if (propertyName.isEmpty()) {
-      propertyName = getCanonicalName(field);
-    }
-    return propertyName;
-  }
-
-  public String extractFromRoleName(final EdmNavigationProperty enp, final Field field) {
-    return getCanonicalRole(field.getDeclaringClass());
-  }
-
-  public String extractToRoleName(final EdmNavigationProperty enp, final Field field) {
-    String role = enp.toRole();
-    if (role.isEmpty()) {
-      role = getCanonicalRole(
-          field.getType().isArray() || Collection.class.isAssignableFrom(field.getType()) ?
-              (Class<?>) ((ParameterizedType) field.getGenericType()).getActualTypeArguments()[0] : field.getType());
-    }
-    return role;
-  }
-
-  public String getCanonicalRole(final Class<?> fallbackClass) {
-    String toRole = extractEntityTypeName(fallbackClass);
-    return "r_" + toRole;
-  }
-
-  public String extractRelationshipName(final EdmNavigationProperty enp, final Field field) {
-    String relationshipName = enp.association();
-    if (relationshipName.isEmpty()) {
-      final String fromRole = extractFromRoleName(enp, field);
-      final String toRole = extractToRoleName(enp, field);
-      if (fromRole.compareTo(toRole) > 0) {
-        relationshipName = toRole + "-" + fromRole;
-      } else {
-        relationshipName = fromRole + "-" + toRole;
-      }
-    }
-    return relationshipName;
-  }
-
-  public EdmMultiplicity getMultiplicity(final EdmNavigationProperty enp, final Field field) {
-    EdmMultiplicity multiplicity = mapMultiplicity(enp.toMultiplicity());
-    final boolean isCollectionType = field.getType().isArray() || Collection.class.isAssignableFrom(field.getType());
-
-    if (multiplicity == EdmMultiplicity.ONE && isCollectionType) {
-      return EdmMultiplicity.MANY;
-    }
-    return multiplicity;
-  }
-
-  /**
-   * Set key fields based on values in map.
-   * If an key field is not available or <code>NULL</code> in the map
-   * it will be not set as <code>NULL</code> at the instance object.
-   * 
-   * @param instance
-   * @param keys
-   * @return
-   */
-  public <T> T setKeyFields(final T instance, final Map<String, Object> keys) {
-    List<Field> fields = getAnnotatedFields(instance, EdmKey.class);
-
-    for (Field field : fields) {
-      String propertyName = getPropertyName(field);
-      Object keyValue = keys.get(propertyName);
-      setValueForProperty(instance, propertyName, keyValue);
-    }
-
-    return instance;
-  }
-
-  public static final class ODataAnnotationException extends ODataException {
-    private static final long serialVersionUID = 42L;
-
-    public ODataAnnotationException(final String message) {
-      super(message);
-    }
-
-    public ODataAnnotationException(final String message, final Exception cause) {
-      super(message, cause);
-    }
-  }
-
-  public class AnnotatedNavInfo {
-    private final Field fromField;
-    private final Field toField;
-    private final EdmNavigationProperty fromNavigation;
-    private final EdmNavigationProperty toNavigation;
-
-    public AnnotatedNavInfo(final Field fromField, final Field toField, final EdmNavigationProperty fromNavigation,
-        final EdmNavigationProperty toNavigation) {
-      this.fromField = fromField;
-      this.toField = toField;
-      this.fromNavigation = fromNavigation;
-      this.toNavigation = toNavigation;
-    }
-
-    public Field getFromField() {
-      return fromField;
-    }
-
-    public Field getToField() {
-      return toField;
-    }
-
-    public EdmMultiplicity getFromMultiplicity() {
-      return getMultiplicity(toNavigation, toField);
-    }
-
-    public EdmMultiplicity getToMultiplicity() {
-      return getMultiplicity(fromNavigation, fromField);
-    }
-
-    public boolean isBiDirectional() {
-      return toNavigation != null;
-    }
-  }
-
-  public AnnotatedNavInfo getCommonNavigationInfo(final Class<?> sourceClass, final Class<?> targetClass) {
-    List<Field> sourceFields = getAnnotatedFields(sourceClass, EdmNavigationProperty.class);
-    List<Field> targetFields = getAnnotatedFields(targetClass, EdmNavigationProperty.class);
-
-    // first try via association name to get full navigation information
-    for (Field sourceField : sourceFields) {
-      final EdmNavigationProperty sourceNav = sourceField.getAnnotation(EdmNavigationProperty.class);
-      final String sourceAssociation = extractRelationshipName(sourceNav, sourceField);
-      for (Field targetField : targetFields) {
-        final EdmNavigationProperty targetNav = targetField.getAnnotation(EdmNavigationProperty.class);
-        final String targetAssociation = extractRelationshipName(targetNav, targetField);
-        if (sourceAssociation.equals(targetAssociation)) {
-          return new AnnotatedNavInfo(sourceField, targetField, sourceNav, targetNav);
-        }
-      }
-    }
-
-    // if nothing was found assume none bi-directinal navigation
-    String targetEntityTypeName = extractEntityTypeName(targetClass);
-    for (Field sourceField : sourceFields) {
-      final EdmNavigationProperty sourceNav = sourceField.getAnnotation(EdmNavigationProperty.class);
-      final String navTargetEntityName = extractEntitTypeName(sourceNav, sourceField);
-
-      if (navTargetEntityName.equals(targetEntityTypeName)) {
-        return new AnnotatedNavInfo(sourceField, null, sourceNav, null);
-      }
-    }
-
-    return null;
-  }
-
-  public Class<?> getFieldTypeForProperty(final Object instance, final String propertyName)
-      throws ODataAnnotationException {
-    if (instance == null) {
-      return null;
-    }
-
-    Field field = getFieldForPropertyName(instance, propertyName, instance.getClass(), true);
-    if (field == null) {
-      throw new ODataAnnotationException("No field for property '" + propertyName
-          + "' found at class '" + instance.getClass() + "'.");
-    }
-    return field.getType();
-  }
-
-  public Object getValueForProperty(final Object instance, final String propertyName) throws ODataAnnotationException {
-    if (instance == null) {
-      return null;
-    }
-
-    Field field = getFieldForPropertyName(instance, propertyName, instance.getClass(), true);
-    if (field == null) {
-      throw new ODataAnnotationException("No field for property '" + propertyName
-          + "' found at class '" + instance.getClass() + "'.");
-    }
-    return getFieldValue(instance, field);
-  }
-
-  public void setValueForProperty(final Object instance, final String propertyName, final Object propertyValue) {
-    if (instance != null) {
-      Field field = getFieldForPropertyName(instance, propertyName, instance.getClass(), true);
-      if (field != null) {
-        setFieldValue(instance, field, propertyValue);
-      }
-    }
-  }
-
-  private Field getFieldForPropertyName(final Object instance, final String propertyName,
-      final Class<?> resultClass, final boolean inherited) {
-    if (instance == null) {
-      return null;
-    }
-
-    Field[] fields = resultClass.getDeclaredFields();
-    for (Field field : fields) {
-      EdmProperty property = field.getAnnotation(EdmProperty.class);
-      if (property != null) {
-        if (property.name().isEmpty() && getCanonicalName(field).equals(propertyName)) {
-          return field;
-        } else if (property.name().equals(propertyName)) {
-          return field;
-        }
-      }
-    }
-
-    Class<?> superClass = resultClass.getSuperclass();
-    if (inherited && superClass != Object.class) {
-      return getFieldForPropertyName(instance, propertyName, superClass, true);
-    }
-
-    return null;
-  }
-
-  public Object getValueForField(final Object instance, final String fieldName,
-      final Class<? extends Annotation> annotation) {
-    if (instance == null) {
-      return null;
-    }
-    return getValueForField(instance, fieldName, instance.getClass(), annotation, true);
-  }
-
-  public Object getValueForField(final Object instance, final Class<? extends Annotation> annotation) {
-    if (instance == null) {
-      return null;
-    }
-    return getValueForField(instance, instance.getClass(), annotation, true);
-  }
-
-  private Object getValueForField(final Object instance, final Class<?> resultClass,
-      final Class<? extends Annotation> annotation, final boolean inherited) {
-    return getValueForField(instance, null, resultClass, annotation, inherited);
-  }
-
-  public Map<String, Object> getValueForAnnotatedFields(final Object instance,
-      final Class<? extends Annotation> annotation) {
-    return getValueForAnnotatedFields(instance, instance.getClass(), annotation, true);
-  }
-
-  private Map<String, Object> getValueForAnnotatedFields(final Object instance, final Class<?> resultClass,
-      final Class<? extends Annotation> annotation, final boolean inherited) {
-    if (instance == null) {
-      return null;
-    }
-
-    Field[] fields = resultClass.getDeclaredFields();
-    Map<String, Object> fieldName2Value = new HashMap<String, Object>();
-
-    for (Field field : fields) {
-      if (field.getAnnotation(annotation) != null) {
-        Object value = getFieldValue(instance, field);
-        final EdmProperty property = field.getAnnotation(EdmProperty.class);
-        final String name = property == null || property.name().isEmpty() ? field.getName() : property.name();
-        fieldName2Value.put(name, value);
-      }
-    }
-
-    Class<?> superClass = resultClass.getSuperclass();
-    if (inherited && superClass != Object.class) {
-      Map<String, Object> tmp = getValueForAnnotatedFields(instance, superClass, annotation, true);
-      fieldName2Value.putAll(tmp);
-    }
-
-    return fieldName2Value;
-  }
-
-  public void setValueForAnnotatedField(final Object instance, final Class<? extends Annotation> annotation,
-      final Object value)
-      throws ODataAnnotationException {
-    List<Field> fields = getAnnotatedFields(instance, annotation);
-
-    if (fields.isEmpty()) {
-      throw new ODataAnnotationException("No field found for annotation '" + annotation
-          + "' on instance '" + instance + "'.");
-    } else if (fields.size() > 1) {
-      throw new ODataAnnotationException("More then one field found for annotation '" + annotation
-          + "' on instance '" + instance + "'.");
-    }
-
-    setFieldValue(instance, fields.get(0), value);
-  }
-
-  public void setValuesToAnnotatedFields(final Object instance,
-      final Class<? extends Annotation> annotation, final Map<String, Object> fieldName2Value) {
-    List<Field> fields = getAnnotatedFields(instance, annotation);
-
-    // XXX: refactore
-    for (Field field : fields) {
-      final String canonicalName = getCanonicalName(field);
-      if (fieldName2Value.containsKey(canonicalName)) {
-        Object value = fieldName2Value.get(canonicalName);
-        setFieldValue(instance, field, value);
-      }
-    }
-  }
-
-  public List<Field> getAnnotatedFields(final Object instance, final Class<? extends Annotation> annotation) {
-    if (instance == null) {
-      return null;
-    }
-    return getAnnotatedFields(instance.getClass(), annotation, true);
-  }
-
-  public List<Field> getAnnotatedFields(final Class<?> fieldClass, final Class<? extends Annotation> annotation) {
-    return getAnnotatedFields(fieldClass, annotation, true);
-  }
-
-  /**
-   * 
-   * @param instance
-   * @param resultClass
-   * @param annotation
-   * @param inherited
-   * @return
-   */
-  private List<Field> getAnnotatedFields(final Class<?> resultClass,
-      final Class<? extends Annotation> annotation, final boolean inherited) {
-    if (resultClass == null) {
-      return null;
-    }
-
-    Field[] fields = resultClass.getDeclaredFields();
-    List<Field> annotatedFields = new ArrayList<Field>();
-
-    for (Field field : fields) {
-      if (field.getAnnotation(annotation) != null) {
-        annotatedFields.add(field);
-      }
-    }
-
-    Class<?> superClass = resultClass.getSuperclass();
-    if (inherited && superClass != Object.class) {
-      List<Field> tmp = getAnnotatedFields(superClass, annotation, true);
-      annotatedFields.addAll(tmp);
-    }
-
-    return annotatedFields;
-  }
-
-  private Object getValueForField(final Object instance, final String fieldName, final Class<?> resultClass,
-      final Class<? extends Annotation> annotation, final boolean inherited) {
-    if (instance == null) {
-      return null;
-    }
-
-    Field[] fields = resultClass.getDeclaredFields();
-    for (Field field : fields) {
-      if (field.getAnnotation(annotation) != null
-          && (fieldName == null || field.getName().equals(fieldName))) {
-        return getFieldValue(instance, field);
-      }
-    }
-
-    Class<?> superClass = resultClass.getSuperclass();
-    if (inherited && superClass != Object.class) {
-      return getValueForField(instance, fieldName, superClass, annotation, true);
-    }
-
-    return null;
-  }
-
-  private Object getFieldValue(final Object instance, final Field field) {
-    try {
-      boolean access = field.isAccessible();
-      field.setAccessible(true);
-      Object value = field.get(instance);
-      field.setAccessible(access);
-      return value;
-    } catch (IllegalArgumentException ex) { // should never happen
-      throw new ODataRuntimeException(ex);
-    } catch (IllegalAccessException ex) { // should never happen
-      throw new ODataRuntimeException(ex);
-    }
-  }
-
-  private void setFieldValue(final Object instance, final Field field, final Object value) {
-    try {
-      Object usedValue = value;
-      if (value != null
-          && field.getType() != value.getClass()
-          && value.getClass() == String.class) {
-        usedValue = convert(field, (String) value);
-      }
-      boolean access = field.isAccessible();
-      field.setAccessible(true);
-      field.set(instance, usedValue);
-      field.setAccessible(access);
-    } catch (IllegalArgumentException ex) { // should never happen
-      throw new ODataRuntimeException(ex);
-    } catch (IllegalAccessException ex) { // should never happen
-      throw new ODataRuntimeException(ex);
-    }
-  }
-
-  public Object convert(final Field field, final String propertyValue) {
-    Class<?> fieldClass = field.getType();
-    try {
-      EdmProperty property = field.getAnnotation(EdmProperty.class);
-      EdmSimpleTypeKind type = mapTypeKind(property.type());
-      return type.getEdmSimpleTypeInstance().valueOfString(propertyValue,
-          EdmLiteralKind.DEFAULT, null, fieldClass);
-    } catch (EdmSimpleTypeException ex) {
-      throw new ODataRuntimeException("Conversion failed for string property with error: "
-          + ex.getMessage(), ex);
-    }
-  }
-
-  public boolean isEdmAnnotated(final Object object) {
-    if (object == null) {
-      return false;
-    }
-    return isEdmAnnotated(object.getClass());
-  }
-
-  public boolean isEdmTypeAnnotated(final Class<?> clazz) {
-    boolean isComplexEntity = clazz.getAnnotation(EdmComplexType.class) != null;
-    boolean isEntity = clazz.getAnnotation(EdmEntityType.class) != null;
-    return isComplexEntity || isEntity;
-  }
-
-  public boolean isEdmAnnotated(final Class<?> clazz) {
-    if (clazz == null) {
-      return false;
-    } else {
-      final boolean isEntity = null != clazz.getAnnotation(EdmEntityType.class);
-      final boolean isEntitySet = null != clazz.getAnnotation(EdmEntitySet.class);
-      final boolean isComplexEntity = null != clazz.getAnnotation(EdmComplexType.class);
-      return isEntity || isComplexEntity || isEntitySet;
-    }
-  }
-
-  public String getCanonicalName(final Field field) {
-    return firstCharToUpperCase(field.getName());
-  }
-
-  public String getCanonicalName(final Class<?> clazz) {
-    return firstCharToUpperCase(clazz.getSimpleName());
-  }
-
-  private String firstCharToUpperCase(final String content) {
-    if (content == null || content.isEmpty()) {
-      return content;
-    }
-    return content.substring(0, 1).toUpperCase(Locale.ENGLISH) + content.substring(1);
-  }
-
-  public EdmSimpleTypeKind mapTypeKind(final org.apache.olingo.odata2.api.annotation.edm.EdmType type) {
-    switch (type) {
-    case BINARY:
-      return EdmSimpleTypeKind.Binary;
-    case BOOLEAN:
-      return EdmSimpleTypeKind.Boolean;
-    case BYTE:
-      return EdmSimpleTypeKind.Byte;
-    case COMPLEX:
-      return EdmSimpleTypeKind.Null;
-    case DATE_TIME:
-      return EdmSimpleTypeKind.DateTime;
-    case DATE_TIME_OFFSET:
-      return EdmSimpleTypeKind.DateTimeOffset;
-    case DECIMAL:
-      return EdmSimpleTypeKind.Decimal;
-    case DOUBLE:
-      return EdmSimpleTypeKind.Double;
-    case GUID:
-      return EdmSimpleTypeKind.Guid;
-    case INT16:
-      return EdmSimpleTypeKind.Int16;
-    case INT32:
-      return EdmSimpleTypeKind.Int32;
-    case INT64:
-      return EdmSimpleTypeKind.Int64;
-    case NULL:
-      return EdmSimpleTypeKind.Null;
-    case SBYTE:
-      return EdmSimpleTypeKind.SByte;
-    case SINGLE:
-      return EdmSimpleTypeKind.Single;
-    case STRING:
-      return EdmSimpleTypeKind.String;
-    case TIME:
-      return EdmSimpleTypeKind.Time;
-    default:
-      throw new ODataRuntimeException("Unknown type '" + type
-          + "' for mapping to EdmSimpleTypeKind.");
-    }
-  }
-
-  public EdmMultiplicity mapMultiplicity(final Multiplicity multiplicity) {
-    switch (multiplicity) {
-    case ZERO_OR_ONE:
-      return EdmMultiplicity.ZERO_TO_ONE;
-    case ONE:
-      return EdmMultiplicity.ONE;
-    case MANY:
-      return EdmMultiplicity.MANY;
-    default:
-      throw new ODataRuntimeException("Unknown type '" + multiplicity + "' for mapping to EdmMultiplicity.");
-    }
-  }
-
-  /**
-   * 
-   */
-  private static class EdmAnnotationException extends RuntimeException {
-
-    private static final long serialVersionUID = 42L;
-
-    public EdmAnnotationException(final String message) {
-      super(message);
-    }
-  }
-
-  public String getCanonicalNamespace(final Class<?> aClass) {
-    return generateNamespace(aClass);
-  }
-
-  public String extractContainerName(final Class<?> aClass) {
-    EdmEntitySet entitySet = aClass.getAnnotation(EdmEntitySet.class);
-    if (entitySet != null) {
-      String containerName = entitySet.container();
-      if (!containerName.isEmpty()) {
-        return containerName;
-      }
-    }
-    return DEFAULT_CONTAINER_NAME;
-  }
-}

http://git-wip-us.apache.org/repos/asf/incubator-olingo-odata2/blob/3bd59050/odata2-annotation-processor/annotation-processor-core/src/main/java/org/apache/olingo/odata2/core/annotation/util/ClassHelper.java
----------------------------------------------------------------------
diff --git a/odata2-annotation-processor/annotation-processor-core/src/main/java/org/apache/olingo/odata2/core/annotation/util/ClassHelper.java b/odata2-annotation-processor/annotation-processor-core/src/main/java/org/apache/olingo/odata2/core/annotation/util/ClassHelper.java
deleted file mode 100644
index cca35ab..0000000
--- a/odata2-annotation-processor/annotation-processor-core/src/main/java/org/apache/olingo/odata2/core/annotation/util/ClassHelper.java
+++ /dev/null
@@ -1,140 +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.odata2.core.annotation.util;
-
-import java.io.File;
-import java.io.FileFilter;
-import java.io.FilenameFilter;
-import java.lang.reflect.Field;
-import java.net.URL;
-import java.util.ArrayList;
-import java.util.List;
-
-import org.apache.olingo.odata2.core.exception.ODataRuntimeException;
-
-/**
- *
- */
-public class ClassHelper {
-
-  private static final File[] EMPTY_FILE_ARRAY = new File[0];
-
-  private static final FilenameFilter CLASSFILE_FILTER = new FilenameFilter() {
-    @Override
-    public boolean accept(final File dir, final String name) {
-      return name.endsWith(CLASSFILE_ENDING);
-    }
-
-    public static final String CLASSFILE_ENDING = ".class";
-  };
-
-  private static final FileFilter FOLDER_FILTER = new FileFilter() {
-    @Override
-    public boolean accept(final File pathname) {
-      return pathname.isDirectory();
-    }
-  };
-
-  public static final List<Class<?>> loadClasses(final String packageToScan, final ClassValidator cv) {
-    return loadClasses(packageToScan, CLASSFILE_FILTER, cv);
-  }
-
-  public static final List<Class<?>> loadClasses(final String packageToScan, final FilenameFilter ff,
-      final ClassValidator cv) {
-    final ClassLoader classLoader = Thread.currentThread().getContextClassLoader();
-    String folderToScan = packageToScan.replace(".", "/");
-    URL url = classLoader.getResource(folderToScan);
-    if (url == null) {
-      throw new IllegalArgumentException("No folder to scan found for package '" + packageToScan + "'.");
-    }
-    File folder = new File(url.getFile());
-    File[] classFiles = folder.listFiles(ff);
-    if (classFiles == null) {
-      classFiles = EMPTY_FILE_ARRAY;
-    }
-
-    List<Class<?>> annotatedClasses = new ArrayList<Class<?>>(classFiles.length);
-    for (File file : classFiles) {
-      String name = file.getName();
-      String fqn = packageToScan + "." + name.substring(0, name.length() - 6);
-      try {
-        Class<?> c = classLoader.loadClass(fqn);
-        if (cv.isClassValid(c)) {
-          annotatedClasses.add(c);
-        }
-      } catch (ClassNotFoundException ex) {
-        throw new IllegalArgumentException("Exception during class loading of class '" + fqn +
-            "' with message '" + ex.getMessage() + "'.");
-      }
-    }
-
-    // recursive search
-    File[] subfolders = listSubFolder(folder);
-    for (File file : subfolders) {
-      List<Class<?>> subFolderClazzes = loadClasses(packageToScan + "." + file.getName(), ff, cv);
-      annotatedClasses.addAll(subFolderClazzes);
-    }
-    //
-
-    return annotatedClasses;
-  }
-
-  public static Object getFieldValue(final Object instance, final Field field) {
-    try {
-      synchronized (field) {
-        boolean access = field.isAccessible();
-        field.setAccessible(true);
-        Object value = field.get(instance);
-        field.setAccessible(access);
-        return value;
-      }
-    } catch (IllegalArgumentException ex) { // should never happen
-      throw new ODataRuntimeException(ex);
-    } catch (IllegalAccessException ex) { // should never happen
-      throw new ODataRuntimeException(ex);
-    }
-  }
-
-  public static void setFieldValue(final Object instance, final Field field, final Object value) {
-    try {
-      synchronized (field) {
-        boolean access = field.isAccessible();
-        field.setAccessible(true);
-        field.set(instance, value);
-        field.setAccessible(access);
-      }
-    } catch (IllegalArgumentException ex) { // should never happen
-      throw new ODataRuntimeException(ex);
-    } catch (IllegalAccessException ex) { // should never happen
-      throw new ODataRuntimeException(ex);
-    }
-  }
-
-  private static File[] listSubFolder(final File folder) {
-    File[] subfolders = folder.listFiles(FOLDER_FILTER);
-    if (subfolders == null) {
-      return EMPTY_FILE_ARRAY;
-    }
-    return subfolders;
-  }
-
-  public interface ClassValidator {
-    boolean isClassValid(Class<?> c);
-  }
-}

http://git-wip-us.apache.org/repos/asf/incubator-olingo-odata2/blob/3bd59050/odata2-annotation-processor/annotation-processor-core/src/test/java/org/apache/olingo/odata2/core/annotation/data/AnnotationsInMemoryDsTest.java
----------------------------------------------------------------------
diff --git a/odata2-annotation-processor/annotation-processor-core/src/test/java/org/apache/olingo/odata2/core/annotation/data/AnnotationsInMemoryDsTest.java b/odata2-annotation-processor/annotation-processor-core/src/test/java/org/apache/olingo/odata2/core/annotation/data/AnnotationsInMemoryDsTest.java
index 3e2fbd4..5059327 100644
--- a/odata2-annotation-processor/annotation-processor-core/src/test/java/org/apache/olingo/odata2/core/annotation/data/AnnotationsInMemoryDsTest.java
+++ b/odata2-annotation-processor/annotation-processor-core/src/test/java/org/apache/olingo/odata2/core/annotation/data/AnnotationsInMemoryDsTest.java
@@ -25,22 +25,24 @@ import java.util.Map;
 import java.util.concurrent.CountDownLatch;
 import java.util.concurrent.TimeUnit;
 
+import org.apache.olingo.odata2.annotation.processor.core.datasource.AnnotationInMemoryDs;
+import org.apache.olingo.odata2.annotation.processor.core.datasource.DataSource;
+import org.apache.olingo.odata2.annotation.processor.core.datasource.DataStore;
+import org.apache.olingo.odata2.annotation.processor.core.datasource.DataSource.BinaryData;
+import org.apache.olingo.odata2.annotation.processor.core.edm.AnnotationEdmProvider;
+import org.apache.olingo.odata2.annotation.processor.core.util.AnnotationHelper;
 import org.apache.olingo.odata2.api.annotation.edm.EdmKey;
 import org.apache.olingo.odata2.api.annotation.edm.EdmProperty;
-import org.apache.olingo.odata2.api.data.DataSource;
-import org.apache.olingo.odata2.api.data.DataSource.BinaryData;
 import org.apache.olingo.odata2.api.edm.EdmEntitySet;
 import org.apache.olingo.odata2.api.edm.EdmEntityType;
 import org.apache.olingo.odata2.api.edm.FullQualifiedName;
 import org.apache.olingo.odata2.api.edm.provider.EntitySet;
 import org.apache.olingo.odata2.api.exception.ODataException;
 import org.apache.olingo.odata2.api.exception.ODataNotFoundException;
-import org.apache.olingo.odata2.core.annotation.edm.AnnotationEdmProvider;
 import org.apache.olingo.odata2.core.annotation.model.Building;
 import org.apache.olingo.odata2.core.annotation.model.ModelSharedConstants;
 import org.apache.olingo.odata2.core.annotation.model.Photo;
 import org.apache.olingo.odata2.core.annotation.model.Room;
-import org.apache.olingo.odata2.core.annotation.util.AnnotationHelper;
 import org.apache.olingo.odata2.core.exception.ODataRuntimeException;
 import org.junit.Assert;
 import org.junit.Ignore;

http://git-wip-us.apache.org/repos/asf/incubator-olingo-odata2/blob/3bd59050/odata2-annotation-processor/annotation-processor-core/src/test/java/org/apache/olingo/odata2/core/annotation/edm/AnnotationEdmProviderTest.java
----------------------------------------------------------------------
diff --git a/odata2-annotation-processor/annotation-processor-core/src/test/java/org/apache/olingo/odata2/core/annotation/edm/AnnotationEdmProviderTest.java b/odata2-annotation-processor/annotation-processor-core/src/test/java/org/apache/olingo/odata2/core/annotation/edm/AnnotationEdmProviderTest.java
index b6863c6..2f9a1e7 100644
--- a/odata2-annotation-processor/annotation-processor-core/src/test/java/org/apache/olingo/odata2/core/annotation/edm/AnnotationEdmProviderTest.java
+++ b/odata2-annotation-processor/annotation-processor-core/src/test/java/org/apache/olingo/odata2/core/annotation/edm/AnnotationEdmProviderTest.java
@@ -27,6 +27,7 @@ import java.util.Arrays;
 import java.util.Collection;
 import java.util.List;
 
+import org.apache.olingo.odata2.annotation.processor.core.edm.AnnotationEdmProvider;
 import org.apache.olingo.odata2.api.annotation.edm.EdmComplexType;
 import org.apache.olingo.odata2.api.annotation.edm.EdmEntitySet;
 import org.apache.olingo.odata2.api.annotation.edm.EdmEntityType;

http://git-wip-us.apache.org/repos/asf/incubator-olingo-odata2/blob/3bd59050/odata2-annotation-processor/annotation-processor-webref/src/main/java/org/apache/olingo/odata2/annotation/processor/ref/AnnotationRefServiceFactory.java
----------------------------------------------------------------------
diff --git a/odata2-annotation-processor/annotation-processor-webref/src/main/java/org/apache/olingo/odata2/annotation/processor/ref/AnnotationRefServiceFactory.java b/odata2-annotation-processor/annotation-processor-webref/src/main/java/org/apache/olingo/odata2/annotation/processor/ref/AnnotationRefServiceFactory.java
new file mode 100644
index 0000000..ccaca81
--- /dev/null
+++ b/odata2-annotation-processor/annotation-processor-webref/src/main/java/org/apache/olingo/odata2/annotation/processor/ref/AnnotationRefServiceFactory.java
@@ -0,0 +1,215 @@
+/**
+ * *****************************************************************************
+ * Licensed to the Apache Software Foundation (ASF) under one or more contributor license agreements. See the NOTICE
+ * file distributed with this work for additional information regarding copyright ownership. The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the "License"); you may not use this file except in compliance with the
+ * License. You may obtain a copy of the License at
+ * 
+ * http://www.apache.org/licenses/LICENSE-2.0
+ * 
+ * Unless required by applicable law or agreed to in writing, software distributed under the License is distributed on
+ * an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the License for the
+ * specific language governing permissions and limitations under the License.
+ ***************************************************************************** 
+ */
+package org.apache.olingo.odata2.annotation.processor.ref;
+
+import java.util.Calendar;
+
+import org.apache.olingo.odata2.annotation.processor.api.AnnotationServiceFactory;
+import org.apache.olingo.odata2.annotation.processor.core.datasource.DataStore;
+import org.apache.olingo.odata2.annotation.processor.core.datasource.DataStore.DataStoreException;
+import org.apache.olingo.odata2.annotation.processor.ref.model.Building;
+import org.apache.olingo.odata2.annotation.processor.ref.model.Employee;
+import org.apache.olingo.odata2.annotation.processor.ref.model.Location;
+import org.apache.olingo.odata2.annotation.processor.ref.model.Manager;
+import org.apache.olingo.odata2.annotation.processor.ref.model.Photo;
+import org.apache.olingo.odata2.annotation.processor.ref.model.ResourceHelper;
+import org.apache.olingo.odata2.annotation.processor.ref.model.Room;
+import org.apache.olingo.odata2.annotation.processor.ref.model.Team;
+import org.apache.olingo.odata2.api.ODataCallback;
+import org.apache.olingo.odata2.api.ODataDebugCallback;
+import org.apache.olingo.odata2.api.ODataService;
+import org.apache.olingo.odata2.api.ODataServiceFactory;
+import org.apache.olingo.odata2.api.commons.HttpStatusCodes;
+import org.apache.olingo.odata2.api.ep.EntityProvider;
+import org.apache.olingo.odata2.api.exception.ODataApplicationException;
+import org.apache.olingo.odata2.api.exception.ODataException;
+import org.apache.olingo.odata2.api.processor.ODataContext;
+import org.apache.olingo.odata2.api.processor.ODataErrorCallback;
+import org.apache.olingo.odata2.api.processor.ODataErrorContext;
+import org.apache.olingo.odata2.api.processor.ODataResponse;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+
+/**
+ * ODataServiceFactory implemantion based on ListProcessor
+ * in combination with Annotation-Support-Classes for EdmProvider, DataSource and ValueAccess.
+ */
+public class AnnotationRefServiceFactory extends ODataServiceFactory {
+
+  /**
+   * Instance holder for all annotation relevant instances which should be used as singleton
+   * instances within the ODataApplication (ODataService)
+   */
+  private static class AnnotationInstances {
+    final static String MODEL_PACKAGE = "org.apache.olingo.odata2.annotation.processor.ref.model";
+
+    final static ODataService ANNOTATION_ODATA_SERVICE;
+    
+    static {
+      try {
+        ANNOTATION_ODATA_SERVICE = AnnotationServiceFactory.createAnnotationService(MODEL_PACKAGE);
+        initializeSampleData();
+      } catch (ODataApplicationException ex) {
+        throw new RuntimeException("Exception during sample data generation.", ex);
+      } catch (ODataException ex) {
+        throw new RuntimeException("Exception during data source initialization generation.", ex);
+      }
+    }
+  }
+
+  @Override
+  public ODataService createService(final ODataContext context) throws ODataException {
+    // Edm via Annotations and ListProcessor via AnnotationDS with AnnotationsValueAccess
+    return AnnotationInstances.ANNOTATION_ODATA_SERVICE;
+  }
+
+  @SuppressWarnings("unchecked")
+  @Override
+  public <T extends ODataCallback> T getCallback(final Class<? extends ODataCallback> callbackInterface) {
+    return (T) (callbackInterface.isAssignableFrom(ScenarioErrorCallback.class)
+        ? new ScenarioErrorCallback() : callbackInterface.isAssignableFrom(ODataDebugCallback.class)
+            ? new ScenarioDebugCallback() : super.getCallback(callbackInterface));
+  }
+
+  /*
+   * Helper classes and methods
+   */
+
+  /**
+   * Callback class to enable debugging.
+   */
+  private final class ScenarioDebugCallback implements ODataDebugCallback {
+
+    @Override
+    public boolean isDebugEnabled() {
+      return true;
+    }
+  }
+
+  /**
+   * Callback class for error handling.
+   */
+  private class ScenarioErrorCallback implements ODataErrorCallback {
+
+    private final Logger LOG = LoggerFactory.getLogger(ScenarioErrorCallback.class);
+
+    @Override
+    public ODataResponse handleError(final ODataErrorContext context) throws ODataApplicationException {
+      if (context.getHttpStatus() == HttpStatusCodes.INTERNAL_SERVER_ERROR) {
+        LOG.error("Internal Server Error", context.getException());
+      }
+
+      return EntityProvider.writeErrorDocument(context);
+    }
+
+  }
+
+  private static <T> DataStore<T> getDataStore(Class<T> clz) throws DataStoreException {
+    return DataStore.createInMemory(clz, true);
+  }
+  
+  private static void initializeSampleData() throws ODataApplicationException {
+    DataStore<Team> teamDs = getDataStore(Team.class);
+    teamDs.create(createTeam("Team Alpha", true));
+    teamDs.create(createTeam("Team Beta", false));
+    teamDs.create(createTeam("Team Gamma", false));
+    teamDs.create(createTeam("Team Omega", true));
+    teamDs.create(createTeam("Team Zeta", true));
+
+    DataStore<Building> buildingsDs = getDataStore(Building.class);
+    Building redBuilding = createBuilding("Red Building");
+    buildingsDs.create(redBuilding);
+    Building greenBuilding = createBuilding("Green Building");
+    buildingsDs.create(greenBuilding);
+    Building blueBuilding = createBuilding("Blue Building");
+    buildingsDs.create(blueBuilding);
+    Building yellowBuilding = createBuilding("Yellow Building");
+    buildingsDs.create(yellowBuilding);
+
+    DataStore<Photo> photoDs = getDataStore(Photo.class);
+    photoDs.create(createPhoto("Small picture", ResourceHelper.Format.GIF));
+    photoDs.create(createPhoto("Medium picture", ResourceHelper.Format.PNG));
+    photoDs.create(createPhoto("Big picture", ResourceHelper.Format.JPEG));
+    photoDs.create(createPhoto("Huge picture", ResourceHelper.Format.BMP));
+
+    DataStore<Room> roomDs = getDataStore(Room.class);
+    roomDs.create(createRoom("Tiny red room", 5, 1, redBuilding));
+    roomDs.create(createRoom("Small red room", 20, 1, redBuilding));
+    roomDs.create(createRoom("Small green room", 20, 1, greenBuilding));
+    roomDs.create(createRoom("Big blue room", 40, 1, blueBuilding));
+    roomDs.create(createRoom("Huge blue room", 120, 1, blueBuilding));
+    roomDs.create(createRoom("Huge yellow room", 120, 1, yellowBuilding));
+
+    DataStore<Employee> employeeDataStore = getDataStore(Employee.class);
+    employeeDataStore.create(createEmployee("first Employee",
+        new Location("Norge", "8392", "Ä"), 42, null,
+        photoDs.read().iterator().next().getImage(), photoDs.read().iterator().next().getImageType(),
+        "http://localhost/image/first.png",
+        null, teamDs.read().iterator().next(), roomDs.read().iterator().next()));
+  }
+
+  private static Employee createEmployee(final String name,
+      final Location location, final int age, final Calendar date,
+      final byte[] image, final String imageType, final String imageUrl,
+      final Manager manager, final Team team, final Room room) {
+    Employee employee = new Employee();
+    employee.setEmployeeName(name);
+    employee.setLocation(location);
+    employee.setAge(age);
+    employee.setEntryDate(date);
+    employee.setImage(image);
+    employee.setImageType(imageType);
+    employee.setImageUri(imageUrl);
+    employee.setManager(manager);
+    employee.setTeam(team);
+    employee.setRoom(room);
+    return employee;
+  }
+
+  private static Team createTeam(final String teamName, final boolean isScrumTeam) {
+    Team team = new Team();
+    team.setName(teamName);
+    team.setScrumTeam(isScrumTeam);
+    return team;
+  }
+
+  private static Building createBuilding(final String buildingName) {
+    Building b = new Building();
+    b.setName(buildingName);
+    return b;
+  }
+
+  private static Photo createPhoto(final String name, final ResourceHelper.Format format) {
+    Photo p = new Photo();
+    p.setName(name);
+    p.setImageUri("http://localhost/image/" + name);
+    p.setType(format.name());
+    p.setImageType("image/" + format.name().toLowerCase());
+    p.setImage(ResourceHelper.generateImage(format));
+    return p;
+  }
+
+  private static Room createRoom(final String name, final int seats, final int version, final Building building) {
+    Room r = new Room();
+    r.setName(name);
+    r.setSeats(seats);
+    r.setVersion(version);
+    r.setBuilding(building);
+
+    building.addRoom(r);
+
+    return r;
+  }
+}

http://git-wip-us.apache.org/repos/asf/incubator-olingo-odata2/blob/3bd59050/odata2-annotation-processor/annotation-processor-webref/src/main/java/org/apache/olingo/odata2/annotation/processor/ref/model/Building.java
----------------------------------------------------------------------
diff --git a/odata2-annotation-processor/annotation-processor-webref/src/main/java/org/apache/olingo/odata2/annotation/processor/ref/model/Building.java b/odata2-annotation-processor/annotation-processor-webref/src/main/java/org/apache/olingo/odata2/annotation/processor/ref/model/Building.java
new file mode 100644
index 0000000..125c936
--- /dev/null
+++ b/odata2-annotation-processor/annotation-processor-webref/src/main/java/org/apache/olingo/odata2/annotation/processor/ref/model/Building.java
@@ -0,0 +1,97 @@
+/*******************************************************************************
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License. You may obtain a copy of the License at
+ * 
+ * http://www.apache.org/licenses/LICENSE-2.0
+ * 
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied. See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ ******************************************************************************/
+package org.apache.olingo.odata2.annotation.processor.ref.model;
+
+import java.util.ArrayList;
+import java.util.Arrays;
+import java.util.List;
+
+import org.apache.olingo.odata2.api.annotation.edm.EdmEntitySet;
+import org.apache.olingo.odata2.api.annotation.edm.EdmEntityType;
+import org.apache.olingo.odata2.api.annotation.edm.EdmKey;
+import org.apache.olingo.odata2.api.annotation.edm.EdmNavigationProperty;
+import org.apache.olingo.odata2.api.annotation.edm.EdmNavigationProperty.Multiplicity;
+import org.apache.olingo.odata2.api.annotation.edm.EdmProperty;
+import org.apache.olingo.odata2.api.annotation.edm.EdmType;
+
+/**
+ *  
+ */
+@EdmEntityType(name = "Building", namespace = ModelSharedConstants.NAMESPACE_1)
+@EdmEntitySet(name = "Buildings")
+public class Building {
+  @EdmKey
+  @EdmProperty(type = EdmType.INT32)
+  private int id;
+  @EdmProperty
+  private String name;
+  @EdmProperty(name = "Image", type = EdmType.BINARY)
+  private byte[] image;
+  @EdmNavigationProperty(name = "nb_Rooms", toType = Room.class,
+      association = "BuildingRooms", toMultiplicity = Multiplicity.MANY)
+  private List<Room> rooms = new ArrayList<Room>();
+
+  public String getId() {
+    return Integer.toString(id);
+  }
+
+  public void setName(final String name) {
+    this.name = name;
+  }
+
+  public String getName() {
+    return name;
+  }
+
+  public void setImage(final byte[] byteArray) {
+    image = byteArray;
+  }
+
+  public byte[] getImage() {
+    if (image == null) {
+      return null;
+    } else {
+      return image.clone();
+    }
+  }
+
+  public void addRoom(final Room room) {
+    rooms.add(room);
+  }
+
+  public List<Room> getRooms() {
+    return rooms;
+  }
+
+  @Override
+  public int hashCode() {
+    return id;
+  }
+
+  @Override
+  public boolean equals(final Object obj) {
+    return this == obj
+        || obj != null && getClass() == obj.getClass() && id == ((Building) obj).id;
+  }
+
+  @Override
+  public String toString() {
+    return "{\"Id\":\"" + id + "\",\"Name\":\"" + name + "\",\"Image\":\"" + Arrays.toString(image) + "\"}";
+  }
+}

http://git-wip-us.apache.org/repos/asf/incubator-olingo-odata2/blob/3bd59050/odata2-annotation-processor/annotation-processor-webref/src/main/java/org/apache/olingo/odata2/annotation/processor/ref/model/City.java
----------------------------------------------------------------------
diff --git a/odata2-annotation-processor/annotation-processor-webref/src/main/java/org/apache/olingo/odata2/annotation/processor/ref/model/City.java b/odata2-annotation-processor/annotation-processor-webref/src/main/java/org/apache/olingo/odata2/annotation/processor/ref/model/City.java
new file mode 100644
index 0000000..7a72178
--- /dev/null
+++ b/odata2-annotation-processor/annotation-processor-webref/src/main/java/org/apache/olingo/odata2/annotation/processor/ref/model/City.java
@@ -0,0 +1,61 @@
+/*******************************************************************************
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License. You may obtain a copy of the License at
+ * 
+ * http://www.apache.org/licenses/LICENSE-2.0
+ * 
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied. See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ ******************************************************************************/
+package org.apache.olingo.odata2.annotation.processor.ref.model;
+
+import org.apache.olingo.odata2.api.annotation.edm.EdmComplexType;
+import org.apache.olingo.odata2.api.annotation.edm.EdmProperty;
+
+/**
+ *  
+ */
+@EdmComplexType(name = "c_City", namespace = ModelSharedConstants.NAMESPACE_1)
+public class City {
+
+  @EdmProperty
+  private String postalCode;
+  @EdmProperty
+  private String cityName;
+
+  public City(final String postalCode, final String name) {
+    this.postalCode = postalCode;
+    cityName = name;
+  }
+
+  public void setPostalCode(final String postalCode) {
+    this.postalCode = postalCode;
+  }
+
+  public String getPostalCode() {
+    return postalCode;
+  }
+
+  public void setCityName(final String cityName) {
+    this.cityName = cityName;
+  }
+
+  public String getCityName() {
+    return cityName;
+  }
+
+  @Override
+  public String toString() {
+    return String.format("%s, %s", cityName, postalCode);
+  }
+
+}

http://git-wip-us.apache.org/repos/asf/incubator-olingo-odata2/blob/3bd59050/odata2-annotation-processor/annotation-processor-webref/src/main/java/org/apache/olingo/odata2/annotation/processor/ref/model/Employee.java
----------------------------------------------------------------------
diff --git a/odata2-annotation-processor/annotation-processor-webref/src/main/java/org/apache/olingo/odata2/annotation/processor/ref/model/Employee.java b/odata2-annotation-processor/annotation-processor-webref/src/main/java/org/apache/olingo/odata2/annotation/processor/ref/model/Employee.java
new file mode 100644
index 0000000..98d57ca
--- /dev/null
+++ b/odata2-annotation-processor/annotation-processor-webref/src/main/java/org/apache/olingo/odata2/annotation/processor/ref/model/Employee.java
@@ -0,0 +1,192 @@
+/*******************************************************************************
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License. You may obtain a copy of the License at
+ * 
+ * http://www.apache.org/licenses/LICENSE-2.0
+ * 
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied. See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ ******************************************************************************/
+package org.apache.olingo.odata2.annotation.processor.ref.model;
+
+import java.text.DateFormat;
+import java.util.Calendar;
+
+import org.apache.olingo.odata2.api.annotation.edm.EdmEntitySet;
+import org.apache.olingo.odata2.api.annotation.edm.EdmEntityType;
+import org.apache.olingo.odata2.api.annotation.edm.EdmFacets;
+import org.apache.olingo.odata2.api.annotation.edm.EdmKey;
+import org.apache.olingo.odata2.api.annotation.edm.EdmMediaResourceContent;
+import org.apache.olingo.odata2.api.annotation.edm.EdmMediaResourceMimeType;
+import org.apache.olingo.odata2.api.annotation.edm.EdmNavigationProperty;
+import org.apache.olingo.odata2.api.annotation.edm.EdmProperty;
+import org.apache.olingo.odata2.api.annotation.edm.EdmType;
+
+/**
+ *  
+ */
+@EdmEntityType(name = "Employee", namespace = ModelSharedConstants.NAMESPACE_1)
+@EdmEntitySet(name = "Employees")
+public class Employee {
+  @EdmKey
+  @EdmProperty(name = "EmployeeId", type = EdmType.STRING)
+  private String employeeId;
+  @EdmProperty(name = "EmployeeName")
+  private String employeeName;
+  @EdmProperty
+  private int age;
+  @EdmNavigationProperty(name = "ne_Manager", association = "ManagerEmployees")
+  private Manager manager;
+  @EdmNavigationProperty(name = "ne_Team", association = "TeamEmployees")
+  private Team team;
+  @EdmNavigationProperty(name = "ne_Room")
+  private Room room;
+  @EdmMediaResourceMimeType
+  private String imageType;
+  @EdmMediaResourceContent
+  private byte[] image;
+  @EdmProperty(name = "ImageUrl")
+  private String imageUrl;
+  @EdmProperty(name = "EntryDate", type = EdmType.DATE_TIME,
+      facets = @EdmFacets(nullable = true))
+  private Calendar entryDate;
+  @EdmProperty(name = "Location", facets = @EdmFacets(nullable = false))
+  private Location location;
+
+  public String getId() {
+    return employeeId;
+  }
+
+  public void setEmployeeName(final String employeeName) {
+    this.employeeName = employeeName;
+  }
+
+  public String getEmployeeName() {
+    return employeeName;
+  }
+
+  public void setAge(final int age) {
+    this.age = age;
+  }
+
+  public int getAge() {
+    return age;
+  }
+
+  public void setManager(final Manager manager) {
+    this.manager = manager;
+  }
+
+  public Manager getManager() {
+    return manager;
+  }
+
+  public void setTeam(final Team team) {
+    this.team = team;
+  }
+
+  public Team getTeam() {
+    return team;
+  }
+
+  public void setRoom(final Room room) {
+    this.room = room;
+  }
+
+  public Room getRoom() {
+    return room;
+  }
+
+  public void setImageUri(final String imageUri) {
+    imageUrl = imageUri;
+  }
+
+  public String getImageUri() {
+    return imageUrl;
+  }
+
+  public void setLocation(final Location location) {
+    this.location = location;
+  }
+
+  public Location getLocation() {
+    return location;
+  }
+
+  public void setEntryDate(final Calendar date) {
+    entryDate = date;
+  }
+
+  public Calendar getEntryDate() {
+    return entryDate;
+  }
+
+  public void setImageType(final String imageType) {
+    this.imageType = imageType;
+  }
+
+  public String getImageType() {
+    return imageType;
+  }
+
+  public void setImage(final byte[] image) {
+    this.image = image;
+  }
+
+  public void setImage(final String imageUrl) {
+    image = loadImage(imageUrl);
+  }
+
+  private static byte[] loadImage(final String imageUrl) {
+    return ResourceHelper.loadAsByte(imageUrl);
+  }
+
+  public byte[] getImage() {
+    if (image == null) {
+      return null;
+    }
+    return image.clone();
+  }
+
+  @Override
+  public int hashCode() {
+    if (employeeId == null) {
+      return 0;
+    }
+    return employeeId.hashCode();
+  }
+
+  @Override
+  public boolean equals(final Object obj) {
+    return this == obj
+        || obj != null && getClass() == obj.getClass() && employeeId == ((Employee) obj).employeeId;
+  }
+
+  @Override
+  public String toString() {
+    return "{\"EmployeeId\":\"" + employeeId + "\","
+        + "\"EmployeeName\":\"" + employeeName + "\","
+        + "\"ManagerId\":" + (manager == null ? "null" : "\"" + manager.getId() + "\"") + ","
+        + "\"RoomId\":" + (room == null ? "null" : "\"" + room.getId() + "\"") + ","
+        + "\"TeamId\":" + (team == null ? "null" : "\"" + team.getId() + "\"") + ","
+        + "\"Location\":"
+        + (location == null ? "null" :
+            "{\"City\":" + (location.getCity() == null ? "null" :
+                "{\"PostalCode\":\"" + location.getCity().getPostalCode() + "\","
+                    + "\"CityName\":\"" + location.getCity().getCityName() + "\"}") + ","
+                + "\"Country\":\"" + location.getCountry() + "\"}") + ","
+        + "\"Age\":" + age + ","
+        + "\"EntryDate\":"
+        + (entryDate == null ? "null" : "\"" + DateFormat.getInstance().format(entryDate.getTime()) + "\"") + ","
+        + "\"ImageUrl\":\"" + imageUrl + "\"}";
+  }
+}

http://git-wip-us.apache.org/repos/asf/incubator-olingo-odata2/blob/3bd59050/odata2-annotation-processor/annotation-processor-webref/src/main/java/org/apache/olingo/odata2/annotation/processor/ref/model/Location.java
----------------------------------------------------------------------
diff --git a/odata2-annotation-processor/annotation-processor-webref/src/main/java/org/apache/olingo/odata2/annotation/processor/ref/model/Location.java b/odata2-annotation-processor/annotation-processor-webref/src/main/java/org/apache/olingo/odata2/annotation/processor/ref/model/Location.java
new file mode 100644
index 0000000..b131f7e
--- /dev/null
+++ b/odata2-annotation-processor/annotation-processor-webref/src/main/java/org/apache/olingo/odata2/annotation/processor/ref/model/Location.java
@@ -0,0 +1,60 @@
+/*******************************************************************************
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License. You may obtain a copy of the License at
+ * 
+ * http://www.apache.org/licenses/LICENSE-2.0
+ * 
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied. See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ ******************************************************************************/
+package org.apache.olingo.odata2.annotation.processor.ref.model;
+
+import org.apache.olingo.odata2.api.annotation.edm.EdmComplexType;
+import org.apache.olingo.odata2.api.annotation.edm.EdmProperty;
+
+/**
+ *  
+ */
+@EdmComplexType(name = "c_Location", namespace = ModelSharedConstants.NAMESPACE_1)
+public class Location {
+  @EdmProperty
+  private String country;
+  @EdmProperty
+  private City city;
+
+  public Location(final String country, final String postalCode, final String cityName) {
+    this.country = country;
+    city = new City(postalCode, cityName);
+  }
+
+  public void setCountry(final String country) {
+    this.country = country;
+  }
+
+  public String getCountry() {
+    return country;
+  }
+
+  public void setCity(final City city) {
+    this.city = city;
+  }
+
+  public City getCity() {
+    return city;
+  }
+
+  @Override
+  public String toString() {
+    return String.format("%s, %s", country, city.toString());
+  }
+
+}

http://git-wip-us.apache.org/repos/asf/incubator-olingo-odata2/blob/3bd59050/odata2-annotation-processor/annotation-processor-webref/src/main/java/org/apache/olingo/odata2/annotation/processor/ref/model/Manager.java
----------------------------------------------------------------------
diff --git a/odata2-annotation-processor/annotation-processor-webref/src/main/java/org/apache/olingo/odata2/annotation/processor/ref/model/Manager.java b/odata2-annotation-processor/annotation-processor-webref/src/main/java/org/apache/olingo/odata2/annotation/processor/ref/model/Manager.java
new file mode 100644
index 0000000..136c476
--- /dev/null
+++ b/odata2-annotation-processor/annotation-processor-webref/src/main/java/org/apache/olingo/odata2/annotation/processor/ref/model/Manager.java
@@ -0,0 +1,43 @@
+/*******************************************************************************
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License. You may obtain a copy of the License at
+ * 
+ * http://www.apache.org/licenses/LICENSE-2.0
+ * 
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied. See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ ******************************************************************************/
+package org.apache.olingo.odata2.annotation.processor.ref.model;
+
+import java.util.ArrayList;
+import java.util.List;
+
+import org.apache.olingo.odata2.api.annotation.edm.EdmEntitySet;
+import org.apache.olingo.odata2.api.annotation.edm.EdmEntityType;
+import org.apache.olingo.odata2.api.annotation.edm.EdmNavigationProperty;
+import org.apache.olingo.odata2.api.annotation.edm.EdmNavigationProperty.Multiplicity;
+
+/**
+ *
+ */
+@EdmEntityType(name = "Manager", namespace = ModelSharedConstants.NAMESPACE_1)
+@EdmEntitySet(name = "Managers")
+public class Manager extends Employee {
+
+  @EdmNavigationProperty(name = "nm_Employees", association = "ManagerEmployees",
+      toMultiplicity = Multiplicity.MANY)
+  private List<Employee> employees = new ArrayList<Employee>();
+
+  public List<Employee> getEmployees() {
+    return employees;
+  }
+}

http://git-wip-us.apache.org/repos/asf/incubator-olingo-odata2/blob/3bd59050/odata2-annotation-processor/annotation-processor-webref/src/main/java/org/apache/olingo/odata2/annotation/processor/ref/model/ModelSharedConstants.java
----------------------------------------------------------------------
diff --git a/odata2-annotation-processor/annotation-processor-webref/src/main/java/org/apache/olingo/odata2/annotation/processor/ref/model/ModelSharedConstants.java b/odata2-annotation-processor/annotation-processor-webref/src/main/java/org/apache/olingo/odata2/annotation/processor/ref/model/ModelSharedConstants.java
new file mode 100644
index 0000000..05cb2db
--- /dev/null
+++ b/odata2-annotation-processor/annotation-processor-webref/src/main/java/org/apache/olingo/odata2/annotation/processor/ref/model/ModelSharedConstants.java
@@ -0,0 +1,25 @@
+/*******************************************************************************
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License. You may obtain a copy of the License at
+ * 
+ * http://www.apache.org/licenses/LICENSE-2.0
+ * 
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied. See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ ******************************************************************************/
+package org.apache.olingo.odata2.annotation.processor.ref.model;
+
+public interface ModelSharedConstants {
+
+  String NAMESPACE_1 = "RefScenario";
+  String CONTAINER_1 = "Container1";
+}

http://git-wip-us.apache.org/repos/asf/incubator-olingo-odata2/blob/3bd59050/odata2-annotation-processor/annotation-processor-webref/src/main/java/org/apache/olingo/odata2/annotation/processor/ref/model/Photo.java
----------------------------------------------------------------------
diff --git a/odata2-annotation-processor/annotation-processor-webref/src/main/java/org/apache/olingo/odata2/annotation/processor/ref/model/Photo.java b/odata2-annotation-processor/annotation-processor-webref/src/main/java/org/apache/olingo/odata2/annotation/processor/ref/model/Photo.java
new file mode 100644
index 0000000..d0285ec
--- /dev/null
+++ b/odata2-annotation-processor/annotation-processor-webref/src/main/java/org/apache/olingo/odata2/annotation/processor/ref/model/Photo.java
@@ -0,0 +1,128 @@
+/*******************************************************************************
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License. You may obtain a copy of the License at
+ * 
+ * http://www.apache.org/licenses/LICENSE-2.0
+ * 
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied. See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ ******************************************************************************/
+package org.apache.olingo.odata2.annotation.processor.ref.model;
+
+import java.util.Arrays;
+
+import org.apache.olingo.odata2.api.annotation.edm.EdmEntitySet;
+import org.apache.olingo.odata2.api.annotation.edm.EdmEntityType;
+import org.apache.olingo.odata2.api.annotation.edm.EdmKey;
+import org.apache.olingo.odata2.api.annotation.edm.EdmMediaResourceContent;
+import org.apache.olingo.odata2.api.annotation.edm.EdmMediaResourceMimeType;
+import org.apache.olingo.odata2.api.annotation.edm.EdmMediaResourceSource;
+import org.apache.olingo.odata2.api.annotation.edm.EdmProperty;
+import org.apache.olingo.odata2.api.annotation.edm.EdmType;
+
+/**
+ *  
+ */
+@EdmEntityType(name = "Photo", namespace = ModelSharedConstants.NAMESPACE_1)
+@EdmEntitySet(name = "Photos")
+public class Photo {
+  @EdmKey
+  @EdmProperty
+  private String name;
+  @EdmKey
+  @EdmProperty
+  private String type;
+  @EdmProperty
+  @EdmMediaResourceMimeType
+  private String mimeType;
+  @EdmProperty
+  @EdmMediaResourceSource
+  private String imageUrl = "http://localhost/someResource.png";
+  @EdmProperty(type = EdmType.BINARY)
+  @EdmMediaResourceContent
+  private byte[] image = ResourceHelper.generateImage();
+
+  public String getName() {
+    return name;
+  }
+
+  public void setName(final String name) {
+    this.name = name;
+  }
+
+  public String getType() {
+    return type;
+  }
+
+  public void setType(final String type) {
+    this.type = type;
+  }
+
+  public String getImageUri() {
+    return imageUrl;
+  }
+
+  public void setImageUri(final String uri) {
+    imageUrl = uri;
+  }
+
+  public byte[] getImage() {
+    return image.clone();
+  }
+
+  public void setImage(final byte[] image) {
+    this.image = image;
+  }
+
+  public String getImageType() {
+    return mimeType;
+  }
+
+  public void setImageType(final String imageType) {
+    mimeType = imageType;
+  }
+
+  @Override
+  public int hashCode() {
+    int hash = 5;
+    hash = 83 * hash + (name != null ? name.hashCode() : 0);
+    hash = 83 * hash + (type != null ? type.hashCode() : 0);
+    return hash;
+  }
+
+  @Override
+  public boolean equals(final Object obj) {
+    if (obj == null) {
+      return false;
+    }
+    if (getClass() != obj.getClass()) {
+      return false;
+    }
+    final Photo other = (Photo) obj;
+    if ((name == null) ? (other.name != null) : !name.equals(other.name)) {
+      return false;
+    }
+    if ((type == null) ? (other.type != null) : !type.equals(other.type)) {
+      return false;
+    }
+    return true;
+  }
+
+  @Override
+  public String toString() {
+    return "{\"Name\":\"" + name + "\","
+        + "\"Type\":\"" + type + "\","
+        + "\"ImageUrl\":\"" + imageUrl + "\","
+        + "\"Image\":\"" + Arrays.toString(image) + "\","
+        + "\"MimeType\":\"" + mimeType + "\"";
+  }
+}

http://git-wip-us.apache.org/repos/asf/incubator-olingo-odata2/blob/3bd59050/odata2-annotation-processor/annotation-processor-webref/src/main/java/org/apache/olingo/odata2/annotation/processor/ref/model/RefBase.java
----------------------------------------------------------------------
diff --git a/odata2-annotation-processor/annotation-processor-webref/src/main/java/org/apache/olingo/odata2/annotation/processor/ref/model/RefBase.java b/odata2-annotation-processor/annotation-processor-webref/src/main/java/org/apache/olingo/odata2/annotation/processor/ref/model/RefBase.java
new file mode 100644
index 0000000..d0d3edc
--- /dev/null
+++ b/odata2-annotation-processor/annotation-processor-webref/src/main/java/org/apache/olingo/odata2/annotation/processor/ref/model/RefBase.java
@@ -0,0 +1,78 @@
+/*******************************************************************************
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License. You may obtain a copy of the License at
+ * 
+ * http://www.apache.org/licenses/LICENSE-2.0
+ * 
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied. See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ ******************************************************************************/
+package org.apache.olingo.odata2.annotation.processor.ref.model;
+
+import org.apache.olingo.odata2.api.annotation.edm.EdmEntityType;
+import org.apache.olingo.odata2.api.annotation.edm.EdmKey;
+import org.apache.olingo.odata2.api.annotation.edm.EdmProperty;
+import org.apache.olingo.odata2.api.annotation.edm.EdmType;
+
+/**
+ *
+ */
+@EdmEntityType(name = "Base", namespace = ModelSharedConstants.NAMESPACE_1)
+public abstract class RefBase {
+  @EdmProperty(name = "Name")
+  protected String name;
+  @EdmProperty(name = "Id", type = EdmType.STRING)
+  @EdmKey
+  protected String id;
+
+  public String getName() {
+    return name;
+  }
+
+  public String getId() {
+    return id;
+  }
+
+  public void setName(final String name) {
+    this.name = name;
+  }
+
+  public void setId(final int id) {
+    this.id = String.valueOf(id);
+  }
+
+  @Override
+  public int hashCode() {
+    if (id == null) {
+      return -1;
+    }
+    return id.hashCode();
+  }
+
+  @Override
+  public boolean equals(final Object obj) {
+    if (obj == null) {
+      return false;
+    }
+    if (getClass() != obj.getClass()) {
+      return false;
+    }
+    final RefBase other = (RefBase) obj;
+    if ((name == null) ? (other.name != null) : !name.equals(other.name)) {
+      return false;
+    }
+    if ((id == null) ? (other.id != null) : !id.equals(other.id)) {
+      return false;
+    }
+    return true;
+  }
+}

http://git-wip-us.apache.org/repos/asf/incubator-olingo-odata2/blob/3bd59050/odata2-annotation-processor/annotation-processor-webref/src/main/java/org/apache/olingo/odata2/annotation/processor/ref/model/ResourceHelper.java
----------------------------------------------------------------------
diff --git a/odata2-annotation-processor/annotation-processor-webref/src/main/java/org/apache/olingo/odata2/annotation/processor/ref/model/ResourceHelper.java b/odata2-annotation-processor/annotation-processor-webref/src/main/java/org/apache/olingo/odata2/annotation/processor/ref/model/ResourceHelper.java
new file mode 100644
index 0000000..7d64bc4
--- /dev/null
+++ b/odata2-annotation-processor/annotation-processor-webref/src/main/java/org/apache/olingo/odata2/annotation/processor/ref/model/ResourceHelper.java
@@ -0,0 +1,96 @@
+/*******************************************************************************
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License. You may obtain a copy of the License at
+ * 
+ * http://www.apache.org/licenses/LICENSE-2.0
+ * 
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied. See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ ******************************************************************************/
+package org.apache.olingo.odata2.annotation.processor.ref.model;
+
+import java.awt.image.BufferedImage;
+import java.awt.image.WritableRaster;
+import java.io.ByteArrayOutputStream;
+import java.io.IOException;
+import java.io.InputStream;
+
+import javax.imageio.ImageIO;
+
+/**
+ *
+ */
+public class ResourceHelper {
+
+  public static byte[] loadAsByte(final String resource) {
+    return load(resource, new byte[0]);
+  }
+
+  public static byte[] load(final String resource, final byte[] defaultResult) {
+    InputStream instream = null;
+    try {
+      instream = Thread.currentThread().getContextClassLoader().getResourceAsStream(resource);
+      if (instream == null) {
+        return defaultResult;
+      }
+      ByteArrayOutputStream stream = new ByteArrayOutputStream();
+      int b = 0;
+      while ((b = instream.read()) != -1) {
+        stream.write(b);
+      }
+
+      return stream.toByteArray();
+    } catch (IOException e) {
+      throw new RuntimeException(e);
+    } finally {
+      if (instream != null) {
+        try {
+          instream.close();
+        } catch (IOException ex) {}
+      }
+    }
+  }
+
+  public enum Format {
+    BMP, JPEG, PNG, GIF
+  };
+
+  public static byte[] generateImage() {
+    return generateImage(Format.PNG);
+  }
+
+  public static byte[] generateImage(final Format format) {
+    try {
+      int width = 320;
+      int height = 320;
+      BufferedImage image = new BufferedImage(width, height, BufferedImage.TYPE_BYTE_BINARY);
+      WritableRaster raster = image.getRaster();
+
+      int mod = format.ordinal() + 2;
+      for (int h = 0; h < height; h++) {
+        for (int w = 0; w < width; w++) {
+          if (((h / 32) + (w / 32)) % mod == 0) {
+            raster.setSample(w, h, 0, 0);
+          } else {
+            raster.setSample(w, h, 0, 1);
+          }
+        }
+      }
+
+      ByteArrayOutputStream out = new ByteArrayOutputStream(1024);
+      ImageIO.write(image, format.name(), out);
+      return out.toByteArray();
+    } catch (IOException ex) {
+      return new byte[0];
+    }
+  }
+}

http://git-wip-us.apache.org/repos/asf/incubator-olingo-odata2/blob/3bd59050/odata2-annotation-processor/annotation-processor-webref/src/main/java/org/apache/olingo/odata2/annotation/processor/ref/model/Room.java
----------------------------------------------------------------------
diff --git a/odata2-annotation-processor/annotation-processor-webref/src/main/java/org/apache/olingo/odata2/annotation/processor/ref/model/Room.java b/odata2-annotation-processor/annotation-processor-webref/src/main/java/org/apache/olingo/odata2/annotation/processor/ref/model/Room.java
new file mode 100644
index 0000000..78e7a2c
--- /dev/null
+++ b/odata2-annotation-processor/annotation-processor-webref/src/main/java/org/apache/olingo/odata2/annotation/processor/ref/model/Room.java
@@ -0,0 +1,88 @@
+/*******************************************************************************
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License. You may obtain a copy of the License at
+ * 
+ * http://www.apache.org/licenses/LICENSE-2.0
+ * 
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied. See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ ******************************************************************************/
+package org.apache.olingo.odata2.annotation.processor.ref.model;
+
+import java.util.ArrayList;
+import java.util.List;
+
+import org.apache.olingo.odata2.api.annotation.edm.EdmEntitySet;
+import org.apache.olingo.odata2.api.annotation.edm.EdmEntityType;
+import org.apache.olingo.odata2.api.annotation.edm.EdmNavigationProperty;
+import org.apache.olingo.odata2.api.annotation.edm.EdmProperty;
+
+/**
+ *
+ */
+@EdmEntityType(name = "Room", namespace = ModelSharedConstants.NAMESPACE_1)
+@EdmEntitySet(name = "Rooms")
+public class Room extends RefBase {
+
+  @EdmProperty
+  private Integer seats;
+  @EdmProperty
+  private Integer version;
+  @EdmNavigationProperty(name = "nr_Building", association = "BuildingRooms")
+  private Building building;
+  @EdmNavigationProperty(name = "nr_Employees")
+  private List<Employee> employees = new ArrayList<Employee>();
+
+  public void setSeats(final int seats) {
+    this.seats = seats;
+  }
+
+  public int getSeats() {
+    return seats;
+  }
+
+  public void setVersion(final int version) {
+    this.version = version;
+  }
+
+  public int getVersion() {
+    return version;
+  }
+
+  public void setBuilding(final Building building) {
+    this.building = building;
+  }
+
+  public Building getBuilding() {
+    return building;
+  }
+
+  public List<Employee> getEmployees() {
+    return employees;
+  }
+
+  @Override
+  public int hashCode() {
+    return super.hashCode();
+  }
+
+  @Override
+  public boolean equals(final Object obj) {
+    return this == obj
+        || obj != null && getClass() == obj.getClass() && id == ((Room) obj).id;
+  }
+
+  @Override
+  public String toString() {
+    return "{\"Id\":\"" + id + "\",\"Name\":\"" + name + "\",\"Seats\":" + seats + ",\"Version\":" + version + "}";
+  }
+}

http://git-wip-us.apache.org/repos/asf/incubator-olingo-odata2/blob/3bd59050/odata2-annotation-processor/annotation-processor-webref/src/main/java/org/apache/olingo/odata2/annotation/processor/ref/model/Team.java
----------------------------------------------------------------------
diff --git a/odata2-annotation-processor/annotation-processor-webref/src/main/java/org/apache/olingo/odata2/annotation/processor/ref/model/Team.java b/odata2-annotation-processor/annotation-processor-webref/src/main/java/org/apache/olingo/odata2/annotation/processor/ref/model/Team.java
new file mode 100644
index 0000000..7f48f66
--- /dev/null
+++ b/odata2-annotation-processor/annotation-processor-webref/src/main/java/org/apache/olingo/odata2/annotation/processor/ref/model/Team.java
@@ -0,0 +1,73 @@
+/*******************************************************************************
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License. You may obtain a copy of the License at
+ * 
+ * http://www.apache.org/licenses/LICENSE-2.0
+ * 
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied. See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ ******************************************************************************/
+package org.apache.olingo.odata2.annotation.processor.ref.model;
+
+import java.util.ArrayList;
+import java.util.List;
+
+import org.apache.olingo.odata2.api.annotation.edm.EdmEntitySet;
+import org.apache.olingo.odata2.api.annotation.edm.EdmEntityType;
+import org.apache.olingo.odata2.api.annotation.edm.EdmNavigationProperty;
+import org.apache.olingo.odata2.api.annotation.edm.EdmNavigationProperty.Multiplicity;
+import org.apache.olingo.odata2.api.annotation.edm.EdmProperty;
+import org.apache.olingo.odata2.api.annotation.edm.EdmType;
+
+/**
+*  
+*/
+@EdmEntityType(name = "Team", namespace = ModelSharedConstants.NAMESPACE_1)
+@EdmEntitySet(name = "Teams")
+public class Team extends RefBase {
+  @EdmProperty(type = EdmType.BOOLEAN)
+  private Boolean isScrumTeam;
+  @EdmNavigationProperty(name = "nt_Employees", association = "TeamEmployees", toMultiplicity = Multiplicity.MANY)
+  private List<Employee> employees = new ArrayList<Employee>();
+
+  public Boolean isScrumTeam() {
+    return isScrumTeam;
+  }
+
+  public void setScrumTeam(final Boolean isScrumTeam) {
+    this.isScrumTeam = isScrumTeam;
+  }
+
+  public void addEmployee(final Employee e) {
+    employees.add(e);
+  }
+
+  public List<Employee> getEmployees() {
+    return employees;
+  }
+
+  @Override
+  public int hashCode() {
+    return super.hashCode();
+  }
+
+  @Override
+  public boolean equals(final Object obj) {
+    return this == obj
+        || obj != null && getClass() == obj.getClass() && id == ((Team) obj).id;
+  }
+
+  @Override
+  public String toString() {
+    return "{\"Id\":\"" + id + "\",\"Name\":\"" + name + "\",\"IsScrumTeam\":" + isScrumTeam + "}";
+  }
+}
\ No newline at end of file


[06/12] [OLINGO-83] Refactoring of 'annotation-processor-*' modules

Posted by tb...@apache.org.
http://git-wip-us.apache.org/repos/asf/incubator-olingo-odata2/blob/3bd59050/odata2-annotation-processor/annotation-processor-core/src/main/java/org/apache/olingo/odata2/annotation/processor/core/util/AnnotationHelper.java
----------------------------------------------------------------------
diff --git a/odata2-annotation-processor/annotation-processor-core/src/main/java/org/apache/olingo/odata2/annotation/processor/core/util/AnnotationHelper.java b/odata2-annotation-processor/annotation-processor-core/src/main/java/org/apache/olingo/odata2/annotation/processor/core/util/AnnotationHelper.java
new file mode 100644
index 0000000..807b6fe
--- /dev/null
+++ b/odata2-annotation-processor/annotation-processor-core/src/main/java/org/apache/olingo/odata2/annotation/processor/core/util/AnnotationHelper.java
@@ -0,0 +1,777 @@
+/**
+ * *****************************************************************************
+ * Licensed to the Apache Software Foundation (ASF) under one or more contributor license agreements. See the NOTICE
+ * file distributed with this work for additional information regarding copyright ownership. The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the "License"); you may not use this file except in compliance with the
+ * License. You may obtain a copy of the License at
+ * 
+ * http://www.apache.org/licenses/LICENSE-2.0
+ * 
+ * Unless required by applicable law or agreed to in writing, software distributed under the License is distributed on
+ * an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the License for the
+ * specific language governing permissions and limitations under the License.
+ * ****************************************************************************
+ */
+package org.apache.olingo.odata2.annotation.processor.core.util;
+
+import java.lang.annotation.Annotation;
+import java.lang.reflect.Field;
+import java.lang.reflect.ParameterizedType;
+import java.util.ArrayList;
+import java.util.Collection;
+import java.util.HashMap;
+import java.util.List;
+import java.util.Locale;
+import java.util.Map;
+import java.util.Set;
+
+import org.apache.olingo.odata2.api.annotation.edm.EdmComplexType;
+import org.apache.olingo.odata2.api.annotation.edm.EdmEntitySet;
+import org.apache.olingo.odata2.api.annotation.edm.EdmEntityType;
+import org.apache.olingo.odata2.api.annotation.edm.EdmKey;
+import org.apache.olingo.odata2.api.annotation.edm.EdmNavigationProperty;
+import org.apache.olingo.odata2.api.annotation.edm.EdmNavigationProperty.Multiplicity;
+import org.apache.olingo.odata2.api.annotation.edm.EdmProperty;
+import org.apache.olingo.odata2.api.edm.EdmLiteralKind;
+import org.apache.olingo.odata2.api.edm.EdmMultiplicity;
+import org.apache.olingo.odata2.api.edm.EdmSimpleTypeException;
+import org.apache.olingo.odata2.api.edm.EdmSimpleTypeKind;
+import org.apache.olingo.odata2.api.edm.FullQualifiedName;
+import org.apache.olingo.odata2.api.exception.ODataException;
+import org.apache.olingo.odata2.core.exception.ODataRuntimeException;
+
+/**
+ *
+ */
+public class AnnotationHelper {
+
+  public static final String DEFAULT_CONTAINER_NAME = "DefaultContainer";
+
+  /**
+   * Compare keys of both instances.
+   * 
+   * @param firstInstance
+   * @param secondInstance
+   * @return
+   */
+  public boolean keyMatch(final Object firstInstance, final Object secondInstance) {
+    if (firstInstance == null || secondInstance == null) {
+      return false;
+    } else if (firstInstance.getClass() != secondInstance.getClass()) {
+      return false;
+    }
+
+    Map<String, Object> firstKeyFields = getValueForAnnotatedFields(firstInstance, EdmKey.class);
+    Map<String, Object> secondKeyFields = getValueForAnnotatedFields(secondInstance, EdmKey.class);
+
+    return keyValuesMatch(firstKeyFields, secondKeyFields);
+  }
+
+  /**
+   * Compare keys of instance with key values in map.
+   * 
+   * @param instance
+   * @param keyName2Value
+   * @return
+   */
+  public boolean keyMatch(final Object instance, final Map<String, Object> keyName2Value) {
+    Map<String, Object> instanceKeyFields = getValueForAnnotatedFields(instance, EdmKey.class);
+    return keyValuesMatch(instanceKeyFields, keyName2Value);
+  }
+
+  private boolean keyValuesMatch(final Map<String, Object> firstKeyValues, final Map<String, Object> secondKeyValues) {
+    if (firstKeyValues.size() != secondKeyValues.size()) {
+      return false;
+    } else {
+      Set<Map.Entry<String, Object>> entries = firstKeyValues.entrySet();
+      for (Map.Entry<String, Object> entry : entries) {
+        Object firstKey = entry.getValue();
+        Object secondKey = secondKeyValues.get(entry.getKey());
+        if (!isEqual(firstKey, secondKey)) {
+          return false;
+        }
+      }
+      return true;
+    }
+  }
+
+  private boolean isEqual(final Object firstKey, final Object secondKey) {
+    if (firstKey == null) {
+      if (secondKey == null) {
+        return true;
+      } else {
+        return secondKey.equals(firstKey);
+      }
+    } else {
+      return firstKey.equals(secondKey);
+    }
+  }
+
+  public String extractEntitTypeName(final EdmNavigationProperty enp, final Class<?> fallbackClass) {
+    Class<?> entityTypeClass = enp.toType();
+    return extractEntityTypeName(entityTypeClass == Object.class ? fallbackClass : entityTypeClass);
+  }
+
+  public String extractEntitTypeName(final EdmNavigationProperty enp, final Field field) {
+    Class<?> entityTypeClass = enp.toType();
+    if (entityTypeClass == Object.class) {
+      Class<?> toClass = field.getType();
+      return extractEntityTypeName((toClass.isArray() || Collection.class.isAssignableFrom(toClass) ?
+          (Class<?>) ((ParameterizedType) field.getGenericType()).getActualTypeArguments()[0] : toClass));
+    } else {
+      return extractEntityTypeName(entityTypeClass);
+    }
+  }
+
+  /**
+   * Returns <code>NULL</code> if given class is not annotated. If annotated the set entity type name is returned and if
+   * no name is set the default name is generated from the simple class name.
+   * 
+   * @param annotatedClass
+   * @return
+   */
+  public String extractEntityTypeName(final Class<?> annotatedClass) {
+    return extractTypeName(annotatedClass, EdmEntityType.class);
+  }
+
+  /**
+   * Returns <code>NULL</code> if given class is not annotated.
+   * If annotated the entity set name is returned and if
+   * no name is set a default name is generated based on the simple class name.
+   * 
+   * @param annotatedClass
+   * @return
+   */
+  public String extractEntitySetName(final Class<?> annotatedClass) {
+    if (annotatedClass == Object.class) {
+      return null;
+    }
+    EdmEntitySet entitySet = annotatedClass.getAnnotation(EdmEntitySet.class);
+    if (entitySet == null) {
+      return null;
+    }
+
+    String name = entitySet.name();
+    if (name.isEmpty()) {
+      return getCanonicalName(annotatedClass) + "Set";
+    }
+    return name;
+  }
+
+  public FullQualifiedName extractEntityTypeFqn(final EdmEntityType type, final Class<?> annotatedClass) {
+    if (type.namespace().isEmpty()) {
+      return new FullQualifiedName(generateNamespace(annotatedClass), extractEntityTypeName(annotatedClass));
+    }
+    return new FullQualifiedName(type.namespace(), extractEntityTypeName(annotatedClass));
+  }
+
+  public FullQualifiedName extractEntityTypeFqn(final Class<?> annotatedClass) {
+    EdmEntityType type = annotatedClass.getAnnotation(EdmEntityType.class);
+    if (type == null) {
+      return null;
+    }
+    return extractEntityTypeFqn(type, annotatedClass);
+  }
+
+  public FullQualifiedName extractComplexTypeFqn(final Class<?> annotatedClass) {
+    EdmComplexType type = annotatedClass.getAnnotation(EdmComplexType.class);
+    if (type == null) {
+      return null;
+    }
+    return extractComplexTypeFqn(type, annotatedClass);
+  }
+
+  public FullQualifiedName extractComplexTypeFqn(final EdmComplexType type, final Class<?> annotatedClass) {
+    if (type.namespace().isEmpty()) {
+      return new FullQualifiedName(generateNamespace(annotatedClass), extractComplexTypeName(annotatedClass));
+    }
+    return new FullQualifiedName(type.namespace(), extractComplexTypeName(annotatedClass));
+  }
+
+  public String extractComplexTypeName(final Class<?> annotatedClass) {
+    return extractTypeName(annotatedClass, EdmComplexType.class);
+  }
+
+  public String generateNamespace(final Class<?> annotatedClass) {
+    String packageName = annotatedClass.getPackage().getName();
+    return packageName;
+  }
+
+  /**
+   * 
+   * 
+   * @param <T> must be EdmEntityType or EdmComplexType annotation
+   * @param annotatedClass
+   * @param typeAnnotation
+   * @return null if annotatedClass is not annotated or name set via annotation or generated via
+   * {@link #getCanonicalName(java.lang.Class)}
+   */
+  private <T extends Annotation> String extractTypeName(final Class<?> annotatedClass, final Class<T> typeAnnotation) {
+    if (annotatedClass == Object.class) {
+      return null;
+    }
+    T type = annotatedClass.getAnnotation(typeAnnotation);
+    if (type == null) {
+      return null;
+    }
+
+    String name;
+    if (typeAnnotation == EdmEntityType.class) {
+      name = ((EdmEntityType) type).name();
+    } else if (typeAnnotation == EdmComplexType.class) {
+      name = ((EdmComplexType) type).name();
+    } else {
+      return null;
+    }
+
+    if (name.isEmpty()) {
+      return getCanonicalName(annotatedClass);
+    }
+    return name;
+  }
+
+  /**
+   * Get the set property name from an EdmProperty or EdmNavigationProperty annotation.
+   * 
+   * @param field
+   * @return
+   */
+  public String getPropertyNameFromAnnotation(final Field field) {
+    EdmProperty property = field.getAnnotation(EdmProperty.class);
+    if (property == null) {
+      EdmNavigationProperty navProperty = field.getAnnotation(EdmNavigationProperty.class);
+      if (navProperty == null) {
+        throw new EdmAnnotationException("Given field '" + field
+            + "' has no EdmProperty or EdmNavigationProperty annotation.");
+      }
+      return navProperty.name();
+    }
+    return property.name();
+  }
+
+  public String getPropertyName(final Field field) {
+    String propertyName = getPropertyNameFromAnnotation(field);
+    if (propertyName.isEmpty()) {
+      propertyName = getCanonicalName(field);
+    }
+    return propertyName;
+  }
+
+  public String extractFromRoleName(final EdmNavigationProperty enp, final Field field) {
+    return getCanonicalRole(field.getDeclaringClass());
+  }
+
+  public String extractToRoleName(final EdmNavigationProperty enp, final Field field) {
+    String role = enp.toRole();
+    if (role.isEmpty()) {
+      role = getCanonicalRole(
+          field.getType().isArray() || Collection.class.isAssignableFrom(field.getType()) ?
+              (Class<?>) ((ParameterizedType) field.getGenericType()).getActualTypeArguments()[0] : field.getType());
+    }
+    return role;
+  }
+
+  public String getCanonicalRole(final Class<?> fallbackClass) {
+    String toRole = extractEntityTypeName(fallbackClass);
+    return "r_" + toRole;
+  }
+
+  public String extractRelationshipName(final EdmNavigationProperty enp, final Field field) {
+    String relationshipName = enp.association();
+    if (relationshipName.isEmpty()) {
+      final String fromRole = extractFromRoleName(enp, field);
+      final String toRole = extractToRoleName(enp, field);
+      if (fromRole.compareTo(toRole) > 0) {
+        relationshipName = toRole + "-" + fromRole;
+      } else {
+        relationshipName = fromRole + "-" + toRole;
+      }
+    }
+    return relationshipName;
+  }
+
+  public EdmMultiplicity getMultiplicity(final EdmNavigationProperty enp, final Field field) {
+    EdmMultiplicity multiplicity = mapMultiplicity(enp.toMultiplicity());
+    final boolean isCollectionType = field.getType().isArray() || Collection.class.isAssignableFrom(field.getType());
+
+    if (multiplicity == EdmMultiplicity.ONE && isCollectionType) {
+      return EdmMultiplicity.MANY;
+    }
+    return multiplicity;
+  }
+
+  /**
+   * Set key fields based on values in map.
+   * If an key field is not available or <code>NULL</code> in the map
+   * it will be not set as <code>NULL</code> at the instance object.
+   * 
+   * @param instance
+   * @param keys
+   * @return
+   */
+  public <T> T setKeyFields(final T instance, final Map<String, Object> keys) {
+    List<Field> fields = getAnnotatedFields(instance, EdmKey.class);
+
+    for (Field field : fields) {
+      String propertyName = getPropertyName(field);
+      Object keyValue = keys.get(propertyName);
+      setValueForProperty(instance, propertyName, keyValue);
+    }
+
+    return instance;
+  }
+
+  public static final class ODataAnnotationException extends ODataException {
+    private static final long serialVersionUID = 42L;
+
+    public ODataAnnotationException(final String message) {
+      super(message);
+    }
+
+    public ODataAnnotationException(final String message, final Exception cause) {
+      super(message, cause);
+    }
+  }
+
+  public class AnnotatedNavInfo {
+    private final Field fromField;
+    private final Field toField;
+    private final EdmNavigationProperty fromNavigation;
+    private final EdmNavigationProperty toNavigation;
+
+    public AnnotatedNavInfo(final Field fromField, final Field toField, final EdmNavigationProperty fromNavigation,
+        final EdmNavigationProperty toNavigation) {
+      this.fromField = fromField;
+      this.toField = toField;
+      this.fromNavigation = fromNavigation;
+      this.toNavigation = toNavigation;
+    }
+
+    public Field getFromField() {
+      return fromField;
+    }
+
+    public Field getToField() {
+      return toField;
+    }
+
+    public EdmMultiplicity getFromMultiplicity() {
+      return getMultiplicity(toNavigation, toField);
+    }
+
+    public EdmMultiplicity getToMultiplicity() {
+      return getMultiplicity(fromNavigation, fromField);
+    }
+
+    public boolean isBiDirectional() {
+      return toNavigation != null;
+    }
+  }
+
+  public AnnotatedNavInfo getCommonNavigationInfo(final Class<?> sourceClass, final Class<?> targetClass) {
+    List<Field> sourceFields = getAnnotatedFields(sourceClass, EdmNavigationProperty.class);
+    List<Field> targetFields = getAnnotatedFields(targetClass, EdmNavigationProperty.class);
+
+    // first try via association name to get full navigation information
+    for (Field sourceField : sourceFields) {
+      final EdmNavigationProperty sourceNav = sourceField.getAnnotation(EdmNavigationProperty.class);
+      final String sourceAssociation = extractRelationshipName(sourceNav, sourceField);
+      for (Field targetField : targetFields) {
+        final EdmNavigationProperty targetNav = targetField.getAnnotation(EdmNavigationProperty.class);
+        final String targetAssociation = extractRelationshipName(targetNav, targetField);
+        if (sourceAssociation.equals(targetAssociation)) {
+          return new AnnotatedNavInfo(sourceField, targetField, sourceNav, targetNav);
+        }
+      }
+    }
+
+    // if nothing was found assume none bi-directinal navigation
+    String targetEntityTypeName = extractEntityTypeName(targetClass);
+    for (Field sourceField : sourceFields) {
+      final EdmNavigationProperty sourceNav = sourceField.getAnnotation(EdmNavigationProperty.class);
+      final String navTargetEntityName = extractEntitTypeName(sourceNav, sourceField);
+
+      if (navTargetEntityName.equals(targetEntityTypeName)) {
+        return new AnnotatedNavInfo(sourceField, null, sourceNav, null);
+      }
+    }
+
+    return null;
+  }
+
+  public Class<?> getFieldTypeForProperty(final Object instance, final String propertyName)
+      throws ODataAnnotationException {
+    if (instance == null) {
+      return null;
+    }
+
+    Field field = getFieldForPropertyName(instance, propertyName, instance.getClass(), true);
+    if (field == null) {
+      throw new ODataAnnotationException("No field for property '" + propertyName
+          + "' found at class '" + instance.getClass() + "'.");
+    }
+    return field.getType();
+  }
+
+  public Object getValueForProperty(final Object instance, final String propertyName) throws ODataAnnotationException {
+    if (instance == null) {
+      return null;
+    }
+
+    Field field = getFieldForPropertyName(instance, propertyName, instance.getClass(), true);
+    if (field == null) {
+      throw new ODataAnnotationException("No field for property '" + propertyName
+          + "' found at class '" + instance.getClass() + "'.");
+    }
+    return getFieldValue(instance, field);
+  }
+
+  public void setValueForProperty(final Object instance, final String propertyName, final Object propertyValue) {
+    if (instance != null) {
+      Field field = getFieldForPropertyName(instance, propertyName, instance.getClass(), true);
+      if (field != null) {
+        setFieldValue(instance, field, propertyValue);
+      }
+    }
+  }
+
+  private Field getFieldForPropertyName(final Object instance, final String propertyName,
+      final Class<?> resultClass, final boolean inherited) {
+    if (instance == null) {
+      return null;
+    }
+
+    Field[] fields = resultClass.getDeclaredFields();
+    for (Field field : fields) {
+      EdmProperty property = field.getAnnotation(EdmProperty.class);
+      if (property != null) {
+        if (property.name().isEmpty() && getCanonicalName(field).equals(propertyName)) {
+          return field;
+        } else if (property.name().equals(propertyName)) {
+          return field;
+        }
+      }
+    }
+
+    Class<?> superClass = resultClass.getSuperclass();
+    if (inherited && superClass != Object.class) {
+      return getFieldForPropertyName(instance, propertyName, superClass, true);
+    }
+
+    return null;
+  }
+
+  public Object getValueForField(final Object instance, final String fieldName,
+      final Class<? extends Annotation> annotation) {
+    if (instance == null) {
+      return null;
+    }
+    return getValueForField(instance, fieldName, instance.getClass(), annotation, true);
+  }
+
+  public Object getValueForField(final Object instance, final Class<? extends Annotation> annotation) {
+    if (instance == null) {
+      return null;
+    }
+    return getValueForField(instance, instance.getClass(), annotation, true);
+  }
+
+  private Object getValueForField(final Object instance, final Class<?> resultClass,
+      final Class<? extends Annotation> annotation, final boolean inherited) {
+    return getValueForField(instance, null, resultClass, annotation, inherited);
+  }
+
+  public Map<String, Object> getValueForAnnotatedFields(final Object instance,
+      final Class<? extends Annotation> annotation) {
+    return getValueForAnnotatedFields(instance, instance.getClass(), annotation, true);
+  }
+
+  private Map<String, Object> getValueForAnnotatedFields(final Object instance, final Class<?> resultClass,
+      final Class<? extends Annotation> annotation, final boolean inherited) {
+    if (instance == null) {
+      return null;
+    }
+
+    Field[] fields = resultClass.getDeclaredFields();
+    Map<String, Object> fieldName2Value = new HashMap<String, Object>();
+
+    for (Field field : fields) {
+      if (field.getAnnotation(annotation) != null) {
+        Object value = getFieldValue(instance, field);
+        final EdmProperty property = field.getAnnotation(EdmProperty.class);
+        final String name = property == null || property.name().isEmpty() ? field.getName() : property.name();
+        fieldName2Value.put(name, value);
+      }
+    }
+
+    Class<?> superClass = resultClass.getSuperclass();
+    if (inherited && superClass != Object.class) {
+      Map<String, Object> tmp = getValueForAnnotatedFields(instance, superClass, annotation, true);
+      fieldName2Value.putAll(tmp);
+    }
+
+    return fieldName2Value;
+  }
+
+  public void setValueForAnnotatedField(final Object instance, final Class<? extends Annotation> annotation,
+      final Object value)
+      throws ODataAnnotationException {
+    List<Field> fields = getAnnotatedFields(instance, annotation);
+
+    if (fields.isEmpty()) {
+      throw new ODataAnnotationException("No field found for annotation '" + annotation
+          + "' on instance '" + instance + "'.");
+    } else if (fields.size() > 1) {
+      throw new ODataAnnotationException("More then one field found for annotation '" + annotation
+          + "' on instance '" + instance + "'.");
+    }
+
+    setFieldValue(instance, fields.get(0), value);
+  }
+
+  public void setValuesToAnnotatedFields(final Object instance,
+      final Class<? extends Annotation> annotation, final Map<String, Object> fieldName2Value) {
+    List<Field> fields = getAnnotatedFields(instance, annotation);
+
+    // XXX: refactore
+    for (Field field : fields) {
+      final String canonicalName = getCanonicalName(field);
+      if (fieldName2Value.containsKey(canonicalName)) {
+        Object value = fieldName2Value.get(canonicalName);
+        setFieldValue(instance, field, value);
+      }
+    }
+  }
+
+  public List<Field> getAnnotatedFields(final Object instance, final Class<? extends Annotation> annotation) {
+    if (instance == null) {
+      return null;
+    }
+    return getAnnotatedFields(instance.getClass(), annotation, true);
+  }
+
+  public List<Field> getAnnotatedFields(final Class<?> fieldClass, final Class<? extends Annotation> annotation) {
+    return getAnnotatedFields(fieldClass, annotation, true);
+  }
+
+  /**
+   * 
+   * @param instance
+   * @param resultClass
+   * @param annotation
+   * @param inherited
+   * @return
+   */
+  private List<Field> getAnnotatedFields(final Class<?> resultClass,
+      final Class<? extends Annotation> annotation, final boolean inherited) {
+    if (resultClass == null) {
+      return null;
+    }
+
+    Field[] fields = resultClass.getDeclaredFields();
+    List<Field> annotatedFields = new ArrayList<Field>();
+
+    for (Field field : fields) {
+      if (field.getAnnotation(annotation) != null) {
+        annotatedFields.add(field);
+      }
+    }
+
+    Class<?> superClass = resultClass.getSuperclass();
+    if (inherited && superClass != Object.class) {
+      List<Field> tmp = getAnnotatedFields(superClass, annotation, true);
+      annotatedFields.addAll(tmp);
+    }
+
+    return annotatedFields;
+  }
+
+  private Object getValueForField(final Object instance, final String fieldName, final Class<?> resultClass,
+      final Class<? extends Annotation> annotation, final boolean inherited) {
+    if (instance == null) {
+      return null;
+    }
+
+    Field[] fields = resultClass.getDeclaredFields();
+    for (Field field : fields) {
+      if (field.getAnnotation(annotation) != null
+          && (fieldName == null || field.getName().equals(fieldName))) {
+        return getFieldValue(instance, field);
+      }
+    }
+
+    Class<?> superClass = resultClass.getSuperclass();
+    if (inherited && superClass != Object.class) {
+      return getValueForField(instance, fieldName, superClass, annotation, true);
+    }
+
+    return null;
+  }
+
+  private Object getFieldValue(final Object instance, final Field field) {
+    try {
+      boolean access = field.isAccessible();
+      field.setAccessible(true);
+      Object value = field.get(instance);
+      field.setAccessible(access);
+      return value;
+    } catch (IllegalArgumentException ex) { // should never happen
+      throw new ODataRuntimeException(ex);
+    } catch (IllegalAccessException ex) { // should never happen
+      throw new ODataRuntimeException(ex);
+    }
+  }
+
+  private void setFieldValue(final Object instance, final Field field, final Object value) {
+    try {
+      Object usedValue = value;
+      if (value != null
+          && field.getType() != value.getClass()
+          && value.getClass() == String.class) {
+        usedValue = convert(field, (String) value);
+      }
+      boolean access = field.isAccessible();
+      field.setAccessible(true);
+      field.set(instance, usedValue);
+      field.setAccessible(access);
+    } catch (IllegalArgumentException ex) { // should never happen
+      throw new ODataRuntimeException(ex);
+    } catch (IllegalAccessException ex) { // should never happen
+      throw new ODataRuntimeException(ex);
+    }
+  }
+
+  public Object convert(final Field field, final String propertyValue) {
+    Class<?> fieldClass = field.getType();
+    try {
+      EdmProperty property = field.getAnnotation(EdmProperty.class);
+      EdmSimpleTypeKind type = mapTypeKind(property.type());
+      return type.getEdmSimpleTypeInstance().valueOfString(propertyValue,
+          EdmLiteralKind.DEFAULT, null, fieldClass);
+    } catch (EdmSimpleTypeException ex) {
+      throw new ODataRuntimeException("Conversion failed for string property with error: "
+          + ex.getMessage(), ex);
+    }
+  }
+
+  public boolean isEdmAnnotated(final Object object) {
+    if (object == null) {
+      return false;
+    }
+    return isEdmAnnotated(object.getClass());
+  }
+
+  public boolean isEdmTypeAnnotated(final Class<?> clazz) {
+    boolean isComplexEntity = clazz.getAnnotation(EdmComplexType.class) != null;
+    boolean isEntity = clazz.getAnnotation(EdmEntityType.class) != null;
+    return isComplexEntity || isEntity;
+  }
+
+  public boolean isEdmAnnotated(final Class<?> clazz) {
+    if (clazz == null) {
+      return false;
+    } else {
+      final boolean isEntity = null != clazz.getAnnotation(EdmEntityType.class);
+      final boolean isEntitySet = null != clazz.getAnnotation(EdmEntitySet.class);
+      final boolean isComplexEntity = null != clazz.getAnnotation(EdmComplexType.class);
+      return isEntity || isComplexEntity || isEntitySet;
+    }
+  }
+
+  public String getCanonicalName(final Field field) {
+    return firstCharToUpperCase(field.getName());
+  }
+
+  public String getCanonicalName(final Class<?> clazz) {
+    return firstCharToUpperCase(clazz.getSimpleName());
+  }
+
+  private String firstCharToUpperCase(final String content) {
+    if (content == null || content.isEmpty()) {
+      return content;
+    }
+    return content.substring(0, 1).toUpperCase(Locale.ENGLISH) + content.substring(1);
+  }
+
+  public EdmSimpleTypeKind mapTypeKind(final org.apache.olingo.odata2.api.annotation.edm.EdmType type) {
+    switch (type) {
+    case BINARY:
+      return EdmSimpleTypeKind.Binary;
+    case BOOLEAN:
+      return EdmSimpleTypeKind.Boolean;
+    case BYTE:
+      return EdmSimpleTypeKind.Byte;
+    case COMPLEX:
+      return EdmSimpleTypeKind.Null;
+    case DATE_TIME:
+      return EdmSimpleTypeKind.DateTime;
+    case DATE_TIME_OFFSET:
+      return EdmSimpleTypeKind.DateTimeOffset;
+    case DECIMAL:
+      return EdmSimpleTypeKind.Decimal;
+    case DOUBLE:
+      return EdmSimpleTypeKind.Double;
+    case GUID:
+      return EdmSimpleTypeKind.Guid;
+    case INT16:
+      return EdmSimpleTypeKind.Int16;
+    case INT32:
+      return EdmSimpleTypeKind.Int32;
+    case INT64:
+      return EdmSimpleTypeKind.Int64;
+    case NULL:
+      return EdmSimpleTypeKind.Null;
+    case SBYTE:
+      return EdmSimpleTypeKind.SByte;
+    case SINGLE:
+      return EdmSimpleTypeKind.Single;
+    case STRING:
+      return EdmSimpleTypeKind.String;
+    case TIME:
+      return EdmSimpleTypeKind.Time;
+    default:
+      throw new ODataRuntimeException("Unknown type '" + type
+          + "' for mapping to EdmSimpleTypeKind.");
+    }
+  }
+
+  public EdmMultiplicity mapMultiplicity(final Multiplicity multiplicity) {
+    switch (multiplicity) {
+    case ZERO_OR_ONE:
+      return EdmMultiplicity.ZERO_TO_ONE;
+    case ONE:
+      return EdmMultiplicity.ONE;
+    case MANY:
+      return EdmMultiplicity.MANY;
+    default:
+      throw new ODataRuntimeException("Unknown type '" + multiplicity + "' for mapping to EdmMultiplicity.");
+    }
+  }
+
+  /**
+   * 
+   */
+  private static class EdmAnnotationException extends RuntimeException {
+
+    private static final long serialVersionUID = 42L;
+
+    public EdmAnnotationException(final String message) {
+      super(message);
+    }
+  }
+
+  public String getCanonicalNamespace(final Class<?> aClass) {
+    return generateNamespace(aClass);
+  }
+
+  public String extractContainerName(final Class<?> aClass) {
+    EdmEntitySet entitySet = aClass.getAnnotation(EdmEntitySet.class);
+    if (entitySet != null) {
+      String containerName = entitySet.container();
+      if (!containerName.isEmpty()) {
+        return containerName;
+      }
+    }
+    return DEFAULT_CONTAINER_NAME;
+  }
+}

http://git-wip-us.apache.org/repos/asf/incubator-olingo-odata2/blob/3bd59050/odata2-annotation-processor/annotation-processor-core/src/main/java/org/apache/olingo/odata2/annotation/processor/core/util/ClassHelper.java
----------------------------------------------------------------------
diff --git a/odata2-annotation-processor/annotation-processor-core/src/main/java/org/apache/olingo/odata2/annotation/processor/core/util/ClassHelper.java b/odata2-annotation-processor/annotation-processor-core/src/main/java/org/apache/olingo/odata2/annotation/processor/core/util/ClassHelper.java
new file mode 100644
index 0000000..fa575ae
--- /dev/null
+++ b/odata2-annotation-processor/annotation-processor-core/src/main/java/org/apache/olingo/odata2/annotation/processor/core/util/ClassHelper.java
@@ -0,0 +1,140 @@
+/*******************************************************************************
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License. You may obtain a copy of the License at
+ * 
+ * http://www.apache.org/licenses/LICENSE-2.0
+ * 
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied. See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ ******************************************************************************/
+package org.apache.olingo.odata2.annotation.processor.core.util;
+
+import java.io.File;
+import java.io.FileFilter;
+import java.io.FilenameFilter;
+import java.lang.reflect.Field;
+import java.net.URL;
+import java.util.ArrayList;
+import java.util.List;
+
+import org.apache.olingo.odata2.core.exception.ODataRuntimeException;
+
+/**
+ *
+ */
+public class ClassHelper {
+
+  private static final File[] EMPTY_FILE_ARRAY = new File[0];
+
+  private static final FilenameFilter CLASSFILE_FILTER = new FilenameFilter() {
+    @Override
+    public boolean accept(final File dir, final String name) {
+      return name.endsWith(CLASSFILE_ENDING);
+    }
+
+    public static final String CLASSFILE_ENDING = ".class";
+  };
+
+  private static final FileFilter FOLDER_FILTER = new FileFilter() {
+    @Override
+    public boolean accept(final File pathname) {
+      return pathname.isDirectory();
+    }
+  };
+
+  public static final List<Class<?>> loadClasses(final String packageToScan, final ClassValidator cv) {
+    return loadClasses(packageToScan, CLASSFILE_FILTER, cv);
+  }
+
+  public static final List<Class<?>> loadClasses(final String packageToScan, final FilenameFilter ff,
+      final ClassValidator cv) {
+    final ClassLoader classLoader = Thread.currentThread().getContextClassLoader();
+    String folderToScan = packageToScan.replace(".", "/");
+    URL url = classLoader.getResource(folderToScan);
+    if (url == null) {
+      throw new IllegalArgumentException("No folder to scan found for package '" + packageToScan + "'.");
+    }
+    File folder = new File(url.getFile());
+    File[] classFiles = folder.listFiles(ff);
+    if (classFiles == null) {
+      classFiles = EMPTY_FILE_ARRAY;
+    }
+
+    List<Class<?>> annotatedClasses = new ArrayList<Class<?>>(classFiles.length);
+    for (File file : classFiles) {
+      String name = file.getName();
+      String fqn = packageToScan + "." + name.substring(0, name.length() - 6);
+      try {
+        Class<?> c = classLoader.loadClass(fqn);
+        if (cv.isClassValid(c)) {
+          annotatedClasses.add(c);
+        }
+      } catch (ClassNotFoundException ex) {
+        throw new IllegalArgumentException("Exception during class loading of class '" + fqn +
+            "' with message '" + ex.getMessage() + "'.");
+      }
+    }
+
+    // recursive search
+    File[] subfolders = listSubFolder(folder);
+    for (File file : subfolders) {
+      List<Class<?>> subFolderClazzes = loadClasses(packageToScan + "." + file.getName(), ff, cv);
+      annotatedClasses.addAll(subFolderClazzes);
+    }
+    //
+
+    return annotatedClasses;
+  }
+
+  public static Object getFieldValue(final Object instance, final Field field) {
+    try {
+      synchronized (field) {
+        boolean access = field.isAccessible();
+        field.setAccessible(true);
+        Object value = field.get(instance);
+        field.setAccessible(access);
+        return value;
+      }
+    } catch (IllegalArgumentException ex) { // should never happen
+      throw new ODataRuntimeException(ex);
+    } catch (IllegalAccessException ex) { // should never happen
+      throw new ODataRuntimeException(ex);
+    }
+  }
+
+  public static void setFieldValue(final Object instance, final Field field, final Object value) {
+    try {
+      synchronized (field) {
+        boolean access = field.isAccessible();
+        field.setAccessible(true);
+        field.set(instance, value);
+        field.setAccessible(access);
+      }
+    } catch (IllegalArgumentException ex) { // should never happen
+      throw new ODataRuntimeException(ex);
+    } catch (IllegalAccessException ex) { // should never happen
+      throw new ODataRuntimeException(ex);
+    }
+  }
+
+  private static File[] listSubFolder(final File folder) {
+    File[] subfolders = folder.listFiles(FOLDER_FILTER);
+    if (subfolders == null) {
+      return EMPTY_FILE_ARRAY;
+    }
+    return subfolders;
+  }
+
+  public interface ClassValidator {
+    boolean isClassValid(Class<?> c);
+  }
+}

http://git-wip-us.apache.org/repos/asf/incubator-olingo-odata2/blob/3bd59050/odata2-annotation-processor/annotation-processor-core/src/main/java/org/apache/olingo/odata2/core/annotation/data/AnnotationInMemoryDs.java
----------------------------------------------------------------------
diff --git a/odata2-annotation-processor/annotation-processor-core/src/main/java/org/apache/olingo/odata2/core/annotation/data/AnnotationInMemoryDs.java b/odata2-annotation-processor/annotation-processor-core/src/main/java/org/apache/olingo/odata2/core/annotation/data/AnnotationInMemoryDs.java
deleted file mode 100644
index a53ee8f..0000000
--- a/odata2-annotation-processor/annotation-processor-core/src/main/java/org/apache/olingo/odata2/core/annotation/data/AnnotationInMemoryDs.java
+++ /dev/null
@@ -1,376 +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.odata2.core.annotation.data;
-
-import java.lang.reflect.Field;
-import java.util.ArrayList;
-import java.util.Collection;
-import java.util.HashMap;
-import java.util.List;
-import java.util.Map;
-
-import org.apache.olingo.odata2.api.annotation.edm.EdmMediaResourceContent;
-import org.apache.olingo.odata2.api.annotation.edm.EdmMediaResourceMimeType;
-import org.apache.olingo.odata2.api.annotation.edm.EdmNavigationProperty;
-import org.apache.olingo.odata2.api.data.DataSource;
-import org.apache.olingo.odata2.api.edm.EdmEntitySet;
-import org.apache.olingo.odata2.api.edm.EdmException;
-import org.apache.olingo.odata2.api.edm.EdmFunctionImport;
-import org.apache.olingo.odata2.api.edm.EdmMultiplicity;
-import org.apache.olingo.odata2.api.exception.ODataApplicationException;
-import org.apache.olingo.odata2.api.exception.ODataException;
-import org.apache.olingo.odata2.api.exception.ODataNotFoundException;
-import org.apache.olingo.odata2.api.exception.ODataNotImplementedException;
-import org.apache.olingo.odata2.core.annotation.util.AnnotationHelper;
-import org.apache.olingo.odata2.core.annotation.util.AnnotationHelper.AnnotatedNavInfo;
-import org.apache.olingo.odata2.core.annotation.util.AnnotationHelper.ODataAnnotationException;
-import org.apache.olingo.odata2.core.annotation.util.ClassHelper;
-import org.apache.olingo.odata2.core.exception.ODataRuntimeException;
-
-public class AnnotationInMemoryDs implements DataSource {
-
-  private static final AnnotationHelper ANNOTATION_HELPER = new AnnotationHelper();
-  private final Map<String, DataStore<Object>> dataStores = new HashMap<String, DataStore<Object>>();
-  private final boolean persistInMemory;
-
-  public AnnotationInMemoryDs(final String packageToScan) throws ODataException {
-    this(packageToScan, true);
-  }
-
-  public AnnotationInMemoryDs(final String packageToScan, final boolean persistInMemory) throws ODataException {
-    this.persistInMemory = persistInMemory;
-    List<Class<?>> foundClasses = ClassHelper.loadClasses(packageToScan, new ClassHelper.ClassValidator() {
-      @Override
-      public boolean isClassValid(final Class<?> c) {
-        return null != c.getAnnotation(org.apache.olingo.odata2.api.annotation.edm.EdmEntitySet.class);
-      }
-    });
-
-    init(foundClasses);
-  }
-
-  @SuppressWarnings("unchecked")
-  private void init(final List<Class<?>> foundClasses) throws ODataException {
-    try {
-      for (Class<?> clz : foundClasses) {
-        DataStore<Object> dhs = (DataStore<Object>) DataStore.createInMemory(clz, persistInMemory);
-        String entitySetName = ANNOTATION_HELPER.extractEntitySetName(clz);
-        dataStores.put(entitySetName, dhs);
-      }
-    } catch (DataStore.DataStoreException e) {
-      throw new ODataException("Error in DataStore initilization with message: " + e.getMessage(), e);
-    }
-  }
-
-  public <T> DataStore<T> getDataStore(final Class<T> clazz) {
-    String entitySetName = ANNOTATION_HELPER.extractEntitySetName(clazz);
-    return (DataStore<T>) dataStores.get(entitySetName);
-  }
-
-  @Override
-  public List<?> readData(final EdmEntitySet entitySet) throws ODataNotImplementedException,
-      ODataNotFoundException, EdmException, ODataApplicationException {
-
-    DataStore<Object> holder = getDataStore(entitySet);
-    if (holder != null) {
-      return new ArrayList<Object>(holder.read());
-    }
-
-    throw new ODataNotFoundException(ODataNotFoundException.ENTITY);
-  }
-
-  @Override
-  public Object readData(final EdmEntitySet entitySet, final Map<String, Object> keys)
-      throws ODataNotFoundException, EdmException, ODataApplicationException {
-
-    DataStore<Object> store = getDataStore(entitySet);
-    if (store != null) {
-      Object keyInstance = store.createInstance();
-      ANNOTATION_HELPER.setKeyFields(keyInstance, keys);
-
-      Object result = store.read(keyInstance);
-      if (result != null) {
-        return result;
-      }
-    }
-
-    throw new ODataNotFoundException(ODataNotFoundException.ENTITY);
-  }
-
-  @Override
-  public Object readData(final EdmFunctionImport function, final Map<String, Object> parameters,
-      final Map<String, Object> keys)
-      throws ODataNotImplementedException, ODataNotFoundException, EdmException, ODataApplicationException {
-    throw new ODataNotImplementedException(ODataNotImplementedException.COMMON);
-  }
-
-  @Override
-  public Object readRelatedData(final EdmEntitySet sourceEntitySet, final Object sourceData,
-      final EdmEntitySet targetEntitySet,
-      final Map<String, Object> targetKeys)
-      throws ODataNotImplementedException, ODataNotFoundException, EdmException, ODataApplicationException {
-
-    DataStore<?> sourceStore = dataStores.get(sourceEntitySet.getName());
-    DataStore<?> targetStore = dataStores.get(targetEntitySet.getName());
-
-    AnnotatedNavInfo navInfo = ANNOTATION_HELPER.getCommonNavigationInfo(
-        sourceStore.getDataTypeClass(), targetStore.getDataTypeClass());
-    Field sourceField = navInfo.getFromField();
-    if (sourceField == null) {
-      throw new ODataRuntimeException("Missing source field for related data (sourceStore='" + sourceStore
-          + "', targetStore='" + targetStore + "').");
-    }
-
-    Object navigationInstance = getValue(sourceField, sourceData);
-    List<Object> resultData = new ArrayList<Object>();
-    for (Object targetInstance : targetStore.read()) {
-      if (navigationInstance instanceof Collection) {
-        for (Object object : (Collection<?>) navigationInstance) {
-          if (targetStore.isKeyEqualChecked(targetInstance, object)) {
-            resultData.add(targetInstance);
-          }
-        }
-      } else if (targetStore.isKeyEqualChecked(targetInstance, navigationInstance)) {
-        resultData.add(targetInstance);
-      }
-    }
-
-    if (navInfo.getToMultiplicity() == EdmMultiplicity.MANY) {
-      if (targetKeys.isEmpty()) {
-        return resultData;
-      } else {
-        Object keyInstance = targetStore.createInstance();
-        ANNOTATION_HELPER.setKeyFields(keyInstance, targetKeys);
-        for (Object result : resultData) {
-          if (targetStore.isKeyEqualChecked(result, keyInstance)) {
-            return result;
-          }
-        }
-        return null;
-      }
-    } else {
-      if (resultData.isEmpty()) {
-        return null;
-      }
-      return resultData.get(0);
-    }
-  }
-
-  @Override
-  public BinaryData readBinaryData(final EdmEntitySet entitySet, final Object mediaLinkEntryData)
-      throws ODataNotImplementedException, ODataNotFoundException, EdmException, ODataApplicationException {
-
-    Object data = ANNOTATION_HELPER.getValueForField(mediaLinkEntryData, EdmMediaResourceContent.class);
-    Object mimeType = ANNOTATION_HELPER.getValueForField(mediaLinkEntryData, EdmMediaResourceMimeType.class);
-
-    if(data == null && mimeType == null) {
-      DataStore<Object> dataStore = getDataStore(entitySet);
-      Object readEntry = dataStore.read(mediaLinkEntryData);
-      if(readEntry != null) {
-        data = ANNOTATION_HELPER.getValueForField(readEntry, EdmMediaResourceContent.class);
-        mimeType = ANNOTATION_HELPER.getValueForField(readEntry, EdmMediaResourceMimeType.class);
-      }
-    }
-    
-    return new BinaryData((byte[]) data, String.valueOf(mimeType));
-  }
-
-  @Override
-  public Object newDataObject(final EdmEntitySet entitySet)
-      throws ODataNotImplementedException, EdmException, ODataApplicationException {
-
-    DataStore<Object> dataStore = getDataStore(entitySet);
-    if (dataStore != null) {
-      return dataStore.createInstance();
-    }
-
-    throw new ODataRuntimeException("No DataStore found for entitySet with name: " + entitySet.getName());
-  }
-
-  @Override
-  public void writeBinaryData(final EdmEntitySet entitySet, final Object mediaEntityInstance,
-      final BinaryData binaryData)
-      throws ODataNotImplementedException, ODataNotFoundException, EdmException, ODataApplicationException {
-
-    try {
-      DataStore<Object> dataStore = getDataStore(entitySet);
-      Object readEntry = dataStore.read(mediaEntityInstance);
-      if(readEntry == null) {
-        throw new ODataNotFoundException(ODataNotFoundException.ENTITY);
-      } else {
-        ANNOTATION_HELPER.setValueForAnnotatedField(
-            mediaEntityInstance, EdmMediaResourceContent.class, binaryData.getData());
-        ANNOTATION_HELPER.setValueForAnnotatedField(
-            mediaEntityInstance, EdmMediaResourceMimeType.class, binaryData.getMimeType());
-      }
-    } catch (ODataAnnotationException e) {
-      throw new ODataRuntimeException("Invalid media resource annotation at entity set '" + entitySet.getName()
-          + "' with message '" + e.getMessage() + "'.", e);
-    }
-  }
-
-  /**
-   * <p>Updates a single data object identified by the specified entity set and key fields of
-   * the data object.</p>
-   * @param entitySet the {@link EdmEntitySet} the object must correspond to
-   * @param data the data object of the new entity
-   * @return updated data object instance
-   * @throws org.apache.olingo.odata2.api.exception.ODataNotImplementedException
-   * @throws org.apache.olingo.odata2.api.edm.EdmException
-   * @throws org.apache.olingo.odata2.api.exception.ODataApplicationException
-   */
-  public Object updateData(final EdmEntitySet entitySet, final Object data)
-      throws ODataNotImplementedException, EdmException, ODataApplicationException {
-
-    DataStore<Object> dataStore = getDataStore(entitySet);
-    return dataStore.update(data);
-  }
-
-  @Override
-  public void deleteData(final EdmEntitySet entitySet, final Map<String, Object> keys)
-      throws ODataNotImplementedException, ODataNotFoundException, EdmException, ODataApplicationException {
-    DataStore<Object> dataStore = getDataStore(entitySet);
-    Object keyInstance = dataStore.createInstance();
-    ANNOTATION_HELPER.setKeyFields(keyInstance, keys);
-    dataStore.delete(keyInstance);
-  }
-
-  @Override
-  public void createData(final EdmEntitySet entitySet, final Object data)
-      throws ODataNotImplementedException, EdmException, ODataApplicationException {
-
-    DataStore<Object> dataStore = getDataStore(entitySet);
-    dataStore.create(data);
-  }
-
-  @Override
-  public void deleteRelation(final EdmEntitySet sourceEntitySet, final Object sourceData,
-      final EdmEntitySet targetEntitySet,
-      final Map<String, Object> targetKeys)
-      throws ODataNotImplementedException, ODataNotFoundException, EdmException, ODataApplicationException {
-    throw new ODataNotImplementedException(ODataNotImplementedException.COMMON);
-  }
-
-  @Override
-  public void writeRelation(final EdmEntitySet sourceEntitySet, final Object sourceEntity,
-      final EdmEntitySet targetEntitySet,
-      final Map<String, Object> targetEntityValues)
-      throws ODataNotImplementedException, ODataNotFoundException, EdmException, ODataApplicationException {
-    // get common data
-    DataStore<Object> sourceStore = dataStores.get(sourceEntitySet.getName());
-    DataStore<Object> targetStore = dataStores.get(targetEntitySet.getName());
-
-    AnnotatedNavInfo commonNavInfo = ANNOTATION_HELPER.getCommonNavigationInfo(
-        sourceStore.getDataTypeClass(), targetStore.getDataTypeClass());
-
-    // get and validate source fields
-    Field sourceField = commonNavInfo.getFromField();
-    if (sourceField == null) {
-      throw new ODataRuntimeException("Missing source field for related data (sourceStore='" + sourceStore
-          + "', targetStore='" + targetStore + "').");
-    }
-
-    // get related target entity
-    Object targetEntity = targetStore.createInstance();
-    ANNOTATION_HELPER.setKeyFields(targetEntity, targetEntityValues);
-    targetEntity = targetStore.read(targetEntity);
-
-    // set at source
-    setValueAtNavigationField(sourceEntity, sourceField, targetEntity);
-    // set at target
-    Field targetField = commonNavInfo.getToField();
-    if (targetField != null) {
-      setValueAtNavigationField(targetEntity, targetField, sourceEntity);
-    }
-  }
-
-  /**
-   * Set (Multiplicity != *) or add (Multiplicity == *) <code>value</code> at <code>field</code>
-   * of <code>instance</code>.
-   * 
-   * @param instance
-   * @param field
-   * @param value
-   * @throws EdmException
-   */
-  private void setValueAtNavigationField(final Object instance, final Field field, final Object value)
-      throws EdmException {
-    Class<?> fieldTypeClass = field.getType();
-    if (Collection.class.isAssignableFrom(fieldTypeClass)) {
-      @SuppressWarnings("unchecked")
-      Collection<Object> collection = (Collection<Object>) ANNOTATION_HELPER.getValueForField(
-          instance, field.getName(), EdmNavigationProperty.class);
-      if (collection == null) {
-        collection = new ArrayList<Object>();
-        setValue(instance, field, collection);
-      }
-      collection.add(value);
-    } else if (fieldTypeClass.isArray()) {
-      throw new ODataRuntimeException("Write relations for internal used arrays is not supported.");
-    } else {
-      setValue(instance, field, value);
-    }
-  }
-
-  /**
-   * Returns corresponding DataStore for EdmEntitySet or if no data store is registered an
-   * ODataRuntimeException is thrown.
-   * Never returns NULL.
-   * 
-   * @param entitySet for which the corresponding DataStore is returned
-   * @return a DataStore object
-   * @throws EdmException
-   * @throws ODataRuntimeException if no DataStore is found
-   */
-  private DataStore<Object> getDataStore(final EdmEntitySet entitySet) throws EdmException {
-    final String name = entitySet.getName();
-    DataStore<Object> dataStore = dataStores.get(name);
-    if (dataStore == null) {
-      throw new ODataRuntimeException("No DataStore found for entity set '" + entitySet + "'.");
-    }
-    return dataStore;
-  }
-
-  private Object getValue(final Field field, final Object instance) {
-    try {
-      boolean access = field.isAccessible();
-      field.setAccessible(true);
-      Object value = field.get(instance);
-      field.setAccessible(access);
-      return value;
-    } catch (IllegalArgumentException e) {
-      throw new ODataRuntimeException("Error for getting value of field '"
-          + field + "' at instance '" + instance + "'.", e);
-    } catch (IllegalAccessException e) {
-      throw new ODataRuntimeException("Error for getting value of field '"
-          + field + "' at instance '" + instance + "'.", e);
-    }
-  }
-
-  private void setValue(final Object instance, final Field field, final Object value) {
-    try {
-      boolean access = field.isAccessible();
-      field.setAccessible(true);
-      field.set(instance, value);
-      field.setAccessible(access);
-    } catch (IllegalArgumentException e) {
-      throw new ODataRuntimeException("Error for setting value of field: '"
-          + field + "' at instance: '" + instance + "'.", e);
-    } catch (IllegalAccessException e) {
-      throw new ODataRuntimeException("Error for setting value of field: '"
-          + field + "' at instance: '" + instance + "'.", e);
-    }
-  }
-}

http://git-wip-us.apache.org/repos/asf/incubator-olingo-odata2/blob/3bd59050/odata2-annotation-processor/annotation-processor-core/src/main/java/org/apache/olingo/odata2/core/annotation/data/AnnotationValueAccess.java
----------------------------------------------------------------------
diff --git a/odata2-annotation-processor/annotation-processor-core/src/main/java/org/apache/olingo/odata2/core/annotation/data/AnnotationValueAccess.java b/odata2-annotation-processor/annotation-processor-core/src/main/java/org/apache/olingo/odata2/core/annotation/data/AnnotationValueAccess.java
deleted file mode 100644
index 5703295..0000000
--- a/odata2-annotation-processor/annotation-processor-core/src/main/java/org/apache/olingo/odata2/core/annotation/data/AnnotationValueAccess.java
+++ /dev/null
@@ -1,109 +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.odata2.core.annotation.data;
-
-import org.apache.olingo.odata2.api.data.ValueAccess;
-import org.apache.olingo.odata2.api.edm.EdmMapping;
-import org.apache.olingo.odata2.api.edm.EdmProperty;
-import org.apache.olingo.odata2.api.exception.ODataException;
-import org.apache.olingo.odata2.api.exception.ODataNotImplementedException;
-import org.apache.olingo.odata2.core.annotation.util.AnnotationHelper;
-
-/**
- *
- */
-public class AnnotationValueAccess implements ValueAccess {
-  private final AnnotationHelper annotationHelper = new AnnotationHelper();
-
-  /**
-   * Retrieves the value of an EDM property for the given data object.
-   * @param data the Java data object
-   * @param property the requested {@link EdmProperty}
-   * @return the requested property value
-   */
-  @Override
-  public <T> Object getPropertyValue(final T data, final EdmProperty property) throws ODataException {
-    if (data == null) {
-      return null;
-    } else if (annotationHelper.isEdmAnnotated(data)) {
-      return annotationHelper.getValueForProperty(data, property.getName());
-    }
-    throw new ODataNotImplementedException(ODataNotImplementedException.COMMON);
-  }
-
-  /**
-   * Sets the value of an EDM property for the given data object.
-   * @param data the Java data object
-   * @param property the {@link EdmProperty}
-   * @param value the new value of the property
-   */
-  @Override
-  public <T, V> void setPropertyValue(final T data, final EdmProperty property, final V value) throws ODataException {
-    if (annotationHelper.isEdmAnnotated(data)) {
-      annotationHelper.setValueForProperty(data, property.getName(), value);
-    } else {
-      throw new ODataNotImplementedException(ODataNotImplementedException.COMMON);
-    }
-  }
-
-  /**
-   * Retrieves the Java type of an EDM property for the given data object.
-   * @param data the Java data object
-   * @param property the requested {@link EdmProperty}
-   * @return the requested Java type
-   */
-  @Override
-  public <T> Class<?> getPropertyType(final T data, final EdmProperty property) throws ODataException {
-    if (annotationHelper.isEdmAnnotated(data)) {
-      Class<?> fieldType = annotationHelper.getFieldTypeForProperty(data, property.getName());
-      if (fieldType == null) {
-        throw new ODataException("No field type found for property " + property);
-      }
-      return fieldType;
-    }
-    throw new ODataNotImplementedException(ODataNotImplementedException.COMMON);
-  }
-
-  /**
-   * Retrieves the value defined by a mapping object for the given data object.
-   * @param data the Java data object
-   * @param mapping the requested {@link EdmMapping}
-   * @return the requested value
-   */
-  @Override
-  public <T> Object getMappingValue(final T data, final EdmMapping mapping) throws ODataException {
-    if (mapping != null && mapping.getMediaResourceMimeTypeKey() != null) {
-      return annotationHelper.getValueForProperty(data, mapping.getMediaResourceMimeTypeKey());
-    }
-    return null;
-  }
-
-  /**
-   * Sets the value defined by a mapping object for the given data object.
-   * @param data the Java data object
-   * @param mapping the {@link EdmMapping}
-   * @param value the new value
-   */
-  @Override
-  public <T, V> void setMappingValue(final T data, final EdmMapping mapping, final V value) throws ODataException {
-    if (mapping != null && mapping.getMediaResourceMimeTypeKey() != null) {
-      annotationHelper.setValueForProperty(data, mapping.getMediaResourceMimeTypeKey(), value);
-    }
-  }
-}

http://git-wip-us.apache.org/repos/asf/incubator-olingo-odata2/blob/3bd59050/odata2-annotation-processor/annotation-processor-core/src/main/java/org/apache/olingo/odata2/core/annotation/data/BeanPropertyAccess.java
----------------------------------------------------------------------
diff --git a/odata2-annotation-processor/annotation-processor-core/src/main/java/org/apache/olingo/odata2/core/annotation/data/BeanPropertyAccess.java b/odata2-annotation-processor/annotation-processor-core/src/main/java/org/apache/olingo/odata2/core/annotation/data/BeanPropertyAccess.java
deleted file mode 100644
index 49794be..0000000
--- a/odata2-annotation-processor/annotation-processor-core/src/main/java/org/apache/olingo/odata2/core/annotation/data/BeanPropertyAccess.java
+++ /dev/null
@@ -1,186 +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.odata2.core.annotation.data;
-
-import java.lang.reflect.InvocationTargetException;
-import java.lang.reflect.Method;
-import java.util.Arrays;
-
-import org.apache.olingo.odata2.api.data.ValueAccess;
-import org.apache.olingo.odata2.api.edm.EdmException;
-import org.apache.olingo.odata2.api.edm.EdmMapping;
-import org.apache.olingo.odata2.api.edm.EdmProperty;
-import org.apache.olingo.odata2.api.edm.EdmSimpleTypeKind;
-import org.apache.olingo.odata2.api.exception.ODataException;
-import org.apache.olingo.odata2.api.exception.ODataHttpException;
-import org.apache.olingo.odata2.api.exception.ODataNotFoundException;
-
-/**
- * Data access.
- */
-public class BeanPropertyAccess implements ValueAccess {
-
-  @Override
-  public <T> Object getPropertyValue(final T data, final EdmProperty property) throws ODataException {
-    return getValue(data, getGetterMethodName(property));
-  }
-
-  @Override
-  public <T, V> void setPropertyValue(final T data, final EdmProperty property, final V value) throws ODataException {
-    final String methodName = getSetterMethodName(getGetterMethodName(property));
-    if (methodName != null) {
-      setValue(data, methodName, value);
-    }
-  }
-
-  @Override
-  public <T> Class<?> getPropertyType(final T data, final EdmProperty property) throws ODataException {
-    return getType(data, getGetterMethodName(property));
-  }
-
-  @Override
-  public <T> Object getMappingValue(final T data, final EdmMapping mapping) throws ODataException {
-    if (mapping != null && mapping.getMimeType() != null) {
-      return getValue(data, mapping.getMimeType());
-    }
-    return null;
-  }
-
-  @Override
-  public <T, V> void setMappingValue(final T data, final EdmMapping mapping, final V value) throws ODataException {
-    if (mapping != null && mapping.getMimeType() != null) {
-      setValue(data, getSetterMethodName(mapping.getMimeType()), value);
-    }
-  }
-
-  private String getGetterMethodName(final EdmProperty property) throws EdmException {
-    final String prefix = isBooleanProperty(property) ? "is" : "get";
-    final String defaultMethodName = prefix + property.getName();
-    return property.getMapping() == null || property.getMapping().getInternalName() == null ?
-        defaultMethodName : property.getMapping().getInternalName();
-  }
-
-  private boolean isBooleanProperty(final EdmProperty property) throws EdmException {
-    return property.isSimple()
-        && property.getType() == EdmSimpleTypeKind.Boolean.getEdmSimpleTypeInstance();
-  }
-
-  private String getSetterMethodName(final String getterMethodName) {
-    return getterMethodName.contains(".") ?
-        null : getterMethodName.replaceFirst("^is", "set").replaceFirst("^get", "set");
-  }
-
-  private <T> Object getValue(final T data, final String methodName) throws ODataNotFoundException {
-    Object dataObject = data;
-
-    for (final String method : methodName.split("\\.", -1)) {
-      if (dataObject != null) {
-        try {
-          dataObject = dataObject.getClass().getMethod(method).invoke(dataObject);
-        } catch (SecurityException e) {
-          throw new ODataNotFoundException(ODataHttpException.COMMON, e);
-        } catch (NoSuchMethodException e) {
-          throw new ODataNotFoundException(ODataHttpException.COMMON, e);
-        } catch (IllegalArgumentException e) {
-          throw new ODataNotFoundException(ODataHttpException.COMMON, e);
-        } catch (IllegalAccessException e) {
-          throw new ODataNotFoundException(ODataHttpException.COMMON, e);
-        } catch (InvocationTargetException e) {
-          throw new ODataNotFoundException(ODataHttpException.COMMON, e);
-        }
-      }
-    }
-
-    return dataObject;
-  }
-
-  private <T, V> void setValue(final T data, final String methodName, final V value)
-      throws ODataNotFoundException {
-    try {
-      boolean found = false;
-      for (final Method method : Arrays.asList(data.getClass().getMethods())) {
-        if (method.getName().equals(methodName)) {
-          found = true;
-          final Class<?> type = method.getParameterTypes()[0];
-          if (value == null) {
-            if (type.equals(byte.class) || type.equals(short.class) || type.equals(int.class)
-                || type.equals(long.class) || type.equals(char.class)) {
-              method.invoke(data, 0);
-            } else if (type.equals(float.class) || type.equals(double.class)) {
-              method.invoke(data, 0.0);
-            } else if (type.equals(boolean.class)) {
-              method.invoke(data, false);
-            } else {
-              method.invoke(data, value);
-            }
-          } else {
-            method.invoke(data, value);
-          }
-          break;
-        }
-      }
-      if (!found) {
-        throw new ODataNotFoundException(null);
-      }
-    } catch (SecurityException e) {
-      throw new ODataNotFoundException(null, e);
-    } catch (IllegalArgumentException e) {
-      throw new ODataNotFoundException(null, e);
-    } catch (IllegalAccessException e) {
-      throw new ODataNotFoundException(null, e);
-    } catch (InvocationTargetException e) {
-      throw new ODataNotFoundException(null, e);
-    }
-  }
-
-  private <T> Class<?> getType(final T data, final String methodName) throws ODataNotFoundException {
-    if (data == null) {
-      throw new ODataNotFoundException(ODataHttpException.COMMON);
-    }
-
-    Class<?> type = data.getClass();
-    for (final String method : methodName.split("\\.", -1)) {
-      try {
-        type = type.getMethod(method).getReturnType();
-        if (type.isPrimitive()) {
-          if (type == boolean.class) {
-            type = Boolean.class;
-          } else if (type == byte.class) {
-            type = Byte.class;
-          } else if (type == short.class) {
-            type = Short.class;
-          } else if (type == int.class) {
-            type = Integer.class;
-          } else if (type == long.class) {
-            type = Long.class;
-          } else if (type == float.class) {
-            type = Float.class;
-          } else if (type == double.class) {
-            type = Double.class;
-          }
-        }
-      } catch (final SecurityException e) {
-        throw new ODataNotFoundException(ODataHttpException.COMMON, e);
-      } catch (final NoSuchMethodException e) {
-        throw new ODataNotFoundException(ODataHttpException.COMMON, e);
-      }
-    }
-    return type;
-  }
-}

http://git-wip-us.apache.org/repos/asf/incubator-olingo-odata2/blob/3bd59050/odata2-annotation-processor/annotation-processor-core/src/main/java/org/apache/olingo/odata2/core/annotation/data/DataStore.java
----------------------------------------------------------------------
diff --git a/odata2-annotation-processor/annotation-processor-core/src/main/java/org/apache/olingo/odata2/core/annotation/data/DataStore.java b/odata2-annotation-processor/annotation-processor-core/src/main/java/org/apache/olingo/odata2/core/annotation/data/DataStore.java
deleted file mode 100644
index ab52c0b..0000000
--- a/odata2-annotation-processor/annotation-processor-core/src/main/java/org/apache/olingo/odata2/core/annotation/data/DataStore.java
+++ /dev/null
@@ -1,294 +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.odata2.core.annotation.data;
-
-import java.lang.reflect.Field;
-import java.util.ArrayList;
-import java.util.Collection;
-import java.util.Collections;
-import java.util.HashMap;
-import java.util.List;
-import java.util.Locale;
-import java.util.Map;
-import java.util.concurrent.atomic.AtomicInteger;
-
-import org.apache.olingo.odata2.api.annotation.edm.EdmKey;
-import org.apache.olingo.odata2.api.exception.ODataApplicationException;
-import org.apache.olingo.odata2.core.annotation.util.AnnotationHelper;
-import org.apache.olingo.odata2.core.annotation.util.ClassHelper;
-import org.apache.olingo.odata2.core.exception.ODataRuntimeException;
-
-/**
- *
- */
-public class DataStore<T> {
-
-  private static final AnnotationHelper ANNOTATION_HELPER = new AnnotationHelper();
-  private final Map<KeyElement, T> dataStore;
-  private final Class<T> dataTypeClass;
-  private final KeyAccess keyAccess;
-
-  private static class InMemoryDataStore {
-    private static final Map<Class<?>, DataStore<?>> c2ds = new HashMap<Class<?>, DataStore<?>>();
-
-    @SuppressWarnings("unchecked")
-    static synchronized DataStore<?> getInstance(final Class<?> clz, final boolean createNewInstance)
-        throws DataStoreException {
-      DataStore<?> ds = c2ds.get(clz);
-      if (createNewInstance || ds == null) {
-        ds = new DataStore<Object>((Class<Object>) clz);
-        c2ds.put(clz, ds);
-      }
-      return ds;
-    }
-  }
-
-  @SuppressWarnings("unchecked")
-  public static <T> DataStore<T> createInMemory(final Class<T> clazz) throws DataStoreException {
-    return (DataStore<T>) InMemoryDataStore.getInstance(clazz, true);
-  }
-
-  @SuppressWarnings("unchecked")
-  public static <T> DataStore<T> createInMemory(final Class<T> clazz, final boolean keepExisting)
-      throws DataStoreException {
-    return (DataStore<T>) InMemoryDataStore.getInstance(clazz, !keepExisting);
-  }
-
-  private DataStore(final Map<KeyElement, T> wrapStore, final Class<T> clz) throws DataStoreException {
-    dataStore = Collections.synchronizedMap(wrapStore);
-    dataTypeClass = clz;
-    keyAccess = new KeyAccess(clz);
-  }
-
-  private DataStore(final Class<T> clz) throws DataStoreException {
-    this(new HashMap<KeyElement, T>(), clz);
-  }
-
-  public Class<T> getDataTypeClass() {
-    return dataTypeClass;
-  }
-
-  public String getEntityTypeName() {
-    return ANNOTATION_HELPER.extractEntityTypeName(dataTypeClass);
-  }
-
-  public T createInstance() {
-    try {
-      return dataTypeClass.newInstance();
-    } catch (InstantiationException e) {
-      throw new ODataRuntimeException("Unable to create instance of class '" + dataTypeClass + "'.", e);
-    } catch (IllegalAccessException e) {
-      throw new ODataRuntimeException("Unable to create instance of class '" + dataTypeClass + "'.", e);
-    }
-  }
-
-  public T read(final T obj) {
-    KeyElement objKeys = getKeys(obj);
-    return dataStore.get(objKeys);
-  }
-
-  public Collection<T> read() {
-    return Collections.unmodifiableCollection(dataStore.values());
-  }
-
-  public T create(final T object) throws DataStoreException {
-    KeyElement keyElement = getKeys(object);
-    return create(object, keyElement);
-  }
-
-  private T create(final T object, final KeyElement keyElement) throws DataStoreException {
-    synchronized (dataStore) {
-      if (keyElement.keyValuesMissing() || dataStore.containsKey(keyElement)) {
-        KeyElement newKey = createSetAndGetKeys(object);
-        return this.create(object, newKey);
-      }
-      dataStore.put(keyElement, object);
-    }
-    return object;
-  }
-
-  public T update(final T object) {
-    KeyElement keyElement = getKeys(object);
-    synchronized (dataStore) {
-      dataStore.remove(keyElement);
-      dataStore.put(keyElement, object);
-    }
-    return object;
-  }
-
-  public T delete(final T object) {
-    KeyElement keyElement = getKeys(object);
-    synchronized (dataStore) {
-      return dataStore.remove(keyElement);
-    }
-  }
-  
-  /**
-   * Are the key values equal for both instances.
-   * If all compared key values are <code>null</code> this also means equal.
-   * 
-   * @param first first instance to check for key equal
-   * @param second second instance to check for key equal
-   * @return <code>true</code> if object instance have equal keys set.
-   */
-  public boolean isKeyEqual(final T first, final T second) {
-    KeyElement firstKeys = getKeys(first);
-    KeyElement secondKeys = getKeys(second);
-    
-    return firstKeys.equals(secondKeys);
-  }
-  
-  /**
-   * Are the key values equal for both instances.
-   * If all compared key values are <code>null</code> this also means equal.
-   * Before object (keys) are compared it is validated that both object instance are NOT null
-   * and that both are from the same class as this {@link DataStore} (see {@link #dataTypeClass}).
-   * For the equal check on {@link #dataTypeClass} instances without validation see
-   * {@link #isKeyEqual(Object, Object)}.
-   * 
-   * @param first first instance to check for key equal
-   * @param second second instance to check for key equal
-   * @return <code>true</code> if object instance have equal keys set.
-   */
-  @SuppressWarnings("unchecked")
-  public boolean isKeyEqualChecked(Object first, Object second) throws DataStoreException {
-    if(first == null || second == null) {
-      throw new DataStoreException("Tried to compare null values which is not allowed.");
-    } else if(first.getClass() != dataTypeClass) {
-      throw new DataStoreException("First value is no instance from required class '" + dataTypeClass + "'.");
-    } else if(second.getClass() != dataTypeClass) {
-      throw new DataStoreException("Second value is no instance from required class '" + dataTypeClass + "'.");
-    }
-    
-    return isKeyEqual((T) first, (T) second);
-  }
-
-
-  private class KeyElement {
-    private int cachedHashCode = 42;
-    private final List<Object> keyValues;
-
-    public KeyElement(final int size) {
-      keyValues = new ArrayList<Object>(size);
-    }
-
-    private void addValue(final Object keyValue) {
-      keyValues.add(keyValue);
-      cachedHashCode = 89 * cachedHashCode + (keyValue != null ? keyValue.hashCode() : 0);
-    }
-
-    boolean keyValuesMissing() {
-      return keyValues.contains(null);
-    }
-
-    @Override
-    public int hashCode() {
-      return cachedHashCode;
-    }
-
-    @Override
-    public boolean equals(final Object obj) {
-      if (obj == null) {
-        return false;
-      }
-      if (getClass() != obj.getClass()) {
-        return false;
-      }
-      @SuppressWarnings("unchecked")
-      final KeyElement other = (KeyElement) obj;
-      if (this.keyValues != other.keyValues && (this.keyValues == null || !this.keyValues.equals(other.keyValues))) {
-        return false;
-      }
-      return true;
-    }
-
-    @Override
-    public String toString() {
-      return "KeyElement{" + "cachedHashCode=" + cachedHashCode + ", keyValues=" + keyValues + '}';
-    }
-  }
-
-  private class KeyAccess {
-    final List<Field> keyFields;
-    final AtomicInteger idCounter = new AtomicInteger(1);
-
-    KeyAccess(final Class<?> clazz) throws DataStoreException {
-      keyFields = ANNOTATION_HELPER.getAnnotatedFields(clazz, EdmKey.class);
-      if (keyFields.isEmpty()) {
-        throw new DataStoreException("No EdmKey annotated fields found for class " + clazz);
-      }
-    }
-
-    KeyElement getKeyValues(final T object) {
-      KeyElement keyElement = new KeyElement(keyFields.size());
-      for (Field field : keyFields) {
-        Object keyValue = ClassHelper.getFieldValue(object, field);
-        keyElement.addValue(keyValue);
-      }
-
-      return keyElement;
-    }
-
-    KeyElement createSetAndGetKeys(final T object) throws DataStoreException {
-      KeyElement keyElement = new KeyElement(keyFields.size());
-      for (Field field : keyFields) {
-        Object key = createKey(field);
-        ClassHelper.setFieldValue(object, field, key);
-        keyElement.addValue(key);
-      }
-
-      return keyElement;
-    }
-
-    private Object createKey(final Field field) {
-      Class<?> type = field.getType();
-
-      if (type == String.class) {
-        return String.valueOf(idCounter.getAndIncrement());
-      } else if (type == Integer.class || type == int.class) {
-        return Integer.valueOf(idCounter.getAndIncrement());
-      } else if (type == Long.class || type == long.class) {
-        return Long.valueOf(idCounter.getAndIncrement());
-      }
-
-      throw new UnsupportedOperationException("Automated key generation for type '" + type
-          + "' is not supported (caused on field '" + field + "').");
-    }
-  }
-
-  private KeyElement getKeys(final T object) {
-    return keyAccess.getKeyValues(object);
-  }
-
-  private KeyElement createSetAndGetKeys(final T object) throws DataStoreException {
-    return keyAccess.createSetAndGetKeys(object);
-  }
-
-  public static class DataStoreException extends ODataApplicationException {
-    private static final long serialVersionUID = 42L;
-
-    public DataStoreException(final String message) {
-      this(message, null);
-    }
-
-    public DataStoreException(final String message, final Throwable cause) {
-      super(message, Locale.ENGLISH, cause);
-    }
-  }
-}


[07/12] [OLINGO-83] Refactoring of 'annotation-processor-*' modules

Posted by tb...@apache.org.
http://git-wip-us.apache.org/repos/asf/incubator-olingo-odata2/blob/3bd59050/odata2-annotation-processor/annotation-processor-core/src/main/java/org/apache/olingo/odata2/annotation/processor/core/datasource/AnnotationInMemoryDs.java
----------------------------------------------------------------------
diff --git a/odata2-annotation-processor/annotation-processor-core/src/main/java/org/apache/olingo/odata2/annotation/processor/core/datasource/AnnotationInMemoryDs.java b/odata2-annotation-processor/annotation-processor-core/src/main/java/org/apache/olingo/odata2/annotation/processor/core/datasource/AnnotationInMemoryDs.java
new file mode 100644
index 0000000..b389fa4
--- /dev/null
+++ b/odata2-annotation-processor/annotation-processor-core/src/main/java/org/apache/olingo/odata2/annotation/processor/core/datasource/AnnotationInMemoryDs.java
@@ -0,0 +1,384 @@
+/**
+ * *****************************************************************************
+ * Licensed to the Apache Software Foundation (ASF) under one or more contributor license agreements. See the NOTICE
+ * file distributed with this work for additional information regarding copyright ownership. The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the "License"); you may not use this file except in compliance with the
+ * License. You may obtain a copy of the License at
+ * 
+ * http://www.apache.org/licenses/LICENSE-2.0
+ * 
+ * Unless required by applicable law or agreed to in writing, software distributed under the License is distributed on
+ * an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the License for the
+ * specific language governing permissions and limitations under the License.
+ ***************************************************************************** 
+ */
+package org.apache.olingo.odata2.annotation.processor.core.datasource;
+
+import java.lang.reflect.Field;
+import java.util.ArrayList;
+import java.util.Collection;
+import java.util.HashMap;
+import java.util.List;
+import java.util.Map;
+
+import org.apache.olingo.odata2.annotation.processor.core.util.AnnotationHelper;
+import org.apache.olingo.odata2.annotation.processor.core.util.AnnotationHelper.AnnotatedNavInfo;
+import org.apache.olingo.odata2.annotation.processor.core.util.AnnotationHelper.ODataAnnotationException;
+import org.apache.olingo.odata2.annotation.processor.core.util.ClassHelper;
+import org.apache.olingo.odata2.api.annotation.edm.EdmMediaResourceContent;
+import org.apache.olingo.odata2.api.annotation.edm.EdmMediaResourceMimeType;
+import org.apache.olingo.odata2.api.annotation.edm.EdmNavigationProperty;
+import org.apache.olingo.odata2.api.edm.EdmEntitySet;
+import org.apache.olingo.odata2.api.edm.EdmException;
+import org.apache.olingo.odata2.api.edm.EdmFunctionImport;
+import org.apache.olingo.odata2.api.edm.EdmMultiplicity;
+import org.apache.olingo.odata2.api.exception.ODataApplicationException;
+import org.apache.olingo.odata2.api.exception.ODataException;
+import org.apache.olingo.odata2.api.exception.ODataNotFoundException;
+import org.apache.olingo.odata2.api.exception.ODataNotImplementedException;
+import org.apache.olingo.odata2.core.exception.ODataRuntimeException;
+
+public class AnnotationInMemoryDs implements DataSource {
+
+  private static final AnnotationHelper ANNOTATION_HELPER = new AnnotationHelper();
+  private final Map<String, DataStore<Object>> dataStores = new HashMap<String, DataStore<Object>>();
+  private final boolean persistInMemory;
+
+  public AnnotationInMemoryDs(Collection<Class<?>> annotatedClasses) throws ODataException {
+    this(annotatedClasses, true);
+  }
+
+  public AnnotationInMemoryDs(Collection<Class<?>> annotatedClasses, boolean persistInMemory) throws ODataException {
+    this.persistInMemory = persistInMemory;
+    init(annotatedClasses);
+  }
+
+  public AnnotationInMemoryDs(final String packageToScan) throws ODataException {
+    this(packageToScan, true);
+  }
+
+  public AnnotationInMemoryDs(final String packageToScan, final boolean persistInMemory) throws ODataException {
+    this.persistInMemory = persistInMemory;
+    List<Class<?>> foundClasses = ClassHelper.loadClasses(packageToScan, new ClassHelper.ClassValidator() {
+      @Override
+      public boolean isClassValid(final Class<?> c) {
+        return null != c.getAnnotation(org.apache.olingo.odata2.api.annotation.edm.EdmEntitySet.class);
+      }
+    });
+
+    init(foundClasses);
+  }
+
+  @SuppressWarnings("unchecked")
+  private void init(final Collection<Class<?>> annotatedClasses) throws ODataException {
+    try {
+      for (Class<?> clz : annotatedClasses) {
+        DataStore<Object> dhs = (DataStore<Object>) DataStore.createInMemory(clz, persistInMemory);
+        String entitySetName = ANNOTATION_HELPER.extractEntitySetName(clz);
+        dataStores.put(entitySetName, dhs);
+      }
+    } catch (DataStore.DataStoreException e) {
+      throw new ODataException("Error in DataStore initilization with message: " + e.getMessage(), e);
+    }
+  }
+
+  public <T> DataStore<T> getDataStore(final Class<T> clazz) {
+    String entitySetName = ANNOTATION_HELPER.extractEntitySetName(clazz);
+    return (DataStore<T>) dataStores.get(entitySetName);
+  }
+
+  @Override
+  public List<?> readData(final EdmEntitySet entitySet) throws ODataNotImplementedException,
+      ODataNotFoundException, EdmException, ODataApplicationException {
+
+    DataStore<Object> holder = getDataStore(entitySet);
+    if (holder != null) {
+      return new ArrayList<Object>(holder.read());
+    }
+
+    throw new ODataNotFoundException(ODataNotFoundException.ENTITY);
+  }
+
+  @Override
+  public Object readData(final EdmEntitySet entitySet, final Map<String, Object> keys)
+      throws ODataNotFoundException, EdmException, ODataApplicationException {
+
+    DataStore<Object> store = getDataStore(entitySet);
+    if (store != null) {
+      Object keyInstance = store.createInstance();
+      ANNOTATION_HELPER.setKeyFields(keyInstance, keys);
+
+      Object result = store.read(keyInstance);
+      if (result != null) {
+        return result;
+      }
+    }
+
+    throw new ODataNotFoundException(ODataNotFoundException.ENTITY);
+  }
+
+  @Override
+  public Object readData(final EdmFunctionImport function, final Map<String, Object> parameters,
+      final Map<String, Object> keys)
+      throws ODataNotImplementedException, ODataNotFoundException, EdmException, ODataApplicationException {
+    throw new ODataNotImplementedException(ODataNotImplementedException.COMMON);
+  }
+
+  @Override
+  public Object readRelatedData(final EdmEntitySet sourceEntitySet, final Object sourceData,
+      final EdmEntitySet targetEntitySet,
+      final Map<String, Object> targetKeys)
+      throws ODataNotImplementedException, ODataNotFoundException, EdmException, ODataApplicationException {
+
+    DataStore<?> sourceStore = dataStores.get(sourceEntitySet.getName());
+    DataStore<?> targetStore = dataStores.get(targetEntitySet.getName());
+
+    AnnotatedNavInfo navInfo = ANNOTATION_HELPER.getCommonNavigationInfo(
+        sourceStore.getDataTypeClass(), targetStore.getDataTypeClass());
+    Field sourceField = navInfo.getFromField();
+    if (sourceField == null) {
+      throw new ODataRuntimeException("Missing source field for related data (sourceStore='" + sourceStore
+          + "', targetStore='" + targetStore + "').");
+    }
+
+    Object navigationInstance = getValue(sourceField, sourceData);
+    List<Object> resultData = new ArrayList<Object>();
+    for (Object targetInstance : targetStore.read()) {
+      if (navigationInstance instanceof Collection) {
+        for (Object object : (Collection<?>) navigationInstance) {
+          if (targetStore.isKeyEqualChecked(targetInstance, object)) {
+            resultData.add(targetInstance);
+          }
+        }
+      } else if (targetStore.isKeyEqualChecked(targetInstance, navigationInstance)) {
+        resultData.add(targetInstance);
+      }
+    }
+
+    if (navInfo.getToMultiplicity() == EdmMultiplicity.MANY) {
+      if (targetKeys.isEmpty()) {
+        return resultData;
+      } else {
+        Object keyInstance = targetStore.createInstance();
+        ANNOTATION_HELPER.setKeyFields(keyInstance, targetKeys);
+        for (Object result : resultData) {
+          if (targetStore.isKeyEqualChecked(result, keyInstance)) {
+            return result;
+          }
+        }
+        return null;
+      }
+    } else {
+      if (resultData.isEmpty()) {
+        return null;
+      }
+      return resultData.get(0);
+    }
+  }
+
+  @Override
+  public BinaryData readBinaryData(final EdmEntitySet entitySet, final Object mediaLinkEntryData)
+      throws ODataNotImplementedException, ODataNotFoundException, EdmException, ODataApplicationException {
+
+    Object data = ANNOTATION_HELPER.getValueForField(mediaLinkEntryData, EdmMediaResourceContent.class);
+    Object mimeType = ANNOTATION_HELPER.getValueForField(mediaLinkEntryData, EdmMediaResourceMimeType.class);
+
+    if(data == null && mimeType == null) {
+      DataStore<Object> dataStore = getDataStore(entitySet);
+      Object readEntry = dataStore.read(mediaLinkEntryData);
+      if(readEntry != null) {
+        data = ANNOTATION_HELPER.getValueForField(readEntry, EdmMediaResourceContent.class);
+        mimeType = ANNOTATION_HELPER.getValueForField(readEntry, EdmMediaResourceMimeType.class);
+      }
+    }
+    
+    return new BinaryData((byte[]) data, String.valueOf(mimeType));
+  }
+
+  @Override
+  public Object newDataObject(final EdmEntitySet entitySet)
+      throws ODataNotImplementedException, EdmException, ODataApplicationException {
+
+    DataStore<Object> dataStore = getDataStore(entitySet);
+    if (dataStore != null) {
+      return dataStore.createInstance();
+    }
+
+    throw new ODataRuntimeException("No DataStore found for entitySet with name: " + entitySet.getName());
+  }
+
+  @Override
+  public void writeBinaryData(final EdmEntitySet entitySet, final Object mediaEntityInstance,
+      final BinaryData binaryData)
+      throws ODataNotImplementedException, ODataNotFoundException, EdmException, ODataApplicationException {
+
+    try {
+      DataStore<Object> dataStore = getDataStore(entitySet);
+      Object readEntry = dataStore.read(mediaEntityInstance);
+      if(readEntry == null) {
+        throw new ODataNotFoundException(ODataNotFoundException.ENTITY);
+      } else {
+        ANNOTATION_HELPER.setValueForAnnotatedField(
+            mediaEntityInstance, EdmMediaResourceContent.class, binaryData.getData());
+        ANNOTATION_HELPER.setValueForAnnotatedField(
+            mediaEntityInstance, EdmMediaResourceMimeType.class, binaryData.getMimeType());
+      }
+    } catch (ODataAnnotationException e) {
+      throw new ODataRuntimeException("Invalid media resource annotation at entity set '" + entitySet.getName()
+          + "' with message '" + e.getMessage() + "'.", e);
+    }
+  }
+
+  /**
+   * <p>Updates a single data object identified by the specified entity set and key fields of
+   * the data object.</p>
+   * @param entitySet the {@link EdmEntitySet} the object must correspond to
+   * @param data the data object of the new entity
+   * @return updated data object instance
+   * @throws org.apache.olingo.odata2.api.exception.ODataNotImplementedException
+   * @throws org.apache.olingo.odata2.api.edm.EdmException
+   * @throws org.apache.olingo.odata2.api.exception.ODataApplicationException
+   */
+  public Object updateData(final EdmEntitySet entitySet, final Object data)
+      throws ODataNotImplementedException, EdmException, ODataApplicationException {
+
+    DataStore<Object> dataStore = getDataStore(entitySet);
+    return dataStore.update(data);
+  }
+
+  @Override
+  public void deleteData(final EdmEntitySet entitySet, final Map<String, Object> keys)
+      throws ODataNotImplementedException, ODataNotFoundException, EdmException, ODataApplicationException {
+    DataStore<Object> dataStore = getDataStore(entitySet);
+    Object keyInstance = dataStore.createInstance();
+    ANNOTATION_HELPER.setKeyFields(keyInstance, keys);
+    dataStore.delete(keyInstance);
+  }
+
+  @Override
+  public void createData(final EdmEntitySet entitySet, final Object data)
+      throws ODataNotImplementedException, EdmException, ODataApplicationException {
+
+    DataStore<Object> dataStore = getDataStore(entitySet);
+    dataStore.create(data);
+  }
+
+  @Override
+  public void deleteRelation(final EdmEntitySet sourceEntitySet, final Object sourceData,
+      final EdmEntitySet targetEntitySet,
+      final Map<String, Object> targetKeys)
+      throws ODataNotImplementedException, ODataNotFoundException, EdmException, ODataApplicationException {
+    throw new ODataNotImplementedException(ODataNotImplementedException.COMMON);
+  }
+
+  @Override
+  public void writeRelation(final EdmEntitySet sourceEntitySet, final Object sourceEntity,
+      final EdmEntitySet targetEntitySet,
+      final Map<String, Object> targetEntityValues)
+      throws ODataNotImplementedException, ODataNotFoundException, EdmException, ODataApplicationException {
+    // get common data
+    DataStore<Object> sourceStore = dataStores.get(sourceEntitySet.getName());
+    DataStore<Object> targetStore = dataStores.get(targetEntitySet.getName());
+
+    AnnotatedNavInfo commonNavInfo = ANNOTATION_HELPER.getCommonNavigationInfo(
+        sourceStore.getDataTypeClass(), targetStore.getDataTypeClass());
+
+    // get and validate source fields
+    Field sourceField = commonNavInfo.getFromField();
+    if (sourceField == null) {
+      throw new ODataRuntimeException("Missing source field for related data (sourceStore='" + sourceStore
+          + "', targetStore='" + targetStore + "').");
+    }
+
+    // get related target entity
+    Object targetEntity = targetStore.createInstance();
+    ANNOTATION_HELPER.setKeyFields(targetEntity, targetEntityValues);
+    targetEntity = targetStore.read(targetEntity);
+
+    // set at source
+    setValueAtNavigationField(sourceEntity, sourceField, targetEntity);
+    // set at target
+    Field targetField = commonNavInfo.getToField();
+    if (targetField != null) {
+      setValueAtNavigationField(targetEntity, targetField, sourceEntity);
+    }
+  }
+
+  /**
+   * Set (Multiplicity != *) or add (Multiplicity == *) <code>value</code> at <code>field</code>
+   * of <code>instance</code>.
+   * 
+   * @param instance
+   * @param field
+   * @param value
+   * @throws EdmException
+   */
+  private void setValueAtNavigationField(final Object instance, final Field field, final Object value)
+      throws EdmException {
+    Class<?> fieldTypeClass = field.getType();
+    if (Collection.class.isAssignableFrom(fieldTypeClass)) {
+      @SuppressWarnings("unchecked")
+      Collection<Object> collection = (Collection<Object>) ANNOTATION_HELPER.getValueForField(
+          instance, field.getName(), EdmNavigationProperty.class);
+      if (collection == null) {
+        collection = new ArrayList<Object>();
+        setValue(instance, field, collection);
+      }
+      collection.add(value);
+    } else if (fieldTypeClass.isArray()) {
+      throw new ODataRuntimeException("Write relations for internal used arrays is not supported.");
+    } else {
+      setValue(instance, field, value);
+    }
+  }
+
+  /**
+   * Returns corresponding DataStore for EdmEntitySet or if no data store is registered an
+   * ODataRuntimeException is thrown.
+   * Never returns NULL.
+   * 
+   * @param entitySet for which the corresponding DataStore is returned
+   * @return a DataStore object
+   * @throws EdmException
+   * @throws ODataRuntimeException if no DataStore is found
+   */
+  private DataStore<Object> getDataStore(final EdmEntitySet entitySet) throws EdmException {
+    final String name = entitySet.getName();
+    DataStore<Object> dataStore = dataStores.get(name);
+    if (dataStore == null) {
+      throw new ODataRuntimeException("No DataStore found for entity set '" + entitySet + "'.");
+    }
+    return dataStore;
+  }
+
+  private Object getValue(final Field field, final Object instance) {
+    try {
+      boolean access = field.isAccessible();
+      field.setAccessible(true);
+      Object value = field.get(instance);
+      field.setAccessible(access);
+      return value;
+    } catch (IllegalArgumentException e) {
+      throw new ODataRuntimeException("Error for getting value of field '"
+          + field + "' at instance '" + instance + "'.", e);
+    } catch (IllegalAccessException e) {
+      throw new ODataRuntimeException("Error for getting value of field '"
+          + field + "' at instance '" + instance + "'.", e);
+    }
+  }
+
+  private void setValue(final Object instance, final Field field, final Object value) {
+    try {
+      boolean access = field.isAccessible();
+      field.setAccessible(true);
+      field.set(instance, value);
+      field.setAccessible(access);
+    } catch (IllegalArgumentException e) {
+      throw new ODataRuntimeException("Error for setting value of field: '"
+          + field + "' at instance: '" + instance + "'.", e);
+    } catch (IllegalAccessException e) {
+      throw new ODataRuntimeException("Error for setting value of field: '"
+          + field + "' at instance: '" + instance + "'.", e);
+    }
+  }
+}

http://git-wip-us.apache.org/repos/asf/incubator-olingo-odata2/blob/3bd59050/odata2-annotation-processor/annotation-processor-core/src/main/java/org/apache/olingo/odata2/annotation/processor/core/datasource/AnnotationValueAccess.java
----------------------------------------------------------------------
diff --git a/odata2-annotation-processor/annotation-processor-core/src/main/java/org/apache/olingo/odata2/annotation/processor/core/datasource/AnnotationValueAccess.java b/odata2-annotation-processor/annotation-processor-core/src/main/java/org/apache/olingo/odata2/annotation/processor/core/datasource/AnnotationValueAccess.java
new file mode 100644
index 0000000..b685ec8
--- /dev/null
+++ b/odata2-annotation-processor/annotation-processor-core/src/main/java/org/apache/olingo/odata2/annotation/processor/core/datasource/AnnotationValueAccess.java
@@ -0,0 +1,108 @@
+/*******************************************************************************
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License. You may obtain a copy of the License at
+ * 
+ * http://www.apache.org/licenses/LICENSE-2.0
+ * 
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied. See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ ******************************************************************************/
+package org.apache.olingo.odata2.annotation.processor.core.datasource;
+
+import org.apache.olingo.odata2.annotation.processor.core.util.AnnotationHelper;
+import org.apache.olingo.odata2.api.edm.EdmMapping;
+import org.apache.olingo.odata2.api.edm.EdmProperty;
+import org.apache.olingo.odata2.api.exception.ODataException;
+import org.apache.olingo.odata2.api.exception.ODataNotImplementedException;
+
+/**
+ *
+ */
+public class AnnotationValueAccess implements ValueAccess {
+  private final AnnotationHelper annotationHelper = new AnnotationHelper();
+
+  /**
+   * Retrieves the value of an EDM property for the given data object.
+   * @param data the Java data object
+   * @param property the requested {@link EdmProperty}
+   * @return the requested property value
+   */
+  @Override
+  public <T> Object getPropertyValue(final T data, final EdmProperty property) throws ODataException {
+    if (data == null) {
+      return null;
+    } else if (annotationHelper.isEdmAnnotated(data)) {
+      return annotationHelper.getValueForProperty(data, property.getName());
+    }
+    throw new ODataNotImplementedException(ODataNotImplementedException.COMMON);
+  }
+
+  /**
+   * Sets the value of an EDM property for the given data object.
+   * @param data the Java data object
+   * @param property the {@link EdmProperty}
+   * @param value the new value of the property
+   */
+  @Override
+  public <T, V> void setPropertyValue(final T data, final EdmProperty property, final V value) throws ODataException {
+    if (annotationHelper.isEdmAnnotated(data)) {
+      annotationHelper.setValueForProperty(data, property.getName(), value);
+    } else {
+      throw new ODataNotImplementedException(ODataNotImplementedException.COMMON);
+    }
+  }
+
+  /**
+   * Retrieves the Java type of an EDM property for the given data object.
+   * @param data the Java data object
+   * @param property the requested {@link EdmProperty}
+   * @return the requested Java type
+   */
+  @Override
+  public <T> Class<?> getPropertyType(final T data, final EdmProperty property) throws ODataException {
+    if (annotationHelper.isEdmAnnotated(data)) {
+      Class<?> fieldType = annotationHelper.getFieldTypeForProperty(data, property.getName());
+      if (fieldType == null) {
+        throw new ODataException("No field type found for property " + property);
+      }
+      return fieldType;
+    }
+    throw new ODataNotImplementedException(ODataNotImplementedException.COMMON);
+  }
+
+  /**
+   * Retrieves the value defined by a mapping object for the given data object.
+   * @param data the Java data object
+   * @param mapping the requested {@link EdmMapping}
+   * @return the requested value
+   */
+  @Override
+  public <T> Object getMappingValue(final T data, final EdmMapping mapping) throws ODataException {
+    if (mapping != null && mapping.getMediaResourceMimeTypeKey() != null) {
+      return annotationHelper.getValueForProperty(data, mapping.getMediaResourceMimeTypeKey());
+    }
+    return null;
+  }
+
+  /**
+   * Sets the value defined by a mapping object for the given data object.
+   * @param data the Java data object
+   * @param mapping the {@link EdmMapping}
+   * @param value the new value
+   */
+  @Override
+  public <T, V> void setMappingValue(final T data, final EdmMapping mapping, final V value) throws ODataException {
+    if (mapping != null && mapping.getMediaResourceMimeTypeKey() != null) {
+      annotationHelper.setValueForProperty(data, mapping.getMediaResourceMimeTypeKey(), value);
+    }
+  }
+}

http://git-wip-us.apache.org/repos/asf/incubator-olingo-odata2/blob/3bd59050/odata2-annotation-processor/annotation-processor-core/src/main/java/org/apache/olingo/odata2/annotation/processor/core/datasource/BeanPropertyAccess.java
----------------------------------------------------------------------
diff --git a/odata2-annotation-processor/annotation-processor-core/src/main/java/org/apache/olingo/odata2/annotation/processor/core/datasource/BeanPropertyAccess.java b/odata2-annotation-processor/annotation-processor-core/src/main/java/org/apache/olingo/odata2/annotation/processor/core/datasource/BeanPropertyAccess.java
new file mode 100644
index 0000000..290b99f
--- /dev/null
+++ b/odata2-annotation-processor/annotation-processor-core/src/main/java/org/apache/olingo/odata2/annotation/processor/core/datasource/BeanPropertyAccess.java
@@ -0,0 +1,185 @@
+/*******************************************************************************
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License. You may obtain a copy of the License at
+ * 
+ * http://www.apache.org/licenses/LICENSE-2.0
+ * 
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied. See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ ******************************************************************************/
+package org.apache.olingo.odata2.annotation.processor.core.datasource;
+
+import java.lang.reflect.InvocationTargetException;
+import java.lang.reflect.Method;
+import java.util.Arrays;
+
+import org.apache.olingo.odata2.api.edm.EdmException;
+import org.apache.olingo.odata2.api.edm.EdmMapping;
+import org.apache.olingo.odata2.api.edm.EdmProperty;
+import org.apache.olingo.odata2.api.edm.EdmSimpleTypeKind;
+import org.apache.olingo.odata2.api.exception.ODataException;
+import org.apache.olingo.odata2.api.exception.ODataHttpException;
+import org.apache.olingo.odata2.api.exception.ODataNotFoundException;
+
+/**
+ * Data access.
+ */
+public class BeanPropertyAccess implements ValueAccess {
+
+  @Override
+  public <T> Object getPropertyValue(final T data, final EdmProperty property) throws ODataException {
+    return getValue(data, getGetterMethodName(property));
+  }
+
+  @Override
+  public <T, V> void setPropertyValue(final T data, final EdmProperty property, final V value) throws ODataException {
+    final String methodName = getSetterMethodName(getGetterMethodName(property));
+    if (methodName != null) {
+      setValue(data, methodName, value);
+    }
+  }
+
+  @Override
+  public <T> Class<?> getPropertyType(final T data, final EdmProperty property) throws ODataException {
+    return getType(data, getGetterMethodName(property));
+  }
+
+  @Override
+  public <T> Object getMappingValue(final T data, final EdmMapping mapping) throws ODataException {
+    if (mapping != null && mapping.getMimeType() != null) {
+      return getValue(data, mapping.getMimeType());
+    }
+    return null;
+  }
+
+  @Override
+  public <T, V> void setMappingValue(final T data, final EdmMapping mapping, final V value) throws ODataException {
+    if (mapping != null && mapping.getMimeType() != null) {
+      setValue(data, getSetterMethodName(mapping.getMimeType()), value);
+    }
+  }
+
+  private String getGetterMethodName(final EdmProperty property) throws EdmException {
+    final String prefix = isBooleanProperty(property) ? "is" : "get";
+    final String defaultMethodName = prefix + property.getName();
+    return property.getMapping() == null || property.getMapping().getInternalName() == null ?
+        defaultMethodName : property.getMapping().getInternalName();
+  }
+
+  private boolean isBooleanProperty(final EdmProperty property) throws EdmException {
+    return property.isSimple()
+        && property.getType() == EdmSimpleTypeKind.Boolean.getEdmSimpleTypeInstance();
+  }
+
+  private String getSetterMethodName(final String getterMethodName) {
+    return getterMethodName.contains(".") ?
+        null : getterMethodName.replaceFirst("^is", "set").replaceFirst("^get", "set");
+  }
+
+  private <T> Object getValue(final T data, final String methodName) throws ODataNotFoundException {
+    Object dataObject = data;
+
+    for (final String method : methodName.split("\\.", -1)) {
+      if (dataObject != null) {
+        try {
+          dataObject = dataObject.getClass().getMethod(method).invoke(dataObject);
+        } catch (SecurityException e) {
+          throw new ODataNotFoundException(ODataHttpException.COMMON, e);
+        } catch (NoSuchMethodException e) {
+          throw new ODataNotFoundException(ODataHttpException.COMMON, e);
+        } catch (IllegalArgumentException e) {
+          throw new ODataNotFoundException(ODataHttpException.COMMON, e);
+        } catch (IllegalAccessException e) {
+          throw new ODataNotFoundException(ODataHttpException.COMMON, e);
+        } catch (InvocationTargetException e) {
+          throw new ODataNotFoundException(ODataHttpException.COMMON, e);
+        }
+      }
+    }
+
+    return dataObject;
+  }
+
+  private <T, V> void setValue(final T data, final String methodName, final V value)
+      throws ODataNotFoundException {
+    try {
+      boolean found = false;
+      for (final Method method : Arrays.asList(data.getClass().getMethods())) {
+        if (method.getName().equals(methodName)) {
+          found = true;
+          final Class<?> type = method.getParameterTypes()[0];
+          if (value == null) {
+            if (type.equals(byte.class) || type.equals(short.class) || type.equals(int.class)
+                || type.equals(long.class) || type.equals(char.class)) {
+              method.invoke(data, 0);
+            } else if (type.equals(float.class) || type.equals(double.class)) {
+              method.invoke(data, 0.0);
+            } else if (type.equals(boolean.class)) {
+              method.invoke(data, false);
+            } else {
+              method.invoke(data, value);
+            }
+          } else {
+            method.invoke(data, value);
+          }
+          break;
+        }
+      }
+      if (!found) {
+        throw new ODataNotFoundException(null);
+      }
+    } catch (SecurityException e) {
+      throw new ODataNotFoundException(null, e);
+    } catch (IllegalArgumentException e) {
+      throw new ODataNotFoundException(null, e);
+    } catch (IllegalAccessException e) {
+      throw new ODataNotFoundException(null, e);
+    } catch (InvocationTargetException e) {
+      throw new ODataNotFoundException(null, e);
+    }
+  }
+
+  private <T> Class<?> getType(final T data, final String methodName) throws ODataNotFoundException {
+    if (data == null) {
+      throw new ODataNotFoundException(ODataHttpException.COMMON);
+    }
+
+    Class<?> type = data.getClass();
+    for (final String method : methodName.split("\\.", -1)) {
+      try {
+        type = type.getMethod(method).getReturnType();
+        if (type.isPrimitive()) {
+          if (type == boolean.class) {
+            type = Boolean.class;
+          } else if (type == byte.class) {
+            type = Byte.class;
+          } else if (type == short.class) {
+            type = Short.class;
+          } else if (type == int.class) {
+            type = Integer.class;
+          } else if (type == long.class) {
+            type = Long.class;
+          } else if (type == float.class) {
+            type = Float.class;
+          } else if (type == double.class) {
+            type = Double.class;
+          }
+        }
+      } catch (final SecurityException e) {
+        throw new ODataNotFoundException(ODataHttpException.COMMON, e);
+      } catch (final NoSuchMethodException e) {
+        throw new ODataNotFoundException(ODataHttpException.COMMON, e);
+      }
+    }
+    return type;
+  }
+}

http://git-wip-us.apache.org/repos/asf/incubator-olingo-odata2/blob/3bd59050/odata2-annotation-processor/annotation-processor-core/src/main/java/org/apache/olingo/odata2/annotation/processor/core/datasource/DataSource.java
----------------------------------------------------------------------
diff --git a/odata2-annotation-processor/annotation-processor-core/src/main/java/org/apache/olingo/odata2/annotation/processor/core/datasource/DataSource.java b/odata2-annotation-processor/annotation-processor-core/src/main/java/org/apache/olingo/odata2/annotation/processor/core/datasource/DataSource.java
new file mode 100644
index 0000000..e23f5f3
--- /dev/null
+++ b/odata2-annotation-processor/annotation-processor-core/src/main/java/org/apache/olingo/odata2/annotation/processor/core/datasource/DataSource.java
@@ -0,0 +1,200 @@
+/*******************************************************************************
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License. You may obtain a copy of the License at
+ * 
+ * http://www.apache.org/licenses/LICENSE-2.0
+ * 
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied. See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ ******************************************************************************/
+package org.apache.olingo.odata2.annotation.processor.core.datasource;
+
+import java.util.Arrays;
+import java.util.List;
+import java.util.Map;
+
+import org.apache.olingo.odata2.api.edm.EdmEntitySet;
+import org.apache.olingo.odata2.api.edm.EdmException;
+import org.apache.olingo.odata2.api.edm.EdmFunctionImport;
+import org.apache.olingo.odata2.api.exception.ODataApplicationException;
+import org.apache.olingo.odata2.api.exception.ODataNotFoundException;
+import org.apache.olingo.odata2.api.exception.ODataNotImplementedException;
+
+/**
+ * <p>This interface is intended to make it easier to implement an OData
+ * service in cases where all data for each entity set can be provided as a {@link List} of objects from which all
+ * properties described in the
+ * Entity Data Model can be retrieved and set.</p>
+ * <p>By obeying these restrictions, data-source implementations get the
+ * following advantages:
+ * <ul>
+ * <li>All system query options can be handled centrally.</li>
+ * <li>Following navigation paths must only be done step by step.</li>
+ * </ul>
+ * </p>
+ * 
+ */
+public interface DataSource {
+
+  /**
+   * Retrieves the whole data list for the specified entity set.
+   * @param entitySet the requested {@link EdmEntitySet}
+   * @return the requested data list
+   */
+  List<?> readData(EdmEntitySet entitySet) throws ODataNotImplementedException, ODataNotFoundException, EdmException,
+      ODataApplicationException;
+
+  /**
+   * Retrieves a single data object for the specified entity set and key.
+   * @param entitySet the requested {@link EdmEntitySet}
+   * @param keys the entity key as map of key names to key values
+   * @return the requested data object
+   */
+  Object readData(EdmEntitySet entitySet, Map<String, Object> keys) throws ODataNotImplementedException,
+      ODataNotFoundException, EdmException, ODataApplicationException;
+
+  /**
+   * <p>Retrieves data for the specified function import and key.</p>
+   * <p>This method is called also for function imports that have defined in
+   * their metadata an other HTTP method than <code>GET</code>.</p>
+   * @param function the requested {@link EdmFunctionImport}
+   * @param parameters the parameters of the function import
+   * as map of parameter names to parameter values
+   * @param keys the key of the returned entity set, as map of key names to key values,
+   * if the return type of the function import is a collection of entities
+   * (optional)
+   * @return the requested data object, either a list or a single object;
+   * if the function import's return type is of type <code>Binary</code>,
+   * the returned object(s) must be of type {@link BinaryData}
+   */
+  Object readData(EdmFunctionImport function, Map<String, Object> parameters, Map<String, Object> keys)
+      throws ODataNotImplementedException, ODataNotFoundException, EdmException, ODataApplicationException;
+
+  /**
+   * <p>Retrieves related data for the specified source data, entity set, and key.</p>
+   * <p>If the underlying association of the EDM is specified to have target
+   * multiplicity '*' and no target key is given, this method returns a list of
+   * related data, otherwise it returns a single data object.</p>
+   * @param sourceEntitySet the {@link EdmEntitySet} of the source entity
+   * @param sourceData the data object of the source entity
+   * @param targetEntitySet the requested target {@link EdmEntitySet}
+   * @param targetKeys the key of the target entity as map of key names to key values
+   * (optional)
+   * @return the requested releated data object, either a list or a single object
+   */
+  Object readRelatedData(EdmEntitySet sourceEntitySet, Object sourceData, EdmEntitySet targetEntitySet,
+      Map<String, Object> targetKeys) throws ODataNotImplementedException, ODataNotFoundException, EdmException,
+      ODataApplicationException;
+
+  /**
+   * Retrieves the binary data and the MIME type for the media resource
+   * associated to the specified media-link entry.
+   * @param entitySet the {@link EdmEntitySet} of the media-link entry
+   * @param mediaLinkEntryData the data object of the media-link entry
+   * @return the binary data and the MIME type of the media resource
+   */
+  BinaryData readBinaryData(EdmEntitySet entitySet, Object mediaLinkEntryData) throws ODataNotImplementedException,
+      ODataNotFoundException, EdmException, ODataApplicationException;
+
+  /**
+   * <p>Creates and returns a new instance of the requested data-object type.</p>
+   * <p>This instance must not be part of the corresponding list and should
+   * have empty content, apart from the key and other mandatory properties.
+   * However, intermediate objects to access complex properties must not be
+   * <code>null</code>.</p>
+   * @param entitySet the {@link EdmEntitySet} the object must correspond to
+   * @return the new data object
+   */
+  Object newDataObject(EdmEntitySet entitySet) throws ODataNotImplementedException, EdmException,
+      ODataApplicationException;
+
+  /**
+   * Writes the binary data for the media resource associated to the
+   * specified media-link entry.
+   * @param entitySet the {@link EdmEntitySet} of the media-link entry
+   * @param mediaLinkEntryData the data object of the media-link entry
+   * @param binaryData the binary data of the media resource along with
+   * the MIME type of the binary data
+   */
+  void writeBinaryData(EdmEntitySet entitySet, Object mediaLinkEntryData, BinaryData binaryData)
+      throws ODataNotImplementedException, ODataNotFoundException, EdmException, ODataApplicationException;
+
+  /**
+   * Deletes a single data object identified by the specified entity set and key.
+   * @param entitySet the {@link EdmEntitySet} of the entity to be deleted
+   * @param keys the entity key as map of key names to key values
+   */
+  void deleteData(EdmEntitySet entitySet, Map<String, Object> keys) throws ODataNotImplementedException,
+      ODataNotFoundException, EdmException, ODataApplicationException;
+
+  /**
+   * <p>Inserts an instance into the entity list of the specified entity set.</p>
+   * <p>If {@link #newDataObject} has not set the key and other mandatory
+   * properties already, this method must set them before inserting the
+   * instance into the list.</p>
+   * @param entitySet the {@link EdmEntitySet} the object must correspond to
+   * @param data the data object of the new entity
+   */
+  void createData(EdmEntitySet entitySet, Object data) throws ODataNotImplementedException, EdmException,
+      ODataApplicationException;
+
+  /**
+   * Deletes the relation from the specified source data to a target entity
+   * specified by entity set and key.
+   * @param sourceEntitySet the {@link EdmEntitySet} of the source entity
+   * @param sourceData the data object of the source entity
+   * @param targetEntitySet the {@link EdmEntitySet} of the target entity
+   * @param targetKeys the key of the target entity as map of key names to key values
+   * (optional)
+   */
+  void deleteRelation(EdmEntitySet sourceEntitySet, Object sourceData, EdmEntitySet targetEntitySet,
+      Map<String, Object> targetKeys) throws ODataNotImplementedException, ODataNotFoundException, EdmException,
+      ODataApplicationException;
+
+  /**
+   * Writes a relation from the specified source data to a target entity
+   * specified by entity set and key.
+   * @param sourceEntitySet the {@link EdmEntitySet} of the source entity
+   * @param sourceData the data object of the source entity
+   * @param targetEntitySet the {@link EdmEntitySet} of the relation target
+   * @param targetKeys the key of the target entity as map of key names to key values
+   */
+  void writeRelation(EdmEntitySet sourceEntitySet, Object sourceData, EdmEntitySet targetEntitySet,
+      Map<String, Object> targetKeys) throws ODataNotImplementedException, ODataNotFoundException, EdmException,
+      ODataApplicationException;
+
+  /**
+   * Container to store binary data (as byte array) and the associated MIME type.
+   */
+  public class BinaryData {
+    private final byte[] data;
+    private final String mimeType;
+
+    public BinaryData(final byte[] data, final String mimeType) {
+      this.data = data;
+      this.mimeType = mimeType;
+    }
+
+    public byte[] getData() {
+      return data;
+    }
+
+    public String getMimeType() {
+      return mimeType;
+    }
+
+    @Override
+    public String toString() {
+      return "data=" + Arrays.toString(data) + ", mimeType=" + mimeType;
+    }
+  }
+}

http://git-wip-us.apache.org/repos/asf/incubator-olingo-odata2/blob/3bd59050/odata2-annotation-processor/annotation-processor-core/src/main/java/org/apache/olingo/odata2/annotation/processor/core/datasource/DataStore.java
----------------------------------------------------------------------
diff --git a/odata2-annotation-processor/annotation-processor-core/src/main/java/org/apache/olingo/odata2/annotation/processor/core/datasource/DataStore.java b/odata2-annotation-processor/annotation-processor-core/src/main/java/org/apache/olingo/odata2/annotation/processor/core/datasource/DataStore.java
new file mode 100644
index 0000000..57b3d8c
--- /dev/null
+++ b/odata2-annotation-processor/annotation-processor-core/src/main/java/org/apache/olingo/odata2/annotation/processor/core/datasource/DataStore.java
@@ -0,0 +1,294 @@
+/*******************************************************************************
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License. You may obtain a copy of the License at
+ * 
+ * http://www.apache.org/licenses/LICENSE-2.0
+ * 
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied. See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ ******************************************************************************/
+package org.apache.olingo.odata2.annotation.processor.core.datasource;
+
+import java.lang.reflect.Field;
+import java.util.ArrayList;
+import java.util.Collection;
+import java.util.Collections;
+import java.util.HashMap;
+import java.util.List;
+import java.util.Locale;
+import java.util.Map;
+import java.util.concurrent.atomic.AtomicInteger;
+
+import org.apache.olingo.odata2.annotation.processor.core.util.AnnotationHelper;
+import org.apache.olingo.odata2.annotation.processor.core.util.ClassHelper;
+import org.apache.olingo.odata2.api.annotation.edm.EdmKey;
+import org.apache.olingo.odata2.api.exception.ODataApplicationException;
+import org.apache.olingo.odata2.core.exception.ODataRuntimeException;
+
+/**
+ *
+ */
+public class DataStore<T> {
+
+  private static final AnnotationHelper ANNOTATION_HELPER = new AnnotationHelper();
+  private final Map<KeyElement, T> dataStore;
+  private final Class<T> dataTypeClass;
+  private final KeyAccess keyAccess;
+
+  private static class InMemoryDataStore {
+    private static final Map<Class<?>, DataStore<?>> c2ds = new HashMap<Class<?>, DataStore<?>>();
+
+    @SuppressWarnings("unchecked")
+    static synchronized DataStore<?> getInstance(final Class<?> clz, final boolean createNewInstance)
+        throws DataStoreException {
+      DataStore<?> ds = c2ds.get(clz);
+      if (createNewInstance || ds == null) {
+        ds = new DataStore<Object>((Class<Object>) clz);
+        c2ds.put(clz, ds);
+      }
+      return ds;
+    }
+  }
+
+  @SuppressWarnings("unchecked")
+  public static <T> DataStore<T> createInMemory(final Class<T> clazz) throws DataStoreException {
+    return (DataStore<T>) InMemoryDataStore.getInstance(clazz, true);
+  }
+
+  @SuppressWarnings("unchecked")
+  public static <T> DataStore<T> createInMemory(final Class<T> clazz, final boolean keepExisting)
+      throws DataStoreException {
+    return (DataStore<T>) InMemoryDataStore.getInstance(clazz, !keepExisting);
+  }
+
+  private DataStore(final Map<KeyElement, T> wrapStore, final Class<T> clz) throws DataStoreException {
+    dataStore = Collections.synchronizedMap(wrapStore);
+    dataTypeClass = clz;
+    keyAccess = new KeyAccess(clz);
+  }
+
+  private DataStore(final Class<T> clz) throws DataStoreException {
+    this(new HashMap<KeyElement, T>(), clz);
+  }
+
+  public Class<T> getDataTypeClass() {
+    return dataTypeClass;
+  }
+
+  public String getEntityTypeName() {
+    return ANNOTATION_HELPER.extractEntityTypeName(dataTypeClass);
+  }
+
+  public T createInstance() {
+    try {
+      return dataTypeClass.newInstance();
+    } catch (InstantiationException e) {
+      throw new ODataRuntimeException("Unable to create instance of class '" + dataTypeClass + "'.", e);
+    } catch (IllegalAccessException e) {
+      throw new ODataRuntimeException("Unable to create instance of class '" + dataTypeClass + "'.", e);
+    }
+  }
+
+  public T read(final T obj) {
+    KeyElement objKeys = getKeys(obj);
+    return dataStore.get(objKeys);
+  }
+
+  public Collection<T> read() {
+    return Collections.unmodifiableCollection(dataStore.values());
+  }
+
+  public T create(final T object) throws DataStoreException {
+    KeyElement keyElement = getKeys(object);
+    return create(object, keyElement);
+  }
+
+  private T create(final T object, final KeyElement keyElement) throws DataStoreException {
+    synchronized (dataStore) {
+      if (keyElement.keyValuesMissing() || dataStore.containsKey(keyElement)) {
+        KeyElement newKey = createSetAndGetKeys(object);
+        return this.create(object, newKey);
+      }
+      dataStore.put(keyElement, object);
+    }
+    return object;
+  }
+
+  public T update(final T object) {
+    KeyElement keyElement = getKeys(object);
+    synchronized (dataStore) {
+      dataStore.remove(keyElement);
+      dataStore.put(keyElement, object);
+    }
+    return object;
+  }
+
+  public T delete(final T object) {
+    KeyElement keyElement = getKeys(object);
+    synchronized (dataStore) {
+      return dataStore.remove(keyElement);
+    }
+  }
+  
+  /**
+   * Are the key values equal for both instances.
+   * If all compared key values are <code>null</code> this also means equal.
+   * 
+   * @param first first instance to check for key equal
+   * @param second second instance to check for key equal
+   * @return <code>true</code> if object instance have equal keys set.
+   */
+  public boolean isKeyEqual(final T first, final T second) {
+    KeyElement firstKeys = getKeys(first);
+    KeyElement secondKeys = getKeys(second);
+    
+    return firstKeys.equals(secondKeys);
+  }
+  
+  /**
+   * Are the key values equal for both instances.
+   * If all compared key values are <code>null</code> this also means equal.
+   * Before object (keys) are compared it is validated that both object instance are NOT null
+   * and that both are from the same class as this {@link DataStore} (see {@link #dataTypeClass}).
+   * For the equal check on {@link #dataTypeClass} instances without validation see
+   * {@link #isKeyEqual(Object, Object)}.
+   * 
+   * @param first first instance to check for key equal
+   * @param second second instance to check for key equal
+   * @return <code>true</code> if object instance have equal keys set.
+   */
+  @SuppressWarnings("unchecked")
+  public boolean isKeyEqualChecked(Object first, Object second) throws DataStoreException {
+    if(first == null || second == null) {
+      throw new DataStoreException("Tried to compare null values which is not allowed.");
+    } else if(first.getClass() != dataTypeClass) {
+      throw new DataStoreException("First value is no instance from required class '" + dataTypeClass + "'.");
+    } else if(second.getClass() != dataTypeClass) {
+      throw new DataStoreException("Second value is no instance from required class '" + dataTypeClass + "'.");
+    }
+    
+    return isKeyEqual((T) first, (T) second);
+  }
+
+
+  private class KeyElement {
+    private int cachedHashCode = 42;
+    private final List<Object> keyValues;
+
+    public KeyElement(final int size) {
+      keyValues = new ArrayList<Object>(size);
+    }
+
+    private void addValue(final Object keyValue) {
+      keyValues.add(keyValue);
+      cachedHashCode = 89 * cachedHashCode + (keyValue != null ? keyValue.hashCode() : 0);
+    }
+
+    boolean keyValuesMissing() {
+      return keyValues.contains(null);
+    }
+
+    @Override
+    public int hashCode() {
+      return cachedHashCode;
+    }
+
+    @Override
+    public boolean equals(final Object obj) {
+      if (obj == null) {
+        return false;
+      }
+      if (getClass() != obj.getClass()) {
+        return false;
+      }
+      @SuppressWarnings("unchecked")
+      final KeyElement other = (KeyElement) obj;
+      if (this.keyValues != other.keyValues && (this.keyValues == null || !this.keyValues.equals(other.keyValues))) {
+        return false;
+      }
+      return true;
+    }
+
+    @Override
+    public String toString() {
+      return "KeyElement{" + "cachedHashCode=" + cachedHashCode + ", keyValues=" + keyValues + '}';
+    }
+  }
+
+  private class KeyAccess {
+    final List<Field> keyFields;
+    final AtomicInteger idCounter = new AtomicInteger(1);
+
+    KeyAccess(final Class<?> clazz) throws DataStoreException {
+      keyFields = ANNOTATION_HELPER.getAnnotatedFields(clazz, EdmKey.class);
+      if (keyFields.isEmpty()) {
+        throw new DataStoreException("No EdmKey annotated fields found for class " + clazz);
+      }
+    }
+
+    KeyElement getKeyValues(final T object) {
+      KeyElement keyElement = new KeyElement(keyFields.size());
+      for (Field field : keyFields) {
+        Object keyValue = ClassHelper.getFieldValue(object, field);
+        keyElement.addValue(keyValue);
+      }
+
+      return keyElement;
+    }
+
+    KeyElement createSetAndGetKeys(final T object) throws DataStoreException {
+      KeyElement keyElement = new KeyElement(keyFields.size());
+      for (Field field : keyFields) {
+        Object key = createKey(field);
+        ClassHelper.setFieldValue(object, field, key);
+        keyElement.addValue(key);
+      }
+
+      return keyElement;
+    }
+
+    private Object createKey(final Field field) {
+      Class<?> type = field.getType();
+
+      if (type == String.class) {
+        return String.valueOf(idCounter.getAndIncrement());
+      } else if (type == Integer.class || type == int.class) {
+        return Integer.valueOf(idCounter.getAndIncrement());
+      } else if (type == Long.class || type == long.class) {
+        return Long.valueOf(idCounter.getAndIncrement());
+      }
+
+      throw new UnsupportedOperationException("Automated key generation for type '" + type
+          + "' is not supported (caused on field '" + field + "').");
+    }
+  }
+
+  private KeyElement getKeys(final T object) {
+    return keyAccess.getKeyValues(object);
+  }
+
+  private KeyElement createSetAndGetKeys(final T object) throws DataStoreException {
+    return keyAccess.createSetAndGetKeys(object);
+  }
+
+  public static class DataStoreException extends ODataApplicationException {
+    private static final long serialVersionUID = 42L;
+
+    public DataStoreException(final String message) {
+      this(message, null);
+    }
+
+    public DataStoreException(final String message, final Throwable cause) {
+      super(message, Locale.ENGLISH, cause);
+    }
+  }
+}

http://git-wip-us.apache.org/repos/asf/incubator-olingo-odata2/blob/3bd59050/odata2-annotation-processor/annotation-processor-core/src/main/java/org/apache/olingo/odata2/annotation/processor/core/datasource/ValueAccess.java
----------------------------------------------------------------------
diff --git a/odata2-annotation-processor/annotation-processor-core/src/main/java/org/apache/olingo/odata2/annotation/processor/core/datasource/ValueAccess.java b/odata2-annotation-processor/annotation-processor-core/src/main/java/org/apache/olingo/odata2/annotation/processor/core/datasource/ValueAccess.java
new file mode 100644
index 0000000..d91d65c
--- /dev/null
+++ b/odata2-annotation-processor/annotation-processor-core/src/main/java/org/apache/olingo/odata2/annotation/processor/core/datasource/ValueAccess.java
@@ -0,0 +1,69 @@
+/*******************************************************************************
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License. You may obtain a copy of the License at
+ * 
+ * http://www.apache.org/licenses/LICENSE-2.0
+ * 
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied. See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ ******************************************************************************/
+package org.apache.olingo.odata2.annotation.processor.core.datasource;
+
+import org.apache.olingo.odata2.api.edm.EdmMapping;
+import org.apache.olingo.odata2.api.edm.EdmProperty;
+import org.apache.olingo.odata2.api.exception.ODataException;
+
+/**
+ * This interface is intended to access values in a Java object.
+ */
+public interface ValueAccess {
+
+  /**
+   * Retrieves the value of an EDM property for the given data object.
+   * @param data the Java data object
+   * @param property the requested {@link EdmProperty}
+   * @return the requested property value
+   */
+  public <T> Object getPropertyValue(final T data, final EdmProperty property) throws ODataException;
+
+  /**
+   * Sets the value of an EDM property for the given data object.
+   * @param data the Java data object
+   * @param property the {@link EdmProperty}
+   * @param value the new value of the property
+   */
+  public <T, V> void setPropertyValue(T data, final EdmProperty property, final V value) throws ODataException;
+
+  /**
+   * Retrieves the Java type of an EDM property for the given data object.
+   * @param data the Java data object
+   * @param property the requested {@link EdmProperty}
+   * @return the requested Java type
+   */
+  public <T> Class<?> getPropertyType(final T data, final EdmProperty property) throws ODataException;
+
+  /**
+   * Retrieves the value defined by a mapping object for the given data object.
+   * @param data the Java data object
+   * @param mapping the requested {@link EdmMapping}
+   * @return the requested value
+   */
+  public <T> Object getMappingValue(final T data, final EdmMapping mapping) throws ODataException;
+
+  /**
+   * Sets the value defined by a mapping object for the given data object.
+   * @param data the Java data object
+   * @param mapping the {@link EdmMapping}
+   * @param value the new value
+   */
+  public <T, V> void setMappingValue(T data, final EdmMapping mapping, final V value) throws ODataException;
+}

http://git-wip-us.apache.org/repos/asf/incubator-olingo-odata2/blob/3bd59050/odata2-annotation-processor/annotation-processor-core/src/main/java/org/apache/olingo/odata2/annotation/processor/core/edm/AnnotationEdmProvider.java
----------------------------------------------------------------------
diff --git a/odata2-annotation-processor/annotation-processor-core/src/main/java/org/apache/olingo/odata2/annotation/processor/core/edm/AnnotationEdmProvider.java b/odata2-annotation-processor/annotation-processor-core/src/main/java/org/apache/olingo/odata2/annotation/processor/core/edm/AnnotationEdmProvider.java
new file mode 100644
index 0000000..7247e5c
--- /dev/null
+++ b/odata2-annotation-processor/annotation-processor-core/src/main/java/org/apache/olingo/odata2/annotation/processor/core/edm/AnnotationEdmProvider.java
@@ -0,0 +1,769 @@
+/*******************************************************************************
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License. You may obtain a copy of the License at
+ * 
+ * http://www.apache.org/licenses/LICENSE-2.0
+ * 
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied. See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ ******************************************************************************/
+package org.apache.olingo.odata2.annotation.processor.core.edm;
+
+import java.lang.reflect.Field;
+import java.lang.reflect.Modifier;
+import java.math.BigDecimal;
+import java.math.BigInteger;
+import java.util.ArrayList;
+import java.util.Calendar;
+import java.util.Collection;
+import java.util.Collections;
+import java.util.Date;
+import java.util.HashMap;
+import java.util.List;
+import java.util.Map;
+import java.util.UUID;
+
+import org.apache.olingo.odata2.annotation.processor.core.util.AnnotationHelper;
+import org.apache.olingo.odata2.annotation.processor.core.util.ClassHelper;
+import org.apache.olingo.odata2.api.annotation.edm.EdmComplexType;
+import org.apache.olingo.odata2.api.annotation.edm.EdmEntitySet;
+import org.apache.olingo.odata2.api.annotation.edm.EdmEntityType;
+import org.apache.olingo.odata2.api.annotation.edm.EdmKey;
+import org.apache.olingo.odata2.api.annotation.edm.EdmMediaResourceContent;
+import org.apache.olingo.odata2.api.annotation.edm.EdmNavigationProperty;
+import org.apache.olingo.odata2.api.annotation.edm.EdmProperty;
+import org.apache.olingo.odata2.api.annotation.edm.EdmType;
+import org.apache.olingo.odata2.api.edm.EdmMultiplicity;
+import org.apache.olingo.odata2.api.edm.FullQualifiedName;
+import org.apache.olingo.odata2.api.edm.provider.AnnotationAttribute;
+import org.apache.olingo.odata2.api.edm.provider.AnnotationElement;
+import org.apache.olingo.odata2.api.edm.provider.Association;
+import org.apache.olingo.odata2.api.edm.provider.AssociationEnd;
+import org.apache.olingo.odata2.api.edm.provider.AssociationSet;
+import org.apache.olingo.odata2.api.edm.provider.AssociationSetEnd;
+import org.apache.olingo.odata2.api.edm.provider.ComplexProperty;
+import org.apache.olingo.odata2.api.edm.provider.ComplexType;
+import org.apache.olingo.odata2.api.edm.provider.EdmProvider;
+import org.apache.olingo.odata2.api.edm.provider.EntityContainer;
+import org.apache.olingo.odata2.api.edm.provider.EntityContainerInfo;
+import org.apache.olingo.odata2.api.edm.provider.EntitySet;
+import org.apache.olingo.odata2.api.edm.provider.EntityType;
+import org.apache.olingo.odata2.api.edm.provider.FunctionImport;
+import org.apache.olingo.odata2.api.edm.provider.Key;
+import org.apache.olingo.odata2.api.edm.provider.NavigationProperty;
+import org.apache.olingo.odata2.api.edm.provider.Property;
+import org.apache.olingo.odata2.api.edm.provider.PropertyRef;
+import org.apache.olingo.odata2.api.edm.provider.Schema;
+import org.apache.olingo.odata2.api.edm.provider.SimpleProperty;
+import org.apache.olingo.odata2.api.edm.provider.Using;
+import org.apache.olingo.odata2.api.exception.ODataException;
+import org.apache.olingo.odata2.core.exception.ODataRuntimeException;
+
+/**
+ * Provider for the entity data model used in the reference scenario
+ * 
+ */
+public class AnnotationEdmProvider extends EdmProvider {
+
+  private static final AnnotationHelper ANNOTATION_HELPER = new AnnotationHelper();
+
+  private final List<Class<?>> annotatedClasses;
+  private final Map<String, EntityContainer> name2Container = new HashMap<String, EntityContainer>();
+  private final Map<String, ContainerBuilder> containerName2ContainerBuilder = new HashMap<String, ContainerBuilder>();
+  private final Map<String, Schema> namespace2Schema = new HashMap<String, Schema>();
+  private EntityContainer defaultContainer;
+
+  public AnnotationEdmProvider(final Collection<Class<?>> annotatedClasses) {
+
+    this.annotatedClasses = new ArrayList<Class<?>>(annotatedClasses.size());
+    for (Class<?> aClass : annotatedClasses) {
+      if (ANNOTATION_HELPER.isEdmAnnotated(aClass)) {
+        this.annotatedClasses.add(aClass);
+      }
+    }
+
+    init();
+  }
+
+  public AnnotationEdmProvider(final String packageToScan) {
+    annotatedClasses = ClassHelper.loadClasses(packageToScan, new ClassHelper.ClassValidator() {
+      @Override
+      public boolean isClassValid(final Class<?> c) {
+        return ANNOTATION_HELPER.isEdmAnnotated(c);
+      }
+    });
+
+    init();
+  }
+
+  private void init() {
+    for (Class<?> aClass : annotatedClasses) {
+      updateSchema(aClass);
+      handleEntityContainer(aClass);
+    }
+
+    finish();
+  }
+
+  @Override
+  public Association getAssociation(final FullQualifiedName edmFQName) throws ODataException {
+    Schema schema = namespace2Schema.get(edmFQName.getNamespace());
+    if (schema != null) {
+      List<Association> associations = schema.getAssociations();
+      for (Association association : associations) {
+        if (association.getName().equals(edmFQName.getName())) {
+          return association;
+        }
+      }
+    }
+    return null;
+  }
+
+  @Override
+  public AssociationSet getAssociationSet(final String entityContainer, final FullQualifiedName association,
+      final String sourceEntitySetName, final String sourceEntitySetRole) throws ODataException {
+    EntityContainer container = name2Container.get(entityContainer);
+    if (container != null) {
+      List<AssociationSet> associations = container.getAssociationSets();
+      for (AssociationSet associationSet : associations) {
+        if (associationSet.getAssociation().equals(association)) {
+          final AssociationSetEnd endOne = associationSet.getEnd1();
+          if (endOne.getRole().equals(sourceEntitySetRole)
+              && endOne.getEntitySet().equals(sourceEntitySetName)) {
+            return associationSet;
+          }
+          final AssociationSetEnd endTwo = associationSet.getEnd2();
+          if (endTwo.getRole().equals(sourceEntitySetRole)
+              && endTwo.getEntitySet().equals(sourceEntitySetName)) {
+            return associationSet;
+          }
+        }
+      }
+    }
+    return null;
+  }
+
+  @Override
+  public ComplexType getComplexType(final FullQualifiedName edmFQName) throws ODataException {
+    Schema schema = namespace2Schema.get(edmFQName.getNamespace());
+    if (schema != null) {
+      List<ComplexType> complexTypes = schema.getComplexTypes();
+      for (ComplexType complexType : complexTypes) {
+        if (complexType.getName().equals(edmFQName.getName())) {
+          return complexType;
+        }
+      }
+    }
+    return null;
+  }
+
+  @Override
+  public EntityContainerInfo getEntityContainerInfo(final String name) throws ODataException {
+    EntityContainer container = name2Container.get(name);
+    if (container == null) {
+      // use default container (if set)
+      container = defaultContainer;
+    }
+    if (container != null) {
+      EntityContainerInfo info = new EntityContainerInfo();
+      info.setName(container.getName());
+      info.setDefaultEntityContainer(container.isDefaultEntityContainer());
+      info.setExtendz(container.getExtendz());
+      info.setAnnotationAttributes(container.getAnnotationAttributes());
+      info.setAnnotationElements(container.getAnnotationElements());
+
+      return info;
+    }
+
+    return null;
+  }
+
+  @Override
+  public EntitySet getEntitySet(final String entityContainer, final String name) throws ODataException {
+    EntityContainer container = name2Container.get(entityContainer);
+    if (container != null) {
+      List<EntitySet> entitySets = container.getEntitySets();
+      for (EntitySet entitySet : entitySets) {
+        if (entitySet.getName().equals(name)) {
+          return entitySet;
+        }
+      }
+    }
+
+    return null;
+  }
+
+  @Override
+  public EntityType getEntityType(final FullQualifiedName edmFQName) throws ODataException {
+    Schema schema = namespace2Schema.get(edmFQName.getNamespace());
+    if (schema != null) {
+      List<EntityType> complexTypes = schema.getEntityTypes();
+      for (EntityType complexType : complexTypes) {
+        if (complexType.getName().equals(edmFQName.getName())) {
+          return complexType;
+        }
+      }
+    }
+    return null;
+  }
+
+  @Override
+  public FunctionImport getFunctionImport(final String entityContainer, final String name) throws ODataException {
+    EntityContainer container = name2Container.get(entityContainer);
+    if (container != null) {
+      List<FunctionImport> functionImports = container.getFunctionImports();
+      for (FunctionImport functionImport : functionImports) {
+        if (functionImport.getName().equals(name)) {
+          return functionImport;
+        }
+      }
+    }
+    return null;
+  }
+
+  @Override
+  public List<Schema> getSchemas() throws ODataException {
+    return new ArrayList<Schema>(namespace2Schema.values());
+  }
+
+  //
+  //
+  //
+  private Map<String, SchemaBuilder> namespace2SchemaBuilder = new HashMap<String, SchemaBuilder>();
+
+  private void updateSchema(final Class<?> aClass) {
+    EdmEntityType et = aClass.getAnnotation(EdmEntityType.class);
+    if (et != null) {
+      updateSchema(aClass, et);
+    }
+    EdmComplexType ect = aClass.getAnnotation(EdmComplexType.class);
+    if (ect != null) {
+      updateSchema(aClass, ect);
+    }
+  }
+
+  private void updateSchema(final Class<?> aClass, final EdmEntityType et) {
+    SchemaBuilder b = getSchemaBuilder(et.namespace(), aClass);
+    TypeBuilder typeBuilder = TypeBuilder.init(et, aClass);
+    b.addEntityType(typeBuilder.buildEntityType());
+    b.addAssociations(typeBuilder.buildAssociations());
+  }
+
+  private SchemaBuilder getSchemaBuilder(final String namespace, final Class<?> aClass) {
+    String usedNamespace = namespace;
+    if (usedNamespace.isEmpty()) {
+      usedNamespace = ANNOTATION_HELPER.getCanonicalNamespace(aClass);
+    }
+    SchemaBuilder builder = namespace2SchemaBuilder.get(usedNamespace);
+    if (builder == null) {
+      builder = SchemaBuilder.init(usedNamespace);
+      namespace2SchemaBuilder.put(usedNamespace, builder);
+    }
+    return builder;
+  }
+
+  private void updateSchema(final Class<?> aClass, final EdmComplexType et) {
+    SchemaBuilder b = getSchemaBuilder(et.namespace(), aClass);
+    TypeBuilder typeBuilder = TypeBuilder.init(et, aClass);
+    b.addComplexType(typeBuilder.buildComplexType());
+  }
+
+  private void handleEntityContainer(final Class<?> aClass) {
+    EdmEntityType entityType = aClass.getAnnotation(EdmEntityType.class);
+    if (entityType != null) {
+      FullQualifiedName typeName = createFqnForEntityType(aClass, entityType);
+      String containerName = ANNOTATION_HELPER.extractContainerName(aClass);
+      ContainerBuilder builder = containerName2ContainerBuilder.get(containerName);
+      if (builder == null) {
+        builder = ContainerBuilder.init(typeName.getNamespace(), containerName);
+        containerName2ContainerBuilder.put(containerName, builder);
+      }
+      EdmEntitySet entitySet = aClass.getAnnotation(EdmEntitySet.class);
+      if (entitySet != null) {
+        builder.addEntitySet(createEntitySet(typeName, aClass));
+      }
+    }
+  }
+
+  private EntitySet createEntitySet(final FullQualifiedName typeName, final Class<?> entitySetClass) {
+    String entitySetName = ANNOTATION_HELPER.extractEntitySetName(entitySetClass);
+    return new EntitySet().setName(entitySetName).setEntityType(typeName);
+  }
+
+  private FullQualifiedName createFqnForEntityType(final Class<?> annotatedClass, final EdmEntityType entityType) {
+    return ANNOTATION_HELPER.extractEntityTypeFqn(annotatedClass);
+  }
+
+  private void finish() {
+    //
+    Collection<ContainerBuilder> containers = containerName2ContainerBuilder.values();
+    for (ContainerBuilder containerBuilder : containers) {
+      SchemaBuilder schemaBuilder = namespace2SchemaBuilder.get(containerBuilder.getNamespace());
+      containerBuilder.addAssociationSets(schemaBuilder.name2Associations.values());
+      final EntityContainer container = containerBuilder.build();
+      schemaBuilder.addEntityContainer(container);
+      name2Container.put(container.getName(), container);
+      if (container.isDefaultEntityContainer()) {
+        defaultContainer = container;
+      }
+    }
+    //
+    Collection<SchemaBuilder> schemaBuilders = namespace2SchemaBuilder.values();
+    for (SchemaBuilder schemaBuilder : schemaBuilders) {
+      final Schema schema = schemaBuilder.build();
+      namespace2Schema.put(schema.getNamespace(), schema);
+    }
+  }
+
+  //
+  //
+  //
+  static class TypeBuilder {
+
+    final private String namespace;
+    final private String name;
+    private boolean isAbstract = false;
+    private boolean isMediaResource = false;
+    private FullQualifiedName baseEntityType = null;
+    private final List<PropertyRef> keyProperties = new ArrayList<PropertyRef>();
+    private final List<Property> properties = new ArrayList<Property>();
+    private final List<NavigationProperty> navProperties = new ArrayList<NavigationProperty>();
+    private final List<Association> associations = new ArrayList<Association>();
+
+    public TypeBuilder(final FullQualifiedName fqn) {
+      namespace = fqn.getNamespace();
+      name = fqn.getName();
+    }
+
+    public static TypeBuilder init(final EdmEntityType entity, final Class<?> aClass) {
+      return new TypeBuilder(ANNOTATION_HELPER.extractEntityTypeFqn(entity, aClass)).withClass(aClass);
+    }
+
+    public static TypeBuilder init(final EdmComplexType entity, final Class<?> aClass) {
+      return new TypeBuilder(ANNOTATION_HELPER.extractComplexTypeFqn(entity, aClass)).withClass(aClass);
+    }
+
+    private TypeBuilder withClass(final Class<?> aClass) {
+      baseEntityType = createBaseEntityFqn(aClass);
+
+      if (Modifier.isAbstract(aClass.getModifiers())) {
+        isAbstract = true;
+      }
+
+      Field[] fields = aClass.getDeclaredFields();
+      for (Field field : fields) {
+        EdmProperty ep = field.getAnnotation(EdmProperty.class);
+        if (ep != null) {
+          properties.add(createProperty(ep, field, namespace));
+          EdmKey eti = field.getAnnotation(EdmKey.class);
+          if (eti != null) {
+            keyProperties.add(createKeyProperty(ep, field));
+          }
+        }
+        EdmNavigationProperty enp = field.getAnnotation(EdmNavigationProperty.class);
+        if (enp != null) {
+          final NavigationProperty navProperty = createNavigationProperty(namespace, enp, field);
+          navProperties.add(navProperty);
+          Association association = createAssociation(field, navProperty);
+          associations.add(association);
+        }
+        EdmMediaResourceContent emrc = field.getAnnotation(EdmMediaResourceContent.class);
+        if (emrc != null) {
+          isMediaResource = true;
+        }
+      }
+
+      return this;
+    }
+
+    public TypeBuilder addProperty(final PropertyRef property) {
+      keyProperties.add(property);
+      return this;
+    }
+
+    public TypeBuilder addProperty(final Property property) {
+      properties.add(property);
+      return this;
+    }
+
+    public TypeBuilder addNavigationProperty(final NavigationProperty property) {
+      navProperties.add(property);
+      return this;
+    }
+
+    public TypeBuilder setAbstract(final boolean isAbstract) {
+      this.isAbstract = isAbstract;
+      return this;
+    }
+
+    public ComplexType buildComplexType() {
+      ComplexType complexType = new ComplexType();
+      if (baseEntityType != null) {
+        complexType.setBaseType(baseEntityType);
+      }
+      return complexType.setName(name).setProperties(properties);
+    }
+
+    public EntityType buildEntityType() {
+      EntityType entityType = new EntityType();
+      if (baseEntityType != null) {
+        entityType.setBaseType(baseEntityType);
+      }
+      if (!keyProperties.isEmpty()) {
+        entityType.setKey(new Key().setKeys(keyProperties));
+      }
+      if (!navProperties.isEmpty()) {
+        entityType.setNavigationProperties(navProperties);
+      }
+      return entityType.setName(name)
+          .setAbstract(isAbstract)
+          .setHasStream(isMediaResource)
+          .setProperties(properties);
+    }
+
+    public Collection<Association> buildAssociations() {
+      return Collections.unmodifiableCollection(associations);
+    }
+
+    private PropertyRef createKeyProperty(final EdmProperty et, final Field field) {
+      PropertyRef keyProperty = new PropertyRef();
+      String entityName = et.name();
+      if (entityName.isEmpty()) {
+        entityName = getCanonicalName(field);
+      }
+      return keyProperty.setName(entityName);
+    }
+
+    private Property createProperty(final EdmProperty ep, final Field field, final String defaultNamespace) {
+      if (isAnnotatedEntity(field.getType())) {
+        return createComplexProperty(field, defaultNamespace);
+      } else {
+        return createSimpleProperty(ep, field);
+      }
+    }
+
+    private Property createSimpleProperty(final EdmProperty ep, final Field field) {
+      SimpleProperty sp = new SimpleProperty();
+      String entityName = ANNOTATION_HELPER.getPropertyName(field);
+      sp.setName(entityName);
+      //
+      EdmType type = ep.type();
+      if (type == EdmType.NULL) {
+        type = getEdmType(field.getType());
+      }
+      sp.setType(ANNOTATION_HELPER.mapTypeKind(type));
+
+      return sp;
+    }
+
+    private Property createComplexProperty(final Field field, final String defaultNamespace) {
+      ComplexProperty cp = new ComplexProperty();
+      // settings from property
+      String entityName = ANNOTATION_HELPER.getPropertyName(field);
+      cp.setName(entityName);
+
+      // settings from related complex entity
+      EdmComplexType ece = field.getType().getAnnotation(EdmComplexType.class);
+      String complexEntityNamespace = ece.namespace();
+      if (complexEntityNamespace.isEmpty()) {
+        complexEntityNamespace = defaultNamespace;
+      }
+      cp.setType(new FullQualifiedName(complexEntityNamespace, ece.name()));
+
+      return cp;
+    }
+
+    private NavigationProperty createNavigationProperty(final String namespace, final EdmNavigationProperty enp,
+        final Field field) {
+      NavigationProperty navProp = new NavigationProperty();
+      navProp.setName(ANNOTATION_HELPER.getPropertyName(field));
+      String fromRole = ANNOTATION_HELPER.extractFromRoleName(enp, field);
+      navProp.setFromRole(fromRole);
+
+      String toRole = ANNOTATION_HELPER.extractToRoleName(enp, field);
+      navProp.setToRole(toRole);
+
+      String relationshipName = ANNOTATION_HELPER.extractRelationshipName(enp, field);
+      navProp.setRelationship(new FullQualifiedName(namespace, relationshipName));
+
+      return navProp;
+    }
+
+//    private EdmSimpleTypeKind getEdmSimpleType(Class<?> type) {
+//      if (type == String.class) {
+//        return EdmType.String;
+//      } else if (type == boolean.class || type == Boolean.class) {
+//        return EdmType.Boolean;
+//      } else if (type == byte.class || type == Byte.class) {
+//        return EdmType.SByte;
+//      } else if (type == short.class || type == Short.class) {
+//        return EdmType.Int16;
+//      } else if (type == int.class || type == Integer.class) {
+//        return EdmType.Int32;
+//      } else if (type == long.class || type == Long.class) {
+//        return EdmType.Int64;
+//      } else if (type == double.class || type == Double.class) {
+//        return EdmType.Double;
+//      } else if (type == float.class || type == Float.class) {
+//        return EdmType.Single;
+//      } else if (type == BigInteger.class || type == BigDecimal.class) {
+//        return EdmType.Decimal;
+//      } else if (type == Byte[].class || type == byte[].class) {
+//        return EdmType.Binary;
+//      } else if (type == Date.class) {
+//        return EdmType.DateTime;
+//      } else if (type == Calendar.class) {
+//        return EdmType.DateTimeOffset;
+//      } else if (type == UUID.class) {
+//        return EdmType.Guid;
+//      } else {
+//        throw new UnsupportedOperationException("Not yet supported type '" + type + "'.");
+//      }
+//    }
+
+    private EdmType getEdmType(final Class<?> type) {
+      if (type == String.class) {
+        return EdmType.STRING;
+      } else if (type == boolean.class || type == Boolean.class) {
+        return EdmType.BOOLEAN;
+      } else if (type == byte.class || type == Byte.class) {
+        return EdmType.SBYTE;
+      } else if (type == short.class || type == Short.class) {
+        return EdmType.INT16;
+      } else if (type == int.class || type == Integer.class) {
+        return EdmType.INT32;
+      } else if (type == long.class || type == Long.class) {
+        return EdmType.INT64;
+      } else if (type == double.class || type == Double.class) {
+        return EdmType.DOUBLE;
+      } else if (type == float.class || type == Float.class) {
+        return EdmType.SINGLE;
+      } else if (type == BigInteger.class || type == BigDecimal.class) {
+        return EdmType.DECIMAL;
+      } else if (type == Byte[].class || type == byte[].class) {
+        return EdmType.BINARY;
+      } else if (type == Date.class) {
+        return EdmType.DATE_TIME;
+      } else if (type == Calendar.class) {
+        return EdmType.DATE_TIME_OFFSET;
+      } else if (type == UUID.class) {
+        return EdmType.GUID;
+      } else {
+        throw new UnsupportedOperationException("Not yet supported type '" + type + "'.");
+      }
+    }
+
+    private Class<?> checkForBaseEntityClass(final Class<?> aClass) {
+      Class<?> superClass = aClass.getSuperclass();
+      if (superClass == Object.class) {
+        return null;
+      } else {
+        EdmEntityType edmEntity = superClass.getAnnotation(EdmEntityType.class);
+        if (edmEntity == null) {
+          return checkForBaseEntityClass(superClass);
+        } else {
+          return superClass;
+        }
+      }
+    }
+
+    private FullQualifiedName createBaseEntityFqn(final Class<?> aClass) {
+      Class<?> baseEntityClass = checkForBaseEntityClass(aClass);
+      if (baseEntityClass == null) {
+        return null;
+      }
+      return ANNOTATION_HELPER.extractEntityTypeFqn(baseEntityClass);
+    }
+
+    private Association createAssociation(final Field field, final NavigationProperty navProperty) {
+      Association association = new Association();
+      EdmNavigationProperty navigation = field.getAnnotation(EdmNavigationProperty.class);
+
+      AssociationEnd fromEnd = new AssociationEnd();
+      fromEnd.setRole(navProperty.getFromRole());
+      String typeName = ANNOTATION_HELPER.extractEntityTypeName(field.getDeclaringClass());
+      fromEnd.setType(new FullQualifiedName(namespace, typeName));
+      fromEnd.setMultiplicity(EdmMultiplicity.ONE);
+      association.setEnd1(fromEnd);
+
+      AssociationEnd toEnd = new AssociationEnd();
+      toEnd.setRole(navProperty.getToRole());
+      String toTypeName = ANNOTATION_HELPER.extractEntitTypeName(navigation, field);
+      toEnd.setType(new FullQualifiedName(namespace, toTypeName));
+      toEnd.setMultiplicity(ANNOTATION_HELPER.getMultiplicity(navigation, field));
+      association.setEnd2(toEnd);
+
+      String associationName = navProperty.getRelationship().getName();
+      association.setName(associationName);
+      return association;
+    }
+
+    private String getCanonicalName(final Field field) {
+      return ANNOTATION_HELPER.getCanonicalName(field);
+    }
+
+    private boolean isAnnotatedEntity(final Class<?> clazz) {
+      return ANNOTATION_HELPER.isEdmTypeAnnotated(clazz);
+    }
+  }
+
+  static class SchemaBuilder {
+
+    final private String namespace;
+    // private String alias;
+    private final List<Using> usings = new ArrayList<Using>();
+    private final List<EntityType> entityTypes = new ArrayList<EntityType>();
+    private final List<ComplexType> complexTypes = new ArrayList<ComplexType>();
+    private final Map<String, Association> name2Associations = new HashMap<String, Association>();
+    private final List<EntityContainer> entityContainers = new ArrayList<EntityContainer>();
+    private final List<AnnotationAttribute> annotationAttributes = new ArrayList<AnnotationAttribute>();
+    private final List<AnnotationElement> annotationElements = new ArrayList<AnnotationElement>();
+
+    private SchemaBuilder(final String namespace) {
+      this.namespace = namespace;
+    }
+
+    public static SchemaBuilder init(final String namespace) {
+      return new SchemaBuilder(namespace);
+    }
+
+    public SchemaBuilder addEntityType(final EntityType type) {
+      entityTypes.add(type);
+      return this;
+    }
+
+    public SchemaBuilder addEntityContainer(final EntityContainer container) {
+      entityContainers.add(container);
+      return this;
+    }
+
+    public SchemaBuilder addComplexType(final ComplexType createEntityType) {
+      complexTypes.add(createEntityType);
+      return this;
+    }
+
+    public void addAssociations(final Collection<Association> associations) {
+      for (Association association : associations) {
+        final String relationshipName = association.getName();
+        if (name2Associations.containsKey(relationshipName)) {
+          association = mergeAssociations(name2Associations.get(relationshipName), association);
+        }
+        name2Associations.put(relationshipName, association);
+      }
+    }
+
+    private Association mergeAssociations(final Association associationOne, final Association associationTwo) {
+      AssociationEnd oneEnd1 = associationOne.getEnd1();
+      AssociationEnd oneEnd2 = associationOne.getEnd2();
+      AssociationEnd twoEnd1 = associationTwo.getEnd1();
+      AssociationEnd twoEnd2 = associationTwo.getEnd2();
+      AssociationEnd[] oneEnds = new AssociationEnd[] { oneEnd1, oneEnd2 };
+
+      for (AssociationEnd associationEnd : oneEnds) {
+        if (associationEnd.getRole().equals(twoEnd1.getRole())) {
+          if (twoEnd1.getMultiplicity() == EdmMultiplicity.MANY) {
+            associationEnd.setMultiplicity(EdmMultiplicity.MANY);
+          }
+        } else if (associationEnd.getRole().equals(twoEnd2.getRole())) {
+          if (twoEnd2.getMultiplicity() == EdmMultiplicity.MANY) {
+            associationEnd.setMultiplicity(EdmMultiplicity.MANY);
+          }
+        }
+      }
+
+      return associationOne;
+    }
+
+    public Schema build() {
+      Schema s = new Schema();
+      s.setUsings(usings);
+      s.setEntityTypes(entityTypes);
+      s.setComplexTypes(complexTypes);
+      s.setAssociations(new ArrayList<Association>(name2Associations.values()));
+      s.setEntityContainers(entityContainers);
+      s.setAnnotationAttributes(annotationAttributes);
+      s.setAnnotationElements(annotationElements);
+      s.setNamespace(namespace);
+      return s;
+    }
+  }
+
+  private static class ContainerBuilder {
+
+    final private String name;
+    final private String namespace;
+    private boolean defaultContainer = true;
+    private final List<EntitySet> entitySets = new ArrayList<EntitySet>();
+    private final List<AssociationSet> associationSets = new ArrayList<AssociationSet>();
+    private final List<FunctionImport> functionImports = new ArrayList<FunctionImport>();
+
+    // private Documentation documentation;
+
+    private ContainerBuilder(final String namespace, final String containerName) {
+      this.namespace = namespace;
+      name = containerName;
+    }
+
+    public String getNamespace() {
+      return namespace;
+    }
+
+    public static ContainerBuilder init(final String namespace, final String containerName) {
+      return new ContainerBuilder(namespace, containerName);
+    }
+
+    public ContainerBuilder addEntitySet(final EntitySet entitySet) {
+      entitySets.add(entitySet);
+      return this;
+    }
+
+    public void addAssociationSets(final Collection<Association> associations) {
+      for (Association association : associations) {
+        AssociationSet as = new AssociationSet();
+        as.setName(association.getName());
+        FullQualifiedName asAssociationFqn = new FullQualifiedName(namespace, association.getName());
+        as.setAssociation(asAssociationFqn);
+
+        AssociationSetEnd asEnd1 = new AssociationSetEnd();
+        asEnd1.setEntitySet(getEntitySetName(association.getEnd1()));
+        asEnd1.setRole(association.getEnd1().getRole());
+        as.setEnd1(asEnd1);
+
+        AssociationSetEnd asEnd2 = new AssociationSetEnd();
+        asEnd2.setEntitySet(getEntitySetName(association.getEnd2()));
+        asEnd2.setRole(association.getEnd2().getRole());
+        as.setEnd2(asEnd2);
+
+        associationSets.add(as);
+      }
+    }
+
+    public EntityContainer build() {
+      EntityContainer ec = new EntityContainer();
+      ec.setName(name);
+      ec.setDefaultEntityContainer(defaultContainer);
+      ec.setEntitySets(entitySets);
+      ec.setAssociationSets(associationSets);
+      ec.setFunctionImports(functionImports);
+      return ec;
+    }
+
+    private String getEntitySetName(final AssociationEnd end) {
+      for (EntitySet entitySet : entitySets) {
+        if (entitySet.getEntityType().equals(end.getType())) {
+          return entitySet.getName();
+        }
+      }
+      throw new ODataRuntimeException("No entity set found for " + end.getType());
+    }
+  }
+}


[10/12] git commit: [OLINGO-95] Refactor ExpandSelectTreeBuilder in smaller methods

Posted by tb...@apache.org.
[OLINGO-95] Refactor ExpandSelectTreeBuilder in smaller methods


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

Branch: refs/heads/ODataServlet
Commit: 33aaa3ae02230cf0d90e387d91df84738972e58f
Parents: 3bd5905
Author: Christian Amend <ch...@apache.org>
Authored: Fri Dec 20 14:41:41 2013 +0100
Committer: Christian Amend <ch...@apache.org>
Committed: Fri Dec 20 14:42:29 2013 +0100

----------------------------------------------------------------------
 .../core/uri/ExpandSelectTreeNodeImpl.java      | 81 +++++++++++---------
 1 file changed, 43 insertions(+), 38 deletions(-)
----------------------------------------------------------------------


http://git-wip-us.apache.org/repos/asf/incubator-olingo-odata2/blob/33aaa3ae/odata2-lib/odata-core/src/main/java/org/apache/olingo/odata2/core/uri/ExpandSelectTreeNodeImpl.java
----------------------------------------------------------------------
diff --git a/odata2-lib/odata-core/src/main/java/org/apache/olingo/odata2/core/uri/ExpandSelectTreeNodeImpl.java b/odata2-lib/odata-core/src/main/java/org/apache/olingo/odata2/core/uri/ExpandSelectTreeNodeImpl.java
index ba3f624..0237cdf 100644
--- a/odata2-lib/odata-core/src/main/java/org/apache/olingo/odata2/core/uri/ExpandSelectTreeNodeImpl.java
+++ b/odata2-lib/odata-core/src/main/java/org/apache/olingo/odata2/core/uri/ExpandSelectTreeNodeImpl.java
@@ -168,7 +168,7 @@ public class ExpandSelectTreeNodeImpl extends ExpandSelectTreeNode {
 
   public class ExpandSelectTreeNodeBuilderImpl extends ExpandSelectTreeNodeBuilder {
 
-    EdmEntitySet entitySet;
+    private EdmEntitySet entitySet;
     private List<String> selectedPropertyNames;
     private List<String> selectedNavigationPropertyNames;
     private Map<String, ExpandSelectTreeNode> customExpandedNavigationProperties;
@@ -184,60 +184,65 @@ public class ExpandSelectTreeNodeImpl extends ExpandSelectTreeNode {
     public ExpandSelectTreeNode build() throws EdmException {
       EdmEntityType entityType = entitySet.getEntityType();
       if (selectedPropertyNames != null) {
-        for (String propertyName : selectedPropertyNames) {
-          EdmTyped property = entityType.getProperty(propertyName);
-          if (property == null) {
-            throw new EdmException(EdmException.PROPERTYNOTFOUND.addContent(propertyName));
-          } else if (!(property instanceof EdmProperty)) {
-            throw new EdmException(EdmException.MUSTBEPROPERTY.addContent(propertyName));
-          }
-          addProperty((EdmProperty) property);
-        }
+        handleProperties(entityType);
       }
 
       if (selectedNavigationPropertyNames != null) {
         setAllKindFalse();
-        for (String navigationPropertyName : selectedNavigationPropertyNames) {
-          EdmTyped navigationProperty = entityType.getProperty(navigationPropertyName);
-          if (navigationProperty == null) {
-            throw new EdmException(EdmException.NAVIGATIONPROPERTYNOTFOUND.addContent(navigationPropertyName));
-          } else if (!(navigationProperty instanceof EdmNavigationProperty)) {
-            throw new EdmException(EdmException.MUSTBENAVIGATIONPROPERTY.addContent(navigationPropertyName));
-          }
-          putLink(navigationPropertyName, null);
-        }
+        handleLinks(entityType, selectedNavigationPropertyNames, null);
       }
 
       if (expandedNavigationPropertyNames != null) {
         ExpandSelectTreeNodeImpl subNode = new ExpandSelectTreeNodeImpl();
         subNode.setExplicitlySelected();
-        for (String navigationPropertyName : expandedNavigationPropertyNames) {
-          EdmTyped navigationProperty = entityType.getProperty(navigationPropertyName);
-          if (navigationProperty == null) {
-            throw new EdmException(EdmException.NAVIGATIONPROPERTYNOTFOUND.addContent(navigationPropertyName));
-          } else if (!(navigationProperty instanceof EdmNavigationProperty)) {
-            throw new EdmException(EdmException.MUSTBENAVIGATIONPROPERTY.addContent(navigationPropertyName));
-          }
-          putLink(navigationPropertyName, subNode);
-        }
+        handleLinks(entityType, expandedNavigationPropertyNames, subNode);
       }
 
       if (customExpandedNavigationProperties != null) {
-        for (Map.Entry<String, ExpandSelectTreeNode> entry : customExpandedNavigationProperties.entrySet()) {
-          EdmTyped navigationProperty = entityType.getProperty(entry.getKey());
-          if (navigationProperty == null) {
-            throw new EdmException(EdmException.NAVIGATIONPROPERTYNOTFOUND.addContent(entry.getKey()));
-          }
-          if (!(navigationProperty instanceof EdmNavigationProperty)) {
-            throw new EdmException(EdmException.MUSTBENAVIGATIONPROPERTY.addContent(entry.getKey()));
-          }
-          putLink(entry.getKey(), (ExpandSelectTreeNodeImpl) entry.getValue());
-        }
+        handleCustomLinks(entityType);
       }
 
       return ExpandSelectTreeNodeImpl.this;
     }
 
+    private void handleCustomLinks(final EdmEntityType entityType) throws EdmException {
+      for (Map.Entry<String, ExpandSelectTreeNode> entry : customExpandedNavigationProperties.entrySet()) {
+        EdmTyped navigationProperty = entityType.getProperty(entry.getKey());
+        if (navigationProperty == null) {
+          throw new EdmException(EdmException.NAVIGATIONPROPERTYNOTFOUND.addContent(entry.getKey()));
+        }
+        if (!(navigationProperty instanceof EdmNavigationProperty)) {
+          throw new EdmException(EdmException.MUSTBENAVIGATIONPROPERTY.addContent(entry.getKey()));
+        }
+        putLink(entry.getKey(), (ExpandSelectTreeNodeImpl) entry.getValue());
+      }
+    }
+
+    private void handleLinks(final EdmEntityType entityType, final List<String> names,
+        final ExpandSelectTreeNodeImpl subNode) throws EdmException {
+      for (String navigationPropertyName : names) {
+        EdmTyped navigationProperty = entityType.getProperty(navigationPropertyName);
+        if (navigationProperty == null) {
+          throw new EdmException(EdmException.NAVIGATIONPROPERTYNOTFOUND.addContent(navigationPropertyName));
+        } else if (!(navigationProperty instanceof EdmNavigationProperty)) {
+          throw new EdmException(EdmException.MUSTBENAVIGATIONPROPERTY.addContent(navigationPropertyName));
+        }
+        putLink(navigationPropertyName, subNode);
+      }
+    }
+
+    private void handleProperties(final EdmEntityType entityType) throws EdmException {
+      for (String propertyName : selectedPropertyNames) {
+        EdmTyped property = entityType.getProperty(propertyName);
+        if (property == null) {
+          throw new EdmException(EdmException.PROPERTYNOTFOUND.addContent(propertyName));
+        } else if (!(property instanceof EdmProperty)) {
+          throw new EdmException(EdmException.MUSTBEPROPERTY.addContent(propertyName));
+        }
+        addProperty((EdmProperty) property);
+      }
+    }
+
     @Override
     public ExpandSelectTreeNodeBuilder selectedProperties(final List<String> selectedPropertyNames) {
       this.selectedPropertyNames = selectedPropertyNames;


[04/12] [OLINGO-83] Refactoring of 'annotation-processor-*' modules

Posted by tb...@apache.org.
http://git-wip-us.apache.org/repos/asf/incubator-olingo-odata2/blob/3bd59050/odata2-annotation-processor/annotation-processor-core/src/main/java/org/apache/olingo/odata2/core/annotation/processor/ListsProcessor.java
----------------------------------------------------------------------
diff --git a/odata2-annotation-processor/annotation-processor-core/src/main/java/org/apache/olingo/odata2/core/annotation/processor/ListsProcessor.java b/odata2-annotation-processor/annotation-processor-core/src/main/java/org/apache/olingo/odata2/core/annotation/processor/ListsProcessor.java
deleted file mode 100644
index 053d2da..0000000
--- a/odata2-annotation-processor/annotation-processor-core/src/main/java/org/apache/olingo/odata2/core/annotation/processor/ListsProcessor.java
+++ /dev/null
@@ -1,1641 +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.odata2.core.annotation.processor;
-
-import java.io.InputStream;
-import java.util.ArrayList;
-import java.util.Arrays;
-import java.util.Collections;
-import java.util.Comparator;
-import java.util.HashMap;
-import java.util.Iterator;
-import java.util.List;
-import java.util.Locale;
-import java.util.Map;
-
-import org.apache.olingo.odata2.api.ODataCallback;
-import org.apache.olingo.odata2.api.batch.BatchHandler;
-import org.apache.olingo.odata2.api.batch.BatchRequestPart;
-import org.apache.olingo.odata2.api.batch.BatchResponsePart;
-import org.apache.olingo.odata2.api.commons.HttpContentType;
-import org.apache.olingo.odata2.api.commons.HttpStatusCodes;
-import org.apache.olingo.odata2.api.commons.InlineCount;
-import org.apache.olingo.odata2.api.data.DataSource;
-import org.apache.olingo.odata2.api.data.DataSource.BinaryData;
-import org.apache.olingo.odata2.api.data.DataSourceProcessor;
-import org.apache.olingo.odata2.api.data.ValueAccess;
-import org.apache.olingo.odata2.api.edm.Edm;
-import org.apache.olingo.odata2.api.edm.EdmConcurrencyMode;
-import org.apache.olingo.odata2.api.edm.EdmEntitySet;
-import org.apache.olingo.odata2.api.edm.EdmEntityType;
-import org.apache.olingo.odata2.api.edm.EdmException;
-import org.apache.olingo.odata2.api.edm.EdmFunctionImport;
-import org.apache.olingo.odata2.api.edm.EdmLiteral;
-import org.apache.olingo.odata2.api.edm.EdmLiteralKind;
-import org.apache.olingo.odata2.api.edm.EdmMapping;
-import org.apache.olingo.odata2.api.edm.EdmMultiplicity;
-import org.apache.olingo.odata2.api.edm.EdmNavigationProperty;
-import org.apache.olingo.odata2.api.edm.EdmProperty;
-import org.apache.olingo.odata2.api.edm.EdmSimpleType;
-import org.apache.olingo.odata2.api.edm.EdmSimpleTypeException;
-import org.apache.olingo.odata2.api.edm.EdmSimpleTypeKind;
-import org.apache.olingo.odata2.api.edm.EdmStructuralType;
-import org.apache.olingo.odata2.api.edm.EdmType;
-import org.apache.olingo.odata2.api.edm.EdmTypeKind;
-import org.apache.olingo.odata2.api.edm.EdmTyped;
-import org.apache.olingo.odata2.api.ep.EntityProvider;
-import org.apache.olingo.odata2.api.ep.EntityProviderBatchProperties;
-import org.apache.olingo.odata2.api.ep.EntityProviderException;
-import org.apache.olingo.odata2.api.ep.EntityProviderReadProperties;
-import org.apache.olingo.odata2.api.ep.EntityProviderWriteProperties;
-import org.apache.olingo.odata2.api.ep.callback.OnWriteEntryContent;
-import org.apache.olingo.odata2.api.ep.callback.OnWriteFeedContent;
-import org.apache.olingo.odata2.api.ep.callback.WriteCallbackContext;
-import org.apache.olingo.odata2.api.ep.callback.WriteEntryCallbackContext;
-import org.apache.olingo.odata2.api.ep.callback.WriteEntryCallbackResult;
-import org.apache.olingo.odata2.api.ep.callback.WriteFeedCallbackContext;
-import org.apache.olingo.odata2.api.ep.callback.WriteFeedCallbackResult;
-import org.apache.olingo.odata2.api.ep.entry.ODataEntry;
-import org.apache.olingo.odata2.api.ep.feed.ODataFeed;
-import org.apache.olingo.odata2.api.exception.ODataApplicationException;
-import org.apache.olingo.odata2.api.exception.ODataBadRequestException;
-import org.apache.olingo.odata2.api.exception.ODataException;
-import org.apache.olingo.odata2.api.exception.ODataHttpException;
-import org.apache.olingo.odata2.api.exception.ODataNotFoundException;
-import org.apache.olingo.odata2.api.exception.ODataNotImplementedException;
-import org.apache.olingo.odata2.api.processor.ODataContext;
-import org.apache.olingo.odata2.api.processor.ODataRequest;
-import org.apache.olingo.odata2.api.processor.ODataResponse;
-import org.apache.olingo.odata2.api.uri.ExpandSelectTreeNode;
-import org.apache.olingo.odata2.api.uri.KeyPredicate;
-import org.apache.olingo.odata2.api.uri.NavigationSegment;
-import org.apache.olingo.odata2.api.uri.PathInfo;
-import org.apache.olingo.odata2.api.uri.UriParser;
-import org.apache.olingo.odata2.api.uri.expression.BinaryExpression;
-import org.apache.olingo.odata2.api.uri.expression.CommonExpression;
-import org.apache.olingo.odata2.api.uri.expression.ExpressionKind;
-import org.apache.olingo.odata2.api.uri.expression.FilterExpression;
-import org.apache.olingo.odata2.api.uri.expression.LiteralExpression;
-import org.apache.olingo.odata2.api.uri.expression.MemberExpression;
-import org.apache.olingo.odata2.api.uri.expression.MethodExpression;
-import org.apache.olingo.odata2.api.uri.expression.OrderByExpression;
-import org.apache.olingo.odata2.api.uri.expression.OrderExpression;
-import org.apache.olingo.odata2.api.uri.expression.PropertyExpression;
-import org.apache.olingo.odata2.api.uri.expression.SortOrder;
-import org.apache.olingo.odata2.api.uri.expression.UnaryExpression;
-import org.apache.olingo.odata2.api.uri.info.DeleteUriInfo;
-import org.apache.olingo.odata2.api.uri.info.GetComplexPropertyUriInfo;
-import org.apache.olingo.odata2.api.uri.info.GetEntityCountUriInfo;
-import org.apache.olingo.odata2.api.uri.info.GetEntityLinkCountUriInfo;
-import org.apache.olingo.odata2.api.uri.info.GetEntityLinkUriInfo;
-import org.apache.olingo.odata2.api.uri.info.GetEntitySetCountUriInfo;
-import org.apache.olingo.odata2.api.uri.info.GetEntitySetLinksCountUriInfo;
-import org.apache.olingo.odata2.api.uri.info.GetEntitySetLinksUriInfo;
-import org.apache.olingo.odata2.api.uri.info.GetEntitySetUriInfo;
-import org.apache.olingo.odata2.api.uri.info.GetEntityUriInfo;
-import org.apache.olingo.odata2.api.uri.info.GetFunctionImportUriInfo;
-import org.apache.olingo.odata2.api.uri.info.GetMediaResourceUriInfo;
-import org.apache.olingo.odata2.api.uri.info.GetSimplePropertyUriInfo;
-import org.apache.olingo.odata2.api.uri.info.PostUriInfo;
-import org.apache.olingo.odata2.api.uri.info.PutMergePatchUriInfo;
-
-/**
- * Implementation of the centralized parts of OData processing,
- * allowing to use the simplified {@link DataSource} for the
- * actual data handling.
- * 
- */
-public class ListsProcessor extends DataSourceProcessor {
-
-  // TODO: Paging size should be configurable.
-  private static final int SERVER_PAGING_SIZE = 100;
-
-  public ListsProcessor(final DataSource dataSource, final ValueAccess valueAccess) {
-    super(dataSource, valueAccess);
-  }
-
-  @Override
-  public ODataResponse readEntitySet(final GetEntitySetUriInfo uriInfo, final String contentType)
-      throws ODataException {
-    ArrayList<Object> data = new ArrayList<Object>();
-    try {
-      data.addAll((List<?>) retrieveData(
-          uriInfo.getStartEntitySet(),
-          uriInfo.getKeyPredicates(),
-          uriInfo.getFunctionImport(),
-          mapFunctionParameters(uriInfo.getFunctionImportParameters()),
-          uriInfo.getNavigationSegments()));
-    } catch (final ODataNotFoundException e) {
-      data.clear();
-    }
-
-    final EdmEntitySet entitySet = uriInfo.getTargetEntitySet();
-    final InlineCount inlineCountType = uriInfo.getInlineCount();
-    final Integer count = applySystemQueryOptions(
-        entitySet,
-        data,
-        uriInfo.getFilter(),
-        inlineCountType,
-        uriInfo.getOrderBy(),
-        uriInfo.getSkipToken(),
-        uriInfo.getSkip(),
-        uriInfo.getTop());
-
-    ODataContext context = getContext();
-    String nextLink = null;
-
-    // Limit the number of returned entities and provide a "next" link
-    // if there are further entities.
-    // Almost all system query options in the current request must be carried
-    // over to the URI for the "next" link, with the exception of $skiptoken
-    // and $skip.
-    if (data.size() > SERVER_PAGING_SIZE) {
-      if (uriInfo.getOrderBy() == null
-          && uriInfo.getSkipToken() == null
-          && uriInfo.getSkip() == null
-          && uriInfo.getTop() == null) {
-        sortInDefaultOrder(entitySet, data);
-      }
-
-      // TODO: Percent-encode "next" link.
-      nextLink = context.getPathInfo().getServiceRoot().relativize(context.getPathInfo().getRequestUri()).toString()
-          .replaceAll("\\$skiptoken=.+?&?", "")
-          .replaceAll("\\$skip=.+?&?", "")
-          .replaceFirst("(?:\\?|&)$", ""); // Remove potentially trailing "?" or "&" left over from remove actions
-                                           // above.
-      nextLink += (nextLink.contains("?") ? "&" : "?")
-          + "$skiptoken=" + getSkipToken(entitySet, data.get(SERVER_PAGING_SIZE));
-
-      while (data.size() > SERVER_PAGING_SIZE) {
-        data.remove(SERVER_PAGING_SIZE);
-      }
-    }
-
-    final EdmEntityType entityType = entitySet.getEntityType();
-    List<Map<String, Object>> values = new ArrayList<Map<String, Object>>();
-    for (final Object entryData : data) {
-      values.add(getStructuralTypeValueMap(entryData, entityType));
-    }
-
-    final EntityProviderWriteProperties feedProperties = EntityProviderWriteProperties
-        .serviceRoot(context.getPathInfo().getServiceRoot())
-        .inlineCountType(inlineCountType)
-        .inlineCount(count)
-        .expandSelectTree(UriParser.createExpandSelectTree(uriInfo.getSelect(), uriInfo.getExpand()))
-        .callbacks(getCallbacks(data, entityType))
-        .nextLink(nextLink)
-        .build();
-
-    final int timingHandle = context.startRuntimeMeasurement("EntityProvider", "writeFeed");
-    final ODataResponse response = EntityProvider.writeFeed(contentType, entitySet, values, feedProperties);
-
-    context.stopRuntimeMeasurement(timingHandle);
-
-    return ODataResponse.fromResponse(response).build();
-  }
-
-  @Override
-  public ODataResponse countEntitySet(final GetEntitySetCountUriInfo uriInfo, final String contentType)
-      throws ODataException {
-    ArrayList<Object> data = new ArrayList<Object>();
-    try {
-      data.addAll((List<?>) retrieveData(
-          uriInfo.getStartEntitySet(),
-          uriInfo.getKeyPredicates(),
-          uriInfo.getFunctionImport(),
-          mapFunctionParameters(uriInfo.getFunctionImportParameters()),
-          uriInfo.getNavigationSegments()));
-    } catch (final ODataNotFoundException e) {
-      data.clear();
-    }
-
-    applySystemQueryOptions(
-        uriInfo.getTargetEntitySet(),
-        data,
-        uriInfo.getFilter(),
-        null,
-        null,
-        null,
-        uriInfo.getSkip(),
-        uriInfo.getTop());
-
-    return ODataResponse.fromResponse(EntityProvider.writeText(String.valueOf(data.size()))).build();
-  }
-
-  @Override
-  public ODataResponse readEntityLinks(final GetEntitySetLinksUriInfo uriInfo, final String contentType)
-      throws ODataException {
-    ArrayList<Object> data = new ArrayList<Object>();
-    try {
-      data.addAll((List<?>) retrieveData(
-          uriInfo.getStartEntitySet(),
-          uriInfo.getKeyPredicates(),
-          uriInfo.getFunctionImport(),
-          mapFunctionParameters(uriInfo.getFunctionImportParameters()),
-          uriInfo.getNavigationSegments()));
-    } catch (final ODataNotFoundException e) {
-      data.clear();
-    }
-
-    final Integer count = applySystemQueryOptions(
-        uriInfo.getTargetEntitySet(),
-        data,
-        uriInfo.getFilter(),
-        uriInfo.getInlineCount(),
-        null, // uriInfo.getOrderBy(),
-        uriInfo.getSkipToken(),
-        uriInfo.getSkip(),
-        uriInfo.getTop());
-
-    final EdmEntitySet entitySet = uriInfo.getTargetEntitySet();
-
-    List<Map<String, Object>> values = new ArrayList<Map<String, Object>>();
-    for (final Object entryData : data) {
-      Map<String, Object> entryValues = new HashMap<String, Object>();
-      for (final EdmProperty property : entitySet.getEntityType().getKeyProperties()) {
-        entryValues.put(property.getName(), valueAccess.getPropertyValue(entryData, property));
-      }
-      values.add(entryValues);
-    }
-
-    ODataContext context = getContext();
-    final EntityProviderWriteProperties entryProperties = EntityProviderWriteProperties
-        .serviceRoot(context.getPathInfo().getServiceRoot())
-        .inlineCountType(uriInfo.getInlineCount())
-        .inlineCount(count)
-        .build();
-
-    final int timingHandle = context.startRuntimeMeasurement("EntityProvider", "writeLinks");
-
-    final ODataResponse response = EntityProvider.writeLinks(contentType, entitySet, values, entryProperties);
-
-    context.stopRuntimeMeasurement(timingHandle);
-
-    return ODataResponse.fromResponse(response).build();
-  }
-
-  @Override
-  public ODataResponse countEntityLinks(final GetEntitySetLinksCountUriInfo uriInfo, final String contentType)
-      throws ODataException {
-    return countEntitySet((GetEntitySetCountUriInfo) uriInfo, contentType);
-  }
-
-  @Override
-  public ODataResponse readEntity(final GetEntityUriInfo uriInfo, final String contentType) throws ODataException {
-    final Object data = retrieveData(
-        uriInfo.getStartEntitySet(),
-        uriInfo.getKeyPredicates(),
-        uriInfo.getFunctionImport(),
-        mapFunctionParameters(uriInfo.getFunctionImportParameters()),
-        uriInfo.getNavigationSegments());
-
-    if (!appliesFilter(data, uriInfo.getFilter())) {
-      throw new ODataNotFoundException(ODataNotFoundException.ENTITY);
-    }
-
-    final ExpandSelectTreeNode expandSelectTreeNode =
-        UriParser.createExpandSelectTree(uriInfo.getSelect(), uriInfo.getExpand());
-    ODataResponse odr =
-        ODataResponse.fromResponse(writeEntry(uriInfo.getTargetEntitySet(), expandSelectTreeNode, data, contentType))
-            .build();
-
-    return odr;
-  }
-
-  @Override
-  public ODataResponse existsEntity(final GetEntityCountUriInfo uriInfo, final String contentType)
-      throws ODataException {
-    final Object data = retrieveData(
-        uriInfo.getStartEntitySet(),
-        uriInfo.getKeyPredicates(),
-        uriInfo.getFunctionImport(),
-        mapFunctionParameters(uriInfo.getFunctionImportParameters()),
-        uriInfo.getNavigationSegments());
-
-    return ODataResponse.fromResponse(EntityProvider.writeText(appliesFilter(data, uriInfo.getFilter()) ? "1" : "0"))
-        .build();
-  }
-
-  @Override
-  public ODataResponse deleteEntity(final DeleteUriInfo uriInfo, final String contentType) throws ODataException {
-    dataSource.deleteData(
-        uriInfo.getStartEntitySet(),
-        mapKey(uriInfo.getKeyPredicates()));
-    return ODataResponse.newBuilder().build();
-  }
-
-  @Override
-  public ODataResponse createEntity(final PostUriInfo uriInfo, final InputStream content,
-      final String requestContentType, final String contentType) throws ODataException {
-    final EdmEntitySet entitySet = uriInfo.getTargetEntitySet();
-    final EdmEntityType entityType = entitySet.getEntityType();
-
-    Object data = dataSource.newDataObject(entitySet);
-    ExpandSelectTreeNode expandSelectTree = null;
-
-    if (entityType.hasStream()) {
-      dataSource.createData(entitySet, data);
-      dataSource.writeBinaryData(entitySet, data,
-          new BinaryData(EntityProvider.readBinary(content), requestContentType));
-
-    } else {
-      final EntityProviderReadProperties properties = EntityProviderReadProperties.init()
-          .mergeSemantic(false)
-          .addTypeMappings(getStructuralTypeTypeMap(data, entityType))
-          .build();
-      final ODataEntry entryValues = parseEntry(entitySet, content, requestContentType, properties);
-
-      setStructuralTypeValuesFromMap(data, entityType, entryValues.getProperties(), false);
-
-      dataSource.createData(entitySet, data);
-
-      createInlinedEntities(entitySet, data, entryValues);
-
-      expandSelectTree = entryValues.getExpandSelectTree();
-    }
-
-    // Link back to the entity the target entity set is related to, if any.
-    final List<NavigationSegment> navigationSegments = uriInfo.getNavigationSegments();
-    if (!navigationSegments.isEmpty()) {
-      final List<NavigationSegment> previousSegments = navigationSegments.subList(0, navigationSegments.size() - 1);
-      final Object sourceData = retrieveData(
-          uriInfo.getStartEntitySet(),
-          uriInfo.getKeyPredicates(),
-          uriInfo.getFunctionImport(),
-          mapFunctionParameters(uriInfo.getFunctionImportParameters()),
-          previousSegments);
-      final EdmEntitySet previousEntitySet = previousSegments.isEmpty() ?
-          uriInfo.getStartEntitySet() : previousSegments.get(previousSegments.size() - 1).getEntitySet();
-      dataSource.writeRelation(previousEntitySet, sourceData, entitySet, getStructuralTypeValueMap(data, entityType));
-    }
-
-    return ODataResponse.fromResponse(writeEntry(uriInfo.getTargetEntitySet(), expandSelectTree, data, contentType))
-        .eTag(constructETag(entitySet, data)).build();
-  }
-
-  @Override
-  public ODataResponse updateEntity(final PutMergePatchUriInfo uriInfo, final InputStream content,
-      final String requestContentType, final boolean merge, final String contentType) throws ODataException {
-    Object data = retrieveData(
-        uriInfo.getStartEntitySet(),
-        uriInfo.getKeyPredicates(),
-        uriInfo.getFunctionImport(),
-        mapFunctionParameters(uriInfo.getFunctionImportParameters()),
-        uriInfo.getNavigationSegments());
-
-    if (!appliesFilter(data, uriInfo.getFilter())) {
-      throw new ODataNotFoundException(ODataNotFoundException.ENTITY);
-    }
-
-    final EdmEntitySet entitySet = uriInfo.getTargetEntitySet();
-    final EdmEntityType entityType = entitySet.getEntityType();
-    final EntityProviderReadProperties properties = EntityProviderReadProperties.init()
-        .mergeSemantic(merge)
-        .addTypeMappings(getStructuralTypeTypeMap(data, entityType))
-        .build();
-    final ODataEntry entryValues = parseEntry(entitySet, content, requestContentType, properties);
-
-    setStructuralTypeValuesFromMap(data, entityType, entryValues.getProperties(), merge);
-
-    return ODataResponse.newBuilder().eTag(constructETag(entitySet, data)).build();
-  }
-
-  @Override
-  public ODataResponse readEntityLink(final GetEntityLinkUriInfo uriInfo, final String contentType)
-      throws ODataException {
-    final Object data = retrieveData(
-        uriInfo.getStartEntitySet(),
-        uriInfo.getKeyPredicates(),
-        uriInfo.getFunctionImport(),
-        mapFunctionParameters(uriInfo.getFunctionImportParameters()),
-        uriInfo.getNavigationSegments());
-
-    // if (!appliesFilter(data, uriInfo.getFilter()))
-    if (data == null) {
-      throw new ODataNotFoundException(ODataNotFoundException.ENTITY);
-    }
-
-    final EdmEntitySet entitySet = uriInfo.getTargetEntitySet();
-
-    Map<String, Object> values = new HashMap<String, Object>();
-    for (final EdmProperty property : entitySet.getEntityType().getKeyProperties()) {
-      values.put(property.getName(), valueAccess.getPropertyValue(data, property));
-    }
-
-    ODataContext context = getContext();
-    final EntityProviderWriteProperties entryProperties = EntityProviderWriteProperties
-        .serviceRoot(context.getPathInfo().getServiceRoot())
-        .build();
-
-    final int timingHandle = context.startRuntimeMeasurement("EntityProvider", "writeLink");
-
-    final ODataResponse response = EntityProvider.writeLink(contentType, entitySet, values, entryProperties);
-
-    context.stopRuntimeMeasurement(timingHandle);
-
-    return ODataResponse.fromResponse(response).build();
-  }
-
-  @Override
-  public ODataResponse existsEntityLink(final GetEntityLinkCountUriInfo uriInfo, final String contentType)
-      throws ODataException {
-    return existsEntity((GetEntityCountUriInfo) uriInfo, contentType);
-  }
-
-  @Override
-  public ODataResponse deleteEntityLink(final DeleteUriInfo uriInfo, final String contentType) throws ODataException {
-    final List<NavigationSegment> navigationSegments = uriInfo.getNavigationSegments();
-    final List<NavigationSegment> previousSegments = navigationSegments.subList(0, navigationSegments.size() - 1);
-
-    final Object sourceData = retrieveData(
-        uriInfo.getStartEntitySet(),
-        uriInfo.getKeyPredicates(),
-        uriInfo.getFunctionImport(),
-        mapFunctionParameters(uriInfo.getFunctionImportParameters()),
-        previousSegments);
-
-    final EdmEntitySet entitySet = previousSegments.isEmpty() ?
-        uriInfo.getStartEntitySet() : previousSegments.get(previousSegments.size() - 1).getEntitySet();
-    final EdmEntitySet targetEntitySet = uriInfo.getTargetEntitySet();
-    final Map<String, Object> keys = mapKey(uriInfo.getTargetKeyPredicates());
-
-    final Object targetData = dataSource.readRelatedData(entitySet, sourceData, targetEntitySet, keys);
-
-    // if (!appliesFilter(targetData, uriInfo.getFilter()))
-    if (targetData == null) {
-      throw new ODataNotFoundException(ODataNotFoundException.ENTITY);
-    }
-
-    dataSource.deleteRelation(entitySet, sourceData, targetEntitySet, keys);
-
-    return ODataResponse.newBuilder().build();
-  }
-
-  @Override
-  public ODataResponse createEntityLink(final PostUriInfo uriInfo, final InputStream content,
-      final String requestContentType, final String contentType) throws ODataException {
-    final List<NavigationSegment> navigationSegments = uriInfo.getNavigationSegments();
-    final List<NavigationSegment> previousSegments = navigationSegments.subList(0, navigationSegments.size() - 1);
-
-    final Object sourceData = retrieveData(
-        uriInfo.getStartEntitySet(),
-        uriInfo.getKeyPredicates(),
-        uriInfo.getFunctionImport(),
-        mapFunctionParameters(uriInfo.getFunctionImportParameters()),
-        previousSegments);
-
-    final EdmEntitySet entitySet = previousSegments.isEmpty() ?
-        uriInfo.getStartEntitySet() : previousSegments.get(previousSegments.size() - 1).getEntitySet();
-    final EdmEntitySet targetEntitySet = uriInfo.getTargetEntitySet();
-
-    final Map<String, Object> targetKeys = parseLink(targetEntitySet, content, requestContentType);
-
-    dataSource.writeRelation(entitySet, sourceData, targetEntitySet, targetKeys);
-
-    return ODataResponse.newBuilder().build();
-  }
-
-  @Override
-  public ODataResponse updateEntityLink(final PutMergePatchUriInfo uriInfo, final InputStream content,
-      final String requestContentType, final String contentType) throws ODataException {
-    final List<NavigationSegment> navigationSegments = uriInfo.getNavigationSegments();
-    final List<NavigationSegment> previousSegments = navigationSegments.subList(0, navigationSegments.size() - 1);
-
-    final Object sourceData = retrieveData(
-        uriInfo.getStartEntitySet(),
-        uriInfo.getKeyPredicates(),
-        uriInfo.getFunctionImport(),
-        mapFunctionParameters(uriInfo.getFunctionImportParameters()),
-        previousSegments);
-
-    final EdmEntitySet entitySet = previousSegments.isEmpty() ?
-        uriInfo.getStartEntitySet() : previousSegments.get(previousSegments.size() - 1).getEntitySet();
-    final EdmEntitySet targetEntitySet = uriInfo.getTargetEntitySet();
-    final Map<String, Object> keys = mapKey(uriInfo.getTargetKeyPredicates());
-
-    final Object targetData = dataSource.readRelatedData(entitySet, sourceData, targetEntitySet, keys);
-
-    if (!appliesFilter(targetData, uriInfo.getFilter())) {
-      throw new ODataNotFoundException(ODataNotFoundException.ENTITY);
-    }
-
-    dataSource.deleteRelation(entitySet, sourceData, targetEntitySet, keys);
-
-    final Map<String, Object> newKeys = parseLink(targetEntitySet, content, requestContentType);
-
-    dataSource.writeRelation(entitySet, sourceData, targetEntitySet, newKeys);
-
-    return ODataResponse.newBuilder().build();
-  }
-
-  @Override
-  public ODataResponse readEntityComplexProperty(final GetComplexPropertyUriInfo uriInfo, final String contentType)
-      throws ODataException {
-    Object data = retrieveData(
-        uriInfo.getStartEntitySet(),
-        uriInfo.getKeyPredicates(),
-        uriInfo.getFunctionImport(),
-        mapFunctionParameters(uriInfo.getFunctionImportParameters()),
-        uriInfo.getNavigationSegments());
-
-    // if (!appliesFilter(data, uriInfo.getFilter()))
-    if (data == null) {
-      throw new ODataNotFoundException(ODataNotFoundException.ENTITY);
-    }
-
-    final List<EdmProperty> propertyPath = uriInfo.getPropertyPath();
-    final EdmProperty property = propertyPath.get(propertyPath.size() - 1);
-    final Object value = property.isSimple() ?
-        property.getMapping() == null || property.getMapping().getMimeType() == null ?
-            getPropertyValue(data, propertyPath) : getSimpleTypeValueMap(data, propertyPath) :
-        getStructuralTypeValueMap(getPropertyValue(data, propertyPath), (EdmStructuralType) property.getType());
-
-    ODataContext context = getContext();
-    final int timingHandle = context.startRuntimeMeasurement("EntityProvider", "writeProperty");
-
-    final ODataResponse response = EntityProvider.writeProperty(contentType, property, value);
-
-    context.stopRuntimeMeasurement(timingHandle);
-
-    return ODataResponse.fromResponse(response).eTag(constructETag(uriInfo.getTargetEntitySet(), data)).build();
-  }
-
-  @Override
-  public ODataResponse readEntitySimpleProperty(final GetSimplePropertyUriInfo uriInfo, final String contentType)
-      throws ODataException {
-    return readEntityComplexProperty((GetComplexPropertyUriInfo) uriInfo, contentType);
-  }
-
-  @Override
-  public ODataResponse readEntitySimplePropertyValue(final GetSimplePropertyUriInfo uriInfo, final String contentType)
-      throws ODataException {
-    Object data = retrieveData(
-        uriInfo.getStartEntitySet(),
-        uriInfo.getKeyPredicates(),
-        uriInfo.getFunctionImport(),
-        mapFunctionParameters(uriInfo.getFunctionImportParameters()),
-        uriInfo.getNavigationSegments());
-
-    // if (!appliesFilter(data, uriInfo.getFilter()))
-    if (data == null) {
-      throw new ODataNotFoundException(ODataNotFoundException.ENTITY);
-    }
-
-    final List<EdmProperty> propertyPath = uriInfo.getPropertyPath();
-    final EdmProperty property = propertyPath.get(propertyPath.size() - 1);
-    final Object value = property.getMapping() == null || property.getMapping().getMimeType() == null ?
-        getPropertyValue(data, propertyPath) : getSimpleTypeValueMap(data, propertyPath);
-
-    return ODataResponse.fromResponse(EntityProvider.writePropertyValue(property, value)).eTag(
-        constructETag(uriInfo.getTargetEntitySet(), data)).build();
-  }
-
-  @Override
-  public ODataResponse deleteEntitySimplePropertyValue(final DeleteUriInfo uriInfo, final String contentType)
-      throws ODataException {
-    Object data = retrieveData(
-        uriInfo.getStartEntitySet(),
-        uriInfo.getKeyPredicates(),
-        uriInfo.getFunctionImport(),
-        mapFunctionParameters(uriInfo.getFunctionImportParameters()),
-        uriInfo.getNavigationSegments());
-
-    if (data == null) {
-      throw new ODataNotFoundException(ODataNotFoundException.ENTITY);
-    }
-
-    final List<EdmProperty> propertyPath = uriInfo.getPropertyPath();
-    final EdmProperty property = propertyPath.get(propertyPath.size() - 1);
-
-    data = getPropertyValue(data, propertyPath.subList(0, propertyPath.size() - 1));
-    valueAccess.setPropertyValue(data, property, null);
-    valueAccess.setMappingValue(data, property.getMapping(), null);
-
-    return ODataResponse.newBuilder().build();
-  }
-
-  @Override
-  public ODataResponse updateEntityComplexProperty(final PutMergePatchUriInfo uriInfo, final InputStream content,
-      final String requestContentType, final boolean merge, final String contentType) throws ODataException {
-    Object data = retrieveData(
-        uriInfo.getStartEntitySet(),
-        uriInfo.getKeyPredicates(),
-        uriInfo.getFunctionImport(),
-        mapFunctionParameters(uriInfo.getFunctionImportParameters()),
-        uriInfo.getNavigationSegments());
-
-    if (!appliesFilter(data, uriInfo.getFilter())) {
-      throw new ODataNotFoundException(ODataNotFoundException.ENTITY);
-    }
-
-    final List<EdmProperty> propertyPath = uriInfo.getPropertyPath();
-    final EdmProperty property = propertyPath.get(propertyPath.size() - 1);
-
-    data = getPropertyValue(data, propertyPath.subList(0, propertyPath.size() - 1));
-
-    ODataContext context = getContext();
-    int timingHandle = context.startRuntimeMeasurement("EntityConsumer", "readProperty");
-
-    Map<String, Object> values;
-    try {
-      values =
-          EntityProvider.readProperty(requestContentType, property, content, EntityProviderReadProperties.init()
-              .mergeSemantic(merge).build());
-    } catch (final EntityProviderException e) {
-      throw new ODataBadRequestException(ODataBadRequestException.BODY, e);
-    }
-
-    context.stopRuntimeMeasurement(timingHandle);
-
-    final Object value = values.get(property.getName());
-    if (property.isSimple()) {
-      valueAccess.setPropertyValue(data, property, value);
-    } else {
-      @SuppressWarnings("unchecked")
-      final Map<String, Object> propertyValue = (Map<String, Object>) value;
-      setStructuralTypeValuesFromMap(valueAccess.getPropertyValue(data, property),
-          (EdmStructuralType) property.getType(), propertyValue, merge);
-    }
-
-    return ODataResponse.newBuilder().eTag(constructETag(uriInfo.getTargetEntitySet(), data)).build();
-  }
-
-  @Override
-  public ODataResponse updateEntitySimpleProperty(final PutMergePatchUriInfo uriInfo, final InputStream content,
-      final String requestContentType, final String contentType) throws ODataException {
-    return updateEntityComplexProperty(uriInfo, content, requestContentType, false, contentType);
-  }
-
-  @Override
-  public ODataResponse updateEntitySimplePropertyValue(final PutMergePatchUriInfo uriInfo, final InputStream content,
-      final String requestContentType, final String contentType) throws ODataException {
-    Object data = retrieveData(
-        uriInfo.getStartEntitySet(),
-        uriInfo.getKeyPredicates(),
-        uriInfo.getFunctionImport(),
-        mapFunctionParameters(uriInfo.getFunctionImportParameters()),
-        uriInfo.getNavigationSegments());
-
-    if (!appliesFilter(data, uriInfo.getFilter())) {
-      throw new ODataNotFoundException(ODataNotFoundException.ENTITY);
-    }
-
-    final List<EdmProperty> propertyPath = uriInfo.getPropertyPath();
-    final EdmProperty property = propertyPath.get(propertyPath.size() - 1);
-
-    data = getPropertyValue(data, propertyPath.subList(0, propertyPath.size() - 1));
-
-    ODataContext context = getContext();
-    int timingHandle = context.startRuntimeMeasurement("EntityConsumer", "readPropertyValue");
-
-    Object value;
-    try {
-      value = EntityProvider.readPropertyValue(property, content);
-    } catch (final EntityProviderException e) {
-      throw new ODataBadRequestException(ODataBadRequestException.BODY, e);
-    }
-
-    context.stopRuntimeMeasurement(timingHandle);
-
-    valueAccess.setPropertyValue(data, property, value);
-    valueAccess.setMappingValue(data, property.getMapping(), requestContentType);
-
-    return ODataResponse.newBuilder().eTag(constructETag(uriInfo.getTargetEntitySet(), data)).build();
-  }
-
-  @Override
-  public ODataResponse readEntityMedia(final GetMediaResourceUriInfo uriInfo, final String contentType)
-      throws ODataException {
-    final Object data = retrieveData(
-        uriInfo.getStartEntitySet(),
-        uriInfo.getKeyPredicates(),
-        uriInfo.getFunctionImport(),
-        mapFunctionParameters(uriInfo.getFunctionImportParameters()),
-        uriInfo.getNavigationSegments());
-
-    if (!appliesFilter(data, uriInfo.getFilter())) {
-      throw new ODataNotFoundException(ODataNotFoundException.ENTITY);
-    }
-
-    final EdmEntitySet entitySet = uriInfo.getTargetEntitySet();
-    final BinaryData binaryData = dataSource.readBinaryData(entitySet, data);
-    if (binaryData == null) {
-      throw new ODataNotFoundException(ODataNotFoundException.ENTITY);
-    }
-
-    final String mimeType = binaryData.getMimeType() == null ?
-        HttpContentType.APPLICATION_OCTET_STREAM : binaryData.getMimeType();
-
-    return ODataResponse.fromResponse(EntityProvider.writeBinary(mimeType, binaryData.getData())).eTag(
-        constructETag(entitySet, data)).build();
-  }
-
-  @Override
-  public ODataResponse deleteEntityMedia(final DeleteUriInfo uriInfo, final String contentType) throws ODataException {
-    final Object data = retrieveData(
-        uriInfo.getStartEntitySet(),
-        uriInfo.getKeyPredicates(),
-        uriInfo.getFunctionImport(),
-        mapFunctionParameters(uriInfo.getFunctionImportParameters()),
-        uriInfo.getNavigationSegments());
-
-    if (data == null) {
-      throw new ODataNotFoundException(ODataNotFoundException.ENTITY);
-    }
-
-    dataSource.writeBinaryData(uriInfo.getTargetEntitySet(), data, new BinaryData(null, null));
-
-    return ODataResponse.newBuilder().build();
-  }
-
-  @Override
-  public ODataResponse updateEntityMedia(final PutMergePatchUriInfo uriInfo, final InputStream content,
-      final String requestContentType, final String contentType) throws ODataException {
-    final Object data = retrieveData(
-        uriInfo.getStartEntitySet(),
-        uriInfo.getKeyPredicates(),
-        uriInfo.getFunctionImport(),
-        mapFunctionParameters(uriInfo.getFunctionImportParameters()),
-        uriInfo.getNavigationSegments());
-
-    if (!appliesFilter(data, uriInfo.getFilter())) {
-      throw new ODataNotFoundException(ODataNotFoundException.ENTITY);
-    }
-
-    ODataContext context = getContext();
-    final int timingHandle = context.startRuntimeMeasurement("EntityProvider", "readBinary");
-
-    final byte[] value = EntityProvider.readBinary(content);
-
-    context.stopRuntimeMeasurement(timingHandle);
-
-    final EdmEntitySet entitySet = uriInfo.getTargetEntitySet();
-    dataSource.writeBinaryData(entitySet, data, new BinaryData(value, requestContentType));
-
-    return ODataResponse.newBuilder().eTag(constructETag(entitySet, data)).build();
-  }
-
-  @Override
-  public ODataResponse executeFunctionImport(final GetFunctionImportUriInfo uriInfo, final String contentType)
-      throws ODataException {
-    final EdmFunctionImport functionImport = uriInfo.getFunctionImport();
-    final EdmType type = functionImport.getReturnType().getType();
-
-    final Object data = dataSource.readData(
-        functionImport,
-        mapFunctionParameters(uriInfo.getFunctionImportParameters()),
-        null);
-
-    if (data == null) {
-      throw new ODataNotFoundException(ODataHttpException.COMMON);
-    }
-
-    Object value;
-    if (type.getKind() == EdmTypeKind.SIMPLE) {
-      value = type == EdmSimpleTypeKind.Binary.getEdmSimpleTypeInstance() ?
-          ((BinaryData) data).getData() : data;
-    } else if (functionImport.getReturnType().getMultiplicity() == EdmMultiplicity.MANY) {
-      List<Map<String, Object>> values = new ArrayList<Map<String, Object>>();
-      for (final Object typeData : (List<?>) data) {
-        values.add(getStructuralTypeValueMap(typeData, (EdmStructuralType) type));
-      }
-      value = values;
-    } else {
-      value = getStructuralTypeValueMap(data, (EdmStructuralType) type);
-    }
-
-    ODataContext context = getContext();
-
-    final EntityProviderWriteProperties entryProperties = EntityProviderWriteProperties
-        .serviceRoot(context.getPathInfo().getServiceRoot()).build();
-
-    final int timingHandle = context.startRuntimeMeasurement("EntityProvider", "writeFunctionImport");
-
-    final ODataResponse response =
-        EntityProvider.writeFunctionImport(contentType, functionImport, value, entryProperties);
-
-    context.stopRuntimeMeasurement(timingHandle);
-
-    return ODataResponse.fromResponse(response).build();
-  }
-
-  @Override
-  public ODataResponse executeFunctionImportValue(final GetFunctionImportUriInfo uriInfo, final String contentType)
-      throws ODataException {
-    final EdmFunctionImport functionImport = uriInfo.getFunctionImport();
-    final EdmSimpleType type = (EdmSimpleType) functionImport.getReturnType().getType();
-
-    final Object data = dataSource.readData(
-        functionImport,
-        mapFunctionParameters(uriInfo.getFunctionImportParameters()),
-        null);
-
-    if (data == null) {
-      throw new ODataNotFoundException(ODataHttpException.COMMON);
-    }
-
-    ODataResponse response;
-    if (type == EdmSimpleTypeKind.Binary.getEdmSimpleTypeInstance()) {
-      response = EntityProvider.writeBinary(((BinaryData) data).getMimeType(), ((BinaryData) data).getData());
-    } else {
-      final String value = type.valueToString(data, EdmLiteralKind.DEFAULT, null);
-      response = EntityProvider.writeText(value == null ? "" : value);
-    }
-    return ODataResponse.fromResponse(response).build();
-  }
-
-  private static Map<String, Object> mapKey(final List<KeyPredicate> keys) throws EdmException {
-    Map<String, Object> keyMap = new HashMap<String, Object>();
-    for (final KeyPredicate key : keys) {
-      final EdmProperty property = key.getProperty();
-      final EdmSimpleType type = (EdmSimpleType) property.getType();
-      keyMap.put(property.getName(), type.valueOfString(key.getLiteral(), EdmLiteralKind.DEFAULT, property.getFacets(),
-          type.getDefaultType()));
-    }
-    return keyMap;
-  }
-
-  private static Map<String, Object> mapFunctionParameters(final Map<String, EdmLiteral> functionImportParameters)
-      throws EdmSimpleTypeException {
-    if (functionImportParameters == null) {
-      return Collections.emptyMap();
-    } else {
-      Map<String, Object> parameterMap = new HashMap<String, Object>();
-      for (final String parameterName : functionImportParameters.keySet()) {
-        final EdmLiteral literal = functionImportParameters.get(parameterName);
-        final EdmSimpleType type = literal.getType();
-        parameterMap.put(parameterName, type.valueOfString(literal.getLiteral(), EdmLiteralKind.DEFAULT, null, type
-            .getDefaultType()));
-      }
-      return parameterMap;
-    }
-  }
-
-  private Object retrieveData(final EdmEntitySet startEntitySet, final List<KeyPredicate> keyPredicates,
-      final EdmFunctionImport functionImport, final Map<String, Object> functionImportParameters,
-      final List<NavigationSegment> navigationSegments) throws ODataException {
-    Object data;
-    final Map<String, Object> keys = mapKey(keyPredicates);
-
-    ODataContext context = getContext();
-    final int timingHandle = context.startRuntimeMeasurement(getClass().getSimpleName(), "retrieveData");
-
-    try {
-      data = functionImport == null ?
-          keys.isEmpty() ?
-              dataSource.readData(startEntitySet) : dataSource.readData(startEntitySet, keys) :
-          dataSource.readData(functionImport, functionImportParameters, keys);
-  
-      EdmEntitySet currentEntitySet =
-          functionImport == null ? startEntitySet : functionImport.getEntitySet();
-      for (NavigationSegment navigationSegment : navigationSegments) {
-        data = dataSource.readRelatedData(
-            currentEntitySet,
-            data,
-            navigationSegment.getEntitySet(),
-            mapKey(navigationSegment.getKeyPredicates()));
-        currentEntitySet = navigationSegment.getEntitySet();
-      }
-    } finally {
-      context.stopRuntimeMeasurement(timingHandle);
-    }
-    return data;
-  }
-
-  private <T> String constructETag(final EdmEntitySet entitySet, final T data) throws ODataException {
-    final EdmEntityType entityType = entitySet.getEntityType();
-    String eTag = null;
-    for (final String propertyName : entityType.getPropertyNames()) {
-      final EdmProperty property = (EdmProperty) entityType.getProperty(propertyName);
-      if (property.getFacets() != null && property.getFacets().getConcurrencyMode() == EdmConcurrencyMode.Fixed) {
-        final EdmSimpleType type = (EdmSimpleType) property.getType();
-        final String component = type.valueToString(valueAccess.getPropertyValue(data, property),
-            EdmLiteralKind.DEFAULT, property.getFacets());
-        eTag = eTag == null ? component : eTag + Edm.DELIMITER + component;
-      }
-    }
-    return eTag == null ? null : "W/\"" + eTag + "\"";
-  }
-
-  private <T> Map<String, ODataCallback> getCallbacks(final T data, final EdmEntityType entityType)
-      throws EdmException {
-    final List<String> navigationPropertyNames = entityType.getNavigationPropertyNames();
-    if (navigationPropertyNames.isEmpty()) {
-      return null;
-    } else {
-      final WriteCallback callback = new WriteCallback(data);
-      Map<String, ODataCallback> callbacks = new HashMap<String, ODataCallback>();
-      for (final String name : navigationPropertyNames) {
-        callbacks.put(name, callback);
-      }
-      return callbacks;
-    }
-  }
-
-  private class WriteCallback implements OnWriteEntryContent, OnWriteFeedContent {
-    private final Object data;
-
-    private <T> WriteCallback(final T data) {
-      this.data = data;
-    }
-
-    @Override
-    public WriteFeedCallbackResult retrieveFeedResult(final WriteFeedCallbackContext context)
-        throws ODataApplicationException {
-      try {
-        final EdmEntityType entityType =
-            context.getSourceEntitySet().getRelatedEntitySet(context.getNavigationProperty()).getEntityType();
-        List<Map<String, Object>> values = new ArrayList<Map<String, Object>>();
-        Object relatedData = null;
-        try {
-          relatedData = readRelatedData(context);
-          for (final Object entryData : (List<?>) relatedData) {
-            values.add(getStructuralTypeValueMap(entryData, entityType));
-          }
-        } catch (final ODataNotFoundException e) {
-          values.clear();
-        }
-        WriteFeedCallbackResult result = new WriteFeedCallbackResult();
-        result.setFeedData(values);
-        EntityProviderWriteProperties inlineProperties =
-            EntityProviderWriteProperties.serviceRoot(getContext().getPathInfo().getServiceRoot()).callbacks(
-                getCallbacks(relatedData, entityType)).expandSelectTree(context.getCurrentExpandSelectTreeNode())
-                .selfLink(context.getSelfLink()).build();
-        result.setInlineProperties(inlineProperties);
-        return result;
-      } catch (final ODataException e) {
-        throw new ODataApplicationException(e.getLocalizedMessage(), Locale.ROOT, e);
-      }
-    }
-
-    @Override
-    public WriteEntryCallbackResult retrieveEntryResult(final WriteEntryCallbackContext context)
-        throws ODataApplicationException {
-      try {
-        final EdmEntityType entityType =
-            context.getSourceEntitySet().getRelatedEntitySet(context.getNavigationProperty()).getEntityType();
-        WriteEntryCallbackResult result = new WriteEntryCallbackResult();
-        Object relatedData;
-        try {
-          relatedData = readRelatedData(context);
-        } catch (final ODataNotFoundException e) {
-          relatedData = null;
-        }
-
-        if (relatedData == null) {
-          result.setEntryData(Collections.<String, Object> emptyMap());
-        } else {
-          result.setEntryData(getStructuralTypeValueMap(relatedData, entityType));
-
-          EntityProviderWriteProperties inlineProperties =
-              EntityProviderWriteProperties.serviceRoot(getContext().getPathInfo().getServiceRoot()).callbacks(
-                  getCallbacks(relatedData, entityType)).expandSelectTree(context.getCurrentExpandSelectTreeNode())
-                  .build();
-          result.setInlineProperties(inlineProperties);
-        }
-        return result;
-      } catch (final ODataException e) {
-        throw new ODataApplicationException(e.getLocalizedMessage(), Locale.ROOT, e);
-      }
-    }
-
-    private Object readRelatedData(final WriteCallbackContext context) throws ODataException {
-      final EdmEntitySet entitySet = context.getSourceEntitySet();
-      return dataSource.readRelatedData(
-          entitySet,
-          data instanceof List ? readEntryData((List<?>) data, entitySet.getEntityType(), context
-              .extractKeyFromEntryData()) : data,
-          entitySet.getRelatedEntitySet(context.getNavigationProperty()),
-          Collections.<String, Object> emptyMap());
-    }
-
-    private <T> T readEntryData(final List<T> data, final EdmEntityType entityType, final Map<String, Object> key)
-        throws ODataException {
-      for (final T entryData : data) {
-        boolean found = true;
-        for (final EdmProperty keyProperty : entityType.getKeyProperties()) {
-          if (!valueAccess.getPropertyValue(entryData, keyProperty).equals(key.get(keyProperty.getName()))) {
-            found = false;
-            break;
-          }
-        }
-        if (found) {
-          return entryData;
-        }
-      }
-      return null;
-    }
-  }
-
-  private <T> ODataResponse writeEntry(final EdmEntitySet entitySet, final ExpandSelectTreeNode expandSelectTree,
-      final T data, final String contentType) throws ODataException, EntityProviderException {
-    final EdmEntityType entityType = entitySet.getEntityType();
-    final Map<String, Object> values = getStructuralTypeValueMap(data, entityType);
-
-    ODataContext context = getContext();
-    EntityProviderWriteProperties writeProperties = EntityProviderWriteProperties
-        .serviceRoot(context.getPathInfo().getServiceRoot())
-        .expandSelectTree(expandSelectTree)
-        .callbacks(getCallbacks(data, entityType))
-        .build();
-
-    final int timingHandle = context.startRuntimeMeasurement("EntityProvider", "writeEntry");
-
-    final ODataResponse response = EntityProvider.writeEntry(contentType, entitySet, values, writeProperties);
-
-    context.stopRuntimeMeasurement(timingHandle);
-
-    return response;
-  }
-
-  private ODataEntry parseEntry(final EdmEntitySet entitySet, final InputStream content,
-      final String requestContentType, final EntityProviderReadProperties properties) throws ODataBadRequestException {
-    ODataContext context = getContext();
-    final int timingHandle = context.startRuntimeMeasurement("EntityConsumer", "readEntry");
-
-    ODataEntry entryValues;
-    try {
-      entryValues = EntityProvider.readEntry(requestContentType, entitySet, content, properties);
-    } catch (final EntityProviderException e) {
-      throw new ODataBadRequestException(ODataBadRequestException.BODY, e);
-    }
-
-    context.stopRuntimeMeasurement(timingHandle);
-
-    return entryValues;
-  }
-
-  private Map<String, Object> parseLink(final EdmEntitySet entitySet, final InputStream content,
-      final String contentType) throws ODataException {
-    ODataContext context = getContext();
-    final int timingHandle = context.startRuntimeMeasurement("EntityProvider", "readLink");
-
-    final String uriString = EntityProvider.readLink(contentType, entitySet, content);
-
-    context.stopRuntimeMeasurement(timingHandle);
-
-    final Map<String, Object> targetKeys = parseLinkUri(entitySet, uriString);
-    if (targetKeys == null) {
-      throw new ODataBadRequestException(ODataBadRequestException.BODY);
-    }
-    return targetKeys;
-  }
-
-  private Map<String, Object> parseLinkUri(final EdmEntitySet targetEntitySet, final String uriString)
-      throws EdmException {
-    ODataContext context = getContext();
-    final int timingHandle = context.startRuntimeMeasurement("UriParser", "getKeyPredicatesFromEntityLink");
-
-    List<KeyPredicate> key = null;
-    try {
-      key = UriParser.getKeyPredicatesFromEntityLink(targetEntitySet, uriString,
-          context.getPathInfo().getServiceRoot());
-    } catch (ODataException e) {
-      // We don't understand the link target. This could also be seen as an error.
-    }
-
-    context.stopRuntimeMeasurement(timingHandle);
-
-    return key == null ? null : mapKey(key);
-  }
-
-  private <T> void createInlinedEntities(final EdmEntitySet entitySet, final T data, final ODataEntry entryValues)
-      throws ODataException {
-    final EdmEntityType entityType = entitySet.getEntityType();
-    for (final String navigationPropertyName : entityType.getNavigationPropertyNames()) {
-
-      final EdmNavigationProperty navigationProperty =
-          (EdmNavigationProperty) entityType.getProperty(navigationPropertyName);
-      final EdmEntitySet relatedEntitySet = entitySet.getRelatedEntitySet(navigationProperty);
-      final EdmEntityType relatedEntityType = relatedEntitySet.getEntityType();
-
-      final Object relatedValue = entryValues.getProperties().get(navigationPropertyName);
-      if (relatedValue == null) {
-        for (final String uriString : entryValues.getMetadata().getAssociationUris(navigationPropertyName)) {
-          final Map<String, Object> key = parseLinkUri(relatedEntitySet, uriString);
-          if (key != null) {
-            dataSource.writeRelation(entitySet, data, relatedEntitySet, key);
-          }
-        }
-
-      } else {
-        if (relatedValue instanceof ODataFeed) {
-          ODataFeed feed = (ODataFeed) relatedValue;
-          final List<ODataEntry> relatedValueList = feed.getEntries();
-          for (final ODataEntry relatedValues : relatedValueList) {
-            Object relatedData = dataSource.newDataObject(relatedEntitySet);
-            setStructuralTypeValuesFromMap(relatedData, relatedEntityType, relatedValues.getProperties(), false);
-            dataSource.createData(relatedEntitySet, relatedData);
-            dataSource.writeRelation(entitySet, data, relatedEntitySet, getStructuralTypeValueMap(relatedData,
-                relatedEntityType));
-            createInlinedEntities(relatedEntitySet, relatedData, relatedValues);
-          }
-        } else if (relatedValue instanceof ODataEntry) {
-          final ODataEntry relatedValueEntry = (ODataEntry) relatedValue;
-          Object relatedData = dataSource.newDataObject(relatedEntitySet);
-          setStructuralTypeValuesFromMap(relatedData, relatedEntityType, relatedValueEntry.getProperties(), false);
-          dataSource.createData(relatedEntitySet, relatedData);
-          dataSource.writeRelation(entitySet, data, relatedEntitySet, getStructuralTypeValueMap(relatedData,
-              relatedEntityType));
-          createInlinedEntities(relatedEntitySet, relatedData, relatedValueEntry);
-        } else {
-          throw new ODataException("Unexpected class for a related value: " + relatedValue.getClass().getSimpleName());
-        }
-
-      }
-    }
-  }
-
-  private <T> Integer applySystemQueryOptions(final EdmEntitySet entitySet, final List<T> data,
-      final FilterExpression filter, final InlineCount inlineCount, final OrderByExpression orderBy,
-      final String skipToken, final Integer skip, final Integer top) throws ODataException {
-    ODataContext context = getContext();
-    final int timingHandle = context.startRuntimeMeasurement(getClass().getSimpleName(), "applySystemQueryOptions");
-
-    if (filter != null) {
-      // Remove all elements the filter does not apply for.
-      // A for-each loop would not work with "remove", see Java documentation.
-      for (Iterator<T> iterator = data.iterator(); iterator.hasNext();) {
-        if (!appliesFilter(iterator.next(), filter)) {
-          iterator.remove();
-        }
-      }
-    }
-
-    final Integer count = inlineCount == InlineCount.ALLPAGES ? data.size() : null;
-
-    if (orderBy != null) {
-      sort(data, orderBy);
-    } else if (skipToken != null || skip != null || top != null) {
-      sortInDefaultOrder(entitySet, data);
-    }
-
-    if (skipToken != null) {
-      while (!data.isEmpty() && !getSkipToken(entitySet, data.get(0)).equals(skipToken)) {
-        data.remove(0);
-      }
-    }
-
-    if (skip != null) {
-      if (skip >= data.size()) {
-        data.clear();
-      } else {
-        for (int i = 0; i < skip; i++) {
-          data.remove(0);
-        }
-      }
-    }
-
-    if (top != null) {
-      while (data.size() > top) {
-        data.remove(top.intValue());
-      }
-    }
-
-    context.stopRuntimeMeasurement(timingHandle);
-
-    return count;
-  }
-
-  private <T> void sort(final List<T> data, final OrderByExpression orderBy) {
-    Collections.sort(data, new Comparator<T>() {
-      @Override
-      public int compare(final T entity1, final T entity2) {
-        try {
-          int result = 0;
-          for (final OrderExpression expression : orderBy.getOrders()) {
-            String first = evaluateExpression(entity1, expression.getExpression());
-            String second = evaluateExpression(entity2, expression.getExpression());
-
-            if (first != null && second != null) {
-              result = first.compareTo(second);
-            } else if (first == null && second != null) {
-              result = 1;
-            } else if (first != null && second == null) {
-              result = -1;
-            }
-
-            if (expression.getSortOrder() == SortOrder.desc) {
-              result = -result;
-            }
-
-            if (result != 0) {
-              break;
-            }
-          }
-          return result;
-        } catch (final ODataException e) {
-          return 0;
-        }
-      }
-    });
-  }
-
-  private <T> void sortInDefaultOrder(final EdmEntitySet entitySet, final List<T> data) {
-    Collections.sort(data, new Comparator<T>() {
-      @Override
-      public int compare(final T entity1, final T entity2) {
-        try {
-          return getSkipToken(entitySet, entity1).compareTo(getSkipToken(entitySet, entity2));
-        } catch (final ODataException e) {
-          return 0;
-        }
-      }
-    });
-  }
-
-  private <T> boolean appliesFilter(final T data, final FilterExpression filter) throws ODataException {
-    ODataContext context = getContext();
-    final int timingHandle = context.startRuntimeMeasurement(getClass().getSimpleName(), "appliesFilter");
-
-    try {
-      return data != null && (filter == null || evaluateExpression(data, filter.getExpression()).equals("true"));
-    } catch (final RuntimeException e) {
-      return false;
-    } finally {
-      context.stopRuntimeMeasurement(timingHandle);
-    }
-  }
-
-  private <T> String evaluateExpression(final T data, final CommonExpression expression) throws ODataException {
-    switch (expression.getKind()) {
-    case UNARY:
-      final UnaryExpression unaryExpression = (UnaryExpression) expression;
-      final String operand = evaluateExpression(data, unaryExpression.getOperand());
-
-      switch (unaryExpression.getOperator()) {
-      case NOT:
-        return Boolean.toString(!Boolean.parseBoolean(operand));
-      case MINUS:
-        return operand.startsWith("-") ? operand.substring(1) : "-" + operand;
-      default:
-        throw new ODataNotImplementedException();
-      }
-
-    case BINARY:
-      final BinaryExpression binaryExpression = (BinaryExpression) expression;
-      final EdmSimpleType type = (EdmSimpleType) binaryExpression.getLeftOperand().getEdmType();
-      final String left = evaluateExpression(data, binaryExpression.getLeftOperand());
-      final String right = evaluateExpression(data, binaryExpression.getRightOperand());
-
-      switch (binaryExpression.getOperator()) {
-      case ADD:
-        if (binaryExpression.getEdmType() == EdmSimpleTypeKind.Decimal.getEdmSimpleTypeInstance()
-            || binaryExpression.getEdmType() == EdmSimpleTypeKind.Double.getEdmSimpleTypeInstance()
-            || binaryExpression.getEdmType() == EdmSimpleTypeKind.Single.getEdmSimpleTypeInstance()) {
-          return Double.toString(Double.valueOf(left) + Double.valueOf(right));
-        } else {
-          return Long.toString(Long.valueOf(left) + Long.valueOf(right));
-        }
-      case SUB:
-        if (binaryExpression.getEdmType() == EdmSimpleTypeKind.Decimal.getEdmSimpleTypeInstance()
-            || binaryExpression.getEdmType() == EdmSimpleTypeKind.Double.getEdmSimpleTypeInstance()
-            || binaryExpression.getEdmType() == EdmSimpleTypeKind.Single.getEdmSimpleTypeInstance()) {
-          return Double.toString(Double.valueOf(left) - Double.valueOf(right));
-        } else {
-          return Long.toString(Long.valueOf(left) - Long.valueOf(right));
-        }
-      case MUL:
-        if (binaryExpression.getEdmType() == EdmSimpleTypeKind.Decimal.getEdmSimpleTypeInstance()
-            || binaryExpression.getEdmType() == EdmSimpleTypeKind.Double.getEdmSimpleTypeInstance()
-            || binaryExpression.getEdmType() == EdmSimpleTypeKind.Single.getEdmSimpleTypeInstance()) {
-          return Double.toString(Double.valueOf(left) * Double.valueOf(right));
-        } else {
-          return Long.toString(Long.valueOf(left) * Long.valueOf(right));
-        }
-      case DIV:
-        final String number = Double.toString(Double.valueOf(left) / Double.valueOf(right));
-        return number.endsWith(".0") ? number.replace(".0", "") : number;
-      case MODULO:
-        if (binaryExpression.getEdmType() == EdmSimpleTypeKind.Decimal.getEdmSimpleTypeInstance()
-            || binaryExpression.getEdmType() == EdmSimpleTypeKind.Double.getEdmSimpleTypeInstance()
-            || binaryExpression.getEdmType() == EdmSimpleTypeKind.Single.getEdmSimpleTypeInstance()) {
-          return Double.toString(Double.valueOf(left) % Double.valueOf(right));
-        } else {
-          return Long.toString(Long.valueOf(left) % Long.valueOf(right));
-        }
-      case AND:
-        return Boolean.toString(left.equals("true") && right.equals("true"));
-      case OR:
-        return Boolean.toString(left.equals("true") || right.equals("true"));
-      case EQ:
-        return Boolean.toString(left.equals(right));
-      case NE:
-        return Boolean.toString(!left.equals(right));
-      case LT:
-        if (type == EdmSimpleTypeKind.String.getEdmSimpleTypeInstance()
-            || type == EdmSimpleTypeKind.DateTime.getEdmSimpleTypeInstance()
-            || type == EdmSimpleTypeKind.DateTimeOffset.getEdmSimpleTypeInstance()
-            || type == EdmSimpleTypeKind.Guid.getEdmSimpleTypeInstance()
-            || type == EdmSimpleTypeKind.Time.getEdmSimpleTypeInstance()) {
-          return Boolean.toString(left.compareTo(right) < 0);
-        } else {
-          return Boolean.toString(Double.valueOf(left) < Double.valueOf(right));
-        }
-      case LE:
-        if (type == EdmSimpleTypeKind.String.getEdmSimpleTypeInstance()
-            || type == EdmSimpleTypeKind.DateTime.getEdmSimpleTypeInstance()
-            || type == EdmSimpleTypeKind.DateTimeOffset.getEdmSimpleTypeInstance()
-            || type == EdmSimpleTypeKind.Guid.getEdmSimpleTypeInstance()
-            || type == EdmSimpleTypeKind.Time.getEdmSimpleTypeInstance()) {
-          return Boolean.toString(left.compareTo(right) <= 0);
-        } else {
-          return Boolean.toString(Double.valueOf(left) <= Double.valueOf(right));
-        }
-      case GT:
-        if (type == EdmSimpleTypeKind.String.getEdmSimpleTypeInstance()
-            || type == EdmSimpleTypeKind.DateTime.getEdmSimpleTypeInstance()
-            || type == EdmSimpleTypeKind.DateTimeOffset.getEdmSimpleTypeInstance()
-            || type == EdmSimpleTypeKind.Guid.getEdmSimpleTypeInstance()
-            || type == EdmSimpleTypeKind.Time.getEdmSimpleTypeInstance()) {
-          return Boolean.toString(left.compareTo(right) > 0);
-        } else {
-          return Boolean.toString(Double.valueOf(left) > Double.valueOf(right));
-        }
-      case GE:
-        if (type == EdmSimpleTypeKind.String.getEdmSimpleTypeInstance()
-            || type == EdmSimpleTypeKind.DateTime.getEdmSimpleTypeInstance()
-            || type == EdmSimpleTypeKind.DateTimeOffset.getEdmSimpleTypeInstance()
-            || type == EdmSimpleTypeKind.Guid.getEdmSimpleTypeInstance()
-            || type == EdmSimpleTypeKind.Time.getEdmSimpleTypeInstance()) {
-          return Boolean.toString(left.compareTo(right) >= 0);
-        } else {
-          return Boolean.toString(Double.valueOf(left) >= Double.valueOf(right));
-        }
-      case PROPERTY_ACCESS:
-        throw new ODataNotImplementedException();
-      default:
-        throw new ODataNotImplementedException();
-      }
-
-    case PROPERTY:
-      final EdmProperty property = (EdmProperty) ((PropertyExpression) expression).getEdmProperty();
-      final EdmSimpleType propertyType = (EdmSimpleType) property.getType();
-      return propertyType.valueToString(valueAccess.getPropertyValue(data, property), EdmLiteralKind.DEFAULT,
-          property.getFacets());
-
-    case MEMBER:
-      final MemberExpression memberExpression = (MemberExpression) expression;
-      final PropertyExpression propertyExpression = (PropertyExpression) memberExpression.getProperty();
-      final EdmProperty memberProperty = (EdmProperty) propertyExpression.getEdmProperty();
-      final EdmSimpleType memberType = (EdmSimpleType) memberExpression.getEdmType();
-      List<EdmProperty> propertyPath = new ArrayList<EdmProperty>();
-      CommonExpression currentExpression = memberExpression;
-      while (currentExpression != null) {
-        final PropertyExpression currentPropertyExpression =
-            (PropertyExpression) (currentExpression.getKind() == ExpressionKind.MEMBER ?
-                ((MemberExpression) currentExpression).getProperty() : currentExpression);
-        final EdmTyped currentProperty = currentPropertyExpression.getEdmProperty();
-        final EdmTypeKind kind = currentProperty.getType().getKind();
-        if (kind == EdmTypeKind.SIMPLE || kind == EdmTypeKind.COMPLEX) {
-          propertyPath.add(0, (EdmProperty) currentProperty);
-        } else {
-          throw new ODataNotImplementedException();
-        }
-        currentExpression =
-            currentExpression.getKind() == ExpressionKind.MEMBER ? ((MemberExpression) currentExpression).getPath()
-                : null;
-      }
-      return memberType.valueToString(getPropertyValue(data, propertyPath), EdmLiteralKind.DEFAULT, memberProperty
-          .getFacets());
-
-    case LITERAL:
-      final LiteralExpression literal = (LiteralExpression) expression;
-      final EdmSimpleType literalType = (EdmSimpleType) literal.getEdmType();
-      return literalType.valueToString(literalType.valueOfString(literal.getUriLiteral(), EdmLiteralKind.URI, null,
-          literalType.getDefaultType()),
-          EdmLiteralKind.DEFAULT, null);
-
-    case METHOD:
-      final MethodExpression methodExpression = (MethodExpression) expression;
-      final String first = evaluateExpression(data, methodExpression.getParameters().get(0));
-      final String second = methodExpression.getParameterCount() > 1 ?
-          evaluateExpression(data, methodExpression.getParameters().get(1)) : null;
-      final String third = methodExpression.getParameterCount() > 2 ?
-          evaluateExpression(data, methodExpression.getParameters().get(2)) : null;
-
-      switch (methodExpression.getMethod()) {
-      case ENDSWITH:
-        return Boolean.toString(first.endsWith(second));
-      case INDEXOF:
-        return Integer.toString(first.indexOf(second));
-      case STARTSWITH:
-        return Boolean.toString(first.startsWith(second));
-      case TOLOWER:
-        return first.toLowerCase(Locale.ROOT);
-      case TOUPPER:
-        return first.toUpperCase(Locale.ROOT);
-      case TRIM:
-        return first.trim();
-      case SUBSTRING:
-        final int offset = Integer.parseInt(second);
-        return first.substring(offset, offset + Integer.parseInt(third));
-      case SUBSTRINGOF:
-        return Boolean.toString(second.contains(first));
-      case CONCAT:
-        return first + second;
-      case LENGTH:
-        return Integer.toString(first.length());
-      case YEAR:
-        return String.valueOf(Integer.parseInt(first.substring(0, 4)));
-      case MONTH:
-        return String.valueOf(Integer.parseInt(first.substring(5, 7)));
-      case DAY:
-        return String.valueOf(Integer.parseInt(first.substring(8, 10)));
-      case HOUR:
-        return String.valueOf(Integer.parseInt(first.substring(11, 13)));
-      case MINUTE:
-        return String.valueOf(Integer.parseInt(first.substring(14, 16)));
-      case SECOND:
-        return String.valueOf(Integer.parseInt(first.substring(17, 19)));
-      case ROUND:
-        return Long.toString(Math.round(Double.valueOf(first)));
-      case FLOOR:
-        return Long.toString(Math.round(Math.floor(Double.valueOf(first))));
-      case CEILING:
-        return Long.toString(Math.round(Math.ceil(Double.valueOf(first))));
-      default:
-        throw new ODataNotImplementedException();
-      }
-
-    default:
-      throw new ODataNotImplementedException();
-    }
-  }
-
-  private <T> String getSkipToken(final EdmEntitySet entitySet, final T data) throws ODataException {
-    String skipToken = "";
-    for (final EdmProperty property : entitySet.getEntityType().getKeyProperties()) {
-      final EdmSimpleType type = (EdmSimpleType) property.getType();
-      skipToken = skipToken.concat(type.valueToString(valueAccess.getPropertyValue(data, property),
-          EdmLiteralKind.DEFAULT, property.getFacets()));
-    }
-    return skipToken;
-  }
-
-  private <T> Object getPropertyValue(final T data, final List<EdmProperty> propertyPath) throws ODataException {
-    Object dataObject = data;
-    for (final EdmProperty property : propertyPath) {
-      if (dataObject != null) {
-        dataObject = valueAccess.getPropertyValue(dataObject, property);
-      }
-    }
-    return dataObject;
-  }
-
-  private void handleMimeType(final Object data, final EdmMapping mapping, final Map<String, Object> valueMap)
-      throws ODataException {
-    final String mimeTypeName = mapping.getMimeType();
-    if (mimeTypeName != null) {
-      Object value = valueAccess.getMappingValue(data, mapping);
-      valueMap.put(mimeTypeName, value);
-      if (mapping.getMediaResourceMimeTypeKey() != null) {
-        valueMap.put(mapping.getMediaResourceMimeTypeKey(), value);
-      }
-    }
-  }
-
-  private <T> Map<String, Object> getSimpleTypeValueMap(final T data, final List<EdmProperty> propertyPath)
-      throws ODataException {
-    final EdmProperty property = propertyPath.get(propertyPath.size() - 1);
-    Map<String, Object> valueWithMimeType = new HashMap<String, Object>();
-    valueWithMimeType.put(property.getName(), getPropertyValue(data, propertyPath));
-
-    handleMimeType(data, property.getMapping(), valueWithMimeType);
-
-    return valueWithMimeType;
-  }
-
-  private <T> Map<String, Object> getStructuralTypeValueMap(final T data, final EdmStructuralType type)
-      throws ODataException {
-    ODataContext context = getContext();
-    final int timingHandle = context.startRuntimeMeasurement(getClass().getSimpleName(), "getStructuralTypeValueMap");
-
-    Map<String, Object> valueMap = new HashMap<String, Object>();
-
-    EdmMapping mapping = type.getMapping();
-    if (mapping != null) {
-      handleMimeType(data, mapping, valueMap);
-    }
-
-    for (final String propertyName : type.getPropertyNames()) {
-      final EdmProperty property = (EdmProperty) type.getProperty(propertyName);
-      final Object value = valueAccess.getPropertyValue(data, property);
-
-      if (property.isSimple()) {
-        if (property.getMapping() == null || property.getMapping().getMimeType() == null) {
-          valueMap.put(propertyName, value);
-        } else {
-          // TODO: enable MIME type mapping outside the current subtree
-          valueMap.put(propertyName, getSimpleTypeValueMap(data, Arrays.asList(property)));
-        }
-      } else {
-        valueMap.put(propertyName, getStructuralTypeValueMap(value, (EdmStructuralType) property.getType()));
-      }
-    }
-
-    context.stopRuntimeMeasurement(timingHandle);
-
-    return valueMap;
-  }
-
-  private <T> Map<String, Object> getStructuralTypeTypeMap(final T data, final EdmStructuralType type)
-      throws ODataException {
-    ODataContext context = getContext();
-    final int timingHandle = context.startRuntimeMeasurement(getClass().getSimpleName(), "getStructuralTypeTypeMap");
-
-    Map<String, Object> typeMap = new HashMap<String, Object>();
-    for (final String propertyName : type.getPropertyNames()) {
-      final EdmProperty property = (EdmProperty) type.getProperty(propertyName);
-      if (property.isSimple()) {
-        typeMap.put(propertyName, valueAccess.getPropertyType(data, property));
-      } else {
-        typeMap.put(propertyName, getStructuralTypeTypeMap(valueAccess.getPropertyValue(data, property),
-            (EdmStructuralType) property.getType()));
-      }
-    }
-
-    context.stopRuntimeMeasurement(timingHandle);
-
-    return typeMap;
-  }
-
-  private <T> void setStructuralTypeValuesFromMap(final T data, final EdmStructuralType type,
-      final Map<String, Object> valueMap, final boolean merge) throws ODataException {
-    ODataContext context = getContext();
-    final int timingHandle =
-        context.startRuntimeMeasurement(getClass().getSimpleName(), "setStructuralTypeValuesFromMap");
-
-    for (final String propertyName : type.getPropertyNames()) {
-      final EdmProperty property = (EdmProperty) type.getProperty(propertyName);
-      if (type instanceof EdmEntityType && ((EdmEntityType) type).getKeyProperties().contains(property)) {
-        Object v = valueAccess.getPropertyValue(data, property);
-        if (v != null) {
-          continue;
-        }
-      }
-
-      if (!merge || valueMap != null && valueMap.containsKey(propertyName)) {
-        final Object value = valueMap == null ? null : valueMap.get(propertyName);
-        if (property.isSimple()) {
-          valueAccess.setPropertyValue(data, property, value);
-        } else {
-          @SuppressWarnings("unchecked")
-          final Map<String, Object> values = (Map<String, Object>) value;
-          setStructuralTypeValuesFromMap(valueAccess.getPropertyValue(data, property),
-              (EdmStructuralType) property.getType(), values, merge);
-        }
-      }
-    }
-
-    context.stopRuntimeMeasurement(timingHandle);
-  }
-
-  @Override
-  public ODataResponse executeBatch(final BatchHandler handler, final String contentType, final InputStream content)
-      throws ODataException {
-    ODataResponse batchResponse;
-    List<BatchResponsePart> batchResponseParts = new ArrayList<BatchResponsePart>();
-    PathInfo pathInfo = getContext().getPathInfo();
-    EntityProviderBatchProperties batchProperties = EntityProviderBatchProperties.init().pathInfo(pathInfo).build();
-    List<BatchRequestPart> batchParts = EntityProvider.parseBatchRequest(contentType, content, batchProperties);
-    for (BatchRequestPart batchPart : batchParts) {
-      batchResponseParts.add(handler.handleBatchPart(batchPart));
-    }
-    batchResponse = EntityProvider.writeBatchResponse(batchResponseParts);
-    return batchResponse;
-  }
-
-  @Override
-  public BatchResponsePart executeChangeSet(final BatchHandler handler, final List<ODataRequest> requests)
-      throws ODataException {
-    List<ODataResponse> responses = new ArrayList<ODataResponse>();
-    for (ODataRequest request : requests) {
-      ODataResponse response = handler.handleRequest(request);
-      if (response.getStatus().getStatusCode() >= HttpStatusCodes.BAD_REQUEST.getStatusCode()) {
-        // Rollback
-        List<ODataResponse> errorResponses = new ArrayList<ODataResponse>(1);
-        errorResponses.add(response);
-        return BatchResponsePart.responses(errorResponses).changeSet(false).build();
-      }
-      responses.add(response);
-    }
-    return BatchResponsePart.responses(responses).changeSet(true).build();
-  }
-}