[OLINGO-175] using commons (de-)serializers to add some capabilities to fit

This commit is contained in:
fmartelli 2014-04-10 16:32:12 +02:00
parent ba791fac39
commit 450ccfd4e3
293 changed files with 2266 additions and 499 deletions

View File

@ -40,6 +40,18 @@
</properties>
<dependencies>
<dependency>
<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>

View File

@ -18,15 +18,35 @@
*/
package org.apache.olingo.fit;
import org.apache.olingo.commons.api.data.Container;
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.api.format.ContentType;
import org.apache.olingo.commons.core.data.AtomDeserializer;
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.core.type.TypeReference;
import com.fasterxml.jackson.databind.JsonNode;
import com.fasterxml.jackson.databind.ObjectMapper;
import java.io.ByteArrayInputStream;
import java.io.ByteArrayOutputStream;
import java.io.File;
import java.io.InputStream;
import java.io.OutputStreamWriter;
import java.util.AbstractMap;
import java.util.Arrays;
import java.util.Collections;
import java.util.EnumSet;
import java.util.HashMap;
import java.util.HashSet;
import java.util.List;
import java.util.Map;
import java.util.Set;
@ -51,18 +71,28 @@ import javax.ws.rs.core.UriInfo;
import org.apache.commons.codec.binary.Base64;
import org.apache.commons.io.IOUtils;
import org.apache.commons.lang3.StringUtils;
import org.apache.olingo.commons.api.data.Entry;
import org.apache.olingo.commons.api.edm.EdmPrimitiveTypeKind;
import org.apache.olingo.commons.core.data.AtomEntryImpl;
import org.apache.olingo.commons.core.data.AtomPropertyImpl;
import org.apache.olingo.commons.core.data.AtomSerializer;
import org.apache.olingo.commons.core.data.JSONEntryImpl;
import org.apache.olingo.commons.core.data.JSONFeedImpl;
import org.apache.olingo.commons.core.data.NullValueImpl;
import org.apache.olingo.commons.core.data.PrimitiveValueImpl;
import org.apache.olingo.fit.metadata.EntitySet;
import org.apache.olingo.fit.metadata.EntityType;
import org.apache.olingo.fit.metadata.NavigationProperty;
import org.apache.olingo.fit.utils.Accept;
import org.apache.olingo.fit.utils.FSManager;
import org.apache.olingo.fit.utils.Commons;
import org.apache.olingo.fit.methods.MERGE;
import org.apache.olingo.fit.methods.PATCH;
import org.apache.olingo.fit.utils.AbstractJSONUtilities;
import org.apache.olingo.fit.utils.AbstractUtilities;
import org.apache.olingo.fit.utils.AbstractXMLUtilities;
import org.apache.olingo.fit.utils.Accept;
import org.apache.olingo.fit.utils.Commons;
import org.apache.olingo.fit.utils.ConstantKey;
import org.apache.olingo.fit.utils.Constants;
import org.apache.olingo.fit.utils.FSManager;
import org.apache.olingo.fit.utils.LinkInfo;
import org.apache.olingo.fit.utils.ODataVersion;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
@ -73,9 +103,7 @@ public abstract class AbstractServices {
*/
protected static final Logger LOG = LoggerFactory.getLogger(AbstractServices.class);
private static final Set<ODataVersion> INITIALIZED = EnumSet.noneOf(ODataVersion.class);
protected final ODataVersion version;
protected final ODataServiceVersion version;
protected final AbstractXMLUtilities xml;
@ -84,9 +112,11 @@ public abstract class AbstractServices {
@Context
protected UriInfo uriInfo;
public AbstractServices(final ODataVersion version) throws Exception {
protected Metadata metadata;
public AbstractServices(final ODataServiceVersion version) throws Exception {
this.version = version;
if (ODataVersion.v3 == version) {
if (version.compareTo(ODataServiceVersion.V30) <= 0) {
this.xml = new org.apache.olingo.fit.utils.v3.XMLUtilities();
this.json = new org.apache.olingo.fit.utils.v3.JSONUtilities();
} else {
@ -94,10 +124,7 @@ public abstract class AbstractServices {
this.json = new org.apache.olingo.fit.utils.v4.JSONUtilities();
}
if (!INITIALIZED.contains(version)) {
xml.retrieveLinkInfoFromMetadata();
INITIALIZED.add(version);
}
metadata = Commons.getMetadata(version);
}
/**
@ -169,7 +196,7 @@ public abstract class AbstractServices {
return utils.getValue().createResponse(
FSManager.instance(version).readFile(Constants.get(version, ConstantKey.REF)
+ File.separatorChar + filename, utils.getKey()),
+ File.separatorChar + filename, utils.getKey()),
null,
utils.getKey());
} catch (Exception e) {
@ -216,9 +243,32 @@ public abstract class AbstractServices {
InputStream res =
util.patchEntity(entitySetName, entityId, IOUtils.toInputStream(changes), acceptType, ifMatch);
final AtomDeserializer atomDeserializer = Commons.getAtomDeserializer(version);
final ObjectMapper mapper = Commons.getJsonMapper(version);
final Container<AtomEntryImpl> cres;
if (acceptType == Accept.ATOM) {
cres = atomDeserializer.read(res, AtomEntryImpl.class);
} else {
final Container<JSONEntryImpl> jcont = mapper.readValue(res, new TypeReference<JSONEntryImpl>() {
});
cres = new Container<AtomEntryImpl>(jcont.getContextURL(), jcont.getMetadataETag(),
(new DataBinder(version)).getAtomEntry(jcont.getObject()));
}
normalizeAtomEntry(cres.getObject(), entitySetName, entityId);
final String path = Commons.getEntityBasePath(entitySetName, entityId);
FSManager.instance(version).putInMemory(
cres, path + File.separatorChar + Constants.get(version, ConstantKey.ENTITY));
final Response response;
if ("return-content".equalsIgnoreCase(prefer)) {
response = xml.createResponse(res, null, acceptType, Response.Status.OK);
response = xml.createResponse(
util.readEntity(entitySetName, entityId, acceptType).getValue(),
null, acceptType, Response.Status.OK);
} else {
res.close();
response = xml.createResponse(null, null, acceptType, Response.Status.NO_CONTENT);
@ -258,9 +308,28 @@ public abstract class AbstractServices {
res = json.addOrReplaceEntity(entityId, entitySetName, IOUtils.toInputStream(entity));
}
final AtomDeserializer atomDeserializer = Commons.getAtomDeserializer(version);
final ObjectMapper mapper = Commons.getJsonMapper(version);
final Container<AtomEntryImpl> cres;
if (acceptType == Accept.ATOM) {
cres = atomDeserializer.read(res, AtomEntryImpl.class);
} else {
final Container<JSONEntryImpl> jcont = mapper.readValue(res, new TypeReference<JSONEntryImpl>() {
});
cres = new Container<AtomEntryImpl>(jcont.getContextURL(), jcont.getMetadataETag(),
(new DataBinder(version)).getAtomEntry(jcont.getObject()));
}
final String path = Commons.getEntityBasePath(entitySetName, entityId);
FSManager.instance(version).putInMemory(
cres, path + File.separatorChar + Constants.get(version, ConstantKey.ENTITY));
final Response response;
if ("return-content".equalsIgnoreCase(prefer)) {
response = xml.createResponse(res, null, acceptType, Response.Status.OK);
response = xml.createResponse(
getUtilities(acceptType).readEntity(entitySetName, entityId, acceptType).getValue(),
null, acceptType, Response.Status.OK);
} else {
res.close();
response = xml.createResponse(null, null, acceptType, Response.Status.NO_CONTENT);
@ -282,6 +351,7 @@ public abstract class AbstractServices {
@Consumes({MediaType.APPLICATION_ATOM_XML, MediaType.APPLICATION_JSON, MediaType.APPLICATION_OCTET_STREAM})
public Response postNewEntity(
@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,
final String entity) {
@ -297,20 +367,89 @@ public abstract class AbstractServices {
utils = getUtilities(acceptType);
final InputStream res;
final AtomDeserializer atomDeserializer = Commons.getAtomDeserializer(version);
final AtomSerializer atomSerializer = Commons.getAtomSerializer(version);
final ObjectMapper mapper = Commons.getJsonMapper(version);
final Container<AtomEntryImpl> container;
final EntitySet entitySet = metadata.getEntitySet(entitySetName);
final AtomEntryImpl entry;
final String entityKey;
if (utils.isMediaContent(entitySetName)) {
res = utils.addMediaEntity(entitySetName, IOUtils.toInputStream(entity));
entityKey = xml.getDefaultEntryKey(entitySetName, null);
utils.addMediaEntityValue(entitySetName, entityKey, IOUtils.toInputStream(entity));
entry = new AtomEntryImpl();
entry.setMediaContentType(ContentType.WILDCARD);
entry.setType(entitySet.getType());
final String id = Commons.getMediaContent().get(entitySetName);
if (StringUtils.isNotBlank(id)) {
final AtomPropertyImpl prop = new AtomPropertyImpl();
prop.setName(id);
prop.setType(EdmPrimitiveTypeKind.Int32.toString());
prop.setValue(new PrimitiveValueImpl(entityKey));
entry.getProperties().add(prop);
}
final Link editLink = new LinkImpl();
editLink.setHref(Commons.getEntityURI(entitySetName, entityKey));
editLink.setRel("edit");
editLink.setTitle(entitySetName);
entry.setEditLink(editLink);
entry.setMediaContentSource(editLink.getHref() + "/$value");
container = new Container<AtomEntryImpl>(null, null, entry);
} else {
res = utils.addOrReplaceEntity(entitySetName, IOUtils.toInputStream(entity));
final Accept contentTypeValue = Accept.parse(contentType, version);
entityKey = getUtilities(contentTypeValue).getDefaultEntryKey(entitySetName, IOUtils.toInputStream(entity));
if (Accept.ATOM == contentTypeValue) {
container = atomDeserializer.read(IOUtils.toInputStream(entity), AtomEntryImpl.class);
entry = container.getObject();
} else {
final Container<JSONEntryImpl> jcontainer =
mapper.readValue(IOUtils.toInputStream(entity), new TypeReference<JSONEntryImpl>() {
});
entry = (new DataBinder(version)).
getAtomEntry(jcontainer.getObject());
container = new Container<AtomEntryImpl>(
jcontainer.getContextURL(),
jcontainer.getMetadataETag(),
entry);
}
}
normalizeAtomEntry(entry, entitySetName, entityKey);
final ByteArrayOutputStream content = new ByteArrayOutputStream();
OutputStreamWriter writer = new OutputStreamWriter(content, Constants.encoding);
atomSerializer.write(writer, container);
writer.flush();
writer.close();
final InputStream serialization =
xml.addOrReplaceEntity(entitySetName, new ByteArrayInputStream(content.toByteArray()));
final Container<AtomEntryImpl> cres = atomDeserializer.read(serialization, AtomEntryImpl.class);
final String path = Commons.getEntityBasePath(entitySetName, entityKey);
FSManager.instance(version).putInMemory(
cres, path + File.separatorChar + Constants.get(version, ConstantKey.ENTITY));
final Response response;
if ("return-no-content".equalsIgnoreCase(prefer)) {
IOUtils.closeQuietly(res);
response = utils.createResponse(null, null, acceptType, Response.Status.NO_CONTENT);
} else {
response = utils.createResponse(res, null, acceptType, Response.Status.CREATED);
response = utils.createResponse(utils.readEntity(entitySetName, entityKey, acceptType).getValue(),
null, acceptType, Response.Status.CREATED);
}
if (StringUtils.isNotBlank(prefer)) {
@ -349,13 +488,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, "UTF-8"),
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);
} catch (Exception e) {
@ -387,7 +526,8 @@ public abstract class AbstractServices {
final StringBuilder path = new StringBuilder(name).
append(File.separatorChar).append(type).
append(File.separatorChar);
path.append(Commons.getLinkInfo().get(version).isSingleton(name)
path.append(metadata.getEntitySet(name).isSingleton()
? Constants.get(version, ConstantKey.ENTITY)
: Constants.get(version, ConstantKey.FEED));
@ -406,9 +546,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, "UTF-8"),
@ -445,7 +585,8 @@ public abstract class AbstractServices {
final StringBuilder path = new StringBuilder(name).
append(File.separatorChar).append(type).
append(File.separatorChar);
path.append(Commons.getLinkInfo().get(version).isSingleton(name)
path.append(metadata.getEntitySet(name).isSingleton()
? Constants.get(version, ConstantKey.ENTITY)
: Constants.get(version, ConstantKey.FEED));
@ -462,7 +603,7 @@ public abstract class AbstractServices {
* @param accept Accept header.
* @param name entity set or function name.
* @param format format query option.
* @param inlinecount inlinecount query option.
* @param count inlinecount query option.
* @param filter filter query option.
* @param orderby orderby query option.
* @param skiptoken skiptoken query option.
@ -474,7 +615,7 @@ public abstract class AbstractServices {
@HeaderParam("Accept") @DefaultValue(StringUtils.EMPTY) String accept,
@PathParam("name") String name,
@QueryParam("$format") @DefaultValue(StringUtils.EMPTY) String format,
@QueryParam("$inlinecount") @DefaultValue(StringUtils.EMPTY) String inlinecount,
@QueryParam("$inlinecount") @DefaultValue(StringUtils.EMPTY) String count,
@QueryParam("$filter") @DefaultValue(StringUtils.EMPTY) String filter,
@QueryParam("$orderby") @DefaultValue(StringUtils.EMPTY) String orderby,
@QueryParam("$skiptoken") @DefaultValue(StringUtils.EMPTY) String skiptoken) {
@ -514,35 +655,55 @@ public abstract class AbstractServices {
builder.append(Constants.get(version, ConstantKey.SKIP_TOKEN)).append(File.separatorChar).
append(skiptoken);
} else {
builder.append(Commons.getLinkInfo().get(version).isSingleton(name)
builder.append(metadata.getEntitySet(name).isSingleton()
? Constants.get(version, ConstantKey.ENTITY)
: Constants.get(version, ConstantKey.FEED));
}
InputStream feed = FSManager.instance(version).readFile(builder.toString(), acceptType);
if ("allpages".equals(inlinecount)) {
int count = xml.countAllElements(name);
feed.close();
if (acceptType == Accept.ATOM) {
feed = xml.addAtomInlinecount(
FSManager.instance(version).readFile(builder.toString(), acceptType),
count,
acceptType);
} else {
feed = json.addJsonInlinecount(
FSManager.instance(version).readFile(builder.toString(), acceptType),
count,
acceptType);
}
final InputStream feed = FSManager.instance(version).readFile(builder.toString(), Accept.ATOM);
final AtomDeserializer atomDeserializer = Commons.getAtomDeserializer(version);
final AtomSerializer atomSerializer = Commons.getAtomSerializer(version);
final Container<Feed> container = atomDeserializer.read(feed, AtomFeedImpl.class);
setInlineCount(container.getObject(), count);
final ByteArrayOutputStream content = new ByteArrayOutputStream();
final OutputStreamWriter writer = new OutputStreamWriter(content, Constants.encoding);
if (acceptType == Accept.ATOM) {
atomSerializer.write(writer, container);
writer.flush();
writer.close();
} else {
final ObjectMapper mapper = Commons.getJsonMapper(version);
mapper.writeValue(
writer, new JsonFeedContainer<JSONFeedImpl>(container.getContextURL(), container.getMetadataETag(),
(new DataBinder(version)).getJsonFeed((AtomFeedImpl) container.getObject())));
}
return xml.createResponse(feed, Commons.getETag(basePath, version), acceptType);
return xml.createResponse(new ByteArrayInputStream(content.toByteArray()),
Commons.getETag(basePath, version), acceptType);
}
} catch (Exception e) {
return xml.createFaultResponse(accept, e);
}
}
protected abstract void setInlineCount(final Feed feed, final String count);
/**
* Retrieve entity with key as segment.
*
* @param accept Accept header.
* @param entitySetName Entity set name.
* @param entityId entity id.
* @param format format query option.
* @param expand expand query option.
* @param select select query option.
* @return entity.
*/
@GET
@Path("/Person({entityId})")
public Response getEntity(
@ -615,31 +776,101 @@ public abstract class AbstractServices {
}
final Map.Entry<String, InputStream> entityInfo =
utils.getValue().readEntity(entitySetName, entityId, utils.getKey());
utils.getValue().readEntity(entitySetName, entityId, Accept.ATOM);
InputStream entity = entityInfo.getValue();
final AtomDeserializer atomDeserializer = Commons.getAtomDeserializer(version);
final AtomSerializer atomSerializer = Commons.getAtomSerializer(version);
final Container<Entry> container = atomDeserializer.<Entry, AtomEntryImpl>read(entity, AtomEntryImpl.class);
final Entry entry = container.getObject();
if (keyAsSegment) {
entity = utils.getValue().addEditLink(
entity, entitySetName,
Constants.get(version, ConstantKey.DEFAULT_SERVICE_URL) + entitySetName + "/" + entityId);
final Link editLink = new LinkImpl();
editLink.setRel("edit");
editLink.setTitle(entitySetName);
editLink.setHref(Constants.get(version, ConstantKey.DEFAULT_SERVICE_URL) + entitySetName + "/" + entityId);
entry.setEditLink(editLink);
}
if (StringUtils.isNotBlank(select)) {
entity = utils.getValue().selectEntity(entity, select.split(","));
final List<String> properties = Arrays.asList(select.split(","));
final Set<Property> toBeRemoved = new HashSet<Property>();
for (Property property : entry.getProperties()) {
if (!properties.contains(property.getName())) {
toBeRemoved.add(property);
}
}
entry.getProperties().removeAll(toBeRemoved);
final Set<Link> linkToBeRemoved = new HashSet<Link>();
for (Link link : entry.getNavigationLinks()) {
if (!properties.contains(link.getTitle().replaceAll("@.*$", "")) && !properties.contains(link.getTitle())) {
linkToBeRemoved.add(link);
}
}
entry.getNavigationLinks().removeAll(linkToBeRemoved);
}
if (StringUtils.isNotBlank(expand)) {
for (String exp : expand.split(",")) {
entity = utils.getValue().expandEntity(
entitySetName,
entityId,
entity,
exp);
final List<String> links = Arrays.asList(expand.split(","));
final Map<Link, Link> replace = new HashMap<Link, Link>();
for (Link link : entry.getNavigationLinks()) {
if (links.contains(link.getTitle())) {
// expand link
final Link rep = new LinkImpl();
rep.setHref(link.getHref());
rep.setRel(link.getRel());
rep.setTitle(link.getTitle());
rep.setType(link.getType());
if (link.getType().equals(Constants.get(ConstantKey.ATOM_LINK_ENTRY))) {
// inline entry
final Entry inline = atomDeserializer.<Entry, AtomEntryImpl>read(
xml.expandEntity(entitySetName, entityId, link.getTitle()),
AtomEntryImpl.class).getObject();
rep.setInlineEntry(inline);
} else if (link.getType().equals(Constants.get(ConstantKey.ATOM_LINK_FEED))) {
// inline feed
final Feed inline = atomDeserializer.<Feed, AtomFeedImpl>read(
xml.expandEntity(entitySetName, entityId, link.getTitle()),
AtomFeedImpl.class).getObject();
rep.setInlineFeed(inline);
}
replace.put(link, rep);
}
}
for (Map.Entry<Link, Link> link : replace.entrySet()) {
entry.getNavigationLinks().remove(link.getKey());
entry.getNavigationLinks().add(link.getValue());
}
}
return utils.getValue().createResponse(entity, Commons.getETag(entityInfo.getKey(), version), utils.getKey());
final ByteArrayOutputStream content = new ByteArrayOutputStream();
final OutputStreamWriter writer = new OutputStreamWriter(content, Constants.encoding);
if (utils.getKey() == Accept.ATOM) {
atomSerializer.write(writer, container);
writer.flush();
writer.close();
} else {
final ObjectMapper mapper = Commons.getJsonMapper(version);
mapper.writeValue(
writer, new JsonEntryContainer<JSONEntryImpl>(container.getContextURL(), container.getMetadataETag(),
(new DataBinder(version)).getJsonEntry((AtomEntryImpl) container.getObject())));
}
return xml.createResponse(new ByteArrayInputStream(content.toByteArray()),
Commons.getETag(entityInfo.getKey(), version), utils.getKey());
} catch (Exception e) {
LOG.error("Error retrieving entity", e);
return xml.createFaultResponse(accept, e);
@ -1384,4 +1615,37 @@ public abstract class AbstractServices {
return utils;
}
private void normalizeAtomEntry(final AtomEntryImpl entry, final String entitySetName, final String entityKey) {
final EntitySet entitySet = metadata.getEntitySet(entitySetName);
final EntityType entityType = metadata.getEntityType(entitySet.getType());
for (Map.Entry<String, org.apache.olingo.fit.metadata.Property> property
: entityType.getPropertyMap().entrySet()) {
if (entry.getProperty(property.getKey()) == null && property.getValue().isNullable()) {
final AtomPropertyImpl prop = new AtomPropertyImpl();
prop.setName(property.getKey());
prop.setValue(new NullValueImpl());
entry.getProperties().add(prop);
}
}
for (Map.Entry<String, NavigationProperty> property : entityType.getNavigationPropertyMap().entrySet()) {
boolean found = false;
for (Link link : entry.getNavigationLinks()) {
if (link.getTitle().equals(property.getKey())) {
found = true;
}
}
if (!found) {
final LinkImpl link = new LinkImpl();
link.setTitle(property.getKey());
link.setType(property.getValue().isFeed()
? Constants.get(ConstantKey.ATOM_LINK_FEED) : Constants.get(ConstantKey.ATOM_LINK_ENTRY));
link.setRel(Constants.get(ConstantKey.ATOM_LINK_REL) + property.getKey());
link.setHref(entitySetName + "(" + entityKey + ")/" + property.getKey());
entry.getNavigationLinks().add(link);
}
}
}
}

View File

@ -35,6 +35,8 @@ import javax.ws.rs.core.Response;
import static javax.ws.rs.core.Response.status;
import org.apache.commons.io.IOUtils;
import org.apache.commons.lang3.StringUtils;
import org.apache.olingo.commons.api.data.Feed;
import org.apache.olingo.commons.api.edm.constants.ODataServiceVersion;
import static org.apache.olingo.fit.AbstractServices.LOG;
import org.apache.olingo.fit.utils.AbstractUtilities;
import org.apache.olingo.fit.utils.Accept;
@ -42,7 +44,6 @@ import org.apache.olingo.fit.utils.Commons;
import org.apache.olingo.fit.utils.ConstantKey;
import org.apache.olingo.fit.utils.Constants;
import org.apache.olingo.fit.utils.FSManager;
import org.apache.olingo.fit.utils.ODataVersion;
import org.springframework.stereotype.Service;
@Service
@ -50,7 +51,7 @@ import org.springframework.stereotype.Service;
public class V3ActionOverloading extends AbstractServices {
public V3ActionOverloading() throws Exception {
super(ODataVersion.v3);
super(ODataServiceVersion.V30);
}
private Response replaceServiceName(final Response response) {
@ -84,7 +85,7 @@ public class V3ActionOverloading extends AbstractServices {
@Produces(MediaType.APPLICATION_XML)
public Response getLargeMetadata() {
return super.getMetadata("actionOverloading"
+ StringUtils.capitalize(Constants.get(ODataVersion.v3, ConstantKey.METADATA)));
+ StringUtils.capitalize(Constants.get(ODataServiceVersion.V30, ConstantKey.METADATA)));
}
@POST
@ -98,14 +99,14 @@ public class V3ActionOverloading extends AbstractServices {
if (StringUtils.isNotBlank(format)) {
acceptType = Accept.valueOf(format.toUpperCase());
} else {
acceptType = Accept.parse(accept, ODataVersion.v3);
acceptType = Accept.parse(accept, ODataServiceVersion.V30);
}
if (acceptType == Accept.XML || acceptType == Accept.TEXT) {
throw new UnsupportedMediaTypeException("Unsupported media type");
}
try {
final InputStream result = FSManager.instance(ODataVersion.v3).
final InputStream result = FSManager.instance(ODataServiceVersion.V30).
readFile("actionOverloadingRetrieveProduct", acceptType);
return replaceServiceName(xml.createResponse(result, null, acceptType));
} catch (Exception e) {
@ -137,7 +138,7 @@ public class V3ActionOverloading extends AbstractServices {
}
return replaceServiceName(utils.getValue().createResponse(
entity, Commons.getETag(entityInfo.getKey(), ODataVersion.v3), utils.getKey()));
entity, Commons.getETag(entityInfo.getKey(), ODataServiceVersion.V30), utils.getKey()));
} catch (Exception e) {
LOG.error("Error retrieving entity", e);
return replaceServiceName(xml.createFaultResponse(accept, e));
@ -180,7 +181,7 @@ public class V3ActionOverloading extends AbstractServices {
}
return replaceServiceName(utils.getValue().createResponse(
entity, Commons.getETag(entityInfo.getKey(), ODataVersion.v3), utils.getKey()));
entity, Commons.getETag(entityInfo.getKey(), ODataServiceVersion.V30), utils.getKey()));
} catch (Exception e) {
LOG.error("Error retrieving entity", e);
return replaceServiceName(xml.createFaultResponse(accept, e));
@ -197,4 +198,8 @@ public class V3ActionOverloading extends AbstractServices {
return unboundRetrieveProduct(accept, format, contentType);
}
@Override
protected void setInlineCount(Feed feed, String count) {
throw new UnsupportedOperationException("Not supported yet.");
}
}

View File

@ -150,10 +150,11 @@ public class V3KeyAsSegment {
@Consumes({MediaType.APPLICATION_ATOM_XML, MediaType.APPLICATION_JSON, MediaType.APPLICATION_OCTET_STREAM})
public Response postNewEntity(
@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,
final String entity) {
return replaceServiceName(services.postNewEntity(accept, prefer, entitySetName, entity));
return replaceServiceName(services.postNewEntity(accept, contentType, prefer, entitySetName, entity));
}
}

View File

@ -22,7 +22,6 @@ import java.io.InputStream;
import javax.ws.rs.DefaultValue;
import javax.ws.rs.GET;
import javax.ws.rs.HeaderParam;
import org.apache.olingo.fit.utils.ODataVersion;
import org.apache.olingo.fit.utils.XHTTPMethodInterceptor;
import javax.ws.rs.Path;
import javax.ws.rs.Produces;
@ -31,6 +30,8 @@ import javax.ws.rs.core.MediaType;
import javax.ws.rs.core.Response;
import org.apache.commons.lang3.StringUtils;
import org.apache.cxf.interceptor.InInterceptors;
import org.apache.olingo.commons.api.data.Feed;
import org.apache.olingo.commons.api.edm.constants.ODataServiceVersion;
import org.apache.olingo.fit.utils.Accept;
import org.apache.olingo.fit.utils.ConstantKey;
import org.apache.olingo.fit.utils.Constants;
@ -43,7 +44,7 @@ import org.springframework.stereotype.Service;
public class V3Services extends AbstractServices {
public V3Services() throws Exception {
super(ODataVersion.v3);
super(ODataServiceVersion.V30);
}
@GET
@ -63,7 +64,7 @@ public class V3Services extends AbstractServices {
final InputStream error = FSManager.instance(version).readFile("InStreamErrorGetCustomer", acceptType);
return Response.ok(error).
header(Constants.get(version, ConstantKey.ODATA_SERVICE_VERSION), version.getVersion() + ";").
header(Constants.get(version, ConstantKey.ODATA_SERVICE_VERSION), version + ";").
header("Content-Type", acceptType.toString(version)).
build();
} catch (Exception e) {
@ -99,4 +100,10 @@ public class V3Services extends AbstractServices {
return getMetadata("openType" + StringUtils.capitalize(Constants.get(version, ConstantKey.METADATA)));
}
@Override
protected void setInlineCount(final Feed feed, final String count) {
if ("allpages".equals(count)) {
feed.setCount(feed.getEntries().size());
}
}
}

View File

@ -18,7 +18,6 @@
*/
package org.apache.olingo.fit;
import org.apache.olingo.fit.utils.ODataVersion;
import org.apache.olingo.fit.utils.XHTTPMethodInterceptor;
import javax.ws.rs.Path;
import javax.ws.rs.core.Response;
@ -30,15 +29,14 @@ import org.springframework.stereotype.Service;
@Service
@Path("/V40/NorthWind.svc")
@InInterceptors(classes = XHTTPMethodInterceptor.class)
public class V4NorthWind extends AbstractServices {
public class V4NorthWind extends V4Services {
public V4NorthWind() throws Exception {
super(ODataVersion.v4);
super();
}
@Override
public Response getMetadata() {
return getMetadata("northwind-" + Constants.get(version, ConstantKey.METADATA));
}
}

View File

@ -18,7 +18,6 @@
*/
package org.apache.olingo.fit;
import org.apache.olingo.fit.utils.ODataVersion;
import org.apache.olingo.fit.utils.XHTTPMethodInterceptor;
import javax.ws.rs.Path;
import javax.ws.rs.core.Response;
@ -31,15 +30,14 @@ import org.springframework.stereotype.Service;
@Service
@Path("/V40/NorthWindExt.svc")
@InInterceptors(classes = {XHTTPMethodInterceptor.class, ResolvingReferencesInterceptor.class})
public class V4NorthWindExt extends AbstractServices {
public class V4NorthWindExt extends V4Services {
public V4NorthWindExt() throws Exception {
super(ODataVersion.v4);
super();
}
@Override
public Response getMetadata() {
return getMetadata("northwindExt-" + Constants.get(version, ConstantKey.METADATA));
}
}

View File

@ -18,10 +18,11 @@
*/
package org.apache.olingo.fit;
import org.apache.olingo.fit.utils.ODataVersion;
import org.apache.olingo.fit.utils.XHTTPMethodInterceptor;
import javax.ws.rs.Path;
import org.apache.cxf.interceptor.InInterceptors;
import org.apache.olingo.commons.api.data.Feed;
import org.apache.olingo.commons.api.edm.constants.ODataServiceVersion;
import org.apache.olingo.fit.utils.ResolvingReferencesInterceptor;
import org.springframework.stereotype.Service;
@ -31,6 +32,13 @@ import org.springframework.stereotype.Service;
public class V4Services extends AbstractServices {
public V4Services() throws Exception {
super(ODataVersion.v4);
super(ODataServiceVersion.V40);
}
@Override
protected void setInlineCount(final Feed feed, final String count) {
if ("true".equals(count)) {
feed.setCount(feed.getEntries().size());
}
}
}

View File

@ -16,20 +16,14 @@
* specific language governing permissions and limitations
* under the License.
*/
package org.apache.olingo.fit.utils;
package org.apache.olingo.fit.metadata;
public enum ODataVersion {
import org.apache.commons.lang3.builder.ReflectionToStringBuilder;
v3("3.0"),
v4("4.0");
public class AbstractMetadataElement {
private final String version;
private ODataVersion(String version) {
this.version = version;
}
public String getVersion() {
return version;
@Override
public String toString() {
return ReflectionToStringBuilder.toString(this);
}
}

View File

@ -0,0 +1,70 @@
/*
* 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.fit.metadata;
import java.util.LinkedHashMap;
import java.util.Map;
public class Association extends AbstractMetadataElement {
private final String name;
private Map<String, Role> roles;
public Association(final String name) {
this.name = name;
roles = new LinkedHashMap<String, Role>();
}
public String getName() {
return name;
}
public Association addRole(final String name, final String type, final String multiplicity) {
roles.put(name, new Role(name, type, multiplicity));
return this;
}
public Role getRole(final String name) {
return roles.get(name);
}
public static class Role {
final String name;
final String type;
final String multiplicity;
public Role(final String name, final String type, final String multiplicity) {
this.name = name;
this.type = type;
this.multiplicity = multiplicity;
}
public String getType() {
return type;
}
public String getMultiplicity() {
return multiplicity;
}
}
}

View File

@ -0,0 +1,74 @@
/*
* 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.fit.metadata;
import java.util.LinkedHashMap;
import java.util.Map;
public class AssociationSet extends AbstractMetadataElement {
private final String name;
private final String association;
private Map<String, Role> roles;
public AssociationSet(final String name, final String association) {
this.name = name;
this.association = association;
roles = new LinkedHashMap<String, Role>();
}
public String getName() {
return name;
}
public String getAssociation() {
return association;
}
public AssociationSet addRole(final String name, final String entitySet) {
roles.put(name, new Role(name, entitySet));
return this;
}
public Role getRole(final String name) {
return roles.get(name);
}
public static class Role {
final String name;
final String entitySet;
public Role(final String name, final String entitySet) {
this.name = name;
this.entitySet = entitySet;
}
public String getName() {
return name;
}
public String getEntitySet() {
return entitySet;
}
}
}

View File

@ -0,0 +1,76 @@
/*
* 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.fit.metadata;
import java.util.Collection;
import java.util.HashMap;
import java.util.HashSet;
import java.util.Map;
public class Container extends AbstractMetadataElement {
private final String name;
private final Map<String, EntitySet> entitySets;
private final Map<String, AssociationSet> associationSets;
public Container(final String name) {
this.name = name;
entitySets = new HashMap<String, EntitySet>();
associationSets = new HashMap<String, AssociationSet>();
}
public String getName() {
return name;
}
public AssociationSet getAssociationSet(final String association) {
return associationSets.get(association);
}
public Collection<EntitySet> getEntitySets() {
return entitySets.values();
}
public Collection<EntitySet> getEntitySets(final String namespace, final String entityTypeName) {
final Collection<EntitySet> res = new HashSet<EntitySet>();
for (EntitySet entitySet : entitySets.values()) {
if ((namespace + "." + entityTypeName).equals(entitySet.getType())) {
res.add(entitySet);
}
}
return res;
}
public EntitySet getEntitySet(final String name) {
return entitySets.get(name);
}
public Container addEntitySet(final String name, final EntitySet entitySet) {
entitySets.put(name, entitySet);
return this;
}
public Container addAssociationSet(final String name, final AssociationSet associationSet) {
associationSets.put(name, associationSet);
return this;
}
}

View File

@ -0,0 +1,72 @@
/*
* Licensed to the Apache Software Foundation (ASF) under one
* or more contributor license agreements. See the NOTICE file
* distributed with this work for additional information
* regarding copyright ownership. The ASF licenses this file
* to you under the Apache License, Version 2.0 (the
* "License"); you may not use this file except in compliance
* with the License. You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing,
* software distributed under the License is distributed on an
* "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
* KIND, either express or implied. See the License for the
* specific language governing permissions and limitations
* under the License.
*/
package org.apache.olingo.fit.metadata;
import java.util.LinkedHashMap;
import java.util.Map;
public class EntitySet extends AbstractMetadataElement {
private final String name;
private String type;
private final boolean singleton;
// --------------------------
// V4 only
// --------------------------
private final Map<String, String> binding;
// --------------------------
public EntitySet(final String name, final boolean singleton) {
this.name = name;
this.singleton = singleton;
this.binding = new LinkedHashMap<String, String>();
}
public EntitySet(final String name) {
this(name, false);
}
public String getName() {
return name;
}
public String getType() {
return type;
}
public void setType(String type) {
this.type = type;
}
public boolean isSingleton() {
return singleton;
}
public EntitySet addBinding(final String path, final String target) {
this.binding.put(path, target);
return this;
}
public String getTarget(final String path) {
return this.binding.get(path);
}
}

View File

@ -0,0 +1,77 @@
/*
* 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.fit.metadata;
import java.util.Collection;
import java.util.HashMap;
import java.util.HashSet;
import java.util.Map;
public class EntityType extends AbstractMetadataElement {
private final String name;
private final Map<String, Property> properties;
private final Map<String, NavigationProperty> navigationProperties;
public EntityType(final String name) {
this.name = name;
properties = new HashMap<String, Property>();
navigationProperties = new HashMap<String, NavigationProperty>();
}
public String getName() {
return name;
}
public Collection<NavigationProperty> getNavigationProperties() {
return new HashSet<NavigationProperty>(navigationProperties.values());
}
public Map<String, NavigationProperty> getNavigationPropertyMap() {
return new HashMap<String, NavigationProperty>(navigationProperties);
}
public Map<String, Property> getPropertyMap() {
return new HashMap<String, Property>(properties);
}
public Collection<Property> getProperties() {
return new HashSet<Property>(properties.values());
}
public Property getProperty(final String name) {
return properties.get(name);
}
public EntityType addProperty(final String name, final Property property) {
properties.put(name, property);
return this;
}
public NavigationProperty getNavigationProperty(final String name) {
return navigationProperties.get(name);
}
public EntityType addNavigationProperty(final String name, final NavigationProperty property) {
navigationProperties.put(name, property);
return this;
}
}

View File

@ -0,0 +1,354 @@
/*
* 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.fit.metadata;
import java.io.InputStream;
import java.util.Collection;
import java.util.HashMap;
import java.util.Iterator;
import java.util.Map;
import javax.xml.namespace.QName;
import javax.xml.stream.XMLEventReader;
import javax.xml.stream.XMLInputFactory;
import javax.xml.stream.XMLStreamException;
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.codehaus.plexus.util.StringUtils;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
public class Metadata extends AbstractMetadataElement {
/**
* Logger.
*/
protected static final Logger LOG = LoggerFactory.getLogger(Metadata.class);
private final Map<String, Schema> schemas;
public Metadata(final InputStream is) {
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");
try {
while (reader.hasNext()) {
XMLEvent event = reader.nextEvent();
if (event.isStartElement() && event.asStartElement().getName().equals(new QName("Schema"))) {
final Schema schema = getSchema(event.asStartElement(), reader);
schemas.put(schema.getNamespace(), schema);
}
}
} catch (Exception ignore) {
// ignore
} finally {
reader.close();
IOUtils.closeQuietly(is);
}
} catch (Exception e) {
LOG.error("Error parsing metadata", e);
}
for (Map.Entry<String, Schema> schemaEntry : schemas.entrySet()) {
for (EntityType entityType : schemaEntry.getValue().getEntityTypes()) {
for (NavigationProperty property : entityType.getNavigationProperties()) {
if (StringUtils.isNotBlank(property.getReleationship())) {
// V3 ...
final Association association = schemaEntry.getValue().getAssociation(
property.getReleationship().replaceAll(schemaEntry.getKey() + "\\.", ""));
final Association.Role role = association.getRole(property.getToRole());
property.setFeed(role.getMultiplicity().equals("*"));
property.setType(property.isFeed() ? "Collection(" + role.getType() + ")" : role.getType());
// let me assume that it will be just a single container
final AssociationSet associationSet = schemaEntry.getValue().getContainers().iterator().next().
getAssociationSet(property.getReleationship());
final AssociationSet.Role associationSetRole = associationSet.getRole(property.getToRole());
property.setTarget(associationSetRole.getEntitySet());
} else {
// V4 ...
property.setFeed(property.getType().startsWith("Collection("));
final Collection<EntitySet> entitySets = schemaEntry.getValue().getContainers().iterator().next().
getEntitySets(schemaEntry.getKey(), entityType.getName());
final Iterator<EntitySet> iter = entitySets.iterator();
boolean found = false;
while (!found && iter.hasNext()) {
final EntitySet entitySet = iter.next();
final String target = entitySet.getTarget(property.getName());
if (StringUtils.isNotBlank(target)) {
property.setTarget(entitySet.getTarget(property.getName()));
found = true;
}
}
}
}
}
}
}
public EntitySet getEntitySet(final String name) {
for (Schema schema : getSchemas()) {
for (Container container : schema.getContainers()) {
final EntitySet entitySet = container.getEntitySet(name);
if (entitySet != null) {
return entitySet;
}
}
}
return null;
}
public EntityType getEntityType(final String fqn) {
int lastDotIndex = fqn.lastIndexOf('.');
final String ns = fqn.substring(0, lastDotIndex).replaceAll("^#", "");
final String name = fqn.substring(lastDotIndex + 1);
return getSchema(ns).getEntityType(name);
}
public Map<String, NavigationProperty> getNavigationProperties(final String entitySetName) {
for (Schema schema : getSchemas()) {
for (Container container : schema.getContainers()) {
final EntitySet entitySet = container.getEntitySet(entitySetName);
if (entitySet != null) {
final String entityTypeFQN = entitySet.getType();
final int lastDotIndex = entityTypeFQN.lastIndexOf('.');
final String entityTypeNS = entityTypeFQN.substring(0, lastDotIndex);
final String entityTypeName = entityTypeFQN.substring(lastDotIndex + 1);
final EntityType entityType = getSchema(entityTypeNS).getEntityType(entityTypeName);
return entityType.getNavigationPropertyMap();
}
}
}
return null;
}
public Collection<Schema> getSchemas() {
return schemas.values();
}
public Schema getSchema(final String namespace) {
return schemas.get(namespace);
}
public Metadata addSchema(final String namespace, final Schema schema) {
schemas.put(namespace, schema);
return this;
}
private Schema getSchema(final StartElement start, final XMLEventReader reader) throws XMLStreamException {
final Schema schema = new Schema(start.getAttributeByName(new QName("Namespace")).getValue());
boolean completed = false;
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"))) {
final EntityType entityType = getEntityType(event.asStartElement(), reader);
schema.addEntityType(entityType.getName(), entityType);
} else if (event.isStartElement() && event.asStartElement().getName().equals(new QName("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"))) {
// just for V3
final Association association = getAssociation(event.asStartElement(), reader);
schema.addAssociation(association.getName(), association);
} else if (event.isEndElement() && event.asEndElement().getName().equals(start.getName())) {
completed = true;
}
}
return schema;
}
private org.apache.olingo.fit.metadata.Container getContainer(
final StartElement start, final XMLEventReader reader) throws XMLStreamException {
final org.apache.olingo.fit.metadata.Container container =
new org.apache.olingo.fit.metadata.Container(start.getAttributeByName(new QName("Name")).getValue());
boolean completed = false;
while (!completed && reader.hasNext()) {
XMLEvent event = reader.nextEvent();
if (event.isStartElement()
&& (event.asStartElement().getName().equals(new QName("EntitySet"))
|| event.asStartElement().getName().equals(new QName("Singleton")))) {
final EntitySet entitySet = getEntitySet(event.asStartElement(), reader);
container.addEntitySet(entitySet.getName(), entitySet);
} else if (event.isStartElement() && event.asStartElement().getName().equals(new QName("AssociationSet"))) {
// just for V3
final AssociationSet associationSet = getAssociationSet(event.asStartElement(), reader);
container.addAssociationSet(associationSet.getAssociation(), associationSet);
} else if (event.isEndElement() && event.asEndElement().getName().equals(start.getName())) {
completed = true;
}
}
return container;
}
private Association getAssociation(
final StartElement start, final XMLEventReader reader) throws XMLStreamException {
final Association association = new Association(start.getAttributeByName(new QName("Name")).getValue());
boolean completed = false;
while (!completed && reader.hasNext()) {
XMLEvent event = reader.nextEvent();
if (event.isStartElement() && event.asStartElement().getName().equals(new QName("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();
association.addRole(role, type, multiplicity);
} else if (event.isEndElement() && event.asEndElement().getName().equals(start.getName())) {
completed = true;
}
}
return association;
}
private AssociationSet getAssociationSet(
final StartElement start, final XMLEventReader reader) throws XMLStreamException {
final AssociationSet associationSet = new AssociationSet(
start.getAttributeByName(new QName("Name")).getValue(),
start.getAttributeByName(new QName("Association")).getValue());
boolean completed = false;
while (!completed && reader.hasNext()) {
XMLEvent event = reader.nextEvent();
if (event.isStartElement() && event.asStartElement().getName().equals(new QName("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);
} else if (event.isEndElement() && event.asEndElement().getName().equals(start.getName())) {
completed = true;
}
}
return associationSet;
}
private EntityType getEntityType(final StartElement start, final XMLEventReader reader) throws XMLStreamException {
final EntityType entityType = new EntityType(start.getAttributeByName(new QName("Name")).getValue());
boolean completed = false;
while (!completed && reader.hasNext()) {
XMLEvent event = reader.nextEvent();
if (event.isStartElement() && event.asStartElement().getName().equals(new QName("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"))) {
final NavigationProperty property = getNavigationProperty(event.asStartElement());
entityType.addNavigationProperty(property.getName(), property);
} else if (event.isEndElement() && event.asEndElement().getName().equals(start.getName())) {
completed = true;
}
}
return entityType;
}
private org.apache.olingo.fit.metadata.Property getProperty(final StartElement start) throws XMLStreamException {
final org.apache.olingo.fit.metadata.Property property =
new org.apache.olingo.fit.metadata.Property(start.getAttributeByName(new QName("Name")).getValue());
final Attribute type = start.getAttributeByName(new QName("Type"));
property.setType(type == null ? "Edm.String" : type.getValue());
final Attribute nullable = start.getAttributeByName(new QName("Nullable"));
property.setNullable(nullable == null || !"false".equals(nullable.getValue()));
return property;
}
private NavigationProperty getNavigationProperty(final StartElement start) throws XMLStreamException {
final NavigationProperty property = new NavigationProperty(start.getAttributeByName(new QName("Name")).getValue());
final Attribute type = start.getAttributeByName(new QName("Type"));
if (type != null) {
property.setType(type.getValue());
}
final Attribute relationship = start.getAttributeByName(new QName("Relationship"));
if (relationship != null) {
property.setReleationship(relationship.getValue());
}
final Attribute toRole = start.getAttributeByName(new QName("ToRole"));
if (toRole != null) {
property.setToRole(toRole.getValue());
}
return property;
}
private EntitySet getEntitySet(final StartElement start, final XMLEventReader reader) throws XMLStreamException {
final EntitySet entitySet = "Singleton".equals(start.getName().getLocalPart())
? new EntitySet(start.getAttributeByName(new QName("Name")).getValue(), true)
: new EntitySet(start.getAttributeByName(new QName("Name")).getValue());
Attribute type = start.getAttributeByName(new QName("EntityType"));
if (type == null) {
type = start.getAttributeByName(new QName("Type"));
entitySet.setType(type == null ? null : type.getValue());
} else {
entitySet.setType(type.getValue());
}
boolean completed = false;
while (!completed && reader.hasNext()) {
XMLEvent event = reader.nextEvent();
if (event.isStartElement() && event.asStartElement().getName().equals(new QName("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);
} else if (event.isEndElement() && event.asEndElement().getName().equals(start.getName())) {
completed = true;
}
}
return entitySet;
}
}

View File

@ -0,0 +1,86 @@
/*
* 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.fit.metadata;
public class NavigationProperty extends AbstractMetadataElement {
private final String name;
// -----------------------
// just for v3
// -----------------------
private String releationship;
private String toRole;
// -----------------------
private String type;
private String target;
private boolean feed;
public NavigationProperty(final String name) {
this.name = name;
}
public String getName() {
return name;
}
public String getReleationship() {
return releationship;
}
public void setReleationship(String releationship) {
this.releationship = releationship;
}
public String getToRole() {
return toRole;
}
public void setToRole(String toRole) {
this.toRole = toRole;
}
public String getType() {
return type;
}
public void setType(String type) {
this.type = type;
}
public String getTarget() {
return target;
}
public void setTarget(String target) {
this.target = target;
}
public boolean isFeed() {
return feed;
}
public void setFeed(boolean feed) {
this.feed = feed;
}
}

View File

@ -0,0 +1,52 @@
/*
* 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.fit.metadata;
public class Property extends AbstractMetadataElement {
private final String name;
private String type;
private boolean nullable;
public Property(String name) {
this.name = name;
}
public String getName() {
return name;
}
public String getType() {
return type;
}
public void setType(String type) {
this.type = type;
}
public boolean isNullable() {
return nullable;
}
public void setNullable(boolean nullable) {
this.nullable = nullable;
}
}

View File

@ -0,0 +1,80 @@
/*
* 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.fit.metadata;
import java.util.Collection;
import java.util.HashMap;
import java.util.Map;
public class Schema extends AbstractMetadataElement {
private final String namespace;
private final Map<String, Container> containers;
private final Map<String, Association> associations;
private final Map<String, EntityType> entityTypes;
public Schema(final String namespace) {
this.namespace = namespace;
entityTypes = new HashMap<String, EntityType>();
this.containers = new HashMap<String, Container>();
this.associations = new HashMap<String, Association>();
}
public String getNamespace() {
return namespace;
}
public Collection<EntityType> getEntityTypes() {
return entityTypes.values();
}
public EntityType getEntityType(final String name) {
return entityTypes.get(name);
}
public Schema addEntityType(final String name, final EntityType entityType) {
entityTypes.put(name, entityType);
return this;
}
public Collection<Container> getContainers() {
return containers.values();
}
public Container getContainer(final String name) {
return containers.get(name);
}
public Schema addContainer(final String name, final Container container) {
containers.put(name, container);
return this;
}
public Association getAssociation(final String name) {
return associations.get(name);
}
public Schema addAssociation(final String name, final Association association) {
associations.put(name, association);
return this;
}
}

View File

@ -0,0 +1,35 @@
/*
* 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.fit.serializer;
import com.fasterxml.jackson.databind.annotation.JsonDeserialize;
import com.fasterxml.jackson.databind.annotation.JsonSerialize;
import java.net.URI;
import org.apache.olingo.commons.api.data.Container;
import org.apache.olingo.commons.core.data.JSONEntryDeserializer;
import org.apache.olingo.commons.core.data.JSONEntrySerializer;
@JsonDeserialize(using = JSONEntryDeserializer.class)
@JsonSerialize(using = JSONEntrySerializer.class)
public class JsonEntryContainer<T> extends Container<T> {
public JsonEntryContainer(final URI contextURL, final String metadataETag, final T object) {
super(contextURL, metadataETag, object);
}
}

View File

@ -0,0 +1,35 @@
/*
* 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.fit.serializer;
import com.fasterxml.jackson.databind.annotation.JsonDeserialize;
import com.fasterxml.jackson.databind.annotation.JsonSerialize;
import java.net.URI;
import org.apache.olingo.commons.api.data.Container;
import org.apache.olingo.commons.core.data.JSONFeedDeserializer;
import org.apache.olingo.commons.core.data.JSONFeedSerializer;
@JsonDeserialize(using = JSONFeedDeserializer.class)
@JsonSerialize(using = JSONFeedSerializer.class)
public class JsonFeedContainer<T> extends Container<T> {
public JsonFeedContainer(final URI contextURL, final String metadataETag, final T object) {
super(contextURL, metadataETag, object);
}
}

View File

@ -38,10 +38,13 @@ import java.util.Set;
import javax.ws.rs.NotFoundException;
import org.apache.commons.io.IOUtils;
import org.apache.commons.lang3.StringUtils;
import org.apache.olingo.commons.api.edm.constants.ODataServiceVersion;
import org.apache.olingo.fit.metadata.Metadata;
import org.apache.olingo.fit.metadata.NavigationProperty;
public abstract class AbstractJSONUtilities extends AbstractUtilities {
public AbstractJSONUtilities(final ODataVersion version) throws Exception {
public AbstractJSONUtilities(final ODataServiceVersion version) throws Exception {
super(version);
}
@ -109,6 +112,9 @@ public abstract class AbstractJSONUtilities extends AbstractUtilities {
final Iterator<Map.Entry<String, JsonNode>> fieldIter = srcNode.fields();
final Metadata metadata = Commons.getMetadata(version);
final Map<String, NavigationProperty> navigationProperties = metadata.getNavigationProperties(entitySetName);
while (fieldIter.hasNext()) {
final Map.Entry<String, JsonNode> field = fieldIter.next();
if (field.getKey().endsWith(Constants.get(version, ConstantKey.JSON_NAVIGATION_BIND_SUFFIX))) {
@ -125,7 +131,7 @@ public abstract class AbstractJSONUtilities extends AbstractUtilities {
}
links.addLinks(title, hrefs);
} else if (Commons.linkInfo.get(version).exists(entitySetName, field.getKey())) {
} else if (navigationProperties.containsKey(field.getKey())) {
links.addInlines(field.getKey(), IOUtils.toInputStream(field.getValue().toString(), "UTf-8"));
}
}
@ -170,7 +176,7 @@ public abstract class AbstractJSONUtilities extends AbstractUtilities {
srcNode.set(
Constants.get(version, ConstantKey.JSON_EDITLINK_NAME), new TextNode(
Constants.get(version, ConstantKey.DEFAULT_SERVICE_URL) + entitySetName + "(" + entityKey + ")"));
Constants.get(version, ConstantKey.DEFAULT_SERVICE_URL) + entitySetName + "(" + entityKey + ")"));
return IOUtils.toInputStream(srcNode.toString(), "UTf-8");
}

View File

@ -40,7 +40,10 @@ import javax.ws.rs.core.Response;
import org.apache.commons.io.IOUtils;
import org.apache.commons.lang3.StringUtils;
import org.apache.commons.vfs2.FileObject;
import org.apache.olingo.commons.api.edm.constants.ODataServiceVersion;
import org.apache.olingo.fit.UnsupportedMediaTypeException;
import org.apache.olingo.fit.metadata.Metadata;
import org.apache.olingo.fit.metadata.NavigationProperty;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
@ -51,13 +54,13 @@ public abstract class AbstractUtilities {
*/
protected static final Logger LOG = LoggerFactory.getLogger(AbstractUtilities.class);
protected final ODataVersion version;
protected final ODataServiceVersion version;
protected final FSManager fsManager;
protected final static Pattern entityUriPattern = Pattern.compile(".*\\/.*\\(.*\\)");
public AbstractUtilities(final ODataVersion version) throws Exception {
public AbstractUtilities(final ODataServiceVersion version) throws Exception {
this.version = version;
this.fsManager = FSManager.instance(version);
}
@ -168,12 +171,15 @@ public abstract class AbstractUtilities {
IOUtils.copy(is, bos);
IOUtils.closeQuietly(is);
final Map<String, NavigationProperty> navigationProperties =
Commons.getMetadata(version).getNavigationProperties(entitySetName);
// -----------------------------------------
// 0. Retrieve navigation links to be mantained
// -----------------------------------------
Set<String> linksToBeMantained;
try {
linksToBeMantained = Commons.linkInfo.get(version).getNavigationLinkNames(entitySetName);
linksToBeMantained = new HashSet<String>(navigationProperties.keySet());
} catch (Exception e) {
linksToBeMantained = Collections.<String>emptySet();
}
@ -195,7 +201,7 @@ public abstract class AbstractUtilities {
// 1. Get default entry key and path (N.B. operation will consume/close the stream; use a copy instead)
// -----------------------------------------
final String entityKey = key == null ? getDefaultEntryKey(
entitySetName, new ByteArrayInputStream(bos.toByteArray()), getDefaultFormat()) : key;
entitySetName, new ByteArrayInputStream(bos.toByteArray())) : key;
final String path = Commons.getEntityBasePath(entitySetName, entityKey);
// -----------------------------------------
@ -236,14 +242,13 @@ public abstract class AbstractUtilities {
// -----------------------------------------
// 4. Create links file and provided inlines
// -----------------------------------------
// -----------------------------------------
for (Map.Entry<String, List<String>> link : links.getLinks()) {
putLinksInMemory(path, entitySetName, entityKey, link.getKey(), link.getValue());
}
for (Map.Entry<String, List<InputStream>> inlineEntry : links.getInlines()) {
final String inlineEntitySetName =
Commons.linkInfo.get(version).getTargetName(entitySetName, inlineEntry.getKey());
final String inlineEntitySetName = navigationProperties.get(inlineEntry.getKey()).getTarget();
final List<String> hrefs = new ArrayList<String>();
@ -253,7 +258,7 @@ public abstract class AbstractUtilities {
IOUtils.closeQuietly(stream);
final String inlineEntryKey = getDefaultEntryKey(
inlineEntitySetName, new ByteArrayInputStream(inlineBos.toByteArray()), getDefaultFormat());
inlineEntitySetName, new ByteArrayInputStream(inlineBos.toByteArray()));
addOrReplaceEntity(
inlineEntryKey,
@ -270,14 +275,14 @@ public abstract class AbstractUtilities {
return fo.getContent().getInputStream();
}
public InputStream addMediaEntity(
public void addMediaEntityValue(
final String entitySetName,
final String entityKey,
final InputStream is) throws Exception {
// -----------------------------------------
// 0. Get default entry key and path (N.B. operation will consume/close the stream; use a copy instead)
// -----------------------------------------
final String entityKey = getDefaultEntryKey(entitySetName, null, getDefaultFormat());
final String path = Commons.getEntityBasePath(entitySetName, entityKey);
// -----------------------------------------
@ -288,6 +293,17 @@ public abstract class AbstractUtilities {
+ Constants.get(version, ConstantKey.MEDIA_CONTENT_FILENAME), null));
IOUtils.closeQuietly(is);
// -----------------------------------------
}
public InputStream addMediaEntity(
final String entitySetName,
final InputStream is) throws Exception {
final String entityKey = getDefaultEntryKey(entitySetName, null);
addMediaEntityValue(entitySetName, entityKey, is);
final String path = Commons.getEntityBasePath(entitySetName, entityKey);
// -----------------------------------------
// 2. save entity as atom
@ -334,7 +350,7 @@ public abstract class AbstractUtilities {
fsManager.putInMemory(
IOUtils.toInputStream(entity), fsManager.getAbsolutePath(path + Constants.get(version, ConstantKey.ENTITY),
Accept.JSON_FULLMETA));
Accept.JSON_FULLMETA));
// -----------------------------------------
return readEntity(entitySetName, entityKey, getDefaultFormat()).getValue();
@ -349,7 +365,10 @@ public abstract class AbstractUtilities {
final HashSet<String> uris = new HashSet<String>();
if (Commons.linkInfo.get(version).isFeed(entitySetName, linkName)) {
final Metadata metadata = Commons.getMetadata(version);
final Map<String, NavigationProperty> navigationProperties = metadata.getNavigationProperties(entitySetName);
if (navigationProperties.get(linkName).isFeed()) {
try {
final Map.Entry<String, List<String>> currents = extractLinkURIs(entitySetName, entityKey, linkName);
uris.addAll(currents.getValue());
@ -383,8 +402,8 @@ public abstract class AbstractUtilities {
public Response createResponse(
final InputStream entity, final String etag, final Accept accept, final Response.Status status) {
final Response.ResponseBuilder builder = Response.ok();
if (version == ODataVersion.v3) {
builder.header(Constants.get(version, ConstantKey.ODATA_SERVICE_VERSION), version.getVersion() + ";");
if (version.compareTo(ODataServiceVersion.V30) <= 0) {
builder.header(Constants.get(version, ConstantKey.ODATA_SERVICE_VERSION), version.toString() + ";");
}
if (StringUtils.isNotBlank(etag)) {
@ -432,7 +451,7 @@ public abstract class AbstractUtilities {
LOG.debug("Create fault response about .... ", e);
final Response.ResponseBuilder builder = Response.serverError();
if (version == ODataVersion.v3) {
if (version.compareTo(ODataServiceVersion.V30) <= 0) {
builder.header(Constants.get(version, ConstantKey.ODATA_SERVICE_VERSION), version + ";");
}
@ -441,7 +460,7 @@ public abstract class AbstractUtilities {
if (accept.startsWith("application/json")) {
ext = ".json";
contentType = Accept.JSON;
} else if (accept.startsWith("application/xml") || version == ODataVersion.v3) {
} else if (accept.startsWith("application/xml") || version.compareTo(ODataServiceVersion.V30) <= 0) {
ext = ".xml";
contentType = Accept.XML;
} else {
@ -470,8 +489,8 @@ public abstract class AbstractUtilities {
return builder.build();
}
protected String getDefaultEntryKey(
final String entitySetName, final InputStream entity, final Accept accept) throws IOException {
public String getDefaultEntryKey(
final String entitySetName, final InputStream entity) throws IOException {
try {
String res;
@ -649,7 +668,10 @@ public abstract class AbstractUtilities {
final LinkInfo linkInfo = new LinkInfo(fsManager.readFile(basePath + linkName, accept));
linkInfo.setEtag(Commons.getETag(basePath, version));
linkInfo.setFeed(Commons.linkInfo.get(version).isFeed(entitySetName, linkName));
final Metadata metadata = Commons.getMetadata(version);
final Map<String, NavigationProperty> navigationProperties = metadata.getNavigationProperties(entitySetName);
linkInfo.setFeed(navigationProperties.get(linkName.replaceAll("\\(.*\\)", "")).isFeed());
return linkInfo;
}
@ -695,31 +717,38 @@ public abstract class AbstractUtilities {
public InputStream expandEntity(
final String entitySetName,
final String entityId,
final InputStream entity,
final String linkName)
throws Exception {
// --------------------------------
// 0. Retrieve all 'linkName' navigation link uris (NotFoundException if missing)
// --------------------------------
final LinkInfo linkInfo = readLinks(entitySetName, entityId, linkName, Accept.XML);
final Map.Entry<String, List<String>> links = extractLinkURIs(entitySetName, entityId, linkName);
// --------------------------------
// --------------------------------
// 1. Retrieve expanded object (entry or feed)
// --------------------------------
final InputStream expanded = readEntities(
final Metadata metadata = Commons.getMetadata(version);
final Map<String, NavigationProperty> navigationProperties = metadata.getNavigationProperties(entitySetName);
return readEntities(
links.getValue(),
linkName,
links.getKey(),
linkInfo.isFeed());
// --------------------------------
navigationProperties.get(linkName).isFeed());
}
public InputStream expandEntity(
final String entitySetName,
final String entityId,
final InputStream entity,
final String linkName)
throws Exception {
// --------------------------------
// 2. Retrieve expanded object (entry or feed)
// --------------------------------
return replaceLink(entity, linkName, expanded);
return replaceLink(entity, linkName, expandEntity(entitySetName, entityId, linkName));
// --------------------------------
}

View File

@ -52,6 +52,9 @@ import org.apache.commons.io.IOUtils;
import org.apache.commons.lang3.StringUtils;
import org.apache.commons.vfs2.FileObject;
import org.apache.commons.vfs2.FileSystemException;
import org.apache.olingo.commons.api.edm.constants.ODataServiceVersion;
import org.apache.olingo.fit.metadata.Metadata;
import org.apache.olingo.fit.metadata.NavigationProperty;
public abstract class AbstractXMLUtilities extends AbstractUtilities {
@ -59,12 +62,10 @@ public abstract class AbstractXMLUtilities extends AbstractUtilities {
protected static XMLOutputFactory ofactory = null;
public AbstractXMLUtilities(final ODataVersion version) throws Exception {
public AbstractXMLUtilities(final ODataServiceVersion version) throws Exception {
super(version);
}
public abstract void retrieveLinkInfoFromMetadata() throws Exception;
@Override
protected Accept getDefaultFormat() {
return Accept.ATOM;
@ -146,6 +147,9 @@ public abstract class AbstractXMLUtilities extends AbstractUtilities {
writer.add(entry.getValue().getStart());
final Metadata metadata = Commons.getMetadata(version);
final Map<String, NavigationProperty> navigationProperties = metadata.getNavigationProperties(entitySetName);
// add for links
for (String link : links) {
final Set<Attribute> attributes = new HashSet<Attribute>();
@ -155,7 +159,7 @@ public abstract class AbstractXMLUtilities extends AbstractUtilities {
attributes.add(eventFactory.createAttribute(new QName("rel"),
Constants.get(version, ConstantKey.ATOM_LINK_REL) + link));
attributes.add(eventFactory.createAttribute(new QName("type"),
Commons.linkInfo.get(version).isFeed(entitySetName, link)
navigationProperties.get(link).isFeed()
? Constants.get(version, ConstantKey.ATOM_LINK_FEED)
: Constants.get(version, ConstantKey.ATOM_LINK_ENTRY)));
@ -192,7 +196,7 @@ public abstract class AbstractXMLUtilities 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();
@ -243,7 +247,7 @@ public abstract class AbstractXMLUtilities extends AbstractUtilities {
try {
final XmlElement inlineElement =
extractElement(link.getContentReader(), null,
Collections.<String>singletonList(Constants.get(version, ConstantKey.INLINE)), 0, -1, -1).
Collections.<String>singletonList(Constants.get(version, ConstantKey.INLINE)), 0, -1, -1).
getValue();
final XMLEventReader inlineReader = inlineElement.getContentReader();
@ -447,7 +451,7 @@ public abstract class AbstractXMLUtilities 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), writer);
writer.add(reader);
@ -540,7 +544,7 @@ public abstract class AbstractXMLUtilities 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\">"),
@ -795,7 +799,7 @@ public abstract class AbstractXMLUtilities 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
@ -803,13 +807,13 @@ public abstract class AbstractXMLUtilities 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) {
@ -826,7 +830,7 @@ public abstract class AbstractXMLUtilities 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;
}
@ -894,10 +898,10 @@ public abstract class AbstractXMLUtilities 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) {
@ -934,7 +938,7 @@ public abstract class AbstractXMLUtilities 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();
@ -958,7 +962,7 @@ public abstract class AbstractXMLUtilities 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(),
@ -988,7 +992,7 @@ public abstract class AbstractXMLUtilities extends AbstractUtilities {
// ---------------------------------
Map.Entry<Integer, XmlElement> propertyElement =
extractElement(reader, writer,
Collections.<String>singletonList(Constants.get(version, ConstantKey.PROPERTIES)), 0, 2, 3);
Collections.<String>singletonList(Constants.get(version, ConstantKey.PROPERTIES)), 0, 2, 3);
writer.flush();
@ -1121,9 +1125,9 @@ public abstract class AbstractXMLUtilities 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());
// ------------------------------------------
@ -1234,7 +1238,7 @@ public abstract class AbstractXMLUtilities extends AbstractUtilities {
final InputStream src =
fsManager.readFile(Commons.getEntityBasePath(entitySetName, entityId)
+ Constants.get(version, ConstantKey.ENTITY), Accept.XML);
+ Constants.get(version, ConstantKey.ENTITY), Accept.XML);
final XMLEventReader reader = getEventReader(src);
final XmlElement property = extractElement(reader, null, pathElements, 0, 3, 4).getValue();

View File

@ -21,6 +21,7 @@ package org.apache.olingo.fit.utils;
import java.util.regex.Pattern;
import org.apache.commons.lang3.StringUtils;
import org.apache.http.entity.ContentType;
import org.apache.olingo.commons.api.edm.constants.ODataServiceVersion;
import org.apache.olingo.fit.UnsupportedMediaTypeException;
public enum Accept {
@ -55,17 +56,17 @@ public enum Accept {
this.fileExtension = fileExtension;
}
public String toString(final ODataVersion version) {
return ODataVersion.v3 == version ? contentTypeV3 : contentTypeV4;
public String toString(final ODataServiceVersion version) {
return version.compareTo(ODataServiceVersion.V40) >= 0 ? contentTypeV4 : contentTypeV3;
}
public String getExtension() {
return fileExtension;
}
public static Accept parse(final String contentType, final ODataVersion version) {
public static Accept parse(final String contentType, final ODataServiceVersion version) {
final Accept def;
if (ODataVersion.v3 == version) {
if (version.compareTo(ODataServiceVersion.V30) <= 0) {
def = ATOM;
} else {
def = JSON_NOMETA;
@ -74,7 +75,7 @@ public enum Accept {
return parse(contentType, version, def);
}
public static Accept parse(final String contentType, final ODataVersion version, final Accept def) {
public static Accept parse(final String contentType, final ODataServiceVersion version, final Accept def) {
if (StringUtils.isBlank(contentType) || allTypesPattern.matcher(contentType).matches()) {
return def;
} else if (JSON_NOMETA.toString(version).equals(contentType)) {

View File

@ -18,6 +18,8 @@
*/
package org.apache.olingo.fit.utils;
import com.fasterxml.jackson.annotation.JsonInclude;
import com.fasterxml.jackson.databind.InjectableValues;
import com.fasterxml.jackson.databind.JsonNode;
import com.fasterxml.jackson.databind.ObjectMapper;
import com.fasterxml.jackson.databind.node.ArrayNode;
@ -39,6 +41,11 @@ import java.util.List;
import java.util.Map;
import java.util.regex.Pattern;
import org.apache.commons.io.IOUtils;
import org.apache.olingo.commons.api.edm.constants.ODataServiceVersion;
import org.apache.olingo.commons.core.data.AtomDeserializer;
import org.apache.olingo.commons.core.data.AtomSerializer;
import org.apache.olingo.commons.core.op.InjectableSerializerProvider;
import org.apache.olingo.fit.metadata.Metadata;
import org.codehaus.plexus.util.StringUtils;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
@ -50,15 +57,24 @@ public abstract class Commons {
*/
protected static final Logger LOG = LoggerFactory.getLogger(Commons.class);
private static Map<ODataServiceVersion, AtomDeserializer> atomDeserializer =
new EnumMap<ODataServiceVersion, AtomDeserializer>(ODataServiceVersion.class);
private static Map<ODataServiceVersion, AtomSerializer> atomSerializer =
new EnumMap<ODataServiceVersion, AtomSerializer>(ODataServiceVersion.class);
private static Map<ODataServiceVersion, ObjectMapper> jsonmapper =
new EnumMap<ODataServiceVersion, ObjectMapper>(ODataServiceVersion.class);
private static EnumMap<ODataServiceVersion, Metadata> metadata =
new EnumMap<ODataServiceVersion, Metadata>(ODataServiceVersion.class);
protected static Pattern multiKeyPattern = Pattern.compile("(.*=.*,?)+");
protected final static Map<String, Integer> sequence = new HashMap<String, Integer>();
protected final static Map<String, String> mediaContent = new HashMap<String, String>();
protected final static Map<ODataVersion, MetadataLinkInfo> linkInfo =
new EnumMap<ODataVersion, MetadataLinkInfo>(ODataVersion.class);
static {
sequence.put("Customer", 1000);
sequence.put("CustomerInfo", 1000);
@ -75,8 +91,56 @@ public abstract class Commons {
mediaContent.put("Car/Photo", null);
}
public static Map<ODataVersion, MetadataLinkInfo> getLinkInfo() {
return linkInfo;
public static AtomDeserializer getAtomDeserializer(final ODataServiceVersion version) {
if (!atomDeserializer.containsKey(version)) {
atomDeserializer.put(version, new AtomDeserializer(version));
}
return atomDeserializer.get(version);
}
public static AtomSerializer getAtomSerializer(final ODataServiceVersion version) {
if (!atomSerializer.containsKey(version)) {
atomSerializer.put(version, new AtomSerializer(version, true));
}
return atomSerializer.get(version);
}
public static ObjectMapper getJsonMapper(final ODataServiceVersion version) {
if (!jsonmapper.containsKey(version)) {
final ObjectMapper mapper = new ObjectMapper().setSerializationInclusion(JsonInclude.Include.NON_NULL);
mapper.setInjectableValues(new InjectableValues.Std()
.addValue(Boolean.class, Boolean.TRUE)
.addValue(ODataServiceVersion.class, version));
mapper.setSerializerProvider(new InjectableSerializerProvider(mapper.getSerializerProvider(),
mapper.getSerializationConfig()
.withAttribute(ODataServiceVersion.class, version)
.withAttribute(Boolean.class, Boolean.TRUE),
mapper.getSerializerFactory()));
jsonmapper.put(version, mapper);
}
return jsonmapper.get(version);
}
public static Metadata getMetadata(final ODataServiceVersion version) {
if (!metadata.containsKey(version)) {
final InputStream is = Commons.class.getResourceAsStream(
File.separatorChar
+ version.name()
+ File.separatorChar + "metadata.xml");
metadata.put(version, new Metadata(is));
}
return metadata.get(version);
}
public static Map<String, String> getMediaContent() {
return mediaContent;
}
public static String getEntityURI(final String entitySetName, final String entityKey) {
@ -91,7 +155,7 @@ public abstract class Commons {
}
public static String getLinksURI(
final ODataVersion version,
final ODataServiceVersion version,
final String entitySetName,
final String entityId,
final String linkName) throws IOException {
@ -99,22 +163,22 @@ public abstract class Commons {
}
public static String getLinksPath(
final ODataVersion version,
final ODataServiceVersion version,
final String entitySetName,
final String entityId,
final String linkName,
final Accept accept) throws IOException {
return getLinksPath(ODataVersion.v3, getEntityBasePath(entitySetName, entityId), linkName, accept);
return getLinksPath(ODataServiceVersion.V30, getEntityBasePath(entitySetName, entityId), linkName, accept);
}
public static String getLinksPath(
final ODataVersion version, final String basePath, final String linkName, final Accept accept)
final ODataServiceVersion version, final String basePath, final String linkName, final Accept accept)
throws IOException {
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);
}
@ -255,7 +319,7 @@ public abstract class Commons {
return node;
}
public static String getETag(final String basePath, final ODataVersion version) throws Exception {
public static String getETag(final String basePath, final ODataServiceVersion version) throws Exception {
try {
final InputStream is = FSManager.instance(version).readFile(basePath + "etag", Accept.TEXT);
if (is.available() <= 0) {

View File

@ -18,8 +18,10 @@
*/
package org.apache.olingo.fit.utils;
import java.nio.charset.Charset;
import java.util.EnumMap;
import java.util.Map;
import org.apache.olingo.commons.api.edm.constants.ODataServiceVersion;
public class Constants {
@ -27,6 +29,8 @@ public class Constants {
private final static Map<ConstantKey, String> constants = new EnumMap<ConstantKey, String>(ConstantKey.class);
public static Charset encoding = Charset.forName("UTF-8");
static {
// -----------------------------
@ -93,8 +97,8 @@ public class Constants {
return get(null, key);
}
public static String get(final ODataVersion version, final ConstantKey key) {
return (version == null || version == ODataVersion.v3 || !v4constants.containsKey(key)
public static String get(final ODataServiceVersion version, final ConstantKey key) {
return (version == null || version.compareTo(ODataServiceVersion.V30) <= 0 || !v4constants.containsKey(key)
? constants : v4constants).get(key);
}
}

View File

@ -0,0 +1,276 @@
/*
* 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.fit.utils;
import java.net.URI;
import java.util.Collection;
import java.util.List;
import java.util.Map;
import org.apache.commons.lang3.StringUtils;
import org.apache.olingo.commons.api.data.Entry;
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.data.Value;
import org.apache.olingo.commons.api.edm.constants.ODataServiceVersion;
import org.apache.olingo.commons.core.data.AtomEntryImpl;
import org.apache.olingo.commons.core.data.AtomFeedImpl;
import org.apache.olingo.commons.core.data.AtomPropertyImpl;
import org.apache.olingo.commons.core.data.CollectionValueImpl;
import org.apache.olingo.commons.core.data.ComplexValueImpl;
import org.apache.olingo.commons.core.data.JSONEntryImpl;
import org.apache.olingo.commons.core.data.JSONFeedImpl;
import org.apache.olingo.commons.core.data.JSONPropertyImpl;
import org.apache.olingo.commons.core.data.LinkImpl;
import org.apache.olingo.fit.metadata.Metadata;
import org.apache.olingo.fit.metadata.NavigationProperty;
import org.springframework.beans.BeanUtils;
public class DataBinder {
private final ODataServiceVersion version;
public DataBinder(final ODataServiceVersion version) {
this.version = version;
}
public JSONFeedImpl getJsonFeed(final AtomFeedImpl atomfeed) {
final JSONFeedImpl jsonfeed = new JSONFeedImpl();
BeanUtils.copyProperties(atomfeed, jsonfeed, "baseURI", "metadataContextURL");
jsonfeed.setMetadataContextURL(atomfeed.getBaseURI() == null
? null
: URI.create(atomfeed.getBaseURI().toASCIIString() + "/$metadata").normalize());
final Collection<Entry> entries = jsonfeed.getEntries();
for (Entry entry : atomfeed.getEntries()) {
entries.add(getJsonEntry((AtomEntryImpl) entry));
}
return jsonfeed;
}
public AtomFeedImpl getAtomFeed(final JSONFeedImpl jsonfeed) {
final AtomFeedImpl atomfeed = new AtomFeedImpl();
BeanUtils.copyProperties(jsonfeed, atomfeed, "baseURI", "metadataContextURL");
atomfeed.setBaseURI(jsonfeed.getBaseURI() == null
? null
: jsonfeed.getBaseURI().toASCIIString() + "/$metadata");
final Collection<Entry> entries = atomfeed.getEntries();
for (Entry entry : jsonfeed.getEntries()) {
entries.add(getAtomEntry((JSONEntryImpl) entry));
}
return atomfeed;
}
public JSONEntryImpl getJsonEntry(final AtomEntryImpl atomentry) {
final JSONEntryImpl jsonentry = new JSONEntryImpl();
BeanUtils.copyProperties(atomentry, jsonentry, "baseURI", "properties", "links");
jsonentry.setBaseURI(atomentry.getBaseURI() == null ? null : atomentry.getBaseURI().toASCIIString());
for (Link link : atomentry.getNavigationLinks()) {
final Link jlink = new LinkImpl();
jlink.setHref(link.getHref());
jlink.setTitle(link.getTitle());
jlink.setType(link.getType());
jlink.setRel(link.getRel());
if (link.getInlineEntry() instanceof AtomEntryImpl) {
Entry inlineEntry = link.getInlineEntry();
if (inlineEntry instanceof AtomEntryImpl) {
jlink.setInlineEntry(getJsonEntry((AtomEntryImpl) link.getInlineEntry()));
}
} else if (link.getInlineFeed() instanceof AtomFeedImpl) {
Feed inlineFeed = link.getInlineFeed();
if (inlineFeed instanceof AtomFeedImpl) {
jlink.setInlineFeed(getJsonFeed((AtomFeedImpl) link.getInlineFeed()));
}
}
jsonentry.getNavigationLinks().add(jlink);
}
final Collection<Property> properties = jsonentry.getProperties();
for (Property property : atomentry.getProperties()) {
properties.add(getJsonProperty((AtomPropertyImpl) property));
}
return jsonentry;
}
public AtomEntryImpl getAtomEntry(final JSONEntryImpl jsonentry) {
final AtomEntryImpl atomentry = new AtomEntryImpl();
final Metadata metadata = Commons.getMetadata(version);
BeanUtils.copyProperties(jsonentry, atomentry, "baseURI", "properties", "links");
atomentry.setBaseURI(jsonentry.getBaseURI() == null ? null : jsonentry.getBaseURI().toASCIIString());
for (Link link : jsonentry.getNavigationLinks()) {
final Link alink = new LinkImpl();
alink.setHref(link.getHref());
alink.setTitle(link.getTitle());
alink.setType(metadata.getEntityType(jsonentry.getType()).getNavigationProperty(link.getTitle()).isFeed()
? Constants.get(ConstantKey.ATOM_LINK_FEED) : Constants.get(ConstantKey.ATOM_LINK_ENTRY));
alink.setRel(link.getRel());
if (link.getInlineEntry() instanceof JSONEntryImpl) {
Entry inlineEntry = link.getInlineEntry();
if (inlineEntry instanceof JSONEntryImpl) {
alink.setInlineEntry(getAtomEntry((JSONEntryImpl) link.getInlineEntry()));
}
} else if (link.getInlineFeed() instanceof JSONFeedImpl) {
Feed inlineFeed = link.getInlineFeed();
if (inlineFeed instanceof JSONFeedImpl) {
alink.setInlineFeed(getAtomFeed((JSONFeedImpl) link.getInlineFeed()));
}
}
atomentry.getNavigationLinks().add(alink);
}
final Map<String, NavigationProperty> navProperties =
metadata.getEntityType(jsonentry.getType()).getNavigationPropertyMap();
final List<Property> properties = atomentry.getProperties();
for (Property property : jsonentry.getProperties()) {
if (navProperties.containsKey(property.getName())) {
final Link alink = new LinkImpl();
alink.setTitle(property.getName());
alink.setType(navProperties.get(property.getName()).isFeed()
? Constants.get(ConstantKey.ATOM_LINK_FEED)
: Constants.get(ConstantKey.ATOM_LINK_ENTRY));
alink.setRel(Constants.get(ConstantKey.ATOM_LINK_REL) + property.getName());
if (property.getValue().isComplex()) {
final Entry inline = new AtomEntryImpl();
inline.setType(navProperties.get(property.getName()).getType());
for (Property prop : property.getValue().asComplex().get()) {
inline.getProperties().add(prop);
}
alink.setInlineEntry(inline);
} else if (property.getValue().isCollection()) {
final Feed inline = new AtomFeedImpl();
for (Value entry : property.getValue().asCollection().get()) {
final Entry inlineEntry = new AtomEntryImpl();
inlineEntry.setType(navProperties.get(property.getName()).getType());
for (Property prop : entry.asComplex().get()) {
inlineEntry.getProperties().add(prop);
}
inline.getEntries().add(inlineEntry);
}
alink.setInlineFeed(inline);
} else {
throw new IllegalStateException("Invalid navigation property " + property);
}
atomentry.getNavigationLinks().add(alink);
} else {
properties.add(getAtomProperty((JSONPropertyImpl) property, atomentry.getType()));
}
}
return atomentry;
}
public JSONPropertyImpl getJsonProperty(final AtomPropertyImpl atomproperty) {
final JSONPropertyImpl jsonproperty = new JSONPropertyImpl();
BeanUtils.copyProperties(atomproperty, jsonproperty, "value");
if (atomproperty.getValue() instanceof ComplexValueImpl) {
final ComplexValueImpl complex = new ComplexValueImpl();
jsonproperty.setValue(complex);
for (Property field : atomproperty.getValue().asComplex().get()) {
complex.get().add(getJsonProperty((AtomPropertyImpl) field));
}
} else if (atomproperty.getValue() instanceof CollectionValueImpl) {
final CollectionValueImpl collection = new CollectionValueImpl();
jsonproperty.setValue(collection);
for (Value element : atomproperty.getValue().asCollection().get()) {
if (element instanceof ComplexValueImpl) {
final ComplexValueImpl complex = new ComplexValueImpl();
collection.get().add(complex);
for (Property field : element.asComplex().get()) {
complex.get().add(getJsonProperty((AtomPropertyImpl) field));
}
} else {
collection.get().add(element);
}
}
} else {
jsonproperty.setValue(atomproperty.getValue());
}
return jsonproperty;
}
public AtomPropertyImpl getAtomProperty(final JSONPropertyImpl jsonproperty, final String entryType) {
final AtomPropertyImpl atomproperty = new AtomPropertyImpl();
atomproperty.setName(jsonproperty.getName());
if (StringUtils.isNotBlank(jsonproperty.getType())) {
atomproperty.setType(jsonproperty.getType());
} else {
atomproperty.setType(
Commons.getMetadata(version).getEntityType(entryType).getProperty(jsonproperty.getName()).getType());
}
if (jsonproperty.getValue() instanceof ComplexValueImpl) {
final ComplexValueImpl complex = new ComplexValueImpl();
atomproperty.setValue(complex);
for (Property field : jsonproperty.getValue().asComplex().get()) {
complex.get().add(getAtomProperty((JSONPropertyImpl) field, atomproperty.getType()));
}
} else if (jsonproperty.getValue() instanceof CollectionValueImpl) {
final CollectionValueImpl collection = new CollectionValueImpl();
atomproperty.setValue(collection);
for (Value element : jsonproperty.getValue().asCollection().get()) {
if (element instanceof ComplexValueImpl) {
final ComplexValueImpl complex = new ComplexValueImpl();
collection.get().add(complex);
for (Property field : element.asComplex().get()) {
complex.get().add(getAtomProperty((JSONPropertyImpl) field,
atomproperty.getType().replaceAll("^Collection\\(", "").replaceAll("\\)$", "")));
}
} else {
collection.get().add(element);
}
}
} else {
atomproperty.setValue(jsonproperty.getValue());
}
return atomproperty;
}
}

View File

@ -18,10 +18,14 @@
*/
package org.apache.olingo.fit.utils;
import com.fasterxml.jackson.databind.ObjectMapper;
import java.io.ByteArrayInputStream;
import java.io.ByteArrayOutputStream;
import java.io.File;
import java.io.IOException;
import java.io.InputStream;
import java.io.OutputStream;
import java.io.OutputStreamWriter;
import java.util.EnumMap;
import java.util.Map;
import javax.ws.rs.NotFoundException;
@ -32,6 +36,12 @@ import org.apache.commons.vfs2.FileSelector;
import org.apache.commons.vfs2.FileSystemException;
import org.apache.commons.vfs2.FileSystemManager;
import org.apache.commons.vfs2.VFS;
import org.apache.olingo.commons.api.data.Container;
import org.apache.olingo.commons.api.edm.constants.ODataServiceVersion;
import org.apache.olingo.commons.core.data.AtomEntryImpl;
import org.apache.olingo.commons.core.data.AtomSerializer;
import org.apache.olingo.commons.core.data.JSONEntryImpl;
import org.apache.olingo.fit.serializer.JsonEntryContainer;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
@ -48,18 +58,19 @@ public class FSManager {
private final FileSystemManager fsManager;
private static Map<ODataVersion, FSManager> instance = new EnumMap<ODataVersion, FSManager>(ODataVersion.class);
private static Map<ODataServiceVersion, FSManager> instance =
new EnumMap<ODataServiceVersion, FSManager>(ODataServiceVersion.class);
private final ODataVersion version;
private final ODataServiceVersion version;
public static FSManager instance(final ODataVersion version) throws Exception {
public static FSManager instance(final ODataServiceVersion version) throws Exception {
if (!instance.containsKey(version)) {
instance.put(version, new FSManager(version));
}
return instance.get(version);
}
private FSManager(final ODataVersion version) throws Exception {
private FSManager(final ODataServiceVersion version) throws Exception {
this.version = version;
fsManager = VFS.getManager();
}
@ -88,6 +99,37 @@ public class FSManager {
return memObject;
}
public void putInMemory(final Container<AtomEntryImpl> container, final String relativePath)
throws IOException {
try {
final ODataServiceVersion serviceVersion =
version == ODataServiceVersion.V30 ? ODataServiceVersion.V30 : ODataServiceVersion.V40;
final AtomSerializer atomSerializer = Commons.getAtomSerializer(serviceVersion);
final ByteArrayOutputStream content = new ByteArrayOutputStream();
final OutputStreamWriter writer = new OutputStreamWriter(content, Constants.encoding);
atomSerializer.write(writer, container);
writer.flush();
putInMemory(new ByteArrayInputStream(content.toByteArray()), getAbsolutePath(relativePath, Accept.ATOM));
content.reset();
final ObjectMapper mapper = Commons.getJsonMapper(serviceVersion);
mapper.writeValue(
writer, new JsonEntryContainer<JSONEntryImpl>(
container.getContextURL(),
container.getMetadataETag(),
(new DataBinder(version == ODataServiceVersion.V30 ? ODataServiceVersion.V30 : ODataServiceVersion.V40)).
getJsonEntry(container.getObject())));
putInMemory(new ByteArrayInputStream(content.toByteArray()), getAbsolutePath(relativePath, Accept.JSON_FULLMETA));
} catch (Exception e) {
throw new IOException(e);
}
}
public InputStream readFile(final String relativePath) {
return readFile(relativePath, null);
}

View File

@ -18,11 +18,11 @@
*/
package org.apache.olingo.fit.utils.v3;
import org.apache.olingo.fit.utils.ODataVersion;
import org.apache.olingo.commons.api.edm.constants.ODataServiceVersion;
public class JSONUtilities extends org.apache.olingo.fit.utils.AbstractJSONUtilities {
public JSONUtilities() throws Exception {
super(ODataVersion.v3);
super(ODataServiceVersion.V30);
}
}

View File

@ -18,175 +18,11 @@
*/
package org.apache.olingo.fit.utils.v3;
import java.io.ByteArrayInputStream;
import java.io.ByteArrayOutputStream;
import java.io.InputStream;
import java.util.AbstractMap.SimpleEntry;
import java.util.Collection;
import java.util.Collections;
import java.util.HashSet;
import java.util.Map;
import javax.xml.namespace.QName;
import javax.xml.stream.XMLEventReader;
import javax.xml.stream.events.StartElement;
import org.apache.commons.io.IOUtils;
import org.apache.olingo.fit.utils.Accept;
import org.apache.olingo.fit.utils.Commons;
import org.apache.olingo.fit.utils.ConstantKey;
import org.apache.olingo.fit.utils.Constants;
import org.apache.olingo.fit.utils.MetadataLinkInfo;
import org.apache.olingo.fit.utils.ODataVersion;
import org.apache.olingo.fit.utils.XmlElement;
import org.apache.olingo.commons.api.edm.constants.ODataServiceVersion;
public class XMLUtilities extends org.apache.olingo.fit.utils.AbstractXMLUtilities {
public XMLUtilities() throws Exception {
super(ODataVersion.v3);
}
@Override
public void retrieveLinkInfoFromMetadata() throws Exception {
final MetadataLinkInfo metadataLinkInfo = new MetadataLinkInfo();
Commons.getLinkInfo().put(version, metadataLinkInfo);
final InputStream metadata = fsManager.readFile(Constants.get(version, ConstantKey.METADATA), Accept.XML);
final XMLEventReader reader = getEventReader(metadata);
try {
while (true) {
final Map.Entry<Integer, XmlElement> entitySetElement =
extractElement(reader, null, Collections.<String>singletonList("EntitySet"),
null, false, 0, -1, -1);
retrieveLinks(entitySetElement.getValue(), metadataLinkInfo);
}
} catch (Exception e) {
} finally {
reader.close();
}
}
private void retrieveLinks(final XmlElement entitySetElement, final MetadataLinkInfo metadataLinkInfo)
throws Exception {
final InputStream metadata = fsManager.readFile(Constants.get(version, ConstantKey.METADATA), Accept.XML);
final ByteArrayOutputStream bos = new ByteArrayOutputStream();
IOUtils.copy(metadata, bos);
IOUtils.closeQuietly(metadata);
final String entitySetName = entitySetElement.getStart().getAttributeByName(new QName("Name")).getValue().trim();
final String entityType = entitySetElement.getStart().getAttributeByName(new QName("EntityType")).getValue().trim();
final Collection<Map.Entry<String, String>> filter = new HashSet<Map.Entry<String, String>>();
filter.add(new SimpleEntry<String, String>(
"Name", entityType.substring(entityType.lastIndexOf(".") + 1, entityType.length())));
filter.add(new SimpleEntry<String, String>("BaseType", entityType));
final XMLEventReader reader = getEventReader(new ByteArrayInputStream(bos.toByteArray()));
final Map.Entry<Integer, XmlElement> entityTypeElement = extractElement(
reader, null, Collections.<String>singletonList("EntityType"), filter, true, 0, -1, -1);
final XMLEventReader entityReader = entityTypeElement.getValue().getContentReader();
int size = 0;
try {
while (true) {
final XmlElement navProperty =
extractElement(entityReader, null, Collections.<String>singletonList("NavigationProperty"),
null, false, 0, -1, -1).getValue();
final String linkName = navProperty.getStart().getAttributeByName(new QName("Name")).getValue();
final Map.Entry<String, Boolean> target = getTargetInfo(navProperty.getStart(), linkName);
metadataLinkInfo.addLink(
entitySetName,
linkName,
target.getKey(),
target.getValue());
size++;
}
} catch (Exception e) {
} finally {
entityReader.close();
}
if (size == 0) {
metadataLinkInfo.addEntitySet(entitySetName);
}
}
private Map.Entry<String, Boolean> getTargetInfo(final StartElement element, final String linkName)
throws Exception {
final InputStream metadata = fsManager.readFile(Constants.get(version, ConstantKey.METADATA), Accept.XML);
final ByteArrayOutputStream bos = new ByteArrayOutputStream();
IOUtils.copy(metadata, bos);
IOUtils.closeQuietly(metadata);
// ------------------------------------
// Retrieve association
// ------------------------------------
XMLEventReader reader = getEventReader(new ByteArrayInputStream(bos.toByteArray()));
final String associationName = element.getAttributeByName(new QName("Relationship")).getValue();
final Map.Entry<Integer, XmlElement> association = extractElement(
reader, null, Collections.<String>singletonList("Association"),
Collections.<Map.Entry<String, String>>singleton(new SimpleEntry<String, String>(
"Name", associationName.substring(associationName.lastIndexOf(".") + 1))), false,
0, 4, 4);
reader.close();
// ------------------------------------
// ------------------------------------
// check for feed or not from Association role
// ------------------------------------
InputStream associationContent = association.getValue().toStream();
reader = getEventReader(associationContent);
Map.Entry<Integer, XmlElement> associationEnd = extractElement(
reader, null, Collections.<String>singletonList("End"),
Collections.<Map.Entry<String, String>>singleton(new SimpleEntry<String, String>("Role", linkName)),
false, 0, -1, -1);
reader.close();
IOUtils.closeQuietly(associationContent);
final boolean feed = associationEnd.getValue().getStart().getAttributeByName(
new QName("Multiplicity")).getValue().equals("*");
// ------------------------------------
// ------------------------------------
// Retrieve target association set name
// ------------------------------------
reader = getEventReader(new ByteArrayInputStream(bos.toByteArray()));
final Map.Entry<Integer, XmlElement> associationSet = extractElement(
reader, null, Collections.<String>singletonList("AssociationSet"),
Collections.<Map.Entry<String, String>>singleton(new SimpleEntry<String, String>(
"Association", associationName)), false, 0, -1, -1);
reader.close();
associationContent = associationSet.getValue().toStream();
reader = getEventReader(associationContent);
associationEnd = extractElement(
reader, null, Collections.<String>singletonList("End"),
Collections.<Map.Entry<String, String>>singleton(new SimpleEntry<String, String>("Role", linkName)),
false, 0, -1, -1);
reader.close();
IOUtils.closeQuietly(associationContent);
final String target = associationEnd.getValue().getStart().getAttributeByName(new QName("EntitySet")).getValue();
// ------------------------------------
return new SimpleEntry<String, Boolean>(target, feed);
super(ODataServiceVersion.V30);
}
}

View File

@ -18,11 +18,11 @@
*/
package org.apache.olingo.fit.utils.v4;
import org.apache.olingo.fit.utils.ODataVersion;
import org.apache.olingo.commons.api.edm.constants.ODataServiceVersion;
public class JSONUtilities extends org.apache.olingo.fit.utils.AbstractJSONUtilities {
public JSONUtilities() throws Exception {
super(ODataVersion.v4);
super(ODataServiceVersion.V40);
}
}

View File

@ -18,130 +18,11 @@
*/
package org.apache.olingo.fit.utils.v4;
import java.io.ByteArrayInputStream;
import java.io.ByteArrayOutputStream;
import java.io.InputStream;
import java.util.Collections;
import java.util.HashSet;
import java.util.Map;
import java.util.Set;
import javax.xml.namespace.QName;
import javax.xml.stream.XMLEventReader;
import org.apache.commons.io.IOUtils;
import org.apache.olingo.fit.utils.Accept;
import org.apache.olingo.fit.utils.Commons;
import org.apache.olingo.fit.utils.ConstantKey;
import org.apache.olingo.fit.utils.Constants;
import org.apache.olingo.fit.utils.MetadataLinkInfo;
import org.apache.olingo.fit.utils.ODataVersion;
import org.apache.olingo.fit.utils.XmlElement;
import org.apache.olingo.commons.api.edm.constants.ODataServiceVersion;
public class XMLUtilities extends org.apache.olingo.fit.utils.AbstractXMLUtilities {
public XMLUtilities() throws Exception {
super(ODataVersion.v4);
}
@Override
public void retrieveLinkInfoFromMetadata() throws Exception {
final MetadataLinkInfo metadataLinkInfo = new MetadataLinkInfo();
Commons.getLinkInfo().put(version, metadataLinkInfo);
final InputStream metadata = fsManager.readFile(Constants.get(version, ConstantKey.METADATA), Accept.XML);
final ByteArrayOutputStream bos = new ByteArrayOutputStream();
IOUtils.copy(metadata, bos);
IOUtils.closeQuietly(metadata);
XMLEventReader reader = getEventReader(new ByteArrayInputStream(bos.toByteArray()));
final Set<String> singletons = new HashSet<String>();
try {
while (true) {
final Map.Entry<Integer, XmlElement> entitySetElement =
extractElement(reader, null, Collections.<String>singletonList("Singleton"),
null, false, 0, -1, -1);
final String entitySetName =
entitySetElement.getValue().getStart().getAttributeByName(new QName("Name")).getValue().trim();
singletons.add(entitySetName);
}
} catch (Exception e) {
} finally {
reader.close();
}
reader = getEventReader(new ByteArrayInputStream(bos.toByteArray()));
try {
while (true) {
final Map.Entry<Integer, XmlElement> entitySetElement =
extractElement(reader, null, Collections.<String>singletonList("EntitySet"),
null, false, 0, -1, -1);
retrieveLinks(entitySetElement.getValue(), metadataLinkInfo, singletons);
}
} catch (Exception e) {
} finally {
reader.close();
}
reader = getEventReader(new ByteArrayInputStream(bos.toByteArray()));
try {
while (true) {
final Map.Entry<Integer, XmlElement> entitySetElement =
extractElement(reader, null, Collections.<String>singletonList("Singleton"),
null, false, 0, -1, -1);
retrieveLinks(entitySetElement.getValue(), metadataLinkInfo, singletons);
}
} catch (Exception e) {
} finally {
reader.close();
}
}
private void retrieveLinks(
final XmlElement entitySetElement, final MetadataLinkInfo metadataLinkInfo, final Set<String> singletons)
throws Exception {
final String entitySetName = entitySetElement.getStart().getAttributeByName(new QName("Name")).getValue().trim();
final XMLEventReader entityReader = entitySetElement.getContentReader();
int size = 0;
try {
while (true) {
final XmlElement navProperty =
extractElement(entityReader, null, Collections.<String>singletonList("NavigationPropertyBinding"),
null, false, 0, -1, -1).getValue();
final String linkName = navProperty.getStart().getAttributeByName(new QName("Path")).getValue();
final String target = navProperty.getStart().getAttributeByName(new QName("Target")).getValue();
final boolean feed = !singletons.contains(target);
metadataLinkInfo.addLink(
entitySetName,
linkName,
target,
feed);
size++;
}
} catch (Exception e) {
} finally {
entityReader.close();
}
if (size == 0) {
metadataLinkInfo.addEntitySet(entitySetName);
}
if (singletons.contains(entitySetName)) {
metadataLinkInfo.setSingleton(entitySetName);
}
super(ODataServiceVersion.V40);
}
}

Some files were not shown because too many files have changed in this diff Show More