You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@olingo.apache.org by fm...@apache.org on 2013/07/26 13:22:19 UTC
[14/51] [partial] initial commit
http://git-wip-us.apache.org/repos/asf/incubator-olingo-odata2/blob/ff2b0a0e/odata-core/src/main/java/org/apache/olingo/odata2/core/ep/producer/XmlCollectionEntityProducer.java
----------------------------------------------------------------------
diff --git a/odata-core/src/main/java/org/apache/olingo/odata2/core/ep/producer/XmlCollectionEntityProducer.java b/odata-core/src/main/java/org/apache/olingo/odata2/core/ep/producer/XmlCollectionEntityProducer.java
new file mode 100644
index 0000000..93beaa1
--- /dev/null
+++ b/odata-core/src/main/java/org/apache/olingo/odata2/core/ep/producer/XmlCollectionEntityProducer.java
@@ -0,0 +1,54 @@
+/*******************************************************************************
+ * 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.odata2.core.ep.producer;
+
+import java.util.List;
+
+import javax.xml.stream.XMLStreamException;
+import javax.xml.stream.XMLStreamWriter;
+
+import org.apache.olingo.odata2.api.edm.Edm;
+import org.apache.olingo.odata2.api.ep.EntityProviderException;
+import org.apache.olingo.odata2.core.ep.aggregator.EntityPropertyInfo;
+import org.apache.olingo.odata2.core.ep.util.FormatXml;
+
+/**
+ * Provider for writing a collection of simple-type or complex-type instances
+ * @author SAP AG
+ */
+public class XmlCollectionEntityProducer {
+
+ public static void append(final XMLStreamWriter writer, final EntityPropertyInfo propertyInfo, final List<?> data) throws EntityProviderException {
+ try {
+ writer.writeStartElement(propertyInfo.getName());
+ writer.writeDefaultNamespace(Edm.NAMESPACE_D_2007_08);
+ if (propertyInfo.isComplex()) {
+ writer.writeNamespace(Edm.PREFIX_M, Edm.NAMESPACE_M_2007_08);
+ }
+ XmlPropertyEntityProducer provider = new XmlPropertyEntityProducer();
+ for (final Object propertyData : data) {
+ provider.append(writer, FormatXml.D_ELEMENT, propertyInfo, propertyData);
+ }
+ writer.writeEndElement();
+ writer.flush();
+ } catch (XMLStreamException e) {
+ throw new EntityProviderException(EntityProviderException.COMMON, e);
+ }
+ }
+}
http://git-wip-us.apache.org/repos/asf/incubator-olingo-odata2/blob/ff2b0a0e/odata-core/src/main/java/org/apache/olingo/odata2/core/ep/producer/XmlErrorDocumentProducer.java
----------------------------------------------------------------------
diff --git a/odata-core/src/main/java/org/apache/olingo/odata2/core/ep/producer/XmlErrorDocumentProducer.java b/odata-core/src/main/java/org/apache/olingo/odata2/core/ep/producer/XmlErrorDocumentProducer.java
new file mode 100644
index 0000000..a94f395
--- /dev/null
+++ b/odata-core/src/main/java/org/apache/olingo/odata2/core/ep/producer/XmlErrorDocumentProducer.java
@@ -0,0 +1,71 @@
+/*******************************************************************************
+ * 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.odata2.core.ep.producer;
+
+import java.util.Locale;
+
+import javax.xml.stream.XMLStreamException;
+import javax.xml.stream.XMLStreamWriter;
+
+import org.apache.olingo.odata2.api.edm.Edm;
+import org.apache.olingo.odata2.core.ep.util.FormatXml;
+
+public class XmlErrorDocumentProducer {
+
+ public void writeErrorDocument(final XMLStreamWriter writer, final String errorCode, final String message, final Locale locale, final String innerError) throws XMLStreamException {
+ writer.writeStartDocument();
+ writer.writeStartElement(FormatXml.M_ERROR);
+ writer.writeDefaultNamespace(Edm.NAMESPACE_M_2007_08);
+ writer.writeStartElement(FormatXml.M_CODE);
+ if (errorCode != null) {
+ writer.writeCharacters(errorCode);
+ }
+ writer.writeEndElement();
+ writer.writeStartElement(FormatXml.M_MESSAGE);
+ if (locale != null) {
+ writer.writeAttribute(Edm.PREFIX_XML, Edm.NAMESPACE_XML_1998, FormatXml.XML_LANG, getLocale(locale));
+ } else {
+ writer.writeAttribute(Edm.PREFIX_XML, Edm.NAMESPACE_XML_1998, FormatXml.XML_LANG, "");
+ }
+ if (message != null) {
+ writer.writeCharacters(message);
+ }
+ writer.writeEndElement();
+
+ if (innerError != null) {
+ writer.writeStartElement(FormatXml.M_INNER_ERROR);
+ writer.writeCharacters(innerError);
+ writer.writeEndElement();
+ }
+
+ writer.writeEndDocument();
+ }
+
+ /**
+ * Gets language and country as defined in RFC 4646 based on {@link Locale}.
+ */
+ private String getLocale(final Locale locale) {
+ if (locale.getCountry().isEmpty()) {
+ return locale.getLanguage();
+ } else {
+ return locale.getLanguage() + "-" + locale.getCountry();
+ }
+ }
+
+}
http://git-wip-us.apache.org/repos/asf/incubator-olingo-odata2/blob/ff2b0a0e/odata-core/src/main/java/org/apache/olingo/odata2/core/ep/producer/XmlLinkEntityProducer.java
----------------------------------------------------------------------
diff --git a/odata-core/src/main/java/org/apache/olingo/odata2/core/ep/producer/XmlLinkEntityProducer.java b/odata-core/src/main/java/org/apache/olingo/odata2/core/ep/producer/XmlLinkEntityProducer.java
new file mode 100644
index 0000000..b3d4b4d
--- /dev/null
+++ b/odata-core/src/main/java/org/apache/olingo/odata2/core/ep/producer/XmlLinkEntityProducer.java
@@ -0,0 +1,60 @@
+/*******************************************************************************
+ * 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.odata2.core.ep.producer;
+
+import java.util.Map;
+
+import javax.xml.stream.XMLStreamException;
+import javax.xml.stream.XMLStreamWriter;
+
+import org.apache.olingo.odata2.api.edm.Edm;
+import org.apache.olingo.odata2.api.ep.EntityProviderException;
+import org.apache.olingo.odata2.api.ep.EntityProviderWriteProperties;
+import org.apache.olingo.odata2.core.ep.aggregator.EntityInfoAggregator;
+import org.apache.olingo.odata2.core.ep.util.FormatXml;
+
+/**
+ * Provider for writing a single link.
+ * @author SAP AG
+ */
+public class XmlLinkEntityProducer {
+
+ private final EntityProviderWriteProperties properties;
+
+ public XmlLinkEntityProducer(final EntityProviderWriteProperties properties) throws EntityProviderException {
+ this.properties = properties == null ? EntityProviderWriteProperties.serviceRoot(null).build() : properties;
+ }
+
+ public void append(final XMLStreamWriter writer, final EntityInfoAggregator entityInfo, final Map<String, Object> data, final boolean isRootElement) throws EntityProviderException {
+ try {
+ writer.writeStartElement(FormatXml.D_URI);
+ if (isRootElement) {
+ writer.writeDefaultNamespace(Edm.NAMESPACE_D_2007_08);
+ }
+ if (properties.getServiceRoot() != null) {
+ writer.writeCharacters(properties.getServiceRoot().toASCIIString());
+ }
+ writer.writeCharacters(AtomEntryEntityProducer.createSelfLink(entityInfo, data, null));
+ writer.writeEndElement();
+ writer.flush();
+ } catch (final XMLStreamException e) {
+ throw new EntityProviderException(EntityProviderException.COMMON, e);
+ }
+ }
+}
http://git-wip-us.apache.org/repos/asf/incubator-olingo-odata2/blob/ff2b0a0e/odata-core/src/main/java/org/apache/olingo/odata2/core/ep/producer/XmlLinksEntityProducer.java
----------------------------------------------------------------------
diff --git a/odata-core/src/main/java/org/apache/olingo/odata2/core/ep/producer/XmlLinksEntityProducer.java b/odata-core/src/main/java/org/apache/olingo/odata2/core/ep/producer/XmlLinksEntityProducer.java
new file mode 100644
index 0000000..f361718
--- /dev/null
+++ b/odata-core/src/main/java/org/apache/olingo/odata2/core/ep/producer/XmlLinksEntityProducer.java
@@ -0,0 +1,65 @@
+/*******************************************************************************
+ * 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.odata2.core.ep.producer;
+
+import java.util.List;
+import java.util.Map;
+
+import javax.xml.stream.XMLStreamException;
+import javax.xml.stream.XMLStreamWriter;
+
+import org.apache.olingo.odata2.api.edm.Edm;
+import org.apache.olingo.odata2.api.ep.EntityProviderException;
+import org.apache.olingo.odata2.api.ep.EntityProviderWriteProperties;
+import org.apache.olingo.odata2.core.ep.aggregator.EntityInfoAggregator;
+import org.apache.olingo.odata2.core.ep.util.FormatXml;
+
+/**
+ * Provider for writing a collection of links
+ * @author SAP AG
+ */
+public class XmlLinksEntityProducer {
+
+ private final EntityProviderWriteProperties properties;
+
+ public XmlLinksEntityProducer(final EntityProviderWriteProperties properties) throws EntityProviderException {
+ this.properties = properties == null ? EntityProviderWriteProperties.serviceRoot(null).build() : properties;
+ }
+
+ public void append(final XMLStreamWriter writer, final EntityInfoAggregator entityInfo, final List<Map<String, Object>> data) throws EntityProviderException {
+ try {
+ writer.writeStartElement(FormatXml.D_LINKS);
+ writer.writeDefaultNamespace(Edm.NAMESPACE_D_2007_08);
+ if (properties.getInlineCount() != null) {
+ writer.writeStartElement(Edm.PREFIX_M, FormatXml.M_COUNT, Edm.NAMESPACE_M_2007_08);
+ writer.writeNamespace(Edm.PREFIX_M, Edm.NAMESPACE_M_2007_08);
+ writer.writeCharacters(properties.getInlineCount().toString());
+ writer.writeEndElement();
+ }
+ XmlLinkEntityProducer provider = new XmlLinkEntityProducer(properties);
+ for (final Map<String, Object> entityData : data) {
+ provider.append(writer, entityInfo, entityData, false);
+ }
+ writer.writeEndElement();
+ writer.flush();
+ } catch (final XMLStreamException e) {
+ throw new EntityProviderException(EntityProviderException.COMMON, e);
+ }
+ }
+}
http://git-wip-us.apache.org/repos/asf/incubator-olingo-odata2/blob/ff2b0a0e/odata-core/src/main/java/org/apache/olingo/odata2/core/ep/producer/XmlMetadataProducer.java
----------------------------------------------------------------------
diff --git a/odata-core/src/main/java/org/apache/olingo/odata2/core/ep/producer/XmlMetadataProducer.java b/odata-core/src/main/java/org/apache/olingo/odata2/core/ep/producer/XmlMetadataProducer.java
new file mode 100644
index 0000000..265c092
--- /dev/null
+++ b/odata-core/src/main/java/org/apache/olingo/odata2/core/ep/producer/XmlMetadataProducer.java
@@ -0,0 +1,591 @@
+/*******************************************************************************
+ * 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.odata2.core.ep.producer;
+
+import java.util.ArrayList;
+import java.util.Collection;
+import java.util.HashMap;
+import java.util.Locale;
+import java.util.Map;
+
+import javax.xml.stream.FactoryConfigurationError;
+import javax.xml.stream.XMLStreamException;
+import javax.xml.stream.XMLStreamWriter;
+
+import org.apache.olingo.odata2.api.edm.Edm;
+import org.apache.olingo.odata2.api.edm.EdmFacets;
+import org.apache.olingo.odata2.api.edm.provider.AnnotationAttribute;
+import org.apache.olingo.odata2.api.edm.provider.AnnotationElement;
+import org.apache.olingo.odata2.api.edm.provider.Association;
+import org.apache.olingo.odata2.api.edm.provider.AssociationEnd;
+import org.apache.olingo.odata2.api.edm.provider.AssociationSet;
+import org.apache.olingo.odata2.api.edm.provider.AssociationSetEnd;
+import org.apache.olingo.odata2.api.edm.provider.ComplexProperty;
+import org.apache.olingo.odata2.api.edm.provider.ComplexType;
+import org.apache.olingo.odata2.api.edm.provider.CustomizableFeedMappings;
+import org.apache.olingo.odata2.api.edm.provider.DataServices;
+import org.apache.olingo.odata2.api.edm.provider.Documentation;
+import org.apache.olingo.odata2.api.edm.provider.EntityContainer;
+import org.apache.olingo.odata2.api.edm.provider.EntitySet;
+import org.apache.olingo.odata2.api.edm.provider.EntityType;
+import org.apache.olingo.odata2.api.edm.provider.FunctionImport;
+import org.apache.olingo.odata2.api.edm.provider.FunctionImportParameter;
+import org.apache.olingo.odata2.api.edm.provider.Key;
+import org.apache.olingo.odata2.api.edm.provider.NavigationProperty;
+import org.apache.olingo.odata2.api.edm.provider.OnDelete;
+import org.apache.olingo.odata2.api.edm.provider.Property;
+import org.apache.olingo.odata2.api.edm.provider.PropertyRef;
+import org.apache.olingo.odata2.api.edm.provider.ReferentialConstraint;
+import org.apache.olingo.odata2.api.edm.provider.ReferentialConstraintRole;
+import org.apache.olingo.odata2.api.edm.provider.Schema;
+import org.apache.olingo.odata2.api.edm.provider.SimpleProperty;
+import org.apache.olingo.odata2.api.edm.provider.Using;
+import org.apache.olingo.odata2.api.ep.EntityProviderException;
+import org.apache.olingo.odata2.core.exception.ODataRuntimeException;
+
+public class XmlMetadataProducer {
+
+ public static void writeMetadata(final DataServices metadata, final XMLStreamWriter xmlStreamWriter, Map<String, String> predefinedNamespaces) throws EntityProviderException {
+
+ try {
+ xmlStreamWriter.writeStartDocument();
+ xmlStreamWriter.setPrefix(Edm.PREFIX_EDMX, Edm.NAMESPACE_EDMX_2007_06);
+ xmlStreamWriter.setPrefix(Edm.PREFIX_M, Edm.NAMESPACE_M_2007_08);
+ xmlStreamWriter.setDefaultNamespace(Edm.NAMESPACE_EDM_2008_09);
+
+ xmlStreamWriter.writeStartElement(Edm.NAMESPACE_EDMX_2007_06, "Edmx");
+ xmlStreamWriter.writeAttribute("Version", "1.0");
+ xmlStreamWriter.writeNamespace(Edm.PREFIX_EDMX, Edm.NAMESPACE_EDMX_2007_06);
+
+ xmlStreamWriter.writeStartElement(Edm.NAMESPACE_EDMX_2007_06, "DataServices");
+ xmlStreamWriter.writeAttribute(Edm.PREFIX_M, Edm.NAMESPACE_M_2007_08, "DataServiceVersion", metadata.getDataServiceVersion());
+ xmlStreamWriter.writeNamespace(Edm.PREFIX_M, Edm.NAMESPACE_M_2007_08);
+
+ if (predefinedNamespaces != null) {
+ for (Map.Entry<String, String> entry : predefinedNamespaces.entrySet()) {
+ xmlStreamWriter.writeNamespace(entry.getKey(), entry.getValue());
+ }
+ } else {
+ predefinedNamespaces = new HashMap<String, String>();
+ }
+
+ Collection<Schema> schemas = metadata.getSchemas();
+ if (schemas != null) {
+ for (Schema schema : schemas) {
+ xmlStreamWriter.writeStartElement("Schema");
+ if (schema.getAlias() != null) {
+ xmlStreamWriter.writeAttribute("Alias", schema.getAlias());
+ }
+ xmlStreamWriter.writeAttribute("Namespace", schema.getNamespace());
+ xmlStreamWriter.writeDefaultNamespace(Edm.NAMESPACE_EDM_2008_09);
+
+ writeAnnotationAttributes(schema.getAnnotationAttributes(), predefinedNamespaces, null, xmlStreamWriter);
+
+ Collection<Using> usings = schema.getUsings();
+ if (usings != null) {
+ for (Using using : usings) {
+ xmlStreamWriter.writeStartElement("Using");
+ xmlStreamWriter.writeAttribute("Namespace", using.getNamespace());
+ xmlStreamWriter.writeAttribute("Alias", using.getAlias());
+ writeAnnotationAttributes(using.getAnnotationAttributes(), predefinedNamespaces, null, xmlStreamWriter);
+ writeDocumentation(using.getDocumentation(), predefinedNamespaces, xmlStreamWriter);
+ writeAnnotationElements(using.getAnnotationElements(), predefinedNamespaces, xmlStreamWriter);
+ xmlStreamWriter.writeEndElement();
+ }
+ }
+
+ Collection<EntityType> entityTypes = schema.getEntityTypes();
+ if (entityTypes != null) {
+ for (EntityType entityType : entityTypes) {
+ xmlStreamWriter.writeStartElement("EntityType");
+ xmlStreamWriter.writeAttribute("Name", entityType.getName());
+ if (entityType.getBaseType() != null) {
+ xmlStreamWriter.writeAttribute("BaseType", entityType.getBaseType().toString());
+ }
+ if (entityType.isAbstract()) {
+ xmlStreamWriter.writeAttribute("Abstract", "true");
+ }
+ if (entityType.isHasStream()) {
+ xmlStreamWriter.writeAttribute(Edm.PREFIX_M, Edm.NAMESPACE_M_2007_08, "HasStream", "true");
+ }
+
+ writeCustomizableFeedMappings(entityType.getCustomizableFeedMappings(), xmlStreamWriter);
+
+ writeAnnotationAttributes(entityType.getAnnotationAttributes(), predefinedNamespaces, null, xmlStreamWriter);
+
+ writeDocumentation(entityType.getDocumentation(), predefinedNamespaces, xmlStreamWriter);
+
+ Key key = entityType.getKey();
+ if (key != null) {
+ xmlStreamWriter.writeStartElement("Key");
+
+ writeAnnotationAttributes(key.getAnnotationAttributes(), predefinedNamespaces, null, xmlStreamWriter);
+
+ Collection<PropertyRef> propertyRefs = entityType.getKey().getKeys();
+ for (PropertyRef propertyRef : propertyRefs) {
+ xmlStreamWriter.writeStartElement("PropertyRef");
+
+ writeAnnotationAttributes(propertyRef.getAnnotationAttributes(), predefinedNamespaces, null, xmlStreamWriter);
+
+ xmlStreamWriter.writeAttribute("Name", propertyRef.getName());
+
+ writeAnnotationElements(propertyRef.getAnnotationElements(), predefinedNamespaces, xmlStreamWriter);
+
+ xmlStreamWriter.writeEndElement();
+ }
+
+ writeAnnotationElements(key.getAnnotationElements(), predefinedNamespaces, xmlStreamWriter);
+
+ xmlStreamWriter.writeEndElement();
+ }
+
+ Collection<Property> properties = entityType.getProperties();
+ if (properties != null) {
+ writeProperties(properties, predefinedNamespaces, xmlStreamWriter);
+ }
+
+ Collection<NavigationProperty> navigationProperties = entityType.getNavigationProperties();
+ if (navigationProperties != null) {
+ for (NavigationProperty navigationProperty : navigationProperties) {
+ xmlStreamWriter.writeStartElement("NavigationProperty");
+ xmlStreamWriter.writeAttribute("Name", navigationProperty.getName());
+ xmlStreamWriter.writeAttribute("Relationship", navigationProperty.getRelationship().toString());
+ xmlStreamWriter.writeAttribute("FromRole", navigationProperty.getFromRole());
+ xmlStreamWriter.writeAttribute("ToRole", navigationProperty.getToRole());
+
+ writeAnnotationAttributes(navigationProperty.getAnnotationAttributes(), predefinedNamespaces, null, xmlStreamWriter);
+
+ writeDocumentation(navigationProperty.getDocumentation(), predefinedNamespaces, xmlStreamWriter);
+
+ writeAnnotationElements(navigationProperty.getAnnotationElements(), predefinedNamespaces, xmlStreamWriter);
+
+ xmlStreamWriter.writeEndElement();
+ }
+ }
+
+ writeAnnotationElements(entityType.getAnnotationElements(), predefinedNamespaces, xmlStreamWriter);
+
+ xmlStreamWriter.writeEndElement();
+ }
+ }
+
+ Collection<ComplexType> complexTypes = schema.getComplexTypes();
+ if (complexTypes != null) {
+ for (ComplexType complexType : complexTypes) {
+ xmlStreamWriter.writeStartElement("ComplexType");
+ xmlStreamWriter.writeAttribute("Name", complexType.getName());
+ if (complexType.getBaseType() != null) {
+ xmlStreamWriter.writeAttribute("BaseType", complexType.getBaseType().toString());
+ }
+ if (complexType.isAbstract()) {
+ xmlStreamWriter.writeAttribute("Abstract", "true");
+ }
+
+ writeAnnotationAttributes(complexType.getAnnotationAttributes(), predefinedNamespaces, null, xmlStreamWriter);
+
+ writeDocumentation(complexType.getDocumentation(), predefinedNamespaces, xmlStreamWriter);
+
+ Collection<Property> properties = complexType.getProperties();
+ if (properties != null) {
+ writeProperties(properties, predefinedNamespaces, xmlStreamWriter);
+ }
+
+ writeAnnotationElements(complexType.getAnnotationElements(), predefinedNamespaces, xmlStreamWriter);
+
+ xmlStreamWriter.writeEndElement();
+ }
+ }
+
+ Collection<Association> associations = schema.getAssociations();
+ if (associations != null) {
+ for (Association association : associations) {
+ xmlStreamWriter.writeStartElement("Association");
+ xmlStreamWriter.writeAttribute("Name", association.getName());
+
+ writeAnnotationAttributes(association.getAnnotationAttributes(), predefinedNamespaces, null, xmlStreamWriter);
+
+ writeDocumentation(association.getDocumentation(), predefinedNamespaces, xmlStreamWriter);
+
+ writeAssociationEnd(association.getEnd1(), predefinedNamespaces, xmlStreamWriter);
+ writeAssociationEnd(association.getEnd2(), predefinedNamespaces, xmlStreamWriter);
+
+ ReferentialConstraint referentialConstraint = association.getReferentialConstraint();
+ if (referentialConstraint != null) {
+ xmlStreamWriter.writeStartElement("ReferentialConstraint");
+ writeAnnotationAttributes(referentialConstraint.getAnnotationAttributes(), predefinedNamespaces, null, xmlStreamWriter);
+ writeDocumentation(referentialConstraint.getDocumentation(), predefinedNamespaces, xmlStreamWriter);
+
+ ReferentialConstraintRole principal = referentialConstraint.getPrincipal();
+ xmlStreamWriter.writeStartElement("Principal");
+ xmlStreamWriter.writeAttribute("Role", principal.getRole());
+ writeAnnotationAttributes(principal.getAnnotationAttributes(), predefinedNamespaces, null, xmlStreamWriter);
+
+ for (PropertyRef propertyRef : principal.getPropertyRefs()) {
+ xmlStreamWriter.writeStartElement("PropertyRef");
+ xmlStreamWriter.writeAttribute("Name", propertyRef.getName());
+ xmlStreamWriter.writeEndElement();
+ }
+ writeAnnotationElements(principal.getAnnotationElements(), predefinedNamespaces, xmlStreamWriter);
+ xmlStreamWriter.writeEndElement();
+
+ ReferentialConstraintRole dependent = referentialConstraint.getDependent();
+ xmlStreamWriter.writeStartElement("Dependent");
+ xmlStreamWriter.writeAttribute("Role", dependent.getRole());
+ writeAnnotationAttributes(dependent.getAnnotationAttributes(), predefinedNamespaces, null, xmlStreamWriter);
+
+ for (PropertyRef propertyRef : dependent.getPropertyRefs()) {
+ xmlStreamWriter.writeStartElement("PropertyRef");
+ xmlStreamWriter.writeAttribute("Name", propertyRef.getName());
+ xmlStreamWriter.writeEndElement();
+ }
+ writeAnnotationElements(dependent.getAnnotationElements(), predefinedNamespaces, xmlStreamWriter);
+ xmlStreamWriter.writeEndElement();
+
+ writeAnnotationElements(referentialConstraint.getAnnotationElements(), predefinedNamespaces, xmlStreamWriter);
+ xmlStreamWriter.writeEndElement();
+ }
+
+ writeAnnotationElements(association.getAnnotationElements(), predefinedNamespaces, xmlStreamWriter);
+
+ xmlStreamWriter.writeEndElement();
+ }
+ }
+
+ Collection<EntityContainer> entityContainers = schema.getEntityContainers();
+ if (entityContainers != null) {
+ for (EntityContainer entityContainer : entityContainers) {
+ xmlStreamWriter.writeStartElement("EntityContainer");
+ xmlStreamWriter.writeAttribute("Name", entityContainer.getName());
+ if (entityContainer.getExtendz() != null) {
+ xmlStreamWriter.writeAttribute("Extends", entityContainer.getExtendz());
+ }
+ if (entityContainer.isDefaultEntityContainer()) {
+ xmlStreamWriter.writeAttribute(Edm.PREFIX_M, Edm.NAMESPACE_M_2007_08, "IsDefaultEntityContainer", "true");
+ }
+
+ writeAnnotationAttributes(entityContainer.getAnnotationAttributes(), predefinedNamespaces, null, xmlStreamWriter);
+
+ writeDocumentation(entityContainer.getDocumentation(), predefinedNamespaces, xmlStreamWriter);
+
+ Collection<EntitySet> entitySets = entityContainer.getEntitySets();
+ if (entitySets != null) {
+ for (EntitySet entitySet : entitySets) {
+ xmlStreamWriter.writeStartElement("EntitySet");
+ xmlStreamWriter.writeAttribute("Name", entitySet.getName());
+ xmlStreamWriter.writeAttribute("EntityType", entitySet.getEntityType().toString());
+
+ writeAnnotationAttributes(entitySet.getAnnotationAttributes(), predefinedNamespaces, null, xmlStreamWriter);
+
+ writeDocumentation(entitySet.getDocumentation(), predefinedNamespaces, xmlStreamWriter);
+
+ writeAnnotationElements(entitySet.getAnnotationElements(), predefinedNamespaces, xmlStreamWriter);
+
+ xmlStreamWriter.writeEndElement();
+ }
+ }
+
+ Collection<AssociationSet> associationSets = entityContainer.getAssociationSets();
+ if (associationSets != null) {
+ for (AssociationSet associationSet : associationSets) {
+ xmlStreamWriter.writeStartElement("AssociationSet");
+ xmlStreamWriter.writeAttribute("Name", associationSet.getName());
+ xmlStreamWriter.writeAttribute("Association", associationSet.getAssociation().toString());
+
+ writeAnnotationAttributes(associationSet.getAnnotationAttributes(), predefinedNamespaces, null, xmlStreamWriter);
+
+ writeDocumentation(associationSet.getDocumentation(), predefinedNamespaces, xmlStreamWriter);
+
+ writeAssociationSetEnd(associationSet.getEnd1(), predefinedNamespaces, xmlStreamWriter);
+ writeAssociationSetEnd(associationSet.getEnd2(), predefinedNamespaces, xmlStreamWriter);
+
+ writeAnnotationElements(associationSet.getAnnotationElements(), predefinedNamespaces, xmlStreamWriter);
+
+ xmlStreamWriter.writeEndElement();
+ }
+ }
+
+ Collection<FunctionImport> functionImports = entityContainer.getFunctionImports();
+ if (functionImports != null) {
+ for (FunctionImport functionImport : functionImports) {
+ xmlStreamWriter.writeStartElement("FunctionImport");
+ xmlStreamWriter.writeAttribute("Name", functionImport.getName());
+ if (functionImport.getReturnType() != null) {
+ xmlStreamWriter.writeAttribute("ReturnType", functionImport.getReturnType().toString());
+ }
+ if (functionImport.getEntitySet() != null) {
+ xmlStreamWriter.writeAttribute("EntitySet", functionImport.getEntitySet());
+ }
+ if (functionImport.getHttpMethod() != null) {
+ xmlStreamWriter.writeAttribute(Edm.PREFIX_M, Edm.NAMESPACE_M_2007_08, "HttpMethod", functionImport.getHttpMethod());
+ }
+
+ writeAnnotationAttributes(functionImport.getAnnotationAttributes(), predefinedNamespaces, null, xmlStreamWriter);
+
+ writeDocumentation(functionImport.getDocumentation(), predefinedNamespaces, xmlStreamWriter);
+
+ Collection<FunctionImportParameter> functionImportParameters = functionImport.getParameters();
+ if (functionImportParameters != null) {
+ for (FunctionImportParameter functionImportParameter : functionImportParameters) {
+ xmlStreamWriter.writeStartElement("Parameter");
+ xmlStreamWriter.writeAttribute("Name", functionImportParameter.getName());
+ xmlStreamWriter.writeAttribute("Type", functionImportParameter.getType().getFullQualifiedName().toString());
+ if (functionImportParameter.getMode() != null) {
+ xmlStreamWriter.writeAttribute("Mode", functionImportParameter.getMode());
+ }
+
+ writeFacets(xmlStreamWriter, functionImportParameter.getFacets());
+
+ writeAnnotationAttributes(functionImportParameter.getAnnotationAttributes(), predefinedNamespaces, null, xmlStreamWriter);
+
+ writeDocumentation(functionImportParameter.getDocumentation(), predefinedNamespaces, xmlStreamWriter);
+
+ writeAnnotationElements(functionImportParameter.getAnnotationElements(), predefinedNamespaces, xmlStreamWriter);
+
+ xmlStreamWriter.writeEndElement();
+ }
+ }
+
+ writeAnnotationElements(functionImport.getAnnotationElements(), predefinedNamespaces, xmlStreamWriter);
+
+ xmlStreamWriter.writeEndElement();
+ }
+ }
+
+ writeAnnotationElements(entityContainer.getAnnotationElements(), predefinedNamespaces, xmlStreamWriter);
+
+ xmlStreamWriter.writeEndElement();
+ }
+ }
+
+ writeAnnotationElements(schema.getAnnotationElements(), predefinedNamespaces, xmlStreamWriter);
+
+ xmlStreamWriter.writeEndElement();
+ }
+ }
+
+ xmlStreamWriter.writeEndElement();
+ xmlStreamWriter.writeEndElement();
+ xmlStreamWriter.writeEndDocument();
+
+ xmlStreamWriter.flush();
+ } catch (XMLStreamException e) {
+ throw new EntityProviderException(EntityProviderException.COMMON, e);
+ } catch (FactoryConfigurationError e) {
+ throw new EntityProviderException(EntityProviderException.COMMON, e);
+ }
+ }
+
+ private static void writeCustomizableFeedMappings(final CustomizableFeedMappings customizableFeedMappings, final XMLStreamWriter xmlStreamWriter) throws XMLStreamException {
+ if (customizableFeedMappings != null) {
+ if (customizableFeedMappings.getFcKeepInContent() != null) {
+ xmlStreamWriter.writeAttribute(Edm.PREFIX_M, Edm.NAMESPACE_M_2007_08, "FC_KeepInContent", customizableFeedMappings.getFcKeepInContent().toString().toLowerCase(Locale.ROOT));
+ }
+ if (customizableFeedMappings.getFcContentKind() != null) {
+ xmlStreamWriter.writeAttribute(Edm.PREFIX_M, Edm.NAMESPACE_M_2007_08, "FC_ContentKind", customizableFeedMappings.getFcContentKind().toString());
+ }
+ if (customizableFeedMappings.getFcNsPrefix() != null) {
+ xmlStreamWriter.writeAttribute(Edm.PREFIX_M, Edm.NAMESPACE_M_2007_08, "FC_NsPrefix", customizableFeedMappings.getFcNsPrefix());
+ }
+ if (customizableFeedMappings.getFcNsUri() != null) {
+ xmlStreamWriter.writeAttribute(Edm.PREFIX_M, Edm.NAMESPACE_M_2007_08, "FC_NsUri", customizableFeedMappings.getFcNsUri());
+ }
+ if (customizableFeedMappings.getFcSourcePath() != null) {
+ xmlStreamWriter.writeAttribute(Edm.PREFIX_M, Edm.NAMESPACE_M_2007_08, "FC_SourcePath", customizableFeedMappings.getFcSourcePath());
+ }
+ if (customizableFeedMappings.getFcTargetPath() != null) {
+ xmlStreamWriter.writeAttribute(Edm.PREFIX_M, Edm.NAMESPACE_M_2007_08, "FC_TargetPath", customizableFeedMappings.getFcTargetPath().toString());
+ }
+ }
+ }
+
+ private static void writeProperties(final Collection<Property> properties, final Map<String, String> predefinedNamespaces, final XMLStreamWriter xmlStreamWriter) throws XMLStreamException {
+ for (Property property : properties) {
+ xmlStreamWriter.writeStartElement("Property");
+ xmlStreamWriter.writeAttribute("Name", property.getName());
+ if (property instanceof SimpleProperty) {
+ xmlStreamWriter.writeAttribute("Type", ((SimpleProperty) property).getType().getFullQualifiedName().toString());
+ } else if (property instanceof ComplexProperty) {
+ xmlStreamWriter.writeAttribute("Type", ((ComplexProperty) property).getType().toString());
+ } else {
+ throw new ODataRuntimeException();
+ }
+
+ writeFacets(xmlStreamWriter, property.getFacets());
+
+ if (property.getMimeType() != null) {
+ xmlStreamWriter.writeAttribute(Edm.PREFIX_M, Edm.NAMESPACE_M_2007_08, "MimeType", property.getMimeType());
+ }
+
+ writeCustomizableFeedMappings(property.getCustomizableFeedMappings(), xmlStreamWriter);
+
+ writeAnnotationAttributes(property.getAnnotationAttributes(), predefinedNamespaces, null, xmlStreamWriter);
+
+ writeDocumentation(property.getDocumentation(), predefinedNamespaces, xmlStreamWriter);
+
+ writeAnnotationElements(property.getAnnotationElements(), predefinedNamespaces, xmlStreamWriter);
+
+ xmlStreamWriter.writeEndElement();
+ }
+ }
+
+ private static void writeFacets(final XMLStreamWriter xmlStreamWriter, final EdmFacets facets) throws XMLStreamException {
+ if (facets != null) {
+ if (facets.isNullable() != null) {
+ xmlStreamWriter.writeAttribute("Nullable", facets.isNullable().toString().toLowerCase(Locale.ROOT));
+ }
+ if (facets.getDefaultValue() != null) {
+ xmlStreamWriter.writeAttribute("DefaultValue", facets.getDefaultValue());
+ }
+ if (facets.getMaxLength() != null) {
+ xmlStreamWriter.writeAttribute("MaxLength", facets.getMaxLength().toString());
+ }
+ if (facets.isFixedLength() != null) {
+ xmlStreamWriter.writeAttribute("FixedLength", facets.isFixedLength().toString().toLowerCase(Locale.ROOT));
+ }
+ if (facets.getPrecision() != null) {
+ xmlStreamWriter.writeAttribute("Precision", facets.getPrecision().toString());
+ }
+ if (facets.getScale() != null) {
+ xmlStreamWriter.writeAttribute("Scale", facets.getScale().toString());
+ }
+ if (facets.isUnicode() != null) {
+ xmlStreamWriter.writeAttribute("Unicode", facets.isUnicode().toString());
+ }
+ if (facets.getCollation() != null) {
+ xmlStreamWriter.writeAttribute("Collation", facets.getCollation());
+ }
+ if (facets.getConcurrencyMode() != null) {
+ xmlStreamWriter.writeAttribute("ConcurrencyMode", facets.getConcurrencyMode().toString());
+ }
+ }
+ }
+
+ private static void writeAssociationEnd(final AssociationEnd end, final Map<String, String> predefinedNamespaces, final XMLStreamWriter xmlStreamWriter) throws XMLStreamException {
+ xmlStreamWriter.writeStartElement("End");
+ xmlStreamWriter.writeAttribute("Type", end.getType().toString());
+ xmlStreamWriter.writeAttribute("Multiplicity", end.getMultiplicity().toString());
+ if (end.getRole() != null) {
+ xmlStreamWriter.writeAttribute("Role", end.getRole());
+ }
+
+ writeAnnotationAttributes(end.getAnnotationAttributes(), predefinedNamespaces, null, xmlStreamWriter);
+
+ writeDocumentation(end.getDocumentation(), predefinedNamespaces, xmlStreamWriter);
+
+ OnDelete onDelete = end.getOnDelete();
+ if (onDelete != null) {
+ xmlStreamWriter.writeStartElement("OnDelete");
+ xmlStreamWriter.writeAttribute("Action", onDelete.getAction().toString());
+ writeAnnotationAttributes(onDelete.getAnnotationAttributes(), predefinedNamespaces, null, xmlStreamWriter);
+ writeDocumentation(onDelete.getDocumentation(), predefinedNamespaces, xmlStreamWriter);
+ writeAnnotationElements(onDelete.getAnnotationElements(), predefinedNamespaces, xmlStreamWriter);
+ xmlStreamWriter.writeEndElement();
+ }
+
+ writeAnnotationElements(end.getAnnotationElements(), predefinedNamespaces, xmlStreamWriter);
+
+ xmlStreamWriter.writeEndElement();
+ }
+
+ private static void writeAssociationSetEnd(final AssociationSetEnd end, final Map<String, String> predefinedNamespaces, final XMLStreamWriter xmlStreamWriter) throws XMLStreamException {
+ xmlStreamWriter.writeStartElement("End");
+ xmlStreamWriter.writeAttribute("EntitySet", end.getEntitySet().toString());
+ if (end.getRole() != null) {
+ xmlStreamWriter.writeAttribute("Role", end.getRole());
+ }
+ writeAnnotationAttributes(end.getAnnotationAttributes(), predefinedNamespaces, null, xmlStreamWriter);
+ writeDocumentation(end.getDocumentation(), predefinedNamespaces, xmlStreamWriter);
+ writeAnnotationElements(end.getAnnotationElements(), predefinedNamespaces, xmlStreamWriter);
+ xmlStreamWriter.writeEndElement();
+ }
+
+ private static void writeDocumentation(final Documentation documentation, final Map<String, String> predefinedNamespaces, final XMLStreamWriter xmlStreamWriter) throws XMLStreamException {
+ if (documentation != null) {
+ xmlStreamWriter.writeStartElement("Documentation");
+ writeAnnotationAttributes(documentation.getAnnotationAttributes(), predefinedNamespaces, null, xmlStreamWriter);
+
+ xmlStreamWriter.writeStartElement("Summary");
+ xmlStreamWriter.writeCharacters(documentation.getSummary());
+ xmlStreamWriter.writeEndElement();
+
+ xmlStreamWriter.writeStartElement("LongDescription");
+ xmlStreamWriter.writeCharacters(documentation.getLongDescription());
+ xmlStreamWriter.writeEndElement();
+
+ writeAnnotationElements(documentation.getAnnotationElements(), predefinedNamespaces, xmlStreamWriter);
+ xmlStreamWriter.writeEndElement();
+ }
+ }
+
+ private static void writeAnnotationAttributes(final Collection<AnnotationAttribute> annotationAttributes, final Map<String, String> predefinedNamespaces, ArrayList<String> setNamespaces, final XMLStreamWriter xmlStreamWriter) throws XMLStreamException {
+ if (annotationAttributes != null) {
+ if (setNamespaces == null) {
+ setNamespaces = new ArrayList<String>();
+ }
+ for (AnnotationAttribute annotationAttribute : annotationAttributes) {
+ if (annotationAttribute.getNamespace() != null) {
+ xmlStreamWriter.writeAttribute(annotationAttribute.getPrefix(), annotationAttribute.getNamespace(), annotationAttribute.getName(), annotationAttribute.getText());
+ if (setNamespaces.contains(annotationAttribute.getNamespace()) == false && predefinedNamespaces.containsValue(annotationAttribute.getNamespace()) == false) {
+ xmlStreamWriter.writeNamespace(annotationAttribute.getPrefix(), annotationAttribute.getNamespace());
+ setNamespaces.add(annotationAttribute.getNamespace());
+ }
+ } else {
+ xmlStreamWriter.writeAttribute(annotationAttribute.getName(), annotationAttribute.getText());
+ }
+ }
+ }
+ }
+
+ private static void writeAnnotationElements(final Collection<AnnotationElement> annotationElements, final Map<String, String> predefinedNamespaces, final XMLStreamWriter xmlStreamWriter) throws XMLStreamException {
+ if (annotationElements != null) {
+ for (AnnotationElement annotationElement : annotationElements) {
+ ArrayList<String> setNamespaces = new ArrayList<String>();
+ if (annotationElement.getNamespace() != null) {
+ if (annotationElement.getPrefix() != null) {
+ xmlStreamWriter.writeStartElement(annotationElement.getPrefix(), annotationElement.getName(), annotationElement.getNamespace());
+ if (!predefinedNamespaces.containsValue(annotationElement.getNamespace())) {
+ xmlStreamWriter.writeNamespace(annotationElement.getPrefix(), annotationElement.getNamespace());
+ setNamespaces.add(annotationElement.getNamespace());
+ }
+ } else {
+ xmlStreamWriter.writeStartElement("", annotationElement.getName(), annotationElement.getNamespace());
+ if (!predefinedNamespaces.containsValue(annotationElement.getNamespace())) {
+ xmlStreamWriter.writeNamespace("", annotationElement.getNamespace());
+ setNamespaces.add(annotationElement.getNamespace());
+ }
+ }
+ } else {
+ xmlStreamWriter.writeStartElement(annotationElement.getName());
+ }
+
+ writeAnnotationAttributes(annotationElement.getAttributes(), predefinedNamespaces, setNamespaces, xmlStreamWriter);
+
+ if (annotationElement.getChildElements() != null) {
+ writeAnnotationElements(annotationElement.getChildElements(), predefinedNamespaces, xmlStreamWriter);
+ } else {
+ if (annotationElement.getText() != null) {
+ xmlStreamWriter.writeCharacters(annotationElement.getText());
+ }
+ }
+
+ xmlStreamWriter.writeEndElement();
+ }
+ }
+ }
+}
http://git-wip-us.apache.org/repos/asf/incubator-olingo-odata2/blob/ff2b0a0e/odata-core/src/main/java/org/apache/olingo/odata2/core/ep/producer/XmlPropertyEntityProducer.java
----------------------------------------------------------------------
diff --git a/odata-core/src/main/java/org/apache/olingo/odata2/core/ep/producer/XmlPropertyEntityProducer.java b/odata-core/src/main/java/org/apache/olingo/odata2/core/ep/producer/XmlPropertyEntityProducer.java
new file mode 100644
index 0000000..930f2f6
--- /dev/null
+++ b/odata-core/src/main/java/org/apache/olingo/odata2/core/ep/producer/XmlPropertyEntityProducer.java
@@ -0,0 +1,211 @@
+/*******************************************************************************
+ * 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.odata2.core.ep.producer;
+
+import java.util.List;
+import java.util.Map;
+
+import javax.xml.stream.XMLStreamException;
+import javax.xml.stream.XMLStreamWriter;
+
+import org.apache.olingo.odata2.api.edm.Edm;
+import org.apache.olingo.odata2.api.edm.EdmCustomizableFeedMappings;
+import org.apache.olingo.odata2.api.edm.EdmException;
+import org.apache.olingo.odata2.api.edm.EdmLiteralKind;
+import org.apache.olingo.odata2.api.edm.EdmSimpleType;
+import org.apache.olingo.odata2.api.ep.EntityProviderException;
+import org.apache.olingo.odata2.core.ep.aggregator.EntityComplexPropertyInfo;
+import org.apache.olingo.odata2.core.ep.aggregator.EntityPropertyInfo;
+import org.apache.olingo.odata2.core.ep.util.FormatXml;
+
+/**
+ * Internal EntityProvider for simple and complex EDM properties which are pre-analyzed as {@link EntityPropertyInfo}.
+ * @author SAP AG
+ */
+public class XmlPropertyEntityProducer {
+
+ /**
+ * Append {@link Object} <code>value</code> based on {@link EntityPropertyInfo} to {@link XMLStreamWriter}
+ * in an already existing XML structure inside the d namespace.
+ *
+ * @param writer
+ * @param name Name of the outer XML tag
+ * @param propertyInfo
+ * @param value
+ * @throws EntityProviderException
+ */
+ public void append(final XMLStreamWriter writer, final String name, final EntityPropertyInfo propertyInfo, final Object value) throws EntityProviderException {
+ try {
+ writer.writeStartElement(Edm.NAMESPACE_D_2007_08, name);
+
+ if (propertyInfo.isComplex()) {
+ appendProperty(writer, (EntityComplexPropertyInfo) propertyInfo, value);
+ } else {
+ appendProperty(writer, propertyInfo, value);
+ }
+
+ writer.writeEndElement();
+ } catch (XMLStreamException e) {
+ throw new EntityProviderException(EntityProviderException.COMMON, e);
+ } catch (EdmException e) {
+ throw new EntityProviderException(EntityProviderException.COMMON, e);
+ }
+ }
+
+ public void appendCustomProperty(final XMLStreamWriter writer, final String name, final EntityPropertyInfo propertyInfo, final Object value) throws EntityProviderException {
+ try {
+ if (!propertyInfo.isComplex()) {
+ writeStartElementWithCustomNamespace(writer, propertyInfo, name);
+ appendProperty(writer, propertyInfo, value);
+ writer.writeEndElement();
+ }
+ } catch (XMLStreamException e) {
+ throw new EntityProviderException(EntityProviderException.COMMON, e);
+ } catch (EdmException e) {
+ throw new EntityProviderException(EntityProviderException.COMMON, e);
+ }
+ }
+
+ /**
+ * Append {@link Object} <code>value</code> based on {@link EntityPropertyInfo} to {@link XMLStreamWriter}
+ * as a stand-alone XML structure, including writing of default namespace declarations.
+ * The name of the outermost XML element comes from the {@link EntityPropertyInfo}.
+ *
+ * @param writer
+ * @param propertyInfo
+ * @param value
+ * @throws EntityProviderException
+ */
+ public void append(final XMLStreamWriter writer, final EntityPropertyInfo propertyInfo, final Object value) throws EntityProviderException {
+ try {
+ writer.writeStartElement(propertyInfo.getName());
+ writer.writeDefaultNamespace(Edm.NAMESPACE_D_2007_08);
+ writer.writeNamespace(Edm.PREFIX_M, Edm.NAMESPACE_M_2007_08);
+
+ if (propertyInfo.isComplex()) {
+ appendProperty(writer, (EntityComplexPropertyInfo) propertyInfo, value);
+ } else {
+ appendProperty(writer, propertyInfo, value);
+ }
+
+ writer.writeEndElement();
+ } catch (XMLStreamException e) {
+ throw new EntityProviderException(EntityProviderException.COMMON, e);
+ } catch (EdmException e) {
+ throw new EntityProviderException(EntityProviderException.COMMON, e);
+ }
+ }
+
+ /**
+ *
+ * @param writer
+ * @param propertyInfo
+ * @param value
+ * @throws XMLStreamException
+ * @throws EdmException
+ * @throws EntityProviderException
+ */
+ private void appendProperty(final XMLStreamWriter writer, final EntityComplexPropertyInfo propertyInfo, final Object value) throws XMLStreamException, EdmException, EntityProviderException {
+
+ if (value == null) {
+ writer.writeAttribute(Edm.NAMESPACE_M_2007_08, FormatXml.ATOM_NULL, FormatXml.ATOM_VALUE_TRUE);
+ } else {
+ writer.writeAttribute(Edm.NAMESPACE_M_2007_08, FormatXml.ATOM_TYPE, getFqnTypeName(propertyInfo));
+ List<EntityPropertyInfo> propertyInfos = propertyInfo.getPropertyInfos();
+ for (EntityPropertyInfo childPropertyInfo : propertyInfos) {
+ Object childValue = extractChildValue(value, childPropertyInfo.getName());
+ append(writer, childPropertyInfo.getName(), childPropertyInfo, childValue);
+ }
+ }
+ }
+
+ /**
+ * Returns full qualified name of a type of a given PropertyInfo.
+ * @return Full qualified name
+ */
+ private String getFqnTypeName(final EntityComplexPropertyInfo propertyInfo) throws EdmException {
+ return propertyInfo.getType().getNamespace() + Edm.DELIMITER + propertyInfo.getType().getName();
+ }
+
+ /**
+ * If <code>value</code> is a {@link Map} the element with given <code>name</code> as key is returned.
+ * If <code>value</code> is NOT a {@link Map} its {@link String#valueOf(Object)} result is returned.
+ *
+ * @param value
+ * @param name
+ * @return name or result (see above)
+ */
+ private Object extractChildValue(final Object value, final String name) {
+ if (value instanceof Map) {
+ Map<?, ?> map = (Map<?, ?>) value;
+ return map.get(name);
+ }
+ return String.valueOf(value);
+ }
+
+ /**
+ * Appends a simple-property value to the XML stream.
+ * @param writer the XML stream writer
+ * @param prop property informations
+ * @param value the value of the property
+ * @throws XMLStreamException
+ * @throws EdmException
+ */
+ private void appendProperty(final XMLStreamWriter writer, final EntityPropertyInfo prop, final Object value) throws XMLStreamException, EdmException {
+ Object contentValue = value;
+ String mimeType = null;
+ if (prop.getMimeType() != null) {
+ mimeType = prop.getMimeType();
+ } else if (prop.getMapping() != null && prop.getMapping().getMimeType() != null) {
+ mimeType = (String) extractChildValue(value, prop.getMapping().getMimeType());
+ contentValue = extractChildValue(value, prop.getName());
+ }
+
+ if (mimeType != null) {
+ writer.writeAttribute(Edm.NAMESPACE_M_2007_08, FormatXml.M_MIME_TYPE, mimeType);
+ }
+
+ final EdmSimpleType type = (EdmSimpleType) prop.getType();
+ final String valueAsString = type.valueToString(contentValue, EdmLiteralKind.DEFAULT, prop.getFacets());
+ if (valueAsString == null) {
+ writer.writeAttribute(Edm.NAMESPACE_M_2007_08, FormatXml.ATOM_NULL, FormatXml.ATOM_VALUE_TRUE);
+ } else {
+ writer.writeCharacters(valueAsString);
+ }
+ }
+
+ /**
+ *
+ * @param writer
+ * @param prop
+ * @param name
+ * @throws XMLStreamException
+ * @throws EntityProviderException
+ */
+ private void writeStartElementWithCustomNamespace(final XMLStreamWriter writer, final EntityPropertyInfo prop, final String name) throws XMLStreamException, EntityProviderException {
+ EdmCustomizableFeedMappings mapping = prop.getCustomMapping();
+ String nsPrefix = mapping.getFcNsPrefix();
+ String nsUri = mapping.getFcNsUri();
+ if (nsUri == null || nsPrefix == null) {
+ throw new EntityProviderException(EntityProviderException.INVALID_NAMESPACE.addContent(name));
+ }
+ writer.writeStartElement(nsPrefix, name, nsUri);
+ writer.writeNamespace(nsPrefix, nsUri);
+ }
+}
http://git-wip-us.apache.org/repos/asf/incubator-olingo-odata2/blob/ff2b0a0e/odata-core/src/main/java/org/apache/olingo/odata2/core/ep/util/CircleStreamBuffer.java
----------------------------------------------------------------------
diff --git a/odata-core/src/main/java/org/apache/olingo/odata2/core/ep/util/CircleStreamBuffer.java b/odata-core/src/main/java/org/apache/olingo/odata2/core/ep/util/CircleStreamBuffer.java
new file mode 100644
index 0000000..759b374
--- /dev/null
+++ b/odata-core/src/main/java/org/apache/olingo/odata2/core/ep/util/CircleStreamBuffer.java
@@ -0,0 +1,326 @@
+/*******************************************************************************
+ * 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.odata2.core.ep.util;
+
+import java.io.IOException;
+import java.io.InputStream;
+import java.io.OutputStream;
+import java.nio.ByteBuffer;
+import java.util.Queue;
+import java.util.concurrent.LinkedBlockingQueue;
+
+/**
+ * Circular stream buffer to write/read into/from one single buffer.
+ * With support of {@link InputStream} and {@link OutputStream} access to buffered data.
+ *
+ * @author SAP AG
+ */
+public class CircleStreamBuffer {
+
+ private static final int NEW_BUFFER_RESIZE_FACTOR = 2;
+ private static final int READ_EOF = -1;
+ private static final int DEFAULT_CAPACITY = 8192;
+ private static final int MAX_CAPACITY = DEFAULT_CAPACITY * 32;
+
+ private int currentAllocateCapacity = DEFAULT_CAPACITY;
+
+ private boolean writeMode = true;
+ private boolean writeClosed = false;
+ private boolean readClosed = false;
+
+ private Queue<ByteBuffer> bufferQueue = new LinkedBlockingQueue<ByteBuffer>();
+ private ByteBuffer currentWriteBuffer;
+
+ private InternalInputStream inStream;
+ private InternalOutputStream outStream;
+
+ /**
+ * Creates a {@link CircleStreamBuffer} with default buffer size.
+ */
+ public CircleStreamBuffer() {
+ this(DEFAULT_CAPACITY);
+ }
+
+ /**
+ * Create a {@link CircleStreamBuffer} with given buffer size in bytes.
+ *
+ * @param bufferSize
+ */
+ public CircleStreamBuffer(final int bufferSize) {
+ currentAllocateCapacity = bufferSize;
+ createNewWriteBuffer();
+ inStream = new InternalInputStream(this);
+ outStream = new InternalOutputStream(this);
+ }
+
+ /**
+ * Get {@link InputStream} for data read access.
+ *
+ * @return the stream
+ */
+ public InputStream getInputStream() {
+ return inStream;
+ }
+
+ /**
+ * Get {@link OutputStream} for write data.
+ *
+ * @return the stream
+ */
+ public OutputStream getOutputStream() {
+ return outStream;
+ }
+
+ // #############################################
+ // #
+ // # Common parts
+ // #
+ // #############################################
+
+ /**
+ * Closes the write (input) part of the {@link CircleStreamBuffer}.
+ * After this call the buffer can only be read out.
+ */
+ public void closeWrite() {
+ writeClosed = true;
+ }
+
+ /**
+ * Closes the read (output) part of the {@link CircleStreamBuffer}.
+ * After this call it is possible to write into the buffer (but can never be read out).
+ */
+ public void closeRead() {
+ readClosed = true;
+ // clear references to byte buffers
+ ByteBuffer buffer = bufferQueue.poll();
+ while (buffer != null) {
+ buffer.clear();
+ buffer = bufferQueue.poll();
+ }
+ }
+
+ /**
+ * Closes write and read part (and hence the complete buffer).
+ */
+ public void close() {
+ closeWrite();
+ closeRead();
+ }
+
+ private int remaining() throws IOException {
+ if (writeMode) {
+ return currentWriteBuffer.remaining();
+ } else {
+ ByteBuffer toRead = getReadBuffer();
+ if (toRead == null) {
+ return 0;
+ }
+ return toRead.remaining();
+ }
+ }
+
+ // #############################################
+ // #
+ // # Reading parts
+ // #
+ // #############################################
+
+ private ByteBuffer getReadBuffer() throws IOException {
+ if (readClosed) {
+ throw new IOException("Tried to read from closed stream.");
+ }
+
+ boolean next = false;
+ ByteBuffer tmp = null;
+ if (writeMode) {
+ writeMode = false;
+ next = true;
+ } else {
+ tmp = bufferQueue.peek();
+ if (tmp != null && !tmp.hasRemaining()) {
+ tmp = bufferQueue.poll();
+ next = true;
+ }
+ }
+
+ if (next) {
+ tmp = bufferQueue.peek();
+ if (tmp != null) {
+ tmp.flip();
+ }
+ tmp = getReadBuffer();
+ }
+
+ return tmp;
+ }
+
+ private int read(final byte[] b, final int off, final int len) throws IOException {
+ ByteBuffer readBuffer = getReadBuffer();
+ if (readBuffer == null) {
+ return READ_EOF;
+ }
+
+ int toReadLength = readBuffer.remaining();
+ if (len < toReadLength) {
+ toReadLength = len;
+ }
+ readBuffer.get(b, off, toReadLength);
+ return toReadLength;
+ }
+
+ private int read() throws IOException {
+ ByteBuffer readBuffer = getReadBuffer();
+ if (readBuffer == null) {
+ return READ_EOF;
+ }
+
+ return readBuffer.get();
+ }
+
+ // #############################################
+ // #
+ // # Writing parts
+ // #
+ // #############################################
+
+ private void write(final byte[] data, final int off, final int len) throws IOException {
+ ByteBuffer writeBuffer = getWriteBuffer(len);
+ writeBuffer.put(data, off, len);
+ }
+
+ private ByteBuffer getWriteBuffer(final int size) throws IOException {
+ if (writeClosed) {
+ throw new IOException("Tried to write into closed stream.");
+ }
+
+ if (writeMode) {
+ if (remaining() < size) {
+ createNewWriteBuffer(size);
+ }
+ } else {
+ writeMode = true;
+ createNewWriteBuffer();
+ }
+
+ return currentWriteBuffer;
+ }
+
+ private void write(final int b) throws IOException {
+ ByteBuffer writeBuffer = getWriteBuffer(1);
+ writeBuffer.put((byte) b);
+ }
+
+ private void createNewWriteBuffer() {
+ createNewWriteBuffer(currentAllocateCapacity);
+ }
+
+ /**
+ * Creates a new buffer (per {@link #allocateBuffer(int)}) with the requested capacity as minimum capacity, add the new allocated
+ * buffer to the {@link #bufferQueue} and set it as {@link #currentWriteBuffer}.
+ *
+ * @param requestedCapacity minimum capacity for new allocated buffer
+ */
+ private void createNewWriteBuffer(final int requestedCapacity) {
+ ByteBuffer b = allocateBuffer(requestedCapacity);
+ bufferQueue.add(b);
+ currentWriteBuffer = b;
+ }
+
+ /**
+ *
+ * @param requestedCapacity
+ * @return the buffer
+ */
+ private ByteBuffer allocateBuffer(final int requestedCapacity) {
+ int allocateCapacity = requestedCapacity;
+ if (allocateCapacity < currentAllocateCapacity) {
+ allocateCapacity = currentAllocateCapacity * NEW_BUFFER_RESIZE_FACTOR;
+ }
+ if (allocateCapacity > MAX_CAPACITY) {
+ allocateCapacity = MAX_CAPACITY;
+ }
+ // update current
+ currentAllocateCapacity = allocateCapacity;
+ return ByteBuffer.allocate(allocateCapacity);
+ }
+
+ // #############################################
+ // #
+ // # Inner classes (streams)
+ // #
+ // #############################################
+
+ /**
+ *
+ */
+ private static class InternalInputStream extends InputStream {
+
+ private final CircleStreamBuffer inBuffer;
+
+ public InternalInputStream(final CircleStreamBuffer csBuffer) {
+ inBuffer = csBuffer;
+ }
+
+ @Override
+ public int available() throws IOException {
+ return inBuffer.remaining();
+ }
+
+ @Override
+ public int read() throws IOException {
+ return inBuffer.read();
+ }
+
+ @Override
+ public int read(final byte[] b, final int off, final int len) throws IOException {
+ return inBuffer.read(b, off, len);
+ }
+
+ @Override
+ public void close() throws IOException {
+ inBuffer.closeRead();
+ }
+ }
+
+ /**
+ *
+ */
+ private static class InternalOutputStream extends OutputStream {
+ private final CircleStreamBuffer outBuffer;
+
+ public InternalOutputStream(final CircleStreamBuffer csBuffer) {
+ outBuffer = csBuffer;
+ }
+
+ @Override
+ public void write(final int b) throws IOException {
+ outBuffer.write(b);
+ }
+
+ @Override
+ public void write(final byte[] b, final int off, final int len) throws IOException {
+ outBuffer.write(b, off, len);
+ }
+
+ @Override
+ public void close() throws IOException {
+ outBuffer.closeWrite();
+ }
+ }
+}
http://git-wip-us.apache.org/repos/asf/incubator-olingo-odata2/blob/ff2b0a0e/odata-core/src/main/java/org/apache/olingo/odata2/core/ep/util/FormatJson.java
----------------------------------------------------------------------
diff --git a/odata-core/src/main/java/org/apache/olingo/odata2/core/ep/util/FormatJson.java b/odata-core/src/main/java/org/apache/olingo/odata2/core/ep/util/FormatJson.java
new file mode 100644
index 0000000..f1a3d67
--- /dev/null
+++ b/odata-core/src/main/java/org/apache/olingo/odata2/core/ep/util/FormatJson.java
@@ -0,0 +1,53 @@
+/*******************************************************************************
+ * 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.odata2.core.ep.util;
+
+/**
+ * String constants for formatting and parsing of JSON.
+ * @author SAP AG
+ */
+public class FormatJson {
+
+ public static final String D = "d";
+ public static final String RESULTS = "results";
+ public static final String COUNT = "__count";
+ public static final String METADATA = "__metadata";
+ public static final String DEFERRED = "__deferred";
+ public static final String ID = "id";
+ public static final String CONTENT_TYPE = "content_type";
+ public static final String MEDIA_SRC = "media_src";
+ public static final String MEDIA_ETAG = "media_etag";
+ public static final String EDIT_MEDIA = "edit_media";
+ public static final String PROPERTIES = "properties";
+ public static final String URI = "uri";
+ public static final String NULL = "null";
+ public static final String TRUE = "true";
+ public static final String FALSE = "false";
+ public static final String TYPE = "type";
+ public static final String ETAG = "etag";
+ public static final String ENTITY_SETS = "EntitySets";
+ public static final String NEXT = "__next";
+ public static final String ERROR = "error";
+ public static final String CODE = "code";
+ public static final String MESSAGE = "message";
+ public static final String LANG = "lang";
+ public static final String VALUE = "value";
+ public static final String INNER_ERROR = "innererror";
+ public static final String DELTA = "__delta";
+}
http://git-wip-us.apache.org/repos/asf/incubator-olingo-odata2/blob/ff2b0a0e/odata-core/src/main/java/org/apache/olingo/odata2/core/ep/util/FormatXml.java
----------------------------------------------------------------------
diff --git a/odata-core/src/main/java/org/apache/olingo/odata2/core/ep/util/FormatXml.java b/odata-core/src/main/java/org/apache/olingo/odata2/core/ep/util/FormatXml.java
new file mode 100644
index 0000000..52ee8d1
--- /dev/null
+++ b/odata-core/src/main/java/org/apache/olingo/odata2/core/ep/util/FormatXml.java
@@ -0,0 +1,94 @@
+/*******************************************************************************
+ * 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.odata2.core.ep.util;
+
+/**
+ * String constants for formatting and parsing of XML.
+ * @author SAP AG
+ */
+public class FormatXml {
+
+ public static final String XML_HEADER_NO = "no";
+ public static final String XML_HEADER_FULL = "full";
+ public static final String XML_HEADER_WITHOUT_ENCODING = "without encoding";
+ public static final String XML_BASE = "base";
+ public static final String XML_LANG = "lang";
+
+ public static final String M_PROPERTIES = "properties";
+ public static final String M_MIME_TYPE = "MimeType";
+
+ public static final String M_ETAG = "etag";
+ public static final String M_COUNT = "count";
+ public static final String M_TYPE = "type";
+ public static final String M_NULL = "null";
+ public static final String M_INLINE = "inline";
+
+ public static final String M_ERROR = "error";
+ public static final String M_CODE = "code";
+ public static final String M_MESSAGE = "message";
+ public static final String M_INNER_ERROR = "innererror";
+
+ public static final String D_ELEMENT = "element";
+ public static final String D_LINKS = "links";
+ public static final String D_URI = "uri";
+
+ public static final String APP_SERVICE = "service";
+ public static final String APP_WORKSPACE = "workspace";
+ public static final String APP_COLLECTION = "collection";
+ public static final String APP_ACCEPT = "accept";
+ public static final String APP_CATEGORIES = "categories";
+ public static final String APP_CATEGORIES_FIXED = "fixed";
+ public static final String APP_CATEGORIES_SCHEME = "scheme";
+
+ public static final String ATOM_FEED = "feed";
+ public static final String ATOM_ENTRY = "entry";
+ public static final String ATOM_LINK = "link";
+ public static final String ATOM_REL = "rel";
+ public static final String ATOM_HREF = "href";
+ public static final String ATOM_SRC = "src";
+ public static final String ATOM_TITLE = "title";
+ public static final String ATOM_TITLE_DEFAULT = "Default";
+ public static final String ATOM_TEXT = "text";
+ public static final String ATOM_TYPE = "type";
+ public static final String ATOM_UPDATED = "updated";
+ public static final String ATOM_ID = "id";
+ public static final String ATOM_AUTHOR = "author";
+ public static final String ATOM_AUTHOR_NAME = "name";
+ public static final String ATOM_AUTHOR_EMAIL = "email";
+ public static final String ATOM_AUTHOR_URI = "uri";
+ public static final String ATOM_SUMMARY = "summary";
+ public static final String ATOM_CONTRIBUTOR = "contributor";
+ public static final String ATOM_CONTRIBUTOR_NAME = "name";
+ public static final String ATOM_CONTRIBUTOR_EMAIL = "email";
+ public static final String ATOM_CONTRIBUTOR_URI = "uri";
+ public static final String ATOM_PUBLISHED = "published";
+ public static final String ATOM_RIGHTS = "rights";
+ public static final String ATOM_CATEGORY = "category";
+ public static final String ATOM_CATEGORY_TERM = "term";
+ public static final String ATOM_CATEGORY_SCHEME = "scheme";
+ public static final String ATOM_CATEGORY_LABEL = "label";
+ public static final String ATOM_CONTENT = "content";
+ public static final String ATOM_NULL = "null";
+ public static final String ATOM_VALUE_TRUE = "true";
+ public static final String ATOM_NEXT_LINK = "next";
+ public static final String ATOM_DELTA_LINK = "delta";
+ public static final String ATOM_TOMBSTONE_REF = "ref";
+ public static final String ATOM_TOMBSTONE_WHEN = "when";
+ public static final String ATOM_TOMBSTONE_DELETED_ENTRY = "deleted-entry";
+}
http://git-wip-us.apache.org/repos/asf/incubator-olingo-odata2/blob/ff2b0a0e/odata-core/src/main/java/org/apache/olingo/odata2/core/ep/util/JsonStreamWriter.java
----------------------------------------------------------------------
diff --git a/odata-core/src/main/java/org/apache/olingo/odata2/core/ep/util/JsonStreamWriter.java b/odata-core/src/main/java/org/apache/olingo/odata2/core/ep/util/JsonStreamWriter.java
new file mode 100644
index 0000000..185d32a
--- /dev/null
+++ b/odata-core/src/main/java/org/apache/olingo/odata2/core/ep/util/JsonStreamWriter.java
@@ -0,0 +1,175 @@
+/*******************************************************************************
+ * 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.odata2.core.ep.util;
+
+import java.io.IOException;
+import java.io.Writer;
+
+/**
+ * Writes JSON output.
+ * @author SAP AG
+ */
+public class JsonStreamWriter {
+ private final Writer writer;
+
+ public JsonStreamWriter(final Writer writer) {
+ this.writer = writer;
+ }
+
+ public JsonStreamWriter beginObject() throws IOException {
+ writer.append('{');
+ return this;
+ }
+
+ public JsonStreamWriter endObject() throws IOException {
+ writer.append('}');
+ return this;
+ }
+
+ public JsonStreamWriter beginArray() throws IOException {
+ writer.append('[');
+ return this;
+ }
+
+ public JsonStreamWriter endArray() throws IOException {
+ writer.append(']');
+ return this;
+ }
+
+ public JsonStreamWriter name(final String name) throws IOException {
+ writer.append('"').append(name).append('"').append(':');
+ return this;
+ }
+
+ public JsonStreamWriter unquotedValue(final String value) throws IOException {
+ writer.append(value == null ? FormatJson.NULL : value);
+ return this;
+ }
+
+ public JsonStreamWriter stringValueRaw(final String value) throws IOException {
+ if (value == null) {
+ writer.append(FormatJson.NULL);
+ } else {
+ writer.append('"').append(value).append('"');
+ }
+ return this;
+ }
+
+ public JsonStreamWriter stringValue(final String value) throws IOException {
+ if (value == null) {
+ writer.append(FormatJson.NULL);
+ } else {
+ writer.append('"');
+ escape(value);
+ writer.append('"');
+ }
+ return this;
+ }
+
+ public JsonStreamWriter namedStringValueRaw(final String name, final String value) throws IOException {
+ name(name);
+ stringValueRaw(value);
+ return this;
+ }
+
+ public JsonStreamWriter namedStringValue(final String name, final String value) throws IOException {
+ name(name);
+ stringValue(value);
+ return this;
+ }
+
+ public JsonStreamWriter separator() throws IOException {
+ writer.append(',');
+ return this;
+ }
+
+ /**
+ * Writes the JSON-escaped form of a Java String value according to RFC 4627.
+ * @param value the Java String
+ * @throws IOException if an I/O error occurs
+ */
+ protected void escape(final String value) throws IOException {
+ // RFC 4627 says: "All Unicode characters may be placed within the
+ // quotation marks except for the characters that must be escaped:
+ // quotation mark, reverse solidus, and the control characters
+ // (U+0000 through U+001F)."
+ // All output here is done on character basis which should be faster
+ // than writing Strings.
+ for (int i = 0; i < value.length(); i++) {
+ final char c = value.charAt(i);
+ switch (c) {
+ case '\\':
+ writer.append('\\').append(c);
+ break;
+ case '"':
+ writer.append('\\').append(c);
+ break;
+ case '\b':
+ writer.append('\\').append('b');
+ break;
+ case '\t':
+ writer.append('\\').append('t');
+ break;
+ case '\n':
+ writer.append('\\').append('n');
+ break;
+ case '\f':
+ writer.append('\\').append('f');
+ break;
+ case '\r':
+ writer.append('\\').append('r');
+ break;
+ case '\u0000':
+ case '\u0001':
+ case '\u0002':
+ case '\u0003':
+ case '\u0004':
+ case '\u0005':
+ case '\u0006':
+ case '\u0007':
+ case '\u000B':
+ case '\u000E':
+ case '\u000F':
+ case '\u0010':
+ case '\u0011':
+ case '\u0012':
+ case '\u0013':
+ case '\u0014':
+ case '\u0015':
+ case '\u0016':
+ case '\u0017':
+ case '\u0018':
+ case '\u0019':
+ case '\u001A':
+ case '\u001B':
+ case '\u001C':
+ case '\u001D':
+ case '\u001E':
+ case '\u001F':
+ final int lastHexDigit = c % 0x10;
+ writer.append('\\').append('u').append('0').append('0')
+ .append(c >= '\u0010' ? '1' : '0')
+ .append((char) ((lastHexDigit > 9 ? 'A' : '0') + lastHexDigit % 10));
+ break;
+ default:
+ writer.append(c);
+ }
+ }
+ }
+}
http://git-wip-us.apache.org/repos/asf/incubator-olingo-odata2/blob/ff2b0a0e/odata-core/src/main/java/org/apache/olingo/odata2/core/ep/util/JsonUtils.java
----------------------------------------------------------------------
diff --git a/odata-core/src/main/java/org/apache/olingo/odata2/core/ep/util/JsonUtils.java b/odata-core/src/main/java/org/apache/olingo/odata2/core/ep/util/JsonUtils.java
new file mode 100644
index 0000000..53542ab
--- /dev/null
+++ b/odata-core/src/main/java/org/apache/olingo/odata2/core/ep/util/JsonUtils.java
@@ -0,0 +1,72 @@
+/*******************************************************************************
+ * 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.odata2.core.ep.util;
+
+import java.io.IOException;
+
+import com.google.gson.stream.JsonReader;
+import com.google.gson.stream.JsonToken;
+import org.apache.olingo.odata2.api.ep.EntityProviderException;
+
+public class JsonUtils {
+
+ public static int startJson(final JsonReader reader) throws EntityProviderException {
+ //The enclosing "d" and "results" are optional - so we cannot check for the presence
+ //but we have to read over them in case they are present.
+ JsonToken token;
+ try {
+ token = reader.peek();
+ int openJsonObjects = 0;
+ if (JsonToken.BEGIN_OBJECT == token) {
+ reader.beginObject();
+ openJsonObjects++;
+ token = reader.peek();
+ if (JsonToken.NAME == token) {
+ String name = reader.nextName();
+ if (!("d".equals(name) ^ "results".equals(name))) {
+ //TODO I18N
+ throw new EntityProviderException(EntityProviderException.COMMON, name + " not expected, only d or results");
+ }
+ }
+
+ token = reader.peek();
+ if (JsonToken.BEGIN_OBJECT == token) {
+ reader.beginObject();
+ openJsonObjects++;
+ } else if (JsonToken.BEGIN_ARRAY == token) {
+ //TODO I18N
+ throw new EntityProviderException(EntityProviderException.COMMON, "Array not expected");
+ }
+ }
+
+ return openJsonObjects;
+ } catch (IOException e) {
+ //TODO I18N
+ throw new EntityProviderException(EntityProviderException.COMMON, e);
+ }
+ }
+
+ public static boolean endJson(final JsonReader reader, final int openJsonObjects) throws IOException, EntityProviderException {
+
+ for (int closedJsonObjects = 0; closedJsonObjects < openJsonObjects; closedJsonObjects++) {
+ reader.endObject();
+ }
+ return reader.peek() == JsonToken.END_DOCUMENT;
+ }
+}