[OLINGO-713] Added tutorial project for system query options

This commit is contained in:
Michael Bolz 2015-07-24 15:50:56 +02:00
parent fb65199d28
commit 010d94f7f7
11 changed files with 1021 additions and 0 deletions

View File

@ -0,0 +1,79 @@
<?xml version="1.0" encoding="UTF-8"?>
<!--
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.
-->
<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/maven-v4_0_0.xsd">
<modelVersion>4.0.0</modelVersion>
<groupId>my.group.id</groupId>
<artifactId>DemoService-QueryOptions</artifactId>
<packaging>war</packaging>
<version>0.0.1</version>
<name>${project.artifactId}-Webapp</name>
<build>
<finalName>DemoService</finalName>
</build>
<properties>
<javax.version>2.5</javax.version>
<odata.version>4.0.0-beta-03</odata.version>
<slf4j.version>1.7.7</slf4j.version>
</properties>
<dependencies>
<dependency>
<groupId>javax.servlet</groupId>
<artifactId>servlet-api</artifactId>
<version>${javax.version}</version>
<scope>provided</scope>
</dependency>
<dependency>
<groupId>org.apache.olingo</groupId>
<artifactId>odata-server-api</artifactId>
<version>${odata.version}</version>
</dependency>
<dependency>
<groupId>org.apache.olingo</groupId>
<artifactId>odata-server-core</artifactId>
<version>${odata.version}</version>
</dependency>
<dependency>
<groupId>org.apache.olingo</groupId>
<artifactId>odata-commons-api</artifactId>
<version>${odata.version}</version>
</dependency>
<dependency>
<groupId>org.apache.olingo</groupId>
<artifactId>odata-commons-core</artifactId>
<version>${odata.version}</version>
</dependency>
<dependency>
<groupId>org.slf4j</groupId>
<artifactId>slf4j-simple</artifactId>
<version>${slf4j.version}</version>
<scope>runtime</scope>
</dependency>
</dependencies>
</project>

View File

@ -0,0 +1,130 @@
/*
* 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 java.util.ArrayList;
import java.util.List;
import java.util.Locale;
import myservice.mynamespace.service.DemoEdmProvider;
import myservice.mynamespace.util.Util;
import org.apache.olingo.commons.api.data.Entity;
import org.apache.olingo.commons.api.data.EntityCollection;
import org.apache.olingo.commons.api.data.Property;
import org.apache.olingo.commons.api.data.ValueType;
import org.apache.olingo.commons.api.edm.EdmEntitySet;
import org.apache.olingo.commons.api.edm.EdmEntityType;
import org.apache.olingo.commons.api.http.HttpStatusCode;
import org.apache.olingo.server.api.ODataApplicationException;
import org.apache.olingo.server.api.uri.UriParameter;
public class Storage {
private List<Entity> productList;
public Storage() {
productList = new ArrayList<Entity>();
initSampleData();
}
/* PUBLIC FACADE */
public EntityCollection readEntitySetData(EdmEntitySet edmEntitySet)throws ODataApplicationException{
// actually, this is only required if we have more than one Entity Sets
if(edmEntitySet.getName().equals(DemoEdmProvider.ES_PRODUCTS_NAME)){
return getProducts();
}
return null;
}
public Entity readEntityData(EdmEntitySet edmEntitySet, List<UriParameter> keyParams)
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)){
return getProduct(edmEntityType, keyParams);
}
return null;
}
/* INTERNAL */
private EntityCollection getProducts(){
EntityCollection retEntitySet = new EntityCollection();
for(Entity productEntity : this.productList){
retEntitySet.getEntities().add(productEntity);
}
return retEntitySet;
}
private Entity getProduct(EdmEntityType edmEntityType, List<UriParameter> keyParams)
throws ODataApplicationException{
// the list of entities at runtime
EntityCollection entitySet = getProducts();
/* generic approach to find the requested entity */
Entity requestedEntity = Util.findEntity(edmEntityType, entitySet, keyParams);
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 requestedEntity;
}
/* HELPER */
private void initSampleData(){
// add some sample product entities
productList.add(new Entity()
.addProperty(new Property(null, "ID", ValueType.PRIMITIVE, 1))
.addProperty(new Property(null, "Name", ValueType.PRIMITIVE, "Notebook Basic 15"))
.addProperty(new Property(null, "Description", ValueType.PRIMITIVE,
"Notebook Basic, 1.7GHz - 15 XGA - 1024MB DDR2 SDRAM - 40GB")));
productList.add(new Entity()
.addProperty(new Property(null, "ID", ValueType.PRIMITIVE, 2))
.addProperty(new Property(null, "Name", ValueType.PRIMITIVE, "1UMTS PDA"))
.addProperty(new Property(null, "Description", ValueType.PRIMITIVE,
"Ultrafast 3G UMTS/HSDPA Pocket PC, supports GSM network")));
productList.add(new Entity()
.addProperty(new Property(null, "ID", ValueType.PRIMITIVE, 3))
.addProperty(new Property(null, "Name", ValueType.PRIMITIVE, "Ergo Screen"))
.addProperty(new Property(null, "Description", ValueType.PRIMITIVE,
"19 Optimum Resolution 1024 x 768 @ 85Hz, resolution 1280 x 960")));
}
}

View File

@ -0,0 +1,154 @@
/*
* 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.ArrayList;
import java.util.Arrays;
import java.util.Collections;
import java.util.List;
import org.apache.olingo.commons.api.ODataException;
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.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.CsdlProperty;
import org.apache.olingo.commons.api.edm.provider.CsdlPropertyRef;
import org.apache.olingo.commons.api.edm.provider.CsdlSchema;
public class DemoEdmProvider extends CsdlAbstractEdmProvider {
// Service Namespace
public static final String NAMESPACE = "OData.Demo";
// EDM Container
public static final String CONTAINER_NAME = "Container";
public static final FullQualifiedName CONTAINER = new FullQualifiedName(NAMESPACE, CONTAINER_NAME);
// Entity Types Names
public static final String ET_PRODUCT_NAME = "Product";
public static final FullQualifiedName ET_PRODUCT_FQN = new FullQualifiedName(NAMESPACE, ET_PRODUCT_NAME);
// Entity Set Names
public static final String ES_PRODUCTS_NAME = "Products";
@Override
public CsdlEntityType getEntityType(FullQualifiedName entityTypeName)
throws ODataException {
// this method is called for one of the EntityTypes that are configured in the Schema
if (ET_PRODUCT_FQN.equals(entityTypeName)) {
// create EntityType properties
CsdlProperty id = new CsdlProperty().setName("ID").setType(
EdmPrimitiveTypeKind.Int32.getFullQualifiedName());
CsdlProperty name = new CsdlProperty().setName("Name").setType(
EdmPrimitiveTypeKind.String.getFullQualifiedName());
CsdlProperty description = new CsdlProperty().setName("Description").setType(
EdmPrimitiveTypeKind.String.getFullQualifiedName());
// create PropertyRef for Key element
CsdlPropertyRef propertyRef = new CsdlPropertyRef();
propertyRef.setName("ID");
// configure EntityType
CsdlEntityType entityType = new CsdlEntityType();
entityType.setName(ET_PRODUCT_NAME);
entityType.setProperties(Arrays.asList(id, name, description));
entityType.setKey(Collections.singletonList(propertyRef));
return entityType;
}
return null;
}
@Override
public CsdlEntitySet getEntitySet(FullQualifiedName entityContainer,
String entitySetName) throws ODataException {
if (entityContainer.equals(CONTAINER)) {
if (entitySetName.equals(ES_PRODUCTS_NAME)) {
CsdlEntitySet entitySet = new CsdlEntitySet();
entitySet.setName(ES_PRODUCTS_NAME);
entitySet.setType(ET_PRODUCT_FQN);
return entitySet;
}
}
return null;
}
@Override
public CsdlEntityContainerInfo getEntityContainerInfo(
FullQualifiedName entityContainerName) throws ODataException {
// This method is invoked when displaying the service document at
// e.g. http://localhost:8080/DemoService/DemoService.svc
if (entityContainerName == null || entityContainerName.equals(CONTAINER)) {
CsdlEntityContainerInfo entityContainerInfo = new CsdlEntityContainerInfo();
entityContainerInfo.setContainerName(CONTAINER);
return entityContainerInfo;
}
return null;
}
@Override
public List<CsdlSchema> getSchemas() throws ODataException {
// create Schema
CsdlSchema schema = new CsdlSchema();
schema.setNamespace(NAMESPACE);
// add EntityTypes
List<CsdlEntityType> entityTypes = new ArrayList<CsdlEntityType>();
entityTypes.add(getEntityType(ET_PRODUCT_FQN));
schema.setEntityTypes(entityTypes);
// add EntityContainer
schema.setEntityContainer(getEntityContainer());
// finally
List<CsdlSchema> schemas = new ArrayList<CsdlSchema>();
schemas.add(schema);
return schemas;
}
@Override
public CsdlEntityContainer getEntityContainer() throws ODataException {
// create EntitySets
List<CsdlEntitySet> entitySets = new ArrayList<CsdlEntitySet>();
entitySets.add(getEntitySet(CONTAINER, ES_PRODUCTS_NAME));
// create EntityContainer
CsdlEntityContainer entityContainer = new CsdlEntityContainer();
entityContainer.setName(CONTAINER_NAME);
entityContainer.setEntitySets(entitySets);
return entityContainer;
}
}

View File

@ -0,0 +1,142 @@
/*
* 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.io.InputStream;
import java.util.List;
import java.util.Locale;
import myservice.mynamespace.data.Storage;
import org.apache.olingo.commons.api.data.ContextURL;
import org.apache.olingo.commons.api.data.Entity;
import org.apache.olingo.commons.api.data.EntityCollection;
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.format.ODataFormat;
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;
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.processor.EntityCollectionProcessor;
import org.apache.olingo.server.api.serializer.EntityCollectionSerializerOptions;
import org.apache.olingo.server.api.serializer.ODataSerializer;
import org.apache.olingo.server.api.serializer.SerializerException;
import org.apache.olingo.server.api.serializer.SerializerResult;
import org.apache.olingo.server.api.uri.UriInfo;
import org.apache.olingo.server.api.uri.UriResource;
import org.apache.olingo.server.api.uri.UriResourceEntitySet;
import org.apache.olingo.server.api.uri.queryoption.CountOption;
import org.apache.olingo.server.api.uri.queryoption.SkipOption;
import org.apache.olingo.server.api.uri.queryoption.TopOption;
public class DemoEntityCollectionProcessor implements EntityCollectionProcessor {
private OData odata;
private ServiceMetadata serviceMetadata;
private Storage storage;
public DemoEntityCollectionProcessor(Storage storage) {
this.storage = storage;
}
public void init(OData odata, ServiceMetadata serviceMetadata) {
this.odata = odata;
this.serviceMetadata = serviceMetadata;
}
public void readEntityCollection(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);
EdmEntitySet edmEntitySet = uriResourceEntitySet.getEntitySet();
// 2nd: fetch the data from backend for this requested EntitySetName and deliver as EntitySet
EntityCollection entityCollection = storage.readEntitySetData(edmEntitySet);
// 3rd: apply System Query Options
// modify the result set according to the query options, specified by the end user
List<Entity> entityList = entityCollection.getEntities();
EntityCollection returnEntityCollection = new EntityCollection();
// handle $count: always return the original number of entities, without considering $top and $skip
CountOption countOption = uriInfo.getCountOption();
if (countOption != null) {
boolean isCount = countOption.getValue();
if (isCount) {
returnEntityCollection.setCount(entityList.size());
}
}
// handle $skip
SkipOption skipOption = uriInfo.getSkipOption();
if (skipOption != null) {
int skipNumber = skipOption.getValue();
if (skipNumber >= 0 && skipNumber <= entityList.size()) {
entityList = entityList.subList(skipNumber, entityList.size());
} else {
throw new ODataApplicationException("Invalid value for $skip", HttpStatusCode.BAD_REQUEST.getStatusCode(),
Locale.ROOT);
}
}
// handle $top
TopOption topOption = uriInfo.getTopOption();
if (topOption != null) {
int topNumber = topOption.getValue();
if (topNumber >= 0 && topNumber <= entityList.size()) {
entityList = entityList.subList(0, topNumber);
} else {
throw new ODataApplicationException("Invalid value for $top", HttpStatusCode.BAD_REQUEST.getStatusCode(),
Locale.ROOT);
}
}
// after applying the system query options, create the EntityCollection based on the reduced list
for (Entity entity : entityList) {
returnEntityCollection.getEntities().add(entity);
}
// 4th: create a serializer based on the requested format (json)
ODataFormat format = ODataFormat.fromContentType(responseFormat);
ODataSerializer serializer = odata.createSerializer(format);
// and serialize the content: transform from the EntitySet object to InputStream
EdmEntityType edmEntityType = edmEntitySet.getEntityType();
ContextURL contextUrl = ContextURL.with().entitySet(edmEntitySet).build();
EntityCollectionSerializerOptions opts =
EntityCollectionSerializerOptions.with().contextURL(contextUrl).count(countOption).build();
SerializerResult serializerResult =
serializer.entityCollection(serviceMetadata, edmEntityType, returnEntityCollection, opts);
InputStream serializedContent = serializerResult.getContent();
// 5th: configure the response object: set the body, headers and status code
response.setContent(serializedContent);
response.setStatusCode(HttpStatusCode.OK.getStatusCode());
response.setHeader(HttpHeader.CONTENT_TYPE, responseFormat.toContentTypeString());
}
}

View File

@ -0,0 +1,118 @@
/*
* 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.io.InputStream;
import java.util.List;
import java.util.Locale;
import myservice.mynamespace.data.Storage;
import org.apache.olingo.commons.api.data.ContextURL;
import org.apache.olingo.commons.api.data.Entity;
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.format.ODataFormat;
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;
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.DeserializerException;
import org.apache.olingo.server.api.processor.EntityProcessor;
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.api.serializer.SerializerResult;
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;
public class DemoEntityProcessor implements EntityProcessor {
private OData odata;
private ServiceMetadata serviceMetadata;
private Storage storage;
public DemoEntityProcessor(Storage storage) {
this.storage = storage;
}
public void init(OData odata, ServiceMetadata serviceMetadata) {
this.odata = odata;
this.serviceMetadata = serviceMetadata;
}
public void readEntity(ODataRequest request, ODataResponse response, UriInfo uriInfo, ContentType responseFormat)
throws ODataApplicationException, SerializerException {
// 1. retrieve the Entity Type
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);
EdmEntitySet edmEntitySet = uriResourceEntitySet.getEntitySet();
// 2. retrieve the data from backend
List<UriParameter> keyPredicates = uriResourceEntitySet.getKeyPredicates();
Entity entity = storage.readEntityData(edmEntitySet, keyPredicates);
// 3. serialize
EdmEntityType entityType = edmEntitySet.getEntityType();
ContextURL contextUrl = ContextURL.with().entitySet(edmEntitySet).suffix(ContextURL.Suffix.ENTITY).build();
// expand and select currently not supported
EntitySerializerOptions options = EntitySerializerOptions.with().contextURL(contextUrl).build();
ODataFormat oDataFormat = ODataFormat.fromContentType(responseFormat);
ODataSerializer serializer = this.odata.createSerializer(oDataFormat);
SerializerResult serializerResult = serializer.entity(serviceMetadata, entityType, entity, options);
InputStream entityStream = serializerResult.getContent();
// 4. configure the response object
response.setContent(entityStream);
response.setStatusCode(HttpStatusCode.OK.getStatusCode());
response.setHeader(HttpHeader.CONTENT_TYPE, responseFormat.toContentTypeString());
}
/*
* These processor methods are not handled in this tutorial
*/
public void createEntity(ODataRequest request, ODataResponse response, UriInfo uriInfo, ContentType requestFormat,
ContentType responseFormat)
throws ODataApplicationException, DeserializerException, SerializerException {
throw new ODataApplicationException("Not supported.", HttpStatusCode.NOT_IMPLEMENTED.getStatusCode(), Locale.ROOT);
}
public void updateEntity(ODataRequest request, ODataResponse response, UriInfo uriInfo, ContentType requestFormat,
ContentType responseFormat)
throws ODataApplicationException, DeserializerException, SerializerException {
throw new ODataApplicationException("Not supported.", HttpStatusCode.NOT_IMPLEMENTED.getStatusCode(), Locale.ROOT);
}
public void deleteEntity(ODataRequest request, ODataResponse response, UriInfo uriInfo)
throws ODataApplicationException {
throw new ODataApplicationException("Not supported.", HttpStatusCode.NOT_IMPLEMENTED.getStatusCode(), Locale.ROOT);
}
}

View File

@ -0,0 +1,150 @@
/*
* 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.io.InputStream;
import java.util.List;
import java.util.Locale;
import myservice.mynamespace.data.Storage;
import org.apache.olingo.commons.api.data.ContextURL;
import org.apache.olingo.commons.api.data.Entity;
import org.apache.olingo.commons.api.data.Property;
import org.apache.olingo.commons.api.edm.EdmEntitySet;
import org.apache.olingo.commons.api.edm.EdmPrimitiveType;
import org.apache.olingo.commons.api.edm.EdmProperty;
import org.apache.olingo.commons.api.format.ContentType;
import org.apache.olingo.commons.api.format.ODataFormat;
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;
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.DeserializerException;
import org.apache.olingo.server.api.processor.PrimitiveProcessor;
import org.apache.olingo.server.api.serializer.ODataSerializer;
import org.apache.olingo.server.api.serializer.PrimitiveSerializerOptions;
import org.apache.olingo.server.api.serializer.SerializerException;
import org.apache.olingo.server.api.serializer.SerializerResult;
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.UriResourceProperty;
public class DemoPrimitiveProcessor implements PrimitiveProcessor {
private OData odata;
private Storage storage;
public DemoPrimitiveProcessor(Storage storage) {
this.storage = storage;
}
public void init(OData odata, ServiceMetadata serviceMetadata) {
this.odata = odata;
}
/*
* In our example, the URL would be: http://localhost:8080/DemoService/DemoService.svc/Products(1)/Name
* and the response:
* {
* @odata.context: "$metadata#Products/Name",
* value: "Notebook Basic 15"
* }
* */
public void readPrimitive(ODataRequest request, ODataResponse response,
UriInfo uriInfo, ContentType responseFormat)
throws ODataApplicationException, SerializerException {
// 1. Retrieve info from URI
// 1.1. retrieve the info about the requested entity set
List<UriResource> resourceParts = uriInfo.getUriResourceParts();
// Note: only in our example we can rely that the first segment is the EntitySet
UriResourceEntitySet uriEntityset = (UriResourceEntitySet) resourceParts.get(0);
EdmEntitySet edmEntitySet = uriEntityset.getEntitySet();
// the key for the entity
List<UriParameter> keyPredicates = uriEntityset.getKeyPredicates();
// 1.2. retrieve the requested (Edm) property
// the last segment is the Property
UriResourceProperty uriProperty = (UriResourceProperty)resourceParts.get(resourceParts.size() -1);
EdmProperty edmProperty = uriProperty.getProperty();
String edmPropertyName = edmProperty.getName();
// in our example, we know we have only primitive types in our model
EdmPrimitiveType edmPropertyType = (EdmPrimitiveType) edmProperty.getType();
// 2. retrieve data from backend
// 2.1. retrieve the entity data, for which the property has to be read
Entity entity = storage.readEntityData(edmEntitySet, keyPredicates);
if (entity == null) { // Bad request
throw new ODataApplicationException("Entity not found", HttpStatusCode.NOT_FOUND.getStatusCode(), Locale.ROOT);
}
// 2.2. retrieve the property data from the entity
Property property = entity.getProperty(edmPropertyName);
if (property == null) {
throw new ODataApplicationException("Property not found", HttpStatusCode.NOT_FOUND.getStatusCode(), Locale.ROOT);
}
// 3. serialize
Object value = property.getValue();
if (value != null) {
// 3.1. configure the serializer
ODataFormat format = ODataFormat.fromContentType(responseFormat);
ODataSerializer serializer = odata.createSerializer(format);
ContextURL contextUrl = ContextURL.with().entitySet(edmEntitySet).navOrPropertyPath(edmPropertyName).build();
PrimitiveSerializerOptions options = PrimitiveSerializerOptions.with().contextURL(contextUrl).build();
// 3.2. serialize
SerializerResult serializerResult = serializer.primitive(edmPropertyType, property, options);
InputStream propertyStream = serializerResult.getContent();
//4. configure the response object
response.setContent(propertyStream);
response.setStatusCode(HttpStatusCode.OK.getStatusCode());
response.setHeader(HttpHeader.CONTENT_TYPE, responseFormat.toContentTypeString());
} else {
// in case there's no value for the property, we can skip the serialization
response.setStatusCode(HttpStatusCode.NO_CONTENT.getStatusCode());
}
}
/*
* These processor methods are not handled in this tutorial
* */
public void updatePrimitive(ODataRequest request, ODataResponse response, UriInfo uriInfo,
ContentType requestFormat, ContentType responseFormat)
throws ODataApplicationException, DeserializerException, SerializerException {
throw new ODataApplicationException("Not supported.", HttpStatusCode.NOT_IMPLEMENTED.getStatusCode(), Locale.ROOT);
}
public void deletePrimitive(ODataRequest request, ODataResponse response, UriInfo uriInfo)
throws ODataApplicationException {
throw new ODataApplicationException("Not supported.", HttpStatusCode.NOT_IMPLEMENTED.getStatusCode(), Locale.ROOT);
}
}

View File

@ -0,0 +1,105 @@
/*
* 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.util;
import java.util.List;
import java.util.Locale;
import org.apache.olingo.commons.api.data.Entity;
import org.apache.olingo.commons.api.data.EntityCollection;
import org.apache.olingo.commons.api.edm.EdmEntitySet;
import org.apache.olingo.commons.api.edm.EdmEntityType;
import org.apache.olingo.commons.api.edm.EdmPrimitiveType;
import org.apache.olingo.commons.api.edm.EdmPrimitiveTypeException;
import org.apache.olingo.commons.api.edm.EdmProperty;
import org.apache.olingo.commons.api.edm.EdmType;
import org.apache.olingo.commons.api.http.HttpStatusCode;
import org.apache.olingo.server.api.ODataApplicationException;
import org.apache.olingo.server.api.uri.UriInfoResource;
import org.apache.olingo.server.api.uri.UriParameter;
import org.apache.olingo.server.api.uri.UriResource;
import org.apache.olingo.server.api.uri.UriResourceEntitySet;
public class Util {
public static Entity findEntity(EdmEntityType edmEntityType, EntityCollection entitySet,
List<UriParameter> keyParams) throws ODataApplicationException {
List<Entity> entityList = entitySet.getEntities();
// loop over all entities in order to find that one that matches all keys in request
// e.g. contacts(ContactID=1, CompanyID=1)
for (Entity entity: entityList) {
boolean foundEntity = entityMatchesAllKeys(edmEntityType, entity, keyParams);
if (foundEntity) {
return entity;
}
}
return null;
}
public static boolean entityMatchesAllKeys(EdmEntityType edmEntityType, Entity entity, List<UriParameter> keyParams)
throws ODataApplicationException {
// loop over all keys
for (final UriParameter key : keyParams) {
// key
String keyName = key.getName();
String keyText = key.getText();
// Edm: we need this info for the comparison below
EdmProperty edmKeyProperty = (EdmProperty) edmEntityType.getProperty(keyName);
Boolean isNullable = edmKeyProperty.isNullable();
Integer maxLength = edmKeyProperty.getMaxLength();
Integer precision = edmKeyProperty.getPrecision();
Boolean isUnicode = edmKeyProperty.isUnicode();
Integer scale = edmKeyProperty.getScale();
// get the EdmType in order to compare
EdmType edmType = edmKeyProperty.getType();
EdmPrimitiveType edmPrimitiveType = (EdmPrimitiveType) edmType;
// Runtime data: the value of the current entity
// don't need to check for null, this is done in olingo library
Object valueObject = entity.getProperty(keyName).getValue();
// now need to compare the valueObject with the keyText String
// this is done using the type.valueToString
String valueAsString;
try {
valueAsString = edmPrimitiveType.valueToString(valueObject, isNullable, maxLength, precision, scale, isUnicode);
} catch (EdmPrimitiveTypeException e) {
throw new ODataApplicationException("Failed to retrieve String value", HttpStatusCode.INTERNAL_SERVER_ERROR
.getStatusCode(), Locale.ENGLISH, e);
}
if (valueAsString == null) {
return false;
}
boolean matches = valueAsString.equals(keyText);
if (!matches) {
// if any of the key properties is not found in the entity, we don't need to search further
return false;
}
}
return true;
}
}

View File

@ -0,0 +1,76 @@
/*
* Licensed to the Apache Software Foundation (ASF) under one
* or more contributor license agreements. See the NOTICE file
* distributed with this work for additional information
* regarding copyright ownership. The ASF licenses this file
* to you under the Apache License, Version 2.0 (the
* "License"); you may not use this file except in compliance
* with the License. You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing,
* software distributed under the License is distributed on an
* "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
* KIND, either express or implied. See the License for the
* specific language governing permissions and limitations
* under the License.
*/
package myservice.mynamespace.web;
import java.io.IOException;
import java.lang.Override;import java.lang.RuntimeException;import java.util.ArrayList;
import javax.servlet.ServletException;
import javax.servlet.http.HttpServlet;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import javax.servlet.http.HttpSession;
import myservice.mynamespace.data.Storage;
import myservice.mynamespace.service.DemoEdmProvider;
import myservice.mynamespace.service.DemoEntityCollectionProcessor;
import myservice.mynamespace.service.DemoEntityProcessor;
import myservice.mynamespace.service.DemoPrimitiveProcessor;
import org.apache.olingo.server.api.OData;
import org.apache.olingo.server.api.ODataHttpHandler;
import org.apache.olingo.server.api.ServiceMetadata;
import org.apache.olingo.server.api.edmx.EdmxReference;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
public class DemoServlet extends HttpServlet {
private static final long serialVersionUID = 1L;
private static final Logger LOG = LoggerFactory.getLogger(DemoServlet.class);
@Override
protected void service(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
try {
HttpSession session = req.getSession(true);
Storage storage = (Storage) session.getAttribute(Storage.class.getName());
if (storage == null) {
storage = new Storage();
session.setAttribute(Storage.class.getName(), storage);
}
// create odata handler and configure it with EdmProvider and Processor
OData odata = OData.newInstance();
ServiceMetadata edm = odata.createServiceMetadata(new DemoEdmProvider(), new ArrayList<EdmxReference>());
ODataHttpHandler handler = odata.createHandler(edm);
handler.register(new DemoEntityCollectionProcessor(storage));
handler.register(new DemoEntityProcessor(storage));
handler.register(new DemoPrimitiveProcessor(storage));
// let the handler do the work
handler.process(req, resp);
} catch (RuntimeException e) {
LOG.error("Server Error occurred in ExampleServlet", e);
throw new ServletException(e);
}
}
}

View File

@ -0,0 +1,40 @@
<?xml version="1.0" encoding="UTF-8"?>
<!--
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.
-->
<web-app xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xmlns="http://java.sun.com/xml/ns/javaee" xmlns:web="http://java.sun.com/xml/ns/javaee/web-app_2_5.xsd"
xsi:schemaLocation="http://java.sun.com/xml/ns/javaee http://java.sun.com/xml/ns/javaee/web-app_2_5.xsd"
id="WebApp_ID" version="2.5">
<!-- Register the HttpServlet implementation -->
<servlet>
<servlet-name>DemoServlet</servlet-name>
<servlet-class>myservice.mynamespace.web.DemoServlet</servlet-class>
<load-on-startup>1</load-on-startup>
</servlet>
<!--
Our OData service can be invoked at
http://localhost:8080/DemoService/DemoService.svc
-->
<servlet-mapping>
<servlet-name>DemoServlet</servlet-name>
<url-pattern>/DemoService.svc/*</url-pattern>
</servlet-mapping>
</web-app>

View File

@ -0,0 +1,26 @@
<!--
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.
-->
<html>
<body>
<h2>Hello World!</h2>
<a href="DemoService.svc/">OData Olingo V4 Demo Service</a>
</body>
</html>

View File

@ -39,6 +39,7 @@
<module>p2_readep</module> <module>p2_readep</module>
<module>p3_write</module> <module>p3_write</module>
<module>p4_navigation</module> <module>p4_navigation</module>
<module>p5_queryoptions</module>
</modules> </modules>
<build> <build>