[OLINGO-1180] Validation of metadata post deserialization
This commit is contained in:
parent
379a3c706e
commit
48263a8ce3
|
@ -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.domain.ClientObjectFactory;
|
||||||
import org.apache.olingo.client.api.serialization.ClientODataDeserializer;
|
import org.apache.olingo.client.api.serialization.ClientODataDeserializer;
|
||||||
import org.apache.olingo.client.api.serialization.ODataBinder;
|
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.ODataReader;
|
||||||
import org.apache.olingo.client.api.serialization.ODataSerializer;
|
import org.apache.olingo.client.api.serialization.ODataSerializer;
|
||||||
import org.apache.olingo.client.api.serialization.ODataWriter;
|
import org.apache.olingo.client.api.serialization.ODataWriter;
|
||||||
|
@ -75,4 +76,6 @@ public interface ODataClient {
|
||||||
CUDRequestFactory getCUDRequestFactory();
|
CUDRequestFactory getCUDRequestFactory();
|
||||||
|
|
||||||
BatchRequestFactory getBatchRequestFactory();
|
BatchRequestFactory getBatchRequestFactory();
|
||||||
|
|
||||||
|
ODataMetadataValidation metadataValidation();
|
||||||
}
|
}
|
||||||
|
|
|
@ -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);
|
||||||
|
}
|
|
@ -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.domain.ClientObjectFactory;
|
||||||
import org.apache.olingo.client.api.serialization.ClientODataDeserializer;
|
import org.apache.olingo.client.api.serialization.ClientODataDeserializer;
|
||||||
import org.apache.olingo.client.api.serialization.ODataBinder;
|
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.ODataReader;
|
||||||
import org.apache.olingo.client.api.serialization.ODataSerializer;
|
import org.apache.olingo.client.api.serialization.ODataSerializer;
|
||||||
import org.apache.olingo.client.api.serialization.ODataWriter;
|
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.ClientODataDeserializerImpl;
|
||||||
import org.apache.olingo.client.core.serialization.JsonSerializer;
|
import org.apache.olingo.client.core.serialization.JsonSerializer;
|
||||||
import org.apache.olingo.client.core.serialization.ODataBinderImpl;
|
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.ODataReaderImpl;
|
||||||
import org.apache.olingo.client.core.serialization.ODataWriterImpl;
|
import org.apache.olingo.client.core.serialization.ODataWriterImpl;
|
||||||
import org.apache.olingo.client.core.uri.FilterFactoryImpl;
|
import org.apache.olingo.client.core.uri.FilterFactoryImpl;
|
||||||
|
@ -80,6 +82,8 @@ public class ODataClientImpl implements ODataClient {
|
||||||
protected final Configuration configuration = new ConfigurationImpl();
|
protected final Configuration configuration = new ConfigurationImpl();
|
||||||
|
|
||||||
private final ODataWriter writer = new ODataWriterImpl(this);
|
private final ODataWriter writer = new ODataWriterImpl(this);
|
||||||
|
|
||||||
|
private final ODataMetadataValidation metadataValidation = new ODataMetadataValidationImpl();
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public Configuration getConfiguration() {
|
public Configuration getConfiguration() {
|
||||||
|
@ -176,4 +180,9 @@ public class ODataClientImpl implements ODataClient {
|
||||||
public BatchRequestFactory getBatchRequestFactory() {
|
public BatchRequestFactory getBatchRequestFactory() {
|
||||||
return batchReqFact;
|
return batchReqFact;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public ODataMetadataValidation metadataValidation() {
|
||||||
|
return metadataValidation;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -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;
|
||||||
|
}
|
||||||
|
}
|
|
@ -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;
|
||||||
|
}
|
||||||
|
}
|
|
@ -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();
|
||||||
|
}
|
||||||
|
}
|
File diff suppressed because it is too large
Load Diff
|
@ -0,0 +1,76 @@
|
||||||
|
<?xml version="1.0" encoding="utf-8"?>
|
||||||
|
<!--
|
||||||
|
|
||||||
|
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.
|
||||||
|
|
||||||
|
-->
|
||||||
|
<edmx:Edmx Version="4.0" xmlns:edmx="http://docs.oasis-open.org/odata/ns/edmx">
|
||||||
|
<edmx:DataServices m:DataServiceVersion="4.0" m:MaxDataServiceVersion="4.0" xmlns:m="http://docs.oasis-open.org/odata/ns/metadata">
|
||||||
|
<Schema Namespace="Microsoft.Exchange.Services.OData.Model" xmlns="http://docs.oasis-open.org/odata/ns/edm">
|
||||||
|
<EntityType Name="Customer" Abstract="true">
|
||||||
|
<Key>
|
||||||
|
<PropertyRef Name="CustomerId" />
|
||||||
|
</Key>
|
||||||
|
<Property Name="CustomerId" Type="Edm.String" Nullable="false"/>
|
||||||
|
<Property Name="CustomerName" Type="Edm.String" />
|
||||||
|
<Property Name="Pet" Type="Microsoft.Exchange.Services.OData.Model.Animal" />
|
||||||
|
</EntityType>
|
||||||
|
<EntityType Name="VipCustomer" BaseType="Microsoft.Exchange.Services.OData.Model.Customer" Abstract="true">
|
||||||
|
<Property Name="CustomerType" Type="Edm.String" />
|
||||||
|
<Property Name="VipLocations" Type="Collection(Microsoft.Exchange.Services.OData.Model.Address)" />
|
||||||
|
</EntityType>
|
||||||
|
<EntityType Name="City">
|
||||||
|
<Key>
|
||||||
|
<PropertyRef Name="Id" />
|
||||||
|
</Key>
|
||||||
|
<Property Name="Id" Type="Edm.String" Nullable="false"/>
|
||||||
|
</EntityType>
|
||||||
|
<ComplexType Name="Animal">
|
||||||
|
</ComplexType>
|
||||||
|
<ComplexType Name="Human" BaseType="Microsoft.Exchange.Services.OData.Model.Animal">
|
||||||
|
<Property Name="HumanAddress" Type="Microsoft.Exchange.Services.OData.Model.USAddress" />
|
||||||
|
</ComplexType>
|
||||||
|
<ComplexType Name="Horse" BaseType="Microsoft.Exchange.Services.OData.Model.Animal">
|
||||||
|
<Property Name="HorseAddress" Type="Microsoft.Exchange.Services.OData.Model.USAddress" />
|
||||||
|
<Property Name="HorseAddresses" Type="Collection(Microsoft.Exchange.Services.OData.Model.USAddress)" />
|
||||||
|
</ComplexType>
|
||||||
|
<ComplexType Name="Address">
|
||||||
|
<NavigationProperty Name="City" Type="Microsoft.Exchange.Services.OData.Model.City" />
|
||||||
|
</ComplexType>
|
||||||
|
<ComplexType Name="USAddress" BaseType="Microsoft.Exchange.Services.OData.Model.Address">
|
||||||
|
<Property Name="CountryAddress" Type="Microsoft.Exchange.Services.OData.Model.CountryAddress" />
|
||||||
|
<NavigationProperty Name="SubCity" Type="Microsoft.Exchange.Services.OData.Model.City" />
|
||||||
|
</ComplexType>
|
||||||
|
<ComplexType Name="CountryAddress" BaseType="Microsoft.Exchange.Services.OData.Model.Address">
|
||||||
|
<NavigationProperty Name="SubCity" Type="Microsoft.Exchange.Services.OData.Model.City" />
|
||||||
|
</ComplexType>
|
||||||
|
<EntityContainer Name="EntityContainer" m:IsDefaultEntityContainer="true">
|
||||||
|
<EntitySet Name="Customers" EntityType="Microsoft.Exchange.Services.OData.Model.Customer">
|
||||||
|
<NavigationPropertyBinding Path="Pet/Microsoft.Exchange.Services.OData.Model.Human/HumanAddress/SubCity" Target="HumanCities" />
|
||||||
|
<NavigationPropertyBinding Path="Pet/Microsoft.Exchange.Services.OData.Model.Horse/HorseAddress/SubCity" Target="HorseCities" />
|
||||||
|
<NavigationPropertyBinding Path="Pet/Microsoft.Exchange.Services.OData.Model.Horse/HorseAddresses/SubCity" Target="HorseCities" />
|
||||||
|
<NavigationPropertyBinding Path="Microsoft.Exchange.Services.OData.Model.VipCustomer/VipLocations/Microsoft.Exchange.Services.OData.Model.USAddress/SubCity" Target="HumanCities" />
|
||||||
|
<NavigationPropertyBinding Path="Microsoft.Exchange.Services.OData.Model.VipCustomer/VipLocations/Microsoft.Exchange.Services.OData.Model.USAddress/CountryAddress/SubCity" Target="HumanCities" />
|
||||||
|
<NavigationPropertyBinding Path="Microsoft.Exchange.Services.OData.Model.VipCustomer/VipLocations/City" Target="HumanCities" />
|
||||||
|
</EntitySet>
|
||||||
|
<EntitySet Name="HumanCities" EntityType="Microsoft.Exchange.Services.OData.Model.City"/>
|
||||||
|
<EntitySet Name="HorseCities" EntityType="Microsoft.Exchange.Services.OData.Model.City"/>
|
||||||
|
</EntityContainer>
|
||||||
|
</Schema>
|
||||||
|
</edmx:DataServices>
|
||||||
|
</edmx:Edmx>
|
|
@ -0,0 +1,88 @@
|
||||||
|
<?xml version="1.0" encoding="utf-8"?>
|
||||||
|
<!--
|
||||||
|
|
||||||
|
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.
|
||||||
|
|
||||||
|
-->
|
||||||
|
<edmx:Edmx Version="4.0" xmlns:edmx="http://docs.oasis-open.org/odata/ns/edmx">
|
||||||
|
<edmx:DataServices m:DataServiceVersion="4.0" m:MaxDataServiceVersion="4.0" xmlns:m="http://docs.oasis-open.org/odata/ns/metadata">
|
||||||
|
<Schema Namespace="Microsoft.Exchange.Services.OData.Model" xmlns="http://docs.oasis-open.org/odata/ns/edm" Alias="Namespace1_Alias">
|
||||||
|
<EntityType Name="Customer" Abstract="true">
|
||||||
|
<Key>
|
||||||
|
<PropertyRef Name="CustomerId" />
|
||||||
|
</Key>
|
||||||
|
<Property Name="CustomerId" Type="Edm.String" Nullable="false"/>
|
||||||
|
<Property Name="CustomerName" Type="Edm.String" />
|
||||||
|
<Property Name="Pet" Type="Microsoft.Exchange.Services.OData.Model.Animal" />
|
||||||
|
</EntityType>
|
||||||
|
<EntityType Name="VipCustomer" BaseType="Microsoft.Exchange.Services.OData.Model.Customer" Abstract="true">
|
||||||
|
<Property Name="CustomerType" Type="Edm.String" />
|
||||||
|
<Property Name="VipLocations" Type="Collection(Microsoft.Exchange.Services.OData.Model.Address)" />
|
||||||
|
</EntityType>
|
||||||
|
<EntityType Name="City">
|
||||||
|
<Key>
|
||||||
|
<PropertyRef Name="Id" />
|
||||||
|
</Key>
|
||||||
|
<Property Name="Id" Type="Edm.String" Nullable="false"/>
|
||||||
|
</EntityType>
|
||||||
|
<ComplexType Name="Animal">
|
||||||
|
</ComplexType>
|
||||||
|
<ComplexType Name="Human" BaseType="Microsoft.Exchange.Services.OData.Model.Animal">
|
||||||
|
<Property Name="HumanAddress" Type="Microsoft.Exchange.Services.OData.Model.USAddress" />
|
||||||
|
</ComplexType>
|
||||||
|
<ComplexType Name="Horse" BaseType="Microsoft.Exchange.Services.OData.Model.Animal">
|
||||||
|
<Property Name="HorseAddress" Type="Microsoft.Exchange.Services.OData.Model.USAddress" />
|
||||||
|
<Property Name="HorseAddresses" Type="Collection(Microsoft.Exchange.Services.OData.Model.USAddress)" />
|
||||||
|
</ComplexType>
|
||||||
|
<ComplexType Name="Address">
|
||||||
|
<NavigationProperty Name="City" Type="Microsoft.Exchange.Services.OData.Model.City" />
|
||||||
|
</ComplexType>
|
||||||
|
<ComplexType Name="USAddress" BaseType="Microsoft.Exchange.Services.OData.Model.Address">
|
||||||
|
<Property Name="CountryAddress" Type="Microsoft.Exchange.Services.OData.Model.CountryAddress" />
|
||||||
|
<NavigationProperty Name="SubCity" Type="Microsoft.Exchange.Services.OData.Model.City" />
|
||||||
|
</ComplexType>
|
||||||
|
<ComplexType Name="CountryAddress" BaseType="Microsoft.Exchange.Services.OData.Model.Address">
|
||||||
|
<NavigationProperty Name="SubCity" Type="Microsoft.Exchange.Services.OData.Model.City" />
|
||||||
|
</ComplexType>
|
||||||
|
<EntityContainer Name="EntityContainer" m:IsDefaultEntityContainer="true">
|
||||||
|
<EntitySet Name="Customers" EntityType="Microsoft.Exchange.Services.OData.Model.Customer">
|
||||||
|
<NavigationPropertyBinding Path="Pet/Microsoft.Exchange.Services.OData.Model.Human/HumanAddress/SubCity" Target="ODataWebExperimental.OData.Model.EntityContainer1/HumanCities" />
|
||||||
|
<NavigationPropertyBinding Path="Pet/Microsoft.Exchange.Services.OData.Model.Horse/HorseAddress/SubCity" Target="HorseCities" />
|
||||||
|
<NavigationPropertyBinding Path="Pet/Microsoft.Exchange.Services.OData.Model.Horse/HorseAddresses/SubCity" Target="HorseCities" />
|
||||||
|
<NavigationPropertyBinding Path="Microsoft.Exchange.Services.OData.Model.VipCustomer/VipLocations/Microsoft.Exchange.Services.OData.Model.USAddress/SubCity" Target="ODataWebExperimental.OData.Model.EntityContainer1/HumanCities" />
|
||||||
|
<NavigationPropertyBinding Path="Microsoft.Exchange.Services.OData.Model.VipCustomer/VipLocations/Microsoft.Exchange.Services.OData.Model.USAddress/CountryAddress/SubCity" Target="ODataWebExperimental.OData.Model.EntityContainer1/HumanCities" />
|
||||||
|
<NavigationPropertyBinding Path="Microsoft.Exchange.Services.OData.Model.VipCustomer/VipLocations/City" Target="ODataWebExperimental.OData.Model.EntityContainer1/HumanCities" />
|
||||||
|
</EntitySet>
|
||||||
|
<EntitySet Name="HorseCities" EntityType="Microsoft.Exchange.Services.OData.Model.City"/>
|
||||||
|
</EntityContainer>
|
||||||
|
</Schema>
|
||||||
|
<Schema Namespace="ODataWebExperimental.OData.Model" xmlns="http://docs.oasis-open.org/odata/ns/edm">
|
||||||
|
<EntityContainer Name="EntityContainer1" p4:LazyLoadingEnabled="true" xmlns:p4="http://schemas.microsoft.com/ado/2009/02/edm/annotation">
|
||||||
|
<EntitySet Name="HumanCities" EntityType="Microsoft.Exchange.Services.OData.Model.City"/>
|
||||||
|
<EntitySet Name="Customers" EntityType="Microsoft.Exchange.Services.OData.Model.Customer">
|
||||||
|
<NavigationPropertyBinding Path="Pet/Microsoft.Exchange.Services.OData.Model.Human/HumanAddress/SubCity" Target="HumanCities" />
|
||||||
|
<NavigationPropertyBinding Path="Pet/Microsoft.Exchange.Services.OData.Model.Horse/HorseAddress/SubCity" Target="Namespace1_Alias.EntityContainer/HorseCities" />
|
||||||
|
<NavigationPropertyBinding Path="Pet/Microsoft.Exchange.Services.OData.Model.Horse/HorseAddresses/SubCity" Target="Microsoft.Exchange.Services.OData.Model.EntityContainer/HorseCities" />
|
||||||
|
<NavigationPropertyBinding Path="Microsoft.Exchange.Services.OData.Model.VipCustomer/VipLocations/Microsoft.Exchange.Services.OData.Model.USAddress/SubCity" Target="HumanCities" />
|
||||||
|
<NavigationPropertyBinding Path="Microsoft.Exchange.Services.OData.Model.VipCustomer/VipLocations/Microsoft.Exchange.Services.OData.Model.USAddress/CountryAddress/SubCity" Target="HumanCities" />
|
||||||
|
<NavigationPropertyBinding Path="Microsoft.Exchange.Services.OData.Model.VipCustomer/VipLocations/City" Target="HumanCities" />
|
||||||
|
</EntitySet>
|
||||||
|
</EntityContainer>
|
||||||
|
</Schema>
|
||||||
|
</edmx:DataServices>
|
||||||
|
</edmx:Edmx>
|
|
@ -0,0 +1,88 @@
|
||||||
|
<?xml version="1.0" encoding="utf-8"?>
|
||||||
|
<!--
|
||||||
|
|
||||||
|
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.
|
||||||
|
|
||||||
|
-->
|
||||||
|
<edmx:Edmx Version="4.0" xmlns:edmx="http://docs.oasis-open.org/odata/ns/edmx">
|
||||||
|
<edmx:DataServices m:DataServiceVersion="4.0" m:MaxDataServiceVersion="4.0" xmlns:m="http://docs.oasis-open.org/odata/ns/metadata">
|
||||||
|
<Schema Namespace="Microsoft.Exchange.Services.OData.Model" Alias="Namespace1_Alias" xmlns="http://docs.oasis-open.org/odata/ns/edm">
|
||||||
|
<EntityType Name="Customer" Abstract="true">
|
||||||
|
<Key>
|
||||||
|
<PropertyRef Name="CustomerId" />
|
||||||
|
</Key>
|
||||||
|
<Property Name="CustomerId" Type="Edm.String" Nullable="false"/>
|
||||||
|
<Property Name="CustomerName" Type="Edm.String" />
|
||||||
|
<Property Name="Pet" Type="Microsoft.Exchange.Services.OData.Model.Animal" />
|
||||||
|
</EntityType>
|
||||||
|
<EntityType Name="VipCustomer" BaseType="Namespace1_Alias.Customer" Abstract="true">
|
||||||
|
<Property Name="CustomerType" Type="Edm.String" />
|
||||||
|
<Property Name="VipLocations" Type="Collection(Namespace1_Alias.Address)" />
|
||||||
|
</EntityType>
|
||||||
|
<EntityType Name="City">
|
||||||
|
<Key>
|
||||||
|
<PropertyRef Name="Id" />
|
||||||
|
</Key>
|
||||||
|
<Property Name="Id" Type="Edm.String" Nullable="false"/>
|
||||||
|
</EntityType>
|
||||||
|
<ComplexType Name="Animal">
|
||||||
|
</ComplexType>
|
||||||
|
<ComplexType Name="Human" BaseType="Namespace1_Alias.Animal">
|
||||||
|
<Property Name="HumanAddress" Type="Microsoft.Exchange.Services.OData.Model.USAddress" />
|
||||||
|
</ComplexType>
|
||||||
|
<ComplexType Name="Horse" BaseType="Microsoft.Exchange.Services.OData.Model.Animal">
|
||||||
|
<Property Name="HorseAddress" Type="Namespace1_Alias.USAddress" />
|
||||||
|
<Property Name="HorseAddresses" Type="Collection(Microsoft.Exchange.Services.OData.Model.USAddress)" />
|
||||||
|
</ComplexType>
|
||||||
|
<ComplexType Name="Address">
|
||||||
|
<NavigationProperty Name="City" Type="Microsoft.Exchange.Services.OData.Model.City" />
|
||||||
|
</ComplexType>
|
||||||
|
<ComplexType Name="USAddress" BaseType="Microsoft.Exchange.Services.OData.Model.Address">
|
||||||
|
<Property Name="CountryAddress" Type="Microsoft.Exchange.Services.OData.Model.CountryAddress" />
|
||||||
|
<NavigationProperty Name="SubCity" Type="Microsoft.Exchange.Services.OData.Model.City" />
|
||||||
|
</ComplexType>
|
||||||
|
<ComplexType Name="CountryAddress" BaseType="Microsoft.Exchange.Services.OData.Model.Address">
|
||||||
|
<NavigationProperty Name="SubCity" Type="Microsoft.Exchange.Services.OData.Model.City" />
|
||||||
|
</ComplexType>
|
||||||
|
<EntityContainer Name="EntityContainer" m:IsDefaultEntityContainer="true">
|
||||||
|
<EntitySet Name="Customers" EntityType="Namespace1_Alias.Customer">
|
||||||
|
<NavigationPropertyBinding Path="Pet/Namespace1_Alias.Human/HumanAddress/SubCity" Target="ODataWebExperimental.OData.Model.EntityContainer1/HumanCities" />
|
||||||
|
<NavigationPropertyBinding Path="Pet/Microsoft.Exchange.Services.OData.Model.Horse/HorseAddress/SubCity" Target="HorseCities" />
|
||||||
|
<NavigationPropertyBinding Path="Pet/Microsoft.Exchange.Services.OData.Model.Horse/HorseAddresses/SubCity" Target="HorseCities" />
|
||||||
|
<NavigationPropertyBinding Path="Microsoft.Exchange.Services.OData.Model.VipCustomer/VipLocations/Microsoft.Exchange.Services.OData.Model.USAddress/SubCity" Target="ODataWebExperimental.OData.Model.EntityContainer1/HumanCities" />
|
||||||
|
<NavigationPropertyBinding Path="Namespace1_Alias.VipCustomer/VipLocations/Microsoft.Exchange.Services.OData.Model.USAddress/CountryAddress/SubCity" Target="ODataWebExperimental.OData.Model.EntityContainer1/HumanCities" />
|
||||||
|
<NavigationPropertyBinding Path="Microsoft.Exchange.Services.OData.Model.VipCustomer/VipLocations/City" Target="ODataWebExperimental.OData.Model.EntityContainer1/HumanCities" />
|
||||||
|
</EntitySet>
|
||||||
|
<EntitySet Name="HorseCities" EntityType="Microsoft.Exchange.Services.OData.Model.City"/>
|
||||||
|
</EntityContainer>
|
||||||
|
</Schema>
|
||||||
|
<Schema Namespace="ODataWebExperimental.OData.Model" xmlns="http://docs.oasis-open.org/odata/ns/edm" Alias="Namespace2_Alias">
|
||||||
|
<EntityContainer Name="EntityContainer1" p4:LazyLoadingEnabled="true" xmlns:p4="http://schemas.microsoft.com/ado/2009/02/edm/annotation">
|
||||||
|
<EntitySet Name="HumanCities" EntityType="Namespace1_Alias.City"/>
|
||||||
|
<EntitySet Name="Customers" EntityType="Microsoft.Exchange.Services.OData.Model.Customer">
|
||||||
|
<NavigationPropertyBinding Path="Pet/Microsoft.Exchange.Services.OData.Model.Human/HumanAddress/SubCity" Target="HumanCities" />
|
||||||
|
<NavigationPropertyBinding Path="Pet/Microsoft.Exchange.Services.OData.Model.Horse/HorseAddress/SubCity" Target="Namespace1_Alias.EntityContainer/HorseCities" />
|
||||||
|
<NavigationPropertyBinding Path="Pet/Microsoft.Exchange.Services.OData.Model.Horse/HorseAddresses/SubCity" Target="Microsoft.Exchange.Services.OData.Model.EntityContainer/HorseCities" />
|
||||||
|
<NavigationPropertyBinding Path="Microsoft.Exchange.Services.OData.Model.VipCustomer/VipLocations/Microsoft.Exchange.Services.OData.Model.USAddress/SubCity" Target="HumanCities" />
|
||||||
|
<NavigationPropertyBinding Path="Microsoft.Exchange.Services.OData.Model.VipCustomer/VipLocations/Microsoft.Exchange.Services.OData.Model.USAddress/CountryAddress/SubCity" Target="HumanCities" />
|
||||||
|
<NavigationPropertyBinding Path="Microsoft.Exchange.Services.OData.Model.VipCustomer/VipLocations/City" Target="HumanCities" />
|
||||||
|
</EntitySet>
|
||||||
|
</EntityContainer>
|
||||||
|
</Schema>
|
||||||
|
</edmx:DataServices>
|
||||||
|
</edmx:Edmx>
|
|
@ -0,0 +1,355 @@
|
||||||
|
<?xml version="1.0" encoding="utf-8"?>
|
||||||
|
<!--
|
||||||
|
|
||||||
|
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.
|
||||||
|
|
||||||
|
-->
|
||||||
|
<edmx:Edmx Version="4.0" xmlns:edmx="http://docs.oasis-open.org/odata/ns/edmx">
|
||||||
|
<edmx:DataServices>
|
||||||
|
<Schema Namespace="Microsoft.OData.SampleService.Models.TripPin" xmlns="http://docs.oasis-open.org/odata/ns/edm">
|
||||||
|
<EnumType Name="PersonGender">
|
||||||
|
<Member Name="Male" Value="0" />
|
||||||
|
<Member Name="Female" Value="1" />
|
||||||
|
<Member Name="Unknown" Value="2" />
|
||||||
|
</EnumType>
|
||||||
|
<ComplexType Name="City">
|
||||||
|
<Property Name="CountryRegion" Type="Edm.String" Nullable="false" />
|
||||||
|
<Property Name="Name" Type="Edm.String" Nullable="false" />
|
||||||
|
<Property Name="Region" Type="Edm.String" Nullable="false" />
|
||||||
|
</ComplexType>
|
||||||
|
<ComplexType Name="Location" OpenType="true">
|
||||||
|
<Property Name="Address" Type="Edm.String" Nullable="false" />
|
||||||
|
<Property Name="City" Type="Microsoft.OData.SampleService.Models.TripPin.City" Nullable="false" />
|
||||||
|
</ComplexType>
|
||||||
|
<ComplexType Name="EventLocation" BaseType="Microsoft.OData.SampleService.Models.TripPin.Location" OpenType="true">
|
||||||
|
<Property Name="BuildingInfo" Type="Edm.String" />
|
||||||
|
</ComplexType>
|
||||||
|
<ComplexType Name="AirportLocation" BaseType="Microsoft.OData.SampleService.Models.TripPin.Location" OpenType="true">
|
||||||
|
<Property Name="Loc" Type="Edm.GeographyPoint" Nullable="false" SRID="4326" />
|
||||||
|
</ComplexType>
|
||||||
|
<EntityType Name="Photo" HasStream="true">
|
||||||
|
<Key>
|
||||||
|
<PropertyRef Name="Id" />
|
||||||
|
</Key>
|
||||||
|
<Property Name="Id" Type="Edm.Int64" Nullable="false">
|
||||||
|
<Annotation Term="Org.OData.Core.V1.Permissions">
|
||||||
|
<EnumMember>Org.OData.Core.V1.Permission/Read</EnumMember>
|
||||||
|
</Annotation>
|
||||||
|
</Property>
|
||||||
|
<Property Name="Name" Type="Edm.String" />
|
||||||
|
<Annotation Term="Org.OData.Core.V1.AcceptableMediaTypes">
|
||||||
|
<Collection>
|
||||||
|
<String>image/jpeg</String>
|
||||||
|
</Collection>
|
||||||
|
</Annotation>
|
||||||
|
</EntityType>
|
||||||
|
<EntityType Name="Person" OpenType="true">
|
||||||
|
<Key>
|
||||||
|
<PropertyRef Name="UserName" />
|
||||||
|
</Key>
|
||||||
|
<Property Name="UserName" Type="Edm.String" Nullable="false">
|
||||||
|
<Annotation Term="Org.OData.Core.V1.Permissions">
|
||||||
|
<EnumMember>Org.OData.Core.V1.Permission/Read</EnumMember>
|
||||||
|
</Annotation>
|
||||||
|
</Property>
|
||||||
|
<Property Name="FirstName" Type="Edm.String" Nullable="false" />
|
||||||
|
<Property Name="LastName" Type="Edm.String" Nullable="false" />
|
||||||
|
<Property Name="Emails" Type="Collection(Edm.String)" />
|
||||||
|
<Property Name="AddressInfo" Type="Collection(Microsoft.OData.SampleService.Models.TripPin.Location)" />
|
||||||
|
<Property Name="Gender" Type="Microsoft.OData.SampleService.Models.TripPin.PersonGender" />
|
||||||
|
<Property Name="Concurrency" Type="Edm.Int64" Nullable="false">
|
||||||
|
<Annotation Term="Org.OData.Core.V1.Computed" Bool="true" />
|
||||||
|
</Property>
|
||||||
|
<NavigationProperty Name="Friends" Type="Collection(Microsoft.OData.SampleService.Models.TripPin.Person)" />
|
||||||
|
<NavigationProperty Name="Trips" Type="Collection(Microsoft.OData.SampleService.Models.TripPin.Trip)" ContainsTarget="true" />
|
||||||
|
<NavigationProperty Name="Photo" Type="Microsoft.OData.SampleService.Models.TripPin.Photo" />
|
||||||
|
</EntityType>
|
||||||
|
<EntityType Name="Airline">
|
||||||
|
<Key>
|
||||||
|
<PropertyRef Name="AirlineCode" />
|
||||||
|
</Key>
|
||||||
|
<Property Name="AirlineCode" Type="Edm.String" Nullable="false">
|
||||||
|
<Annotation Term="Org.OData.Core.V1.Permissions">
|
||||||
|
<EnumMember>Org.OData.Core.V1.Permission/Read</EnumMember>
|
||||||
|
</Annotation>
|
||||||
|
</Property>
|
||||||
|
<Property Name="Name" Type="Edm.String" Nullable="false" />
|
||||||
|
</EntityType>
|
||||||
|
<EntityType Name="Airport">
|
||||||
|
<Key>
|
||||||
|
<PropertyRef Name="IcaoCode" />
|
||||||
|
</Key>
|
||||||
|
<Property Name="IcaoCode" Type="Edm.String" Nullable="false">
|
||||||
|
<Annotation Term="Org.OData.Core.V1.Permissions">
|
||||||
|
<EnumMember>Org.OData.Core.V1.Permission/Read</EnumMember>
|
||||||
|
</Annotation>
|
||||||
|
</Property>
|
||||||
|
<Property Name="Name" Type="Edm.String" Nullable="false" />
|
||||||
|
<Property Name="IataCode" Type="Edm.String" Nullable="false">
|
||||||
|
<Annotation Term="Org.OData.Core.V1.Immutable" Bool="true" />
|
||||||
|
</Property>
|
||||||
|
<Property Name="Location" Type="Microsoft.OData.SampleService.Models.TripPin.AirportLocation" Nullable="false" />
|
||||||
|
</EntityType>
|
||||||
|
<EntityType Name="PlanItem">
|
||||||
|
<Key>
|
||||||
|
<PropertyRef Name="PlanItemId" />
|
||||||
|
</Key>
|
||||||
|
<Property Name="PlanItemId" Type="Edm.Int32" Nullable="false">
|
||||||
|
<Annotation Term="Org.OData.Core.V1.Permissions">
|
||||||
|
<EnumMember>Org.OData.Core.V1.Permission/Read</EnumMember>
|
||||||
|
</Annotation>
|
||||||
|
</Property>
|
||||||
|
<Property Name="ConfirmationCode" Type="Edm.String" />
|
||||||
|
<Property Name="StartsAt" Type="Edm.DateTimeOffset" />
|
||||||
|
<Property Name="EndsAt" Type="Edm.DateTimeOffset" />
|
||||||
|
<Property Name="Duration" Type="Edm.Duration" />
|
||||||
|
</EntityType>
|
||||||
|
<EntityType Name="PublicTransportation" BaseType="Microsoft.OData.SampleService.Models.TripPin.PlanItem">
|
||||||
|
<Property Name="SeatNumber" Type="Edm.String" />
|
||||||
|
</EntityType>
|
||||||
|
<EntityType Name="Flight" BaseType="Microsoft.OData.SampleService.Models.TripPin.PublicTransportation">
|
||||||
|
<Property Name="FlightNumber" Type="Edm.String" Nullable="false" />
|
||||||
|
<NavigationProperty Name="From" Type="Microsoft.OData.SampleService.Models.TripPin.Airport" Nullable="false" />
|
||||||
|
<NavigationProperty Name="To" Type="Microsoft.OData.SampleService.Models.TripPin.Airport" Nullable="false" />
|
||||||
|
<NavigationProperty Name="Airline" Type="Microsoft.OData.SampleService.Models.TripPin.Airline" Nullable="false" />
|
||||||
|
</EntityType>
|
||||||
|
<EntityType Name="Event" BaseType="Microsoft.OData.SampleService.Models.TripPin.PlanItem" OpenType="true">
|
||||||
|
<Property Name="Description" Type="Edm.String" />
|
||||||
|
<Property Name="OccursAt" Type="Microsoft.OData.SampleService.Models.TripPin.EventLocation" Nullable="false" />
|
||||||
|
</EntityType>
|
||||||
|
<EntityType Name="Trip">
|
||||||
|
<Key>
|
||||||
|
<PropertyRef Name="TripId" />
|
||||||
|
</Key>
|
||||||
|
<Property Name="TripId" Type="Edm.Int32" Nullable="false">
|
||||||
|
<Annotation Term="Org.OData.Core.V1.Permissions">
|
||||||
|
<EnumMember>Org.OData.Core.V1.Permission/Read</EnumMember>
|
||||||
|
</Annotation>
|
||||||
|
</Property>
|
||||||
|
<Property Name="ShareId" Type="Edm.Guid" />
|
||||||
|
<Property Name="Description" Type="Edm.String" />
|
||||||
|
<Property Name="Name" Type="Edm.String" Nullable="false" />
|
||||||
|
<Property Name="Budget" Type="Edm.Single" Nullable="false">
|
||||||
|
<Annotation Term="Org.OData.Measures.V1.ISOCurrency" String="USD" />
|
||||||
|
<Annotation Term="Org.OData.Measures.V1.Scale" Int="2" />
|
||||||
|
</Property>
|
||||||
|
<Property Name="StartsAt" Type="Edm.DateTimeOffset" Nullable="false" />
|
||||||
|
<Property Name="EndsAt" Type="Edm.DateTimeOffset" Nullable="false" />
|
||||||
|
<Property Name="Tags" Type="Collection(Edm.String)" Nullable="false" />
|
||||||
|
<NavigationProperty Name="Photos" Type="Collection(Microsoft.OData.SampleService.Models.TripPin.Photo)" />
|
||||||
|
<NavigationProperty Name="PlanItems" Type="Collection(Microsoft.OData.SampleService.Models.TripPin.PlanItem)" ContainsTarget="true" />
|
||||||
|
</EntityType>
|
||||||
|
<Function Name="GetFavoriteAirline" IsBound="true" EntitySetPath="person/Trips/PlanItems/Microsoft.OData.SampleService.Models.TripPin.Flight/Airline" IsComposable="true">
|
||||||
|
<Parameter Name="person" Type="Microsoft.OData.SampleService.Models.TripPin.Person" Nullable="false" />
|
||||||
|
<ReturnType Type="Microsoft.OData.SampleService.Models.TripPin.Airline" Nullable="false" />
|
||||||
|
</Function>
|
||||||
|
<Function Name="GetInvolvedPeople" IsBound="true" IsComposable="true">
|
||||||
|
<Parameter Name="trip" Type="Microsoft.OData.SampleService.Models.TripPin.Trip" Nullable="false" />
|
||||||
|
<ReturnType Type="Collection(Microsoft.OData.SampleService.Models.TripPin.Person)" Nullable="false" />
|
||||||
|
</Function>
|
||||||
|
<Function Name="GetFriendsTrips" IsBound="true" EntitySetPath="person/Friends/Trips" IsComposable="true">
|
||||||
|
<Parameter Name="person" Type="Microsoft.OData.SampleService.Models.TripPin.Person" Nullable="false" />
|
||||||
|
<Parameter Name="userName" Type="Edm.String" Nullable="false" />
|
||||||
|
<ReturnType Type="Collection(Microsoft.OData.SampleService.Models.TripPin.Trip)" Nullable="false" />
|
||||||
|
</Function>
|
||||||
|
<Function Name="GetNearestAirport" IsComposable="true">
|
||||||
|
<Parameter Name="lat" Type="Edm.Double" Nullable="false" />
|
||||||
|
<Parameter Name="lon" Type="Edm.Double" Nullable="false" />
|
||||||
|
<ReturnType Type="Microsoft.OData.SampleService.Models.TripPin.Airport" Nullable="false" />
|
||||||
|
</Function>
|
||||||
|
<Action Name="ResetDataSource" />
|
||||||
|
<Action Name="ShareTrip" IsBound="true">
|
||||||
|
<Parameter Name="person" Type="Microsoft.OData.SampleService.Models.TripPin.Person" Nullable="false" />
|
||||||
|
<Parameter Name="userName" Type="Edm.String" Nullable="false" />
|
||||||
|
<Parameter Name="tripId" Type="Edm.Int32" Nullable="false" />
|
||||||
|
</Action>
|
||||||
|
<EntityContainer Name="DefaultContainer">
|
||||||
|
<EntitySet Name="Photos" EntityType="Microsoft.OData.SampleService.Models.TripPin.Photo">
|
||||||
|
<Annotation Term="Org.OData.Core.V1.ResourcePath" String="Photos" />
|
||||||
|
<Annotation Term="Org.OData.Capabilities.V1.SearchRestrictions">
|
||||||
|
<Record>
|
||||||
|
<PropertyValue Property="Searchable" Bool="true" />
|
||||||
|
<PropertyValue Property="UnsupportedExpressions">
|
||||||
|
<EnumMember>Org.OData.Capabilities.V1.SearchExpressions/none</EnumMember>
|
||||||
|
</PropertyValue>
|
||||||
|
</Record>
|
||||||
|
</Annotation>
|
||||||
|
<Annotation Term="Org.OData.Capabilities.V1.InsertRestrictions">
|
||||||
|
<Record>
|
||||||
|
<PropertyValue Property="Insertable" Bool="true" />
|
||||||
|
<PropertyValue Property="NonInsertableNavigationProperties">
|
||||||
|
<Collection />
|
||||||
|
</PropertyValue>
|
||||||
|
</Record>
|
||||||
|
</Annotation>
|
||||||
|
</EntitySet>
|
||||||
|
<EntitySet Name="People" EntityType="Microsoft.OData.SampleService.Models.TripPin.Person">
|
||||||
|
<NavigationPropertyBinding Path="Friends" Target="People" />
|
||||||
|
<NavigationPropertyBinding Path="Microsoft.OData.SampleService.Models.TripPin.Flight/Airline" Target="Airlines" />
|
||||||
|
<NavigationPropertyBinding Path="Microsoft.OData.SampleService.Models.TripPin.Flight/From" Target="Airports" />
|
||||||
|
<NavigationPropertyBinding Path="Microsoft.OData.SampleService.Models.TripPin.Flight/To" Target="Airports" />
|
||||||
|
<NavigationPropertyBinding Path="Photo" Target="Photos" />
|
||||||
|
<NavigationPropertyBinding Path="Microsoft.OData.SampleService.Models.TripPin.Trip/Photos" Target="Photos" />
|
||||||
|
<Annotation Term="Org.OData.Core.V1.OptimisticConcurrency">
|
||||||
|
<Collection>
|
||||||
|
<PropertyPath>Concurrency</PropertyPath>
|
||||||
|
</Collection>
|
||||||
|
</Annotation>
|
||||||
|
<Annotation Term="Org.OData.Core.V1.ResourcePath" String="People" />
|
||||||
|
<Annotation Term="Org.OData.Capabilities.V1.NavigationRestrictions">
|
||||||
|
<Record>
|
||||||
|
<PropertyValue Property="Navigability">
|
||||||
|
<EnumMember>Org.OData.Capabilities.V1.NavigationType/None</EnumMember>
|
||||||
|
</PropertyValue>
|
||||||
|
<PropertyValue Property="RestrictedProperties">
|
||||||
|
<Collection>
|
||||||
|
<Record>
|
||||||
|
<PropertyValue Property="NavigationProperty" NavigationPropertyPath="Friends" />
|
||||||
|
<PropertyValue Property="Navigability">
|
||||||
|
<EnumMember>Org.OData.Capabilities.V1.NavigationType/Recursive</EnumMember>
|
||||||
|
</PropertyValue>
|
||||||
|
</Record>
|
||||||
|
</Collection>
|
||||||
|
</PropertyValue>
|
||||||
|
</Record>
|
||||||
|
</Annotation>
|
||||||
|
<Annotation Term="Org.OData.Capabilities.V1.SearchRestrictions">
|
||||||
|
<Record>
|
||||||
|
<PropertyValue Property="Searchable" Bool="true" />
|
||||||
|
<PropertyValue Property="UnsupportedExpressions">
|
||||||
|
<EnumMember>Org.OData.Capabilities.V1.SearchExpressions/none</EnumMember>
|
||||||
|
</PropertyValue>
|
||||||
|
</Record>
|
||||||
|
</Annotation>
|
||||||
|
<Annotation Term="Org.OData.Capabilities.V1.InsertRestrictions">
|
||||||
|
<Record>
|
||||||
|
<PropertyValue Property="Insertable" Bool="true" />
|
||||||
|
<PropertyValue Property="NonInsertableNavigationProperties">
|
||||||
|
<Collection>
|
||||||
|
<NavigationPropertyPath>Trips</NavigationPropertyPath>
|
||||||
|
<NavigationPropertyPath>Friends</NavigationPropertyPath>
|
||||||
|
</Collection>
|
||||||
|
</PropertyValue>
|
||||||
|
</Record>
|
||||||
|
</Annotation>
|
||||||
|
</EntitySet>
|
||||||
|
<EntitySet Name="Airlines" EntityType="Microsoft.OData.SampleService.Models.TripPin.Airline">
|
||||||
|
<Annotation Term="Org.OData.Core.V1.ResourcePath" String="Airlines" />
|
||||||
|
<Annotation Term="Org.OData.Capabilities.V1.SearchRestrictions">
|
||||||
|
<Record>
|
||||||
|
<PropertyValue Property="Searchable" Bool="true" />
|
||||||
|
<PropertyValue Property="UnsupportedExpressions">
|
||||||
|
<EnumMember>Org.OData.Capabilities.V1.SearchExpressions/none</EnumMember>
|
||||||
|
</PropertyValue>
|
||||||
|
</Record>
|
||||||
|
</Annotation>
|
||||||
|
<Annotation Term="Org.OData.Capabilities.V1.InsertRestrictions">
|
||||||
|
<Record>
|
||||||
|
<PropertyValue Property="Insertable" Bool="true" />
|
||||||
|
<PropertyValue Property="NonInsertableNavigationProperties">
|
||||||
|
<Collection />
|
||||||
|
</PropertyValue>
|
||||||
|
</Record>
|
||||||
|
</Annotation>
|
||||||
|
</EntitySet>
|
||||||
|
<EntitySet Name="Airports" EntityType="Microsoft.OData.SampleService.Models.TripPin.Airport">
|
||||||
|
<Annotation Term="Org.OData.Core.V1.ResourcePath" String="Airports" />
|
||||||
|
<Annotation Term="Org.OData.Capabilities.V1.SearchRestrictions">
|
||||||
|
<Record>
|
||||||
|
<PropertyValue Property="Searchable" Bool="true" />
|
||||||
|
<PropertyValue Property="UnsupportedExpressions">
|
||||||
|
<EnumMember>Org.OData.Capabilities.V1.SearchExpressions/none</EnumMember>
|
||||||
|
</PropertyValue>
|
||||||
|
</Record>
|
||||||
|
</Annotation>
|
||||||
|
<Annotation Term="Org.OData.Capabilities.V1.InsertRestrictions">
|
||||||
|
<Record>
|
||||||
|
<PropertyValue Property="Insertable" Bool="false" />
|
||||||
|
<PropertyValue Property="NonInsertableNavigationProperties">
|
||||||
|
<Collection />
|
||||||
|
</PropertyValue>
|
||||||
|
</Record>
|
||||||
|
</Annotation>
|
||||||
|
<Annotation Term="Org.OData.Capabilities.V1.DeleteRestrictions">
|
||||||
|
<Record>
|
||||||
|
<PropertyValue Property="Deletable" Bool="false" />
|
||||||
|
<PropertyValue Property="NonDeletableNavigationProperties">
|
||||||
|
<Collection />
|
||||||
|
</PropertyValue>
|
||||||
|
</Record>
|
||||||
|
</Annotation>
|
||||||
|
</EntitySet>
|
||||||
|
<Singleton Name="Me" Type="Microsoft.OData.SampleService.Models.TripPin.Person">
|
||||||
|
<NavigationPropertyBinding Path="Friends" Target="People" />
|
||||||
|
<NavigationPropertyBinding Path="Microsoft.OData.SampleService.Models.TripPin.Flight/Airline" Target="Airlines" />
|
||||||
|
<NavigationPropertyBinding Path="Microsoft.OData.SampleService.Models.TripPin.Flight/From" Target="Airports" />
|
||||||
|
<NavigationPropertyBinding Path="Microsoft.OData.SampleService.Models.TripPin.Flight/To" Target="Airports" />
|
||||||
|
<NavigationPropertyBinding Path="Photo" Target="Photos" />
|
||||||
|
<NavigationPropertyBinding Path="Microsoft.OData.SampleService.Models.TripPin.Trip/Photos" Target="Photos" />
|
||||||
|
<Annotation Term="Org.OData.Core.V1.ResourcePath" String="Me" />
|
||||||
|
</Singleton>
|
||||||
|
<FunctionImport Name="GetNearestAirport" Function="Microsoft.OData.SampleService.Models.TripPin.GetNearestAirport" EntitySet="Airports" IncludeInServiceDocument="true">
|
||||||
|
<Annotation Term="Org.OData.Core.V1.ResourcePath" String="Microsoft.OData.SampleService.Models.TripPin.GetNearestAirport" />
|
||||||
|
</FunctionImport>
|
||||||
|
<ActionImport Name="ResetDataSource" Action="Microsoft.OData.SampleService.Models.TripPin.ResetDataSource" />
|
||||||
|
<Annotation Term="Org.OData.Core.V1.Description" String="TripPin service is a sample service for OData V4." />
|
||||||
|
</EntityContainer>
|
||||||
|
<Annotations Target="Microsoft.OData.SampleService.Models.TripPin.DefaultContainer">
|
||||||
|
<Annotation Term="Org.OData.Core.V1.DereferenceableIDs" Bool="true" />
|
||||||
|
<Annotation Term="Org.OData.Core.V1.ConventionalIDs" Bool="true" />
|
||||||
|
<Annotation Term="Org.OData.Capabilities.V1.ConformanceLevel">
|
||||||
|
<EnumMember>Org.OData.Capabilities.V1.ConformanceLevelType/Advanced</EnumMember>
|
||||||
|
</Annotation>
|
||||||
|
<Annotation Term="Org.OData.Capabilities.V1.SupportedFormats">
|
||||||
|
<Collection>
|
||||||
|
<String>application/json;odata.metadata=full;IEEE754Compatible=false;odata.streaming=true</String>
|
||||||
|
<String>application/json;odata.metadata=minimal;IEEE754Compatible=false;odata.streaming=true</String>
|
||||||
|
<String>application/json;odata.metadata=none;IEEE754Compatible=false;odata.streaming=true</String>
|
||||||
|
</Collection>
|
||||||
|
</Annotation>
|
||||||
|
<Annotation Term="Org.OData.Capabilities.V1.AsynchronousRequestsSupported" Bool="true" />
|
||||||
|
<Annotation Term="Org.OData.Capabilities.V1.BatchContinueOnErrorSupported" Bool="false" />
|
||||||
|
<Annotation Term="Org.OData.Capabilities.V1.FilterFunctions">
|
||||||
|
<Collection>
|
||||||
|
<String>contains</String>
|
||||||
|
<String>endswith</String>
|
||||||
|
<String>startswith</String>
|
||||||
|
<String>length</String>
|
||||||
|
<String>indexof</String>
|
||||||
|
<String>substring</String>
|
||||||
|
<String>tolower</String>
|
||||||
|
<String>toupper</String>
|
||||||
|
<String>trim</String>
|
||||||
|
<String>concat</String>
|
||||||
|
<String>year</String>
|
||||||
|
<String>month</String>
|
||||||
|
<String>day</String>
|
||||||
|
<String>hour</String>
|
||||||
|
<String>minute</String>
|
||||||
|
<String>second</String>
|
||||||
|
<String>round</String>
|
||||||
|
<String>floor</String>
|
||||||
|
<String>ceiling</String>
|
||||||
|
<String>cast</String>
|
||||||
|
<String>isof</String>
|
||||||
|
</Collection>
|
||||||
|
</Annotation>
|
||||||
|
</Annotations>
|
||||||
|
</Schema>
|
||||||
|
</edmx:DataServices>
|
||||||
|
</edmx:Edmx>
|
Loading…
Reference in New Issue