Contained entity CRUD tests

This commit is contained in:
Francesco Chicchiriccò 2014-04-15 18:41:53 +02:00
parent 68f27d57a1
commit 4376658343
22 changed files with 384 additions and 196 deletions

View File

@ -20,19 +20,6 @@ package org.apache.olingo.fit;
import com.fasterxml.jackson.core.type.TypeReference; import com.fasterxml.jackson.core.type.TypeReference;
import com.fasterxml.jackson.databind.JsonNode; import com.fasterxml.jackson.databind.JsonNode;
import org.apache.olingo.commons.api.data.Feed;
import org.apache.olingo.commons.api.data.Link;
import org.apache.olingo.commons.api.data.Property;
import org.apache.olingo.commons.api.edm.constants.ODataServiceVersion;
import org.apache.olingo.commons.core.data.AtomFeedImpl;
import org.apache.olingo.commons.core.data.LinkImpl;
import org.apache.olingo.fit.metadata.Metadata;
import org.apache.olingo.fit.serializer.JsonFeedContainer;
import org.apache.olingo.fit.serializer.JsonEntryContainer;
import org.apache.olingo.fit.utils.ConstantKey;
import org.apache.olingo.fit.utils.Constants;
import org.apache.olingo.fit.utils.DataBinder;
import com.fasterxml.jackson.databind.ObjectMapper; import com.fasterxml.jackson.databind.ObjectMapper;
import java.io.ByteArrayInputStream; import java.io.ByteArrayInputStream;
import java.io.ByteArrayOutputStream; import java.io.ByteArrayOutputStream;
@ -83,6 +70,12 @@ import org.apache.olingo.commons.api.data.Container;
import org.apache.olingo.commons.api.data.Entry; import org.apache.olingo.commons.api.data.Entry;
import org.apache.olingo.commons.api.edm.EdmPrimitiveTypeKind; import org.apache.olingo.commons.api.edm.EdmPrimitiveTypeKind;
import org.apache.olingo.commons.api.format.ContentType; import org.apache.olingo.commons.api.format.ContentType;
import org.apache.olingo.commons.api.data.Feed;
import org.apache.olingo.commons.api.data.Link;
import org.apache.olingo.commons.api.data.Property;
import org.apache.olingo.commons.api.edm.constants.ODataServiceVersion;
import org.apache.olingo.commons.core.data.AtomFeedImpl;
import org.apache.olingo.commons.core.data.LinkImpl;
import org.apache.olingo.commons.core.data.AtomEntryImpl; import org.apache.olingo.commons.core.data.AtomEntryImpl;
import org.apache.olingo.commons.core.data.AtomPropertyImpl; import org.apache.olingo.commons.core.data.AtomPropertyImpl;
import org.apache.olingo.commons.core.data.AtomSerializer; import org.apache.olingo.commons.core.data.AtomSerializer;
@ -98,12 +91,17 @@ import org.apache.olingo.fit.methods.PATCH;
import org.apache.olingo.fit.serializer.FITAtomDeserializer; import org.apache.olingo.fit.serializer.FITAtomDeserializer;
import org.apache.olingo.fit.utils.Accept; import org.apache.olingo.fit.utils.Accept;
import org.apache.olingo.fit.utils.FSManager; import org.apache.olingo.fit.utils.FSManager;
import org.apache.olingo.fit.utils.Commons; import org.apache.olingo.fit.utils.Commons;
import org.apache.olingo.fit.utils.AbstractJSONUtilities; import org.apache.olingo.fit.utils.AbstractJSONUtilities;
import org.apache.olingo.fit.utils.AbstractUtilities; import org.apache.olingo.fit.utils.AbstractUtilities;
import org.apache.olingo.fit.utils.AbstractXMLUtilities; import org.apache.olingo.fit.utils.AbstractXMLUtilities;
import org.apache.olingo.fit.utils.LinkInfo; import org.apache.olingo.fit.utils.LinkInfo;
import org.apache.olingo.fit.metadata.Metadata;
import org.apache.olingo.fit.serializer.JsonFeedContainer;
import org.apache.olingo.fit.serializer.JsonEntryContainer;
import org.apache.olingo.fit.utils.ConstantKey;
import org.apache.olingo.fit.utils.Constants;
import org.apache.olingo.fit.utils.DataBinder;
import org.slf4j.Logger; import org.slf4j.Logger;
import org.slf4j.LoggerFactory; import org.slf4j.LoggerFactory;
@ -114,9 +112,9 @@ public abstract class AbstractServices {
*/ */
protected static final Logger LOG = LoggerFactory.getLogger(AbstractServices.class); protected static final Logger LOG = LoggerFactory.getLogger(AbstractServices.class);
private Pattern requestPatter = Pattern.compile("(.*) (http://.*) HTTP/.*"); private static final Pattern REQUEST_PATTERN = Pattern.compile("(.*) (http://.*) HTTP/.*");
private static final String boundary = "batch_243234_25424_ef_892u748"; private static final String BOUNDARY = "batch_243234_25424_ef_892u748";
protected final ODataServiceVersion version; protected final ODataServiceVersion version;
@ -193,10 +191,10 @@ public abstract class AbstractServices {
@POST @POST
@Path("/$batch") @Path("/$batch")
@Consumes("multipart/mixed") @Consumes("multipart/mixed")
@Produces("application/octet-stream; boundary=" + boundary) @Produces("application/octet-stream; boundary=" + BOUNDARY)
public Response batch(final @Multipart MultipartBody attachment) { public Response batch(final @Multipart MultipartBody attachment) {
try { try {
return xml.createBatchResponse(exploreMultipart(attachment.getAllAttachments(), boundary), boundary); return xml.createBatchResponse(exploreMultipart(attachment.getAllAttachments(), BOUNDARY), BOUNDARY);
} catch (IOException e) { } catch (IOException e) {
return xml.createFaultResponse(Accept.XML.toString(version), e); return xml.createFaultResponse(Accept.XML.toString(version), e);
} }
@ -209,7 +207,7 @@ public abstract class AbstractServices {
Header header = en.nextElement(); Header header = en.nextElement();
final String request = header.getName() + ":" + header.getValue(); final String request = header.getName() + ":" + header.getValue();
final Matcher matcher = requestPatter.matcher(request); final Matcher matcher = REQUEST_PATTERN.matcher(request);
if (matcher.find()) { if (matcher.find()) {
final MultivaluedMap<String, String> headers = new MultivaluedHashMap<String, String>(); final MultivaluedMap<String, String> headers = new MultivaluedHashMap<String, String>();
@ -343,7 +341,7 @@ public abstract class AbstractServices {
bos.write(Constants.CRLF); bos.write(Constants.CRLF);
for (Map.Entry<String, List<Object>> header : response.getHeaders().entrySet()) { for (Map.Entry<String, List<Object>> header : response.getHeaders().entrySet()) {
StringBuilder builder = new StringBuilder(); final StringBuilder builder = new StringBuilder();
for (Object value : header.getValue()) { for (Object value : header.getValue()) {
if (builder.length() > 0) { if (builder.length() > 0) {
builder.append(", "); builder.append(", ");
@ -593,7 +591,7 @@ public abstract class AbstractServices {
} else { } else {
final Container<JSONEntryImpl> jcontainer = final Container<JSONEntryImpl> jcontainer =
mapper.readValue(IOUtils.toInputStream(entity), new TypeReference<JSONEntryImpl>() { mapper.readValue(IOUtils.toInputStream(entity), new TypeReference<JSONEntryImpl>() {
}); });
entry = (new DataBinder(version)). entry = (new DataBinder(version)).
getAtomEntry(jcontainer.getObject()); getAtomEntry(jcontainer.getObject());
@ -666,13 +664,13 @@ public abstract class AbstractServices {
replaceAll("\"Salary\":[0-9]*,", "\"Salary\":0,"). replaceAll("\"Salary\":[0-9]*,", "\"Salary\":0,").
replaceAll("\"Title\":\".*\"", "\"Title\":\"[Sacked]\""). replaceAll("\"Title\":\".*\"", "\"Title\":\"[Sacked]\"").
replaceAll("\\<d:Salary m:type=\"Edm.Int32\"\\>.*\\</d:Salary\\>", 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>"); replaceAll("\\<d:Title\\>.*\\</d:Title\\>", "<d:Title>[Sacked]</d:Title>");
final FSManager fsManager = FSManager.instance(version); final FSManager fsManager = FSManager.instance(version);
fsManager.putInMemory(IOUtils.toInputStream(newContent, "UTF-8"), fsManager.putInMemory(IOUtils.toInputStream(newContent, "UTF-8"),
fsManager.getAbsolutePath(Commons.getEntityBasePath("Person", entityId) + Constants.get(version, fsManager.getAbsolutePath(Commons.getEntityBasePath("Person", entityId) + Constants.get(version,
ConstantKey.ENTITY), utils.getKey())); ConstantKey.ENTITY), utils.getKey()));
return utils.getValue().createResponse(null, null, utils.getKey(), Response.Status.NO_CONTENT); return utils.getValue().createResponse(null, null, utils.getKey(), Response.Status.NO_CONTENT);
} catch (Exception e) { } catch (Exception e) {
@ -724,9 +722,9 @@ public abstract class AbstractServices {
final Long newSalary = Long.valueOf(salaryMatcher.group(1)) + n; final Long newSalary = Long.valueOf(salaryMatcher.group(1)) + n;
newContent = newContent. newContent = newContent.
replaceAll("\"Salary\":" + salaryMatcher.group(1) + ",", replaceAll("\"Salary\":" + salaryMatcher.group(1) + ",",
"\"Salary\":" + newSalary + ","). "\"Salary\":" + newSalary + ",").
replaceAll("\\<d:Salary m:type=\"Edm.Int32\"\\>" + salaryMatcher.group(1) + "</d:Salary\\>", 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, "UTF-8"), FSManager.instance(version).putInMemory(IOUtils.toInputStream(newContent, "UTF-8"),
@ -858,7 +856,7 @@ public abstract class AbstractServices {
mapper.writeValue( mapper.writeValue(
writer, new JsonFeedContainer<JSONFeedImpl>(container.getContextURL(), container.getMetadataETag(), writer, new JsonFeedContainer<JSONFeedImpl>(container.getContextURL(), container.getMetadataETag(),
new DataBinder(version).getJsonFeed(container.getObject()))); new DataBinder(version).getJsonFeed(container.getObject())));
} }
return xml.createResponse(new ByteArrayInputStream(content.toByteArray()), return xml.createResponse(new ByteArrayInputStream(content.toByteArray()),
@ -1040,7 +1038,7 @@ public abstract class AbstractServices {
final ObjectMapper mapper = Commons.getJsonMapper(version); final ObjectMapper mapper = Commons.getJsonMapper(version);
mapper.writeValue( mapper.writeValue(
writer, new JsonEntryContainer<JSONEntryImpl>(container.getContextURL(), container.getMetadataETag(), writer, new JsonEntryContainer<JSONEntryImpl>(container.getContextURL(), container.getMetadataETag(),
(new DataBinder(version)).getJsonEntry((AtomEntryImpl) container.getObject()))); (new DataBinder(version)).getJsonEntry((AtomEntryImpl) container.getObject())));
} }
return xml.createResponse(new ByteArrayInputStream(content.toByteArray()), return xml.createResponse(new ByteArrayInputStream(content.toByteArray()),
@ -1469,27 +1467,50 @@ public abstract class AbstractServices {
private Response navigateEntity( private Response navigateEntity(
final Accept acceptType, final Accept acceptType,
String entitySetName, final String entitySetName,
String entityId, final String entityId,
String path) throws Exception { final String path) throws Exception {
final String basePath = Commons.getEntityBasePath(entitySetName, entityId);
final LinkInfo linkInfo = xml.readLinks(entitySetName, entityId, path, Accept.XML);
final Map.Entry<String, List<String>> links = xml.extractLinkURIs(linkInfo.getLinks());
final LinkInfo linkInfo;
InputStream stream; InputStream stream;
if (version.compareTo(ODataServiceVersion.V30) <= 0) {
linkInfo = xml.readLinks(entitySetName, entityId, path, Accept.XML);
final Map.Entry<String, List<String>> links = xml.extractLinkURIs(linkInfo.getLinks());
switch (acceptType) { switch (acceptType) {
case JSON: case JSON:
case JSON_FULLMETA: case JSON_FULLMETA:
case JSON_NOMETA: case JSON_NOMETA:
stream = json.readEntities(links.getValue(), path, links.getKey(), linkInfo.isFeed()); stream = json.readEntities(links.getValue(), path, links.getKey(), linkInfo.isFeed());
stream = json.wrapJsonEntities(stream); stream = json.wrapJsonEntities(stream);
break; break;
default: default:
stream = xml.readEntities(links.getValue(), path, links.getKey(), linkInfo.isFeed()); stream = xml.readEntities(links.getValue(), path, links.getKey(), linkInfo.isFeed());
}
} else {
linkInfo = xml.readLinks(entitySetName, entityId, path, Accept.ATOM);
if (acceptType == Accept.ATOM) {
stream = linkInfo.getLinks();
} else {
final FITAtomDeserializer atomDeserializer = Commons.getAtomDeserializer(version);
final DataBinder dataBinder = new DataBinder(version);
final ObjectMapper mapper = Commons.getJsonMapper(version);
final ByteArrayOutputStream baos = new ByteArrayOutputStream();
final Object object;
if (linkInfo.isFeed()) {
final Container<AtomFeedImpl> container = atomDeserializer.read(linkInfo.getLinks(), AtomFeedImpl.class);
object = dataBinder.getJsonFeed(container.getObject());
} else {
final Container<AtomEntryImpl> container = atomDeserializer.read(linkInfo.getLinks(), AtomEntryImpl.class);
object = dataBinder.getJsonEntry(container.getObject());
}
mapper.writeValue(baos, object);
stream = new ByteArrayInputStream(baos.toByteArray());
}
} }
final String basePath = Commons.getEntityBasePath(entitySetName, entityId);
return xml.createResponse(stream, Commons.getETag(basePath, version), acceptType); return xml.createResponse(stream, Commons.getETag(basePath, version), acceptType);
} }

View File

@ -223,7 +223,7 @@ public class V4Services extends AbstractServices {
final ObjectMapper mapper = Commons.getJsonMapper(version); final ObjectMapper mapper = Commons.getJsonMapper(version);
final DataBinder dataBinder = new DataBinder(version); final DataBinder dataBinder = new DataBinder(version);
Container<JSONEntryImpl> jsonContainer = mapper.readValue(IOUtils.toInputStream(changes), final Container<JSONEntryImpl> jsonContainer = mapper.readValue(IOUtils.toInputStream(changes),
new TypeReference<JSONEntryImpl>() { new TypeReference<JSONEntryImpl>() {
}); });
jsonContainer.getObject().setType(typeInfo.getFullQualifiedName().toString()); jsonContainer.getObject().setType(typeInfo.getFullQualifiedName().toString());
@ -243,7 +243,6 @@ public class V4Services extends AbstractServices {
return xml.createResponse(null, null, acceptType, Response.Status.NO_CONTENT); return xml.createResponse(null, null, acceptType, Response.Status.NO_CONTENT);
} catch (Exception e) { } catch (Exception e) {
e.printStackTrace();
return xml.createFaultResponse(accept, e); return xml.createFaultResponse(accept, e);
} }
} }

View File

@ -359,7 +359,7 @@ public abstract class AbstractJSONUtilities extends AbstractUtilities {
node.set(Constants.get(version, ConstantKey.JSON_NEXTLINK_NAME), new TextNode(next)); node.set(Constants.get(version, ConstantKey.JSON_NEXTLINK_NAME), new TextNode(next));
} }
return IOUtils.toInputStream(node.toString(), "UTf-8"); return IOUtils.toInputStream(node.toString(), "UTF-8");
} }
@Override @Override

View File

@ -365,7 +365,7 @@ public abstract class AbstractUtilities {
fsManager.putInMemory( fsManager.putInMemory(
IOUtils.toInputStream(entity), fsManager.getAbsolutePath(path + Constants.get(version, ConstantKey.ENTITY), IOUtils.toInputStream(entity), fsManager.getAbsolutePath(path + Constants.get(version, ConstantKey.ENTITY),
Accept.JSON_FULLMETA)); Accept.JSON_FULLMETA));
// ----------------------------------------- // -----------------------------------------
return readEntity(entitySetName, entityKey, getDefaultFormat()).getValue(); return readEntity(entitySetName, entityKey, getDefaultFormat()).getValue();
@ -415,7 +415,6 @@ public abstract class AbstractUtilities {
} }
public Response createBatchResponse(final InputStream stream, final String boundary) { public Response createBatchResponse(final InputStream stream, final String boundary) {
final Response.ResponseBuilder builder = Response.accepted(stream); final Response.ResponseBuilder builder = Response.accepted(stream);
builder.header(Constants.get(version, ConstantKey.ODATA_SERVICE_VERSION), version.toString() + ";"); builder.header(Constants.get(version, ConstantKey.ODATA_SERVICE_VERSION), version.toString() + ";");
return builder.build(); return builder.build();
@ -423,6 +422,7 @@ public abstract class AbstractUtilities {
public Response createResponse( public Response createResponse(
final InputStream entity, final String etag, final Accept accept, final Response.Status status) { final InputStream entity, final String etag, final Accept accept, final Response.Status status) {
final Response.ResponseBuilder builder = Response.ok(); final Response.ResponseBuilder builder = Response.ok();
if (version.compareTo(ODataServiceVersion.V30) <= 0) { if (version.compareTo(ODataServiceVersion.V30) <= 0) {
builder.header(Constants.get(version, ConstantKey.ODATA_SERVICE_VERSION), version.toString() + ";"); builder.header(Constants.get(version, ConstantKey.ODATA_SERVICE_VERSION), version.toString() + ";");
@ -444,8 +444,8 @@ public abstract class AbstractUtilities {
try { try {
final InputStream toBeStreamedBack; final InputStream toBeStreamedBack;
if (accept != null && (Accept.JSON == accept || Accept.JSON_NOMETA == accept)) { if (Accept.JSON == accept || Accept.JSON_NOMETA == accept) {
toBeStreamedBack = Commons.changeFormat(entity, accept); toBeStreamedBack = Commons.changeFormat(entity, version, accept);
} else { } else {
toBeStreamedBack = entity; toBeStreamedBack = entity;
} }
@ -685,10 +685,10 @@ public abstract class AbstractUtilities {
} }
public String getLinksBasePath(final String entitySetName, final String entityId) { public String getLinksBasePath(final String entitySetName, final String entityId) {
return entitySetName + File.separatorChar + Commons.getEntityKey(entityId) + File.separatorChar return entitySetName + File.separatorChar + Commons.getEntityKey(entityId) + File.separatorChar
+ Constants.get(version, ConstantKey.LINKS_FILE_PATH) + File.separatorChar; + Constants.get(version, ConstantKey.LINKS_FILE_PATH) + File.separatorChar;
} }
/** /**
* Retrieves entity links about the given link name. * Retrieves entity links about the given link name.
* *

View File

@ -251,7 +251,7 @@ public abstract class Commons {
return IOUtils.toInputStream(links.toString(), "UTf-8"); return IOUtils.toInputStream(links.toString(), "UTf-8");
} }
public static InputStream changeFormat(final InputStream is, final Accept target) { public static InputStream changeFormat(final InputStream is, final ODataServiceVersion version, final Accept target) {
final ByteArrayOutputStream bos = new ByteArrayOutputStream(); final ByteArrayOutputStream bos = new ByteArrayOutputStream();
try { try {
@ -260,7 +260,7 @@ public abstract class Commons {
final ObjectMapper mapper = new ObjectMapper(); final ObjectMapper mapper = new ObjectMapper();
final JsonNode node = final JsonNode node =
changeFormat((ObjectNode) mapper.readTree(new ByteArrayInputStream(bos.toByteArray())), target); changeFormat((ObjectNode) mapper.readTree(new ByteArrayInputStream(bos.toByteArray())), version, target);
return IOUtils.toInputStream(node.toString(), "UTF-8"); return IOUtils.toInputStream(node.toString(), "UTF-8");
} catch (Exception e) { } catch (Exception e) {
@ -272,30 +272,35 @@ public abstract class Commons {
} }
@SuppressWarnings("fallthrough") @SuppressWarnings("fallthrough")
public static JsonNode changeFormat(final ObjectNode node, final Accept target) { public static JsonNode changeFormat(final ObjectNode node, final ODataServiceVersion version, final Accept target) {
final List<String> toBeRemoved = new ArrayList<String>(); final List<String> toBeRemoved = new ArrayList<String>();
final Map<String, JsonNode> toBeReplaced = new HashMap<String, JsonNode>();
switch (target) { switch (target) {
case JSON_NOMETA: case JSON_NOMETA:
// nometa + minimal // nometa + minimal
toBeRemoved.add(Constants.get(ConstantKey.JSON_ODATAMETADATA_NAME)); toBeRemoved.add(Constants.get(version, ConstantKey.JSON_ODATAMETADATA_NAME));
case JSON: case JSON:
// minimal // minimal
toBeRemoved.add(Constants.get(ConstantKey.JSON_EDITLINK_NAME)); toBeRemoved.add(Constants.get(version, ConstantKey.JSON_EDITLINK_NAME));
toBeRemoved.add(Constants.get(ConstantKey.JSON_ID_NAME)); toBeRemoved.add(Constants.get(version, ConstantKey.JSON_ID_NAME));
toBeRemoved.add(Constants.get(ConstantKey.JSON_TYPE_NAME)); toBeRemoved.add(Constants.get(version, ConstantKey.JSON_TYPE_NAME));
final Iterator<Map.Entry<String, JsonNode>> fields = node.fields(); final Iterator<Map.Entry<String, JsonNode>> fields = node.fields();
while (fields.hasNext()) { while (fields.hasNext()) {
final Map.Entry<String, JsonNode> field = fields.next(); final Map.Entry<String, JsonNode> field = fields.next();
if (field.getKey().endsWith(Constants.get(ConstantKey.JSON_MEDIA_SUFFIX)) if (field.getKey().endsWith(Constants.get(version, ConstantKey.JSON_MEDIA_SUFFIX))
|| field.getKey().endsWith(Constants.get(ConstantKey.JSON_NAVIGATION_SUFFIX)) || field.getKey().endsWith(Constants.get(version, ConstantKey.JSON_NAVIGATION_SUFFIX))
|| field.getKey().endsWith(Constants.get(ConstantKey.JSON_TYPE_SUFFIX))) { || field.getKey().endsWith(Constants.get(version, ConstantKey.JSON_TYPE_SUFFIX))) {
toBeRemoved.add(field.getKey()); toBeRemoved.add(field.getKey());
} else if (field.getValue().isObject()) { } else if (field.getValue().isObject()) {
toBeReplaced.put(field.getKey(), changeFormat((ObjectNode) field.getValue(), target)); changeFormat((ObjectNode) field.getValue(), version, target);
} else if (field.getValue().isArray()) {
for (final Iterator<JsonNode> subItor = field.getValue().elements(); subItor.hasNext();) {
final JsonNode subNode = subItor.next();
if (subNode.isObject()) {
changeFormat((ObjectNode) subNode, version, target);
}
}
} }
} }
case JSON_FULLMETA: case JSON_FULLMETA:
@ -305,14 +310,7 @@ public abstract class Commons {
default: default:
throw new UnsupportedOperationException(target.name()); throw new UnsupportedOperationException(target.name());
} }
node.remove(toBeRemoved);
for (String field : toBeRemoved) {
node.remove(field);
}
for (Map.Entry<String, JsonNode> field : toBeReplaced.entrySet()) {
node.replace(field.getKey(), field.getValue());
}
return node; return node;
} }

View File

@ -41,6 +41,8 @@ public class Constants {
// ----------------------------- // -----------------------------
// V4 only // V4 only
// ----------------------------- // -----------------------------
v4constants.put(ConstantKey.JSON_ID_NAME, "@odata.id");
v4constants.put(ConstantKey.JSON_TYPE_NAME, "@odata.type");
v4constants.put(ConstantKey.JSON_NAVIGATION_SUFFIX, "@odata.navigationLink"); v4constants.put(ConstantKey.JSON_NAVIGATION_SUFFIX, "@odata.navigationLink");
v4constants.put(ConstantKey.DATASERVICES_NS, "http://docs.oasis-open.org/odata/ns/dataservices"); 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.METADATA_NS, "http://docs.oasis-open.org/odata/ns/metadata");

View File

@ -203,20 +203,20 @@ public class DataBinder {
public JSONPropertyImpl getJsonProperty(final AtomPropertyImpl atomproperty) { public JSONPropertyImpl getJsonProperty(final AtomPropertyImpl atomproperty) {
final JSONPropertyImpl jsonproperty = new JSONPropertyImpl(); final JSONPropertyImpl jsonproperty = new JSONPropertyImpl();
BeanUtils.copyProperties(atomproperty, jsonproperty, "value"); BeanUtils.copyProperties(atomproperty, jsonproperty, "value");
if (atomproperty.getValue() instanceof ComplexValueImpl) { if (atomproperty.getValue().isComplex()) {
final ComplexValueImpl complex = new ComplexValueImpl(); final ComplexValueImpl complex = new ComplexValueImpl();
jsonproperty.setValue(complex); jsonproperty.setValue(complex);
for (Property field : atomproperty.getValue().asComplex().get()) { for (Property field : atomproperty.getValue().asComplex().get()) {
complex.get().add(getJsonProperty((AtomPropertyImpl) field)); complex.get().add(getJsonProperty((AtomPropertyImpl) field));
} }
} else if (atomproperty.getValue() instanceof CollectionValueImpl) { } else if (atomproperty.getValue().isCollection()) {
final CollectionValueImpl collection = new CollectionValueImpl(); final CollectionValueImpl collection = new CollectionValueImpl();
jsonproperty.setValue(collection); jsonproperty.setValue(collection);
for (Value element : atomproperty.getValue().asCollection().get()) { for (Value element : atomproperty.getValue().asCollection().get()) {
if (element instanceof ComplexValueImpl) { if (element.isComplex()) {
final ComplexValueImpl complex = new ComplexValueImpl(); final ComplexValueImpl complex = new ComplexValueImpl();
collection.get().add(complex); collection.get().add(complex);

View File

@ -21,9 +21,9 @@
--> -->
<entry xml:base="http://odatae2etest.azurewebsites.net/javatest/DefaultService/" xmlns="http://www.w3.org/2005/Atom" xmlns:d="http://docs.oasis-open.org/odata/ns/data" xmlns:m="http://docs.oasis-open.org/odata/ns/metadata" xmlns:georss="http://www.georss.org/georss" xmlns:gml="http://www.opengis.net/gml" m:context="http://odatae2etest.azurewebsites.net/javatest/DefaultService/$metadata#Accounts(101)/MyPaymentInstruments/$entity"> <entry xml:base="http://odatae2etest.azurewebsites.net/javatest/DefaultService/" xmlns="http://www.w3.org/2005/Atom" xmlns:d="http://docs.oasis-open.org/odata/ns/data" xmlns:m="http://docs.oasis-open.org/odata/ns/metadata" xmlns:georss="http://www.georss.org/georss" xmlns:gml="http://www.opengis.net/gml" m:context="http://odatae2etest.azurewebsites.net/javatest/DefaultService/$metadata#Accounts(101)/MyPaymentInstruments/$entity">
<category term="#Microsoft.Test.OData.Services.ODataWCFService.PaymentInstrument" scheme="http://docs.oasis-open.org/odata/ns/scheme"/> <category term="#Microsoft.Test.OData.Services.ODataWCFService.PaymentInstrument" scheme="http://docs.oasis-open.org/odata/ns/scheme"/>
<link rel="http://docs.oasis-open.org/odata/ns/related/TheStoredPI" type="application/atom+xml;type=entry" title="TheStoredPI" href="potato"/> <link rel="http://docs.oasis-open.org/odata/ns/related/TheStoredPI" type="application/atom+xml;type=entry" title="TheStoredPI" href="http://odatae2etest.azurewebsites.net/javatest/DefaultService/Accounts(101)/MyPaymentInstruments(101901)/TheStoredPI"/>
<link rel="http://docs.oasis-open.org/odata/ns/related/BillingStatements" type="application/atom+xml;type=feed" title="BillingStatements" href="potato"/> <link rel="http://docs.oasis-open.org/odata/ns/related/BillingStatements" type="application/atom+xml;type=feed" title="BillingStatements" href="http://odatae2etest.azurewebsites.net/javatest/DefaultService/Accounts(101)/MyPaymentInstruments(101901)/BillingStatements"/>
<link rel="http://docs.oasis-open.org/odata/ns/related/BackupStoredPI" type="application/atom+xml;type=entry" title="BackupStoredPI" href="potato"/> <link rel="http://docs.oasis-open.org/odata/ns/related/BackupStoredPI" type="application/atom+xml;type=entry" title="BackupStoredPI" href="http://odatae2etest.azurewebsites.net/javatest/DefaultService/Accounts(101)/MyPaymentInstruments(101901)/BackupStoredPI"/>
<id/> <id/>
<title/> <title/>
<updated>2014-04-14T12:47:37Z</updated> <updated>2014-04-14T12:47:37Z</updated>

View File

@ -25,9 +25,9 @@
<updated>2014-04-14T12:45:33Z</updated> <updated>2014-04-14T12:45:33Z</updated>
<entry> <entry>
<category term="#Microsoft.Test.OData.Services.ODataWCFService.PaymentInstrument" scheme="http://docs.oasis-open.org/odata/ns/scheme"/> <category term="#Microsoft.Test.OData.Services.ODataWCFService.PaymentInstrument" scheme="http://docs.oasis-open.org/odata/ns/scheme"/>
<link rel="http://docs.oasis-open.org/odata/ns/related/TheStoredPI" type="application/atom+xml;type=entry" title="TheStoredPI" href="potato"/> <link rel="http://docs.oasis-open.org/odata/ns/related/TheStoredPI" type="application/atom+xml;type=entry" title="TheStoredPI" href="http://odatae2etest.azurewebsites.net/javatest/DefaultService/Accounts(101)/MyPaymentInstruments(101901)/TheStoredPI"/>
<link rel="http://docs.oasis-open.org/odata/ns/related/BillingStatements" type="application/atom+xml;type=feed" title="BillingStatements" href="potato"/> <link rel="http://docs.oasis-open.org/odata/ns/related/BillingStatements" type="application/atom+xml;type=feed" title="BillingStatements" href="http://odatae2etest.azurewebsites.net/javatest/DefaultService/Accounts(101)/MyPaymentInstruments(101901)/BillingStatements"/>
<link rel="http://docs.oasis-open.org/odata/ns/related/BackupStoredPI" type="application/atom+xml;type=entry" title="BackupStoredPI" href="potato"/> <link rel="http://docs.oasis-open.org/odata/ns/related/BackupStoredPI" type="application/atom+xml;type=entry" title="BackupStoredPI" href="http://odatae2etest.azurewebsites.net/javatest/DefaultService/Accounts(101)/MyPaymentInstruments(101901)/BackupStoredPI"/>
<id/> <id/>
<title/> <title/>
<updated>2014-04-14T12:45:33Z</updated> <updated>2014-04-14T12:45:33Z</updated>
@ -44,10 +44,10 @@
</entry> </entry>
<entry> <entry>
<category term="#Microsoft.Test.OData.Services.ODataWCFService.CreditCardPI" scheme="http://docs.oasis-open.org/odata/ns/scheme"/> <category term="#Microsoft.Test.OData.Services.ODataWCFService.CreditCardPI" scheme="http://docs.oasis-open.org/odata/ns/scheme"/>
<link rel="http://docs.oasis-open.org/odata/ns/related/TheStoredPI" type="application/atom+xml;type=entry" title="TheStoredPI" href="potato"/> <link rel="http://docs.oasis-open.org/odata/ns/related/TheStoredPI" type="application/atom+xml;type=entry" title="TheStoredPI" href="http://odatae2etest.azurewebsites.net/javatest/DefaultService/Accounts(101)/MyPaymentInstruments(101902)/Microsoft.Test.OData.Services.ODataWCFService.CreditCardPI/TheStoredPI"/>
<link rel="http://docs.oasis-open.org/odata/ns/related/BillingStatements" type="application/atom+xml;type=feed" title="BillingStatements" href="potato"/> <link rel="http://docs.oasis-open.org/odata/ns/related/BillingStatements" type="application/atom+xml;type=feed" title="BillingStatements" href="http://odatae2etest.azurewebsites.net/javatest/DefaultService/Accounts(101)/MyPaymentInstruments(101902)/Microsoft.Test.OData.Services.ODataWCFService.CreditCardPI/BillingStatements"/>
<link rel="http://docs.oasis-open.org/odata/ns/related/BackupStoredPI" type="application/atom+xml;type=entry" title="BackupStoredPI" href="potato"/> <link rel="http://docs.oasis-open.org/odata/ns/related/BackupStoredPI" type="application/atom+xml;type=entry" title="BackupStoredPI" href="http://odatae2etest.azurewebsites.net/javatest/DefaultService/Accounts(101)/MyPaymentInstruments(101902)/Microsoft.Test.OData.Services.ODataWCFService.CreditCardPI/BackupStoredPI"/>
<link rel="http://docs.oasis-open.org/odata/ns/related/CreditRecords" type="application/atom+xml;type=feed" title="CreditRecords" href="potato"/> <link rel="http://docs.oasis-open.org/odata/ns/related/CreditRecords" type="application/atom+xml;type=feed" title="CreditRecords" href="http://odatae2etest.azurewebsites.net/javatest/DefaultService/Accounts(101)/MyPaymentInstruments(101902)/Microsoft.Test.OData.Services.ODataWCFService.CreditCardPI/CreditRecords"/>
<id/> <id/>
<title/> <title/>
<updated>2014-04-14T12:45:33Z</updated> <updated>2014-04-14T12:45:33Z</updated>
@ -69,10 +69,10 @@
</entry> </entry>
<entry> <entry>
<category term="#Microsoft.Test.OData.Services.ODataWCFService.CreditCardPI" scheme="http://docs.oasis-open.org/odata/ns/scheme"/> <category term="#Microsoft.Test.OData.Services.ODataWCFService.CreditCardPI" scheme="http://docs.oasis-open.org/odata/ns/scheme"/>
<link rel="http://docs.oasis-open.org/odata/ns/related/TheStoredPI" type="application/atom+xml;type=entry" title="TheStoredPI" href="potato"/> <link rel="http://docs.oasis-open.org/odata/ns/related/TheStoredPI" type="application/atom+xml;type=entry" title="TheStoredPI" href="http://odatae2etest.azurewebsites.net/javatest/DefaultService/Accounts(101)/MyPaymentInstruments(101903)/Microsoft.Test.OData.Services.ODataWCFService.CreditCardPI/TheStoredPI"/>
<link rel="http://docs.oasis-open.org/odata/ns/related/BillingStatements" type="application/atom+xml;type=feed" title="BillingStatements" href="potato"/> <link rel="http://docs.oasis-open.org/odata/ns/related/BillingStatements" type="application/atom+xml;type=feed" title="BillingStatements" href="http://odatae2etest.azurewebsites.net/javatest/DefaultService/Accounts(101)/MyPaymentInstruments(101903)/Microsoft.Test.OData.Services.ODataWCFService.CreditCardPI/BillingStatements"/>
<link rel="http://docs.oasis-open.org/odata/ns/related/BackupStoredPI" type="application/atom+xml;type=entry" title="BackupStoredPI" href="potato"/> <link rel="http://docs.oasis-open.org/odata/ns/related/BackupStoredPI" type="application/atom+xml;type=entry" title="BackupStoredPI" href="http://odatae2etest.azurewebsites.net/javatest/DefaultService/Accounts(101)/MyPaymentInstruments(101903)/Microsoft.Test.OData.Services.ODataWCFService.CreditCardPI/BackupStoredPI"/>
<link rel="http://docs.oasis-open.org/odata/ns/related/CreditRecords" type="application/atom+xml;type=feed" title="CreditRecords" href="potato"/> <link rel="http://docs.oasis-open.org/odata/ns/related/CreditRecords" type="application/atom+xml;type=feed" title="CreditRecords" href="http://odatae2etest.azurewebsites.net/javatest/DefaultService/Accounts(101)/MyPaymentInstruments(101903)/Microsoft.Test.OData.Services.ODataWCFService.CreditCardPI/CreditRecords"/>
<id/> <id/>
<title/> <title/>
<updated>2014-04-14T12:45:33Z</updated> <updated>2014-04-14T12:45:33Z</updated>

View File

@ -58,6 +58,10 @@
<groupId>xmlunit</groupId> <groupId>xmlunit</groupId>
<artifactId>xmlunit</artifactId> <artifactId>xmlunit</artifactId>
</dependency> </dependency>
<dependency>
<groupId>org.slf4j</groupId>
<artifactId>slf4j-simple</artifactId>
</dependency>
<dependency> <dependency>
<groupId>org.apache.olingo</groupId> <groupId>org.apache.olingo</groupId>
@ -70,10 +74,27 @@
<build> <build>
<plugins> <plugins>
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-surefire-plugin</artifactId>
<inherited>true</inherited>
<configuration>
<systemPropertyVariables>
<propertyName>org.slf4j.simpleLogger.defaultLogLevel</propertyName>
<org.slf4j.simpleLogger.defaultLogLevel>ERROR</org.slf4j.simpleLogger.defaultLogLevel>
</systemPropertyVariables>
</configuration>
</plugin>
<plugin> <plugin>
<groupId>org.apache.maven.plugins</groupId> <groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-failsafe-plugin</artifactId> <artifactId>maven-failsafe-plugin</artifactId>
<inherited>true</inherited> <inherited>true</inherited>
<configuration>
<systemPropertyVariables>
<propertyName>org.slf4j.simpleLogger.defaultLogLevel</propertyName>
<org.slf4j.simpleLogger.defaultLogLevel>DEBUG</org.slf4j.simpleLogger.defaultLogLevel>
</systemPropertyVariables>
</configuration>
</plugin> </plugin>
<plugin> <plugin>

View File

@ -0,0 +1,98 @@
/*
* Licensed to the Apache Software Foundation (ASF) under one
* or more contributor license agreements. See the NOTICE file
* distributed with this work for additional information
* regarding copyright ownership. The ASF licenses this file
* to you under the Apache License, Version 2.0 (the
* "License"); you may not use this file except in compliance
* with the License. You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing,
* software distributed under the License is distributed on an
* "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
* KIND, either express or implied. See the License for the
* specific language governing permissions and limitations
* under the License.
*/
package org.apache.olingo.client.core.it;
import java.io.IOException;
import java.io.InputStream;
import java.io.StringWriter;
import org.apache.commons.io.IOUtils;
import org.apache.olingo.client.api.CommonODataClient;
import org.apache.olingo.commons.api.data.Entry;
import org.apache.olingo.commons.api.data.Feed;
import org.apache.olingo.commons.api.domain.CommonODataEntity;
import org.apache.olingo.commons.api.domain.CommonODataProperty;
import org.apache.olingo.commons.api.domain.ODataValue;
import org.apache.olingo.commons.core.data.AtomEntryImpl;
import org.apache.olingo.commons.core.data.JSONEntryImpl;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
public abstract class AbstractBaseTestITCase {
/**
* Logger.
*/
protected static final Logger LOG = LoggerFactory.getLogger(AbstractBaseTestITCase.class);
@SuppressWarnings("rawtypes")
protected abstract CommonODataClient getClient();
protected void debugEntry(final Entry entry, final String message) {
if (LOG.isDebugEnabled()) {
final StringWriter writer = new StringWriter();
getClient().getSerializer().entry(entry, writer);
writer.flush();
LOG.debug(message + "\n{}", writer.toString());
}
}
protected void debugFeed(final Feed feed, final String message) {
if (LOG.isDebugEnabled()) {
final StringWriter writer = new StringWriter();
getClient().getSerializer().feed(feed, writer);
writer.flush();
LOG.debug(message + "\n{}", writer.toString());
}
}
protected void debugODataProperty(final CommonODataProperty property, final String message) {
LOG.debug(message + "\n{}", property.toString());
}
protected void debugODataValue(final ODataValue value, final String message) {
LOG.debug(message + "\n{}", value.toString());
}
protected void debugODataEntity(final CommonODataEntity entity, final String message) {
if (LOG.isDebugEnabled()) {
StringWriter writer = new StringWriter();
getClient().getSerializer().entry(getClient().getBinder().getEntry(entity, AtomEntryImpl.class), writer);
writer.flush();
LOG.debug(message + " (Atom)\n{}", writer.toString());
writer = new StringWriter();
getClient().getSerializer().entry(getClient().getBinder().getEntry(entity, JSONEntryImpl.class), writer);
writer.flush();
LOG.debug(message + " (JSON)\n{}", writer.toString());
}
}
protected void debugInputStream(final InputStream input, final String message) {
if (LOG.isDebugEnabled()) {
try {
LOG.debug(message + "\n{}", IOUtils.toString(input));
} catch (IOException e) {
LOG.error("Error writing stream", e);
} finally {
IOUtils.closeQuietly(input);
}
}
}
}

View File

@ -22,6 +22,7 @@ import org.apache.olingo.client.api.CommonODataClient;
public abstract class AbstractMetadataTestITCase { public abstract class AbstractMetadataTestITCase {
@SuppressWarnings("rawtypes")
protected abstract CommonODataClient getClient(); protected abstract CommonODataClient getClient();
protected String getTestServiceRoot() { protected String getTestServiceRoot() {

View File

@ -26,8 +26,6 @@ import static org.junit.Assert.assertTrue;
import static org.junit.Assert.fail; import static org.junit.Assert.fail;
import java.io.IOException; import java.io.IOException;
import java.io.InputStream;
import java.io.StringWriter;
import java.net.URI; import java.net.URI;
import java.util.ArrayList; import java.util.ArrayList;
import java.util.Collection; import java.util.Collection;
@ -36,7 +34,6 @@ import java.util.HashSet;
import java.util.List; import java.util.List;
import java.util.Map; import java.util.Map;
import java.util.Set; import java.util.Set;
import org.apache.commons.io.IOUtils;
import org.apache.commons.lang3.StringUtils; import org.apache.commons.lang3.StringUtils;
import org.apache.olingo.client.api.communication.ODataClientErrorException; import org.apache.olingo.client.api.communication.ODataClientErrorException;
import org.apache.olingo.client.api.communication.request.cud.ODataDeleteRequest; import org.apache.olingo.client.api.communication.request.cud.ODataDeleteRequest;
@ -52,9 +49,8 @@ import org.apache.olingo.client.api.http.HttpMethod;
import org.apache.olingo.client.api.uri.CommonURIBuilder; import org.apache.olingo.client.api.uri.CommonURIBuilder;
import org.apache.olingo.client.api.v3.ODataClient; import org.apache.olingo.client.api.v3.ODataClient;
import org.apache.olingo.client.core.ODataClientFactory; import org.apache.olingo.client.core.ODataClientFactory;
import org.apache.olingo.client.core.it.AbstractBaseTestITCase;
import org.apache.olingo.client.core.uri.URIUtils; import org.apache.olingo.client.core.uri.URIUtils;
import org.apache.olingo.commons.api.data.Entry;
import org.apache.olingo.commons.api.data.Feed;
import org.apache.olingo.commons.api.domain.CommonODataEntity; import org.apache.olingo.commons.api.domain.CommonODataEntity;
import org.apache.olingo.commons.api.domain.CommonODataEntitySet; import org.apache.olingo.commons.api.domain.CommonODataEntitySet;
import org.apache.olingo.commons.api.domain.CommonODataProperty; import org.apache.olingo.commons.api.domain.CommonODataProperty;
@ -68,19 +64,9 @@ import org.apache.olingo.commons.api.domain.v3.ODataEntity;
import org.apache.olingo.commons.api.domain.v3.ODataProperty; import org.apache.olingo.commons.api.domain.v3.ODataProperty;
import org.apache.olingo.commons.api.edm.FullQualifiedName; import org.apache.olingo.commons.api.edm.FullQualifiedName;
import org.apache.olingo.commons.api.format.ODataPubFormat; import org.apache.olingo.commons.api.format.ODataPubFormat;
import org.apache.olingo.commons.core.data.AtomEntryImpl;
import org.apache.olingo.commons.core.data.JSONEntryImpl;
import org.junit.BeforeClass; import org.junit.BeforeClass;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
public abstract class AbstractTestITCase { public abstract class AbstractTestITCase extends AbstractBaseTestITCase {
/**
* Logger.
*/
protected static final Logger LOG = LoggerFactory.getLogger(AbstractTestITCase.class);
protected static final FullQualifiedName TEST_PRODUCT_TYPE = protected static final FullQualifiedName TEST_PRODUCT_TYPE =
new FullQualifiedName("Microsoft.Test.OData.Services.AstoriaDefaultService.Product"); new FullQualifiedName("Microsoft.Test.OData.Services.AstoriaDefaultService.Product");
@ -114,6 +100,7 @@ public abstract class AbstractTestITCase {
client = ODataClientFactory.getV3(); client = ODataClientFactory.getV3();
} }
@Override
protected ODataClient getClient() { protected ODataClient getClient() {
return client; return client;
} }
@ -307,58 +294,6 @@ public abstract class AbstractTestITCase {
return entity; return entity;
} }
protected void debugEntry(final Entry entry, final String message) {
if (LOG.isDebugEnabled()) {
final StringWriter writer = new StringWriter();
getClient().getSerializer().entry(entry, writer);
writer.flush();
LOG.debug(message + "\n{}", writer.toString());
}
}
protected void debugFeed(final Feed feed, final String message) {
if (LOG.isDebugEnabled()) {
final StringWriter writer = new StringWriter();
getClient().getSerializer().feed(feed, writer);
writer.flush();
LOG.debug(message + "\n{}", writer.toString());
}
}
protected void debugODataProperty(final ODataProperty property, final String message) {
LOG.debug(message + "\n{}", property.toString());
}
protected void debugODataValue(final ODataValue value, final String message) {
LOG.debug(message + "\n{}", value.toString());
}
protected void debugODataEntity(final ODataEntity entity, final String message) {
if (LOG.isDebugEnabled()) {
StringWriter writer = new StringWriter();
getClient().getSerializer().entry(getClient().getBinder().getEntry(entity, AtomEntryImpl.class), writer);
writer.flush();
LOG.debug(message + " (Atom)\n{}", writer.toString());
writer = new StringWriter();
getClient().getSerializer().entry(getClient().getBinder().getEntry(entity, JSONEntryImpl.class), writer);
writer.flush();
LOG.debug(message + " (JSON)\n{}", writer.toString());
}
}
protected void debugInputStream(final InputStream input, final String message) {
if (LOG.isDebugEnabled()) {
try {
LOG.debug(message + "\n{}", IOUtils.toString(input));
} catch (IOException e) {
LOG.error("Error writing stream", e);
} finally {
IOUtils.closeQuietly(input);
}
}
}
protected String getETag(final URI uri) { protected String getETag(final URI uri) {
final ODataRetrieveResponse<ODataEntity> res = getClient().getRetrieveRequestFactory(). final ODataRetrieveResponse<ODataEntity> res = getClient().getRetrieveRequestFactory().
getEntityRequest(uri).execute(); getEntityRequest(uri).execute();

View File

@ -27,15 +27,12 @@ import org.apache.olingo.client.api.communication.request.retrieve.ODataEntityRe
import org.apache.olingo.client.api.communication.response.ODataRetrieveResponse; import org.apache.olingo.client.api.communication.response.ODataRetrieveResponse;
import org.apache.olingo.client.api.v4.ODataClient; import org.apache.olingo.client.api.v4.ODataClient;
import org.apache.olingo.client.core.ODataClientFactory; import org.apache.olingo.client.core.ODataClientFactory;
import org.apache.olingo.client.core.it.AbstractBaseTestITCase;
import org.apache.olingo.commons.api.domain.v4.ODataEntity; import org.apache.olingo.commons.api.domain.v4.ODataEntity;
import org.apache.olingo.commons.api.format.ODataPubFormat; import org.apache.olingo.commons.api.format.ODataPubFormat;
import org.junit.BeforeClass; import org.junit.BeforeClass;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
public abstract class AbstractTestITCase { public abstract class AbstractTestITCase extends AbstractBaseTestITCase {
protected static final Logger LOG = LoggerFactory.getLogger(AbstractTestITCase.class);
protected static ODataClient client; protected static ODataClient client;
@ -60,6 +57,7 @@ public abstract class AbstractTestITCase {
client = ODataClientFactory.getV4(); client = ODataClientFactory.getV4();
} }
@Override
protected ODataClient getClient() { protected ODataClient getClient() {
return client; return client;
} }

View File

@ -21,20 +21,51 @@ package org.apache.olingo.client.core.it.v4;
import static org.junit.Assert.assertEquals; import static org.junit.Assert.assertEquals;
import static org.junit.Assert.assertNotNull; import static org.junit.Assert.assertNotNull;
import java.io.IOException;
import java.net.InetSocketAddress;
import java.net.Socket;
import java.net.URI;
import java.util.Calendar;
import org.apache.commons.io.IOUtils;
import org.apache.commons.lang3.RandomUtils;
import org.apache.olingo.client.api.communication.request.cud.ODataEntityCreateRequest; import org.apache.olingo.client.api.communication.request.cud.ODataEntityCreateRequest;
import org.apache.olingo.client.api.communication.response.ODataDeleteResponse;
import org.apache.olingo.client.api.communication.response.ODataEntityCreateResponse;
import org.apache.olingo.commons.api.domain.ODataCollectionValue; import org.apache.olingo.commons.api.domain.ODataCollectionValue;
import org.apache.olingo.commons.api.domain.v4.ODataEntity; import org.apache.olingo.commons.api.domain.v4.ODataEntity;
import org.apache.olingo.commons.api.domain.v4.ODataEntitySet;
import org.apache.olingo.commons.api.domain.v4.ODataProperty; import org.apache.olingo.commons.api.domain.v4.ODataProperty;
import org.apache.olingo.commons.api.domain.v4.ODataValue; import org.apache.olingo.commons.api.domain.v4.ODataValue;
import org.apache.olingo.commons.api.edm.EdmPrimitiveTypeKind; import org.apache.olingo.commons.api.edm.EdmPrimitiveTypeKind;
import org.apache.olingo.commons.api.edm.FullQualifiedName; import org.apache.olingo.commons.api.edm.FullQualifiedName;
import org.apache.olingo.commons.api.format.ODataPubFormat; import org.apache.olingo.commons.api.format.ODataPubFormat;
import org.apache.olingo.commons.core.domain.v4.ODataEntityImpl; import org.apache.olingo.commons.core.domain.v4.ODataEntityImpl;
import org.junit.Assume;
import org.junit.BeforeClass;
import org.junit.Test; import org.junit.Test;
public class EntityCreateTestITCase extends AbstractTestITCase { public class EntityCreateTestITCase extends AbstractTestITCase {
private void createOrder(final ODataPubFormat format, final int id) { private static final String serviceRoot = "http://odatae2etest.azurewebsites.net/javatest/DefaultService";
// TODO: remove once fit provides contained entity CRUD
@BeforeClass
public static void checkServerIsOnline() throws IOException {
final Socket socket = new Socket();
boolean reachable = false;
try {
socket.connect(new InetSocketAddress("odatae2etest.azurewebsites.net", 80), 2000);
reachable = true;
} catch (Exception e) {
LOG.warn("External test service not reachable, ignoring this whole class: {}",
OperationImportInvokeTestITCase.class.getName());
} finally {
IOUtils.closeQuietly(socket);
}
Assume.assumeTrue(reachable);
}
private void order(final ODataPubFormat format, final int id) {
final ODataEntity order = new ODataEntityImpl( final ODataEntity order = new ODataEntityImpl(
new FullQualifiedName("Microsoft.Test.OData.Services.ODataWCFService.Order")); new FullQualifiedName("Microsoft.Test.OData.Services.ODataWCFService.Order"));
@ -73,11 +104,67 @@ public class EntityCreateTestITCase extends AbstractTestITCase {
@Test @Test
public void atom() { public void atom() {
createOrder(ODataPubFormat.ATOM, 1000); order(ODataPubFormat.ATOM, 1000);
} }
@Test @Test
public void json() { public void json() {
createOrder(ODataPubFormat.JSON, 1001); order(ODataPubFormat.JSON, 1001);
}
private void onContained(final ODataPubFormat format) {
final URI uri = getClient().getURIBuilder(serviceRoot).appendEntitySetSegment("Accounts").appendKeySegment(101).
appendNavigationSegment("MyPaymentInstruments").build();
// 1. read contained collection before any operation
ODataEntitySet instruments = getClient().getRetrieveRequestFactory().getEntitySetRequest(uri).execute().getBody();
assertNotNull(instruments);
final int sizeBefore = instruments.getCount();
// 2. instantiate an ODataEntity of the same type as the collection above
final ODataEntity instrument = getClient().getObjectFactory().
newEntity(new FullQualifiedName("Microsoft.Test.OData.Services.ODataWCFService.PaymentInstrument"));
int id = RandomUtils.nextInt(101999, 105000);
instrument.getProperties().add(getClient().getObjectFactory().newPrimitiveProperty("PaymentInstrumentID",
getClient().getObjectFactory().newPrimitiveValueBuilder().buildInt32(id)));
instrument.getProperties().add(getClient().getObjectFactory().newPrimitiveProperty("FriendlyName",
getClient().getObjectFactory().newPrimitiveValueBuilder().buildString("New one")));
instrument.getProperties().add(getClient().getObjectFactory().newPrimitiveProperty("CreatedDate",
getClient().getObjectFactory().newPrimitiveValueBuilder().
setType(EdmPrimitiveTypeKind.DateTimeOffset).setValue(Calendar.getInstance()).build()));
// 3. create it as contained entity
final ODataEntityCreateRequest<ODataEntity> req = getClient().getCUDRequestFactory().
getEntityCreateRequest(uri, instrument);
final ODataEntityCreateResponse<ODataEntity> res = req.execute();
assertEquals(201, res.getStatusCode());
// 4. verify that the contained collection effectively grew
instruments = getClient().getRetrieveRequestFactory().getEntitySetRequest(uri).execute().getBody();
assertNotNull(instruments);
final int sizeAfter = instruments.getCount();
assertEquals(sizeBefore + 1, sizeAfter);
// 5. remove the contained entity created above
final ODataDeleteResponse deleteRes = getClient().getCUDRequestFactory().
getDeleteRequest(getClient().getURIBuilder(uri.toASCIIString()).appendKeySegment(id).build()).execute();
assertEquals(204, deleteRes.getStatusCode());
// 6. verify that the contained collection effectively reduced
instruments = getClient().getRetrieveRequestFactory().getEntitySetRequest(uri).execute().getBody();
assertNotNull(instruments);
final int sizeEnd = instruments.getCount();
assertEquals(sizeBefore, sizeEnd);
}
@Test
public void atomOnContained() {
onContained(ODataPubFormat.ATOM);
}
@Test
public void jsonOnContained() {
onContained(ODataPubFormat.JSON);
} }
} }

View File

@ -60,6 +60,7 @@ public class AtomTest extends JSONTest {
return result.toString(); return result.toString();
} }
@Override
protected void assertSimilar(final String filename, final String actual) throws Exception { protected void assertSimilar(final String filename, final String actual) throws Exception {
final Diff diff = new Diff(cleanup(IOUtils.toString(getClass().getResourceAsStream(filename))), actual); final Diff diff = new Diff(cleanup(IOUtils.toString(getClass().getResourceAsStream(filename))), actual);
diff.overrideElementQualifier(new AtomLinksQualifier()); diff.overrideElementQualifier(new AtomLinksQualifier());

View File

@ -33,6 +33,7 @@ import org.apache.olingo.commons.api.data.CollectionValue;
import org.apache.olingo.commons.api.data.Entry; import org.apache.olingo.commons.api.data.Entry;
import org.apache.olingo.commons.api.data.Link; import org.apache.olingo.commons.api.data.Link;
import org.apache.olingo.commons.api.data.Linked; import org.apache.olingo.commons.api.data.Linked;
import org.apache.olingo.commons.api.data.PrimitiveValue;
import org.apache.olingo.commons.api.data.Property; import org.apache.olingo.commons.api.data.Property;
import org.apache.olingo.commons.api.data.Value; import org.apache.olingo.commons.api.data.Value;
import org.apache.olingo.commons.api.domain.ODataLinkType; import org.apache.olingo.commons.api.domain.ODataLinkType;
@ -140,6 +141,26 @@ abstract class AbstractJsonSerializer<T> extends ODataJacksonSerializer<T> {
jgen.writeEndArray(); jgen.writeEndArray();
} }
protected void primitiveValue(final JsonGenerator jgen, final EdmTypeInfo typeInfo, final PrimitiveValue value)
throws IOException {
final boolean isNumber = typeInfo == null
? NumberUtils.isNumber(value.get())
: ArrayUtils.contains(NUMBER_TYPES, typeInfo.getPrimitiveTypeKind());
final boolean isBoolean = typeInfo == null
? (value.get().equalsIgnoreCase(Boolean.TRUE.toString())
|| value.get().equalsIgnoreCase(Boolean.FALSE.toString()))
: typeInfo.getPrimitiveTypeKind() == EdmPrimitiveTypeKind.Boolean;
if (isNumber) {
jgen.writeNumber(value.get());
} else if (isBoolean) {
jgen.writeBoolean(BooleanUtils.toBoolean(value.get()));
} else {
jgen.writeString(value.get());
}
}
private void value(final JsonGenerator jgen, final String type, final Value value) throws IOException { private void value(final JsonGenerator jgen, final String type, final Value value) throws IOException {
final EdmTypeInfo typeInfo = type == null final EdmTypeInfo typeInfo = type == null
? null ? null
@ -148,21 +169,7 @@ abstract class AbstractJsonSerializer<T> extends ODataJacksonSerializer<T> {
if (value == null || value.isNull()) { if (value == null || value.isNull()) {
jgen.writeNull(); jgen.writeNull();
} else if (value.isPrimitive()) { } else if (value.isPrimitive()) {
final boolean isNumber = typeInfo == null primitiveValue(jgen, typeInfo, value.asPrimitive());
? NumberUtils.isNumber(value.asPrimitive().get())
: ArrayUtils.contains(NUMBER_TYPES, typeInfo.getPrimitiveTypeKind());
final boolean isBoolean = typeInfo == null
? (value.asPrimitive().get().equalsIgnoreCase(Boolean.TRUE.toString())
|| value.asPrimitive().get().equalsIgnoreCase(Boolean.FALSE.toString()))
: typeInfo.getPrimitiveTypeKind() == EdmPrimitiveTypeKind.Boolean;
if (isNumber) {
jgen.writeNumber(value.asPrimitive().get());
} else if (isBoolean) {
jgen.writeBoolean(BooleanUtils.toBoolean(value.asPrimitive().get()));
} else {
jgen.writeString(value.asPrimitive().get());
}
} else if (value.isEnum()) { } else if (value.isEnum()) {
jgen.writeString(value.asEnum().get()); jgen.writeString(value.asEnum().get());
} else if (value.isGeospatial()) { } else if (value.isGeospatial()) {

View File

@ -271,6 +271,10 @@ public class AtomDeserializer extends AbstractAtomDealer {
break; break;
case PRIMITIVE: case PRIMITIVE:
// No type specified? Defaults to Edm.String
if (typeInfo == null) {
property.setType(EdmPrimitiveTypeKind.String.getFullQualifiedName().toString());
}
value = fromPrimitive(reader, start, typeInfo); value = fromPrimitive(reader, start, typeInfo);
break; break;

View File

@ -34,6 +34,7 @@ import org.apache.olingo.commons.api.data.Feed;
import org.apache.olingo.commons.api.data.Link; import org.apache.olingo.commons.api.data.Link;
import org.apache.olingo.commons.api.data.Property; import org.apache.olingo.commons.api.data.Property;
import org.apache.olingo.commons.api.data.Value; import org.apache.olingo.commons.api.data.Value;
import org.apache.olingo.commons.api.edm.EdmPrimitiveTypeKind;
import org.apache.olingo.commons.api.edm.constants.ODataServiceVersion; import org.apache.olingo.commons.api.edm.constants.ODataServiceVersion;
import org.apache.olingo.commons.api.format.ContentType; import org.apache.olingo.commons.api.format.ContentType;
import org.apache.olingo.commons.core.edm.EdmTypeInfo; import org.apache.olingo.commons.core.edm.EdmTypeInfo;
@ -102,9 +103,11 @@ public class AtomSerializer extends AbstractAtomDealer {
} }
if (StringUtils.isNotBlank(property.getType())) { if (StringUtils.isNotBlank(property.getType())) {
writer.writeAttribute(Constants.PREFIX_METADATA, version.getNamespaceMap().get(ODataServiceVersion.NS_METADATA), final EdmTypeInfo typeInfo = new EdmTypeInfo.Builder().setTypeExpression(property.getType()).build();
Constants.ATTR_TYPE, if (!EdmPrimitiveTypeKind.String.getFullQualifiedName().toString().equals(typeInfo.internal())) {
new EdmTypeInfo.Builder().setTypeExpression(property.getType()).build().external(version)); writer.writeAttribute(Constants.PREFIX_METADATA, version.getNamespaceMap().get(ODataServiceVersion.NS_METADATA),
Constants.ATTR_TYPE, typeInfo.external(version));
}
} }
if (property.getValue().isNull()) { if (property.getValue().isNull()) {

View File

@ -59,15 +59,11 @@ public class JSONEntrySerializer extends AbstractJsonSerializer<JSONEntryImpl> {
if (serverMode) { if (serverMode) {
if (version.compareTo(ODataServiceVersion.V40) >= 0 && StringUtils.isNotBlank(container.getMetadataETag())) { if (version.compareTo(ODataServiceVersion.V40) >= 0 && StringUtils.isNotBlank(container.getMetadataETag())) {
jgen.writeStringField( jgen.writeStringField(Constants.JSON_METADATA_ETAG, container.getMetadataETag());
Constants.JSON_METADATA_ETAG,
container.getMetadataETag());
} }
if (StringUtils.isNotBlank(entry.getETag())) { if (StringUtils.isNotBlank(entry.getETag())) {
jgen.writeStringField( jgen.writeStringField(version.getJSONMap().get(ODataServiceVersion.JSON_ETAG), entry.getETag());
version.getJSONMap().get(ODataServiceVersion.JSON_ETAG),
entry.getETag());
} }
} }

View File

@ -25,6 +25,7 @@ import java.io.IOException;
import org.apache.olingo.commons.api.Constants; import org.apache.olingo.commons.api.Constants;
import org.apache.olingo.commons.api.data.Container; import org.apache.olingo.commons.api.data.Container;
import org.apache.olingo.commons.api.data.Property; import org.apache.olingo.commons.api.data.Property;
import org.apache.olingo.commons.core.edm.EdmTypeInfo;
/** /**
* Writes out JSON string from <tt>JSONPropertyImpl</tt>. * Writes out JSON string from <tt>JSONPropertyImpl</tt>.
@ -51,7 +52,12 @@ public class JSONPropertySerializer extends AbstractJsonSerializer<JSONPropertyI
if (property.getValue().isNull()) { if (property.getValue().isNull()) {
jgen.writeBooleanField(Constants.JSON_NULL, true); jgen.writeBooleanField(Constants.JSON_NULL, true);
} else if (property.getValue().isPrimitive()) { } else if (property.getValue().isPrimitive()) {
jgen.writeStringField(Constants.VALUE, property.getValue().asPrimitive().get()); final EdmTypeInfo typeInfo = property.getType() == null
? null
: new EdmTypeInfo.Builder().setTypeExpression(property.getType()).build();
jgen.writeFieldName(Constants.VALUE);
primitiveValue(jgen, typeInfo, property.getValue().asPrimitive());
} else if (property.getValue().isEnum()) { } else if (property.getValue().isEnum()) {
jgen.writeStringField(Constants.VALUE, property.getValue().asEnum().get()); jgen.writeStringField(Constants.VALUE, property.getValue().asEnum().get());
} else if (property.getValue().isGeospatial() || property.getValue().isCollection()) { } else if (property.getValue().isGeospatial() || property.getValue().isCollection()) {

15
pom.xml
View File

@ -20,7 +20,7 @@
--> -->
<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" <project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd"> xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
<modelVersion>4.0.0</modelVersion> <modelVersion>4.0.0</modelVersion>
<groupId>org.apache.olingo</groupId> <groupId>org.apache.olingo</groupId>
@ -210,6 +210,12 @@
<version>1.5</version> <version>1.5</version>
<scope>test</scope> <scope>test</scope>
</dependency> </dependency>
<dependency>
<groupId>org.slf4j</groupId>
<artifactId>slf4j-simple</artifactId>
<version>${sl4j.version}</version>
<scope>test</scope>
</dependency>
</dependencies> </dependencies>
</dependencyManagement> </dependencyManagement>
@ -307,6 +313,7 @@
<artifactId>maven-surefire-plugin</artifactId> <artifactId>maven-surefire-plugin</artifactId>
<version>2.17</version> <version>2.17</version>
<configuration> <configuration>
<redirectTestOutputToFile>true</redirectTestOutputToFile>
<runOrder>alphabetical</runOrder> <runOrder>alphabetical</runOrder>
<encoding>UTF-8</encoding> <encoding>UTF-8</encoding>
<inputEncoding>UTF-8</inputEncoding> <inputEncoding>UTF-8</inputEncoding>
@ -319,8 +326,12 @@
<artifactId>maven-failsafe-plugin</artifactId> <artifactId>maven-failsafe-plugin</artifactId>
<version>2.17</version> <version>2.17</version>
<configuration> <configuration>
<encoding>utf-8</encoding> <redirectTestOutputToFile>true</redirectTestOutputToFile>
<runOrder>alphabetical</runOrder> <runOrder>alphabetical</runOrder>
<encoding>UTF-8</encoding>
<inputEncoding>UTF-8</inputEncoding>
<outputEncoding>UTF-8</outputEncoding>
<argLine>-Dfile.encoding=UTF-8</argLine>
</configuration> </configuration>
<executions> <executions>
<execution> <execution>