From f79db0b3c7724a17349c265de55f2caf1372d77d Mon Sep 17 00:00:00 2001 From: fmartelli Date: Tue, 29 Apr 2014 10:12:22 +0200 Subject: [PATCH] provided complex type BATCH update + removed aalto transitive dependency exclusion --- fit/pom.xml | 14 --- .../apache/olingo/fit/AbstractServices.java | 113 ++++++++++++------ .../org/apache/olingo/fit/V3OpenType.java | 3 +- .../org/apache/olingo/fit/V4OpenType.java | 2 +- .../apache/olingo/fit/metadata/Metadata.java | 50 +++++--- .../olingo/fit/utils/AbstractUtilities.java | 72 +++++------ .../org/apache/olingo/fit/utils/Commons.java | 6 +- .../apache/olingo/fit/utils/ConstantKey.java | 3 + .../apache/olingo/fit/utils/Constants.java | 12 ++ .../apache/olingo/fit/utils/XMLElement.java | 5 +- .../fit/utils/XMLEventReaderWrapper.java | 29 +++-- .../apache/olingo/fit/utils/XMLUtilities.java | 73 +++++------ .../main/resources/V30/openTypeMetadata.xml | 2 +- .../client/core/it/v4/PropertyTestITCase.java | 57 ++++++++- 14 files changed, 270 insertions(+), 171 deletions(-) diff --git a/fit/pom.xml b/fit/pom.xml index b7e404364..699541cf2 100644 --- a/fit/pom.xml +++ b/fit/pom.xml @@ -44,22 +44,8 @@ org.apache.olingo olingo-commons-core ${project.version} - - - com.fasterxml - aalto-xml - - - - - stax - stax-api - 1.0.1 - - - org.apache.cxf diff --git a/fit/src/main/java/org/apache/olingo/fit/AbstractServices.java b/fit/src/main/java/org/apache/olingo/fit/AbstractServices.java index a3a414d87..021de16f8 100644 --- a/fit/src/main/java/org/apache/olingo/fit/AbstractServices.java +++ b/fit/src/main/java/org/apache/olingo/fit/AbstractServices.java @@ -67,6 +67,7 @@ import org.apache.cxf.jaxrs.client.WebClient; import org.apache.cxf.jaxrs.ext.multipart.Attachment; import org.apache.cxf.jaxrs.ext.multipart.Multipart; import org.apache.cxf.jaxrs.ext.multipart.MultipartBody; +import org.apache.olingo.commons.api.data.ComplexValue; import org.apache.olingo.commons.api.data.ResWrap; import org.apache.olingo.commons.api.data.Entry; import org.apache.olingo.commons.api.edm.EdmPrimitiveTypeKind; @@ -411,7 +412,7 @@ public abstract class AbstractServices { } else { final ResWrap jcont = mapper.readValue(IOUtils.toInputStream(changes, Constants.ENCODING), new TypeReference() { - }); + }); entryChanges = dataBinder.toAtomEntry(jcont.getPayload()); } @@ -593,8 +594,8 @@ public abstract class AbstractServices { } else { final ResWrap jcontainer = mapper.readValue(IOUtils.toInputStream(entity, Constants.ENCODING), - new TypeReference() { - }); + new TypeReference() { + }); entry = dataBinder.toAtomEntry(jcontainer.getPayload()); @@ -621,7 +622,7 @@ public abstract class AbstractServices { ResWrap result = atomDeserializer.read(serialization, AtomEntryImpl.class); result = new ResWrap( URI.create(Constants.get(version, ConstantKey.ODATA_METADATA_PREFIX) - + entitySetName + Constants.get(version, ConstantKey.ODATA_METADATA_ENTITY_SUFFIX)), + + entitySetName + Constants.get(version, ConstantKey.ODATA_METADATA_ENTITY_SUFFIX)), null, result.getPayload()); final String path = Commons.getEntityBasePath(entitySetName, entityKey); @@ -684,13 +685,13 @@ public abstract class AbstractServices { replaceAll("\"Salary\":[0-9]*,", "\"Salary\":0,"). replaceAll("\"Title\":\".*\"", "\"Title\":\"[Sacked]\""). replaceAll("\\.*\\", - "0"). + "0"). replaceAll("\\.*\\", "[Sacked]"); final FSManager fsManager = FSManager.instance(version); fsManager.putInMemory(IOUtils.toInputStream(newContent, Constants.ENCODING), fsManager.getAbsolutePath(Commons.getEntityBasePath("Person", entityId) + Constants.get(version, - ConstantKey.ENTITY), utils.getKey())); + ConstantKey.ENTITY), utils.getKey())); return utils.getValue().createResponse(null, null, null, utils.getKey(), Response.Status.NO_CONTENT); } catch (Exception e) { @@ -742,9 +743,9 @@ public abstract class AbstractServices { final Long newSalary = Long.valueOf(salaryMatcher.group(1)) + n; newContent = newContent. replaceAll("\"Salary\":" + salaryMatcher.group(1) + ",", - "\"Salary\":" + newSalary + ","). + "\"Salary\":" + newSalary + ","). replaceAll("\\" + salaryMatcher.group(1) + "", - "" + newSalary + ""); + "" + newSalary + ""); } FSManager.instance(version).putInMemory(IOUtils.toInputStream(newContent, Constants.ENCODING), @@ -893,7 +894,7 @@ public abstract class AbstractServices { } else { mapper.writeValue( writer, new JSONFeedContainer(container.getContextURL(), container.getMetadataETag(), - dataBinder.toJSONFeed(container.getPayload()))); + dataBinder.toJSONFeed(container.getPayload()))); } return xml.createResponse( @@ -1135,6 +1136,7 @@ public abstract class AbstractServices { private Response replaceProperty( final String location, final String accept, + final String contentType, final String prefer, final String entitySetName, final String entityId, @@ -1143,31 +1145,62 @@ public abstract class AbstractServices { final String changes, final boolean justValue) { + // if the given path is not about any link then search for property + LOG.info("Retrieve property {}", path); + try { - Accept acceptType = null; - if (StringUtils.isNotBlank(format)) { - acceptType = Accept.valueOf(format.toUpperCase()); - } else if (StringUtils.isNotBlank(accept)) { - acceptType = Accept.parse(accept, version, null); + final FSManager fsManager = FSManager.instance(version); + + final String basePath = Commons.getEntityBasePath(entitySetName, entityId); + final ResWrap container = xml.readContainerEntry(Accept.ATOM, + fsManager.readFile(basePath + Constants.get(version, ConstantKey.ENTITY), Accept.ATOM)); + + final AtomEntryImpl entry = container.getPayload(); + + Property toBeReplaced = null; + for (String element : path.split("/")) { + if (toBeReplaced == null) { + toBeReplaced = entry.getProperty(element.trim()); + } else { + ComplexValue value = toBeReplaced.getValue().asComplex(); + for (Property field : value.get()) { + if (field.getName().equalsIgnoreCase(element)) { + toBeReplaced = field; + } + } + } } - // if the given path is not about any link then search for property - LOG.info("Retrieve property {}", path); + if (toBeReplaced == null) { + throw new NotFoundException(); + } - final AbstractUtilities utils = getUtilities(acceptType); + if (justValue) { + // just for primitive values + toBeReplaced.setValue(new PrimitiveValueImpl(changes)); + } else { + final AtomPropertyImpl pchanges = xml.readProperty( + Accept.parse(contentType, version), + IOUtils.toInputStream(changes, Constants.ENCODING), + entry.getType()); - utils.replaceProperty( - entitySetName, - entityId, - IOUtils.toInputStream(changes, Constants.ENCODING), - Arrays.asList(path.split("/")), - acceptType, - justValue); + toBeReplaced.setValue(pchanges.getValue()); + } + + fsManager.putInMemory(xml.writeEntry(Accept.ATOM, container), + fsManager.getAbsolutePath(basePath + Constants.get(version, ConstantKey.ENTITY), Accept.ATOM)); final Response response; if ("return-content".equalsIgnoreCase(prefer)) { response = getEntityInternal(location, accept, entitySetName, entityId, format, null, null, false); } else { + Accept acceptType = null; + if (StringUtils.isNotBlank(format)) { + acceptType = Accept.valueOf(format.toUpperCase()); + } else if (StringUtils.isNotBlank(accept)) { + acceptType = Accept.parse(accept, version, null); + } + response = xml.createResponse(null, null, null, acceptType, Response.Status.NO_CONTENT); } @@ -1242,6 +1275,7 @@ public abstract class AbstractServices { public Response replacePropertyValue( @Context UriInfo uriInfo, @HeaderParam("Accept") @DefaultValue(StringUtils.EMPTY) String accept, + @HeaderParam("Content-Type") @DefaultValue(StringUtils.EMPTY) String contentType, @HeaderParam("Prefer") @DefaultValue(StringUtils.EMPTY) String prefer, @PathParam("entitySetName") String entitySetName, @PathParam("entityId") String entityId, @@ -1250,7 +1284,7 @@ public abstract class AbstractServices { final String changes) { return replaceProperty(uriInfo.getRequestUri().toASCIIString(), - accept, prefer, entitySetName, entityId, path, format, changes, true); + accept, contentType, prefer, entitySetName, entityId, path, format, changes, true); } /** @@ -1269,6 +1303,7 @@ public abstract class AbstractServices { public Response mergeProperty( @Context UriInfo uriInfo, @HeaderParam("Accept") @DefaultValue(StringUtils.EMPTY) String accept, + @HeaderParam("Content-Type") @DefaultValue(StringUtils.EMPTY) String contentType, @HeaderParam("Prefer") @DefaultValue(StringUtils.EMPTY) String prefer, @PathParam("entitySetName") String entitySetName, @PathParam("entityId") String entityId, @@ -1277,7 +1312,7 @@ public abstract class AbstractServices { final String changes) { return replaceProperty(uriInfo.getRequestUri().toASCIIString(), - accept, prefer, entitySetName, entityId, path, format, changes, false); + accept, contentType, prefer, entitySetName, entityId, path, format, changes, false); } /** @@ -1296,6 +1331,7 @@ public abstract class AbstractServices { public Response patchProperty( @Context UriInfo uriInfo, @HeaderParam("Accept") @DefaultValue(StringUtils.EMPTY) String accept, + @HeaderParam("Content-Type") @DefaultValue(StringUtils.EMPTY) String contentType, @HeaderParam("Prefer") @DefaultValue(StringUtils.EMPTY) String prefer, @PathParam("entitySetName") String entitySetName, @PathParam("entityId") String entityId, @@ -1304,7 +1340,7 @@ public abstract class AbstractServices { final String changes) { return replaceProperty(uriInfo.getRequestUri().toASCIIString(), - accept, prefer, entitySetName, entityId, path, format, changes, false); + accept, contentType, prefer, entitySetName, entityId, path, format, changes, false); } @PUT @@ -1363,6 +1399,7 @@ public abstract class AbstractServices { public Response replaceProperty( @Context UriInfo uriInfo, @HeaderParam("Accept") @DefaultValue(StringUtils.EMPTY) String accept, + @HeaderParam("Content-Type") @DefaultValue(StringUtils.EMPTY) String contentType, @HeaderParam("Prefer") @DefaultValue(StringUtils.EMPTY) String prefer, @PathParam("entitySetName") String entitySetName, @PathParam("entityId") String entityId, @@ -1374,7 +1411,7 @@ public abstract class AbstractServices { return replaceMediaProperty(prefer, entitySetName, entityId, path, changes); } else { return replaceProperty(uriInfo.getRequestUri().toASCIIString(), - accept, prefer, entitySetName, entityId, path, format, changes, false); + accept, contentType, prefer, entitySetName, entityId, path, format, changes, false); } } @@ -1518,8 +1555,8 @@ public abstract class AbstractServices { mapper.writeValue( writer, new JSONFeedContainer(container.getContextURL(), - container.getMetadataETag(), - dataBinder.toJSONFeed((AtomFeedImpl) container.getPayload()))); + container.getMetadataETag(), + dataBinder.toJSONFeed((AtomFeedImpl) container.getPayload()))); } } else { final ResWrap container = atomDeserializer.read(stream, AtomEntryImpl.class); @@ -1531,8 +1568,8 @@ public abstract class AbstractServices { mapper.writeValue( writer, new JSONEntryContainer(container.getContextURL(), - container.getMetadataETag(), - dataBinder.toJSONEntry((AtomEntryImpl) container.getPayload()))); + container.getMetadataETag(), + dataBinder.toJSONEntry((AtomEntryImpl) container.getPayload()))); } } @@ -1602,9 +1639,9 @@ public abstract class AbstractServices { final ResWrap container = new ResWrap( URI.create(Constants.get(version, ConstantKey.ODATA_METADATA_PREFIX) - + (version.compareTo(ODataServiceVersion.V40) >= 0 - ? entitySetName + "(" + entityId + ")/" + path - : property.getType())), + + (version.compareTo(ODataServiceVersion.V40) >= 0 + ? entitySetName + "(" + entityId + ")/" + path + : property.getType())), entryContainer.getMetadataETag(), property); @@ -1612,9 +1649,9 @@ public abstract class AbstractServices { null, searchForValue ? IOUtils.toInputStream( - container.getPayload().getValue() == null || container.getPayload().getValue().isNull() - ? StringUtils.EMPTY - : container.getPayload().getValue().asPrimitive().get(), Constants.ENCODING) + container.getPayload().getValue() == null || container.getPayload().getValue().isNull() + ? StringUtils.EMPTY + : container.getPayload().getValue().asPrimitive().get(), Constants.ENCODING) : utils.writeProperty(acceptType, container), Commons.getETag(Commons.getEntityBasePath(entitySetName, entityId), version), acceptType); diff --git a/fit/src/main/java/org/apache/olingo/fit/V3OpenType.java b/fit/src/main/java/org/apache/olingo/fit/V3OpenType.java index 43e1201b8..32e0073c9 100644 --- a/fit/src/main/java/org/apache/olingo/fit/V3OpenType.java +++ b/fit/src/main/java/org/apache/olingo/fit/V3OpenType.java @@ -60,9 +60,8 @@ public class V3OpenType { public V3OpenType() throws Exception { this.openMetadata = new Metadata(FSManager.instance(ODataServiceVersion.V30). readFile("openType" + StringUtils.capitalize(Constants.get(ODataServiceVersion.V30, ConstantKey.METADATA)), - Accept.XML)); + Accept.XML), ODataServiceVersion.V30); this.services = new V3Services() { - @Override protected Metadata getMetadataObj() { return openMetadata; diff --git a/fit/src/main/java/org/apache/olingo/fit/V4OpenType.java b/fit/src/main/java/org/apache/olingo/fit/V4OpenType.java index c9690f4bd..7eb99d9c7 100644 --- a/fit/src/main/java/org/apache/olingo/fit/V4OpenType.java +++ b/fit/src/main/java/org/apache/olingo/fit/V4OpenType.java @@ -56,7 +56,7 @@ public class V4OpenType { public V4OpenType() throws Exception { this.openMetadata = new Metadata(FSManager.instance(ODataServiceVersion.V40). readFile("openType" + StringUtils.capitalize(Constants.get(ODataServiceVersion.V40, ConstantKey.METADATA)), - Accept.XML)); + Accept.XML), ODataServiceVersion.V40); this.services = new V4Services() { @Override protected Metadata getMetadataObj() { diff --git a/fit/src/main/java/org/apache/olingo/fit/metadata/Metadata.java b/fit/src/main/java/org/apache/olingo/fit/metadata/Metadata.java index ebd599b12..846a86b0b 100644 --- a/fit/src/main/java/org/apache/olingo/fit/metadata/Metadata.java +++ b/fit/src/main/java/org/apache/olingo/fit/metadata/Metadata.java @@ -31,6 +31,9 @@ import javax.xml.stream.events.Attribute; import javax.xml.stream.events.StartElement; import javax.xml.stream.events.XMLEvent; import org.apache.commons.io.IOUtils; +import org.apache.olingo.commons.api.edm.constants.ODataServiceVersion; +import org.apache.olingo.fit.utils.ConstantKey; +import org.apache.olingo.fit.utils.Constants; import org.codehaus.plexus.util.StringUtils; import org.slf4j.Logger; import org.slf4j.LoggerFactory; @@ -42,21 +45,26 @@ public class Metadata extends AbstractMetadataElement { */ protected static final Logger LOG = LoggerFactory.getLogger(Metadata.class); + protected final ODataServiceVersion version; + private final Map schemas; - public Metadata(final InputStream is) { + private final String DEF_NS; + + public Metadata(final InputStream is, final ODataServiceVersion version) { + this.version = version; + this.DEF_NS = Constants.get(version, ConstantKey.EDM_NS); this.schemas = new HashMap(); try { final XMLInputFactory ifactory = XMLInputFactory.newInstance(); - ifactory.setProperty(XMLInputFactory.IS_NAMESPACE_AWARE, false); - final XMLEventReader reader = ifactory.createXMLEventReader(is, "UTF-8"); + final XMLEventReader reader = ifactory.createXMLEventReader(is, org.apache.olingo.commons.api.Constants.UTF8); try { while (reader.hasNext()) { final XMLEvent event = reader.nextEvent(); - if (event.isStartElement() && event.asStartElement().getName().equals(new QName("Schema"))) { + if (event.isStartElement() && event.asStartElement().getName().equals(new QName(DEF_NS, "Schema"))) { final Schema schema = getSchema(event.asStartElement(), reader); schemas.put(schema.getNamespace(), schema); } @@ -175,14 +183,15 @@ public class Metadata extends AbstractMetadataElement { while (!completed && reader.hasNext()) { XMLEvent event = reader.nextEvent(); - if (event.isStartElement() && event.asStartElement().getName().equals(new QName("EntityType")) - || event.isStartElement() && event.asStartElement().getName().equals(new QName("ComplexType"))) { + if (event.isStartElement() && event.asStartElement().getName().equals(new QName(DEF_NS, "EntityType")) + || event.isStartElement() && event.asStartElement().getName().equals(new QName(DEF_NS, "ComplexType"))) { final EntityType entityType = getEntityType(event.asStartElement(), reader); schema.addEntityType(entityType.getName(), entityType); - } else if (event.isStartElement() && event.asStartElement().getName().equals(new QName("EntityContainer"))) { + } else if (event.isStartElement() + && event.asStartElement().getName().equals(new QName(DEF_NS, "EntityContainer"))) { final org.apache.olingo.fit.metadata.Container container = getContainer(event.asStartElement(), reader); schema.addContainer(container.getName(), container); - } else if (event.isStartElement() && event.asStartElement().getName().equals(new QName("Association"))) { + } else if (event.isStartElement() && event.asStartElement().getName().equals(new QName(DEF_NS, "Association"))) { // just for V3 final Association association = getAssociation(event.asStartElement(), reader); schema.addAssociation(association.getName(), association); @@ -205,11 +214,12 @@ public class Metadata extends AbstractMetadataElement { XMLEvent event = reader.nextEvent(); if (event.isStartElement() - && (event.asStartElement().getName().equals(new QName("EntitySet")) - || event.asStartElement().getName().equals(new QName("Singleton")))) { + && (event.asStartElement().getName().equals(new QName(DEF_NS, "EntitySet")) + || event.asStartElement().getName().equals(new QName(DEF_NS, "Singleton")))) { final EntitySet entitySet = getEntitySet(event.asStartElement(), reader); container.addEntitySet(entitySet.getName(), entitySet); - } else if (event.isStartElement() && event.asStartElement().getName().equals(new QName("AssociationSet"))) { + } else if (event.isStartElement() + && event.asStartElement().getName().equals(new QName(DEF_NS, "AssociationSet"))) { // just for V3 final AssociationSet associationSet = getAssociationSet(event.asStartElement(), reader); container.addAssociationSet(associationSet.getAssociation(), associationSet); @@ -230,10 +240,11 @@ public class Metadata extends AbstractMetadataElement { while (!completed && reader.hasNext()) { XMLEvent event = reader.nextEvent(); - if (event.isStartElement() && event.asStartElement().getName().equals(new QName("End"))) { + if (event.isStartElement() && event.asStartElement().getName().equals(new QName(DEF_NS, "End"))) { final String role = event.asStartElement().getAttributeByName(new QName("Role")).getValue(); final String type = event.asStartElement().getAttributeByName(new QName("Type")).getValue(); - final String multiplicity = event.asStartElement().getAttributeByName(new QName("Multiplicity")).getValue(); + final String multiplicity = + event.asStartElement().getAttributeByName(new QName("Multiplicity")).getValue(); association.addRole(role, type, multiplicity); } else if (event.isEndElement() && event.asEndElement().getName().equals(start.getName())) { completed = true; @@ -254,7 +265,7 @@ public class Metadata extends AbstractMetadataElement { while (!completed && reader.hasNext()) { XMLEvent event = reader.nextEvent(); - if (event.isStartElement() && event.asStartElement().getName().equals(new QName("End"))) { + if (event.isStartElement() && event.asStartElement().getName().equals(new QName(DEF_NS, "End"))) { final String role = event.asStartElement().getAttributeByName(new QName("Role")).getValue(); final String entitySet = event.asStartElement().getAttributeByName(new QName("EntitySet")).getValue(); associationSet.addRole(role, entitySet); @@ -274,10 +285,11 @@ public class Metadata extends AbstractMetadataElement { while (!completed && reader.hasNext()) { XMLEvent event = reader.nextEvent(); - if (event.isStartElement() && event.asStartElement().getName().equals(new QName("Property"))) { + if (event.isStartElement() && event.asStartElement().getName().equals(new QName(DEF_NS, "Property"))) { final org.apache.olingo.fit.metadata.Property property = getProperty(event.asStartElement()); entityType.addProperty(property.getName(), property); - } else if (event.isStartElement() && event.asStartElement().getName().equals(new QName("NavigationProperty"))) { + } else if (event.isStartElement() + && event.asStartElement().getName().equals(new QName(DEF_NS, "NavigationProperty"))) { final NavigationProperty property = getNavigationProperty(event.asStartElement()); entityType.addNavigationProperty(property.getName(), property); } else if (event.isEndElement() && event.asEndElement().getName().equals(start.getName())) { @@ -302,7 +314,8 @@ public class Metadata extends AbstractMetadataElement { } private NavigationProperty getNavigationProperty(final StartElement start) throws XMLStreamException { - final NavigationProperty property = new NavigationProperty(start.getAttributeByName(new QName("Name")).getValue()); + final NavigationProperty property = + new NavigationProperty(start.getAttributeByName(new QName("Name")).getValue()); final Attribute type = start.getAttributeByName(new QName("Type")); if (type != null) { @@ -340,7 +353,8 @@ public class Metadata extends AbstractMetadataElement { while (!completed && reader.hasNext()) { XMLEvent event = reader.nextEvent(); - if (event.isStartElement() && event.asStartElement().getName().equals(new QName("NavigationPropertyBinding"))) { + if (event.isStartElement() + && event.asStartElement().getName().equals(new QName(DEF_NS, "NavigationPropertyBinding"))) { final String path = event.asStartElement().getAttributeByName(new QName("Path")).getValue(); final String target = event.asStartElement().getAttributeByName(new QName("Target")).getValue(); entitySet.addBinding(path, target); diff --git a/fit/src/main/java/org/apache/olingo/fit/utils/AbstractUtilities.java b/fit/src/main/java/org/apache/olingo/fit/utils/AbstractUtilities.java index c01718628..bf1e4e3c4 100644 --- a/fit/src/main/java/org/apache/olingo/fit/utils/AbstractUtilities.java +++ b/fit/src/main/java/org/apache/olingo/fit/utils/AbstractUtilities.java @@ -26,7 +26,6 @@ import java.io.File; import java.io.IOException; import java.io.InputStream; import java.io.StringWriter; -import java.net.URI; import java.util.AbstractMap.SimpleEntry; import java.util.ArrayList; import java.util.Collection; @@ -551,28 +550,35 @@ public abstract class AbstractUtilities { } else { mapper.writeValue( writer, new JSONFeedContainer(container.getContextURL(), - container.getMetadataETag(), dataBinder.toJSONFeed(container.getPayload()))); + container.getMetadataETag(), dataBinder.toJSONFeed(container.getPayload()))); } return IOUtils.toInputStream(writer.toString(), Constants.ENCODING); } - public AtomEntryImpl readEntry(final Accept accept, final InputStream entity) + public ResWrap readContainerEntry(final Accept accept, final InputStream entity) throws XMLStreamException, IOException { - - final AtomEntryImpl entry; + final ResWrap container; if (accept == Accept.ATOM || accept == Accept.XML) { - final ResWrap container = atomDeserializer.read(entity, AtomEntryImpl.class); - entry = container.getPayload(); + container = atomDeserializer.read(entity, AtomEntryImpl.class); } else { - final ResWrap container = + final ResWrap jcontainer = mapper.readValue(entity, new TypeReference() { - }); - entry = dataBinder.toAtomEntry(container.getPayload()); + }); + container = new ResWrap( + jcontainer.getContextURL(), + jcontainer.getMetadataETag(), + dataBinder.toAtomEntry(jcontainer.getPayload())); } - return entry; + return container; + } + + public AtomEntryImpl readEntry(final Accept accept, final InputStream entity) + throws XMLStreamException, IOException { + return readContainerEntry(accept, entity).getPayload(); + } public InputStream writeEntry(final Accept accept, final ResWrap container) @@ -584,7 +590,7 @@ public abstract class AbstractUtilities { } else { mapper.writeValue( writer, new JSONEntryContainer(container.getContextURL(), container.getMetadataETag(), - dataBinder.toJSONEntry(container.getPayload()))); + dataBinder.toJSONEntry(container.getPayload()))); } return IOUtils.toInputStream(writer.toString(), Constants.ENCODING); @@ -605,6 +611,23 @@ public abstract class AbstractUtilities { return IOUtils.toInputStream(writer.toString(), Constants.ENCODING); } + public AtomPropertyImpl readProperty(final Accept accept, final InputStream property, final String entryType) + throws XMLStreamException, IOException { + final AtomPropertyImpl atomProperty; + if (Accept.ATOM == accept || Accept.XML == accept) { + final ResWrap container = atomDeserializer.read(property, AtomPropertyImpl.class); + atomProperty = container.getPayload(); + } else { + final ResWrap jcontainer = mapper.readValue(property, + new TypeReference() { + }); + + atomProperty = dataBinder.toAtomProperty(jcontainer.getPayload(), entryType); + } + + return atomProperty; + } + public InputStream writeProperty(final Accept accept, final ResWrap container) throws XMLStreamException, IOException { @@ -614,7 +637,7 @@ public abstract class AbstractUtilities { } else { mapper.writeValue( writer, new JSONPropertyContainer(container.getContextURL(), container.getMetadataETag(), - dataBinder.toJSONProperty(container.getPayload()))); + dataBinder.toJSONProperty(container.getPayload()))); } return IOUtils.toInputStream(writer.toString(), Constants.ENCODING); @@ -816,29 +839,6 @@ public abstract class AbstractUtilities { // -------------------------------- } - public void replaceProperty( - final String entitySetName, - final String entityId, - final InputStream changes, - final List path, - final Accept accept, - final boolean justValue) throws Exception { - - final String basePath = Commons.getEntityBasePath(entitySetName, entityId); - - final Accept acceptType = accept == null || Accept.TEXT == accept - ? Accept.XML : accept.getExtension().equals(Accept.JSON.getExtension()) ? Accept.JSON_FULLMETA : accept; - - InputStream stream = fsManager.readFile(basePath + Constants.get(version, ConstantKey.ENTITY), acceptType); - stream = replaceProperty(stream, changes, path, justValue); - - final AtomEntryImpl entry = readEntry(acceptType, stream); - final ResWrap container = new ResWrap((URI) null, null, entry); - - fsManager.putInMemory(writeEntry(Accept.ATOM, container), - fsManager.getAbsolutePath(basePath + Constants.get(version, ConstantKey.ENTITY), Accept.ATOM)); - } - public InputStream deleteProperty( final String entitySetName, final String entityId, diff --git a/fit/src/main/java/org/apache/olingo/fit/utils/Commons.java b/fit/src/main/java/org/apache/olingo/fit/utils/Commons.java index af15f2d2f..bab6a0df6 100644 --- a/fit/src/main/java/org/apache/olingo/fit/utils/Commons.java +++ b/fit/src/main/java/org/apache/olingo/fit/utils/Commons.java @@ -135,7 +135,7 @@ public abstract class Commons { if (!METADATA.containsKey(version)) { final InputStream is = Commons.class.getResourceAsStream("/" + version.name() + "/metadata.xml"); - METADATA.put(version, new Metadata(is)); + METADATA.put(version, new Metadata(is, version)); } return METADATA.get(version); @@ -180,7 +180,7 @@ public abstract class Commons { try { return FSManager.instance(version) .getAbsolutePath(basePath + Constants.get(version, ConstantKey.LINKS_FILE_PATH) - + File.separatorChar + linkName, accept); + + File.separatorChar + linkName, accept); } catch (Exception e) { throw new IOException(e); } @@ -208,7 +208,7 @@ public abstract class Commons { final StringBuilder builder = new StringBuilder(); builder.append(""); - builder.append(""); + builder.append(""); for (String uri : link.getValue()) { builder.append(""); diff --git a/fit/src/main/java/org/apache/olingo/fit/utils/ConstantKey.java b/fit/src/main/java/org/apache/olingo/fit/utils/ConstantKey.java index 40b030d18..7ff1bd457 100644 --- a/fit/src/main/java/org/apache/olingo/fit/utils/ConstantKey.java +++ b/fit/src/main/java/org/apache/olingo/fit/utils/ConstantKey.java @@ -43,6 +43,9 @@ public enum ConstantKey { LINK, DATASERVICES_NS, METADATA_NS, + GEORSS_NS, + GML_NS, + EDM_NS, METADATA, SERVICES, FEED, diff --git a/fit/src/main/java/org/apache/olingo/fit/utils/Constants.java b/fit/src/main/java/org/apache/olingo/fit/utils/Constants.java index 1d79c91e8..44bbe1136 100644 --- a/fit/src/main/java/org/apache/olingo/fit/utils/Constants.java +++ b/fit/src/main/java/org/apache/olingo/fit/utils/Constants.java @@ -19,6 +19,8 @@ package org.apache.olingo.fit.utils; import java.nio.charset.Charset; +import java.nio.charset.CharsetDecoder; +import java.nio.charset.CodingErrorAction; import java.util.EnumMap; import java.util.Map; import org.apache.olingo.commons.api.edm.constants.ODataServiceVersion; @@ -36,7 +38,11 @@ public class Constants { public static final Charset ENCODING = Charset.forName("UTF-8"); + public static final CharsetDecoder DECODER = ENCODING.newDecoder(); + static { + DECODER.onMalformedInput(CodingErrorAction.IGNORE); + DECODER.onUnmappableCharacter(CodingErrorAction.IGNORE); // ----------------------------- // V4 only @@ -46,6 +52,9 @@ public class Constants { v4constants.put(ConstantKey.JSON_NAVIGATION_SUFFIX, "@odata.navigationLink"); v4constants.put(ConstantKey.DATASERVICES_NS, "http://docs.oasis-open.org/odata/ns/dataservices"); v4constants.put(ConstantKey.METADATA_NS, "http://docs.oasis-open.org/odata/ns/metadata"); + v4constants.put(ConstantKey.GEORSS_NS, "http://www.georss.org/georss"); + v4constants.put(ConstantKey.GML_NS, "http://www.opengis.net/gml"); + v4constants.put(ConstantKey.EDM_NS, "http://docs.oasis-open.org/odata/ns/edm"); v4constants.put(ConstantKey.ATOM_LINK_REL, "http://docs.oasis-open.org/odata/ns/related/"); v4constants.put(ConstantKey.ODATA_SERVICE_VERSION, "OData-Version"); v4constants.put(ConstantKey.DEFAULT_SERVICE_URL, "http://localhost:9080/StaticService/V40/Static.svc/"); @@ -79,6 +88,9 @@ public class Constants { constants.put(ConstantKey.LINK, "link"); constants.put(ConstantKey.METADATA_NS, "http://schemas.microsoft.com/ado/2007/08/dataservices/metadta"); constants.put(ConstantKey.DATASERVICES_NS, "http://schemas.microsoft.com/ado/2007/08/dataservices"); + constants.put(ConstantKey.GEORSS_NS, "http://www.georss.org/georss"); + constants.put(ConstantKey.GML_NS, "http://www.opengis.net/gml"); + constants.put(ConstantKey.EDM_NS, "http://schemas.microsoft.com/ado/2009/11/edm"); constants.put(ConstantKey.METADATA, "metadata"); constants.put(ConstantKey.SERVICES, "services"); constants.put(ConstantKey.FEED, "feed"); diff --git a/fit/src/main/java/org/apache/olingo/fit/utils/XMLElement.java b/fit/src/main/java/org/apache/olingo/fit/utils/XMLElement.java index 304b8ff4a..b412ba31f 100644 --- a/fit/src/main/java/org/apache/olingo/fit/utils/XMLElement.java +++ b/fit/src/main/java/org/apache/olingo/fit/utils/XMLElement.java @@ -29,6 +29,7 @@ import javax.xml.stream.XMLStreamException; import javax.xml.stream.events.EndElement; import javax.xml.stream.events.StartElement; import org.apache.commons.io.IOUtils; +import org.apache.olingo.commons.api.edm.constants.ODataServiceVersion; import org.slf4j.Logger; import org.slf4j.LoggerFactory; @@ -65,8 +66,8 @@ public class XMLElement { return new ByteArrayInputStream(content.toByteArray()); } - public XMLEventReader getContentReader() throws Exception { - return new XMLEventReaderWrapper(getContent()); + public XMLEventReader getContentReader(final ODataServiceVersion version) throws Exception { + return new XMLEventReaderWrapper(getContent(), version); } public void setContent(final InputStream content) throws IOException { diff --git a/fit/src/main/java/org/apache/olingo/fit/utils/XMLEventReaderWrapper.java b/fit/src/main/java/org/apache/olingo/fit/utils/XMLEventReaderWrapper.java index 5c88a42e8..7bae6d8ae 100644 --- a/fit/src/main/java/org/apache/olingo/fit/utils/XMLEventReaderWrapper.java +++ b/fit/src/main/java/org/apache/olingo/fit/utils/XMLEventReaderWrapper.java @@ -22,21 +22,20 @@ import java.io.ByteArrayInputStream; import java.io.InputStream; import java.io.InputStreamReader; import java.nio.charset.Charset; -import java.nio.charset.CharsetDecoder; -import java.nio.charset.CodingErrorAction; import javax.xml.stream.XMLEventReader; import javax.xml.stream.XMLInputFactory; import javax.xml.stream.XMLStreamException; import javax.xml.stream.events.XMLEvent; import org.apache.commons.io.IOUtils; +import org.apache.olingo.commons.api.edm.constants.ODataServiceVersion; public class XMLEventReaderWrapper implements XMLEventReader { - private static final Charset ENCODING = Charset.forName("UTF-8"); + private static final Charset ENCODING = Charset.forName(org.apache.olingo.commons.api.Constants.UTF8); public final static String CONTENT = "CONTENT_TAG"; - public final static String CONTENT_STAG = "<" + CONTENT + ">"; + public final String CONTENT_STAG; public final static String CONTENT_ETAG = ""; @@ -44,20 +43,24 @@ public class XMLEventReaderWrapper implements XMLEventReader { private XMLEvent nextGivenEvent = null; - public XMLEventReaderWrapper(final InputStream stream) throws Exception { - final XMLInputFactory factory = XMLInputFactory.newInstance(); - factory.setProperty(XMLInputFactory.IS_VALIDATING, false); - factory.setProperty(XMLInputFactory.IS_NAMESPACE_AWARE, false); + public XMLEventReaderWrapper(final InputStream stream, final ODataServiceVersion version) throws Exception { + final StringBuilder startBuilder = new StringBuilder(); + startBuilder.append("<").append(CONTENT). + append(" xmlns:m").append("=\"").append(Constants.get(version, ConstantKey.METADATA_NS)).append("\""). + append(" xmlns:d").append("=\"").append(Constants.get(version, ConstantKey.DATASERVICES_NS)).append("\""). + append(" xmlns:georss").append("=\"").append(Constants.get(version, ConstantKey.GEORSS_NS)).append("\""). + append(" xmlns:gml").append("=\"").append(Constants.get(version, ConstantKey.GML_NS)).append("\""). + append(">"); - final CharsetDecoder decoder = ENCODING.newDecoder(); - decoder.onMalformedInput(CodingErrorAction.IGNORE); - decoder.onUnmappableCharacter(CodingErrorAction.IGNORE); + CONTENT_STAG = startBuilder.toString(); + + final XMLInputFactory factory = XMLInputFactory.newInstance(); final InputStreamReader reader = new InputStreamReader( - new ByteArrayInputStream((XMLEventReaderWrapper.CONTENT_STAG + new ByteArrayInputStream((CONTENT_STAG + IOUtils.toString(stream, ENCODING).replaceAll("^<\\?xml.*\\?>", "") + XMLEventReaderWrapper.CONTENT_ETAG).getBytes(ENCODING)), - decoder); + Constants.DECODER); this.wrapped = factory.createXMLEventReader(reader); diff --git a/fit/src/main/java/org/apache/olingo/fit/utils/XMLUtilities.java b/fit/src/main/java/org/apache/olingo/fit/utils/XMLUtilities.java index 162221a2e..ccc02fe4d 100644 --- a/fit/src/main/java/org/apache/olingo/fit/utils/XMLUtilities.java +++ b/fit/src/main/java/org/apache/olingo/fit/utils/XMLUtilities.java @@ -22,6 +22,7 @@ import java.io.ByteArrayInputStream; import java.io.ByteArrayOutputStream; import java.io.File; import java.io.InputStream; +import java.io.InputStreamReader; import java.io.OutputStream; import java.io.OutputStreamWriter; import java.nio.charset.Charset; @@ -75,8 +76,8 @@ public class XMLUtilities extends AbstractUtilities { if (ifactory == null) { ifactory = XMLInputFactory.newInstance(); } - ifactory.setProperty(XMLInputFactory.IS_NAMESPACE_AWARE, false); - return ifactory.createXMLEventReader(is, "UTF-8"); + + return ifactory.createXMLEventReader(new InputStreamReader(is, Constants.DECODER)); } protected static XMLEventWriter getEventWriter(final OutputStream os) throws XMLStreamException { @@ -168,7 +169,7 @@ public class XMLUtilities extends AbstractUtilities { writer.add(eventFactory.createEndElement(new QName(Constants.get(version, ConstantKey.LINK)), null)); } - writer.add(entry.getValue().getContentReader()); + writer.add(entry.getValue().getContentReader(version)); writer.add(entry.getValue().getEnd()); writer.add(reader); IOUtils.closeQuietly(is); @@ -196,7 +197,7 @@ public class XMLUtilities extends AbstractUtilities { while (true) { final Map.Entry linkInfo = extractElement(reader, null, - Collections.singletonList(Constants.get(version, ConstantKey.LINK)), startDepth, 2, 2); + Collections.singletonList(Constants.get(version, ConstantKey.LINK)), startDepth, 2, 2); startDepth = linkInfo.getKey(); @@ -246,10 +247,10 @@ public class XMLUtilities extends AbstractUtilities { try { final XMLElement inlineElement = - extractElement(link.getContentReader(), null, - Collections.singletonList(Constants.get(version, ConstantKey.INLINE)), 0, -1, -1). + extractElement(link.getContentReader(version), null, + Collections.singletonList(Constants.get(version, ConstantKey.INLINE)), 0, -1, -1). getValue(); - final XMLEventReader inlineReader = inlineElement.getContentReader(); + final XMLEventReader inlineReader = inlineElement.getContentReader(version); try { while (true) { @@ -373,7 +374,7 @@ public class XMLUtilities extends AbstractUtilities { final XMLElement res = new XMLElement(); res.setStart(start); - final Charset encoding = Charset.forName("UTF-8"); + final Charset encoding = Charset.forName(org.apache.olingo.commons.api.Constants.UTF8); final ByteArrayOutputStream content = new ByteArrayOutputStream(); final OutputStreamWriter writer = new OutputStreamWriter(content, encoding); @@ -451,7 +452,7 @@ public class XMLUtilities extends AbstractUtilities { // check edit link existence extractElement(reader, writer, Collections.singletonList(Constants.get(version, ConstantKey.LINK)), Collections.>singletonList( - new AbstractMap.SimpleEntry("rel", "edit")), false, 0, -1, -1); + new AbstractMap.SimpleEntry("rel", "edit")), false, 0, -1, -1); addAtomElement(IOUtils.toInputStream(editLinkElement, Constants.ENCODING), writer); writer.add(reader); @@ -470,7 +471,7 @@ public class XMLUtilities extends AbstractUtilities { addAtomElement(IOUtils.toInputStream(editLinkElement, Constants.ENCODING), writer); - writer.add(entryElement.getContentReader()); + writer.add(entryElement.getContentReader(version)); writer.add(entryElement.getEnd()); writer.add(reader); @@ -518,7 +519,7 @@ public class XMLUtilities extends AbstractUtilities { XMLElement contentElement = extractElement(reader, writer, Collections.singletonList("content"), 0, 2, 2).getValue(); writer.add(contentElement.getStart()); - writer.add(contentElement.getContentReader()); + writer.add(contentElement.getContentReader(version)); writer.add(contentElement.getEnd()); writer.add(reader); } catch (Exception e) { @@ -533,7 +534,7 @@ public class XMLUtilities extends AbstractUtilities { extractElement(reader, writer, Collections.singletonList("entry"), 0, 1, 1).getValue(); writer.add(entryElement.getStart()); - writer.add(entryElement.getContentReader()); + writer.add(entryElement.getContentReader(version)); addAtomElement( IOUtils.toInputStream(String.format("", href)), @@ -544,14 +545,14 @@ public class XMLUtilities extends AbstractUtilities { try { final XMLElement entryElement = extractElement(reader, writer, Collections.singletonList( - Constants.get(version, ConstantKey.PROPERTIES)), 0, 2, 3).getValue(); + Constants.get(version, ConstantKey.PROPERTIES)), 0, 2, 3).getValue(); addAtomElement( IOUtils.toInputStream(""), writer); writer.add(entryElement.getStart()); - writer.add(entryElement.getContentReader()); + writer.add(entryElement.getContentReader(version)); writer.add(entryElement.getEnd()); addAtomElement( @@ -567,7 +568,7 @@ public class XMLUtilities extends AbstractUtilities { final XMLElement entryElement = extractElement(reader, writer, Collections.singletonList("entry"), 0, 1, 1).getValue(); writer.add(entryElement.getStart()); - writer.add(entryElement.getContentReader()); + writer.add(entryElement.getContentReader(version)); addAtomElement( IOUtils.toInputStream(""), @@ -742,7 +743,7 @@ public class XMLUtilities extends AbstractUtilities { writer.add(feedElement.getStart()); addAtomElement(IOUtils.toInputStream(String.format("%d", count), Constants.ENCODING), writer); - writer.add(feedElement.getContentReader()); + writer.add(feedElement.getContentReader(version)); writer.add(feedElement.getEnd()); while (reader.hasNext()) { @@ -780,7 +781,7 @@ public class XMLUtilities extends AbstractUtilities { if (event.getEventType() == XMLStreamConstants.START_ELEMENT && Constants.get(version, ConstantKey.LINK).equals(event.asStartElement().getName().getLocalPart()) && !fieldToBeSaved.contains( - event.asStartElement().getAttributeByName(new QName("title")).getValue()) + event.asStartElement().getAttributeByName(new QName("title")).getValue()) && !"edit".equals(event.asStartElement().getAttributeByName(new QName("rel")).getValue())) { writeCurrent = false; } else if (event.getEventType() == XMLStreamConstants.END_ELEMENT @@ -788,13 +789,13 @@ public class XMLUtilities extends AbstractUtilities { writeNext = true; } else if (event.getEventType() == XMLStreamConstants.START_ELEMENT && (Constants.get(version, ConstantKey.PROPERTIES)).equals( - event.asStartElement().getName().getLocalPart())) { + event.asStartElement().getName().getLocalPart())) { writeCurrent = true; writeNext = false; inProperties = true; } else if (event.getEventType() == XMLStreamConstants.END_ELEMENT && (Constants.get(version, ConstantKey.PROPERTIES)).equals( - event.asEndElement().getName().getLocalPart())) { + event.asEndElement().getName().getLocalPart())) { writeCurrent = true; } else if (inProperties) { if (event.getEventType() == XMLStreamConstants.START_ELEMENT) { @@ -811,7 +812,7 @@ public class XMLUtilities extends AbstractUtilities { } else if (event.getEventType() == XMLStreamConstants.END_ELEMENT && StringUtils.isNotBlank(currentName) && (Constants.get(version, ConstantKey.ATOM_PROPERTY_PREFIX) + currentName.trim()).equals( - event.asEndElement().getName().getLocalPart())) { + event.asEndElement().getName().getLocalPart())) { writeNext = false; currentName = null; } @@ -879,10 +880,10 @@ public class XMLUtilities extends AbstractUtilities { final XMLElement entry = extractElement( - getEventReader(readEntity(uri.getKey(), uri.getValue(), Accept.ATOM).getValue()), - null, - Collections.singletonList("entry"), - 0, 1, 1).getValue(); + getEventReader(readEntity(uri.getKey(), uri.getValue(), Accept.ATOM).getValue()), + null, + Collections.singletonList("entry"), + 0, 1, 1).getValue(); IOUtils.copy(entry.toStream(), writer, encoding); } catch (Exception e) { @@ -919,10 +920,10 @@ public class XMLUtilities extends AbstractUtilities { final Map.Entry propertyElement = extractElement(reader, null, - Collections.singletonList(Constants.get(version, ConstantKey.PROPERTIES)), 0, 2, 3); + Collections.singletonList(Constants.get(version, ConstantKey.PROPERTIES)), 0, 2, 3); reader.close(); - reader = propertyElement.getValue().getContentReader(); + reader = propertyElement.getValue().getContentReader(version); try { while (true) { @@ -943,7 +944,7 @@ public class XMLUtilities extends AbstractUtilities { while (true) { final Map.Entry linkElement = extractElement(reader, null, - Collections.singletonList(Constants.get(version, ConstantKey.LINK)), pos, 2, 2); + Collections.singletonList(Constants.get(version, ConstantKey.LINK)), pos, 2, 2); res.put("[Constants.get(version, ConstantKey.LINK)]" + linkElement.getValue().getStart().getAttributeByName(new QName("title")).getValue(), @@ -973,9 +974,9 @@ public class XMLUtilities extends AbstractUtilities { try { final XMLElement linkElement = extractElement(reader, writer, - Collections.singletonList(Constants.get(version, ConstantKey.LINK)), - Collections.>singletonList( - new SimpleEntry("title", linkName)), false, 0, -1, -1).getValue(); + Collections.singletonList(Constants.get(version, ConstantKey.LINK)), + Collections.>singletonList( + new SimpleEntry("title", linkName)), false, 0, -1, -1).getValue(); writer.add(linkElement.getStart()); // ------------------------------------------ @@ -1068,7 +1069,7 @@ public class XMLUtilities extends AbstractUtilities { writer.add(element.getValue().getStart()); } - final XMLEventReader changesReader = new XMLEventReaderWrapper(replacement); + final XMLEventReader changesReader = new XMLEventReaderWrapper(replacement, version); while (changesReader.hasNext()) { final XMLEvent event = changesReader.nextEvent(); @@ -1100,21 +1101,13 @@ public class XMLUtilities extends AbstractUtilities { @Override public InputStream deleteProperty(final InputStream src, final List path) throws Exception { - final List pathElements = new ArrayList(); - - for (String element : path) { - pathElements.add(Constants.get(version, ConstantKey.ATOM_PROPERTY_PREFIX) + element); - } - final XMLEventReader reader = getEventReader(src); final ByteArrayOutputStream bos = new ByteArrayOutputStream(); final XMLEventWriter writer = getEventWriter(bos); - final Map.Entry element = extractElement(reader, writer, pathElements, 0, 3, 4); - final XMLEventReader changesReader = new XMLEventReaderWrapper(IOUtils.toInputStream( - String.format("<%s m:null=\"true\" />", path.get(path.size() - 1)), Constants.ENCODING)); + String.format("<%s m:null=\"true\" />", path.get(path.size() - 1)), Constants.ENCODING), version); writer.add(changesReader); changesReader.close(); diff --git a/fit/src/main/resources/V30/openTypeMetadata.xml b/fit/src/main/resources/V30/openTypeMetadata.xml index 42a7deaa0..5c9da364e 100644 --- a/fit/src/main/resources/V30/openTypeMetadata.xml +++ b/fit/src/main/resources/V30/openTypeMetadata.xml @@ -21,7 +21,7 @@ --> - + diff --git a/lib/client-core/src/test/java/org/apache/olingo/client/core/it/v4/PropertyTestITCase.java b/lib/client-core/src/test/java/org/apache/olingo/client/core/it/v4/PropertyTestITCase.java index 00247ae7e..78605bfbc 100644 --- a/lib/client-core/src/test/java/org/apache/olingo/client/core/it/v4/PropertyTestITCase.java +++ b/lib/client-core/src/test/java/org/apache/olingo/client/core/it/v4/PropertyTestITCase.java @@ -18,10 +18,16 @@ */ package org.apache.olingo.client.core.it.v4; +import java.io.IOException; +import org.apache.olingo.client.api.communication.request.cud.ODataPropertyUpdateRequest; +import org.apache.olingo.client.api.communication.request.cud.v4.UpdateType; import static org.junit.Assert.assertEquals; import static org.junit.Assert.assertNotNull; import org.apache.olingo.client.api.communication.request.retrieve.ODataPropertyRequest; +import org.apache.olingo.client.api.communication.response.ODataPropertyUpdateResponse; +import org.apache.olingo.client.api.communication.response.ODataRetrieveResponse; +import org.apache.olingo.client.api.http.HttpMethod; import org.apache.olingo.client.api.uri.v4.URIBuilder; import org.apache.olingo.client.api.v4.ODataClient; import org.apache.olingo.commons.api.domain.v4.ODataProperty; @@ -29,7 +35,7 @@ import org.apache.olingo.commons.api.format.ODataFormat; import org.junit.Test; public class PropertyTestITCase extends AbstractTestITCase { - + private void _enum(final ODataClient client, final ODataFormat format) { final URIBuilder uriBuilder = client.getURIBuilder(testStaticServiceRootURL). appendEntitySetSegment("Products").appendKeySegment(5).appendPropertySegment("CoverColors"); @@ -39,7 +45,7 @@ public class PropertyTestITCase extends AbstractTestITCase { final ODataProperty prop = req.execute().getBody(); assertNotNull(prop); - assertEquals("Collection(Microsoft.Test.OData.Services.ODataWCFService.Color)", prop.getValue().getTypeName()); + assertEquals("Collection(Microsoft.Test.OData.Services.ODataWCFService.Color)", prop.getValue().getTypeName()); } @Test @@ -56,7 +62,7 @@ public class PropertyTestITCase extends AbstractTestITCase { public void enumFromFullJSON() { _enum(client, ODataFormat.JSON_FULL_METADATA); } - + private void geospatial(final ODataClient client, final ODataFormat format) { final URIBuilder uriBuilder = client.getURIBuilder(testStaticServiceRootURL). appendEntitySetSegment("People").appendKeySegment(5).appendPropertySegment("Home"); @@ -110,4 +116,49 @@ public class PropertyTestITCase extends AbstractTestITCase { public void complexFromFullJSON() { complex(client, ODataFormat.JSON_FULL_METADATA); } + + @Test + public void patchComplexPropertyAsJSON() throws IOException { + updateComplexProperty(ODataFormat.JSON_FULL_METADATA, UpdateType.PATCH); + } + + private void updateComplexProperty(final ODataFormat format, final UpdateType type) throws IOException { + final URIBuilder uriBuilder = client.getURIBuilder(testStaticServiceRootURL). + appendEntitySetSegment("Customers").appendKeySegment(1).appendPropertySegment("HomeAddress"); + + ODataPropertyRequest retrieveReq = + client.getRetrieveRequestFactory().getPropertyRequest(uriBuilder.build()); + retrieveReq.setFormat(format); + + ODataRetrieveResponse retrieveRes = retrieveReq.execute(); + assertEquals(200, retrieveRes.getStatusCode()); + + ODataProperty homeAddress = + client.getObjectFactory().newComplexProperty("HomeAddress", + client.getObjectFactory().newComplexValue(retrieveRes.getBody().getComplexValue().getTypeName())); + + homeAddress.getComplexValue().add(client.getObjectFactory(). + newPrimitiveProperty("City", client.getObjectFactory().newPrimitiveValueBuilder().buildString("Pescara"))); + + final ODataPropertyUpdateRequest updateReq = client.getCUDRequestFactory(). + getPropertyComplexValueUpdateRequest(uriBuilder.build(), type, homeAddress); + if (client.getConfiguration().isUseXHTTPMethod()) { + assertEquals(HttpMethod.POST, updateReq.getMethod()); + } else { + assertEquals(type.getMethod(), updateReq.getMethod()); + } + updateReq.setFormat(format); + + final ODataPropertyUpdateResponse updateRes = updateReq.execute(); + assertEquals(204, updateRes.getStatusCode()); + + retrieveReq = client.getRetrieveRequestFactory().getPropertyRequest(uriBuilder.build()); + retrieveReq.setFormat(format); + + retrieveRes = retrieveReq.execute(); + assertEquals(200, retrieveRes.getStatusCode()); + + homeAddress = retrieveRes.getBody(); + assertEquals("Pescara", homeAddress.getComplexValue().get("City").getPrimitiveValue().toString()); + } }