@Override
  public BaseResponse callFunction(
      ODataContext context,
      EdmFunctionImport name,
      Map<String, OFunctionParameter> params,
      QueryInfo queryInfo) {
    BaseResponse response;

    ServiceOperationsProducerMock.LOGGER.debug("EdmFunctionImport Object:    " + name.getName());
    ServiceOperationsProducerMock.LOGGER.debug("EdmFunctionImport Parameter: " + params);
    ServiceOperationsProducerMock.LOGGER.debug("EdmFunctionImport QueryInfo: " + queryInfo);

    this.queryParameter = params;
    this.queryInfo = queryInfo;

    if (ServiceOperationsMetadataUtil.TEST_FUNCTION_RETURN_STRING.equals(name.getName())) {
      response =
          Responses.simple(
              EdmSimpleType.STRING, name.getName(), ServiceOperationsProducerMock.SOME_TEXT);
    } else if (ServiceOperationsMetadataUtil.TEST_FUNCTION_RETURN_STRING_PUT.equals(
        name.getName())) {
      response =
          Responses.simple(
              EdmSimpleType.STRING, name.getName(), ServiceOperationsProducerMock.SOME_TEXT);
    } else if (ServiceOperationsMetadataUtil.TEST_FUNCTION_RETURN_STRING_GET.equals(
        name.getName())) {
      response =
          Responses.simple(
              EdmSimpleType.STRING, name.getName(), ServiceOperationsProducerMock.SOME_TEXT);
    } else if (ServiceOperationsMetadataUtil.TEST_FUNCTION_RETURN_STRING_DELETE.equals(
        name.getName())) {
      response =
          Responses.simple(
              EdmSimpleType.STRING, name.getName(), ServiceOperationsProducerMock.SOME_TEXT);
    } else if (ServiceOperationsMetadataUtil.TEST_FUNCTION_RETURN_STRING_PATCH.equals(
        name.getName())) {
      response =
          Responses.simple(
              EdmSimpleType.STRING, name.getName(), ServiceOperationsProducerMock.SOME_TEXT);
    } else if (ServiceOperationsMetadataUtil.TEST_FUNCTION_RETURN_STRING_MERGE.equals(
        name.getName())) {
      response =
          Responses.simple(
              EdmSimpleType.STRING, name.getName(), ServiceOperationsProducerMock.SOME_TEXT);
    } else if (ServiceOperationsMetadataUtil.TEST_FUNCTION_RETURN_STRING_POST.equals(
        name.getName())) {
      response =
          Responses.simple(
              EdmSimpleType.STRING, name.getName(), ServiceOperationsProducerMock.SOME_TEXT);
    } else if (ServiceOperationsMetadataUtil.TEST_FUNCTION_RETURN_BOOLEAN.equals(name.getName())) {
      response =
          Responses.simple(
              EdmSimpleType.BOOLEAN, name.getName(), ServiceOperationsProducerMock.BOOLEAN_VALUE);
    } else if (ServiceOperationsMetadataUtil.TEST_FUNCTION_RETURN_INT16.equals(name.getName())) {
      response =
          Responses.simple(
              EdmSimpleType.INT16, name.getName(), ServiceOperationsProducerMock.INT16_VALUE);
    } else if (ServiceOperationsMetadataUtil.TEST_FUNCTION_RETURN_ENTITY.equals(name.getName())) {
      OEntity entity = this.createEmployeeEntity();
      response = Responses.entity(entity);
    } else if (ServiceOperationsMetadataUtil.TEST_FUNCTION_RETURN_COMPLEX_TYPE.equals(
        name.getName())) {
      OComplexObject complexObject = this.createComplexTypeLocation();
      response =
          Responses.complexObject(
              complexObject, ServiceOperationsMetadataUtil.TEST_FUNCTION_RETURN_COMPLEX_TYPE);
    } else if (ServiceOperationsMetadataUtil.TEST_FUNCTION_RETURN_COLLECTION_STRING.equals(
        name.getName())) {
      Builder<OObject> collectionBuilder = OCollections.newBuilder(EdmSimpleType.STRING);
      collectionBuilder
          .add(
              OSimpleObjects.create(
                  EdmSimpleType.STRING, ServiceOperationsProducerMock.COLLECTION_STRING1))
          .build();
      collectionBuilder
          .add(
              OSimpleObjects.create(
                  EdmSimpleType.STRING, ServiceOperationsProducerMock.COLLECTION_STRING2))
          .build();
      OCollection<OObject> collection = collectionBuilder.build();
      response =
          Responses.collection(
              collection,
              null,
              null,
              null,
              ServiceOperationsMetadataUtil.TEST_FUNCTION_RETURN_COLLECTION_STRING);
    } else if (ServiceOperationsMetadataUtil.TEST_FUNCTION_RETURN_COLLECTION_DOUBLE.equals(
        name.getName())) {
      Builder<OObject> collectionBuilder = OCollections.newBuilder(EdmSimpleType.DOUBLE);
      collectionBuilder
          .add(
              OSimpleObjects.create(
                  EdmSimpleType.DOUBLE, ServiceOperationsProducerMock.COLLECTION_DOUBLE1))
          .build();
      collectionBuilder
          .add(
              OSimpleObjects.create(
                  EdmSimpleType.DOUBLE, ServiceOperationsProducerMock.COLLECTION_DOUBLE2))
          .build();
      OCollection<OObject> collection = collectionBuilder.build();
      response =
          Responses.collection(
              collection,
              null,
              null,
              null,
              ServiceOperationsMetadataUtil.TEST_FUNCTION_RETURN_COLLECTION_DOUBLE);
    } else if (ServiceOperationsMetadataUtil.TEST_FUNCTION_RETURN_COLLECTION_COMPLEX_TYPE.equals(
        name.getName())) {
      OComplexObject complexObject1 = this.createComplexTypeLocation();
      OComplexObject complexObject2 = this.createComplexTypeLocation();

      EdmComplexType type =
          this.getMetadata()
              .findEdmComplexType(ServiceOperationsProducerMock.COMPLEY_TYPE_NAME_LOCATION);
      Builder<OObject> collectionBuilder = OCollections.newBuilder(type);

      collectionBuilder.add(complexObject1);
      collectionBuilder.add(complexObject2);

      OCollection<OObject> collection = collectionBuilder.build();
      response =
          Responses.collection(
              collection,
              null,
              null,
              null,
              ServiceOperationsMetadataUtil.TEST_FUNCTION_RETURN_COLLECTION_COMPLEX_TYPE);
    } else if (ServiceOperationsMetadataUtil.TEST_FUNCTION_RETURN_COLLECTION_ENTITY.equals(
        name.getName())) {
      OEntity entity = this.createEmployeeEntity();

      Builder<OObject> collectionBuilder = OCollections.newBuilder(entity.getType());
      collectionBuilder.add(entity);
      OCollection<OObject> collection = collectionBuilder.build();

      response =
          Responses.collection(
              collection,
              entity.getEntitySet(),
              null,
              null,
              ServiceOperationsMetadataUtil.TEST_FUNCTION_RETURN_COLLECTION_ENTITY);
    } else if (ServiceOperationsMetadataUtil.TEST_FUNCTION_RETURN_ENTITYSET.equals(
        name.getName())) {
      List<OEntity> entities = new ArrayList<OEntity>();
      entities.add(createEmployeeEntity());
      response = Responses.entities(entities, name.getEntitySet(), null, null);
    } else {
      throw new RuntimeException("Unsupported Test Case for FunctionImport: " + name.getName());
    }

    return response;
  }
  public static void write(EdmDataServices services, Writer w) {

    XMLWriter2 writer = XMLFactoryProvider2.getInstance().newXMLWriterFactory2().createXMLWriter(w);
    writer.startDocument();

    writer.startElement(new QName2(edmx, "Edmx", "edmx"));
    writer.writeAttribute("Version", "1.0");
    writer.writeNamespace("edmx", edmx);
    writer.writeNamespace("d", d);
    writer.writeNamespace("m", m);
    writeExtensionNamespaces(services, writer);

    writer.startElement(new QName2(edmx, "DataServices", "edmx"));
    writer.writeAttribute(new QName2(m, "DataServiceVersion", "m"), "1.0");

    // Schema
    for (EdmSchema schema : services.getSchemas()) {

      writer.startElement(new QName2("Schema"), edm);
      writer.writeAttribute("Namespace", schema.getNamespace());
      writeAnnotationAttributes(schema, writer);
      writeDocumentation(schema, writer);

      // ComplexType
      for (EdmComplexType ect : schema.getComplexTypes()) {
        writer.startElement(new QName2("ComplexType"));

        writer.writeAttribute("Name", ect.getName());
        if (null != ect.getIsAbstract()) {
          writer.writeAttribute("Abstract", ect.getIsAbstract().toString());
        }
        writeAnnotationAttributes(ect, writer);
        writeDocumentation(ect, writer);

        writeProperties(ect.getProperties(), writer);
        writeAnnotationElements(ect, writer);
        writer.endElement("ComplexType");
      }
      // EntityType
      for (EdmEntityType eet : schema.getEntityTypes()) {
        writer.startElement(new QName2("EntityType"));

        writer.writeAttribute("Name", eet.getName());
        if (null != eet.getIsAbstract()) {
          writer.writeAttribute("Abstract", eet.getIsAbstract().toString());
        }

        if (Boolean.TRUE.equals(eet.getHasStream())) {
          writer.writeAttribute(new QName2(m, "HasStream", "m"), "true");
        }

        // keys only on base types
        if (eet.isRootType()) {
          writeAnnotationAttributes(eet, writer);
          writeDocumentation(eet, writer);
          writer.startElement(new QName2("Key"));
          for (String key : eet.getKeys()) {
            writer.startElement(new QName2("PropertyRef"));
            writer.writeAttribute("Name", key);
            writer.endElement("PropertyRef");
          }

          writer.endElement("Key");
        } else {
          writer.writeAttribute("BaseType", eet.getBaseType().getFullyQualifiedTypeName());
          writeAnnotationAttributes(eet, writer);
          writeDocumentation(eet, writer);
        }

        writeProperties(eet.getDeclaredProperties(), writer);

        for (EdmNavigationProperty np : eet.getDeclaredNavigationProperties()) {

          writer.startElement(new QName2("NavigationProperty"));
          writer.writeAttribute("Name", np.getName());
          writer.writeAttribute("Relationship", np.getRelationship().getFQNamespaceName());
          writer.writeAttribute("FromRole", np.getFromRole().getRole());
          writer.writeAttribute("ToRole", np.getToRole().getRole());
          writeAnnotationAttributes(np, writer);
          writeDocumentation(np, writer);
          writeAnnotationElements(np, writer);
          writer.endElement("NavigationProperty");
        }

        writeAnnotationElements(eet, writer);
        writer.endElement("EntityType");
      }

      // Association
      for (EdmAssociation assoc : schema.getAssociations()) {
        writer.startElement(new QName2("Association"));

        writer.writeAttribute("Name", assoc.getName());
        writeAnnotationAttributes(assoc, writer);
        writeDocumentation(assoc, writer);

        writer.startElement(new QName2("End"));
        writer.writeAttribute("Role", assoc.getEnd1().getRole());
        writer.writeAttribute("Type", assoc.getEnd1().getType().getFullyQualifiedTypeName());
        writer.writeAttribute("Multiplicity", assoc.getEnd1().getMultiplicity().getSymbolString());
        writer.endElement("End");

        writer.startElement(new QName2("End"));
        writer.writeAttribute("Role", assoc.getEnd2().getRole());
        writer.writeAttribute("Type", assoc.getEnd2().getType().getFullyQualifiedTypeName());
        writer.writeAttribute("Multiplicity", assoc.getEnd2().getMultiplicity().getSymbolString());
        writer.endElement("End");

        writeAnnotationElements(assoc, writer);
        writer.endElement("Association");
      }

      // EntityContainer
      for (EdmEntityContainer container : schema.getEntityContainers()) {
        writer.startElement(new QName2("EntityContainer"));

        writer.writeAttribute("Name", container.getName());
        writer.writeAttribute(
            new QName2(m, "IsDefaultEntityContainer", "m"),
            Boolean.toString(container.isDefault()));
        writeAnnotationAttributes(container, writer);
        writeDocumentation(container, writer);

        for (EdmEntitySet ees : container.getEntitySets()) {
          writer.startElement(new QName2("EntitySet"));
          writer.writeAttribute("Name", ees.getName());
          writer.writeAttribute("EntityType", ees.getType().getFullyQualifiedTypeName());
          writeAnnotationAttributes(ees, writer);
          writeDocumentation(ees, writer);
          writeAnnotationElements(ees, writer);
          writer.endElement("EntitySet");
        }

        for (EdmFunctionImport fi : container.getFunctionImports()) {
          writer.startElement(new QName2("FunctionImport"));
          writer.writeAttribute("Name", fi.getName());
          if (null != fi.getEntitySet()) {
            writer.writeAttribute("EntitySet", fi.getEntitySet().getName());
          }
          if (fi.getReturnType() != null) {
            // TODO: how to differentiate inline ReturnType vs embedded ReturnType?
            writer.writeAttribute("ReturnType", fi.getReturnType().getFullyQualifiedTypeName());
          }
          writer.writeAttribute(new QName2(m, "HttpMethod", "m"), fi.getHttpMethod());
          writeAnnotationAttributes(fi, writer);
          writeDocumentation(fi, writer);

          for (EdmFunctionParameter param : fi.getParameters()) {
            writer.startElement(new QName2("Parameter"));
            writer.writeAttribute("Name", param.getName());
            writer.writeAttribute("Type", param.getType().getFullyQualifiedTypeName());
            if (param.getMode() != null) writer.writeAttribute("Mode", param.getMode().toString());
            writeAnnotationAttributes(param, writer);
            writeDocumentation(param, writer);
            writeAnnotationElements(param, writer);
            writer.endElement("Parameter");
          }
          writeAnnotationElements(fi, writer);
          writer.endElement("FunctionImport");
        }

        for (EdmAssociationSet eas : container.getAssociationSets()) {
          writer.startElement(new QName2("AssociationSet"));
          writer.writeAttribute("Name", eas.getName());
          writer.writeAttribute("Association", eas.getAssociation().getFQNamespaceName());
          writeAnnotationAttributes(eas, writer);
          writeDocumentation(eas, writer);

          writer.startElement(new QName2("End"));
          writer.writeAttribute("Role", eas.getEnd1().getRole().getRole());
          writer.writeAttribute("EntitySet", eas.getEnd1().getEntitySet().getName());
          writer.endElement("End");

          writer.startElement(new QName2("End"));
          writer.writeAttribute("Role", eas.getEnd2().getRole().getRole());
          writer.writeAttribute("EntitySet", eas.getEnd2().getEntitySet().getName());
          writer.endElement("End");

          writeAnnotationElements(eas, writer);
          writer.endElement("AssociationSet");
        }

        writeAnnotationElements(container, writer);
        writer.endElement("EntityContainer");
      }

      writeAnnotationElements(schema, writer);
      writer.endElement("Schema");
    }

    writer.endDocument();
  }