[OLINGO-713] Updated Tutorial p0 with action/function importrs
This commit is contained in:
parent
d483c8fd1e
commit
1051f9b6cf
|
@ -39,7 +39,9 @@ import org.apache.olingo.commons.api.ex.ODataRuntimeException;
|
|||
import org.apache.olingo.commons.api.http.HttpMethod;
|
||||
import org.apache.olingo.commons.api.http.HttpStatusCode;
|
||||
import org.apache.olingo.server.api.ODataApplicationException;
|
||||
import org.apache.olingo.server.api.ServiceMetadata;
|
||||
import org.apache.olingo.server.api.uri.UriParameter;
|
||||
import org.apache.olingo.server.api.uri.UriResourceFunction;
|
||||
|
||||
public class Storage {
|
||||
|
||||
|
@ -59,30 +61,97 @@ public class Storage {
|
|||
|
||||
/* PUBLIC FACADE */
|
||||
|
||||
public EntityCollection readEntitySetData(EdmEntitySet edmEntitySet) {
|
||||
EntityCollection entitySet = null;
|
||||
public Entity readFunctionImportEntity(final UriResourceFunction uriResourceFunction,
|
||||
final ServiceMetadata serviceMetadata) throws ODataApplicationException {
|
||||
|
||||
if (edmEntitySet.getName().equals(DemoEdmProvider.ES_PRODUCTS_NAME)) {
|
||||
entitySet = getProducts();
|
||||
} else if (edmEntitySet.getName().equals(DemoEdmProvider.ES_CATEGORIES_NAME)) {
|
||||
entitySet = getCategories();
|
||||
}
|
||||
final EntityCollection entityCollection = readFunctionImportCollection(uriResourceFunction, serviceMetadata);
|
||||
final EdmEntityType edmEntityType = (EdmEntityType) uriResourceFunction.getFunction().getReturnType().getType();
|
||||
|
||||
return entitySet;
|
||||
return Util.findEntity(edmEntityType, entityCollection, uriResourceFunction.getKeyPredicates());
|
||||
}
|
||||
|
||||
public Entity readEntityData(EdmEntitySet edmEntitySet, List<UriParameter> keyParams) {
|
||||
Entity entity = null;
|
||||
public EntityCollection readFunctionImportCollection(final UriResourceFunction uriResourceFunction,
|
||||
final ServiceMetadata serviceMetadata) throws ODataApplicationException {
|
||||
|
||||
if (DemoEdmProvider.FUNCTION_COUNT_CATEGORIES.equals(uriResourceFunction.getFunctionImport().getName())) {
|
||||
// Get the parameter of the function
|
||||
final UriParameter parameterAmount = uriResourceFunction.getParameters().get(0);
|
||||
// Try to convert the parameter to an Integer.
|
||||
// We have to take care, that the type of parameter fits to its EDM declaration
|
||||
int amount;
|
||||
try {
|
||||
amount = Integer.parseInt(parameterAmount.getText());
|
||||
} catch (NumberFormatException e) {
|
||||
throw new ODataApplicationException("Type of parameter Amount must be Edm.Int32", HttpStatusCode.BAD_REQUEST
|
||||
.getStatusCode(), Locale.ENGLISH);
|
||||
}
|
||||
|
||||
final EdmEntityType productEntityType = serviceMetadata.getEdm().getEntityType(DemoEdmProvider.ET_PRODUCT_FQN);
|
||||
final List<Entity> resultEntityList = new ArrayList<Entity>();
|
||||
|
||||
// Loop over all categories and check how many products are linked
|
||||
for (final Entity category : categoryList) {
|
||||
final EntityCollection products = getRelatedEntityCollection(category, productEntityType);
|
||||
if (products.getEntities().size() == amount) {
|
||||
resultEntityList.add(category);
|
||||
}
|
||||
}
|
||||
|
||||
final EntityCollection resultCollection = new EntityCollection();
|
||||
resultCollection.getEntities().addAll(resultEntityList);
|
||||
return resultCollection;
|
||||
} else {
|
||||
throw new ODataApplicationException("Function not implemented", HttpStatusCode.NOT_IMPLEMENTED.getStatusCode(),
|
||||
Locale.ROOT);
|
||||
}
|
||||
}
|
||||
|
||||
public void resetDataSet() {
|
||||
resetDataSet(Integer.MAX_VALUE);
|
||||
}
|
||||
|
||||
public void resetDataSet(final int amount) {
|
||||
// Replace the old lists with empty ones
|
||||
productList = new ArrayList<Entity>();
|
||||
categoryList = new ArrayList<Entity>();
|
||||
|
||||
// Create new sample data
|
||||
initProductSampleData();
|
||||
initCategorySampleData();
|
||||
|
||||
// Truncate the lists
|
||||
if (amount < productList.size()) {
|
||||
productList = productList.subList(0, amount);
|
||||
// Products 0, 1 are linked to category 0
|
||||
// Products 2, 3 are linked to category 1
|
||||
// Products 4, 5 are linked to category 2
|
||||
categoryList = categoryList.subList(0, (amount / 2) + 1);
|
||||
}
|
||||
}
|
||||
|
||||
public EntityCollection readEntitySetData(EdmEntitySet edmEntitySet) throws ODataApplicationException {
|
||||
|
||||
if (edmEntitySet.getName().equals(DemoEdmProvider.ES_PRODUCTS_NAME)) {
|
||||
return getEntityCollection(productList);
|
||||
} else if (edmEntitySet.getName().equals(DemoEdmProvider.ES_CATEGORIES_NAME)) {
|
||||
return getEntityCollection(categoryList);
|
||||
}
|
||||
|
||||
return null;
|
||||
}
|
||||
|
||||
public Entity readEntityData(EdmEntitySet edmEntitySet, List<UriParameter> keyParams)
|
||||
throws ODataApplicationException {
|
||||
|
||||
EdmEntityType edmEntityType = edmEntitySet.getEntityType();
|
||||
|
||||
if (edmEntityType.getName().equals(DemoEdmProvider.ET_PRODUCT_NAME)) {
|
||||
entity = getProduct(edmEntityType, keyParams);
|
||||
return getEntity(edmEntityType, keyParams, productList);
|
||||
} else if (edmEntityType.getName().equals(DemoEdmProvider.ET_CATEGORY_NAME)) {
|
||||
entity = getCategory(edmEntityType, keyParams);
|
||||
return getEntity(edmEntityType, keyParams, categoryList);
|
||||
}
|
||||
|
||||
return entity;
|
||||
return null;
|
||||
}
|
||||
|
||||
// Navigation
|
||||
|
@ -109,37 +178,31 @@ public class Storage {
|
|||
|
||||
if (sourceEntityFqn.equals(DemoEdmProvider.ET_PRODUCT_FQN.getFullQualifiedNameAsString())
|
||||
&& relatedEntityFqn.equals(DemoEdmProvider.ET_CATEGORY_FQN)) {
|
||||
navigationTargetEntityCollection.setId(createId(sourceEntity, "ID", DemoEdmProvider.NAV_TO_CATEGORY));
|
||||
// relation Products->Category (result all categories)
|
||||
int productID = (Integer) sourceEntity.getProperty("ID").getValue();
|
||||
if (productID == 1 || productID == 2) {
|
||||
if (productID == 0 || productID == 1) {
|
||||
navigationTargetEntityCollection.getEntities().add(categoryList.get(0));
|
||||
} else if (productID == 3 || productID == 4) {
|
||||
} else if (productID == 2 || productID == 3) {
|
||||
navigationTargetEntityCollection.getEntities().add(categoryList.get(1));
|
||||
} else if (productID == 5 || productID == 6) {
|
||||
} else if (productID == 4 || productID == 5) {
|
||||
navigationTargetEntityCollection.getEntities().add(categoryList.get(2));
|
||||
}
|
||||
} else if (sourceEntityFqn.equals(DemoEdmProvider.ET_CATEGORY_FQN.getFullQualifiedNameAsString())
|
||||
&& relatedEntityFqn.equals(DemoEdmProvider.ET_PRODUCT_FQN)) {
|
||||
navigationTargetEntityCollection.setId(createId(sourceEntity, "ID", DemoEdmProvider.NAV_TO_PRODUCTS));
|
||||
// relation Category->Products (result all products)
|
||||
int categoryID = (Integer) sourceEntity.getProperty("ID").getValue();
|
||||
if (categoryID == 1) {
|
||||
if (categoryID == 0) {
|
||||
// the first 2 products are notebooks
|
||||
navigationTargetEntityCollection.getEntities().addAll(productList.subList(0, 2));
|
||||
} else if (categoryID == 2) {
|
||||
} else if (categoryID == 1) {
|
||||
// the next 2 products are organizers
|
||||
navigationTargetEntityCollection.getEntities().addAll(productList.subList(2, 4));
|
||||
} else if (categoryID == 3) {
|
||||
} else if (categoryID == 2) {
|
||||
// the first 2 products are monitors
|
||||
navigationTargetEntityCollection.getEntities().addAll(productList.subList(4, 6));
|
||||
}
|
||||
}
|
||||
|
||||
if (navigationTargetEntityCollection.getEntities().isEmpty()) {
|
||||
return null;
|
||||
}
|
||||
|
||||
return navigationTargetEntityCollection;
|
||||
}
|
||||
|
||||
|
@ -147,9 +210,10 @@ public class Storage {
|
|||
|
||||
EdmEntityType edmEntityType = edmEntitySet.getEntityType();
|
||||
|
||||
// actually, this is only required if we have more than one Entity Type
|
||||
if (edmEntityType.getName().equals(DemoEdmProvider.ET_PRODUCT_NAME)) {
|
||||
return createProduct(edmEntityType, entityToCreate);
|
||||
return createEntity(edmEntityType, entityToCreate, productList);
|
||||
} else if (edmEntityType.getName().equals(DemoEdmProvider.ET_CATEGORY_NAME)) {
|
||||
return createEntity(edmEntityType, entityToCreate, categoryList);
|
||||
}
|
||||
|
||||
return null;
|
||||
|
@ -157,15 +221,16 @@ public class Storage {
|
|||
|
||||
/**
|
||||
* This method is invoked for PATCH or PUT requests
|
||||
* */
|
||||
*/
|
||||
public void updateEntityData(EdmEntitySet edmEntitySet, List<UriParameter> keyParams, Entity updateEntity,
|
||||
HttpMethod httpMethod) throws ODataApplicationException {
|
||||
|
||||
EdmEntityType edmEntityType = edmEntitySet.getEntityType();
|
||||
|
||||
// actually, this is only required if we have more than one Entity Type
|
||||
if (edmEntityType.getName().equals(DemoEdmProvider.ET_PRODUCT_NAME)) {
|
||||
updateProduct(edmEntityType, keyParams, updateEntity, httpMethod);
|
||||
updateEntity(edmEntityType, keyParams, updateEntity, httpMethod, productList);
|
||||
} else if (edmEntityType.getName().equals(DemoEdmProvider.ET_CATEGORY_NAME)) {
|
||||
updateEntity(edmEntityType, keyParams, updateEntity, httpMethod, categoryList);
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -174,63 +239,86 @@ public class Storage {
|
|||
|
||||
EdmEntityType edmEntityType = edmEntitySet.getEntityType();
|
||||
|
||||
// actually, this is only required if we have more than one Entity Type
|
||||
if (edmEntityType.getName().equals(DemoEdmProvider.ET_PRODUCT_NAME)) {
|
||||
deleteProduct(edmEntityType, keyParams);
|
||||
deleteEntity(edmEntityType, keyParams, productList);
|
||||
} else if (edmEntityType.getName().equals(DemoEdmProvider.ET_CATEGORY_NAME)) {
|
||||
deleteEntity(edmEntityType, keyParams, categoryList);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
/* INTERNAL */
|
||||
|
||||
private EntityCollection getProducts() {
|
||||
EntityCollection retEntitySet = new EntityCollection();
|
||||
private Entity createEntity(EdmEntityType edmEntityType, Entity entity, List<Entity> entityList) {
|
||||
|
||||
for (Entity productEntity : this.productList) {
|
||||
retEntitySet.getEntities().add(productEntity);
|
||||
// the ID of the newly created entity is generated automatically
|
||||
int newId = 1;
|
||||
while (entityIdExists(newId, entityList)) {
|
||||
newId++;
|
||||
}
|
||||
|
||||
Property idProperty = entity.getProperty("ID");
|
||||
if (idProperty != null) {
|
||||
idProperty.setValue(ValueType.PRIMITIVE, Integer.valueOf(newId));
|
||||
} else {
|
||||
// as of OData v4 spec, the key property can be omitted from the POST request body
|
||||
entity.getProperties().add(new Property(null, "ID", ValueType.PRIMITIVE, newId));
|
||||
}
|
||||
entity.setId(createId(entity, "ID"));
|
||||
entityList.add(entity);
|
||||
|
||||
return entity;
|
||||
}
|
||||
|
||||
private EntityCollection getEntityCollection(final List<Entity> entityList) {
|
||||
|
||||
EntityCollection retEntitySet = new EntityCollection();
|
||||
retEntitySet.getEntities().addAll(entityList);
|
||||
|
||||
return retEntitySet;
|
||||
}
|
||||
|
||||
private Entity getProduct(EdmEntityType edmEntityType, List<UriParameter> keyParams) {
|
||||
private Entity getEntity(EdmEntityType edmEntityType, List<UriParameter> keyParams, List<Entity> entityList)
|
||||
throws ODataApplicationException {
|
||||
|
||||
// the list of entities at runtime
|
||||
EntityCollection entityCollection = getProducts();
|
||||
EntityCollection entitySet = getEntityCollection(entityList);
|
||||
|
||||
/* generic approach to find the requested entity */
|
||||
return Util.findEntity(edmEntityType, entityCollection, keyParams);
|
||||
}
|
||||
Entity requestedEntity = Util.findEntity(edmEntityType, entitySet, keyParams);
|
||||
|
||||
private EntityCollection getCategories() {
|
||||
EntityCollection entitySet = new EntityCollection();
|
||||
|
||||
for (Entity categoryEntity : this.categoryList) {
|
||||
entitySet.getEntities().add(categoryEntity);
|
||||
if (requestedEntity == null) {
|
||||
// this variable is null if our data doesn't contain an entity for the requested key
|
||||
// Throw suitable exception
|
||||
throw new ODataApplicationException("Entity for requested key doesn't exist",
|
||||
HttpStatusCode.NOT_FOUND.getStatusCode(), Locale.ENGLISH);
|
||||
}
|
||||
|
||||
return entitySet;
|
||||
return requestedEntity;
|
||||
}
|
||||
|
||||
private Entity getCategory(EdmEntityType edmEntityType, List<UriParameter> keyParams) {
|
||||
private boolean entityIdExists(int id, List<Entity> entityList) {
|
||||
|
||||
// the list of entities at runtime
|
||||
EntityCollection entitySet = getCategories();
|
||||
for (Entity entity : entityList) {
|
||||
Integer existingID = (Integer) entity.getProperty("ID").getValue();
|
||||
if (existingID.intValue() == id) {
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
||||
/* generic approach to find the requested entity */
|
||||
return Util.findEntity(edmEntityType, entitySet, keyParams);
|
||||
return false;
|
||||
}
|
||||
|
||||
private void updateProduct(EdmEntityType edmEntityType, List<UriParameter> keyParams, Entity entity,
|
||||
HttpMethod httpMethod) throws ODataApplicationException {
|
||||
|
||||
Entity productEntity = getProduct(edmEntityType, keyParams);
|
||||
if (productEntity == null) {
|
||||
private void updateEntity(EdmEntityType edmEntityType, List<UriParameter> keyParams, Entity updateEntity,
|
||||
HttpMethod httpMethod, List<Entity> entityList) throws ODataApplicationException {
|
||||
|
||||
Entity entity = getEntity(edmEntityType, keyParams, entityList);
|
||||
if (entity == null) {
|
||||
throw new ODataApplicationException("Entity not found", HttpStatusCode.NOT_FOUND.getStatusCode(), Locale.ENGLISH);
|
||||
}
|
||||
|
||||
// loop over all properties and replace the values with the values of the given payload
|
||||
// Note: ignoring ComplexType, as we don't have it in our odata model
|
||||
List<Property> existingProperties = productEntity.getProperties();
|
||||
List<Property> existingProperties = entity.getProperties();
|
||||
for (Property existingProp : existingProperties) {
|
||||
String propName = existingProp.getName();
|
||||
|
||||
|
@ -239,7 +327,7 @@ public class Storage {
|
|||
continue;
|
||||
}
|
||||
|
||||
Property updateProperty = entity.getProperty(propName);
|
||||
Property updateProperty = updateEntity.getProperty(propName);
|
||||
// the request payload might not consider ALL properties, so it can be null
|
||||
if (updateProperty == null) {
|
||||
// if a property has NOT been added to the request payload
|
||||
|
@ -258,54 +346,18 @@ public class Storage {
|
|||
existingProp.setValue(existingProp.getValueType(), updateProperty.getValue());
|
||||
}
|
||||
}
|
||||
|
||||
private void deleteProduct(EdmEntityType edmEntityType, List<UriParameter> keyParams)
|
||||
|
||||
private void deleteEntity(EdmEntityType edmEntityType, List<UriParameter> keyParams, List<Entity> entityList)
|
||||
throws ODataApplicationException {
|
||||
|
||||
Entity productEntity = getProduct(edmEntityType, keyParams);
|
||||
if (productEntity == null) {
|
||||
|
||||
Entity entity = getEntity(edmEntityType, keyParams, entityList);
|
||||
if (entity == null) {
|
||||
throw new ODataApplicationException("Entity not found", HttpStatusCode.NOT_FOUND.getStatusCode(), Locale.ENGLISH);
|
||||
}
|
||||
|
||||
this.productList.remove(productEntity);
|
||||
entityList.remove(entity);
|
||||
}
|
||||
|
||||
private Entity createProduct(EdmEntityType edmEntityType, Entity entity) {
|
||||
|
||||
// the ID of the newly created product entity is generated automatically
|
||||
int newId = 1;
|
||||
while (productIdExists(newId)) {
|
||||
newId++;
|
||||
}
|
||||
|
||||
Property idProperty = entity.getProperty("ID");
|
||||
if (idProperty != null) {
|
||||
idProperty.setValue(ValueType.PRIMITIVE, Integer.valueOf(newId));
|
||||
} else {
|
||||
// as of OData v4 spec, the key property can be omitted from the POST request body
|
||||
entity.getProperties().add(new Property(null, "ID", ValueType.PRIMITIVE, newId));
|
||||
}
|
||||
entity.setId(createId(entity, "ID"));
|
||||
this.productList.add(entity);
|
||||
|
||||
return entity;
|
||||
|
||||
}
|
||||
|
||||
private boolean productIdExists(int id) {
|
||||
|
||||
for (Entity entity : this.productList) {
|
||||
Integer existingID = (Integer) entity.getProperty("ID").getValue();
|
||||
if (existingID.intValue() == id) {
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
/* HELPER */
|
||||
|
||||
private boolean isKey(EdmEntityType edmEntityType, String propertyName) {
|
||||
List<EdmKeyPropertyRef> keyPropertyRefs = edmEntityType.getKeyPropertyRefs();
|
||||
for (EdmKeyPropertyRef propRef : keyPropertyRefs) {
|
||||
|
@ -316,12 +368,12 @@ public class Storage {
|
|||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
|
||||
private void initProductSampleData() {
|
||||
|
||||
Entity entity = new Entity();
|
||||
|
||||
entity.addProperty(new Property(null, "ID", ValueType.PRIMITIVE, 1));
|
||||
entity.addProperty(new Property(null, "ID", ValueType.PRIMITIVE, 0));
|
||||
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"));
|
||||
|
@ -330,7 +382,7 @@ public class Storage {
|
|||
productList.add(entity);
|
||||
|
||||
entity = new Entity();
|
||||
entity.addProperty(new Property(null, "ID", ValueType.PRIMITIVE, 2));
|
||||
entity.addProperty(new Property(null, "ID", ValueType.PRIMITIVE, 1));
|
||||
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"));
|
||||
|
@ -339,7 +391,7 @@ public class Storage {
|
|||
productList.add(entity);
|
||||
|
||||
entity = new Entity();
|
||||
entity.addProperty(new Property(null, "ID", ValueType.PRIMITIVE, 3));
|
||||
entity.addProperty(new Property(null, "ID", ValueType.PRIMITIVE, 2));
|
||||
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"));
|
||||
|
@ -348,7 +400,7 @@ public class Storage {
|
|||
productList.add(entity);
|
||||
|
||||
entity = new Entity();
|
||||
entity.addProperty(new Property(null, "ID", ValueType.PRIMITIVE, 4));
|
||||
entity.addProperty(new Property(null, "ID", ValueType.PRIMITIVE, 3));
|
||||
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"));
|
||||
|
@ -357,7 +409,7 @@ public class Storage {
|
|||
productList.add(entity);
|
||||
|
||||
entity = new Entity();
|
||||
entity.addProperty(new Property(null, "ID", ValueType.PRIMITIVE, 5));
|
||||
entity.addProperty(new Property(null, "ID", ValueType.PRIMITIVE, 4));
|
||||
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"));
|
||||
|
@ -366,7 +418,7 @@ public class Storage {
|
|||
productList.add(entity);
|
||||
|
||||
entity = new Entity();
|
||||
entity.addProperty(new Property(null, "ID", ValueType.PRIMITIVE, 6));
|
||||
entity.addProperty(new Property(null, "ID", ValueType.PRIMITIVE, 5));
|
||||
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"));
|
||||
|
@ -379,21 +431,21 @@ public class Storage {
|
|||
|
||||
Entity entity = new Entity();
|
||||
|
||||
entity.addProperty(new Property(null, "ID", ValueType.PRIMITIVE, 1));
|
||||
entity.addProperty(new Property(null, "ID", ValueType.PRIMITIVE, 0));
|
||||
entity.addProperty(new Property(null, "Name", ValueType.PRIMITIVE, "Notebooks"));
|
||||
entity.setType(DemoEdmProvider.ET_CATEGORY_FQN.getFullQualifiedNameAsString());
|
||||
entity.setId(createId(entity, "ID"));
|
||||
categoryList.add(entity);
|
||||
|
||||
entity = new Entity();
|
||||
entity.addProperty(new Property(null, "ID", ValueType.PRIMITIVE, 2));
|
||||
entity.addProperty(new Property(null, "ID", ValueType.PRIMITIVE, 1));
|
||||
entity.addProperty(new Property(null, "Name", ValueType.PRIMITIVE, "Organizers"));
|
||||
entity.setType(DemoEdmProvider.ET_CATEGORY_FQN.getFullQualifiedNameAsString());
|
||||
entity.setId(createId(entity, "ID"));
|
||||
categoryList.add(entity);
|
||||
|
||||
entity = new Entity();
|
||||
entity.addProperty(new Property(null, "ID", ValueType.PRIMITIVE, 3));
|
||||
entity.addProperty(new Property(null, "ID", ValueType.PRIMITIVE, 2));
|
||||
entity.addProperty(new Property(null, "Name", ValueType.PRIMITIVE, "Monitors"));
|
||||
entity.setType(DemoEdmProvider.ET_CATEGORY_FQN.getFullQualifiedNameAsString());
|
||||
entity.setId(createId(entity, "ID"));
|
||||
|
@ -409,7 +461,7 @@ public class Storage {
|
|||
StringBuilder sb = new StringBuilder(getEntitySetName(entity)).append("(");
|
||||
final Property property = entity.getProperty(idPropertyName);
|
||||
sb.append(property.asPrimitive()).append(")");
|
||||
if(navigationName != null) {
|
||||
if (navigationName != null) {
|
||||
sb.append("/").append(navigationName);
|
||||
}
|
||||
return new URI(sb.toString());
|
||||
|
@ -419,9 +471,9 @@ public class Storage {
|
|||
}
|
||||
|
||||
private String getEntitySetName(Entity entity) {
|
||||
if(DemoEdmProvider.ET_CATEGORY_FQN.getFullQualifiedNameAsString().equals(entity.getType())) {
|
||||
if (DemoEdmProvider.ET_CATEGORY_FQN.getFullQualifiedNameAsString().equals(entity.getType())) {
|
||||
return DemoEdmProvider.ES_CATEGORIES_NAME;
|
||||
} else if(DemoEdmProvider.ET_PRODUCT_FQN.getFullQualifiedNameAsString().equals(entity.getType())) {
|
||||
} else if (DemoEdmProvider.ET_PRODUCT_FQN.getFullQualifiedNameAsString().equals(entity.getType())) {
|
||||
return DemoEdmProvider.ES_PRODUCTS_NAME;
|
||||
}
|
||||
return entity.getType();
|
||||
|
|
|
@ -0,0 +1,85 @@
|
|||
/*
|
||||
* 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.service;
|
||||
|
||||
import java.util.Locale;
|
||||
import java.util.Map;
|
||||
|
||||
import org.apache.olingo.commons.api.data.Parameter;
|
||||
import org.apache.olingo.commons.api.edm.EdmAction;
|
||||
import org.apache.olingo.commons.api.format.ContentType;
|
||||
import org.apache.olingo.commons.api.http.HttpStatusCode;
|
||||
import org.apache.olingo.server.api.OData;
|
||||
import org.apache.olingo.server.api.ODataApplicationException;
|
||||
import org.apache.olingo.server.api.ODataLibraryException;
|
||||
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.processor.ActionVoidProcessor;
|
||||
import org.apache.olingo.server.api.uri.UriInfo;
|
||||
import org.apache.olingo.server.api.uri.UriResourceAction;
|
||||
|
||||
import myservice.mynamespace.data.Storage;
|
||||
|
||||
public class DemoActionProcessor implements ActionVoidProcessor {
|
||||
|
||||
private OData odata;
|
||||
private Storage storage;
|
||||
|
||||
public DemoActionProcessor(final Storage storage) {
|
||||
this.storage = storage;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void init(final OData odata, final ServiceMetadata serviceMetadata) {
|
||||
this.odata = odata;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void processActionVoid(ODataRequest request, ODataResponse response, UriInfo uriInfo,
|
||||
ContentType requestFormat) throws ODataApplicationException, ODataLibraryException {
|
||||
|
||||
// 1st Get the action from the resource path
|
||||
final EdmAction edmAction = ((UriResourceAction) uriInfo.asUriInfoResource().getUriResourceParts()
|
||||
.get(0)).getAction();
|
||||
|
||||
// 2nd Deserialize the parameter
|
||||
// In our case there is only one action. So we can be sure that parameter "Amount" has been provided by the client
|
||||
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 Map<String, Parameter> actionParameter = deserializer.actionParameters(request.getBody(), edmAction)
|
||||
.getActionParameters();
|
||||
final Parameter parameterAmount = actionParameter.get(DemoEdmProvider.PARAMETER_AMOUNT);
|
||||
|
||||
// The parameter amount is nullable
|
||||
if(parameterAmount.isNull()) {
|
||||
storage.resetDataSet();
|
||||
} else {
|
||||
final Integer amount = (Integer) parameterAmount.asPrimitive();
|
||||
storage.resetDataSet(amount);
|
||||
}
|
||||
|
||||
response.setStatusCode(HttpStatusCode.NO_CONTENT.getStatusCode());
|
||||
}
|
||||
}
|
|
@ -25,14 +25,20 @@ import java.util.List;
|
|||
import org.apache.olingo.commons.api.edm.EdmPrimitiveTypeKind;
|
||||
import org.apache.olingo.commons.api.edm.FullQualifiedName;
|
||||
import org.apache.olingo.commons.api.edm.provider.CsdlAbstractEdmProvider;
|
||||
import org.apache.olingo.commons.api.edm.provider.CsdlAction;
|
||||
import org.apache.olingo.commons.api.edm.provider.CsdlActionImport;
|
||||
import org.apache.olingo.commons.api.edm.provider.CsdlEntityContainer;
|
||||
import org.apache.olingo.commons.api.edm.provider.CsdlEntityContainerInfo;
|
||||
import org.apache.olingo.commons.api.edm.provider.CsdlEntitySet;
|
||||
import org.apache.olingo.commons.api.edm.provider.CsdlEntityType;
|
||||
import org.apache.olingo.commons.api.edm.provider.CsdlFunction;
|
||||
import org.apache.olingo.commons.api.edm.provider.CsdlFunctionImport;
|
||||
import org.apache.olingo.commons.api.edm.provider.CsdlNavigationProperty;
|
||||
import org.apache.olingo.commons.api.edm.provider.CsdlNavigationPropertyBinding;
|
||||
import org.apache.olingo.commons.api.edm.provider.CsdlParameter;
|
||||
import org.apache.olingo.commons.api.edm.provider.CsdlProperty;
|
||||
import org.apache.olingo.commons.api.edm.provider.CsdlPropertyRef;
|
||||
import org.apache.olingo.commons.api.edm.provider.CsdlReturnType;
|
||||
import org.apache.olingo.commons.api.edm.provider.CsdlSchema;
|
||||
|
||||
public class DemoEdmProvider extends CsdlAbstractEdmProvider {
|
||||
|
@ -57,6 +63,101 @@ public class DemoEdmProvider extends CsdlAbstractEdmProvider {
|
|||
public static final String NAV_TO_CATEGORY = "Category";
|
||||
public static final String NAV_TO_PRODUCTS = "Products";
|
||||
|
||||
//Action
|
||||
public static final String ACTION_RESET = "Reset";
|
||||
public static final FullQualifiedName ACTION_RESET_FQN = new FullQualifiedName(NAMESPACE, ACTION_RESET);
|
||||
|
||||
// Function
|
||||
public static final String FUNCTION_COUNT_CATEGORIES = "CountCategories";
|
||||
public static final FullQualifiedName FUNCTION_COUNT_CATEGORIES_FQN
|
||||
= new FullQualifiedName(NAMESPACE, FUNCTION_COUNT_CATEGORIES);
|
||||
|
||||
// Function/Action Parameters
|
||||
public static final String PARAMETER_AMOUNT = "Amount";
|
||||
|
||||
@Override
|
||||
public List<CsdlAction> getActions(final FullQualifiedName actionName) {
|
||||
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>();
|
||||
final CsdlParameter 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_RESET_FQN.getName());
|
||||
action.setParameters(parameters);
|
||||
actions.add(action);
|
||||
|
||||
return actions;
|
||||
}
|
||||
|
||||
return null;
|
||||
}
|
||||
|
||||
@Override
|
||||
public CsdlActionImport getActionImport(final FullQualifiedName entityContainer, final String actionImportName) {
|
||||
if(entityContainer.equals(CONTAINER)) {
|
||||
if(actionImportName.equals(ACTION_RESET_FQN.getName())) {
|
||||
return new CsdlActionImport()
|
||||
.setName(actionImportName)
|
||||
.setAction(ACTION_RESET_FQN);
|
||||
}
|
||||
}
|
||||
|
||||
return null;
|
||||
}
|
||||
|
||||
@Override
|
||||
public List<CsdlFunction> getFunctions(final FullQualifiedName functionName) {
|
||||
if (functionName.equals(FUNCTION_COUNT_CATEGORIES_FQN)) {
|
||||
// It is allowed to overload functions, so we have to provide a list of functions for each function name
|
||||
final List<CsdlFunction> functions = new ArrayList<CsdlFunction>();
|
||||
|
||||
// Create the parameter for the function
|
||||
final CsdlParameter parameterAmount = new CsdlParameter();
|
||||
parameterAmount.setName(PARAMETER_AMOUNT);
|
||||
parameterAmount.setNullable(false);
|
||||
parameterAmount.setType(EdmPrimitiveTypeKind.Int32.getFullQualifiedName());
|
||||
|
||||
// Create the return type of the function
|
||||
final CsdlReturnType returnType = new CsdlReturnType();
|
||||
returnType.setCollection(true);
|
||||
returnType.setType(ET_CATEGORY_FQN);
|
||||
|
||||
// Create the function
|
||||
final CsdlFunction function = new CsdlFunction();
|
||||
function.setName(FUNCTION_COUNT_CATEGORIES_FQN.getName())
|
||||
.setParameters(Arrays.asList(parameterAmount))
|
||||
.setReturnType(returnType);
|
||||
functions.add(function);
|
||||
|
||||
return functions;
|
||||
}
|
||||
|
||||
return null;
|
||||
}
|
||||
|
||||
@Override
|
||||
public CsdlFunctionImport getFunctionImport(FullQualifiedName entityContainer, String functionImportName) {
|
||||
if(entityContainer.equals(CONTAINER)) {
|
||||
if(functionImportName.equals(FUNCTION_COUNT_CATEGORIES_FQN.getName())) {
|
||||
return new CsdlFunctionImport()
|
||||
.setName(functionImportName)
|
||||
.setFunction(FUNCTION_COUNT_CATEGORIES_FQN)
|
||||
.setEntitySet(ES_CATEGORIES_NAME)
|
||||
.setIncludeInServiceDocument(true);
|
||||
}
|
||||
}
|
||||
|
||||
return null;
|
||||
}
|
||||
|
||||
@Override
|
||||
public CsdlEntityType getEntityType(FullQualifiedName entityTypeName) {
|
||||
|
||||
|
@ -78,7 +179,7 @@ public class DemoEdmProvider extends CsdlAbstractEdmProvider {
|
|||
|
||||
// navigation property: many-to-one, null not allowed (product must have a category)
|
||||
CsdlNavigationProperty navProp = new CsdlNavigationProperty().setName(NAV_TO_CATEGORY)
|
||||
.setType(ET_CATEGORY_FQN).setNullable(false).setPartner("Products");
|
||||
.setType(ET_CATEGORY_FQN).setNullable(true).setPartner("Products");
|
||||
List<CsdlNavigationProperty> navPropList = new ArrayList<CsdlNavigationProperty>();
|
||||
navPropList.add(navProp);
|
||||
|
||||
|
@ -183,7 +284,17 @@ public class DemoEdmProvider extends CsdlAbstractEdmProvider {
|
|||
entityTypes.add(getEntityType(ET_PRODUCT_FQN));
|
||||
entityTypes.add(getEntityType(ET_CATEGORY_FQN));
|
||||
schema.setEntityTypes(entityTypes);
|
||||
|
||||
|
||||
// add actions
|
||||
List<CsdlAction> actions = new ArrayList<CsdlAction>();
|
||||
actions.addAll(getActions(ACTION_RESET_FQN));
|
||||
schema.setActions(actions);
|
||||
|
||||
// add functions
|
||||
List<CsdlFunction> functions = new ArrayList<CsdlFunction>();
|
||||
functions.addAll(getFunctions(FUNCTION_COUNT_CATEGORIES_FQN));
|
||||
schema.setFunctions(functions);
|
||||
|
||||
// add EntityContainer
|
||||
schema.setEntityContainer(getEntityContainer());
|
||||
|
||||
|
@ -201,10 +312,20 @@ public class DemoEdmProvider extends CsdlAbstractEdmProvider {
|
|||
List<CsdlEntitySet> entitySets = new ArrayList<CsdlEntitySet>();
|
||||
entitySets.add(getEntitySet(CONTAINER, ES_PRODUCTS_NAME));
|
||||
entitySets.add(getEntitySet(CONTAINER, ES_CATEGORIES_NAME));
|
||||
|
||||
|
||||
// Create function imports
|
||||
List<CsdlFunctionImport> functionImports = new ArrayList<CsdlFunctionImport>();
|
||||
functionImports.add(getFunctionImport(CONTAINER, FUNCTION_COUNT_CATEGORIES));
|
||||
|
||||
// Create action imports
|
||||
List<CsdlActionImport> actionImports = new ArrayList<CsdlActionImport>();
|
||||
actionImports.add(getActionImport(CONTAINER, ACTION_RESET));
|
||||
|
||||
// create EntityContainer
|
||||
CsdlEntityContainer entityContainer = new CsdlEntityContainer();
|
||||
entityContainer.setName(CONTAINER_NAME);
|
||||
entityContainer.setActionImports(actionImports);
|
||||
entityContainer.setFunctionImports(functionImports);
|
||||
entityContainer.setEntitySets(entitySets);
|
||||
|
||||
return entityContainer;
|
||||
|
|
|
@ -19,6 +19,7 @@
|
|||
package myservice.mynamespace.service;
|
||||
|
||||
import java.io.InputStream;
|
||||
import java.net.URI;
|
||||
import java.util.ArrayList;
|
||||
import java.util.Collections;
|
||||
import java.util.Comparator;
|
||||
|
@ -56,6 +57,7 @@ import org.apache.olingo.server.api.uri.UriInfo;
|
|||
import org.apache.olingo.server.api.uri.UriInfoResource;
|
||||
import org.apache.olingo.server.api.uri.UriResource;
|
||||
import org.apache.olingo.server.api.uri.UriResourceEntitySet;
|
||||
import org.apache.olingo.server.api.uri.UriResourceFunction;
|
||||
import org.apache.olingo.server.api.uri.UriResourceNavigation;
|
||||
import org.apache.olingo.server.api.uri.UriResourcePrimitiveProperty;
|
||||
import org.apache.olingo.server.api.uri.queryoption.CountOption;
|
||||
|
@ -86,10 +88,54 @@ public class DemoEntityCollectionProcessor implements EntityCollectionProcessor
|
|||
this.serviceMetadata = serviceMetadata;
|
||||
}
|
||||
|
||||
public void readEntityCollection(ODataRequest request, ODataResponse response, UriInfo uriInfo,
|
||||
ContentType responseFormat) throws ODataApplicationException, SerializerException {
|
||||
public void readEntityCollection(ODataRequest request, ODataResponse response,
|
||||
UriInfo uriInfo, ContentType responseFormat)
|
||||
throws ODataApplicationException, SerializerException {
|
||||
|
||||
final UriResource firstResourceSegment = uriInfo.getUriResourceParts().get(0);
|
||||
|
||||
if(firstResourceSegment instanceof UriResourceEntitySet) {
|
||||
readEntityCollectionInternal(request, response, uriInfo, responseFormat);
|
||||
} else if(firstResourceSegment instanceof UriResourceFunction) {
|
||||
readFunctionImportCollection(request, response, uriInfo, responseFormat);
|
||||
} else {
|
||||
throw new ODataApplicationException("Not implemented", HttpStatusCode.NOT_IMPLEMENTED.getStatusCode(),
|
||||
Locale.ENGLISH);
|
||||
}
|
||||
}
|
||||
|
||||
private void readFunctionImportCollection(final ODataRequest request, final ODataResponse response,
|
||||
final UriInfo uriInfo, final ContentType responseFormat) throws ODataApplicationException, SerializerException {
|
||||
|
||||
// 1st step: Analyze the URI and fetch the entity collection returned by the function import
|
||||
// Function Imports are always the first segment of the resource path
|
||||
final UriResource firstSegment = uriInfo.getUriResourceParts().get(0);
|
||||
|
||||
if(!(firstSegment instanceof UriResourceFunction)) {
|
||||
throw new ODataApplicationException("Not implemented", HttpStatusCode.NOT_IMPLEMENTED.getStatusCode(),
|
||||
Locale.ENGLISH);
|
||||
}
|
||||
|
||||
final UriResourceFunction uriResourceFunction = (UriResourceFunction) firstSegment;
|
||||
final EntityCollection entityCol = storage.readFunctionImportCollection(uriResourceFunction, serviceMetadata);
|
||||
|
||||
// 2nd step: Serialize the response entity
|
||||
final EdmEntityType edmEntityType = (EdmEntityType) uriResourceFunction.getFunction().getReturnType().getType();
|
||||
final ContextURL contextURL = ContextURL.with().asCollection().type(edmEntityType).build();
|
||||
EntityCollectionSerializerOptions opts = EntityCollectionSerializerOptions.with().contextURL(contextURL).build();
|
||||
final ODataSerializer serializer = odata.createSerializer(responseFormat);
|
||||
final SerializerResult serializerResult = serializer.entityCollection(serviceMetadata, edmEntityType, entityCol,
|
||||
opts);
|
||||
|
||||
// 1st: retrieve the requested EntitySet from the uriInfo (representation of the parsed URI)
|
||||
// 3rd configure the response object
|
||||
response.setContent(serializerResult.getContent());
|
||||
response.setStatusCode(HttpStatusCode.OK.getStatusCode());
|
||||
response.setHeader(HttpHeader.CONTENT_TYPE, responseFormat.toContentTypeString());
|
||||
}
|
||||
|
||||
private void readEntityCollectionInternal(ODataRequest request, ODataResponse response, UriInfo uriInfo,
|
||||
ContentType responseFormat) throws ODataApplicationException, SerializerException {
|
||||
// 1st: retrieve the requested EntitySet from the uriInfo (representation of the parsed URI)
|
||||
List<UriResource> resourcePaths = uriInfo.getUriResourceParts();
|
||||
// in our example, the first segment is the EntitySet
|
||||
UriResourceEntitySet uriResourceEntitySet = (UriResourceEntitySet) resourcePaths.get(0);
|
||||
|
@ -100,10 +146,10 @@ public class DemoEntityCollectionProcessor implements EntityCollectionProcessor
|
|||
EntityCollection modifiedEntityCollection = new EntityCollection();
|
||||
List<Entity> modifiedEntityList = new ArrayList<Entity>();
|
||||
modifiedEntityList.addAll(entityCollection.getEntities());
|
||||
|
||||
// 3rd: Apply system query option
|
||||
// The system query options have to be applied in a defined order
|
||||
// 3.1.) $filter
|
||||
|
||||
// 3rd: Apply system query option
|
||||
// The system query options have to be applied in a defined order
|
||||
// 3.1.) $filter
|
||||
modifiedEntityList = applyFilterQueryOption(modifiedEntityList, uriInfo.getFilterOption());
|
||||
// 3.2.) $orderby
|
||||
modifiedEntityList = applyOrderQueryOption(modifiedEntityList, uriInfo.getOrderByOption());
|
||||
|
@ -124,9 +170,9 @@ public class DemoEntityCollectionProcessor implements EntityCollectionProcessor
|
|||
|
||||
// 4th: create a serializer based on the requested format (json)
|
||||
ODataSerializer serializer = odata.createSerializer(responseFormat);
|
||||
|
||||
// we need the property names of the $select, in order to build the context URL
|
||||
EdmEntityType edmEntityType = edmEntitySet.getEntityType();
|
||||
|
||||
// we need the property names of the $select, in order to build the context URL
|
||||
EdmEntityType edmEntityType = edmEntitySet.getEntityType();
|
||||
String selectList = odata.createUriHelper()
|
||||
.buildContextURLSelectList(edmEntityType, uriInfo.getExpandOption(), selectOption);
|
||||
ContextURL contextUrl = ContextURL.with().entitySet(edmEntitySet).selectList(selectList).build();
|
||||
|
@ -150,8 +196,8 @@ public class DemoEntityCollectionProcessor implements EntityCollectionProcessor
|
|||
response.setContent(serializedContent);
|
||||
response.setStatusCode(HttpStatusCode.OK.getStatusCode());
|
||||
response.setHeader(HttpHeader.CONTENT_TYPE, responseFormat.toContentTypeString());
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
private List<Entity> applyExpandQueryOption(List<Entity> modifiedEntityList,
|
||||
EdmEntitySet edmEntitySet, ExpandOption expandOption) {
|
||||
|
||||
|
@ -200,13 +246,14 @@ public class DemoEntityCollectionProcessor implements EntityCollectionProcessor
|
|||
// fetch the data for the $expand (to-many navigation) from backend
|
||||
EntityCollection expandEntityCollection = storage.getRelatedEntityCollection(entity, expandEdmEntityType);
|
||||
link.setInlineEntitySet(expandEntityCollection);
|
||||
link.setHref(expandEntityCollection.getId().toASCIIString());
|
||||
final URI entityId = expandEntityCollection.getId();
|
||||
link.setHref(entityId != null ? entityId.toASCIIString() : null);
|
||||
} else { // in case of Products?$expand=Category
|
||||
// fetch the data for the $expand (to-one navigation) from backend
|
||||
// here we get the data for the expand
|
||||
Entity expandEntity = storage.getRelatedEntity(entity, expandEdmEntityType);
|
||||
link.setInlineEntity(expandEntity);
|
||||
link.setHref(expandEntity.getId().toASCIIString());
|
||||
link.setHref(expandEntity != null ? expandEntity.getId().toASCIIString() : null);
|
||||
}
|
||||
|
||||
// set the link - containing the expanded data - to the current entity
|
||||
|
|
|
@ -54,6 +54,7 @@ import org.apache.olingo.server.api.uri.UriInfo;
|
|||
import org.apache.olingo.server.api.uri.UriParameter;
|
||||
import org.apache.olingo.server.api.uri.UriResource;
|
||||
import org.apache.olingo.server.api.uri.UriResourceEntitySet;
|
||||
import org.apache.olingo.server.api.uri.UriResourceFunction;
|
||||
import org.apache.olingo.server.api.uri.UriResourceNavigation;
|
||||
import org.apache.olingo.server.api.uri.queryoption.ExpandItem;
|
||||
import org.apache.olingo.server.api.uri.queryoption.ExpandOption;
|
||||
|
@ -77,10 +78,61 @@ public class DemoEntityProcessor implements EntityProcessor {
|
|||
this.serviceMetadata = serviceMetadata;
|
||||
}
|
||||
|
||||
public void readEntity(ODataRequest request, ODataResponse response, UriInfo uriInfo, ContentType responseFormat)
|
||||
throws ODataApplicationException, SerializerException {
|
||||
public void readEntity(ODataRequest request, ODataResponse response, UriInfo uriInfo, ContentType responseFormat)
|
||||
throws ODataApplicationException, SerializerException {
|
||||
|
||||
EdmEntityType responseEdmEntityType = null; // we'll need this to build the ContextURL
|
||||
// The sample service supports only functions imports and entity sets.
|
||||
// We do not care about bound functions and composable functions.
|
||||
|
||||
UriResource uriResource = uriInfo.getUriResourceParts().get(0);
|
||||
|
||||
if (uriResource instanceof UriResourceEntitySet) {
|
||||
readEntityInternal(request, response, uriInfo, responseFormat);
|
||||
} else if (uriResource instanceof UriResourceFunction) {
|
||||
readFunctionImportInternal(request, response, uriInfo, responseFormat);
|
||||
} else {
|
||||
throw new ODataApplicationException("Only EntitySet is supported",
|
||||
HttpStatusCode.NOT_IMPLEMENTED.getStatusCode(), Locale.ENGLISH);
|
||||
}
|
||||
}
|
||||
|
||||
private void readFunctionImportInternal(final ODataRequest request, final ODataResponse response,
|
||||
final UriInfo uriInfo, final ContentType responseFormat) throws ODataApplicationException, SerializerException {
|
||||
|
||||
// 1st step: Analyze the URI and fetch the entity returned by the function import
|
||||
// Function Imports are always the first segment of the resource path
|
||||
final UriResource firstSegment = uriInfo.getUriResourceParts().get(0);
|
||||
|
||||
if (!(firstSegment instanceof UriResourceFunction)) {
|
||||
throw new ODataApplicationException("Not implemented", HttpStatusCode.NOT_IMPLEMENTED.getStatusCode(),
|
||||
Locale.ENGLISH);
|
||||
}
|
||||
|
||||
final UriResourceFunction uriResourceFunction = (UriResourceFunction) firstSegment;
|
||||
final Entity entity = storage.readFunctionImportEntity(uriResourceFunction, serviceMetadata);
|
||||
|
||||
if (entity == null) {
|
||||
throw new ODataApplicationException("Nothing found.", HttpStatusCode.NOT_FOUND.getStatusCode(), Locale.ROOT);
|
||||
}
|
||||
|
||||
// 2nd step: Serialize the response entity
|
||||
final EdmEntityType edmEntityType = (EdmEntityType) uriResourceFunction.getFunction().getReturnType().getType();
|
||||
final ContextURL contextURL = ContextURL.with().type(edmEntityType).build();
|
||||
final EntitySerializerOptions opts = EntitySerializerOptions.with().contextURL(contextURL).build();
|
||||
final ODataSerializer serializer = odata.createSerializer(responseFormat);
|
||||
final SerializerResult serializerResult = serializer.entity(serviceMetadata, edmEntityType, entity, opts);
|
||||
|
||||
// 3rd configure the response object
|
||||
response.setContent(serializerResult.getContent());
|
||||
response.setStatusCode(HttpStatusCode.OK.getStatusCode());
|
||||
response.setHeader(HttpHeader.CONTENT_TYPE, responseFormat.toContentTypeString());
|
||||
}
|
||||
|
||||
private void readEntityInternal(ODataRequest request, ODataResponse response, UriInfo uriInfo,
|
||||
ContentType responseFormat)
|
||||
throws ODataApplicationException, SerializerException {
|
||||
|
||||
EdmEntityType responseEdmEntityType = null; // we'll need this to build the ContextURL
|
||||
Entity responseEntity = null; // required for serialization of the response body
|
||||
EdmEntitySet responseEdmEntitySet = null; // we need this for building the contextUrl
|
||||
|
||||
|
@ -141,123 +193,122 @@ public class DemoEntityProcessor implements EntityProcessor {
|
|||
throw new ODataApplicationException("Nothing found.", HttpStatusCode.NOT_FOUND.getStatusCode(), Locale.ROOT);
|
||||
}
|
||||
|
||||
// 3. apply system query options
|
||||
// 3. apply system query options
|
||||
|
||||
// handle $select
|
||||
SelectOption selectOption = uriInfo.getSelectOption();
|
||||
// in our example, we don't have performance issues, so we can rely upon the handling in the Olingo lib
|
||||
// nothing else to be done
|
||||
// handle $select
|
||||
SelectOption selectOption = uriInfo.getSelectOption();
|
||||
// in our example, we don't have performance issues, so we can rely upon the handling in the Olingo lib
|
||||
// nothing else to be done
|
||||
|
||||
// handle $expand
|
||||
ExpandOption expandOption = uriInfo.getExpandOption();
|
||||
// in our example: http://localhost:8080/DemoService/DemoService.svc/Categories(1)/$expand=Products
|
||||
// or http://localhost:8080/DemoService/DemoService.svc/Products(1)?$expand=Category
|
||||
if(expandOption != null) {
|
||||
// retrieve the EdmNavigationProperty from the expand expression
|
||||
// Note: in our example, we have only one NavigationProperty, so we can directly access it
|
||||
EdmNavigationProperty edmNavigationProperty = null;
|
||||
ExpandItem expandItem = expandOption.getExpandItems().get(0);
|
||||
if(expandItem.isStar()) {
|
||||
List<EdmNavigationPropertyBinding> bindings = responseEdmEntitySet.getNavigationPropertyBindings();
|
||||
// we know that there are navigation bindings
|
||||
// however normally in this case a check if navigation bindings exists is done
|
||||
if(!bindings.isEmpty()) {
|
||||
// can in our case only be 'Category' or 'Products', so we can take the first
|
||||
EdmNavigationPropertyBinding binding = bindings.get(0);
|
||||
EdmElement property = responseEdmEntitySet.getEntityType().getProperty(binding.getPath());
|
||||
// we don't need to handle error cases, as it is done in the Olingo library
|
||||
if(property instanceof EdmNavigationProperty) {
|
||||
edmNavigationProperty = (EdmNavigationProperty) property;
|
||||
}
|
||||
}
|
||||
} else {
|
||||
// can be 'Category' or 'Products', no path supported
|
||||
UriResource expandUriResource = expandItem.getResourcePath().getUriResourceParts().get(0);
|
||||
// we don't need to handle error cases, as it is done in the Olingo library
|
||||
if(expandUriResource instanceof UriResourceNavigation) {
|
||||
edmNavigationProperty = ((UriResourceNavigation) expandUriResource).getProperty();
|
||||
}
|
||||
}
|
||||
// handle $expand
|
||||
ExpandOption expandOption = uriInfo.getExpandOption();
|
||||
// in our example: http://localhost:8080/DemoService/DemoService.svc/Categories(1)/$expand=Products
|
||||
// or http://localhost:8080/DemoService/DemoService.svc/Products(1)?$expand=Category
|
||||
if (expandOption != null) {
|
||||
// retrieve the EdmNavigationProperty from the expand expression
|
||||
// Note: in our example, we have only one NavigationProperty, so we can directly access it
|
||||
EdmNavigationProperty edmNavigationProperty = null;
|
||||
ExpandItem expandItem = expandOption.getExpandItems().get(0);
|
||||
if (expandItem.isStar()) {
|
||||
List<EdmNavigationPropertyBinding> bindings = responseEdmEntitySet.getNavigationPropertyBindings();
|
||||
// we know that there are navigation bindings
|
||||
// however normally in this case a check if navigation bindings exists is done
|
||||
if (!bindings.isEmpty()) {
|
||||
// can in our case only be 'Category' or 'Products', so we can take the first
|
||||
EdmNavigationPropertyBinding binding = bindings.get(0);
|
||||
EdmElement property = responseEdmEntitySet.getEntityType().getProperty(binding.getPath());
|
||||
// we don't need to handle error cases, as it is done in the Olingo library
|
||||
if (property instanceof EdmNavigationProperty) {
|
||||
edmNavigationProperty = (EdmNavigationProperty) property;
|
||||
}
|
||||
}
|
||||
} else {
|
||||
// can be 'Category' or 'Products', no path supported
|
||||
UriResource expandUriResource = expandItem.getResourcePath().getUriResourceParts().get(0);
|
||||
// we don't need to handle error cases, as it is done in the Olingo library
|
||||
if (expandUriResource instanceof UriResourceNavigation) {
|
||||
edmNavigationProperty = ((UriResourceNavigation) expandUriResource).getProperty();
|
||||
}
|
||||
}
|
||||
|
||||
// can be 'Category' or 'Products', no path supported
|
||||
// we don't need to handle error cases, as it is done in the Olingo library
|
||||
if(edmNavigationProperty != null) {
|
||||
EdmEntityType expandEdmEntityType = edmNavigationProperty.getType();
|
||||
String navPropName = edmNavigationProperty.getName();
|
||||
// can be 'Category' or 'Products', no path supported
|
||||
// we don't need to handle error cases, as it is done in the Olingo library
|
||||
if (edmNavigationProperty != null) {
|
||||
EdmEntityType expandEdmEntityType = edmNavigationProperty.getType();
|
||||
String navPropName = edmNavigationProperty.getName();
|
||||
|
||||
// build the inline data
|
||||
Link link = new Link();
|
||||
link.setTitle(navPropName);
|
||||
link.setType(Constants.ENTITY_NAVIGATION_LINK_TYPE);
|
||||
// build the inline data
|
||||
Link link = new Link();
|
||||
link.setTitle(navPropName);
|
||||
link.setType(Constants.ENTITY_NAVIGATION_LINK_TYPE);
|
||||
link.setRel(Constants.NS_ASSOCIATION_LINK_REL + navPropName);
|
||||
|
||||
if(edmNavigationProperty.isCollection()) { // in case of Categories(1)/$expand=Products
|
||||
// fetch the data for the $expand (to-many navigation) from backend
|
||||
// here we get the data for the expand
|
||||
EntityCollection expandEntityCollection =
|
||||
if (edmNavigationProperty.isCollection()) { // in case of Categories(1)/$expand=Products
|
||||
// fetch the data for the $expand (to-many navigation) from backend
|
||||
// here we get the data for the expand
|
||||
EntityCollection expandEntityCollection =
|
||||
storage.getRelatedEntityCollection(responseEntity, expandEdmEntityType);
|
||||
link.setInlineEntitySet(expandEntityCollection);
|
||||
link.setInlineEntitySet(expandEntityCollection);
|
||||
link.setHref(expandEntityCollection.getId().toASCIIString());
|
||||
} else { // in case of Products(1)?$expand=Category
|
||||
// fetch the data for the $expand (to-one navigation) from backend
|
||||
// here we get the data for the expand
|
||||
Entity expandEntity = storage.getRelatedEntity(responseEntity, expandEdmEntityType);
|
||||
link.setInlineEntity(expandEntity);
|
||||
} else { // in case of Products(1)?$expand=Category
|
||||
// fetch the data for the $expand (to-one navigation) from backend
|
||||
// here we get the data for the expand
|
||||
Entity expandEntity = storage.getRelatedEntity(responseEntity, expandEdmEntityType);
|
||||
link.setInlineEntity(expandEntity);
|
||||
link.setHref(expandEntity.getId().toASCIIString());
|
||||
}
|
||||
}
|
||||
|
||||
// set the link - containing the expanded data - to the current entity
|
||||
responseEntity.getNavigationLinks().add(link);
|
||||
}
|
||||
}
|
||||
// set the link - containing the expanded data - to the current entity
|
||||
responseEntity.getNavigationLinks().add(link);
|
||||
}
|
||||
}
|
||||
|
||||
// 4. serialize
|
||||
EdmEntityType edmEntityType = responseEdmEntitySet.getEntityType();
|
||||
// we need the property names of the $select, in order to build the context URL
|
||||
String selectList = odata.createUriHelper().buildContextURLSelectList(edmEntityType, expandOption, selectOption);
|
||||
ContextURL contextUrl = ContextURL.with().entitySet(responseEdmEntitySet)
|
||||
.selectList(selectList)
|
||||
.suffix(Suffix.ENTITY).build();
|
||||
|
||||
// 4. serialize
|
||||
EdmEntityType edmEntityType = responseEdmEntitySet.getEntityType();
|
||||
// we need the property names of the $select, in order to build the context URL
|
||||
String selectList = odata.createUriHelper().buildContextURLSelectList(edmEntityType, expandOption, selectOption);
|
||||
ContextURL contextUrl = ContextURL.with().entitySet(responseEdmEntitySet)
|
||||
.selectList(selectList)
|
||||
.suffix(Suffix.ENTITY).build();
|
||||
// make sure that $expand and $select are considered by the serializer
|
||||
// adding the selectOption to the serializerOpts will actually tell the lib to do the job
|
||||
EntitySerializerOptions opts = EntitySerializerOptions.with()
|
||||
.contextURL(contextUrl)
|
||||
.select(selectOption)
|
||||
.expand(expandOption)
|
||||
.build();
|
||||
|
||||
// make sure that $expand and $select are considered by the serializer
|
||||
// adding the selectOption to the serializerOpts will actually tell the lib to do the job
|
||||
EntitySerializerOptions opts = EntitySerializerOptions.with()
|
||||
.contextURL(contextUrl)
|
||||
.select(selectOption)
|
||||
.expand(expandOption)
|
||||
.build();
|
||||
ODataSerializer serializer = this.odata.createSerializer(responseFormat);
|
||||
SerializerResult serializerResult = serializer.entity(serviceMetadata, edmEntityType, responseEntity, opts);
|
||||
|
||||
ODataSerializer serializer = this.odata.createSerializer(responseFormat);
|
||||
SerializerResult serializerResult = serializer.entity(serviceMetadata, edmEntityType, responseEntity, opts);
|
||||
// 5. configure the response object
|
||||
response.setContent(serializerResult.getContent());
|
||||
response.setStatusCode(HttpStatusCode.OK.getStatusCode());
|
||||
response.setHeader(HttpHeader.CONTENT_TYPE, responseFormat.toContentTypeString());
|
||||
}
|
||||
|
||||
// 5. configure the response object
|
||||
response.setContent(serializerResult.getContent());
|
||||
response.setStatusCode(HttpStatusCode.OK.getStatusCode());
|
||||
response.setHeader(HttpHeader.CONTENT_TYPE, responseFormat.toContentTypeString());
|
||||
}
|
||||
|
||||
/*
|
||||
/*
|
||||
* Example request:
|
||||
*
|
||||
* POST URL: http://localhost:8080/DemoService/DemoService.svc/Products
|
||||
* Header: Content-Type: application/json; odata.metadata=minimal
|
||||
* Request body:
|
||||
{
|
||||
"ID":3,
|
||||
"Name":"Ergo Screen",
|
||||
"Description":"17 Optimum Resolution 1024 x 768 @ 85Hz, resolution 1280 x 960"
|
||||
}
|
||||
* */
|
||||
* {
|
||||
* "ID":3,
|
||||
* "Name":"Ergo Screen",
|
||||
* "Description":"17 Optimum Resolution 1024 x 768 @ 85Hz, resolution 1280 x 960"
|
||||
* }
|
||||
*/
|
||||
public void createEntity(ODataRequest request, ODataResponse response, UriInfo uriInfo,
|
||||
ContentType requestFormat, ContentType responseFormat)
|
||||
throws ODataApplicationException, DeserializerException, SerializerException {
|
||||
|
||||
// 1. Retrieve the entity type from the URI
|
||||
ContentType requestFormat, ContentType responseFormat)
|
||||
throws ODataApplicationException, DeserializerException, SerializerException {
|
||||
|
||||
// 1. Retrieve the entity type from the URI
|
||||
EdmEntitySet edmEntitySet = Util.getEdmEntitySet(uriInfo);
|
||||
EdmEntityType edmEntityType = edmEntitySet.getEntityType();
|
||||
|
||||
// 2. create the data in backend
|
||||
// 2. create the data in backend
|
||||
// 2.1. retrieve the payload from the POST request for the entity to create and deserialize it
|
||||
InputStream requestInputStream = request.getBody();
|
||||
ODataDeserializer deserializer = this.odata.createDeserializer(requestFormat);
|
||||
|
@ -265,34 +316,35 @@ public class DemoEntityProcessor implements EntityProcessor {
|
|||
Entity requestEntity = result.getEntity();
|
||||
// 2.2 do the creation in backend, which returns the newly created entity
|
||||
Entity createdEntity = storage.createEntityData(edmEntitySet, requestEntity);
|
||||
|
||||
|
||||
// 3. serialize the response (we have to return the created entity)
|
||||
ContextURL contextUrl = ContextURL.with().entitySet(edmEntitySet).build();
|
||||
EntitySerializerOptions options = EntitySerializerOptions.with().contextURL(contextUrl).build(); // expand and select currently not supported
|
||||
|
||||
ContextURL contextUrl = ContextURL.with().entitySet(edmEntitySet).build();
|
||||
EntitySerializerOptions options = EntitySerializerOptions.with().contextURL(contextUrl).build(); // expand and
|
||||
// select currently
|
||||
// not supported
|
||||
|
||||
ODataSerializer serializer = this.odata.createSerializer(responseFormat);
|
||||
SerializerResult serializedResponse = serializer.entity(serviceMetadata, edmEntityType, createdEntity, options);
|
||||
|
||||
//4. configure the response object
|
||||
|
||||
// 4. configure the response object
|
||||
response.setContent(serializedResponse.getContent());
|
||||
response.setStatusCode(HttpStatusCode.CREATED.getStatusCode());
|
||||
response.setHeader(HttpHeader.CONTENT_TYPE, responseFormat.toContentTypeString());
|
||||
}
|
||||
|
||||
|
||||
public void updateEntity(ODataRequest request, ODataResponse response, UriInfo uriInfo,
|
||||
ContentType requestFormat, ContentType responseFormat)
|
||||
throws ODataApplicationException, DeserializerException, SerializerException {
|
||||
|
||||
// 1. Retrieve the entity set which belongs to the requested entity
|
||||
ContentType requestFormat, ContentType responseFormat)
|
||||
throws ODataApplicationException, DeserializerException, SerializerException {
|
||||
|
||||
// 1. Retrieve the entity set which belongs to the requested entity
|
||||
List<UriResource> resourcePaths = uriInfo.getUriResourceParts();
|
||||
// Note: only in our example we can assume that the first segment is the EntitySet
|
||||
UriResourceEntitySet uriResourceEntitySet = (UriResourceEntitySet) resourcePaths.get(0);
|
||||
UriResourceEntitySet uriResourceEntitySet = (UriResourceEntitySet) resourcePaths.get(0);
|
||||
EdmEntitySet edmEntitySet = uriResourceEntitySet.getEntitySet();
|
||||
EdmEntityType edmEntityType = edmEntitySet.getEntityType();
|
||||
|
||||
// 2. update the data in backend
|
||||
// 2.1. retrieve the payload from the PUT request for the entity to be updated
|
||||
// 2.1. retrieve the payload from the PUT request for the entity to be updated
|
||||
InputStream requestInputStream = request.getBody();
|
||||
ODataDeserializer deserializer = this.odata.createDeserializer(requestFormat);
|
||||
DeserializerResult result = deserializer.entity(requestInputStream, edmEntityType);
|
||||
|
@ -302,26 +354,25 @@ public class DemoEntityProcessor implements EntityProcessor {
|
|||
// Note that this updateEntity()-method is invoked for both PUT or PATCH operations
|
||||
HttpMethod httpMethod = request.getMethod();
|
||||
storage.updateEntityData(edmEntitySet, keyPredicates, requestEntity, httpMethod);
|
||||
|
||||
//3. configure the response object
|
||||
|
||||
// 3. configure the response object
|
||||
response.setStatusCode(HttpStatusCode.NO_CONTENT.getStatusCode());
|
||||
}
|
||||
|
||||
|
||||
public void deleteEntity(ODataRequest request, ODataResponse response, UriInfo uriInfo)
|
||||
throws ODataApplicationException {
|
||||
|
||||
// 1. Retrieve the entity set which belongs to the requested entity
|
||||
throws ODataApplicationException {
|
||||
|
||||
// 1. Retrieve the entity set which belongs to the requested entity
|
||||
List<UriResource> resourcePaths = uriInfo.getUriResourceParts();
|
||||
// Note: only in our example we can assume that the first segment is the EntitySet
|
||||
UriResourceEntitySet uriResourceEntitySet = (UriResourceEntitySet) resourcePaths.get(0);
|
||||
UriResourceEntitySet uriResourceEntitySet = (UriResourceEntitySet) resourcePaths.get(0);
|
||||
EdmEntitySet edmEntitySet = uriResourceEntitySet.getEntitySet();
|
||||
|
||||
// 2. delete the data in backend
|
||||
List<UriParameter> keyPredicates = uriResourceEntitySet.getKeyPredicates();
|
||||
storage.deleteEntityData(edmEntitySet, keyPredicates);
|
||||
|
||||
//3. configure the response object
|
||||
|
||||
// 3. configure the response object
|
||||
response.setStatusCode(HttpStatusCode.NO_CONTENT.getStatusCode());
|
||||
}
|
||||
}
|
||||
|
|
|
@ -28,6 +28,7 @@ import javax.servlet.http.HttpServletResponse;
|
|||
import javax.servlet.http.HttpSession;
|
||||
|
||||
import myservice.mynamespace.data.Storage;
|
||||
import myservice.mynamespace.service.DemoActionProcessor;
|
||||
import myservice.mynamespace.service.DemoEdmProvider;
|
||||
import myservice.mynamespace.service.DemoEntityCollectionProcessor;
|
||||
import myservice.mynamespace.service.DemoEntityProcessor;
|
||||
|
@ -63,6 +64,7 @@ public class DemoServlet extends HttpServlet {
|
|||
handler.register(new DemoEntityCollectionProcessor(storage));
|
||||
handler.register(new DemoEntityProcessor(storage));
|
||||
handler.register(new DemoPrimitiveProcessor(storage));
|
||||
handler.register(new DemoActionProcessor(storage));
|
||||
|
||||
// let the handler do the work
|
||||
handler.process(req, resp);
|
||||
|
|
|
@ -108,7 +108,7 @@ public class Storage {
|
|||
resetDataSet(Integer.MAX_VALUE);
|
||||
}
|
||||
|
||||
public void resetDataSet(final Integer amount) {
|
||||
public void resetDataSet(final int amount) {
|
||||
// Replace the old lists with empty ones
|
||||
productList = new ArrayList<Entity>();
|
||||
categoryList = new ArrayList<Entity>();
|
||||
|
|
|
@ -61,7 +61,7 @@ public class DemoActionProcessor implements ActionVoidProcessor {
|
|||
.get(0)).getAction();
|
||||
|
||||
// 2nd Deserialize the parameter
|
||||
// In our case there is only one action. So we can be sure that parameter has been provided by the client
|
||||
// In our case there is only one action. So we can be sure that parameter "Amount" has been provided by the client
|
||||
if (requestFormat == null) {
|
||||
throw new ODataApplicationException("The content type has not been set in the request.",
|
||||
HttpStatusCode.BAD_REQUEST.getStatusCode(), Locale.ROOT);
|
||||
|
|
Loading…
Reference in New Issue