[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(); + } +}
