[OLINGO-1180] Validation of metadata post deserialization

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

Branch: refs/heads/master
Commit: 48263a8ce34845a94cb6bd8ecda2c1d8d6091fc4
Parents: 379a3c7
Author: ramya vasanth <[email protected]>
Authored: Thu Oct 12 10:46:46 2017 +0530
Committer: ramya vasanth <[email protected]>
Committed: Thu Oct 12 10:46:46 2017 +0530

----------------------------------------------------------------------
 .../apache/olingo/client/api/ODataClient.java   |    3 +
 .../serialization/ODataMetadataValidation.java  |   37 +
 .../olingo/client/core/ODataClientImpl.java     |    9 +
 .../metadatavalidator/CsdlTypeValidator.java    |  491 +++++++
 .../metadatavalidator/EdmTypeValidator.java     |  294 ++++
 .../ODataMetadataValidationImpl.java            |  118 ++
 .../client/core/MetadataValidationTest.java     | 1254 ++++++++++++++++++
 .../apache/olingo/client/core/metadata_1.xml    |   76 ++
 .../apache/olingo/client/core/metadata_2.xml    |   88 ++
 .../apache/olingo/client/core/metadata_3.xml    |   88 ++
 .../client/core/metadata_TripInService.xml      |  355 +++++
 11 files changed, 2813 insertions(+)
----------------------------------------------------------------------


http://git-wip-us.apache.org/repos/asf/olingo-odata4/blob/48263a8c/lib/client-api/src/main/java/org/apache/olingo/client/api/ODataClient.java
----------------------------------------------------------------------
diff --git 
a/lib/client-api/src/main/java/org/apache/olingo/client/api/ODataClient.java 
b/lib/client-api/src/main/java/org/apache/olingo/client/api/ODataClient.java
index 842dcf6..835ca1f 100644
--- a/lib/client-api/src/main/java/org/apache/olingo/client/api/ODataClient.java
+++ b/lib/client-api/src/main/java/org/apache/olingo/client/api/ODataClient.java
@@ -28,6 +28,7 @@ import 
org.apache.olingo.client.api.communication.request.retrieve.RetrieveReque
 import org.apache.olingo.client.api.domain.ClientObjectFactory;
 import org.apache.olingo.client.api.serialization.ClientODataDeserializer;
 import org.apache.olingo.client.api.serialization.ODataBinder;
+import org.apache.olingo.client.api.serialization.ODataMetadataValidation;
 import org.apache.olingo.client.api.serialization.ODataReader;
 import org.apache.olingo.client.api.serialization.ODataSerializer;
 import org.apache.olingo.client.api.serialization.ODataWriter;
@@ -75,4 +76,6 @@ public interface ODataClient {
   CUDRequestFactory getCUDRequestFactory();
 
   BatchRequestFactory getBatchRequestFactory();
+  
+  ODataMetadataValidation metadataValidation();
 }

http://git-wip-us.apache.org/repos/asf/olingo-odata4/blob/48263a8c/lib/client-api/src/main/java/org/apache/olingo/client/api/serialization/ODataMetadataValidation.java
----------------------------------------------------------------------
diff --git 
a/lib/client-api/src/main/java/org/apache/olingo/client/api/serialization/ODataMetadataValidation.java
 
b/lib/client-api/src/main/java/org/apache/olingo/client/api/serialization/ODataMetadataValidation.java
new file mode 100644
index 0000000..f1bf5ef
--- /dev/null
+++ 
b/lib/client-api/src/main/java/org/apache/olingo/client/api/serialization/ODataMetadataValidation.java
@@ -0,0 +1,37 @@
+/*
+ * 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.client.api.serialization;
+
+import org.apache.olingo.client.api.edm.xml.XMLMetadata;
+import org.apache.olingo.commons.api.edm.Edm;
+
+public interface ODataMetadataValidation {
+
+  /**
+   * This method validates the metadata based on the Edm provided
+   * @param edm
+   */
+  void validateMetadata(Edm edm);
+  
+  /**
+   * This method validates the metadata based on the XMLMetadata provided
+   * @param xmlMetadata
+   */
+  void validateMetadata(XMLMetadata xmlMetadata);
+}

http://git-wip-us.apache.org/repos/asf/olingo-odata4/blob/48263a8c/lib/client-core/src/main/java/org/apache/olingo/client/core/ODataClientImpl.java
----------------------------------------------------------------------
diff --git 
a/lib/client-core/src/main/java/org/apache/olingo/client/core/ODataClientImpl.java
 
b/lib/client-core/src/main/java/org/apache/olingo/client/core/ODataClientImpl.java
index 811b63f..a23301c 100644
--- 
a/lib/client-core/src/main/java/org/apache/olingo/client/core/ODataClientImpl.java
+++ 
b/lib/client-core/src/main/java/org/apache/olingo/client/core/ODataClientImpl.java
@@ -30,6 +30,7 @@ import 
org.apache.olingo.client.api.communication.request.retrieve.RetrieveReque
 import org.apache.olingo.client.api.domain.ClientObjectFactory;
 import org.apache.olingo.client.api.serialization.ClientODataDeserializer;
 import org.apache.olingo.client.api.serialization.ODataBinder;
+import org.apache.olingo.client.api.serialization.ODataMetadataValidation;
 import org.apache.olingo.client.api.serialization.ODataReader;
 import org.apache.olingo.client.api.serialization.ODataSerializer;
 import org.apache.olingo.client.api.serialization.ODataWriter;
@@ -47,6 +48,7 @@ import 
org.apache.olingo.client.core.serialization.AtomSerializer;
 import org.apache.olingo.client.core.serialization.ClientODataDeserializerImpl;
 import org.apache.olingo.client.core.serialization.JsonSerializer;
 import org.apache.olingo.client.core.serialization.ODataBinderImpl;
+import org.apache.olingo.client.core.serialization.ODataMetadataValidationImpl;
 import org.apache.olingo.client.core.serialization.ODataReaderImpl;
 import org.apache.olingo.client.core.serialization.ODataWriterImpl;
 import org.apache.olingo.client.core.uri.FilterFactoryImpl;
@@ -80,6 +82,8 @@ public class ODataClientImpl implements ODataClient {
   protected final Configuration configuration = new ConfigurationImpl();
 
   private final ODataWriter writer = new ODataWriterImpl(this);
+  
+  private final ODataMetadataValidation metadataValidation = new 
ODataMetadataValidationImpl();
 
   @Override
   public Configuration getConfiguration() {
@@ -176,4 +180,9 @@ public class ODataClientImpl implements ODataClient {
   public BatchRequestFactory getBatchRequestFactory() {
     return batchReqFact;
   }
+
+  @Override
+  public ODataMetadataValidation metadataValidation() {
+    return metadataValidation;
+  }
 }

http://git-wip-us.apache.org/repos/asf/olingo-odata4/blob/48263a8c/lib/client-core/src/main/java/org/apache/olingo/client/core/metadatavalidator/CsdlTypeValidator.java
----------------------------------------------------------------------
diff --git 
a/lib/client-core/src/main/java/org/apache/olingo/client/core/metadatavalidator/CsdlTypeValidator.java
 
b/lib/client-core/src/main/java/org/apache/olingo/client/core/metadatavalidator/CsdlTypeValidator.java
new file mode 100644
index 0000000..b85dfa6
--- /dev/null
+++ 
b/lib/client-core/src/main/java/org/apache/olingo/client/core/metadatavalidator/CsdlTypeValidator.java
@@ -0,0 +1,491 @@
+/*
+ * 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.client.core.metadatavalidator;
+
+import java.util.HashMap;
+import java.util.List;
+import java.util.Map;
+import java.util.Map.Entry;
+
+import org.apache.olingo.commons.api.edm.FullQualifiedName;
+import org.apache.olingo.commons.api.edm.provider.CsdlAction;
+import org.apache.olingo.commons.api.edm.provider.CsdlActionImport;
+import org.apache.olingo.commons.api.edm.provider.CsdlComplexType;
+import org.apache.olingo.commons.api.edm.provider.CsdlEntityContainer;
+import org.apache.olingo.commons.api.edm.provider.CsdlEntitySet;
+import org.apache.olingo.commons.api.edm.provider.CsdlEntityType;
+import org.apache.olingo.commons.api.edm.provider.CsdlFunction;
+import org.apache.olingo.commons.api.edm.provider.CsdlFunctionImport;
+import org.apache.olingo.commons.api.edm.provider.CsdlNavigationProperty;
+import 
org.apache.olingo.commons.api.edm.provider.CsdlNavigationPropertyBinding;
+import org.apache.olingo.commons.api.edm.provider.CsdlStructuralType;
+
+public class CsdlTypeValidator {
+
+  private Map<String, String> aliasNamespaceMap = new HashMap<String, 
String>();
+  private Map<FullQualifiedName, CsdlEntityContainer> csdlContainersMap = 
+      new HashMap<FullQualifiedName, CsdlEntityContainer>();
+  private Map<FullQualifiedName, CsdlEntityType> csdlEntityTypesMap = 
+      new HashMap<FullQualifiedName, CsdlEntityType>();
+  private Map<FullQualifiedName, CsdlComplexType> csdlComplexTypesMap = 
+      new HashMap<FullQualifiedName, CsdlComplexType>();
+  private Map<FullQualifiedName, CsdlAction> csdlActionsMap = 
+      new HashMap<FullQualifiedName, CsdlAction>();
+  private Map<FullQualifiedName, CsdlFunction> csdlFunctionsMap = 
+      new HashMap<FullQualifiedName, CsdlFunction>();
+  
+  /**
+   * 
+   * @param aliasNamespaceMap
+   * @param csdlContainersMap
+   * @param csdlEntityTypesMap
+   * @param csdlComplexTypesMap
+   * @param csdlActionsMap
+   * @param csdlFunctionsMap
+   * @param csdlTermsMap
+   */
+  public CsdlTypeValidator(Map<String, String> aliasNamespaceMap, 
+      Map<FullQualifiedName, CsdlEntityContainer> csdlContainersMap,
+      Map<FullQualifiedName, CsdlEntityType> csdlEntityTypesMap,
+      Map<FullQualifiedName, CsdlComplexType> csdlComplexTypesMap,
+      Map<FullQualifiedName, CsdlAction> csdlActionsMap,
+      Map<FullQualifiedName, CsdlFunction> csdlFunctionsMap) {
+    this.aliasNamespaceMap = aliasNamespaceMap;
+    this.csdlContainersMap = csdlContainersMap;
+    this.csdlEntityTypesMap = csdlEntityTypesMap;
+    this.csdlComplexTypesMap = csdlComplexTypesMap;
+    this.csdlActionsMap = csdlActionsMap;
+    this.csdlFunctionsMap = csdlFunctionsMap;
+  }
+  
+  /**
+   * Validates metadata
+   */
+  public void validateMetadataXML() {
+    validateCsdlEntityTypes();
+    validateCsdlComplexTypes();
+    validateCsdlEntitySet();
+    validateCsdlActionImport();
+    validateCsdlFunctionImport();
+  }
+  
+  /**
+   * This method validates Csdl Entity types.
+   * Looks for correct namespace aliases and correct base types
+   */
+  private void validateCsdlEntityTypes() {
+    for (Map.Entry<FullQualifiedName, CsdlEntityType> entityTypes : 
csdlEntityTypesMap.entrySet()) {
+      if (entityTypes.getValue() != null && entityTypes.getKey() != null) {
+        CsdlEntityType entityType = entityTypes.getValue();
+        if (entityType.getBaseType() != null) {
+          CsdlEntityType baseEntityType;
+          FullQualifiedName baseTypeFQName = entityType.getBaseTypeFQN();
+          if (!csdlEntityTypesMap.containsKey(baseTypeFQName)) {
+            FullQualifiedName fqName = 
validateCsdlEntityTypeWithAlias(baseTypeFQName);
+            baseEntityType = fetchLastCsdlBaseType(fqName);
+          } else {
+            baseEntityType = fetchLastCsdlBaseType(baseTypeFQName);
+          }
+          if (baseEntityType != null && (baseEntityType.getKey() == null || 
+              baseEntityType.getKey().isEmpty())) {
+            throw new RuntimeException("Missing key for EntityType " + 
baseEntityType.getName());
+          }
+        } else if (entityType.getKey() == null || 
entityType.getKey().isEmpty()) {
+          throw new RuntimeException("Missing key for EntityType " + 
entityType.getName());
+        }
+      }
+    }
+  }
+
+  /**
+   * This fetches the last Base Type entity from a hierarchy of base type 
derived types
+   * @param baseTypeFQName
+   * @return CsdlEntityType
+   */
+  private CsdlEntityType fetchLastCsdlBaseType(FullQualifiedName 
baseTypeFQName) {
+    CsdlEntityType baseEntityType = null;
+    while (baseTypeFQName != null) {
+      if (!(csdlEntityTypesMap.containsKey(baseTypeFQName))) {
+        baseTypeFQName = validateCsdlEntityTypeWithAlias(baseTypeFQName);
+      }
+      baseEntityType = csdlEntityTypesMap.get(baseTypeFQName);
+      if (baseEntityType.getKey() != null) {
+        break;
+      } else if (baseEntityType != null && baseEntityType.getBaseType() != 
null) {
+        baseTypeFQName = baseEntityType.getBaseTypeFQN();
+      } else if (baseEntityType.getBaseType() == null) {
+        break;
+      }
+    }
+    return baseEntityType;
+  }
+  
+  /**
+   * This fetches the last Base Type entity from a hierarchy of base type 
derived types
+   * @param baseTypeFQName
+   * @return CsdlNavigationProperty
+   */
+  private CsdlNavigationProperty fetchLastBaseEntityHavingNavigationProperty(
+      FullQualifiedName baseTypeFQName, String navBindingProperty) {
+    CsdlEntityType baseEntityType = null;
+    while (baseTypeFQName != null) {
+      if (!(csdlEntityTypesMap.containsKey(baseTypeFQName))) {
+        baseTypeFQName = validateCsdlEntityTypeWithAlias(baseTypeFQName);
+      }
+      baseEntityType = csdlEntityTypesMap.get(baseTypeFQName);
+      if (baseEntityType.getNavigationProperty(navBindingProperty) != null) {
+        break;
+      } else if (baseEntityType != null && baseEntityType.getBaseType() != 
null) {
+        baseTypeFQName = baseEntityType.getBaseTypeFQN();
+      } else if (baseEntityType.getBaseType() == null) {
+        break;
+      }
+    }
+    if (baseEntityType == null) {
+      throw new RuntimeException("Entity TYpe is null with fully qualified 
name:" + baseTypeFQName);
+    }
+    return baseEntityType.getNavigationProperty(navBindingProperty);
+  }
+
+  /**
+   * This validates the namespace to alias mapping
+   * @param fQName
+   * @return FullQualifiedName
+   */
+  private FullQualifiedName validateCsdlEntityTypeWithAlias(FullQualifiedName 
fQName) {
+    String namespace = aliasNamespaceMap.get(fQName.getNamespace());
+    FullQualifiedName fqName = new FullQualifiedName(namespace, 
fQName.getName());
+    if (!csdlEntityTypesMap.containsKey(fqName)) {
+      throw new RuntimeException("Invalid Entity Type " + fQName);
+    }
+    return fqName;
+  }
+  
+  /**
+   * This validates the namespace to alias mapping
+   * @param fqName
+   * @return FullQualifiedName
+   */
+  private FullQualifiedName fetchCorrectNamespaceFromAlias(FullQualifiedName 
fqName) {
+    if (aliasNamespaceMap.containsKey(fqName.getNamespace())) {
+      String namespace = aliasNamespaceMap.get(fqName.getNamespace());
+      fqName = new FullQualifiedName(namespace, fqName.getName());
+    }
+    return fqName;
+  }
+  
+  /**
+   * This method validates Csdl Complex types.
+   * Looks for correct namespace aliases and correct complex base types
+   */
+  private void validateCsdlComplexTypes() {
+    for (Map.Entry<FullQualifiedName, CsdlComplexType> complexTypes : 
csdlComplexTypesMap.entrySet()) {
+      if (complexTypes.getValue() != null && complexTypes.getKey() != null) {
+        CsdlComplexType complexType = complexTypes.getValue();
+        if (complexType.getBaseType() != null) {
+          FullQualifiedName baseTypeFQName = complexType.getBaseTypeFQN();
+          if (!csdlComplexTypesMap.containsKey(baseTypeFQName)) {
+            validateCsdlComplexTypeWithAlias(baseTypeFQName);
+          }
+        }
+      }
+    }
+  }
+
+  /**
+   * This validates the namespace to alias mapping
+   * @param aliasName
+   * @return
+   */
+  private FullQualifiedName validateCsdlComplexTypeWithAlias(FullQualifiedName 
aliasName) {
+    String namespace = aliasNamespaceMap.get(aliasName.getNamespace());
+    FullQualifiedName fqName = new FullQualifiedName(namespace, 
aliasName.getName());
+    if (!csdlComplexTypesMap.containsKey(fqName)) {
+      throw new RuntimeException("Invalid Complex BaseType " + aliasName);
+    }
+    return fqName;
+  }
+  
+  /**
+   * This method validates Csdl entity sets.
+   * It checks if entity sets are part of correct container and 
+   * entity types defined for entity sets are correct.
+   */
+  private void validateCsdlEntitySet() {
+    for (Map.Entry<FullQualifiedName, CsdlEntityContainer> container : 
csdlContainersMap.entrySet()) {
+      for (CsdlEntitySet entitySet : container.getValue().getEntitySets()) {
+        FullQualifiedName entityType = entitySet.getTypeFQN();
+        if (!(csdlEntityTypesMap.containsKey(entityType))) {
+          validateCsdlEntityTypeWithAlias(entityType);
+        }
+        validateNavigationBindingPaths(entitySet, container);
+      }
+    }
+  }
+  
+  /**
+   * This method checks if the target entity of the navigation binding path is 
defined.
+   * It checks if the type of navigation property of the source entity and 
target entity is the same
+   * @param container 
+   * @param CsdlEntitySet
+   */
+  private void validateNavigationBindingPaths(CsdlEntitySet entitySet, 
+      Entry<FullQualifiedName, CsdlEntityContainer> container) {
+    List<CsdlNavigationPropertyBinding> navigationPropertyBindings = 
entitySet.getNavigationPropertyBindings();
+    if (!navigationPropertyBindings.isEmpty()) {
+      for (CsdlNavigationPropertyBinding navigationPropertyBinding : 
navigationPropertyBindings) {
+        String navBindingPath = navigationPropertyBinding.getPath();
+        String navBindingTarget = navigationPropertyBinding.getTarget();
+        CsdlEntityType sourceEntityType = null;
+        if (!(csdlEntityTypesMap.containsKey(new 
FullQualifiedName(entitySet.getType())))) {
+          sourceEntityType = csdlEntityTypesMap.get(
+              validateCsdlEntityTypeWithAlias(new 
FullQualifiedName(entitySet.getType())));
+        } else {
+          sourceEntityType = csdlEntityTypesMap.get(new 
FullQualifiedName(entitySet.getType()));
+        }
+        
+        CsdlNavigationProperty navProperty = null;
+        String targetType = null;
+        if (navBindingPath.contains("/")) {
+          navProperty = 
findLastQualifiedNameHavingNavigationProperty(navBindingPath, sourceEntityType);
+        } else {
+          navProperty = (CsdlNavigationProperty) sourceEntityType.
+              getNavigationProperty(navBindingPath);
+          if (navProperty == null) {
+            navProperty = fetchLastBaseEntityHavingNavigationProperty(
+                sourceEntityType.getBaseTypeFQN(), navBindingPath);
+          }
+        }
+        if (navBindingTarget.contains("/")) {
+          targetType = findLastQualifiedTargetName(navBindingTarget);
+        } else {
+          if (container.getValue().getEntitySet(navBindingTarget) == null) {
+            if (container.getValue().getSingleton(navBindingTarget) != null) {
+              throw new RuntimeException("Validations of Singletons are not 
supported: "+ navBindingTarget);
+            } else {
+              throw new RuntimeException("Navigation Property Target " + 
navBindingTarget + 
+                  " is not part of the same container " + container.getKey());
+            }
+          }
+          FullQualifiedName fqName = 
container.getValue().getEntitySet(navBindingTarget).getTypeFQN();
+          if (!(csdlEntityTypesMap.containsKey(fqName))) {
+            fqName = validateCsdlEntityTypeWithAlias(fqName);
+          }
+          targetType = fqName.getFullQualifiedNameAsString();
+        }
+        FullQualifiedName navFQName = 
fetchCorrectNamespaceFromAlias(navProperty.getTypeFQN());
+        validateReferentialConstraint(sourceEntityType, 
+            csdlEntityTypesMap.get(new FullQualifiedName(targetType)), 
navProperty);
+        if (!(navFQName.getFullQualifiedNameAsString().equals(targetType))
+            && !(csdlEntityTypesMap.get(navFQName).getBaseTypeFQN() != null &&
+                
fetchCorrectNamespaceFromAlias(csdlEntityTypesMap.get(navFQName).
+                    
getBaseTypeFQN()).getFullQualifiedNameAsString().equals(targetType))) {
+          throw new RuntimeException("Navigation Property Type " +  
+              navFQName +" does not match "
+                  + "the binding target type " + targetType);
+        }
+      }
+    }
+  }
+  
+  /**
+   * @param sourceEntityType
+   * @param targetEntityType
+   * @param navProperty
+   */
+  private void validateReferentialConstraint(CsdlEntityType sourceEntityType, 
CsdlEntityType targetEntityType,
+      CsdlNavigationProperty navProperty) {
+    if (!navProperty.getReferentialConstraints().isEmpty()) {
+      String propertyName = 
navProperty.getReferentialConstraints().get(0).getProperty();
+      if (sourceEntityType.getProperty(propertyName) == null) {
+        throw new RuntimeException("Property name " + propertyName + " not 
part of the source entity.");
+      }
+      String referencedPropertyName = 
navProperty.getReferentialConstraints().get(0).getReferencedProperty();
+      if (targetEntityType.getProperty(referencedPropertyName) == null) {
+        throw new RuntimeException("Property name " + referencedPropertyName + 
" not part of the target entity.");
+      }
+    }
+  }
+  
+  /**
+   * This looks for the correct entity set 
+   * when the target entity set is part of some other namespace
+   * e.g <NavigationPropertyBinding Path="Products" 
Target="SomeModel.SomeContainer/SomeSet" />
+   * @param navBindingTarget
+   * @return String
+   */
+  private String findLastQualifiedTargetName(String navBindingTarget) {
+    String[] targetPaths = navBindingTarget.split("/");
+    CsdlEntityContainer csdlContainer = csdlContainersMap.containsKey(new 
FullQualifiedName(targetPaths[0])) ?
+      csdlContainersMap.get(new FullQualifiedName(targetPaths[0])) : 
+        csdlContainersMap.get(fetchCorrectNamespaceFromAlias(new 
FullQualifiedName(targetPaths[0])));
+    if (csdlContainer == null) {
+      throw new RuntimeException("Container with FullyQualifiedName " + 
targetPaths[0] + " not found.");
+    }
+    String targetEntitySetName = targetPaths[1];
+    CsdlEntitySet csdlEntitySet = 
csdlContainer.getEntitySet(targetEntitySetName);
+    if (csdlEntitySet == null) {
+      throw new RuntimeException("Target Entity Set mentioned in 
navigationBindingProperty "
+          + "not found in the container " + csdlContainer.getName());
+    }
+    FullQualifiedName fqName = csdlEntitySet.getTypeFQN();
+    if (!(csdlEntityTypesMap.containsKey(fqName))) {
+      fqName = validateCsdlEntityTypeWithAlias(fqName);
+    }
+    return fqName.getFullQualifiedNameAsString();
+  }
+  
+  /**
+   * This looks for the last fully qualified identifier to fetch the 
navigation property
+   * e.g if navigation property path is 
Microsoft.Exchange.Services.OData.Model.ItemAttachment/Item 
+   * then it fetches the entity ItemAttachment and fetches the navigation 
property Item
+   * if navigation property path is 
EntityType/ComplexType/OData.Model.DerivedComplexType/Item
+   * then it fetches the complex type DerivedComplexType and fetches the 
navigation property Item
+   * @param navBindingPath
+   * @return CsdlNavigationProperty
+   */
+  private CsdlNavigationProperty 
findLastQualifiedNameHavingNavigationProperty(String navBindingPath,
+      CsdlEntityType sourceEntityType) {
+    String[] paths = navBindingPath.split("/");
+    String lastFullQualifiedName = "";
+    for (String path : paths) {
+      if (path.contains(".")) {
+        lastFullQualifiedName = path;
+      }
+    }
+    String strNavProperty = paths[paths.length - 1];
+    String remainingPath = 
navBindingPath.substring(navBindingPath.indexOf(lastFullQualifiedName) 
+        + lastFullQualifiedName.length() + (lastFullQualifiedName.length() == 
0 ? 0 : 1), 
+        navBindingPath.lastIndexOf(strNavProperty));
+    if (remainingPath.length() > 0) {
+      remainingPath = remainingPath.substring(0, remainingPath.length() - 1);
+    }
+    CsdlNavigationProperty navProperty = null;
+    CsdlEntityType sourceEntityTypeHavingNavProp = 
lastFullQualifiedName.length() == 0 ? sourceEntityType : 
+      (csdlEntityTypesMap.containsKey(new 
FullQualifiedName(lastFullQualifiedName)) ? 
+          csdlEntityTypesMap.get(new FullQualifiedName(lastFullQualifiedName)) 
: 
+            csdlEntityTypesMap.get(fetchCorrectNamespaceFromAlias(new 
FullQualifiedName(lastFullQualifiedName))));
+    if (sourceEntityTypeHavingNavProp == null) {
+      CsdlComplexType sourceComplexTypeHavingNavProp = 
+          csdlComplexTypesMap.containsKey(new 
FullQualifiedName(lastFullQualifiedName)) ?
+          csdlComplexTypesMap.get(new 
FullQualifiedName(lastFullQualifiedName)) : 
+            csdlComplexTypesMap.get(fetchCorrectNamespaceFromAlias(new 
FullQualifiedName(lastFullQualifiedName)));
+      if (sourceComplexTypeHavingNavProp == null) {
+        throw new RuntimeException("The fully Qualified type " + 
lastFullQualifiedName + 
+            " mentioned in navigation binding path not found ");
+      }
+      navProperty = remainingPath.length() > 0 ? 
fetchNavigationProperty(remainingPath, strNavProperty, 
+          sourceComplexTypeHavingNavProp) : 
sourceComplexTypeHavingNavProp.getNavigationProperty(strNavProperty);
+    } else {
+      navProperty = remainingPath.length() > 0 ? 
fetchNavigationProperty(remainingPath, strNavProperty, 
+          sourceEntityTypeHavingNavProp) : 
sourceEntityTypeHavingNavProp.getNavigationProperty(strNavProperty);
+    }
+    return navProperty;
+  }
+  
+  /**
+   * fetch the actual navigation property from the remaning path
+   * @param remainingPath
+   * @param strNavProperty
+   * @param sourceTypeHavingNavProp
+   * @return CsdlNavigationProperty
+   */
+  private CsdlNavigationProperty fetchNavigationProperty(String remainingPath,
+      String strNavProperty, CsdlStructuralType sourceTypeHavingNavProp) {
+    String[] paths = remainingPath.split("/");
+    for (String path : paths) {
+      FullQualifiedName fqName = null;
+      if (sourceTypeHavingNavProp instanceof CsdlComplexType) {
+        fqName = 
((CsdlComplexType)sourceTypeHavingNavProp).getProperty(path).getTypeAsFQNObject();
+      } else if (sourceTypeHavingNavProp instanceof CsdlEntityType) {
+        fqName = 
((CsdlEntityType)sourceTypeHavingNavProp).getProperty(path).getTypeAsFQNObject();
+      }
+      if (fqName != null) {
+        String namespace = aliasNamespaceMap.get(fqName.getNamespace());
+        fqName = namespace != null ? new FullQualifiedName(namespace, 
fqName.getName()) : fqName;
+      }
+      
+      sourceTypeHavingNavProp = csdlEntityTypesMap.get(fqName) != null ? 
+          csdlEntityTypesMap.get(fqName) : 
+            csdlComplexTypesMap.get(fqName);
+    }
+    return sourceTypeHavingNavProp.getNavigationProperty(strNavProperty);
+  }
+
+  /**
+   * This method validates Csdl action import.
+   * It checks if action imports are part of correct container and
+   * actions defined for action imports are correct
+   */
+  private void validateCsdlActionImport() {
+    for (Map.Entry<FullQualifiedName, CsdlEntityContainer> container : 
csdlContainersMap.entrySet()) {
+      for (CsdlActionImport actionImport : 
container.getValue().getActionImports()) {
+        FullQualifiedName fqaction = actionImport.getActionFQN();
+        if (!(csdlActionsMap.containsKey(fqaction))) {
+          validateCsdlActionsWithAlias(fqaction);
+        }
+      }
+    }
+  }
+
+  /**
+   * This validates the namespace to alias mapping
+   * @param aliasName
+   * @return FullQualifiedName
+   */
+  private FullQualifiedName validateCsdlActionsWithAlias(FullQualifiedName 
aliasName) {
+    String namespace = aliasNamespaceMap.get(aliasName.getNamespace());
+    FullQualifiedName fqName = new FullQualifiedName(namespace, 
aliasName.getName());
+    if (!csdlActionsMap.containsKey(fqName)) {
+      throw new RuntimeException("Invalid Action " + aliasName);
+    }
+    return fqName;
+  }
+
+  /**
+   * This methods validates csdl function imports.
+   * It checks if function imports are part of correct container and
+   * functions defined for function imports are correct
+   */
+  private void validateCsdlFunctionImport() {
+    for (Map.Entry<FullQualifiedName, CsdlEntityContainer> container : 
csdlContainersMap.entrySet()) {
+      for (CsdlFunctionImport functionImport : 
container.getValue().getFunctionImports()) {
+        FullQualifiedName fqaction = functionImport.getFunctionFQN();
+        if (!(csdlFunctionsMap.containsKey(fqaction))) {
+          validateCsdlFunctionsWithAlias(fqaction);
+        }
+      }
+    }
+    
+  }
+
+  /**
+   * This validates the namespace to alias mapping
+   * @param aliasName
+   * @return FullQualifiedName
+   */
+  private FullQualifiedName validateCsdlFunctionsWithAlias(FullQualifiedName 
aliasName) {
+    String namespace = aliasNamespaceMap.get(aliasName.getNamespace());
+    FullQualifiedName fqName = new FullQualifiedName(namespace, 
aliasName.getName());
+    if (!csdlFunctionsMap.containsKey(fqName)) {
+      throw new RuntimeException("Invalid Function " + aliasName);
+    }
+    return fqName;
+  }
+}

http://git-wip-us.apache.org/repos/asf/olingo-odata4/blob/48263a8c/lib/client-core/src/main/java/org/apache/olingo/client/core/metadatavalidator/EdmTypeValidator.java
----------------------------------------------------------------------
diff --git 
a/lib/client-core/src/main/java/org/apache/olingo/client/core/metadatavalidator/EdmTypeValidator.java
 
b/lib/client-core/src/main/java/org/apache/olingo/client/core/metadatavalidator/EdmTypeValidator.java
new file mode 100644
index 0000000..236e18e
--- /dev/null
+++ 
b/lib/client-core/src/main/java/org/apache/olingo/client/core/metadatavalidator/EdmTypeValidator.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.client.core.metadatavalidator;
+
+import java.util.HashMap;
+import java.util.List;
+import java.util.Map;
+
+import org.apache.olingo.commons.api.edm.EdmBindingTarget;
+import org.apache.olingo.commons.api.edm.EdmComplexType;
+import org.apache.olingo.commons.api.edm.EdmEntityContainer;
+import org.apache.olingo.commons.api.edm.EdmEntitySet;
+import org.apache.olingo.commons.api.edm.EdmEntityType;
+import org.apache.olingo.commons.api.edm.EdmFunction;
+import org.apache.olingo.commons.api.edm.EdmFunctionImport;
+import org.apache.olingo.commons.api.edm.EdmNavigationProperty;
+import org.apache.olingo.commons.api.edm.EdmNavigationPropertyBinding;
+import org.apache.olingo.commons.api.edm.EdmSingleton;
+import org.apache.olingo.commons.api.edm.EdmStructuredType;
+import org.apache.olingo.commons.api.edm.FullQualifiedName;
+
+public class EdmTypeValidator {
+  
+  private Map<String, String> aliasNamespaceMap = new HashMap<String, 
String>();
+  private Map<FullQualifiedName, EdmEntityContainer> edmContainersMap = 
+      new HashMap<FullQualifiedName, EdmEntityContainer>();
+  private Map<FullQualifiedName, EdmEntityType> edmEntityTypesMap = 
+      new HashMap<FullQualifiedName, EdmEntityType>();
+  private Map<FullQualifiedName, EdmComplexType> edmComplexTypesMap = 
+      new HashMap<FullQualifiedName, EdmComplexType>();
+  private Map<FullQualifiedName, EdmFunction> edmFunctionsMap = 
+      new HashMap<FullQualifiedName, EdmFunction>();
+
+  /**
+   * 
+   * @param aliasNamespaceMap
+   * @param edmContainersMap
+   * @param edmEntityTypesMap
+   * @param edmComplexTypesMap
+   * @param edmFunctionsMap
+   * @param edmTermsMap
+   */
+  public EdmTypeValidator(Map<String, String> aliasNamespaceMap,
+      Map<FullQualifiedName, EdmEntityContainer> edmContainersMap,
+      Map<FullQualifiedName, EdmEntityType> edmEntityTypesMap,
+      Map<FullQualifiedName, EdmComplexType> edmComplexTypesMap,
+      Map<FullQualifiedName, EdmFunction> edmFunctionsMap) {
+    this.aliasNamespaceMap = aliasNamespaceMap;
+    this.edmContainersMap = edmContainersMap;
+    this.edmEntityTypesMap = edmEntityTypesMap;
+    this.edmComplexTypesMap = edmComplexTypesMap;
+    this.edmFunctionsMap = edmFunctionsMap;
+  }
+  
+  /**
+   * Validates Edm
+   */
+  public void validateEdm() {
+    validateEdmEntityTypes();
+    validateEdmEntitySet();
+    validateEdmFunctionImport();
+  }
+  
+  /**
+   * This method validates Edm Entity types.
+   * Looks for correct namespace aliases and correct base types
+   */
+  private void validateEdmEntityTypes() {
+    for (Map.Entry<FullQualifiedName, EdmEntityType> entityTypes : 
edmEntityTypesMap.entrySet()) {
+      if (entityTypes.getValue() != null && entityTypes.getKey() != null) {
+        EdmEntityType entityType = entityTypes.getValue();
+        if (entityType.getBaseType() != null) {
+          FullQualifiedName baseTypeFQName = 
entityType.getBaseType().getFullQualifiedName();
+          EdmEntityType baseEntityType = edmEntityTypesMap.get(baseTypeFQName);
+          
+          if (baseEntityType != null && 
baseEntityType.getKeyPredicateNames().isEmpty()) {
+            throw new RuntimeException("Missing key for EntityType " + 
baseEntityType.getName());
+          }
+        } else if (entityType.getKeyPredicateNames().isEmpty()) {
+          throw new RuntimeException("Missing key for EntityType " + 
entityType.getName());
+        }
+      }
+    }
+
+  }
+  
+  /**
+   * This method validates Edm entity sets.
+   * It checks if entity sets are part of correct container and 
+   * entity types defined for entity sets are correct and
+   * validates navigation property bindings 
+   */
+  private void validateEdmEntitySet() {
+    for (Map.Entry<FullQualifiedName, EdmEntityContainer> container : 
edmContainersMap.entrySet()) {
+      for (EdmEntitySet entitySet : container.getValue().getEntitySets()) {
+        validateNavigationBindingPaths(entitySet);
+      }
+    }
+  }
+
+  /**
+   * This method checks if the target entity of the navigation binding path is 
defined.
+   * It checks if the type of navigation property of the source entity and 
target entity is the same
+   * @param entitySet
+   * @param container 
+   */
+  private void validateNavigationBindingPaths(EdmEntitySet entitySet) {
+    List<EdmNavigationPropertyBinding> navigationPropertyBindings = 
entitySet.getNavigationPropertyBindings();
+    if (!navigationPropertyBindings.isEmpty()) {
+      for (EdmNavigationPropertyBinding navigationPropertyBinding : 
navigationPropertyBindings) {
+        String navBindingPath = navigationPropertyBinding.getPath();
+        EdmBindingTarget edmBindingTarget = 
entitySet.getRelatedBindingTarget(navBindingPath);
+        EdmEntityType sourceEntityType = 
edmEntityTypesMap.get(entitySet.getEntityType().getFullQualifiedName());
+        
+        if (edmBindingTarget instanceof EdmSingleton) {
+          throw new RuntimeException("Validations of Singletons are not 
supported: " + edmBindingTarget.getName());
+        }
+        
+        EdmEntityType targetEntityType = edmBindingTarget.getEntityType();
+        EdmNavigationProperty navProperty = null;
+        if (navBindingPath.contains("/")) {
+          navProperty = 
findLastQualifiedNameHavingNavigationProperty(navBindingPath, sourceEntityType);
+        } else {
+          navProperty = (EdmNavigationProperty) 
sourceEntityType.getProperty(navBindingPath);
+        }
+        FullQualifiedName navFQName = 
fetchCorrectNamespaceFromAlias(navProperty.getType().getFullQualifiedName());
+        validateReferentialConstraint(sourceEntityType, targetEntityType, 
navProperty);
+        String targetType = 
targetEntityType.getFullQualifiedName().getFullQualifiedNameAsString();
+        if (!(navFQName.getFullQualifiedNameAsString().equals(targetType)) 
+            && !(navProperty.getType().compatibleTo(targetEntityType))) {
+          throw new RuntimeException("Navigation Property Type " +  
+            navProperty.getType().getFullQualifiedName() +" does not match "
+                + "the binding target type " + targetType);
+        }
+      }
+    }
+  }
+
+  /**
+   * @param sourceEntityType
+   * @param targetEntityType
+   * @param navProperty
+   */
+  private void validateReferentialConstraint(EdmEntityType sourceEntityType, 
EdmEntityType targetEntityType,
+      EdmNavigationProperty navProperty) {
+    if (!navProperty.getReferentialConstraints().isEmpty()) {
+      String propertyName = 
navProperty.getReferentialConstraints().get(0).getPropertyName();
+      if (sourceEntityType.getProperty(propertyName) == null) {
+        throw new RuntimeException("Property name "+ propertyName + " not part 
of the source entity.");
+      }
+      String referencedPropertyName = 
navProperty.getReferentialConstraints().get(0).getReferencedPropertyName();
+      if (targetEntityType.getProperty(referencedPropertyName) == null) {
+        throw new RuntimeException("Property name " + referencedPropertyName + 
" not part of the target entity.");
+      }
+    }
+  }
+  
+  /**
+   * This looks for the last fully qualified identifier to fetch the 
navigation property
+   * e.g if navigation property path is 
Microsoft.Exchange.Services.OData.Model.ItemAttachment/Item 
+   * then it fetches the entity ItemAttachment and fetches the navigation 
property Item
+   * if navigation property path is 
EntityType/ComplexType/OData.Model.DerivedComplexType/Item
+   * then it fetches the complex type DerivedComplexType and fetches the 
navigation property Item
+   * @param navBindingPath
+   * @param sourceEntityType 
+   * @return EdmNavigationProperty
+   */
+  private EdmNavigationProperty 
findLastQualifiedNameHavingNavigationProperty(String navBindingPath, 
+      EdmEntityType sourceEntityType) {
+    String[] paths = navBindingPath.split("/");
+    String lastFullQualifiedName = "";
+    for (String path : paths) {
+      if (path.contains(".")) {
+        lastFullQualifiedName = path;
+      }
+    }
+    String strNavProperty = paths[paths.length - 1];
+    String remainingPath = 
navBindingPath.substring(navBindingPath.indexOf(lastFullQualifiedName) 
+        + lastFullQualifiedName.length() + (lastFullQualifiedName.length() == 
0 ? 0 : 1), 
+        navBindingPath.lastIndexOf(strNavProperty));
+    if (remainingPath.length() > 0) {
+      remainingPath = remainingPath.substring(0, remainingPath.length() - 1);
+    }
+    EdmNavigationProperty navProperty = null;
+    EdmEntityType sourceEntityTypeHavingNavProp = 
lastFullQualifiedName.length() == 0 ? sourceEntityType : 
+      (edmEntityTypesMap.containsKey(new 
FullQualifiedName(lastFullQualifiedName)) ? 
+        edmEntityTypesMap.get(new FullQualifiedName(lastFullQualifiedName)) : 
+          edmEntityTypesMap.get(fetchCorrectNamespaceFromAlias(new 
FullQualifiedName(lastFullQualifiedName))));
+    if (sourceEntityTypeHavingNavProp == null) {
+      EdmComplexType sourceComplexTypeHavingNavProp = 
+          edmComplexTypesMap.containsKey(new 
FullQualifiedName(lastFullQualifiedName)) ?
+          edmComplexTypesMap.get(new FullQualifiedName(lastFullQualifiedName)) 
: 
+            edmComplexTypesMap.get(fetchCorrectNamespaceFromAlias(new 
FullQualifiedName(lastFullQualifiedName)));
+      if (sourceComplexTypeHavingNavProp == null) {
+        throw new RuntimeException("The fully Qualified type " + 
lastFullQualifiedName + 
+            " mentioned in navigation binding path not found ");
+      }
+      navProperty = remainingPath.length() > 0 ? 
fetchNavigationProperty(remainingPath, strNavProperty, 
+          sourceComplexTypeHavingNavProp) : 
sourceComplexTypeHavingNavProp.getNavigationProperty(strNavProperty);
+    } else {
+      navProperty = remainingPath.length() > 0 ? 
fetchNavigationProperty(remainingPath, strNavProperty, 
+          sourceEntityTypeHavingNavProp) : 
sourceEntityTypeHavingNavProp.getNavigationProperty(strNavProperty);
+    }
+    return navProperty;
+  }
+  
+  /**
+   * Fetch the correct navigation property from the remaining path
+   * @param remainingPath
+   * @param strNavProperty
+   * @param sourceTypeHavingNavProp
+   * @return EdmNavigationProperty
+   */
+  private EdmNavigationProperty fetchNavigationProperty(String remainingPath,
+      String strNavProperty, EdmStructuredType sourceTypeHavingNavProp) {
+    String[] paths = remainingPath.split("/");
+    for (String path : paths) {
+      FullQualifiedName fqName = null;
+      if (sourceTypeHavingNavProp instanceof EdmComplexType) {
+        fqName = 
((EdmComplexType)sourceTypeHavingNavProp).getProperty(path).getType().getFullQualifiedName();
+      } else if (sourceTypeHavingNavProp instanceof EdmEntityType) {
+        fqName = 
((EdmEntityType)sourceTypeHavingNavProp).getProperty(path).getType().getFullQualifiedName();
+      }
+      if (fqName != null) {
+        String namespace = aliasNamespaceMap.get(fqName.getNamespace());
+        fqName = namespace != null ? new FullQualifiedName(namespace, 
fqName.getName()) : fqName;
+      }
+      
+      sourceTypeHavingNavProp = edmEntityTypesMap.containsKey(fqName) ? 
+          edmEntityTypesMap.get(fqName) : 
+            edmComplexTypesMap.get(fqName);
+    }
+    return sourceTypeHavingNavProp.getNavigationProperty(strNavProperty);
+  }
+
+  /**
+   * This validates the namespace to alias mapping
+   * @param fQName
+   * @return FullQualifiedName
+   */
+  private FullQualifiedName fetchCorrectNamespaceFromAlias(FullQualifiedName 
fqName) {
+    if (aliasNamespaceMap.containsKey(fqName.getNamespace())) {
+      String namespace = aliasNamespaceMap.get(fqName.getNamespace());
+      fqName = new FullQualifiedName(namespace, fqName.getName());
+    }
+    return fqName;
+  }
+
+  /**
+   * This methods validates edm function imports.
+   * It checks if function imports are part of correct container and
+   * functions defined for function imports are correct
+   */
+  private void validateEdmFunctionImport() {
+    for (Map.Entry<FullQualifiedName, EdmEntityContainer> container : 
edmContainersMap.entrySet()) {
+      for (EdmFunctionImport functionImport : 
container.getValue().getFunctionImports()) {
+        FullQualifiedName fqFunction = functionImport.getFunctionFqn();
+        if (!(edmFunctionsMap.containsKey(fqFunction))) {
+          validateEdmFunctionsWithAlias(fqFunction);
+        }
+      }
+    }
+  }
+
+  /**
+   * This validates the namespace to alias mapping
+   * @param aliasName
+   * @return FullQualifiedName
+   */
+  private FullQualifiedName validateEdmFunctionsWithAlias(FullQualifiedName 
aliasName) {
+    String namespace = aliasNamespaceMap.get(aliasName.getNamespace());
+    FullQualifiedName fqName = new FullQualifiedName(namespace, 
aliasName.getName());
+    if (!edmFunctionsMap.containsKey(fqName)) {
+      throw new RuntimeException("Invalid Function " + aliasName);
+    }
+    return fqName;
+  }
+}

http://git-wip-us.apache.org/repos/asf/olingo-odata4/blob/48263a8c/lib/client-core/src/main/java/org/apache/olingo/client/core/serialization/ODataMetadataValidationImpl.java
----------------------------------------------------------------------
diff --git 
a/lib/client-core/src/main/java/org/apache/olingo/client/core/serialization/ODataMetadataValidationImpl.java
 
b/lib/client-core/src/main/java/org/apache/olingo/client/core/serialization/ODataMetadataValidationImpl.java
new file mode 100644
index 0000000..97e2d6d
--- /dev/null
+++ 
b/lib/client-core/src/main/java/org/apache/olingo/client/core/serialization/ODataMetadataValidationImpl.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.client.core.serialization;
+
+import java.util.HashMap;
+import java.util.List;
+import java.util.Map;
+
+import org.apache.olingo.client.api.edm.xml.XMLMetadata;
+import org.apache.olingo.client.api.serialization.ODataMetadataValidation;
+import org.apache.olingo.client.core.metadatavalidator.CsdlTypeValidator;
+import org.apache.olingo.client.core.metadatavalidator.EdmTypeValidator;
+import org.apache.olingo.commons.api.edm.Edm;
+import org.apache.olingo.commons.api.edm.EdmAction;
+import org.apache.olingo.commons.api.edm.EdmComplexType;
+import org.apache.olingo.commons.api.edm.EdmEntityContainer;
+import org.apache.olingo.commons.api.edm.EdmEntityType;
+import org.apache.olingo.commons.api.edm.EdmFunction;
+import org.apache.olingo.commons.api.edm.EdmSchema;
+import org.apache.olingo.commons.api.edm.FullQualifiedName;
+import org.apache.olingo.commons.api.edm.provider.CsdlAction;
+import org.apache.olingo.commons.api.edm.provider.CsdlComplexType;
+import org.apache.olingo.commons.api.edm.provider.CsdlEntityContainer;
+import org.apache.olingo.commons.api.edm.provider.CsdlEntityType;
+import org.apache.olingo.commons.api.edm.provider.CsdlFunction;
+import org.apache.olingo.commons.api.edm.provider.CsdlSchema;
+
+public class ODataMetadataValidationImpl implements ODataMetadataValidation {
+
+  @Override
+  public void validateMetadata(Edm edm) {
+    Map<FullQualifiedName, EdmEntityType> edmEntityTypesMap = new 
HashMap<FullQualifiedName, EdmEntityType>();
+    Map<FullQualifiedName, EdmComplexType> edmComplexTypesMap = new 
HashMap<FullQualifiedName, EdmComplexType>();
+    Map<FullQualifiedName, EdmFunction> edmFunctionsMap = new 
HashMap<FullQualifiedName, EdmFunction>();
+    Map<FullQualifiedName, EdmEntityContainer> edmContainersMap = new 
HashMap<FullQualifiedName, EdmEntityContainer>();
+    Map<String, String> aliasNamespaceMap = new HashMap<String, String>();
+    List<EdmSchema> edmSchemas = edm.getSchemas();
+    for (EdmSchema edmSchema : edmSchemas) {
+      List<EdmEntityType> edmEntityTypes = edmSchema.getEntityTypes();
+      for (EdmEntityType edmEntityType : edmEntityTypes) {
+        edmEntityTypesMap.put(edmEntityType.getFullQualifiedName(), 
edmEntityType);
+      }
+      List<EdmComplexType> edmComplexTypes = edmSchema.getComplexTypes();
+      for (EdmComplexType edmComplexType : edmComplexTypes) {
+        edmComplexTypesMap.put(edmComplexType.getFullQualifiedName(), 
edmComplexType);
+      }
+      List<EdmFunction> edmFunctions = edmSchema.getFunctions();
+      for (EdmFunction edmFunction : edmFunctions) {
+        edmFunctionsMap.put(edmFunction.getFullQualifiedName(), edmFunction);
+      }
+      aliasNamespaceMap.put(edmSchema.getAlias(), edmSchema.getNamespace());
+      if (edmSchema.getEntityContainer() != null) {
+        
edmContainersMap.put(edmSchema.getEntityContainer().getFullQualifiedName(), 
edmSchema.getEntityContainer());
+      }
+    }
+    EdmTypeValidator edmTypeValidator = new 
EdmTypeValidator(aliasNamespaceMap, edmContainersMap, 
+        edmEntityTypesMap, edmComplexTypesMap, edmFunctionsMap);
+    edmTypeValidator.validateEdm();
+  }
+
+  @Override
+  public void validateMetadata(XMLMetadata xmlMetadata) {
+    Map<FullQualifiedName, CsdlEntityType> csdlEntityTypesMap = new 
HashMap<FullQualifiedName, CsdlEntityType>();
+    Map<FullQualifiedName, CsdlComplexType> csdlComplexTypesMap = new 
HashMap<FullQualifiedName, CsdlComplexType>();
+    Map<FullQualifiedName, CsdlAction> csdlActionsMap = new 
HashMap<FullQualifiedName, CsdlAction>();
+    Map<FullQualifiedName, CsdlFunction> csdlFunctionsMap = new 
HashMap<FullQualifiedName, CsdlFunction>();
+    Map<FullQualifiedName, CsdlEntityContainer> csdlContainersMap = 
+        new HashMap<FullQualifiedName, CsdlEntityContainer>();
+    Map<String, String> aliasNamespaceMap = new HashMap<String, String>();
+    List<CsdlSchema> csdlSchemas = xmlMetadata.getSchemas();
+    for (CsdlSchema csdlSchema : csdlSchemas) {
+      List<CsdlEntityType> csdlEntityTypes = csdlSchema.getEntityTypes();
+      for (CsdlEntityType csdlEntityType : csdlEntityTypes) {
+        csdlEntityTypesMap.put(new FullQualifiedName(
+            csdlSchema.getNamespace(), csdlEntityType.getName()), 
csdlEntityType);
+      }
+      List<CsdlComplexType> csdlComplexTypes = csdlSchema.getComplexTypes();
+      for (CsdlComplexType csdlComplexType : csdlComplexTypes) {
+        csdlComplexTypesMap.put(new FullQualifiedName(
+            csdlSchema.getNamespace(), csdlComplexType.getName()), 
csdlComplexType);
+      }
+      List<CsdlAction> csdlActions = csdlSchema.getActions();
+      for (CsdlAction csdlAction : csdlActions) {
+        csdlActionsMap.put(new FullQualifiedName(
+            csdlSchema.getNamespace(), csdlAction.getName()), csdlAction);
+      }
+      List<CsdlFunction> csdlFunctions = csdlSchema.getFunctions();
+      for (CsdlFunction csdlFunction : csdlFunctions) {
+        csdlFunctionsMap.put(
+            new FullQualifiedName(csdlSchema.getNamespace(), 
csdlFunction.getName()), csdlFunction);
+      }
+      aliasNamespaceMap.put(csdlSchema.getAlias(), csdlSchema.getNamespace());
+      if (csdlSchema.getEntityContainer() != null) {
+        csdlContainersMap.put(new FullQualifiedName(
+            csdlSchema.getNamespace(), 
csdlSchema.getEntityContainer().getName()), csdlSchema.getEntityContainer());
+      }
+    }
+    CsdlTypeValidator csdlTypeValidator = new 
CsdlTypeValidator(aliasNamespaceMap, csdlContainersMap, 
+        csdlEntityTypesMap, csdlComplexTypesMap, csdlActionsMap, 
csdlFunctionsMap);
+    csdlTypeValidator.validateMetadataXML();
+  }
+}

Reply via email to