Merge from master

This commit is contained in:
Francesco Chicchiriccò 2014-04-29 10:59:19 +02:00
commit 6c7aef90ea
14 changed files with 273 additions and 174 deletions

View File

@ -44,22 +44,8 @@
<groupId>org.apache.olingo</groupId>
<artifactId>olingo-commons-core</artifactId>
<version>${project.version}</version>
<exclusions>
<exclusion>
<groupId>com.fasterxml</groupId>
<artifactId>aalto-xml</artifactId>
</exclusion>
</exclusions>
</dependency>
<!-- Stax -->
<dependency>
<groupId>stax</groupId>
<artifactId>stax-api</artifactId>
<version>1.0.1</version>
</dependency>
<!-- /Stax -->
<!-- REST services CXF -->
<dependency>
<groupId>org.apache.cxf</groupId>

View File

@ -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.Entity;
import org.apache.olingo.commons.api.edm.EdmPrimitiveTypeKind;
@ -410,7 +411,7 @@ public abstract class AbstractServices {
} else {
final ResWrap<JSONEntityImpl> jcont = mapper.readValue(IOUtils.toInputStream(changes, Constants.ENCODING),
new TypeReference<JSONEntityImpl>() {
});
});
entryChanges = dataBinder.toAtomEntity(jcont.getPayload());
}
@ -592,8 +593,8 @@ public abstract class AbstractServices {
} else {
final ResWrap<JSONEntityImpl> jcontainer =
mapper.readValue(IOUtils.toInputStream(entity, Constants.ENCODING),
new TypeReference<JSONEntityImpl>() {
});
new TypeReference<JSONEntityImpl>() {
});
entry = dataBinder.toAtomEntity(jcontainer.getPayload());
@ -620,7 +621,7 @@ public abstract class AbstractServices {
ResWrap<AtomEntityImpl> result = atomDeserializer.read(serialization, AtomEntityImpl.class);
result = new ResWrap<AtomEntityImpl>(
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);
@ -683,13 +684,13 @@ public abstract class AbstractServices {
replaceAll("\"Salary\":[0-9]*,", "\"Salary\":0,").
replaceAll("\"Title\":\".*\"", "\"Title\":\"[Sacked]\"").
replaceAll("\\<d:Salary m:type=\"Edm.Int32\"\\>.*\\</d:Salary\\>",
"<d:Salary m:type=\"Edm.Int32\">0</d:Salary>").
"<d:Salary m:type=\"Edm.Int32\">0</d:Salary>").
replaceAll("\\<d:Title\\>.*\\</d:Title\\>", "<d:Title>[Sacked]</d:Title>");
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) {
@ -741,9 +742,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("\\<d:Salary m:type=\"Edm.Int32\"\\>" + salaryMatcher.group(1) + "</d:Salary\\>",
"<d:Salary m:type=\"Edm.Int32\">" + newSalary + "</d:Salary>");
"<d:Salary m:type=\"Edm.Int32\">" + newSalary + "</d:Salary>");
}
FSManager.instance(version).putInMemory(IOUtils.toInputStream(newContent, Constants.ENCODING),
@ -892,7 +893,7 @@ public abstract class AbstractServices {
} else {
mapper.writeValue(
writer, new JSONFeedContainer(container.getContextURL(), container.getMetadataETag(),
dataBinder.toJSONEntitySet(container.getPayload())));
dataBinder.toJSONEntitySet(container.getPayload())));
}
return xml.createResponse(
@ -1134,6 +1135,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,
@ -1142,31 +1144,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<AtomEntityImpl> container = xml.readContainerEntity(Accept.ATOM,
fsManager.readFile(basePath + Constants.get(version, ConstantKey.ENTITY), Accept.ATOM));
final AtomEntityImpl 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.writeEntity(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);
}
@ -1241,6 +1274,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,
@ -1249,7 +1283,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);
}
/**
@ -1268,6 +1302,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,
@ -1276,7 +1311,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);
}
/**
@ -1295,6 +1330,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,
@ -1303,7 +1339,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
@ -1362,6 +1398,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,
@ -1373,7 +1410,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.toJSONEntitySet((AtomEntitySetImpl) container.getPayload())));
container.getMetadataETag(),
dataBinder.toJSONEntitySet((AtomEntitySetImpl) container.getPayload())));
}
} else {
final ResWrap<Entity> container =
@ -1532,8 +1569,8 @@ public abstract class AbstractServices {
mapper.writeValue(
writer,
new JSONEntryContainer(container.getContextURL(),
container.getMetadataETag(),
dataBinder.toJSONEntityType((AtomEntityImpl) container.getPayload())));
container.getMetadataETag(),
dataBinder.toJSONEntityType((AtomEntityImpl) container.getPayload())));
}
}
@ -1603,9 +1640,9 @@ public abstract class AbstractServices {
final ResWrap<AtomPropertyImpl> container = new ResWrap<AtomPropertyImpl>(
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);
@ -1613,9 +1650,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);

View File

@ -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;

View File

@ -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() {

View File

@ -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<String, Schema> 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<String, Schema>();
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);

View File

@ -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;
@ -576,22 +575,29 @@ public abstract class AbstractUtilities {
return IOUtils.toInputStream(writer.toString(), Constants.ENCODING);
}
public ResWrap<AtomEntityImpl> readContainerEntity(final Accept accept, final InputStream entity)
throws XMLStreamException, IOException {
final ResWrap<AtomEntityImpl> container;
if (accept == Accept.ATOM || accept == Accept.XML) {
container = atomDeserializer.read(entity, AtomEntityImpl.class);
} else {
final ResWrap<JSONEntityImpl> jcontainer =
mapper.readValue(entity, new TypeReference<JSONEntityImpl>() {
});
container = new ResWrap<AtomEntityImpl>(
jcontainer.getContextURL(),
jcontainer.getMetadataETag(),
dataBinder.toAtomEntity(jcontainer.getPayload()));
}
return container;
}
public AtomEntityImpl readEntity(final Accept accept, final InputStream entity)
throws XMLStreamException, IOException {
final AtomEntityImpl entry;
if (accept == Accept.ATOM || accept == Accept.XML) {
final ResWrap<AtomEntityImpl> container = atomDeserializer.read(entity, AtomEntityImpl.class);
entry = container.getPayload();
} else {
final ResWrap<JSONEntityImpl> container =
mapper.readValue(entity, new TypeReference<JSONEntityImpl>() {
});
entry = dataBinder.toAtomEntity(container.getPayload());
}
return entry;
return readContainerEntity(accept, entity).getPayload();
}
public InputStream writeEntity(final Accept accept, final ResWrap<AtomEntityImpl> container)
@ -624,6 +630,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<AtomPropertyImpl> container = atomDeserializer.read(property, AtomPropertyImpl.class);
atomProperty = container.getPayload();
} else {
final ResWrap<JSONPropertyImpl> jcontainer = mapper.readValue(property,
new TypeReference<JSONPropertyImpl>() {
});
atomProperty = dataBinder.toAtomProperty(jcontainer.getPayload(), entryType);
}
return atomProperty;
}
public InputStream writeProperty(final Accept accept, final ResWrap<AtomPropertyImpl> container)
throws XMLStreamException, IOException {
@ -835,29 +858,6 @@ public abstract class AbstractUtilities {
// --------------------------------
}
public void replaceProperty(
final String entitySetName,
final String entityId,
final InputStream changes,
final List<String> 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 AtomEntityImpl entry = readEntity(acceptType, stream);
final ResWrap<AtomEntityImpl> container = new ResWrap<AtomEntityImpl>((URI) null, null, entry);
fsManager.putInMemory(writeEntity(Accept.ATOM, container),
fsManager.getAbsolutePath(basePath + Constants.get(version, ConstantKey.ENTITY), Accept.ATOM));
}
public InputStream deleteProperty(
final String entitySetName,
final String entityId,

View File

@ -137,7 +137,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);
@ -182,7 +182,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);
}
@ -210,7 +210,7 @@ public abstract class Commons {
final StringBuilder builder = new StringBuilder();
builder.append("<?xml version=\"1.0\" encoding=\"utf-8\"?>");
builder.append("<links xmlns=\"" + Constants.get(version, ConstantKey.DATASERVICES_NS) + "\">");
builder.append("<links xmlns=\"").append(Constants.get(version, ConstantKey.DATASERVICES_NS)).append("\">");
for (String uri : link.getValue()) {
builder.append("<uri>");

View File

@ -43,6 +43,9 @@ public enum ConstantKey {
LINK,
DATASERVICES_NS,
METADATA_NS,
GEORSS_NS,
GML_NS,
EDM_NS,
METADATA,
SERVICES,
FEED,

View File

@ -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");

View File

@ -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 {

View File

@ -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 = "</" + CONTENT + ">";
@ -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);

View File

@ -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<Integer, XMLElement> linkInfo =
extractElement(reader, null,
Collections.<String>singletonList(Constants.get(version, ConstantKey.LINK)), startDepth, 2, 2);
Collections.<String>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.<String>singletonList(Constants.get(version, ConstantKey.INLINE)), 0, -1, -1).
extractElement(link.getContentReader(version), null,
Collections.<String>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.<String>singletonList(Constants.get(version, ConstantKey.LINK)),
Collections.<Map.Entry<String, String>>singletonList(
new AbstractMap.SimpleEntry<String, String>("rel", "edit")), false, 0, -1, -1);
new AbstractMap.SimpleEntry<String, String>("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.<String>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.<String>singletonList("entry"), 0, 1, 1).getValue();
writer.add(entryElement.getStart());
writer.add(entryElement.getContentReader());
writer.add(entryElement.getContentReader(version));
addAtomElement(
IOUtils.toInputStream(String.format("<content type=\"*/*\" src=\"%s/$value\" />", href)),
@ -544,14 +545,14 @@ public class XMLUtilities extends AbstractUtilities {
try {
final XMLElement entryElement =
extractElement(reader, writer, Collections.<String>singletonList(
Constants.get(version, ConstantKey.PROPERTIES)), 0, 2, 3).getValue();
Constants.get(version, ConstantKey.PROPERTIES)), 0, 2, 3).getValue();
addAtomElement(
IOUtils.toInputStream("<content type=\"application/xml\">"),
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.<String>singletonList("entry"), 0, 1, 1).getValue();
writer.add(entryElement.getStart());
writer.add(entryElement.getContentReader());
writer.add(entryElement.getContentReader(version));
addAtomElement(
IOUtils.toInputStream("<content type=\"application/xml\"/>"),
@ -742,7 +743,7 @@ public class XMLUtilities extends AbstractUtilities {
writer.add(feedElement.getStart());
addAtomElement(IOUtils.toInputStream(String.format("<m:count>%d</m:count>", 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.<String>singletonList("entry"),
0, 1, 1).getValue();
getEventReader(readEntity(uri.getKey(), uri.getValue(), Accept.ATOM).getValue()),
null,
Collections.<String>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<Integer, XMLElement> propertyElement =
extractElement(reader, null,
Collections.<String>singletonList(Constants.get(version, ConstantKey.PROPERTIES)), 0, 2, 3);
Collections.<String>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<Integer, XMLElement> linkElement =
extractElement(reader, null,
Collections.<String>singletonList(Constants.get(version, ConstantKey.LINK)), pos, 2, 2);
Collections.<String>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.<String>singletonList(Constants.get(version, ConstantKey.LINK)),
Collections.<Map.Entry<String, String>>singletonList(
new SimpleEntry<String, String>("title", linkName)), false, 0, -1, -1).getValue();
Collections.<String>singletonList(Constants.get(version, ConstantKey.LINK)),
Collections.<Map.Entry<String, String>>singletonList(
new SimpleEntry<String, String>("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<String> path) throws Exception {
final List<String> pathElements = new ArrayList<String>();
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<Integer, XMLElement> 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();

View File

@ -21,7 +21,7 @@
-->
<edmx:Edmx Version="1.0" xmlns:edmx="http://schemas.microsoft.com/ado/2007/06/edmx">
<edmx:DataServices m:DataServiceVersion="1.0" m:MaxDataServiceVersion="3.0" xmlns:m="http://schemas.microsoft.com/ado/2007/08/dataservices/metadata">
<Schema Namespace="Microsoft.Test.OData.Services.OpenTypesService" xmlns="http://schemas.microsoft.com/ado/2008/01/edm">
<Schema Namespace="Microsoft.Test.OData.Services.OpenTypesService" xmlns="http://schemas.microsoft.com/ado/2009/11/edm">
<ComplexType Name="ContactDetails">
<Property Name="FirstContacted" Type="Edm.Binary"/>
<Property Name="LastContacted" Type="Edm.DateTimeOffset" Nullable="false"/>

View File

@ -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;
@ -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<ODataProperty> retrieveReq =
client.getRetrieveRequestFactory().getPropertyRequest(uriBuilder.build());
retrieveReq.setFormat(format);
ODataRetrieveResponse<ODataProperty> 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());
}
}