[Olingo-1259]Function Import enhancements
authorArchana Rai <archana.rai@sap.com>
Mon, 4 Jun 2018 12:34:13 +0000 (18:04 +0530)
committerArchana Rai <archana.rai@sap.com>
Mon, 4 Jun 2018 12:34:13 +0000 (18:04 +0530)
odata2-lib/odata-client-core/src/main/java/org/apache/olingo/odata2/client/core/edm/Impl/EdmEntityContainerImpl.java
odata2-lib/odata-client-core/src/main/java/org/apache/olingo/odata2/client/core/edm/Impl/EdmFunctionImportImpl.java
odata2-lib/odata-client-core/src/main/java/org/apache/olingo/odata2/client/core/ep/deserializer/XmlMetadataDeserializer.java
odata2-lib/odata-client-core/src/test/java/org/apache/olingo/odata2/client/core/ep/deserializer/XMLMetadataFunctionImportDeserializerTest.java
odata2-lib/odata-core/src/main/java/org/apache/olingo/odata2/core/ep/consumer/XmlMetadataConsumer.java
odata2-lib/odata-core/src/test/java/org/apache/olingo/odata2/core/ep/consumer/XmlMetadataConsumerTest.java

index 2a95ef9..1511a21 100644 (file)
@@ -32,7 +32,6 @@ import org.apache.olingo.odata2.api.edm.EdmEntitySet;
 import org.apache.olingo.odata2.api.edm.EdmException;
 import org.apache.olingo.odata2.api.edm.EdmFunctionImport;
 import org.apache.olingo.odata2.api.edm.EdmNavigationProperty;
-import org.apache.olingo.odata2.api.exception.ODataException;
 import org.apache.olingo.odata2.client.api.edm.ClientEdm;
 import org.apache.olingo.odata2.client.api.edm.EdmDocumentation;
 
@@ -131,7 +130,7 @@ public class EdmEntityContainerImpl implements EdmEntityContainer, EdmAnnotatabl
       for(EdmEntitySet entity:edmEntitySets){
         if(entity.getName().equals(name)){
           edmEntitySet = entity;
-                
+          break;
       }
     }
     return edmEntitySet;
index 99f2f15..ff6cbca 100644 (file)
@@ -99,6 +99,10 @@ public class EdmFunctionImportImpl extends EdmNamedImpl implements EdmFunctionIm
     this.edmEntityContainer = edmEntityContainer;
   }
 
+  public String getEntitySetName() {
+    return entitySet;
+  } 
+  
   public Map<String, EdmParameter> getEdmParameters() {
     return edmParameters;
   }
index 3b470a6..f2d85b2 100644 (file)
@@ -60,6 +60,7 @@ import org.apache.olingo.odata2.api.edm.EdmReferentialConstraintRole;
 import org.apache.olingo.odata2.api.edm.EdmSimpleType;
 import org.apache.olingo.odata2.api.edm.EdmSimpleTypeKind;
 import org.apache.olingo.odata2.api.edm.EdmTypeKind;
+import org.apache.olingo.odata2.api.edm.EdmTyped;
 import org.apache.olingo.odata2.api.edm.FullQualifiedName;
 import org.apache.olingo.odata2.api.edm.provider.Facets;
 import org.apache.olingo.odata2.api.ep.EntityProviderException;
@@ -125,7 +126,7 @@ public class XmlMetadataDeserializer {
       new HashMap<FullQualifiedName, FullQualifiedName>();
   private Map<FullQualifiedName, FullQualifiedName> complexBaseTypeMap = 
       new HashMap<FullQualifiedName, FullQualifiedName>();
-   private List<EdmFunctionImport> edmFunctionImportList = new ArrayList<EdmFunctionImport>();
+  private List<EdmFunctionImport> edmFunctionImportList = new ArrayList<EdmFunctionImport>();
   private List<EdmEntitySet> edmEntitySetList = new ArrayList<EdmEntitySet>();
   private List<EdmNavigationProperty> navProperties = new ArrayList<EdmNavigationProperty>();
   private String currentHandledStartTagName;
@@ -556,21 +557,11 @@ public class XmlMetadataDeserializer {
     if (returnTypeString != null) {
       if (returnTypeString.startsWith("Collection") || returnTypeString.startsWith("collection")) {
         returnTypeString = returnTypeString.substring(returnTypeString.indexOf("(") + 1, returnTypeString.length() - 1);
-        fqName = extractFQName(returnTypeString);
-        if(entitySet == null && entityTypesMap.get(fqName) != null){
-          throw new EntityProviderException(EntityProviderException.MISSING_ATTRIBUTE.addContent
-              ("EntitySet = "+entitySet, XmlMetadataConstants.EDM_FUNCTION_IMPORT +" = "+ function.getName()));
-        }
         returnType.setMultiplicity(EdmMultiplicity.MANY);
       } else {
-        fqName = extractFQName(returnTypeString);
-        if(entitySet != null && entityTypesMap.get(fqName) == null) {
-          throw new EntityProviderException(EntityProviderException.INVALID_ATTRIBUTE.addContent
-              ("EntitySet = "+entitySet, XmlMetadataConstants.EDM_FUNCTION_IMPORT 
-                  + " = "+ function.getName()));
-        }
         returnType.setMultiplicity(EdmMultiplicity.ONE);
       }
+      fqName = extractFQName(returnTypeString);
       returnType.setTypeName(fqName);
       ((EdmNamedImpl) returnType).setName(fqName.getName());
       ((EdmNamedImpl) returnType).setEdm(edm);
@@ -1557,6 +1548,27 @@ public class XmlMetadataDeserializer {
     }
   }
 
+  private void validateFunctionImport() throws EntityProviderException, EdmException {
+    for (EdmFunctionImport functionImport : edmFunctionImportList) {
+      EdmTyped returnType = functionImport.getReturnType();
+      if (returnType != null) {
+        FullQualifiedName fqn = extractFQName(returnType.toString());
+        String entitySet = ((EdmFunctionImportImpl)functionImport).getEntitySetName();
+        if (returnType.getMultiplicity() == EdmMultiplicity.MANY && entitySet == null && entityTypesMap.get(
+            fqn) != null) {
+          throw new EntityProviderException(EntityProviderException.MISSING_ATTRIBUTE.addContent("EntitySet = "
+              + entitySet, XmlMetadataConstants.EDM_FUNCTION_IMPORT + " = " + functionImport.getName()));
+        } else if (returnType.getMultiplicity() != EdmMultiplicity.MANY && entitySet != null && entityTypesMap.get(
+            fqn) == null) {
+          throw new EntityProviderException(EntityProviderException.INVALID_ATTRIBUTE.addContent("EntitySet = "
+              + entitySet, XmlMetadataConstants.EDM_FUNCTION_IMPORT
+                  + " = " + functionImport.getName()));
+        }
+      }
+    }
+  }
+
+  
   private void validate() throws EntityProviderException, EdmException {
     checkMandatoryNamespacesAvailable();
     validateEntityTypes();
@@ -1564,6 +1576,7 @@ public class XmlMetadataDeserializer {
     validateRelationship();
     validateEntitySet();
     validateAssociation();
+    validateFunctionImport();
   }
 
   private void initialize() {
index 50788e2..10d3db4 100644 (file)
@@ -374,6 +374,14 @@ public class XMLMetadataFunctionImportDeserializerTest {
             + "\" xmlns=\""
             + Edm.NAMESPACE_EDM_2008_09
             + "\">"
+           + "<EntityContainer Name=\"Container1\" m:IsDefaultEntityContainer=\"true\">"
+            + "<EntitySet Name=\"Employees\" EntityType=\"RefScenario.Employee\"/>"
+            + "<FunctionImport Name=\"EmployeeSearch\" ReturnType=\"RefScenario.Employee\" " +
+            "EntitySet=\"Employees\" m:HttpMethod=\"GET\">"
+            + "<Parameter Name=\"q1\" Type=\"Edm.String\" Nullable=\"true\" />"
+            + "<Parameter Name=\"q2\" Type=\"Edm.Int32\" Nullable=\"false\" />"
+            + "</FunctionImport>"
+            + "</EntityContainer>" 
             + "<EntityType Name= \"Employee\" m:HasStream=\"true\">"
             + "<Key><PropertyRef Name=\"EmployeeId\"/></Key>"
             + "<Property Name=\""
@@ -383,14 +391,58 @@ public class XMLMetadataFunctionImportDeserializerTest {
             + propertyNames[1]
             + "\" Type=\"Edm.String\" m:FC_TargetPath=\"SyndicationTitle\"/>"
             + "</EntityType>"
-            + "<EntityContainer Name=\"Container1\" m:IsDefaultEntityContainer=\"true\">"
+            + "</Schema>" + "</edmx:DataServices>" + "</edmx:Edmx>";
+    XmlMetadataDeserializer parser = new XmlMetadataDeserializer();
+    InputStream reader = createStreamReader(xmWithEntityContainer);
+    EdmDataServices result = parser.readMetadata(reader, true);
+    for (EdmSchema schema : result.getEdm().getSchemas()) {
+      for (EdmEntityContainer container : schema.getEntityContainers()) {
+        assertEquals("Container1", container.getName());
+        assertEquals(Boolean.TRUE, container.isDefaultEntityContainer());
+
+        EdmFunctionImport functionImport1 = container.getFunctionImport("EmployeeSearch");
+
+        assertEquals("EmployeeSearch", functionImport1.getName());
+        assertEquals("Employees", functionImport1.getEntitySet().getName());
+        assertEquals(EdmMultiplicity.ONE, functionImport1.getReturnType().getMultiplicity());
+        assertEquals("GET", functionImport1.getHttpMethod());
+      }
+    }
+  }
+  
+//Function Import with return type as entity type and entityset attribute set
+  @Test
+  public void testFunctionImportEntityOrderChange() throws Exception {
+    final String xmWithEntityContainer =
+        "<edmx:Edmx Version=\"1.0\" xmlns:edmx=\""
+            + Edm.NAMESPACE_EDMX_2007_06
+            + "\">"
+            + "<edmx:DataServices m:DataServiceVersion=\"2.0\" xmlns:m=\""
+            + Edm.NAMESPACE_M_2007_08
+            + "\">"
+            + "<Schema Namespace=\""
+            + NAMESPACE
+            + "\" xmlns=\""
+            + Edm.NAMESPACE_EDM_2008_09
+            + "\">"
+            + "<EntityType Name= \"Employee\" m:HasStream=\"true\">"
+           + "<Key><PropertyRef Name=\"EmployeeId\"/></Key>"
+           + "<Property Name=\""
+           + propertyNames[0]
+           + "\" Type=\"Edm.String\" Nullable=\"false\"/>"
+           + "<Property Name=\""
+           + propertyNames[1]
+           + "\" Type=\"Edm.String\" m:FC_TargetPath=\"SyndicationTitle\"/>"
+           + "</EntityType>"
+           + "<EntityContainer Name=\"Container1\" m:IsDefaultEntityContainer=\"true\">"
             + "<EntitySet Name=\"Employees\" EntityType=\"RefScenario.Employee\"/>"
             + "<FunctionImport Name=\"EmployeeSearch\" ReturnType=\"RefScenario.Employee\" " +
             "EntitySet=\"Employees\" m:HttpMethod=\"GET\">"
             + "<Parameter Name=\"q1\" Type=\"Edm.String\" Nullable=\"true\" />"
             + "<Parameter Name=\"q2\" Type=\"Edm.Int32\" Nullable=\"false\" />"
             + "</FunctionImport>"
-            + "</EntityContainer>" + "</Schema>" + "</edmx:DataServices>" + "</edmx:Edmx>";
+            + "</EntityContainer>" 
+            + "</Schema>" + "</edmx:DataServices>" + "</edmx:Edmx>";
     XmlMetadataDeserializer parser = new XmlMetadataDeserializer();
     InputStream reader = createStreamReader(xmWithEntityContainer);
     EdmDataServices result = parser.readMetadata(reader, true);
@@ -409,6 +461,7 @@ public class XMLMetadataFunctionImportDeserializerTest {
     }
   }
   
+  
 //Function Import with return type as entity type and entityset attribute not set
   @Test
   public void testFunctionImportEntityWithoutEntitySet() throws Exception {
index 92f57c7..e6dea17 100644 (file)
@@ -78,6 +78,7 @@ public class XmlMetadataConsumer {
   private Map<FullQualifiedName, Association> associationsMap = new HashMap<FullQualifiedName, Association>();
   private Map<FullQualifiedName, EntityContainer> containerMap = new HashMap<FullQualifiedName, EntityContainer>();
   private List<NavigationProperty> navProperties = new ArrayList<NavigationProperty>();
+  private List<FunctionImport> edmFunctionImportList = new ArrayList<FunctionImport>();
   private String currentHandledStartTagName;
   private String currentNamespace;
   private String edmNamespace = Edm.NAMESPACE_EDM_2008_09;
@@ -246,7 +247,7 @@ public class XmlMetadataConsumer {
       container.setAnnotationElements(annotationElements);
     }
     container.setEntitySets(entitySets).setAssociationSets(associationSets).setFunctionImports(functionImports);
-
+    edmFunctionImportList.addAll(functionImports);
     containerMap.put(new FullQualifiedName(currentNamespace, container.getName()), container);
     return container;
   }
@@ -268,19 +269,8 @@ public class XmlMetadataConsumer {
       ReturnType returnType = new ReturnType();
       if (returnTypeString.startsWith("Collection") || returnTypeString.startsWith("collection")) {
         returnTypeString = returnTypeString.substring(returnTypeString.indexOf("(") + 1, returnTypeString.length() - 1);
-        fqName = extractFQName(returnTypeString);
-        if(function.getEntitySet() == null && entityTypesMap.get(fqName) != null){
-          throw new EntityProviderException(EntityProviderException.MISSING_ATTRIBUTE.addContent
-              ("EntitySet = "+function.getEntitySet(), XmlMetadataConstants.EDM_FUNCTION_IMPORT + function.getName()));
-        }
         returnType.setMultiplicity(EdmMultiplicity.MANY);
       } else {
-        fqName = extractFQName(returnTypeString);
-        if(function.getEntitySet() != null && entityTypesMap.get(fqName) == null) {
-          throw new EntityProviderException(EntityProviderException.INVALID_ATTRIBUTE.addContent
-              ("EntitySet = "+function.getEntitySet(), XmlMetadataConstants.EDM_FUNCTION_IMPORT 
-                  + " : "+ function.getName()));
-        }
         returnType.setMultiplicity(EdmMultiplicity.ONE);
       }
       fqName = extractFQName(returnTypeString);
@@ -1088,6 +1078,26 @@ public class XmlMetadataConsumer {
     }
 
   }
+  
+  private void validateFunctionImport() throws EntityProviderException {
+    for (FunctionImport functionImport : edmFunctionImportList) {
+      ReturnType returnType = functionImport.getReturnType();
+      if (returnType != null) {
+        String entitySet = functionImport.getEntitySet();
+        FullQualifiedName fqn = returnType.getTypeName();
+        if (returnType.getMultiplicity() == EdmMultiplicity.MANY && entitySet == null && entityTypesMap.get(
+            fqn) != null) {
+          throw new EntityProviderException(EntityProviderException.MISSING_ATTRIBUTE.addContent("EntitySet = "
+              + entitySet, XmlMetadataConstants.EDM_FUNCTION_IMPORT + " = " + functionImport.getName()));
+        } else if (returnType.getMultiplicity() != EdmMultiplicity.MANY && entitySet != null && entityTypesMap.get(
+            fqn) == null) {
+          throw new EntityProviderException(EntityProviderException.INVALID_ATTRIBUTE.addContent("EntitySet = "
+              + entitySet, XmlMetadataConstants.EDM_FUNCTION_IMPORT
+                  + " = " + functionImport.getName()));
+        }
+      }
+    }
+  }
 
   private void validateAssociation() throws EntityProviderException {
     for (Map.Entry<FullQualifiedName, EntityContainer> container : containerMap.entrySet()) {
@@ -1145,6 +1155,7 @@ public class XmlMetadataConsumer {
     validateRelationship();
     validateEntitySet();
     validateAssociation();
+    validateFunctionImport();
   }
 
   private void initialize() {
index 54f7d4b..6b2ad73 100644 (file)
@@ -1004,6 +1004,65 @@ public class XmlMetadataConsumerTest extends AbstractXmlConsumerTest {
     }
   }
   
+  @Test
+  public void testFunctionImportEntityOrderChange() throws XMLStreamException, EntityProviderException {
+    final String xmWithEntityContainer =
+        "<edmx:Edmx Version=\"1.0\" xmlns:edmx=\""
+            + Edm.NAMESPACE_EDMX_2007_06
+            + "\">"
+            + "<edmx:DataServices m:DataServiceVersion=\"2.0\" xmlns:m=\""
+            + Edm.NAMESPACE_M_2007_08
+            + "\">"
+            + "<Schema Namespace=\""
+            + NAMESPACE
+            + "\" xmlns=\""
+            + Edm.NAMESPACE_EDM_2008_09
+            + "\">"
+            + "<EntityContainer Name=\"Container1\" m:IsDefaultEntityContainer=\"true\">"
+            + "<EntitySet Name=\"Employees\" EntityType=\"RefScenario.Employee\"/>"
+            + "<FunctionImport Name=\"EmployeeSearch\" ReturnType=\"RefScenario.Employee\" " +
+            "EntitySet=\"Employees\" m:HttpMethod=\"GET\">"
+            + "<Parameter Name=\"q1\" Type=\"Edm.String\" Nullable=\"true\" />"
+            + "<Parameter Name=\"q2\" Type=\"Edm.Int32\" Nullable=\"false\" />"
+            + "</FunctionImport>"
+            + "</EntityContainer>" 
+            + "<EntityType Name= \"Employee\" m:HasStream=\"true\">"
+            + "<Key><PropertyRef Name=\"EmployeeId\"/></Key>"
+            + "<Property Name=\""
+            + propertyNames[0]
+            + "\" Type=\"Edm.String\" Nullable=\"false\"/>"
+            + "<Property Name=\""
+            + propertyNames[1]
+            + "\" Type=\"Edm.String\" m:FC_TargetPath=\"SyndicationTitle\"/>"
+            + "</EntityType>"
+            + "</Schema>" + "</edmx:DataServices>" + "</edmx:Edmx>";
+    XmlMetadataConsumer parser = new XmlMetadataConsumer();
+    XMLStreamReader reader = createStreamReader(xmWithEntityContainer);
+    DataServices result = parser.readMetadata(reader, true);
+    for (Schema schema : result.getSchemas()) {
+      for (EntityContainer container : schema.getEntityContainers()) {
+        assertEquals("Container1", container.getName());
+        assertEquals(Boolean.TRUE, container.isDefaultEntityContainer());
+
+        FunctionImport functionImport1 = container.getFunctionImports().get(0);
+
+        assertEquals("EmployeeSearch", functionImport1.getName());
+        assertEquals("Employees", functionImport1.getEntitySet());
+        assertEquals(NAMESPACE, functionImport1.getReturnType().getTypeName().getNamespace());
+        assertEquals("Employee", functionImport1.getReturnType().getTypeName().getName());
+        assertEquals(EdmMultiplicity.ONE, functionImport1.getReturnType().getMultiplicity());
+        assertEquals("GET", functionImport1.getHttpMethod());
+        assertEquals(2, functionImport1.getParameters().size());
+        assertEquals("q1", functionImport1.getParameters().get(0).getName());
+        assertEquals(EdmSimpleTypeKind.String, functionImport1.getParameters().get(0).getType());
+        assertEquals(Boolean.TRUE, functionImport1.getParameters().get(0).getFacets().isNullable());
+        assertEquals("q2", functionImport1.getParameters().get(1).getName());
+        assertEquals(EdmSimpleTypeKind.Int32, functionImport1.getParameters().get(1).getType());
+        assertEquals(Boolean.FALSE, functionImport1.getParameters().get(1).getFacets().isNullable());
+      }
+    }
+  }
+  
 //Function Import with return type as entity type and entityset attribute not set
   @Test
   public void testFunctionImportEntityWithoutEntitySet() throws XMLStreamException, EntityProviderException {