You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@olingo.apache.org by ra...@apache.org on 2015/02/11 17:45:49 UTC

[3/4] olingo-odata4 git commit: A new service dispatcher mechanism for handling server side requests

http://git-wip-us.apache.org/repos/asf/olingo-odata4/blob/b25fc8c2/lib/server-core-ext/src/main/java/org/apache/olingo/server/core/MetadataParser.java
----------------------------------------------------------------------
diff --git a/lib/server-core-ext/src/main/java/org/apache/olingo/server/core/MetadataParser.java b/lib/server-core-ext/src/main/java/org/apache/olingo/server/core/MetadataParser.java
new file mode 100644
index 0000000..2324648
--- /dev/null
+++ b/lib/server-core-ext/src/main/java/org/apache/olingo/server/core/MetadataParser.java
@@ -0,0 +1,674 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied. See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ */
+package org.apache.olingo.server.core;
+
+import java.io.Reader;
+import java.util.ArrayList;
+import java.util.List;
+
+import javax.xml.namespace.QName;
+import javax.xml.stream.XMLEventReader;
+import javax.xml.stream.XMLInputFactory;
+import javax.xml.stream.XMLStreamException;
+import javax.xml.stream.events.Attribute;
+import javax.xml.stream.events.EndElement;
+import javax.xml.stream.events.StartElement;
+import javax.xml.stream.events.XMLEvent;
+
+import org.apache.olingo.commons.api.edm.FullQualifiedName;
+import org.apache.olingo.commons.api.edm.constants.EdmOnDelete;
+import org.apache.olingo.server.api.edm.provider.Action;
+import org.apache.olingo.server.api.edm.provider.ActionImport;
+import org.apache.olingo.server.api.edm.provider.ComplexType;
+import org.apache.olingo.server.api.edm.provider.EdmProvider;
+import org.apache.olingo.server.api.edm.provider.EntityContainer;
+import org.apache.olingo.server.api.edm.provider.EntitySet;
+import org.apache.olingo.server.api.edm.provider.EntitySetPath;
+import org.apache.olingo.server.api.edm.provider.EntityType;
+import org.apache.olingo.server.api.edm.provider.EnumMember;
+import org.apache.olingo.server.api.edm.provider.EnumType;
+import org.apache.olingo.server.api.edm.provider.Function;
+import org.apache.olingo.server.api.edm.provider.FunctionImport;
+import org.apache.olingo.server.api.edm.provider.NavigationProperty;
+import org.apache.olingo.server.api.edm.provider.NavigationPropertyBinding;
+import org.apache.olingo.server.api.edm.provider.Operation;
+import org.apache.olingo.server.api.edm.provider.Parameter;
+import org.apache.olingo.server.api.edm.provider.Property;
+import org.apache.olingo.server.api.edm.provider.PropertyRef;
+import org.apache.olingo.server.api.edm.provider.ReferentialConstraint;
+import org.apache.olingo.server.api.edm.provider.ReturnType;
+import org.apache.olingo.server.api.edm.provider.Schema;
+import org.apache.olingo.server.api.edm.provider.Singleton;
+import org.apache.olingo.server.api.edm.provider.Term;
+import org.apache.olingo.server.api.edm.provider.TypeDefinition;
+
+public class MetadataParser {
+
+  public EdmProvider buildEdmProvider(Reader csdl) throws XMLStreamException {
+    XMLInputFactory xmlInputFactory = XMLInputFactory.newInstance();
+    XMLEventReader reader = xmlInputFactory.createXMLEventReader(csdl);
+
+    SchemaBasedEdmProvider provider = new SchemaBasedEdmProvider();
+    new ElementReader<SchemaBasedEdmProvider>() {
+      @Override
+      void build(XMLEventReader reader, StartElement element, SchemaBasedEdmProvider provider,
+          String name) throws XMLStreamException {
+        String version = attr(element, "Version");
+        if (version.equals("4.0")) {
+          readDataServicesAndReference(reader, element, provider);
+        }
+      }
+    }.read(reader, null, provider, "Edmx");
+
+    return provider;
+  }
+
+  private void readDataServicesAndReference(XMLEventReader reader, StartElement element,
+      SchemaBasedEdmProvider provider) throws XMLStreamException {
+    new ElementReader<SchemaBasedEdmProvider>() {
+      @Override
+      void build(XMLEventReader reader, StartElement element, SchemaBasedEdmProvider provider,
+          String name) throws XMLStreamException {
+        if (name.equals("DataServices")) {
+          readSchema(reader, element, provider);
+        } else if (name.equals("Reference")) {
+          readReference(reader, element, provider, "Reference");
+        }
+      }
+    }.read(reader, element, provider, "DataServices", "Reference");
+  }
+
+  private void readReference(XMLEventReader reader, StartElement element,
+      SchemaBasedEdmProvider provider, String name) throws XMLStreamException {
+    new ElementReader<SchemaBasedEdmProvider>() {
+      @Override
+      void build(XMLEventReader reader, StartElement element, SchemaBasedEdmProvider t, String name)
+          throws XMLStreamException {
+        // TODO:
+      }
+    }.read(reader, element, provider, name);
+  }
+
+  private void readSchema(XMLEventReader reader, StartElement element,
+      SchemaBasedEdmProvider provider) throws XMLStreamException {
+
+    Schema schema = new Schema();
+    schema.setComplexTypes(new ArrayList<ComplexType>());
+    schema.setActions(new ArrayList<Action>());
+    schema.setEntityTypes(new ArrayList<EntityType>());
+    schema.setEnumTypes(new ArrayList<EnumType>());
+    schema.setFunctions(new ArrayList<Function>());
+    schema.setTerms(new ArrayList<Term>());
+    schema.setTypeDefinitions(new ArrayList<TypeDefinition>());
+
+    new ElementReader<Schema>() {
+      @Override
+      void build(XMLEventReader reader, StartElement element, Schema schema, String name)
+          throws XMLStreamException {
+        schema.setNamespace(attr(element, "Namespace"));
+        schema.setAlias(attr(element, "Alias"));
+        readSchemaContents(reader, schema);
+      }
+    }.read(reader, element, schema, "Schema");
+    provider.addSchema(schema);
+  }
+
+  private void readSchemaContents(XMLEventReader reader, Schema schema) throws XMLStreamException {
+    new ElementReader<Schema>() {
+      @Override
+      void build(XMLEventReader reader, StartElement element, Schema schema, String name)
+          throws XMLStreamException {
+        if (name.equals("Action")) {
+          readAction(reader, element, schema);
+        } else if (name.equals("Annotations")) {
+          // TODO:
+        } else if (name.equals("Annotation")) {
+          // TODO:
+        } else if (name.equals("ComplexType")) {
+          readComplexType(reader, element, schema);
+        } else if (name.equals("EntityContainer")) {
+          readEntityContainer(reader, element, schema);
+        } else if (name.equals("EntityType")) {
+          readEntityType(reader, element, schema);
+        } else if (name.equals("EnumType")) {
+          readEnumType(reader, element, schema);
+        } else if (name.equals("Function")) {
+          readFunction(reader, element, schema);
+        } else if (name.equals("Term")) {
+          schema.getTerms().add(readTerm(element));
+        } else if (name.equals("TypeDefinition")) {
+          schema.getTypeDefinitions().add(readTypeDefinition(element));
+        }
+      }
+    }.read(reader, null, schema, "Action", "Annotations", "Annotation", "ComplexType",
+        "EntityContainer", "EntityType", "EnumType", "Function", "Term", "TypeDefinition");
+  }
+
+  private void readAction(XMLEventReader reader, StartElement element, Schema schema)
+      throws XMLStreamException {
+
+    Action action = new Action();
+    action.setParameters(new ArrayList<Parameter>());
+    action.setName(attr(element, "Name"));
+    action.setBound(Boolean.parseBoolean(attr(element, "IsBound")));
+    String entitySetPath = attr(element, "EntitySetPath");
+    if (entitySetPath != null) {
+      // TODO: need to parse into binding and path.
+      action.setEntitySetPath(new EntitySetPath().setPath(entitySetPath));
+    }
+    readOperationParameters(reader, action);
+    schema.getActions().add(action);
+  }
+
+  private FullQualifiedName readType(StartElement element) {
+    String type = attr(element, "Type");
+    if (type.startsWith("Collection(") && type.endsWith(")")) {
+      return new FullQualifiedName(type.substring(11, type.length() - 1));
+    }
+    return new FullQualifiedName(type);
+  }
+
+  private boolean isCollectionType(StartElement element) {
+    String type = attr(element, "Type");
+    if (type.startsWith("Collection(") && type.endsWith(")")) {
+      return true;
+    }
+    return false;
+  }
+
+  private void readReturnType(StartElement element, Operation operation) {
+    ReturnType returnType = new ReturnType();
+    returnType.setType(readType(element));
+    returnType.setCollection(isCollectionType(element));
+    returnType.setNullable(Boolean.parseBoolean(attr(element, "Nullable")));
+
+    String maxLength = attr(element, "MaxLength");
+    if (maxLength != null) {
+      returnType.setMaxLength(Integer.parseInt(maxLength));
+    }
+    String precision = attr(element, "Precision");
+    if (precision != null) {
+      returnType.setPrecision(Integer.parseInt(precision));
+    }
+    String scale = attr(element, "Scale");
+    if (scale != null) {
+      returnType.setScale(Integer.parseInt(scale));
+    }
+    String srid = attr(element, "SRID");
+    if (srid != null) {
+      // TODO: no olingo support yet.
+    }
+    operation.setReturnType(returnType);
+  }
+
+  private void readParameter(StartElement element, Operation operation) {
+    Parameter parameter = new Parameter();
+    parameter.setName(attr(element, "Name"));
+    parameter.setType(readType(element));
+    parameter.setCollection(isCollectionType(element));
+    parameter.setNullable(Boolean.parseBoolean(attr(element, "Nullable")));
+
+    String maxLength = attr(element, "MaxLength");
+    if (maxLength != null) {
+      parameter.setMaxLength(Integer.parseInt(maxLength));
+    }
+    String precision = attr(element, "Precision");
+    if (precision != null) {
+      parameter.setPrecision(Integer.parseInt(precision));
+    }
+    String scale = attr(element, "Scale");
+    if (scale != null) {
+      parameter.setScale(Integer.parseInt(scale));
+    }
+    String srid = attr(element, "SRID");
+    if (srid != null) {
+      // TODO: no olingo support yet.
+    }
+    operation.getParameters().add(parameter);
+  }
+
+  private TypeDefinition readTypeDefinition(StartElement element) {
+    TypeDefinition td = new TypeDefinition();
+    td.setName(attr(element, "Name"));
+    td.setUnderlyingType(new FullQualifiedName(attr(element, "UnderlyingType")));
+    td.setIsUnicode(Boolean.parseBoolean(attr(element, "Unicode")));
+
+    String maxLength = attr(element, "MaxLength");
+    if (maxLength != null) {
+      td.setMaxLength(Integer.parseInt(maxLength));
+    }
+    String precision = attr(element, "Precision");
+    if (precision != null) {
+      td.setPrecision(Integer.parseInt(precision));
+    }
+    String scale = attr(element, "Scale");
+    if (scale != null) {
+      td.setScale(Integer.parseInt(scale));
+    }
+    String srid = attr(element, "SRID");
+    if (srid != null) {
+      // TODO: no olingo support yet.
+    }
+    return td;
+  }
+
+  private Term readTerm(StartElement element) {
+    Term term = new Term();
+    term.setName(attr(element, "Name"));
+    term.setType(new FullQualifiedName(attr(element, "Type")));
+    if (attr(element, "BaseTerm") != null) {
+      term.setBaseTerm(new FullQualifiedName(attr(element, "BaseTerm")));
+    }
+    if (attr(element, "DefaultValue") != null) {
+      term.setDefaultValue(attr(element, "DefaultValue"));
+    }
+    if (attr(element, "AppliesTo") != null) {
+      term.setAppliesTo(attr(element, "AppliesTo"));
+    }
+    term.setNullable(Boolean.parseBoolean(attr(element, "Nullable")));
+    String maxLength = attr(element, "MaxLength");
+    if (maxLength != null) {
+      term.setMaxLength(Integer.parseInt(maxLength));
+    }
+    String precision = attr(element, "Precision");
+    if (precision != null) {
+      term.setPrecision(Integer.parseInt(precision));
+    }
+    String scale = attr(element, "Scale");
+    if (scale != null) {
+      term.setScale(Integer.parseInt(scale));
+    }
+    String srid = attr(element, "SRID");
+    if (srid != null) {
+      // TODO: no olingo support yet.
+    }
+    return term;
+  }
+
+  private void readFunction(XMLEventReader reader, StartElement element, Schema schema)
+      throws XMLStreamException {
+    Function function = new Function();
+    function.setParameters(new ArrayList<Parameter>());
+    function.setName(attr(element, "Name"));
+    function.setBound(Boolean.parseBoolean(attr(element, "IsBound")));
+    function.setComposable(Boolean.parseBoolean(attr(element, "IsComposable")));
+    String entitySetPath = attr(element, "EntitySetPath");
+    if (entitySetPath != null) {
+      // TODO: need to parse into binding and path.
+      function.setEntitySetPath(new EntitySetPath().setPath(entitySetPath));
+    }
+    readOperationParameters(reader, function);
+    schema.getFunctions().add(function);
+  }
+
+  private void readOperationParameters(XMLEventReader reader, final Operation operation)
+      throws XMLStreamException {
+    new ElementReader<Operation>() {
+      @Override
+      void build(XMLEventReader reader, StartElement element, Operation operation, String name)
+          throws XMLStreamException {
+        if (name.equals("Parameter")) {
+          readParameter(element, operation);
+        } else if (name.equals("ReturnType")) {
+          readReturnType(element, operation);
+        }
+      }
+    }.read(reader, null, operation, "Parameter", "ReturnType");
+  }
+
+  private void readEnumType(XMLEventReader reader, StartElement element, Schema schema)
+      throws XMLStreamException {
+    EnumType type = new EnumType();
+    type.setMembers(new ArrayList<EnumMember>());
+    type.setName(attr(element, "Name"));
+    if (attr(element, "UnderlyingType") != null) {
+      type.setUnderlyingType(new FullQualifiedName(attr(element, "UnderlyingType")));
+    }
+    type.setFlags(Boolean.parseBoolean(attr(element, "IsFlags")));
+
+    readEnumMembers(reader, element, type);
+    schema.getEnumTypes().add(type);
+  }
+
+  private void readEnumMembers(XMLEventReader reader, StartElement element, EnumType type)
+      throws XMLStreamException {
+    new ElementReader<EnumType>() {
+      @Override
+      void build(XMLEventReader reader, StartElement element, EnumType type, String name)
+          throws XMLStreamException {
+        EnumMember member = new EnumMember();
+        member.setName(attr(element, "Name"));
+        member.setValue(attr(element, "Value"));
+        type.getMembers().add(member);
+      }
+    }.read(reader, element, type, "Member");
+  }
+
+  private void readEntityType(XMLEventReader reader, StartElement element, Schema schema)
+      throws XMLStreamException {
+    EntityType entityType = new EntityType();
+    entityType.setProperties(new ArrayList<Property>());
+    entityType.setNavigationProperties(new ArrayList<NavigationProperty>());
+    entityType.setKey(new ArrayList<PropertyRef>());
+    entityType.setName(attr(element, "Name"));
+    if (attr(element, "BaseType") != null) {
+      entityType.setBaseType(new FullQualifiedName(attr(element, "BaseType")));
+    }
+    entityType.setAbstract(Boolean.parseBoolean(attr(element, "Abstract")));
+    entityType.setOpenType(Boolean.parseBoolean(attr(element, "OpenType")));
+    entityType.setHasStream(Boolean.parseBoolean(attr(element, "HasStream")));
+    readEntityProperties(reader, entityType);
+    schema.getEntityTypes().add(entityType);
+  }
+
+  private void readEntityProperties(XMLEventReader reader, EntityType entityType)
+      throws XMLStreamException {
+    new ElementReader<EntityType>() {
+      @Override
+      void build(XMLEventReader reader, StartElement element, EntityType entityType, String name)
+          throws XMLStreamException {
+        if (name.equals("Property")) {
+          entityType.getProperties().add(readProperty(element));
+        } else if (name.equals("NavigationProperty")) {
+          entityType.getNavigationProperties().add(readNavigationProperty(reader, element));
+        } else if (name.equals("Key")) {
+          readKey(reader, element, entityType);
+        }
+      }
+    }.read(reader, null, entityType, "Property", "NavigationProperty", "Key");
+  }
+
+  private void readKey(XMLEventReader reader, StartElement element, EntityType entityType)
+      throws XMLStreamException {
+    new ElementReader<EntityType>() {
+      @Override
+      void build(XMLEventReader reader, StartElement element, EntityType entityType, String name)
+          throws XMLStreamException {
+        PropertyRef ref = new PropertyRef();
+        ref.setName(attr(element, "Name"));
+        ref.setAlias(attr(element, "Alias"));
+        entityType.getKey().add(ref);
+      }
+    }.read(reader, element, entityType, "PropertyRef");
+  }
+
+  private NavigationProperty readNavigationProperty(XMLEventReader reader, StartElement element)
+      throws XMLStreamException {
+    NavigationProperty property = new NavigationProperty();
+    property.setReferentialConstraints(new ArrayList<ReferentialConstraint>());
+
+    property.setName(attr(element, "Name"));
+    property.setType(readType(element));
+    property.setCollection(isCollectionType(element));
+    property.setNullable(Boolean.parseBoolean(attr(element, "Nullable")));
+    property.setPartner(attr(element, "Partner"));
+    property.setContainsTarget(Boolean.parseBoolean(attr(element, "ContainsTarget")));
+
+    new ElementReader<NavigationProperty>() {
+      @Override
+      void build(XMLEventReader reader, StartElement element, NavigationProperty property,
+          String name) throws XMLStreamException {
+        if (name.equals("ReferentialConstraint")) {
+          ReferentialConstraint constraint = new ReferentialConstraint();
+          constraint.setProperty(attr(element, "Property"));
+          constraint.setReferencedProperty(attr(element, "ReferencedProperty"));
+          property.getReferentialConstraints().add(constraint);
+        } else if (name.equals("OnDelete")) {
+          property.setOnDelete(EdmOnDelete.valueOf(attr(element, "Action")));
+        }
+      }
+    }.read(reader, element, property, "ReferentialConstraint", "OnDelete");
+    return property;
+  }
+
+  private String attr(StartElement element, String name) {
+    Attribute attr = element.getAttributeByName(new QName(name));
+    if (attr != null) {
+      return attr.getValue();
+    }
+    return null;
+  }
+
+  private Property readProperty(StartElement element) {
+    Property property = new Property();
+    property.setName(attr(element, "Name"));
+    property.setType(readType(element));
+    property.setCollection(isCollectionType(element));
+    property.setNullable(Boolean.parseBoolean(attr(element, "Nullable")));
+    property.setUnicode(Boolean.parseBoolean(attr(element, "Unicode")));
+
+    String maxLength = attr(element, "MaxLength");
+    if (maxLength != null) {
+      property.setMaxLength(Integer.parseInt(maxLength));
+    }
+    String precision = attr(element, "Precision");
+    if (precision != null) {
+      property.setPrecision(Integer.parseInt(precision));
+    }
+    String scale = attr(element, "Scale");
+    if (scale != null) {
+      property.setScale(Integer.parseInt(scale));
+    }
+    String srid = attr(element, "SRID");
+    if (srid != null) {
+      // TODO: no olingo support yet.
+    }
+    String defaultValue = attr(element, "DefaultValue");
+    if (defaultValue != null) {
+      property.setDefaultValue(defaultValue);
+    }
+    return property;
+  }
+
+  private void readEntityContainer(XMLEventReader reader, StartElement element, Schema schema)
+      throws XMLStreamException {
+    final EntityContainer container = new EntityContainer();
+    container.setName(attr(element, "Name"));
+    if (attr(element, "Extends") != null) {
+      container.setExtendsContainer(new FullQualifiedName(attr(element, "Extends")));
+    }
+    container.setActionImports(new ArrayList<ActionImport>());
+    container.setFunctionImports(new ArrayList<FunctionImport>());
+    container.setEntitySets(new ArrayList<EntitySet>());
+    container.setSingletons(new ArrayList<Singleton>());
+
+    new ElementReader<Schema>() {
+      @Override
+      void build(XMLEventReader reader, StartElement element, Schema schema, String name)
+          throws XMLStreamException {
+        if (name.equals("EntitySet")) {
+          readEntitySet(reader, element, container);
+        } else if (name.equals("Singleton")) {
+          readSingleton(reader, element, container);
+        } else if (name.equals("ActionImport")) {
+          readActionImport(element, container);
+        } else if (name.equals("FunctionImport")) {
+          readFunctionImport(element, container);
+        }
+      }
+
+      private void readFunctionImport(StartElement element, EntityContainer container) {
+        FunctionImport functionImport = new FunctionImport();
+        functionImport.setName(attr(element, "Name"));
+        functionImport.setFunction(new FullQualifiedName(attr(element, "Function")));
+        functionImport.setIncludeInServiceDocument(Boolean.parseBoolean(attr(element,
+            "IncludeInServiceDocument")));
+
+        String entitySet = attr(element, "EntitySet");
+        if (entitySet != null) {
+          functionImport.setEntitySet(new org.apache.olingo.server.core.Target(entitySet));
+        }
+        container.getFunctionImports().add(functionImport);
+      }
+
+      private void readActionImport(StartElement element, EntityContainer container) {
+        ActionImport actionImport = new ActionImport();
+        actionImport.setName(attr(element, "Name"));
+        actionImport.setAction(new FullQualifiedName(attr(element, "Action")));
+
+        String entitySet = attr(element, "EntitySet");
+        if (entitySet != null) {
+          actionImport.setEntitySet(new org.apache.olingo.server.core.Target(entitySet));
+        }
+        container.getActionImports().add(actionImport);
+      }
+
+      private void readSingleton(XMLEventReader reader, StartElement element,
+          EntityContainer container) throws XMLStreamException {
+        Singleton singleton = new Singleton();
+        singleton.setNavigationPropertyBindings(new ArrayList<NavigationPropertyBinding>());
+        singleton.setName(attr(element, "Name"));
+        singleton.setType(new FullQualifiedName(attr(element, "Type")));
+        singleton.setNavigationPropertyBindings(new ArrayList<NavigationPropertyBinding>());
+        readNavigationPropertyBindings(reader, element, singleton.getNavigationPropertyBindings());
+        container.getSingletons().add(singleton);
+      }
+
+      private void readEntitySet(XMLEventReader reader, StartElement element,
+          EntityContainer container) throws XMLStreamException {
+        EntitySet entitySet = new EntitySet();
+        entitySet.setName(attr(element, "Name"));
+        entitySet.setType(new FullQualifiedName(attr(element, "EntityType")));
+        entitySet.setIncludeInServiceDocument(Boolean.parseBoolean(attr(element,
+            "IncludeInServiceDocument")));
+        entitySet.setNavigationPropertyBindings(new ArrayList<NavigationPropertyBinding>());
+        readNavigationPropertyBindings(reader, element, entitySet.getNavigationPropertyBindings());
+        container.getEntitySets().add(entitySet);
+      }
+
+      private void readNavigationPropertyBindings(XMLEventReader reader, StartElement element,
+          List<NavigationPropertyBinding> bindings) throws XMLStreamException {
+        new ElementReader<List<NavigationPropertyBinding>>() {
+          @Override
+          void build(XMLEventReader reader, StartElement element,
+              List<NavigationPropertyBinding> bindings, String name) throws XMLStreamException {
+            NavigationPropertyBinding binding = new NavigationPropertyBinding();
+            binding.setPath(attr(element, "Path"));
+            binding.setTarget(new org.apache.olingo.server.core.Target(attr(element, "Target")));
+            bindings.add(binding);
+          }
+
+        }.read(reader, element, bindings, "NavigationPropertyBinding");
+        ;
+      }
+    }.read(reader, element, schema, "EntitySet", "Singleton", "ActionImport", "FunctionImport");
+    schema.setEntityContainer(container);
+  }
+
+  private void readComplexType(XMLEventReader reader, StartElement element, Schema schema)
+      throws XMLStreamException {
+    ComplexType complexType = new ComplexType();
+    complexType.setProperties(new ArrayList<Property>());
+    complexType.setNavigationProperties(new ArrayList<NavigationProperty>());
+    complexType.setName(attr(element, "Name"));
+    if (attr(element, "BaseType") != null) {
+      complexType.setBaseType(new FullQualifiedName(attr(element, "BaseType")));
+    }
+    complexType.setAbstract(Boolean.parseBoolean(attr(element, "Abstract")));
+    complexType.setOpenType(Boolean.parseBoolean(attr(element, "OpenType")));
+    readProperties(reader, complexType);
+
+    schema.getComplexTypes().add(complexType);
+  }
+
+  private void readProperties(XMLEventReader reader, ComplexType complexType)
+      throws XMLStreamException {
+    new ElementReader<ComplexType>() {
+      @Override
+      void build(XMLEventReader reader, StartElement element, ComplexType complexType, String name)
+          throws XMLStreamException {
+        if (name.equals("Property")) {
+          complexType.getProperties().add(readProperty(element));
+        } else if (name.equals("NavigationProperty")) {
+          complexType.getNavigationProperties().add(readNavigationProperty(reader, element));
+        }
+      }
+    }.read(reader, null, complexType, "Property", "NavigationProperty");
+  }
+
+  abstract class ElementReader<T> {
+    void read(XMLEventReader reader, StartElement element, T t, String... names)
+        throws XMLStreamException {
+      while (reader.hasNext()) {
+        XMLEvent event = reader.peek();
+
+        event = skipAnnotations(reader, event);
+
+        if (!event.isStartElement() && !event.isEndElement()) {
+          reader.nextEvent();
+          continue;
+        }
+
+        boolean hit = false;
+
+        for (int i = 0; i < names.length; i++) {
+          if (event.isStartElement()) {
+            element = event.asStartElement();
+            if (element.getName().getLocalPart().equals(names[i])) {
+              reader.nextEvent(); // advance cursor
+              // System.out.println("reading = "+names[i]);
+              build(reader, element, t, names[i]);
+              hit = true;
+            }
+          }
+          if (event.isEndElement()) {
+            EndElement e = event.asEndElement();
+            if (e.getName().getLocalPart().equals(names[i])) {
+              reader.nextEvent(); // advance cursor
+              // System.out.println("done reading = "+names[i]);
+              hit = true;
+            }
+          }
+        }
+        if (!hit) {
+          break;
+        }
+      }
+    }
+
+    private XMLEvent skipAnnotations(XMLEventReader reader, XMLEvent event)
+        throws XMLStreamException {
+      boolean skip = false;
+
+      while (reader.hasNext()) {
+        if (event.isStartElement()) {
+          StartElement element = event.asStartElement();
+          if (element.getName().getLocalPart().equals("Annotation")) {
+            skip = true;
+          }
+        }
+        if (event.isEndElement()) {
+          EndElement element = event.asEndElement();
+          if (element.getName().getLocalPart().equals("Annotation")) {
+            return reader.peek();
+          }
+        }
+        if (skip) {
+          event = reader.nextEvent();
+        } else {
+          return event;
+        }
+      }
+      return event;
+    }
+
+    abstract void build(XMLEventReader reader, StartElement element, T t, String name)
+        throws XMLStreamException;
+  }
+}

http://git-wip-us.apache.org/repos/asf/olingo-odata4/blob/b25fc8c2/lib/server-core-ext/src/main/java/org/apache/olingo/server/core/MetadataRequest.java
----------------------------------------------------------------------
diff --git a/lib/server-core-ext/src/main/java/org/apache/olingo/server/core/MetadataRequest.java b/lib/server-core-ext/src/main/java/org/apache/olingo/server/core/MetadataRequest.java
new file mode 100644
index 0000000..49735cb
--- /dev/null
+++ b/lib/server-core-ext/src/main/java/org/apache/olingo/server/core/MetadataRequest.java
@@ -0,0 +1,57 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied. See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ */
+package org.apache.olingo.server.core;
+
+import org.apache.olingo.commons.api.format.ContentType;
+import org.apache.olingo.server.api.OData;
+import org.apache.olingo.server.api.ODataApplicationException;
+import org.apache.olingo.server.api.ODataResponse;
+import org.apache.olingo.server.api.ODataTranslatedException;
+import org.apache.olingo.server.api.ServiceMetadata;
+import org.apache.olingo.server.api.serializer.RepresentationType;
+import org.apache.olingo.server.api.uri.UriInfoMetadata;
+
+public class MetadataRequest extends ServiceRequest {
+
+  public MetadataRequest(OData odata, ServiceMetadata serviceMetadata) {
+    super(odata, serviceMetadata);
+  }
+
+  @Override
+  public ContentType getResponseContentType() throws ContentNegotiatorException {
+    return ContentNegotiator.doContentNegotiation(this.uriInfo.getFormatOption(), this.request,
+        this.customContentType, RepresentationType.METADATA);
+  }
+
+  public UriInfoMetadata getUriInfoMetadata() {
+    return uriInfo.asUriInfoMetadata();
+  }
+
+  @Override
+  public void execute(ServiceHandler handler, ODataResponse response)
+      throws ODataTranslatedException, ODataApplicationException {
+
+    if (!allowedMethod()) {
+      methodNotAllowed();
+    }
+
+    handler.readMetadata(this, MetadataResponse.getinstance(this, response));
+  }
+
+}

http://git-wip-us.apache.org/repos/asf/olingo-odata4/blob/b25fc8c2/lib/server-core-ext/src/main/java/org/apache/olingo/server/core/MetadataResponse.java
----------------------------------------------------------------------
diff --git a/lib/server-core-ext/src/main/java/org/apache/olingo/server/core/MetadataResponse.java b/lib/server-core-ext/src/main/java/org/apache/olingo/server/core/MetadataResponse.java
new file mode 100644
index 0000000..aac7d84
--- /dev/null
+++ b/lib/server-core-ext/src/main/java/org/apache/olingo/server/core/MetadataResponse.java
@@ -0,0 +1,56 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied. See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ */
+package org.apache.olingo.server.core;
+
+import org.apache.olingo.commons.api.format.ContentType;
+import org.apache.olingo.server.api.ODataApplicationException;
+import org.apache.olingo.server.api.ODataResponse;
+import org.apache.olingo.server.api.ODataTranslatedException;
+import org.apache.olingo.server.api.ServiceMetadata;
+import org.apache.olingo.server.api.serializer.ODataSerializer;
+import org.apache.olingo.server.api.serializer.SerializerException;
+
+public class MetadataResponse extends ServiceResponse {
+  private final ODataSerializer serializer;
+  private final ContentType responseContentType;
+
+  public static MetadataResponse getinstance(ServiceRequest request, ODataResponse response)
+      throws ContentNegotiatorException, SerializerException {
+    return new MetadataResponse(response, request.getSerializer(), request.getResponseContentType());
+  }
+
+  private MetadataResponse(ODataResponse response, ODataSerializer serializer, ContentType responseContentType) {
+    super(response);
+    this.serializer = serializer;
+    this.responseContentType = responseContentType;
+  }
+
+  public void writeMetadata(ServiceMetadata metadata)throws ODataTranslatedException {
+    assert (!isClosed());
+    this.response.setContent(this.serializer.metadataDocument(metadata));
+    writeOK(this.responseContentType.toContentTypeString());
+    close();
+  }
+
+  @Override
+  public void accepts(ServiceResponseVisior visitor) throws ODataTranslatedException,
+      ODataApplicationException {
+    visitor.visit(this);
+  }
+}

http://git-wip-us.apache.org/repos/asf/olingo-odata4/blob/b25fc8c2/lib/server-core-ext/src/main/java/org/apache/olingo/server/core/NoContentResponse.java
----------------------------------------------------------------------
diff --git a/lib/server-core-ext/src/main/java/org/apache/olingo/server/core/NoContentResponse.java b/lib/server-core-ext/src/main/java/org/apache/olingo/server/core/NoContentResponse.java
new file mode 100644
index 0000000..7bf0c21
--- /dev/null
+++ b/lib/server-core-ext/src/main/java/org/apache/olingo/server/core/NoContentResponse.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.server.core;
+
+import org.apache.olingo.commons.api.http.HttpStatusCode;
+import org.apache.olingo.server.api.ODataApplicationException;
+import org.apache.olingo.server.api.ODataResponse;
+import org.apache.olingo.server.api.ODataTranslatedException;
+
+public class NoContentResponse extends ServiceResponse {
+
+  public NoContentResponse(ODataResponse response) {
+    super(response);
+  }
+
+  // 200
+  public void writeOK() {
+    this.response.setStatusCode(HttpStatusCode.OK.getStatusCode());
+    close();
+  }
+
+  // 201
+  public void writeCreated() {
+    this.response.setStatusCode(HttpStatusCode.CREATED.getStatusCode());
+    close();
+  }
+
+  // 202
+  public void writeAccepted() {
+    this.response.setStatusCode(HttpStatusCode.ACCEPTED.getStatusCode());
+    close();
+  }
+
+  // 204
+  public void writeNoContent() {
+    writeNoContent(true);
+  }
+
+  // 304
+  public void writeNotModified() {
+    this.response.setStatusCode(HttpStatusCode.NOT_MODIFIED.getStatusCode());
+    close();
+  }
+
+  // error response codes
+
+  // 404
+  public void writeNotFound() {
+    writeNotFound(true);
+  }
+
+  // 501
+  public void writeNotImplemented() {
+    this.response.setStatusCode(HttpStatusCode.NOT_IMPLEMENTED.getStatusCode());
+    close();
+  }
+
+  // 405
+  public void writeMethodNotAllowed() {
+    this.response.setStatusCode(HttpStatusCode.METHOD_NOT_ALLOWED.getStatusCode());
+    close();
+  }
+
+  // 410
+  public void writeGone() {
+    this.response.setStatusCode(HttpStatusCode.GONE.getStatusCode());
+    close();
+  }
+
+  // 412
+  public void writePreConditionFailed() {
+    this.response.setStatusCode(HttpStatusCode.PRECONDITION_FAILED.getStatusCode());
+    close();
+  }
+
+  @Override
+  public void accepts(ServiceResponseVisior visitor) throws ODataTranslatedException,
+      ODataApplicationException {
+    visitor.visit(this);
+  }
+}

http://git-wip-us.apache.org/repos/asf/olingo-odata4/blob/b25fc8c2/lib/server-core-ext/src/main/java/org/apache/olingo/server/core/OData4HttpHandler.java
----------------------------------------------------------------------
diff --git a/lib/server-core-ext/src/main/java/org/apache/olingo/server/core/OData4HttpHandler.java b/lib/server-core-ext/src/main/java/org/apache/olingo/server/core/OData4HttpHandler.java
new file mode 100644
index 0000000..bc93eeb
--- /dev/null
+++ b/lib/server-core-ext/src/main/java/org/apache/olingo/server/core/OData4HttpHandler.java
@@ -0,0 +1,111 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied. See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ */
+package org.apache.olingo.server.core;
+
+import java.io.IOException;
+
+import javax.servlet.http.HttpServletRequest;
+import javax.servlet.http.HttpServletResponse;
+
+import org.apache.olingo.commons.api.edm.constants.ODataServiceVersion;
+import org.apache.olingo.commons.api.http.HttpHeader;
+import org.apache.olingo.server.api.OData;
+import org.apache.olingo.server.api.ODataRequest;
+import org.apache.olingo.server.api.ODataResponse;
+import org.apache.olingo.server.api.ODataTranslatedException;
+import org.apache.olingo.server.api.ServiceMetadata;
+import org.apache.olingo.server.api.processor.Processor;
+import org.apache.olingo.server.api.serializer.CustomContentTypeSupport;
+import org.apache.olingo.server.api.serializer.SerializerException;
+
+public class OData4HttpHandler extends ODataHttpHandlerImpl {
+  private ServiceHandler handler;
+  private final ServiceMetadata serviceMetadata;
+  private final OData odata;
+  private CustomContentTypeSupport customContentTypeSupport;
+
+  public OData4HttpHandler(OData odata, ServiceMetadata serviceMetadata) {
+    super(odata, serviceMetadata);
+    this.odata = odata;
+    this.serviceMetadata = serviceMetadata;
+  }
+
+  @Override
+  public void process(final HttpServletRequest httpRequest, final HttpServletResponse httpResponse) {
+    ODataRequest request = null;
+    ODataResponse response = new ODataResponse();
+
+    try {
+      request = createODataRequest(httpRequest, 0);
+      validateODataVersion(request, response);
+
+      ServiceDispatcher dispatcher = new ServiceDispatcher(this.odata, this.serviceMetadata,
+          handler, this.customContentTypeSupport);
+      dispatcher.execute(request, response);
+
+    } catch (Exception e) {
+      ErrorHandler handler = new ErrorHandler(this.odata, this.serviceMetadata,
+          this.customContentTypeSupport);
+      handler.handleException(e, request, response);
+    }
+    convertToHttp(httpResponse, response);
+  }
+
+
+  ODataRequest createODataRequest(final HttpServletRequest httpRequest, final int split)
+      throws ODataTranslatedException {
+    try {
+      ODataRequest odRequest = new ODataRequest();
+
+      odRequest.setBody(httpRequest.getInputStream());
+      extractHeaders(odRequest, httpRequest);
+      extractMethod(odRequest, httpRequest);
+      extractUri(odRequest, httpRequest, split);
+
+      return odRequest;
+    } catch (final IOException e) {
+      throw new SerializerException(
+          "An I/O exception occurred.", e, SerializerException.MessageKeys.IO_EXCEPTION); //$NON-NLS-1$
+    }
+  }
+
+  void validateODataVersion(final ODataRequest request, final ODataResponse response)
+      throws ODataHandlerException {
+    final String maxVersion = request.getHeader(HttpHeader.ODATA_MAX_VERSION);
+    response.setHeader(HttpHeader.ODATA_VERSION, ODataServiceVersion.V40.toString());
+
+    if (maxVersion != null) {
+      if (ODataServiceVersion.isBiggerThan(ODataServiceVersion.V40.toString(), maxVersion)) {
+        throw new ODataHandlerException("ODataVersion not supported: " + maxVersion, //$NON-NLS-1$
+            ODataHandlerException.MessageKeys.ODATA_VERSION_NOT_SUPPORTED, maxVersion);
+      }
+    }
+  }
+
+  @Override
+  public void register(final Processor processor) {
+    this.handler = (ServiceHandler) processor;
+    this.handler.init(this.odata, this.serviceMetadata);
+  }
+
+  @Override
+  public void register(final CustomContentTypeSupport customContentTypeSupport) {
+    this.customContentTypeSupport = customContentTypeSupport;
+  }
+}

http://git-wip-us.apache.org/repos/asf/olingo-odata4/blob/b25fc8c2/lib/server-core-ext/src/main/java/org/apache/olingo/server/core/OData4Impl.java
----------------------------------------------------------------------
diff --git a/lib/server-core-ext/src/main/java/org/apache/olingo/server/core/OData4Impl.java b/lib/server-core-ext/src/main/java/org/apache/olingo/server/core/OData4Impl.java
new file mode 100644
index 0000000..bde9c96
--- /dev/null
+++ b/lib/server-core-ext/src/main/java/org/apache/olingo/server/core/OData4Impl.java
@@ -0,0 +1,45 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied. See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ */
+package org.apache.olingo.server.core;
+
+import org.apache.olingo.commons.api.ODataRuntimeException;
+import org.apache.olingo.server.api.OData;
+import org.apache.olingo.server.api.ODataHttpHandler;
+import org.apache.olingo.server.api.ServiceMetadata;
+
+public class OData4Impl extends ODataImpl {
+
+  public static OData newInstance() {
+    try {
+      final Class<?> clazz = Class.forName(OData4Impl.class.getName());
+      final Object object = clazz.newInstance();
+      return (OData) object;
+    } catch (final Exception e) {
+      throw new ODataRuntimeException(e);
+    }
+  }
+
+  private OData4Impl() {
+  }
+
+  @Override
+  public ODataHttpHandler createHandler(final ServiceMetadata edm) {
+    return new OData4HttpHandler(this, edm);
+  }
+}

http://git-wip-us.apache.org/repos/asf/olingo-odata4/blob/b25fc8c2/lib/server-core-ext/src/main/java/org/apache/olingo/server/core/ODataServiceHandler.java
----------------------------------------------------------------------
diff --git a/lib/server-core-ext/src/main/java/org/apache/olingo/server/core/ODataServiceHandler.java b/lib/server-core-ext/src/main/java/org/apache/olingo/server/core/ODataServiceHandler.java
new file mode 100644
index 0000000..1e29f9f
--- /dev/null
+++ b/lib/server-core-ext/src/main/java/org/apache/olingo/server/core/ODataServiceHandler.java
@@ -0,0 +1,38 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied. See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ */
+package org.apache.olingo.server.core;
+
+import org.apache.olingo.server.api.ODataApplicationException;
+import org.apache.olingo.server.api.ODataRequest;
+import org.apache.olingo.server.api.ODataResponse;
+import org.apache.olingo.server.api.ODataServerError;
+import org.apache.olingo.server.api.ODataTranslatedException;
+
+public interface ODataServiceHandler {
+
+  void readMetadata(MetadataRequest request, MetadataResponse response)
+      throws ODataTranslatedException, ODataApplicationException;
+
+  void readServiceDocument(ServiceDocumentRequest request,
+      ServiceDocumentResponse response) throws ODataTranslatedException,
+      ODataApplicationException;
+
+  void handleException(ODataRequest request, ODataResponse response,
+      ODataServerError serverError);
+}

http://git-wip-us.apache.org/repos/asf/olingo-odata4/blob/b25fc8c2/lib/server-core-ext/src/main/java/org/apache/olingo/server/core/OperationRequest.java
----------------------------------------------------------------------
diff --git a/lib/server-core-ext/src/main/java/org/apache/olingo/server/core/OperationRequest.java b/lib/server-core-ext/src/main/java/org/apache/olingo/server/core/OperationRequest.java
new file mode 100644
index 0000000..f4252ea
--- /dev/null
+++ b/lib/server-core-ext/src/main/java/org/apache/olingo/server/core/OperationRequest.java
@@ -0,0 +1,117 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied. See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ */
+
+package org.apache.olingo.server.core;
+
+import org.apache.olingo.commons.api.data.ContextURL;
+import org.apache.olingo.commons.api.edm.EdmReturnType;
+import org.apache.olingo.commons.api.edm.constants.EdmTypeKind;
+import org.apache.olingo.commons.api.format.ContentType;
+import org.apache.olingo.server.api.OData;
+import org.apache.olingo.server.api.ServiceMetadata;
+import org.apache.olingo.server.api.serializer.RepresentationType;
+import org.apache.olingo.server.api.serializer.SerializerException;
+import org.apache.olingo.server.api.uri.UriHelper;
+import org.apache.olingo.server.api.uri.UriResourceFunction;
+
+public abstract class OperationRequest extends ServiceRequest {
+  private UriResourceFunction uriResourceFunction;
+
+  public OperationRequest(OData odata, ServiceMetadata serviceMetadata) {
+    super(odata, serviceMetadata);
+  }
+
+  @Override
+  public ContentType getResponseContentType() throws ContentNegotiatorException {
+    if (!hasReturnType()) {
+      // this default content type
+      return ContentType.APPLICATION_OCTET_STREAM;
+    }
+
+    if (isReturnTypePrimitive()) {
+      return ContentNegotiator.doContentNegotiation(uriInfo.getFormatOption(), this.request,
+          getCustomContentTypeSupport(), isCollection() ? RepresentationType.COLLECTION_PRIMITIVE
+              : RepresentationType.PRIMITIVE);
+    } else if (isReturnTypeComplex()) {
+      return ContentNegotiator.doContentNegotiation(uriInfo.getFormatOption(), this.request,
+          getCustomContentTypeSupport(), isCollection() ? RepresentationType.COLLECTION_COMPLEX
+              : RepresentationType.COMPLEX);
+    } else {
+      return ContentNegotiator.doContentNegotiation(uriInfo.getFormatOption(), this.request,
+          getCustomContentTypeSupport(), isCollection() ? RepresentationType.COLLECTION_ENTITY
+              : RepresentationType.ENTITY);
+    }
+  }
+
+  public abstract boolean isBound();
+
+  public abstract boolean isCollection();
+
+  public abstract EdmReturnType getReturnType();
+
+  public abstract boolean hasReturnType();
+
+  public ContextURL getContextURL(OData odata) throws SerializerException {
+    if (!hasReturnType()) {
+      return null;
+    }
+
+    final UriHelper helper = odata.createUriHelper();
+
+    if (isReturnTypePrimitive() || isReturnTypeComplex()) {
+      // Part 1 {10.14, 10.14} since the function return properties does not
+      // represent a Entity property
+      ContextURL.Builder builder = ContextURL.with().type(getReturnType().getType());
+      if (isCollection()) {
+        builder.asCollection();
+      }
+      return builder.build();
+    }
+
+    /*
+    // EdmTypeKind.ENTITY;
+    if (isBound()) {
+      // Bound means, we know the EnitySet of the return type. Part 1 {10.2,
+      // 10.3}
+      EdmEntitySet entitySet = this.uriResourceFunction.getFunctionImport().getReturnedEntitySet();
+      ContextURL.Builder builder = DataRequest.buildEntitySetContextURL(helper, entitySet,
+          this.uriInfo, isCollection(), false);
+      return builder.build();
+    }
+    */
+
+    // EdmTypeKind.ENTITY; Not Bound
+    // Here we do not know the EntitySet, then follow directions from
+    // Part-1{10.2. 10.3} to use
+    // {context-url}#{type-name}
+    ContextURL.Builder builder = ContextURL.with().type(getReturnType().getType());
+    if (isCollection()) {
+      builder.asCollection();
+    }
+    return builder.build();
+  }
+
+  protected boolean isReturnTypePrimitive() {
+    return getReturnType().getType().getKind() == EdmTypeKind.PRIMITIVE;
+  }
+
+  protected boolean isReturnTypeComplex() {
+    return getReturnType().getType().getKind() == EdmTypeKind.COMPLEX;
+  }
+}
\ No newline at end of file

http://git-wip-us.apache.org/repos/asf/olingo-odata4/blob/b25fc8c2/lib/server-core-ext/src/main/java/org/apache/olingo/server/core/PrimitiveValueResponse.java
----------------------------------------------------------------------
diff --git a/lib/server-core-ext/src/main/java/org/apache/olingo/server/core/PrimitiveValueResponse.java b/lib/server-core-ext/src/main/java/org/apache/olingo/server/core/PrimitiveValueResponse.java
new file mode 100644
index 0000000..52801da
--- /dev/null
+++ b/lib/server-core-ext/src/main/java/org/apache/olingo/server/core/PrimitiveValueResponse.java
@@ -0,0 +1,99 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied. See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ */
+package org.apache.olingo.server.core;
+
+import org.apache.olingo.commons.api.edm.EdmPrimitiveType;
+import org.apache.olingo.commons.api.edm.EdmProperty;
+import org.apache.olingo.commons.api.edm.EdmReturnType;
+import org.apache.olingo.commons.api.http.HttpContentType;
+import org.apache.olingo.server.api.ODataApplicationException;
+import org.apache.olingo.server.api.ODataResponse;
+import org.apache.olingo.server.api.ODataTranslatedException;
+import org.apache.olingo.server.api.serializer.FixedFormatSerializer;
+import org.apache.olingo.server.api.serializer.PrimitiveValueSerializerOptions;
+import org.apache.olingo.server.api.serializer.SerializerException;
+
+public class PrimitiveValueResponse extends ServiceResponse {
+  private final boolean returnCollection;
+  private EdmProperty type;
+  private EdmReturnType returnType;
+  private final FixedFormatSerializer serializer;
+
+  public static PrimitiveValueResponse getInstance(ServiceRequest request, ODataResponse response,
+      boolean collection, EdmProperty type) {
+    FixedFormatSerializer serializer = request.getOdata().createFixedFormatSerializer();
+    return new PrimitiveValueResponse(serializer, response, collection, type);
+  }
+
+  public static PrimitiveValueResponse getInstance(ServiceRequest request, ODataResponse response,
+      boolean collection, EdmReturnType type) {
+    FixedFormatSerializer serializer = request.getOdata().createFixedFormatSerializer();
+    return new PrimitiveValueResponse(serializer, response, collection, type);
+  }
+
+  private PrimitiveValueResponse(FixedFormatSerializer serializer, ODataResponse response,
+      boolean collection, EdmProperty type) {
+    super(response);
+    this.returnCollection = collection;
+    this.type = type;
+    this.serializer = serializer;
+  }
+
+  private PrimitiveValueResponse(FixedFormatSerializer serializer, ODataResponse response,
+      boolean collection, EdmReturnType type) {
+    super(response);
+    this.returnCollection = collection;
+    this.returnType = type;
+    this.serializer = serializer;
+  }
+
+  public void write(Object value) throws SerializerException {
+
+    if (value == null) {
+      writeNoContent(true);
+      return;
+    }
+
+    if (this.type != null) {
+      PrimitiveValueSerializerOptions options = PrimitiveValueSerializerOptions.with()
+          .facetsFrom(this.type).build();
+
+      this.response.setContent(this.serializer.primitiveValue((EdmPrimitiveType) this.type.getType(),
+          value, options));
+    } else {
+      PrimitiveValueSerializerOptions options = PrimitiveValueSerializerOptions.with()
+          .nullable(this.returnType.isNullable()).maxLength(this.returnType.getMaxLength())
+          .precision(this.returnType.getPrecision()).scale(this.returnType.getScale()).build();
+      this.response.setContent(this.serializer.primitiveValue(
+          (EdmPrimitiveType) this.returnType.getType(), value, options));
+    }
+
+    writeOK(HttpContentType.TEXT_PLAIN);
+  }
+
+  public boolean isReturnCollection() {
+    return returnCollection;
+  }
+
+  @Override
+  public void accepts(ServiceResponseVisior visitor) throws ODataTranslatedException,
+      ODataApplicationException {
+    visitor.visit(this);
+  }
+}

http://git-wip-us.apache.org/repos/asf/olingo-odata4/blob/b25fc8c2/lib/server-core-ext/src/main/java/org/apache/olingo/server/core/PropertyResponse.java
----------------------------------------------------------------------
diff --git a/lib/server-core-ext/src/main/java/org/apache/olingo/server/core/PropertyResponse.java b/lib/server-core-ext/src/main/java/org/apache/olingo/server/core/PropertyResponse.java
new file mode 100644
index 0000000..994a5e1
--- /dev/null
+++ b/lib/server-core-ext/src/main/java/org/apache/olingo/server/core/PropertyResponse.java
@@ -0,0 +1,133 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied. See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ */
+package org.apache.olingo.server.core;
+
+import org.apache.olingo.commons.api.data.ContextURL;
+import org.apache.olingo.commons.api.data.Property;
+import org.apache.olingo.commons.api.edm.EdmComplexType;
+import org.apache.olingo.commons.api.edm.EdmPrimitiveType;
+import org.apache.olingo.commons.api.edm.EdmType;
+import org.apache.olingo.commons.api.edm.constants.EdmTypeKind;
+import org.apache.olingo.commons.api.format.ContentType;
+import org.apache.olingo.server.api.ODataApplicationException;
+import org.apache.olingo.server.api.ODataResponse;
+import org.apache.olingo.server.api.ODataTranslatedException;
+import org.apache.olingo.server.api.serializer.ComplexSerializerOptions;
+import org.apache.olingo.server.api.serializer.ODataSerializer;
+import org.apache.olingo.server.api.serializer.PrimitiveSerializerOptions;
+import org.apache.olingo.server.api.serializer.SerializerException;
+
+public class PropertyResponse extends ServiceResponse {
+  private PrimitiveSerializerOptions primitiveOptions;
+  private ComplexSerializerOptions complexOptions;
+  private final ContentType responseContentType;
+  private final ODataSerializer serializer;
+  private final boolean collection;
+
+  public static PropertyResponse getInstance(ServiceRequest request, ODataResponse response,
+      EdmType edmType, ContextURL contextURL, boolean collection) throws ContentNegotiatorException,
+      SerializerException {
+    if (edmType.getKind() == EdmTypeKind.PRIMITIVE) {
+      PrimitiveSerializerOptions options = request.getSerializerOptions(
+          PrimitiveSerializerOptions.class, contextURL);
+      ContentType type = request.getResponseContentType();
+      return new PropertyResponse(request.getSerializer(), response, options, type, collection);
+    }
+    ComplexSerializerOptions options = request.getSerializerOptions(ComplexSerializerOptions.class,
+        contextURL);
+    ContentType type = request.getResponseContentType();
+    return new PropertyResponse(request.getSerializer(), response, options, type, collection);
+  }
+
+  private PropertyResponse(ODataSerializer serializer, ODataResponse response,
+      PrimitiveSerializerOptions options, ContentType contentType, boolean collection) {
+    super(response);
+    this.serializer = serializer;
+    this.primitiveOptions = options;
+    this.responseContentType = contentType;
+    this.collection = collection;
+  }
+
+  private PropertyResponse(ODataSerializer serializer, ODataResponse response,
+      ComplexSerializerOptions options, ContentType contentType, boolean collection) {
+    super(response);
+    this.serializer = serializer;
+    this.complexOptions = options;
+    this.responseContentType = contentType;
+    this.collection = collection;
+  }
+
+  public void writeProperty(EdmType edmType, Property property) throws SerializerException {
+    assert (!isClosed());
+
+    if (property == null) {
+      writeNotFound(true);
+      return;
+    }
+
+    if (property.getValue() == null) {
+      writeNoContent(true);
+      return;
+    }
+
+    if (edmType.getKind() == EdmTypeKind.PRIMITIVE) {
+      writePrimitiveProperty((EdmPrimitiveType) edmType, property);
+    } else {
+      writeComplexProperty((EdmComplexType) edmType, property);
+    }
+  }
+
+  private void writeComplexProperty(EdmComplexType type, Property property)
+      throws SerializerException {
+    if (this.collection) {
+      this.response.setContent(this.serializer.complexCollection(type, property, this.complexOptions));
+    } else {
+      this.response.setContent(this.serializer.complex(type, property, this.complexOptions));
+    }
+    writeOK(this.responseContentType.toContentTypeString());
+    close();
+  }
+
+  private void writePrimitiveProperty(EdmPrimitiveType type, Property property)
+      throws SerializerException {
+    if(this.collection) {
+      this.response.setContent(this.serializer.primitiveCollection(type, property, this.primitiveOptions));
+    } else {
+      this.response.setContent(this.serializer.primitive(type, property, this.primitiveOptions));
+    }
+    writeOK(this.responseContentType.toContentTypeString());
+    close();
+  }
+
+  @Override
+  public void accepts(ServiceResponseVisior visitor) throws ODataTranslatedException,
+      ODataApplicationException {
+    visitor.visit(this);
+  }
+
+  public void writePropertyUpdated() {
+    // spec says just success response; so either 200 or 204. 200 typically has
+    // payload
+    writeNoContent(true);
+  }
+
+  public void writePropertyDeleted() {
+    writeNoContent(true);
+  }
+}

http://git-wip-us.apache.org/repos/asf/olingo-odata4/blob/b25fc8c2/lib/server-core-ext/src/main/java/org/apache/olingo/server/core/RequestURLHierarchyVisitor.java
----------------------------------------------------------------------
diff --git a/lib/server-core-ext/src/main/java/org/apache/olingo/server/core/RequestURLHierarchyVisitor.java b/lib/server-core-ext/src/main/java/org/apache/olingo/server/core/RequestURLHierarchyVisitor.java
new file mode 100644
index 0000000..38c4407
--- /dev/null
+++ b/lib/server-core-ext/src/main/java/org/apache/olingo/server/core/RequestURLHierarchyVisitor.java
@@ -0,0 +1,332 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied. See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ */
+package org.apache.olingo.server.core;
+
+import java.util.List;
+
+import org.apache.olingo.server.api.uri.UriInfo;
+import org.apache.olingo.server.api.uri.UriInfoAll;
+import org.apache.olingo.server.api.uri.UriInfoBatch;
+import org.apache.olingo.server.api.uri.UriInfoCrossjoin;
+import org.apache.olingo.server.api.uri.UriInfoEntityId;
+import org.apache.olingo.server.api.uri.UriInfoKind;
+import org.apache.olingo.server.api.uri.UriInfoMetadata;
+import org.apache.olingo.server.api.uri.UriInfoResource;
+import org.apache.olingo.server.api.uri.UriInfoService;
+import org.apache.olingo.server.api.uri.UriResource;
+import org.apache.olingo.server.api.uri.UriResourceAction;
+import org.apache.olingo.server.api.uri.UriResourceComplexProperty;
+import org.apache.olingo.server.api.uri.UriResourceCount;
+import org.apache.olingo.server.api.uri.UriResourceEntitySet;
+import org.apache.olingo.server.api.uri.UriResourceFunction;
+import org.apache.olingo.server.api.uri.UriResourceIt;
+import org.apache.olingo.server.api.uri.UriResourceLambdaAll;
+import org.apache.olingo.server.api.uri.UriResourceLambdaAny;
+import org.apache.olingo.server.api.uri.UriResourceLambdaVariable;
+import org.apache.olingo.server.api.uri.UriResourceNavigation;
+import org.apache.olingo.server.api.uri.UriResourcePrimitiveProperty;
+import org.apache.olingo.server.api.uri.UriResourceRef;
+import org.apache.olingo.server.api.uri.UriResourceRoot;
+import org.apache.olingo.server.api.uri.UriResourceSingleton;
+import org.apache.olingo.server.api.uri.UriResourceValue;
+import org.apache.olingo.server.api.uri.queryoption.CountOption;
+import org.apache.olingo.server.api.uri.queryoption.ExpandOption;
+import org.apache.olingo.server.api.uri.queryoption.FilterOption;
+import org.apache.olingo.server.api.uri.queryoption.FormatOption;
+import org.apache.olingo.server.api.uri.queryoption.IdOption;
+import org.apache.olingo.server.api.uri.queryoption.OrderByOption;
+import org.apache.olingo.server.api.uri.queryoption.SearchOption;
+import org.apache.olingo.server.api.uri.queryoption.SelectOption;
+import org.apache.olingo.server.api.uri.queryoption.SkipOption;
+import org.apache.olingo.server.api.uri.queryoption.SkipTokenOption;
+import org.apache.olingo.server.api.uri.queryoption.TopOption;
+
+public class RequestURLHierarchyVisitor implements RequestURLVisitor {
+
+  private UriInfo uriInfo;
+
+  public UriInfo getUriInfo() {
+    return this.uriInfo;
+  }
+
+  @Override
+  public void visit(UriInfo info) {
+    this.uriInfo = info;
+
+    UriInfoKind kind = info.getKind();
+    switch (kind) {
+    case all:
+      visit(info.asUriInfoAll());
+      break;
+    case batch:
+      visit(info.asUriInfoBatch());
+      break;
+    case crossjoin:
+      visit(info.asUriInfoCrossjoin());
+      break;
+    case entityId:
+      visit(info.asUriInfoEntityId());
+      break;
+    case metadata:
+      visit(info.asUriInfoMetadata());
+      break;
+    case resource:
+      visit(info.asUriInfoResource());
+      break;
+    case service:
+      visit(info.asUriInfoService());
+      break;
+    }
+  }
+
+  @Override
+  public void visit(UriInfoService info) {
+  }
+
+  @Override
+  public void visit(UriInfoAll info) {
+  }
+
+  @Override
+  public void visit(UriInfoBatch info) {
+  }
+
+  @Override
+  public void visit(UriInfoCrossjoin info) {
+  }
+
+  @Override
+  public void visit(UriInfoEntityId info) {
+    visit(info.getSelectOption());
+
+    if (info.getExpandOption() != null) {
+      visit(info.getExpandOption());
+    }
+    if (info.getFormatOption() != null) {
+      visit(info.getFormatOption());
+    }
+    if (info.getIdOption() != null) {
+      visit(info.getIdOption());
+    }
+  }
+
+  @Override
+  public void visit(UriInfoMetadata info) {
+  }
+
+  @Override
+  public void visit(UriInfoResource info) {
+    List<UriResource> parts = info.getUriResourceParts();
+    for (UriResource resource : parts) {
+      switch (resource.getKind()) {
+      case action:
+        visit((UriResourceAction) resource);
+        break;
+      case complexProperty:
+        visit((UriResourceComplexProperty) resource);
+        break;
+      case count:
+        visit((UriResourceCount) resource);
+        break;
+      case entitySet:
+        visit((UriResourceEntitySet) resource);
+        break;
+      case function:
+        visit((UriResourceFunction) resource);
+        break;
+      case it:
+        visit((UriResourceIt) resource);
+        break;
+      case lambdaAll:
+        visit((UriResourceLambdaAll) resource);
+        break;
+      case lambdaAny:
+        visit((UriResourceLambdaAny) resource);
+        break;
+      case lambdaVariable:
+        visit((UriResourceLambdaVariable) resource);
+        break;
+      case navigationProperty:
+        visit((UriResourceNavigation) resource);
+        break;
+      case ref:
+        visit((UriResourceRef) resource);
+        break;
+      case root:
+        visit((UriResourceRoot) resource);
+        break;
+      case primitiveProperty:
+        visit((UriResourcePrimitiveProperty) resource);
+        break;
+      case singleton:
+        visit((UriResourceSingleton) resource);
+        break;
+      case value:
+        visit((UriResourceValue) resource);
+        break;
+      }
+    }
+
+    // http://docs.oasis-open.org/odata/odata/v4.0/os/part1-protocol/odata-v4.0-os-part1-protocol.html#_Toc372793682
+    if (info.getSearchOption() != null) {
+      visit(info.getSearchOption());
+    }
+
+    if (info.getFilterOption() != null) {
+      visit(info.getFilterOption());
+    }
+
+    if (info.getCountOption() != null) {
+      visit(info.getCountOption());
+    }
+
+    visit(info.getOrderByOption());
+
+    if (info.getSkipOption() != null) {
+      visit(info.getSkipOption());
+    }
+
+    if (info.getTopOption() != null) {
+      visit(info.getTopOption());
+    }
+
+    if (info.getExpandOption() != null) {
+      visit(info.getExpandOption());
+    }
+
+    visit(info.getSelectOption());
+
+    if (info.getFormatOption() != null) {
+      visit(info.getFormatOption());
+    }
+
+    if (info.getIdOption() != null) {
+      visit(info.getIdOption());
+    }
+
+    if (info.getSkipTokenOption() != null) {
+      visit(info.getSkipTokenOption());
+    }
+
+  }
+
+  @Override
+  public void visit(ExpandOption option) {
+  }
+
+  @Override
+  public void visit(FilterOption info) {
+  }
+
+  @Override
+  public void visit(FormatOption info) {
+  }
+
+  @Override
+  public void visit(IdOption info) {
+  }
+
+  @Override
+  public void visit(CountOption info) {
+  }
+
+  @Override
+  public void visit(OrderByOption option) {
+  }
+
+  @Override
+  public void visit(SearchOption option) {
+  }
+
+  @Override
+  public void visit(SelectOption option) {
+  }
+
+  @Override
+  public void visit(SkipOption option) {
+  }
+
+  @Override
+  public void visit(SkipTokenOption option) {
+  }
+
+  @Override
+  public void visit(TopOption option) {
+  }
+
+  @Override
+  public void visit(UriResourceCount option) {
+  }
+
+  @Override
+  public void visit(UriResourceRef info) {
+  }
+
+  @Override
+  public void visit(UriResourceRoot info) {
+  }
+
+  @Override
+  public void visit(UriResourceValue info) {
+  }
+
+  @Override
+  public void visit(UriResourceAction info) {
+  }
+
+  @Override
+  public void visit(UriResourceEntitySet info) {
+  }
+
+  @Override
+  public void visit(UriResourceFunction info) {
+  }
+
+  @Override
+  public void visit(UriResourceIt info) {
+  }
+
+  @Override
+  public void visit(UriResourceLambdaAll info) {
+  }
+
+  @Override
+  public void visit(UriResourceLambdaAny info) {
+  }
+
+  @Override
+  public void visit(UriResourceLambdaVariable info) {
+  }
+
+  @Override
+  public void visit(UriResourceNavigation info) {
+  }
+
+  @Override
+  public void visit(UriResourceSingleton info) {
+  }
+
+  @Override
+  public void visit(UriResourceComplexProperty info) {
+  }
+
+  @Override
+  public void visit(UriResourcePrimitiveProperty info) {
+  }
+}

http://git-wip-us.apache.org/repos/asf/olingo-odata4/blob/b25fc8c2/lib/server-core-ext/src/main/java/org/apache/olingo/server/core/RequestURLVisitor.java
----------------------------------------------------------------------
diff --git a/lib/server-core-ext/src/main/java/org/apache/olingo/server/core/RequestURLVisitor.java b/lib/server-core-ext/src/main/java/org/apache/olingo/server/core/RequestURLVisitor.java
new file mode 100644
index 0000000..21324b1
--- /dev/null
+++ b/lib/server-core-ext/src/main/java/org/apache/olingo/server/core/RequestURLVisitor.java
@@ -0,0 +1,126 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied. See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ */
+package org.apache.olingo.server.core;
+
+import org.apache.olingo.server.api.uri.UriInfo;
+import org.apache.olingo.server.api.uri.UriInfoAll;
+import org.apache.olingo.server.api.uri.UriInfoBatch;
+import org.apache.olingo.server.api.uri.UriInfoCrossjoin;
+import org.apache.olingo.server.api.uri.UriInfoEntityId;
+import org.apache.olingo.server.api.uri.UriInfoMetadata;
+import org.apache.olingo.server.api.uri.UriInfoResource;
+import org.apache.olingo.server.api.uri.UriInfoService;
+import org.apache.olingo.server.api.uri.UriResourceAction;
+import org.apache.olingo.server.api.uri.UriResourceComplexProperty;
+import org.apache.olingo.server.api.uri.UriResourceCount;
+import org.apache.olingo.server.api.uri.UriResourceEntitySet;
+import org.apache.olingo.server.api.uri.UriResourceFunction;
+import org.apache.olingo.server.api.uri.UriResourceIt;
+import org.apache.olingo.server.api.uri.UriResourceLambdaAll;
+import org.apache.olingo.server.api.uri.UriResourceLambdaAny;
+import org.apache.olingo.server.api.uri.UriResourceLambdaVariable;
+import org.apache.olingo.server.api.uri.UriResourceNavigation;
+import org.apache.olingo.server.api.uri.UriResourcePrimitiveProperty;
+import org.apache.olingo.server.api.uri.UriResourceRef;
+import org.apache.olingo.server.api.uri.UriResourceRoot;
+import org.apache.olingo.server.api.uri.UriResourceSingleton;
+import org.apache.olingo.server.api.uri.UriResourceValue;
+import org.apache.olingo.server.api.uri.queryoption.CountOption;
+import org.apache.olingo.server.api.uri.queryoption.ExpandOption;
+import org.apache.olingo.server.api.uri.queryoption.FilterOption;
+import org.apache.olingo.server.api.uri.queryoption.FormatOption;
+import org.apache.olingo.server.api.uri.queryoption.IdOption;
+import org.apache.olingo.server.api.uri.queryoption.OrderByOption;
+import org.apache.olingo.server.api.uri.queryoption.SearchOption;
+import org.apache.olingo.server.api.uri.queryoption.SelectOption;
+import org.apache.olingo.server.api.uri.queryoption.SkipOption;
+import org.apache.olingo.server.api.uri.queryoption.SkipTokenOption;
+import org.apache.olingo.server.api.uri.queryoption.TopOption;
+
+public interface RequestURLVisitor {
+
+  void visit(UriInfo info);
+
+  void visit(UriInfoService info);
+
+  void visit(UriInfoAll info);
+
+  void visit(UriInfoBatch info);
+
+  void visit(UriInfoCrossjoin info);
+
+  void visit(UriInfoEntityId info);
+
+  void visit(UriInfoMetadata info);
+
+  void visit(UriInfoResource info);
+
+  // Walk UriInfoResource
+  void visit(ExpandOption option);
+
+  void visit(FilterOption info);
+
+  void visit(FormatOption info);
+
+  void visit(IdOption info);
+
+  void visit(CountOption info);
+
+  void visit(OrderByOption option);
+
+  void visit(SearchOption option);
+
+  void visit(SelectOption option);
+
+  void visit(SkipOption option);
+
+  void visit(SkipTokenOption option);
+
+  void visit(TopOption option);
+
+  void visit(UriResourceCount option);
+
+  void visit(UriResourceRef info);
+
+  void visit(UriResourceRoot info);
+
+  void visit(UriResourceValue info);
+
+  void visit(UriResourceAction info);
+
+  void visit(UriResourceEntitySet info);
+
+  void visit(UriResourceFunction info);
+
+  void visit(UriResourceIt info);
+
+  void visit(UriResourceLambdaAll info);
+
+  void visit(UriResourceLambdaAny info);
+
+  void visit(UriResourceLambdaVariable info);
+
+  void visit(UriResourceNavigation info);
+
+  void visit(UriResourceSingleton info);
+
+  void visit(UriResourceComplexProperty info);
+
+  void visit(UriResourcePrimitiveProperty info);
+}

http://git-wip-us.apache.org/repos/asf/olingo-odata4/blob/b25fc8c2/lib/server-core-ext/src/main/java/org/apache/olingo/server/core/SchemaBasedEdmProvider.java
----------------------------------------------------------------------
diff --git a/lib/server-core-ext/src/main/java/org/apache/olingo/server/core/SchemaBasedEdmProvider.java b/lib/server-core-ext/src/main/java/org/apache/olingo/server/core/SchemaBasedEdmProvider.java
new file mode 100644
index 0000000..b1d3c93
--- /dev/null
+++ b/lib/server-core-ext/src/main/java/org/apache/olingo/server/core/SchemaBasedEdmProvider.java
@@ -0,0 +1,301 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied. See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ */
+package org.apache.olingo.server.core;
+
+import java.util.ArrayList;
+import java.util.Arrays;
+import java.util.List;
+
+import org.apache.olingo.commons.api.ODataException;
+import org.apache.olingo.commons.api.edm.FullQualifiedName;
+import org.apache.olingo.server.api.edm.provider.Action;
+import org.apache.olingo.server.api.edm.provider.ActionImport;
+import org.apache.olingo.server.api.edm.provider.AliasInfo;
+import org.apache.olingo.server.api.edm.provider.ComplexType;
+import org.apache.olingo.server.api.edm.provider.EdmProvider;
+import org.apache.olingo.server.api.edm.provider.EntityContainer;
+import org.apache.olingo.server.api.edm.provider.EntityContainerInfo;
+import org.apache.olingo.server.api.edm.provider.EntitySet;
+import org.apache.olingo.server.api.edm.provider.EntityType;
+import org.apache.olingo.server.api.edm.provider.EnumType;
+import org.apache.olingo.server.api.edm.provider.Function;
+import org.apache.olingo.server.api.edm.provider.FunctionImport;
+import org.apache.olingo.server.api.edm.provider.Schema;
+import org.apache.olingo.server.api.edm.provider.Singleton;
+import org.apache.olingo.server.api.edm.provider.Term;
+import org.apache.olingo.server.api.edm.provider.TypeDefinition;
+
+public class SchemaBasedEdmProvider extends EdmProvider {
+  private final List<Schema> edmSchemas = new ArrayList<Schema>();
+
+  protected void addSchema(Schema schema) {
+    this.edmSchemas.add(schema);
+  }
+
+  private Schema getSchema(String ns) {
+    for (Schema s : this.edmSchemas) {
+      if (s.getNamespace().equals(ns)) {
+        return s;
+      }
+    }
+    return null;
+  }
+
+  @Override
+  public EnumType getEnumType(FullQualifiedName fqn) throws ODataException {
+    Schema schema = getSchema(fqn.getNamespace());
+    if (schema != null) {
+      List<EnumType> types = schema.getEnumTypes();
+      if (types != null) {
+        for (EnumType type : types) {
+          if (type.getName().equals(fqn.getName())) {
+            return type;
+          }
+        }
+      }
+    }
+    return null;
+  }
+
+  @Override
+  public TypeDefinition getTypeDefinition(FullQualifiedName fqn) throws ODataException {
+    Schema schema = getSchema(fqn.getNamespace());
+    if (schema != null) {
+      List<TypeDefinition> types = schema.getTypeDefinitions();
+      if (types != null) {
+        for (TypeDefinition type : types) {
+          if (type.getName().equals(fqn.getName())) {
+            return type;
+          }
+        }
+      }
+    }
+    return null;
+  }
+
+  @Override
+  public List<Function> getFunctions(FullQualifiedName fqn) throws ODataException {
+    ArrayList<Function> foundFuncs = new ArrayList<Function>();
+    Schema schema = getSchema(fqn.getNamespace());
+    if (schema != null) {
+      List<Function> functions = schema.getFunctions();
+      if (functions != null) {
+        for (Function func : functions) {
+          if (func.getName().equals(fqn.getName())) {
+            foundFuncs.add(func);
+          }
+        }
+      }
+    }
+    return foundFuncs;
+  }
+
+  @Override
+  public Term getTerm(FullQualifiedName fqn) throws ODataException {
+    Schema schema = getSchema(fqn.getNamespace());
+    if (schema != null) {
+      List<Term> terms = schema.getTerms();
+      if (terms != null) {
+        for (Term term : terms) {
+          if (term.getName().equals(fqn.getName())) {
+            return term;
+          }
+        }
+      }
+    }
+    return null;
+  }
+
+  @Override
+  public EntitySet getEntitySet(FullQualifiedName fqn, String entitySetName) throws ODataException {
+    Schema schema = getSchema(fqn.getFullQualifiedNameAsString());
+    if (schema != null) {
+      EntityContainer ec = schema.getEntityContainer();
+      if (ec != null && ec.getEntitySets() != null) {
+        for (EntitySet es : ec.getEntitySets()) {
+          if (es.getName().equals(entitySetName)) {
+            return es;
+          }
+        }
+      }
+    }
+    return null;
+  }
+
+  @Override
+  public Singleton getSingleton(FullQualifiedName fqn, String singletonName) throws ODataException {
+    Schema schema = getSchema(fqn.getFullQualifiedNameAsString());
+    if (schema != null) {
+      EntityContainer ec = schema.getEntityContainer();
+      if (ec != null && ec.getSingletons() != null) {
+        for (Singleton es : ec.getSingletons()) {
+          if (es.getName().equals(singletonName)) {
+            return es;
+          }
+        }
+      }
+    }
+    return null;
+  }
+
+  @Override
+  public ActionImport getActionImport(FullQualifiedName fqn, String actionImportName)
+      throws ODataException {
+    Schema schema = getSchema(fqn.getFullQualifiedNameAsString());
+    if (schema != null) {
+      EntityContainer ec = schema.getEntityContainer();
+      if (ec != null && ec.getActionImports() != null) {
+        for (ActionImport es : ec.getActionImports()) {
+          if (es.getName().equals(actionImportName)) {
+            return es;
+          }
+        }
+      }
+    }
+    return null;
+  }
+
+  @Override
+  public FunctionImport getFunctionImport(FullQualifiedName fqn, String functionImportName)
+      throws ODataException {
+    Schema schema = getSchema(fqn.getFullQualifiedNameAsString());
+    if (schema != null) {
+      EntityContainer ec = schema.getEntityContainer();
+      if (ec != null && ec.getFunctionImports() != null) {
+        for (FunctionImport es : ec.getFunctionImports()) {
+          if (es.getName().equals(functionImportName)) {
+            return es;
+          }
+        }
+      }
+    }
+    return null;
+  }
+
+  @Override
+  public EntityContainerInfo getEntityContainerInfo(FullQualifiedName fqn) throws ODataException {
+    Schema schema = null;
+
+    if (fqn == null) {
+      for (Schema s : this.edmSchemas) {
+        if (s.getEntityContainer() != null) {
+          schema = s;
+          break;
+        }
+      }
+    } else {
+      schema = getSchema(fqn.getFullQualifiedNameAsString());
+    }
+
+    if (schema != null) {
+      EntityContainer ec = schema.getEntityContainer();
+      if (ec != null) {
+        EntityContainerInfo info = new EntityContainerInfo();
+        info.setContainerName(new FullQualifiedName(schema.getNamespace()));
+        info.setExtendsContainer(schema.getEntityContainer().getExtendsContainer());
+        return info;
+      }
+    }
+    return null;
+  }
+
+  @Override
+  public List<AliasInfo> getAliasInfos() throws ODataException {
+    Schema schema = null;
+    for (Schema s : this.edmSchemas) {
+      if (s.getEntityContainer() != null) {
+        schema = s;
+        break;
+      }
+    }
+
+    if (schema == null) {
+      schema = this.edmSchemas.get(0);
+    }
+
+    AliasInfo ai = new AliasInfo();
+    ai.setAlias(schema.getAlias());
+    ai.setNamespace(schema.getNamespace());
+    return Arrays.asList(ai);
+  }
+
+  @Override
+  public EntityContainer getEntityContainer() throws ODataException {
+    // note that there can be many schemas, but only one needs to contain the
+    // entity container in a given metadata document.
+    for (Schema s : this.edmSchemas) {
+      if (s.getEntityContainer() != null) {
+        return s.getEntityContainer();
+      }
+    }
+    return null;
+  }
+
+  @Override
+  public List<Schema> getSchemas() throws ODataException {
+    return new ArrayList<Schema>(this.edmSchemas);
+  }
+
+  @Override
+  public EntityType getEntityType(final FullQualifiedName fqn) throws ODataException {
+    Schema schema = getSchema(fqn.getNamespace());
+    if (schema != null) {
+      if (schema.getEntityTypes() != null) {
+        for (EntityType type : schema.getEntityTypes()) {
+          if (type.getName().equals(fqn.getName())) {
+            return type;
+          }
+        }
+      }
+    }
+    return null;
+  }
+
+  @Override
+  public ComplexType getComplexType(final FullQualifiedName fqn) throws ODataException {
+    Schema schema = getSchema(fqn.getNamespace());
+    if (schema != null) {
+      if (schema.getComplexTypes() != null) {
+        for (ComplexType type : schema.getComplexTypes()) {
+          if (type.getName().equals(fqn.getName())) {
+            return type;
+          }
+        }
+      }
+    }
+    return null;
+  }
+
+  @Override
+  public List<Action> getActions(final FullQualifiedName fqn) throws ODataException {
+    ArrayList<Action> actions = new ArrayList<Action>();
+    Schema schema = getSchema(fqn.getNamespace());
+    if (schema != null) {
+      List<Action> types = schema.getActions();
+      if (types != null) {
+        for (Action type : types) {
+          if (type.getName().equals(fqn.getName())) {
+            actions.add(type);
+          }
+        }
+      }
+    }
+    return actions;
+  }
+}