package com.temenos.interaction.media.odata.xml.atom;
/*
* #%L
* interaction-media-odata-xml
* %%
* Copyright (C) 2012 - 2013 Temenos Holdings N.V.
* %%
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU Affero General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU Affero General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>.
* #L%
*/
import java.io.ByteArrayInputStream;
import java.io.ByteArrayOutputStream;
import java.io.IOException;
import java.io.InputStream;
import java.io.InputStreamReader;
import java.io.OutputStream;
import java.io.OutputStreamWriter;
import java.io.PushbackInputStream;
import java.io.Reader;
import java.lang.annotation.Annotation;
import java.lang.reflect.Type;
import java.util.ArrayList;
import java.util.Collection;
import java.util.HashMap;
import java.util.HashSet;
import java.util.List;
import java.util.Map;
import java.util.Set;
import java.util.regex.Pattern;
import javax.ws.rs.Consumes;
import javax.ws.rs.Produces;
import javax.ws.rs.WebApplicationException;
import javax.ws.rs.core.Context;
import javax.ws.rs.core.HttpHeaders;
import javax.ws.rs.core.MediaType;
import javax.ws.rs.core.MultivaluedMap;
import javax.ws.rs.core.Request;
import javax.ws.rs.core.Response;
import javax.ws.rs.core.Response.Status;
import javax.ws.rs.core.UriInfo;
import javax.ws.rs.ext.MessageBodyReader;
import javax.ws.rs.ext.MessageBodyWriter;
import javax.ws.rs.ext.Provider;
import org.apache.commons.io.IOUtils;
import org.odata4j.core.OEntities;
import org.odata4j.core.OEntity;
import org.odata4j.core.OEntityKey;
import org.odata4j.core.OLink;
import org.odata4j.core.OLinks;
import org.odata4j.edm.EdmDataServices;
import org.odata4j.edm.EdmEntitySet;
import org.odata4j.edm.EdmEntityType;
import org.odata4j.exceptions.NotFoundException;
import org.odata4j.format.Entry;
import org.odata4j.format.xml.AtomEntryFormatParserExt;
import org.odata4j.internal.InternalUtil;
import org.odata4j.producer.Responses;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import com.temenos.interaction.core.ExtendedMediaTypes;
import com.temenos.interaction.core.UriInfoImpl;
import com.temenos.interaction.core.command.InteractionContext;
import com.temenos.interaction.core.entity.Entity;
import com.temenos.interaction.core.entity.EntityProperties;
import com.temenos.interaction.core.entity.EntityProperty;
import com.temenos.interaction.core.entity.Metadata;
import com.temenos.interaction.core.hypermedia.BeanTransformer;
import com.temenos.interaction.core.hypermedia.CollectionResourceState;
import com.temenos.interaction.core.hypermedia.DefaultResourceStateProvider;
import com.temenos.interaction.core.hypermedia.HypermediaTemplateHelper;
import com.temenos.interaction.core.hypermedia.Link;
import com.temenos.interaction.core.hypermedia.MethodNotAllowedException;
import com.temenos.interaction.core.hypermedia.ResourceState;
import com.temenos.interaction.core.hypermedia.ResourceStateMachine;
import com.temenos.interaction.core.hypermedia.ResourceStateProvider;
import com.temenos.interaction.core.hypermedia.Transformer;
import com.temenos.interaction.core.hypermedia.Transition;
import com.temenos.interaction.core.resource.CollectionResource;
import com.temenos.interaction.core.resource.EntityResource;
import com.temenos.interaction.core.resource.RESTResource;
import com.temenos.interaction.core.resource.ResourceTypeHelper;
import com.temenos.interaction.core.rim.URLHelper;
import com.temenos.interaction.core.web.RequestContext;
import com.temenos.interaction.odataext.entity.MetadataOData4j;
@Provider
@Consumes({MediaType.APPLICATION_ATOM_XML})
@Produces({ExtendedMediaTypes.APPLICATION_ATOMSVC_XML, MediaType.APPLICATION_ATOM_XML, MediaType.APPLICATION_XML})
public class AtomXMLProvider implements MessageBodyReader<RESTResource>, MessageBodyWriter<RESTResource> {
private static final String UTF_8 = "UTF-8";
private static final Logger LOGGER = LoggerFactory.getLogger(AtomXMLProvider.class);
private static final Pattern STRING_KEY_RESOURCE_PATTERN = Pattern.compile("(\\('.*'\\))");
@Context
private UriInfo uriInfo;
@Context
private Request requestContext;
private AtomEntryFormatWriter entryWriter;
private AtomFeedFormatWriter feedWriter;
private AtomEntityEntryFormatWriter entityEntryWriter;
private final MetadataOData4j metadataOData4j;
private final Metadata metadata;
private final ResourceState serviceDocument;
private final Transformer transformer;
private final LinkInterceptor linkInterceptor = new ODataLinkInterceptor(this);
private ResourceStateProvider resourceStateProvider;
/**
* Construct the jax-rs Provider for OData media type.
* @param metadataOData4j
* The entity metadata for reading and writing OData entities.
* @param metadata
* The entity metadata for reading and writing Entity entities.
* @param hypermediaEngine
* The hypermedia engine contains all the resource to entity mappings
* @param transformer
* Transformer to convert an entity to a properties map
*/
public AtomXMLProvider(MetadataOData4j metadataOData4j, Metadata metadata, ResourceStateMachine hypermediaEngine, Transformer transformer) {
this(metadataOData4j, metadata, new DefaultResourceStateProvider(hypermediaEngine), hypermediaEngine.getResourceStateByName("ServiceDocument"), transformer);
}
public AtomXMLProvider(MetadataOData4j metadataOData4j, Metadata metadata, ResourceStateProvider resourceStateProvider, ResourceState serviceDocument, Transformer transformer) {
this.metadataOData4j = metadataOData4j;
this.metadata = metadata;
this.resourceStateProvider = resourceStateProvider;
assert resourceStateProvider != null;
this.serviceDocument = serviceDocument;
if (serviceDocument == null)
throw new RuntimeException("No 'ServiceDocument' found.");
assert metadata != null;
this.transformer = transformer;
entryWriter = new AtomEntryFormatWriter(serviceDocument);
feedWriter = new AtomFeedFormatWriter(serviceDocument);
entityEntryWriter = new AtomEntityEntryFormatWriter(serviceDocument, metadata);
this.uriInfo = new UriInfoImpl(uriInfo);
}
@Override
public boolean isWriteable(Class<?> type, Type genericType,
Annotation[] annotations, MediaType mediaType) {
if (mediaType.isCompatible(MediaType.APPLICATION_ATOM_XML_TYPE)
// good old Microsoft Excel 2013 has forced us to need to accept this media type (which is completely wrong) https://github.com/temenostech/IRIS/issues/154
|| mediaType.equals(ExtendedMediaTypes.APPLICATION_ATOMSVC_XML_TYPE)
|| mediaType.equals(MediaType.APPLICATION_XML_TYPE)) {
return ResourceTypeHelper.isType(type, genericType, EntityResource.class) ||
ResourceTypeHelper.isType(type, genericType, CollectionResource.class, OEntity.class) ||
ResourceTypeHelper.isType(type, genericType, CollectionResource.class, Entity.class);
}
return false;
}
@Override
public long getSize(RESTResource t, Class<?> type, Type genericType,
Annotation[] annotations, MediaType mediaType) {
return -1;
}
/**
* Writes a Atom (OData) representation of {@link EntityResource} to the output stream.
*
* @precondition supplied {@link EntityResource} is non null
* @precondition {@link EntityResource#getEntity()} returns a valid OEntity, this
* provider only supports serialising OEntities
* @postcondition non null Atom (OData) XML document written to OutputStream
* @invariant valid OutputStream
*/
@SuppressWarnings("unchecked")
@Override
public void writeTo(RESTResource resource, Class<?> type, Type genericType,
Annotation[] annotations, MediaType mediaType,
MultivaluedMap<String, Object> httpHeaders,
OutputStream entityStream) throws IOException,
WebApplicationException {
assert resource != null;
assert uriInfo != null;
ByteArrayOutputStream buffer = new ByteArrayOutputStream();
RESTResource restResource = processLinks((RESTResource) resource);
Collection<Link> processedLinks = restResource.getLinks();
if(ResourceTypeHelper.isType(type, genericType, EntityResource.class, OEntity.class)) {
EntityResource<OEntity> entityResource = (EntityResource<OEntity>) resource;
OEntity tempEntity = entityResource.getEntity();
EdmEntitySet entitySet = getEdmEntitySet(entityResource.getEntityName());
List<OLink> olinks = formOLinks(entityResource);
//Write entry
// create OEntity with our EdmEntitySet see issue https://github.com/aphethean/IRIS/issues/20
OEntity oentity = OEntities.create(entitySet, tempEntity.getEntityKey(), tempEntity.getProperties(), null);
entryWriter.write(uriInfo, new OutputStreamWriter(buffer, UTF_8), Responses.entity(oentity), entitySet, olinks);
} else if(ResourceTypeHelper.isType(type, genericType, EntityResource.class, Entity.class)) {
EntityResource<Entity> entityResource = (EntityResource<Entity>) resource;
//Write entry
Entity entity = entityResource.getEntity();
String entityName = entityResource.getEntityName();
// Write Entity object with Abdera implementation
entityEntryWriter.write(uriInfo, new OutputStreamWriter(buffer, UTF_8), entityName, entity, processedLinks, entityResource.getEmbedded());
} else if(ResourceTypeHelper.isType(type, genericType, EntityResource.class)) {
EntityResource<Object> entityResource = (EntityResource<Object>) resource;
//Links and entity properties
Object entity = entityResource.getEntity();
String entityName = entityResource.getEntityName();
EntityProperties props = new EntityProperties();
if(entity != null) {
Map<String, Object> objProps = (transformer != null ? transformer : new BeanTransformer()).transform(entity);
if (objProps != null) {
for(String propName : objProps.keySet()) {
props.setProperty(new EntityProperty(propName, objProps.get(propName)));
}
}
}
entityEntryWriter.write(uriInfo, new OutputStreamWriter(buffer, UTF_8), entityName, new Entity(entityName, props), processedLinks, entityResource.getEmbedded());
} else if(ResourceTypeHelper.isType(type, genericType, CollectionResource.class, OEntity.class)) {
CollectionResource<OEntity> collectionResource = ((CollectionResource<OEntity>) resource);
EdmEntitySet entitySet = getEdmEntitySet(collectionResource.getEntityName());
List<EntityResource<OEntity>> collectionEntities = (List<EntityResource<OEntity>>) collectionResource.getEntities();
List<OEntity> entities = new ArrayList<OEntity>();
Map<OEntity, Collection<Link>> linkId = new HashMap<OEntity, Collection<Link>>();
for (EntityResource<OEntity> collectionEntity : collectionEntities) {
// create OEntity with our EdmEntitySet see issue https://github.com/aphethean/IRIS/issues/20
OEntity tempEntity = collectionEntity.getEntity();
List<OLink> olinks = formOLinks(collectionEntity);
Collection<Link> links = collectionEntity.getLinks();
OEntity entity = OEntities.create(entitySet, null, tempEntity.getEntityKey(), tempEntity.getEntityTag(), tempEntity.getProperties(), olinks);
entities.add(entity);
linkId.put(entity, links);
}
// TODO implement collection properties and get transient value for skiptoken
Integer inlineCount = collectionResource.getInlineCount();
String skipToken = null;
feedWriter.write(uriInfo, new OutputStreamWriter(buffer, UTF_8),
processedLinks,
Responses.entities(entities, entitySet, inlineCount, skipToken),
metadata.getModelName(), linkId);
} else if(ResourceTypeHelper.isType(type, genericType, CollectionResource.class, Entity.class)) {
CollectionResource<Entity> collectionResource = ((CollectionResource<Entity>) resource);
// TODO implement collection properties and get transient value for skiptoken
Integer inlineCount = collectionResource.getInlineCount();
String skipToken = null;
//Write feed
AtomEntityFeedFormatWriter entityFeedWriter = new AtomEntityFeedFormatWriter(serviceDocument, metadata);
entityFeedWriter.write(uriInfo, new OutputStreamWriter(buffer, UTF_8), collectionResource, inlineCount, skipToken, metadata.getModelName());
} else {
LOGGER.error("Accepted object for writing in isWriteable, but type not supported in writeTo method");
throw new WebApplicationException(Response.Status.INTERNAL_SERVER_ERROR);
}
//Set response headers
if(httpHeaders != null) {
httpHeaders.putSingle(HttpHeaders.CONTENT_TYPE, MediaType.APPLICATION_ATOM_XML); //Workaround for https://issues.apache.org/jira/browse/WINK-374
httpHeaders.putSingle(HttpHeaders.CONTENT_LENGTH, Integer.toString(buffer.size()));
}
IOUtils.copy(new ByteArrayInputStream(buffer.toByteArray()), entityStream);
}
public RESTResource processLinks(RESTResource restResource) {
Collection<Link> linksCollection = restResource.getLinks();
List<Link> processedLinks = new ArrayList<Link>();
if (linksCollection != null) {
for (Link linkToAdd : linksCollection) {
Link link = linkInterceptor.addingLink(restResource, linkToAdd);
if (link != null) {
processedLinks.add(link);
}
}
}
restResource.setLinks(processedLinks);
// process embedded resources
if (restResource.getEmbedded() != null) {
Map<Transition,RESTResource> embeddedResources = restResource.getEmbedded();
for (RESTResource embeddedResource : embeddedResources.values()) {
processLinks(embeddedResource);
}
}
// process entities in collection resource
if (restResource instanceof CollectionResource) {
CollectionResource<?> collectionResource = (CollectionResource<?>) restResource;
for (EntityResource<?> entityResource : collectionResource.getEntities()) {
processLinks(entityResource);
}
}
return restResource;
}
public List<OLink> formOLinks(EntityResource<OEntity> entityResource) {
// Create embedded resources from $expand
addExpandedLinks(entityResource);
//Add entity links
List<OLink> olinks = new ArrayList<OLink>();
if (entityResource.getLinks() != null && !entityResource.getLinks().isEmpty()) {
for(Link link : entityResource.getLinks()) {
addLinkToOLinks(olinks, link, entityResource);
}
}
return olinks;
}
/*
* Using the supplied EntityResource, add the embedded resources
* from the OEntity embedded resources. NB - only an OEntity can
* carry OLinks.
*/
public void addExpandedLinks(EntityResource<OEntity> entityResource) {
RequestContext requestContext = RequestContext.getRequestContext();
Collection<Link> links = entityResource.getLinks();
if (links != null) {
OEntity oentity = entityResource.getEntity();
List<OLink> olinks = oentity.getLinks();
for (OLink olink : olinks) {
if (olink.isInline()) {
String relid = InternalUtil.getEntityRelId(oentity);
String href = relid + "/" + olink.getTitle();
for (Link link : links) {
String linkHref = link.getHref();
if(requestContext != null) {
//Extract the transition fragment from the URI path
linkHref = link.getRelativeHref(getBaseUri(serviceDocument, uriInfo));
}
if (href.equals(linkHref)) {
if (entityResource.getEmbedded() == null) {
entityResource.setEmbedded(new HashMap<Transition, RESTResource>());
}
if (olink.isCollection()) {
List<OEntity> oentities = olink.getRelatedEntities();
Collection<EntityResource<OEntity>> entityResources = new ArrayList<EntityResource<OEntity>>();
for (OEntity oe : oentities) {
entityResources.add(new EntityResource<OEntity>(oe));
}
entityResource.getEmbedded().put(link.getTransition(), new CollectionResource<OEntity>(entityResources));
} else {
// replace the OLink's on the current entity
OEntity inlineOentity = olink.getRelatedEntity();
List<OLink> inlineResourceOlinks = formOLinks(new EntityResource<OEntity>(inlineOentity));
OEntity newInlineOentity = OEntities.create(inlineOentity.getEntitySet(), inlineOentity.getEntityKey(), inlineOentity.getProperties(), inlineResourceOlinks);
entityResource.getEmbedded().put(link.getTransition(), new EntityResource<OEntity>(newInlineOentity));
}
}
}
}
}
}
}
private void addLinkToOLinks(List<OLink> olinks, Link link, RESTResource resource) {
RequestContext requestContext = RequestContext.getRequestContext();
assert link != null;
assert link.getTransition() != null;
Map<Transition,RESTResource> embeddedResources = resource.getEmbedded();
String rel = link.getRel();
String href = link.getHref();
if(requestContext != null) {
//Extract the transition fragment from the URI path
href = link.getRelativeHref(getBaseUri(serviceDocument, uriInfo));
}
String title = link.getTitle();
OLink olink = null;
Transition linkTransition = link.getTransition();
if(linkTransition != null) {
if (embeddedResources != null && embeddedResources.get(linkTransition) != null
&&embeddedResources.get(linkTransition) instanceof EntityResource) {
@SuppressWarnings("unchecked")
EntityResource<OEntity> embeddedResource = (EntityResource<OEntity>) embeddedResources.get(linkTransition);
// replace the OLink's on the embedded entity
OEntity newEmbeddedEntity = processOEntity(embeddedResource);
olink = OLinks.relatedEntityInline(rel, title, href, newEmbeddedEntity);
} else if (embeddedResources != null && embeddedResources.get(linkTransition) != null
&&embeddedResources.get(linkTransition) instanceof CollectionResource) {
@SuppressWarnings("unchecked")
CollectionResource<OEntity> embeddedCollectionResource = (CollectionResource<OEntity>) embeddedResources.get(linkTransition);
List<OEntity> entities = new ArrayList<OEntity>();
for (EntityResource<OEntity> embeddedResource : embeddedCollectionResource.getEntities()) {
// replace the OLink's on the embedded entity
OEntity newEmbeddedEntity = processOEntity(embeddedResource);
entities.add(newEmbeddedEntity);
}
olink = OLinks.relatedEntitiesInline(rel, title, href, entities);
}
if (olink == null) {
if (linkTransition.getTarget() instanceof CollectionResourceState) {
olink = OLinks.relatedEntities(rel, title, href);
} else {
olink = OLinks.relatedEntity(rel, title, href);
}
}
}
olinks.add(olink);
}
private OEntity processOEntity(EntityResource<OEntity> entityResource) {
List<OLink> embeddedLinks = formOLinks(entityResource);
OEntity embeddedEntity = entityResource.getEntity();
// replace the OLink's on the embedded entity
OEntity newOEntity = OEntities.create(embeddedEntity.getEntitySet(), embeddedEntity.getEntityKey(), embeddedEntity.getProperties(), embeddedLinks);
return newOEntity;
}
@Override
public boolean isReadable(Class<?> type, Type genericType,
Annotation[] annotations, MediaType mediaType) {
// this class can only deserialise EntityResource with OEntity
return ResourceTypeHelper.isType(type, genericType, EntityResource.class);
}
/**
* Reads a Atom (OData) representation of {@link EntityResource} from the input stream.
*
* @precondition {@link InputStream} contains a valid Atom (OData) Entity enclosed in a <resource/> document
* @postcondition {@link EntityResource} will be constructed and returned.
* @invariant valid InputStream
*/
@Override
public EntityResource<OEntity> readFrom(Class<RESTResource> type,
Type genericType, Annotation[] annotations, MediaType mediaType,
MultivaluedMap<String, String> httpHeaders, InputStream entityStream)
throws IOException, WebApplicationException {
// check media type can be handled, isReadable must have been called
assert ResourceTypeHelper.isType(type, genericType, EntityResource.class);
assert mediaType.isCompatible(MediaType.APPLICATION_ATOM_XML_TYPE);
try {
OEntityKey entityKey = null;
// work out the entity name using resource path from UriInfo
String absoluteUri = uriInfo.getAbsolutePath().toString();
String resourcePath = absoluteUri.substring(uriInfo.getBaseUri().toString().length());
ResourceState currentState = null;
try {
currentState = getCurrentState(serviceDocument, resourcePath);
} catch (MethodNotAllowedException e1) {
StringBuilder allowHeader = new StringBuilder();
Set<String> allowedMethods = new HashSet<String>(e1.getAllowedMethods());
allowedMethods.add("HEAD");
allowedMethods.add("OPTIONS");
for(String method: allowedMethods) {
allowHeader.append(method);
allowHeader.append(", ");
}
Response response = Response.status(405).header("Allow", allowHeader.toString().substring(0, allowHeader.length() - 2)).build();
throw new WebApplicationException(e1, response);
}
if (currentState == null)
throw new IllegalStateException("No state found");
String pathIdParameter = getPathIdParameter(currentState);
UriInfo tmpUriInfo = new UriInfoImpl(uriInfo);
String uriPath = uriInfo.getAbsolutePath().toString().substring(uriInfo.getBaseUri().toString().length());
if(uriPath.charAt(0) == '/') {
uriPath = uriPath.substring(1);
}
String statePath = currentState.getPath();
if(statePath.charAt(0) == '/') {
statePath = statePath.substring(1);
}
new URLHelper().extractPathParameters(tmpUriInfo, uriPath.split("/"), statePath.split("/"));
MultivaluedMap<String, String> pathParameters = tmpUriInfo.getPathParameters();
if (pathParameters != null && pathParameters.getFirst(pathIdParameter) != null) {
if (STRING_KEY_RESOURCE_PATTERN.matcher(resourcePath).find()) {
entityKey = OEntityKey.create(pathParameters.getFirst(pathIdParameter));
} else {
entityKey = OEntityKey.parse(pathParameters.getFirst(pathIdParameter));
}
}
if (currentState.getEntityName() == null) {
throw new IllegalStateException("Entity name could not be determined");
}
/*
* get the entity set name using the metadata
*/
String entitySetName = getEntitySet(currentState);
// Check contents of the stream, if empty or null then return empty resource
InputStream verifiedStream = verifyContentReceieved(entityStream);
if (verifiedStream == null) {
return new EntityResource<OEntity>();
}
// Lets parse the request content
Reader reader = new InputStreamReader(verifiedStream);
assert entitySetName != null : "Must have found a resource or thrown exception";
Entry e = new AtomEntryFormatParserExt(metadataOData4j, entitySetName, entityKey, null).parse(reader);
return new EntityResource<OEntity>(e.getEntity());
} catch (IllegalStateException e) {
LOGGER.warn("Malformed request from client", e);
throw new WebApplicationException(Status.BAD_REQUEST);
}
}
/*
* Find the entity set name for this resource
*/
public String getEntitySet(ResourceState state) {
String entitySetName = null;
String fqTargetEntityName = metadata.getModelName() + Metadata.MODEL_SUFFIX + "." + state.getEntityName();
try {
EdmEntityType targetEntityType = (EdmEntityType) getEdmDataService().findEdmEntityType(fqTargetEntityName);
if (targetEntityType != null) {
EdmEntitySet targetEntitySet = getEdmDataService().getEdmEntitySet(targetEntityType);
if (targetEntitySet != null)
entitySetName = targetEntitySet.getName();
}
} catch (NotFoundException e) {
if(LOGGER.isDebugEnabled()) {
LOGGER.debug("Failed to get entity set name", e);
}
}
if (entitySetName == null) {
try {
entitySetName = getEdmEntitySet(state.getEntityName()).getName();
} catch (NotFoundException e) {
LOGGER.warn("Entity [" + fqTargetEntityName + "] is not an entity set.", e);
}
if(entitySetName == null) {
entitySetName = state.getName();
}
}
return entitySetName;
}
protected ResourceState getCurrentState(ResourceState serviceDocument, String resourcePath) throws MethodNotAllowedException {
ResourceState state = null;
if (resourcePath != null) {
String tmpResourcePath = uriInfo.getAbsolutePath().toString().replaceFirst(uriInfo.getBaseUri().toString(), "");
if(tmpResourcePath.charAt(0) != '/') {
tmpResourcePath = '/' + tmpResourcePath;
}
state = resourceStateProvider.getResourceState(requestContext.getMethod(), tmpResourcePath);
}
return state;
}
/*
* For a given resource state, get the path parameter used for the id.
* @param state
* @return
*/
private String getPathIdParameter(ResourceState state) {
String pathIdParameter = InteractionContext.DEFAULT_ID_PATH_ELEMENT;
if (state.getPathIdParameter() != null) {
pathIdParameter = state.getPathIdParameter();
}
return pathIdParameter;
}
/* Ugly testing support :-( */
void setUriInfo(UriInfo uriInfo) {
this.uriInfo = uriInfo;
if(resourceStateProvider instanceof DefaultResourceStateProvider) {
((DefaultResourceStateProvider)resourceStateProvider).setUriInfo(uriInfo);
}
}
void setRequestContext(Request request) {
this.requestContext = request;
}
void setResourceStateProvider(ResourceStateProvider resourceStateProvider) {
this.resourceStateProvider = resourceStateProvider;
}
/**
* Method to verify if receieved stream has content or its empty
* @param stream Stream to check
* @return verified stream
* @throws IOException
*/
private InputStream verifyContentReceieved(InputStream stream) throws IOException {
if (stream == null) { // Check if its null
LOGGER.debug("Request stream received as null");
return null;
} else if (stream.markSupported()) { // Check stream supports mark/reset
// mark() and read the first byte just to check
stream.mark(1);
final int bytesRead = stream.read(new byte[1]);
if (bytesRead != -1) {
//stream not empty
stream.reset(); // reset the stream as if untouched
return stream;
} else {
//stream empty
LOGGER.debug("Request received with empty body");
return null;
}
} else {
// Panic! this stream does not support mark/reset, try with PushbackInputStream as a last resort
int bytesRead;
PushbackInputStream pbs = new PushbackInputStream(stream);
if ((bytesRead = pbs.read()) != -1) {
// Contents detected, unread and return
pbs.unread(bytesRead);
return pbs;
} else {
// Empty stream detected
LOGGER.debug("Request received with empty body!");
return null;
}
}
}
/**
* Our base uri is the uri to the service document.
* @param serviceDocument
* @param uriInfo
* @return
*/
public static String getBaseUri(ResourceState serviceDocument, UriInfo uriInfo) {
String baseUri = uriInfo.getBaseUri().toString();
if (serviceDocument.getPath() != null) {
if (baseUri.endsWith("/")) {
baseUri = baseUri.substring(0, baseUri.lastIndexOf("/"));
}
baseUri = baseUri + serviceDocument.getPath();
String absPath = getAbsolutePath(uriInfo);
baseUri = HypermediaTemplateHelper.getTemplatedBaseUri(baseUri, absPath);
if (!baseUri.endsWith("/")) {
baseUri += "/";
}
}
return baseUri;
}
public static String getAbsolutePath(UriInfo uriInfo) {
return uriInfo.getBaseUri() + uriInfo.getPath();
}
private EdmDataServices getEdmDataService() {
return metadataOData4j.getMetadata();
}
/*
* get edmEntitySet
*/
public EdmEntitySet getEdmEntitySet(String entityName) {
EdmEntityType entityType = (EdmEntityType) getEdmDataService().findEdmEntityType(entityName);
EdmEntitySet entitySet = null;
try {
entitySet = getEdmDataService().getEdmEntitySet(entityType);
} catch (Exception e) {
if(LOGGER.isDebugEnabled()) {
LOGGER.debug("Unable to find entity set for [" +entityName + "]", e);
}
}
if(entitySet == null) {
return metadataOData4j.getEdmEntitySetByEntityName(entityName);
}
return entitySet;
}
}