blob: 6d92abc83de9161e9aa654132a2b97e4ebcd33cf [file] [log] [blame]
/*
* 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.server.core.responses;
import java.util.List;
import java.util.Map;
import org.apache.olingo.commons.api.data.ContextURL;
import org.apache.olingo.commons.api.data.Entity;
import org.apache.olingo.commons.api.edm.EdmAction;
import org.apache.olingo.commons.api.edm.EdmEntitySet;
import org.apache.olingo.commons.api.edm.EdmEntityType;
import org.apache.olingo.commons.api.edm.EdmFunction;
import org.apache.olingo.commons.api.edm.EdmPrimitiveTypeException;
import org.apache.olingo.commons.api.edm.EdmPrimitiveTypeKind;
import org.apache.olingo.commons.api.format.ContentType;
import org.apache.olingo.commons.api.http.HttpHeader;
import org.apache.olingo.commons.api.http.HttpStatusCode;
import org.apache.olingo.commons.core.Encoder;
import org.apache.olingo.commons.core.edm.primitivetype.EdmPrimitiveTypeFactory;
import org.apache.olingo.commons.core.edm.primitivetype.EdmString;
import org.apache.olingo.server.api.ODataApplicationException;
import org.apache.olingo.server.api.ODataLibraryException;
import org.apache.olingo.server.api.ODataResponse;
import org.apache.olingo.server.api.ODataServerError;
import org.apache.olingo.server.api.ServiceMetadata;
import org.apache.olingo.server.api.serializer.EntitySerializerOptions;
import org.apache.olingo.server.api.serializer.ODataSerializer;
import org.apache.olingo.server.api.serializer.SerializerException;
import org.apache.olingo.server.core.ContentNegotiatorException;
import org.apache.olingo.server.core.ReturnRepresentation;
import org.apache.olingo.server.core.ServiceRequest;
import org.apache.olingo.server.core.serializer.utils.ContentTypeHelper;
public class EntityResponse extends ServiceResponse {
private final ReturnRepresentation returnRepresentation;
private final ODataSerializer serializer;
private final EntitySerializerOptions options;
private final ContentType responseContentType;
private final String baseURL;
private EntityResponse(ServiceMetadata metadata, ODataResponse response,
ODataSerializer serializer, EntitySerializerOptions options, ContentType responseContentType,
Map<String, String> preferences, ReturnRepresentation returnRepresentation, String baseURL) {
super(metadata, response, preferences);
this.serializer = serializer;
this.options = options;
this.responseContentType = responseContentType;
this.returnRepresentation = returnRepresentation;
this.baseURL = baseURL;
}
public static EntityResponse getInstance(ServiceRequest request, ContextURL contextURL,
boolean references, ODataResponse response, ReturnRepresentation returnRepresentation)
throws ContentNegotiatorException, SerializerException {
EntitySerializerOptions options = request.getSerializerOptions(EntitySerializerOptions.class,
contextURL, references);
return new EntityResponse(request.getServiceMetaData(), response, request.getSerializer(),
options, request.getResponseContentType(), request.getPreferences(), returnRepresentation,
request.getODataRequest().getRawBaseUri());
}
public static EntityResponse getInstance(ServiceRequest request, ContextURL contextURL,
boolean references, ODataResponse response)
throws ContentNegotiatorException, SerializerException {
EntitySerializerOptions options = request.getSerializerOptions(EntitySerializerOptions.class,
contextURL, references);
return new EntityResponse(request.getServiceMetaData(), response, request.getSerializer(),
options, request.getResponseContentType(), request.getPreferences(), null,
request.getODataRequest().getRawBaseUri());
}
// write single entity
public void writeReadEntity(EdmEntityType entityType, Entity entity) throws SerializerException {
assert (!isClosed());
if (entity == null) {
writeNotFound(true);
return;
}
if (ContentTypeHelper.isODataMetadataFull(this.responseContentType)) {
EdmAction action = this.metadata.getEdm().getBoundActionWithBindingType(
entityType.getFullQualifiedName(), false);
if (action != null) {
entity.getOperations().add(buildOperation(action, entity.getId().toASCIIString()));
}
List<EdmFunction> functions = this.metadata.getEdm()
.getBoundFunctionsWithBindingType(entityType.getFullQualifiedName(),false);
for (EdmFunction function:functions) {
entity.getOperations().add(buildOperation(function, entity.getId().toASCIIString()));
}
}
// write the entity to response
this.response.setContent(this.serializer.entity(this.metadata, entityType, entity, this.options).getContent());
writeOK(responseContentType);
close();
}
public void writeCreatedEntity(EdmEntitySet entitySet, Entity entity)
throws SerializerException {
// upsert/insert must created a entity, otherwise should have throw an
// exception
assert (entity != null);
String locationHeader;
try {
locationHeader = buildLocation(this.baseURL, entity, entitySet.getName(), entitySet.getEntityType());
} catch (EdmPrimitiveTypeException e) {
throw new SerializerException(e.getMessage(), e, SerializerException.MessageKeys.WRONG_PRIMITIVE_VALUE);
}
// Note that if media written just like Stream, but on entity URL
// 8.2.8.7
if (this.returnRepresentation == ReturnRepresentation.MINIMAL) {
writeNoContent(false);
writeHeader(HttpHeader.LOCATION, locationHeader);
writeHeader("Preference-Applied", "return=minimal"); //$NON-NLS-1$ //$NON-NLS-2$
// 8.3.3
writeHeader("OData-EntityId", entity.getId().toASCIIString()); //$NON-NLS-1$
close();
return;
}
// return the content of the created entity
this.response.setContent(this.serializer.entity(this.metadata, entitySet.getEntityType(), entity, this.options)
.getContent());
writeCreated(false);
writeHeader(HttpHeader.LOCATION, locationHeader);
if (this.returnRepresentation != ReturnRepresentation.NONE) {
writeHeader("Preference-Applied", "return=representation"); //$NON-NLS-1$ //$NON-NLS-2$
}
writeHeader(HttpHeader.CONTENT_TYPE, this.responseContentType.toContentTypeString());
close();
}
public void writeUpdatedEntity() {
// spec says just success response; so either 200 or 204. 200 typically has
// payload
writeNoContent(true);
}
public void writeDeletedEntityOrReference() {
writeNoContent(true);
}
@Override
public void accepts(ServiceResponseVisior visitor) throws ODataLibraryException,
ODataApplicationException {
visitor.visit(this);
}
public void writeCreated(boolean closeResponse) {
this.response.setStatusCode(HttpStatusCode.CREATED.getStatusCode());
if (closeResponse) {
close();
}
}
public void writeError(ODataServerError error) {
try {
writeHeader(HttpHeader.CONTENT_TYPE, this.responseContentType.toContentTypeString());
writeContent(this.serializer.error(error).getContent(), error.getStatusCode(), true);
} catch (SerializerException e) {
writeServerError(true);
}
}
public void writeNotModified() {
this.response.setStatusCode(HttpStatusCode.NOT_MODIFIED.getStatusCode());
close();
}
public static String buildLocation(String baseURL, Entity entity, String enitySetName, EdmEntityType type)
throws EdmPrimitiveTypeException {
StringBuilder location = new StringBuilder();
location.append(baseURL).append("/").append(enitySetName);
int i = 0;
boolean usename = type.getKeyPredicateNames().size() > 1;
location.append("(");
for (String key : type.getKeyPredicateNames()) {
if (i > 0) {
location.append(",");
}
i++;
if (usename) {
location.append(key).append("=");
}
String propertyType = entity.getProperty(key).getType();
Object propertyValue = entity.getProperty(key).getValue();
if(propertyType.startsWith("Edm.")) {
propertyType = propertyType.substring(4);
}
EdmPrimitiveTypeKind kind = EdmPrimitiveTypeKind.valueOf(propertyType);
String value = EdmPrimitiveTypeFactory.getInstance(kind).valueToString(
propertyValue, true, 4000, 0, 0, true);
if (kind == EdmPrimitiveTypeKind.String) {
value = EdmString.getInstance().toUriLiteral(Encoder.encode(value));
}
location.append(value);
}
location.append(")");
return location.toString();
}
}