[OLINGO-1198]Create a sample project for bound actions

This commit is contained in:
ramya vasanth 2017-10-25 09:20:56 +05:30
parent dd09d61ab2
commit dd992163b7
4 changed files with 327 additions and 5 deletions

View File

@ -0,0 +1,45 @@
/*
* 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 myservice.mynamespace.data;
import org.apache.olingo.commons.api.data.Entity;
public class DemoEntityActionResult {
private Entity entity;
private boolean created = false;
public Entity getEntity() {
return entity;
}
public DemoEntityActionResult setEntity(final Entity entity) {
this.entity = entity;
return this;
}
public boolean isCreated() {
return created;
}
public DemoEntityActionResult setCreated(final boolean created) {
this.created = created;
return this;
}
}

View File

@ -23,11 +23,14 @@ import java.net.URISyntaxException;
import java.util.ArrayList;
import java.util.List;
import java.util.Locale;
import java.util.Map;
import org.apache.olingo.commons.api.data.Entity;
import org.apache.olingo.commons.api.data.EntityCollection;
import org.apache.olingo.commons.api.data.Parameter;
import org.apache.olingo.commons.api.data.Property;
import org.apache.olingo.commons.api.data.ValueType;
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.EdmKeyPropertyRef;
@ -47,6 +50,10 @@ public class Storage {
private List<Entity> productList;
private List<Entity> categoryList;
public static final String ACTION_PROVIDE_DISCOUNT = "DiscountProducts";
public static final String ACTION_PROVIDE_DISCOUNT_FOR_PRODUCT = "DiscountProduct";
public static final String AMOUNT_PROPERTY = "Amount";
public static final String PRICE_PROPERTY= "Price";
public Storage() {
@ -378,6 +385,7 @@ public class Storage {
entity.addProperty(new Property(null, "Name", ValueType.PRIMITIVE, "Notebook Basic 15"));
entity.addProperty(new Property(null, "Description", ValueType.PRIMITIVE,
"Notebook Basic, 1.7GHz - 15 XGA - 1024MB DDR2 SDRAM - 40GB"));
entity.addProperty(new Property(null, "Price", ValueType.PRIMITIVE, 100));
entity.setType(DemoEdmProvider.ET_PRODUCT_FQN.getFullQualifiedNameAsString());
entity.setId(createId(entity, "ID"));
productList.add(entity);
@ -387,6 +395,7 @@ public class Storage {
entity.addProperty(new Property(null, "Name", ValueType.PRIMITIVE, "Notebook Professional 17"));
entity.addProperty(new Property(null, "Description", ValueType.PRIMITIVE,
"Notebook Professional, 2.8GHz - 15 XGA - 8GB DDR3 RAM - 500GB"));
entity.addProperty(new Property(null, "Price", ValueType.PRIMITIVE, 200));
entity.setType(DemoEdmProvider.ET_PRODUCT_FQN.getFullQualifiedNameAsString());
entity.setId(createId(entity, "ID"));
productList.add(entity);
@ -396,6 +405,7 @@ public class Storage {
entity.addProperty(new Property(null, "Name", ValueType.PRIMITIVE, "1UMTS PDA"));
entity.addProperty(new Property(null, "Description", ValueType.PRIMITIVE,
"Ultrafast 3G UMTS/HSDPA Pocket PC, supports GSM network"));
entity.addProperty(new Property(null, "Price", ValueType.PRIMITIVE, 300));
entity.setType(DemoEdmProvider.ET_PRODUCT_FQN.getFullQualifiedNameAsString());
entity.setId(createId(entity, "ID"));
productList.add(entity);
@ -405,6 +415,7 @@ public class Storage {
entity.addProperty(new Property(null, "Name", ValueType.PRIMITIVE, "Comfort Easy"));
entity.addProperty(new Property(null, "Description", ValueType.PRIMITIVE,
"32 GB Digital Assitant with high-resolution color screen"));
entity.addProperty(new Property(null, "Price", ValueType.PRIMITIVE, 100));
entity.setType(DemoEdmProvider.ET_PRODUCT_FQN.getFullQualifiedNameAsString());
entity.setId(createId(entity, "ID"));
productList.add(entity);
@ -414,6 +425,7 @@ public class Storage {
entity.addProperty(new Property(null, "Name", ValueType.PRIMITIVE, "Ergo Screen"));
entity.addProperty(new Property(null, "Description", ValueType.PRIMITIVE,
"19 Optimum Resolution 1024 x 768 @ 85Hz, resolution 1280 x 960"));
entity.addProperty(new Property(null, "Price", ValueType.PRIMITIVE, 400));
entity.setType(DemoEdmProvider.ET_PRODUCT_FQN.getFullQualifiedNameAsString());
entity.setId(createId(entity, "ID"));
productList.add(entity);
@ -423,6 +435,7 @@ public class Storage {
entity.addProperty(new Property(null, "Name", ValueType.PRIMITIVE, "Flat Basic"));
entity.addProperty(new Property(null, "Description", ValueType.PRIMITIVE,
"Optimum Hi-Resolution max. 1600 x 1200 @ 85Hz, Dot Pitch: 0.24mm"));
entity.addProperty(new Property(null, "Price", ValueType.PRIMITIVE, 100));
entity.setType(DemoEdmProvider.ET_PRODUCT_FQN.getFullQualifiedNameAsString());
entity.setId(createId(entity, "ID"));
productList.add(entity);
@ -479,4 +492,35 @@ public class Storage {
}
return entity.getType();
}
public EntityCollection processBoundActionEntityCollection(EdmAction action, Map<String, Parameter> parameters) {
EntityCollection collection = new EntityCollection();
if (ACTION_PROVIDE_DISCOUNT.equals(action.getName())) {
for (Entity entity : categoryList) {
Entity en = getRelatedEntity(entity, (EdmEntityType) action.getReturnType().getType());
Integer currentValue = (Integer)en.getProperty(PRICE_PROPERTY).asPrimitive();
Integer newValue = currentValue - (Integer)parameters.get(AMOUNT_PROPERTY).asPrimitive();
en.getProperty(PRICE_PROPERTY).setValue(ValueType.PRIMITIVE, newValue);
collection.getEntities().add(en);
}
}
return collection;
}
public DemoEntityActionResult processBoundActionEntity(EdmAction action, Map<String, Parameter> parameters,
List<UriParameter> keyParams) throws ODataApplicationException {
DemoEntityActionResult result = new DemoEntityActionResult();
if (ACTION_PROVIDE_DISCOUNT_FOR_PRODUCT.equals(action.getName())) {
for (Entity entity : categoryList) {
Entity en = getRelatedEntity(entity, (EdmEntityType) action.getReturnType().getType(), keyParams);
Integer currentValue = (Integer)en.getProperty(PRICE_PROPERTY).asPrimitive();
Integer newValue = currentValue - (Integer)parameters.get(AMOUNT_PROPERTY).asPrimitive();
en.getProperty(PRICE_PROPERTY).setValue(ValueType.PRIMITIVE, newValue);
result.setEntity(en);
result.setCreated(true);
return result;
}
}
return null;
}
}

View File

@ -18,12 +18,21 @@
*/
package myservice.mynamespace.service;
import java.util.HashMap;
import java.util.List;
import java.util.Locale;
import java.util.Map;
import org.apache.olingo.commons.api.data.ContextURL;
import org.apache.olingo.commons.api.data.ContextURL.Builder;
import org.apache.olingo.commons.api.data.ContextURL.Suffix;
import org.apache.olingo.commons.api.data.EntityCollection;
import org.apache.olingo.commons.api.data.Parameter;
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.format.ContentType;
import org.apache.olingo.commons.api.http.HttpHeader;
import org.apache.olingo.commons.api.http.HttpStatusCode;
import org.apache.olingo.server.api.OData;
import org.apache.olingo.server.api.ODataApplicationException;
@ -32,17 +41,28 @@ import org.apache.olingo.server.api.ODataRequest;
import org.apache.olingo.server.api.ODataResponse;
import org.apache.olingo.server.api.ServiceMetadata;
import org.apache.olingo.server.api.deserializer.ODataDeserializer;
import org.apache.olingo.server.api.prefer.Preferences.Return;
import org.apache.olingo.server.api.prefer.PreferencesApplied;
import org.apache.olingo.server.api.processor.ActionEntityCollectionProcessor;
import org.apache.olingo.server.api.processor.ActionEntityProcessor;
import org.apache.olingo.server.api.processor.ActionVoidProcessor;
import org.apache.olingo.server.api.serializer.EntityCollectionSerializerOptions;
import org.apache.olingo.server.api.serializer.EntitySerializerOptions;
import org.apache.olingo.server.api.uri.UriInfo;
import org.apache.olingo.server.api.uri.UriResource;
import org.apache.olingo.server.api.uri.UriResourceAction;
import org.apache.olingo.server.api.uri.UriResourceEntitySet;
import org.apache.olingo.server.api.uri.UriResourceNavigation;
import myservice.mynamespace.data.DemoEntityActionResult;
import myservice.mynamespace.data.Storage;
public class DemoActionProcessor implements ActionVoidProcessor {
public class DemoActionProcessor implements ActionVoidProcessor, ActionEntityCollectionProcessor, ActionEntityProcessor {
private OData odata;
private Storage storage;
private ServiceMetadata serviceMetadata;
public DemoActionProcessor(final Storage storage) {
this.storage = storage;
}
@ -50,6 +70,7 @@ public class DemoActionProcessor implements ActionVoidProcessor {
@Override
public void init(final OData odata, final ServiceMetadata serviceMetadata) {
this.odata = odata;
this.serviceMetadata = serviceMetadata;
}
@Override
@ -82,4 +103,157 @@ public class DemoActionProcessor implements ActionVoidProcessor {
response.setStatusCode(HttpStatusCode.NO_CONTENT.getStatusCode());
}
@Override
public void processActionEntity(ODataRequest request, ODataResponse response, UriInfo uriInfo,
ContentType requestFormat, ContentType responseFormat) throws ODataApplicationException, ODataLibraryException {
EdmAction action = null;
Map<String, Parameter> parameters = new HashMap<String, Parameter>();
DemoEntityActionResult entityResult = null;
if (requestFormat == null) {
throw new ODataApplicationException("The content type has not been set in the request.",
HttpStatusCode.BAD_REQUEST.getStatusCode(), Locale.ROOT);
}
final ODataDeserializer deserializer = odata.createDeserializer(requestFormat);
final List<UriResource> resourcePaths = uriInfo.asUriInfoResource().getUriResourceParts();
UriResourceEntitySet boundEntity = (UriResourceEntitySet) resourcePaths.get(0);
if (resourcePaths.size() > 1) {
if (resourcePaths.get(1) instanceof UriResourceNavigation) {
action = ((UriResourceAction) resourcePaths.get(2))
.getAction();
throw new ODataApplicationException("Action " + action.getName() + " is not yet implemented.",
HttpStatusCode.NOT_IMPLEMENTED.getStatusCode(), Locale.ENGLISH);
} else if (resourcePaths.get(0) instanceof UriResourceEntitySet) {
action = ((UriResourceAction) resourcePaths.get(1))
.getAction();
parameters = deserializer.actionParameters(request.getBody(), action)
.getActionParameters();
entityResult =
storage.processBoundActionEntity(action, parameters, boundEntity.getKeyPredicates());
}
}
final EdmEntitySet edmEntitySet = boundEntity.getEntitySet();
final EdmEntityType type = (EdmEntityType) action.getReturnType().getType();
if (entityResult == null || entityResult.getEntity() == null) {
if (action.getReturnType().isNullable()) {
response.setStatusCode(HttpStatusCode.NO_CONTENT.getStatusCode());
} else {
// Not nullable return type so we have to give back a 500
throw new ODataApplicationException("The action could not be executed.",
HttpStatusCode.INTERNAL_SERVER_ERROR.getStatusCode(), Locale.ROOT);
}
} else {
final Return returnPreference = odata.createPreferences(request.getHeaders(HttpHeader.PREFER)).getReturn();
if (returnPreference == null || returnPreference == Return.REPRESENTATION) {
response.setContent(odata.createSerializer(responseFormat).entity(
serviceMetadata,
type,
entityResult.getEntity(),
EntitySerializerOptions.with()
.contextURL(isODataMetadataNone(responseFormat) ? null :
getContextUrl(action.getReturnedEntitySet(edmEntitySet), type, true))
.build())
.getContent());
response.setHeader(HttpHeader.CONTENT_TYPE, responseFormat.toContentTypeString());
response.setStatusCode((entityResult.isCreated() ? HttpStatusCode.CREATED : HttpStatusCode.OK)
.getStatusCode());
} else {
response.setStatusCode(HttpStatusCode.NO_CONTENT.getStatusCode());
}
if (returnPreference != null) {
response.setHeader(HttpHeader.PREFERENCE_APPLIED,
PreferencesApplied.with().returnRepresentation(returnPreference).build().toValueString());
}
if (entityResult.isCreated()) {
final String location = request.getRawBaseUri() + '/'
+ odata.createUriHelper().buildCanonicalURL(edmEntitySet, entityResult.getEntity());
response.setHeader(HttpHeader.LOCATION, location);
if (returnPreference == Return.MINIMAL) {
response.setHeader(HttpHeader.ODATA_ENTITY_ID, location);
}
}
if (entityResult.getEntity().getETag() != null) {
response.setHeader(HttpHeader.ETAG, entityResult.getEntity().getETag());
}
}
}
@Override
public void processActionEntityCollection(ODataRequest request, ODataResponse response, UriInfo uriInfo,
ContentType requestFormat, ContentType responseFormat) throws ODataApplicationException, ODataLibraryException {
Map<String, Parameter> parameters = new HashMap<String, Parameter>();
EdmAction action = null;
EntityCollection collection = null;
if (requestFormat == null) {
throw new ODataApplicationException("The content type has not been set in the request.",
HttpStatusCode.BAD_REQUEST.getStatusCode(), Locale.ROOT);
}
List<UriResource> resourcePaths = uriInfo.asUriInfoResource().getUriResourceParts();
final ODataDeserializer deserializer = odata.createDeserializer(requestFormat);
UriResourceEntitySet boundEntitySet = (UriResourceEntitySet) resourcePaths.get(0);
if (resourcePaths.size() > 1) {
if (resourcePaths.get(1) instanceof UriResourceNavigation) {
action = ((UriResourceAction) resourcePaths.get(2))
.getAction();
throw new ODataApplicationException("Action " + action.getName() + " is not yet implemented.",
HttpStatusCode.NOT_IMPLEMENTED.getStatusCode(), Locale.ENGLISH);
} else {
action = ((UriResourceAction) resourcePaths.get(1))
.getAction();
parameters = deserializer.actionParameters(request.getBody(), action)
.getActionParameters();
collection =
storage.processBoundActionEntityCollection(action, parameters);
}
}
// Collections must never be null.
// Not nullable return types must not contain a null value.
if (collection == null
|| collection.getEntities().contains(null) && !action.getReturnType().isNullable()) {
throw new ODataApplicationException("The action could not be executed.",
HttpStatusCode.INTERNAL_SERVER_ERROR.getStatusCode(), Locale.ROOT);
}
final Return returnPreference = odata.createPreferences(request.getHeaders(HttpHeader.PREFER)).getReturn();
if (returnPreference == null || returnPreference == Return.REPRESENTATION) {
final EdmEntitySet edmEntitySet = boundEntitySet.getEntitySet();
final EdmEntityType type = (EdmEntityType) action.getReturnType().getType();
final EntityCollectionSerializerOptions options = EntityCollectionSerializerOptions.with()
.contextURL(isODataMetadataNone(responseFormat) ? null :
getContextUrl(action.getReturnedEntitySet(edmEntitySet), type, false))
.build();
response.setContent(odata.createSerializer(responseFormat)
.entityCollection(serviceMetadata, type, collection, options).getContent());
response.setHeader(HttpHeader.CONTENT_TYPE, responseFormat.toContentTypeString());
response.setStatusCode(HttpStatusCode.OK.getStatusCode());
} else {
response.setStatusCode(HttpStatusCode.NO_CONTENT.getStatusCode());
}
if (returnPreference != null) {
response.setHeader(HttpHeader.PREFERENCE_APPLIED,
PreferencesApplied.with().returnRepresentation(returnPreference).build().toValueString());
}
}
private ContextURL getContextUrl(final EdmEntitySet entitySet, final EdmEntityType entityType,
final boolean isSingleEntity) throws ODataLibraryException {
Builder builder = ContextURL.with();
builder = entitySet == null ?
isSingleEntity ? builder.type(entityType) : builder.asCollection().type(entityType) :
builder.entitySet(entitySet);
builder = builder.suffix(isSingleEntity && entitySet != null ? Suffix.ENTITY : null);
return builder.build();
}
protected boolean isODataMetadataNone(final ContentType contentType) {
return contentType.isCompatible(ContentType.APPLICATION_JSON)
&& ContentType.VALUE_ODATA_METADATA_NONE.equalsIgnoreCase(
contentType.getParameter(ContentType.PARAMETER_ODATA_METADATA));
}
}

View File

@ -70,6 +70,14 @@ public class DemoEdmProvider extends CsdlAbstractEdmProvider {
public static final String ACTION_RESET = "Reset";
public static final FullQualifiedName ACTION_RESET_FQN = new FullQualifiedName(NAMESPACE, ACTION_RESET);
//Bound Action
public static final String ACTION_PROVIDE_DISCOUNT = "DiscountProducts";
public static final FullQualifiedName ACTION_PROVIDE_DISCOUNT_FQN = new FullQualifiedName(NAMESPACE, ACTION_PROVIDE_DISCOUNT);
//Bound Action
public static final String ACTION_PROVIDE_DISCOUNT_FOR_PRODUCT = "DiscountProduct";
public static final FullQualifiedName ACTION_PROVIDE_DISCOUNT_FOR_PRODUCT_FQN = new FullQualifiedName(NAMESPACE, ACTION_PROVIDE_DISCOUNT_FOR_PRODUCT);
// Function
public static final String FUNCTION_COUNT_CATEGORIES = "CountCategories";
public static final FullQualifiedName FUNCTION_COUNT_CATEGORIES_FQN
@ -78,11 +86,14 @@ public class DemoEdmProvider extends CsdlAbstractEdmProvider {
// Function/Action Parameters
public static final String PARAMETER_AMOUNT = "Amount";
//Bound Action Binding Parameter
public static final String PARAMETER_CATEGORY = "ParamCategory";
@Override
public List<CsdlAction> getActions(final FullQualifiedName actionName) {
// It is allowed to overload actions, so we have to provide a list of Actions for each action name
final List<CsdlAction> actions = new ArrayList<CsdlAction>();
if(actionName.equals(ACTION_RESET_FQN)) {
// It is allowed to overload actions, so we have to provide a list of Actions for each action name
final List<CsdlAction> actions = new ArrayList<CsdlAction>();
// Create parameters
final List<CsdlParameter> parameters = new ArrayList<CsdlParameter>();
@ -97,6 +108,50 @@ public class DemoEdmProvider extends CsdlAbstractEdmProvider {
action.setParameters(parameters);
actions.add(action);
return actions;
} else if (actionName.equals(ACTION_PROVIDE_DISCOUNT_FQN)) {
// Create parameters
final List<CsdlParameter> parameters = new ArrayList<CsdlParameter>();
CsdlParameter parameter = new CsdlParameter();
parameter.setName(PARAMETER_CATEGORY);
parameter.setType(ET_CATEGORY_FQN);
parameter.setCollection(true);
parameters.add(parameter);
parameter = new CsdlParameter();
parameter.setName(PARAMETER_AMOUNT);
parameter.setType(EdmPrimitiveTypeKind.Int32.getFullQualifiedName());
parameters.add(parameter);
// Create the Csdl Action
final CsdlAction action = new CsdlAction();
action.setName(ACTION_PROVIDE_DISCOUNT_FQN.getName());
action.setBound(true);
action.setParameters(parameters);
action.setReturnType(new CsdlReturnType().setType(ET_PRODUCT_FQN).setCollection(true));
actions.add(action);
return actions;
} else if (actionName.equals(ACTION_PROVIDE_DISCOUNT_FOR_PRODUCT_FQN)) {
// Create parameters
final List<CsdlParameter> parameters = new ArrayList<CsdlParameter>();
CsdlParameter parameter = new CsdlParameter();
parameter.setName(PARAMETER_CATEGORY);
parameter.setType(ET_CATEGORY_FQN);
parameter.setCollection(false);
parameters.add(parameter);
parameter = new CsdlParameter();
parameter.setName(PARAMETER_AMOUNT);
parameter.setType(EdmPrimitiveTypeKind.Int32.getFullQualifiedName());
parameters.add(parameter);
// Create the Csdl Action
final CsdlAction action = new CsdlAction();
action.setName(ACTION_PROVIDE_DISCOUNT_FOR_PRODUCT_FQN.getName());
action.setBound(true);
action.setParameters(parameters);
action.setReturnType(new CsdlReturnType().setType(ET_PRODUCT_FQN).setCollection(false));
actions.add(action);
return actions;
}
@ -174,6 +229,8 @@ public class DemoEdmProvider extends CsdlAbstractEdmProvider {
.setType(EdmPrimitiveTypeKind.String.getFullQualifiedName());
CsdlProperty description = new CsdlProperty().setName("Description")
.setType(EdmPrimitiveTypeKind.String.getFullQualifiedName());
CsdlProperty price = new CsdlProperty().setName("Price")
.setType(EdmPrimitiveTypeKind.Int32.getFullQualifiedName());
// create PropertyRef for Key element
CsdlPropertyRef propertyRef = new CsdlPropertyRef();
@ -189,7 +246,7 @@ public class DemoEdmProvider extends CsdlAbstractEdmProvider {
// configure EntityType
entityType = new CsdlEntityType();
entityType.setName(ET_PRODUCT_NAME);
entityType.setProperties(Arrays.asList(id, name, description));
entityType.setProperties(Arrays.asList(id, name, description, price));
entityType.setKey(Arrays.asList(propertyRef));
entityType.setNavigationProperties(navPropList);
@ -279,6 +336,8 @@ public class DemoEdmProvider extends CsdlAbstractEdmProvider {
// add actions
List<CsdlAction> actions = new ArrayList<CsdlAction>();
actions.addAll(getActions(ACTION_RESET_FQN));
actions.addAll(getActions(ACTION_PROVIDE_DISCOUNT_FQN));
actions.addAll(getActions(ACTION_PROVIDE_DISCOUNT_FOR_PRODUCT_FQN));
schema.setActions(actions);
// add functions