[OLINGO-713] Adaptions for tutorials for xml format

This commit is contained in:
Michael Bolz 2015-09-16 14:18:39 +02:00
parent 9c3ca381e2
commit dec27a4918
6 changed files with 197 additions and 53 deletions

View File

@ -18,6 +18,8 @@
*/
package myservice.mynamespace.data;
import java.net.URI;
import java.net.URISyntaxException;
import java.util.ArrayList;
import java.util.List;
import java.util.Locale;
@ -33,6 +35,7 @@ import org.apache.olingo.commons.api.edm.EdmEntitySet;
import org.apache.olingo.commons.api.edm.EdmEntityType;
import org.apache.olingo.commons.api.edm.EdmKeyPropertyRef;
import org.apache.olingo.commons.api.edm.FullQualifiedName;
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;
@ -106,6 +109,7 @@ 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) {
@ -117,6 +121,7 @@ public class Storage {
}
} 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) {
@ -137,7 +142,7 @@ public class Storage {
return navigationTargetEntityCollection;
}
public Entity createEntityData(EdmEntitySet edmEntitySet, Entity entityToCreate) {
EdmEntityType edmEntityType = edmEntitySet.getEntityType();
@ -321,6 +326,7 @@ public class Storage {
entity.addProperty(new Property(null, "Description", ValueType.PRIMITIVE,
"Notebook Basic, 1.7GHz - 15 XGA - 1024MB DDR2 SDRAM - 40GB"));
entity.setType(DemoEdmProvider.ET_PRODUCT_FQN.getFullQualifiedNameAsString());
entity.setId(createId(entity, "ID"));
productList.add(entity);
entity = new Entity();
@ -329,6 +335,7 @@ public class Storage {
entity.addProperty(new Property(null, "Description", ValueType.PRIMITIVE,
"Notebook Professional, 2.8GHz - 15 XGA - 8GB DDR3 RAM - 500GB"));
entity.setType(DemoEdmProvider.ET_PRODUCT_FQN.getFullQualifiedNameAsString());
entity.setId(createId(entity, "ID"));
productList.add(entity);
entity = new Entity();
@ -337,6 +344,7 @@ public class Storage {
entity.addProperty(new Property(null, "Description", ValueType.PRIMITIVE,
"Ultrafast 3G UMTS/HSDPA Pocket PC, supports GSM network"));
entity.setType(DemoEdmProvider.ET_PRODUCT_FQN.getFullQualifiedNameAsString());
entity.setId(createId(entity, "ID"));
productList.add(entity);
entity = new Entity();
@ -345,6 +353,7 @@ public class Storage {
entity.addProperty(new Property(null, "Description", ValueType.PRIMITIVE,
"32 GB Digital Assitant with high-resolution color screen"));
entity.setType(DemoEdmProvider.ET_PRODUCT_FQN.getFullQualifiedNameAsString());
entity.setId(createId(entity, "ID"));
productList.add(entity);
entity = new Entity();
@ -353,6 +362,7 @@ public class Storage {
entity.addProperty(new Property(null, "Description", ValueType.PRIMITIVE,
"19 Optimum Resolution 1024 x 768 @ 85Hz, resolution 1280 x 960"));
entity.setType(DemoEdmProvider.ET_PRODUCT_FQN.getFullQualifiedNameAsString());
entity.setId(createId(entity, "ID"));
productList.add(entity);
entity = new Entity();
@ -361,6 +371,7 @@ public class Storage {
entity.addProperty(new Property(null, "Description", ValueType.PRIMITIVE,
"Optimum Hi-Resolution max. 1600 x 1200 @ 85Hz, Dot Pitch: 0.24mm"));
entity.setType(DemoEdmProvider.ET_PRODUCT_FQN.getFullQualifiedNameAsString());
entity.setId(createId(entity, "ID"));
productList.add(entity);
}
@ -371,19 +382,48 @@ public class Storage {
entity.addProperty(new Property(null, "ID", ValueType.PRIMITIVE, 1));
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, "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, "Name", ValueType.PRIMITIVE, "Monitors"));
entity.setType(DemoEdmProvider.ET_CATEGORY_FQN.getFullQualifiedNameAsString());
entity.setId(createId(entity, "ID"));
categoryList.add(entity);
}
private URI createId(Entity entity, String idPropertyName) {
return createId(entity, idPropertyName, null);
}
private URI createId(Entity entity, String idPropertyName, String navigationName) {
try {
StringBuilder sb = new StringBuilder(getEntitySetName(entity)).append("(");
final Property property = entity.getProperty(idPropertyName);
sb.append(property.asPrimitive()).append(")");
if(navigationName != null) {
sb.append("/").append(navigationName);
}
return new URI(sb.toString());
} catch (URISyntaxException e) {
throw new ODataRuntimeException("Unable to create (Atom) id for entity: " + entity, e);
}
}
private String getEntitySetName(Entity entity) {
if(DemoEdmProvider.ET_CATEGORY_FQN.getFullQualifiedNameAsString().equals(entity.getType())) {
return DemoEdmProvider.ES_CATEGORIES_NAME;
} else if(DemoEdmProvider.ET_PRODUCT_FQN.getFullQualifiedNameAsString().equals(entity.getType())) {
return DemoEdmProvider.ES_PRODUCTS_NAME;
}
return entity.getType();
}
}

View File

@ -54,6 +54,8 @@ public class DemoEdmProvider extends CsdlAbstractEdmProvider {
// Entity Set Names
public static final String ES_PRODUCTS_NAME = "Products";
public static final String ES_CATEGORIES_NAME = "Categories";
public static final String NAV_TO_CATEGORY = "Category";
public static final String NAV_TO_PRODUCTS = "Products";
@Override
public CsdlEntityType getEntityType(FullQualifiedName entityTypeName) {
@ -75,7 +77,7 @@ public class DemoEdmProvider extends CsdlAbstractEdmProvider {
propertyRef.setName("ID");
// navigation property: many-to-one, null not allowed (product must have a category)
CsdlNavigationProperty navProp = new CsdlNavigationProperty().setName("Category")
CsdlNavigationProperty navProp = new CsdlNavigationProperty().setName(NAV_TO_CATEGORY)
.setType(ET_CATEGORY_FQN).setNullable(false).setPartner("Products");
List<CsdlNavigationProperty> navPropList = new ArrayList<CsdlNavigationProperty>();
navPropList.add(navProp);
@ -99,7 +101,7 @@ public class DemoEdmProvider extends CsdlAbstractEdmProvider {
propertyRef.setName("ID");
// navigation property: one-to-many
CsdlNavigationProperty navProp = new CsdlNavigationProperty().setName("Products")
CsdlNavigationProperty navProp = new CsdlNavigationProperty().setName(NAV_TO_PRODUCTS)
.setType(ET_PRODUCT_FQN).setCollection(true).setPartner("Category");
List<CsdlNavigationProperty> navPropList = new ArrayList<CsdlNavigationProperty>();
navPropList.add(navProp);

View File

@ -115,8 +115,7 @@ public class DemoEntityCollectionProcessor implements EntityCollectionProcessor
modifiedEntityList = applyTopQueryOption(modifiedEntityList, uriInfo.getTopOption());
// 3.6.) Server driven paging (not part of this tutorial)
// 3.7.) $expand
modifiedEntityList = applyExpandQueryOption(modifiedEntityCollection, modifiedEntityList, edmEntitySet,
uriInfo.getExpandOption());
modifiedEntityList = applyExpandQueryOption(modifiedEntityList, edmEntitySet, uriInfo.getExpandOption());
// 3.8.) $select
SelectOption selectOption = uriInfo.getSelectOption();
@ -133,13 +132,15 @@ public class DemoEntityCollectionProcessor implements EntityCollectionProcessor
ContextURL contextUrl = ContextURL.with().entitySet(edmEntitySet).selectList(selectList).build();
// adding the selectOption to the serializerOpts will actually tell the lib to do the job
final String id = request.getRawBaseUri() + "/" + edmEntitySet.getName();
EntityCollectionSerializerOptions opts = EntityCollectionSerializerOptions.with()
.contextURL(contextUrl)
.count(uriInfo.getCountOption())
.select(selectOption)
.expand(uriInfo.getExpandOption())
.setId(id)
.build();
// and serialize the content: transform from the EntitySet object to InputStream
SerializerResult serializerResult = serializer.entityCollection(serviceMetadata, edmEntityType,
modifiedEntityCollection, opts);
@ -151,7 +152,7 @@ public class DemoEntityCollectionProcessor implements EntityCollectionProcessor
response.setHeader(HttpHeader.CONTENT_TYPE, responseFormat.toContentTypeString());
}
private List<Entity> applyExpandQueryOption(EntityCollection entityCollection, List<Entity> modifiedEntityList,
private List<Entity> applyExpandQueryOption(List<Entity> modifiedEntityList,
EdmEntitySet edmEntitySet, ExpandOption expandOption) {
// in our example: http://localhost:8080/DemoService/DemoService.svc/Categories/$expand=Products
@ -193,16 +194,19 @@ public class DemoEntityCollectionProcessor implements EntityCollectionProcessor
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/$expand=Products
// 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());
} 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());
}
// set the link - containing the expanded data - to the current entity

View File

@ -99,7 +99,6 @@ public class DemoEntityProcessor implements EntityProcessor {
// Analyze the URI segments
if (segmentCount == 1) { // no navigation
responseEdmEntityType = startEdmEntitySet.getEntityType();
responseEdmEntitySet = startEdmEntitySet; // since we have only one segment
// 2. step: retrieve the data from backend
@ -190,17 +189,21 @@ public class DemoEntityProcessor implements EntityProcessor {
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
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);
EntityCollection expandEntityCollection =
storage.getRelatedEntityCollection(responseEntity, expandEdmEntityType);
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);
link.setHref(expandEntity.getId().toASCIIString());
}
// set the link - containing the expanded data - to the current entity

View File

@ -46,7 +46,6 @@ public class FilterExpressionVisitor implements ExpressionVisitor<Object> {
this.currentEntity = currentEntity;
}
@Override
public Object visitMember(UriInfoResource member) throws ExpressionVisitException, ODataApplicationException {
// To keeps things simple, this tutorial allows only primitive properties.
// We have faith that the java type of Edm.Int32 is Integer
@ -73,7 +72,6 @@ public class FilterExpressionVisitor implements ExpressionVisitor<Object> {
}
}
@Override
public Object visitLiteral(Literal literal) throws ExpressionVisitException, ODataApplicationException {
// To keep this tutorial simple, our filter expression visitor supports only Edm.Int32 and Edm.String
// In real world scenarios it can be difficult to guess the type of an literal.
@ -100,8 +98,7 @@ public class FilterExpressionVisitor implements ExpressionVisitor<Object> {
}
}
@Override
public Object visitUnaryOperator(UnaryOperatorKind operator, Object operand)
public Object visitUnaryOperator(UnaryOperatorKind operator, Object operand)
throws ExpressionVisitException, ODataApplicationException {
// OData allows two different unary operators. We have to take care, that the type of the operand fits to
// operand
@ -119,8 +116,7 @@ public class FilterExpressionVisitor implements ExpressionVisitor<Object> {
HttpStatusCode.BAD_REQUEST.getStatusCode(), Locale.ENGLISH);
}
@Override
public Object visitBinaryOperator(BinaryOperatorKind operator, Object left, Object right)
public Object visitBinaryOperator(BinaryOperatorKind operator, Object left, Object right)
throws ExpressionVisitException, ODataApplicationException {
// Binary Operators are split up in three different kinds. Up to the kind of the operator it can be applied
@ -181,11 +177,11 @@ public class FilterExpressionVisitor implements ExpressionVisitor<Object> {
// Luckily all used types String, Boolean and also Integer support the interface Comparable
int result;
if(left instanceof Integer) {
result = ((Comparable<Integer>) (Integer)left).compareTo((Integer) right);
result = ((Integer) left).compareTo((Integer) right);
} else if(left instanceof String) {
result = ((Comparable<String>) (String)left).compareTo((String) right);
result = ((String) left).compareTo((String) right);
} else if(left instanceof Boolean) {
result = ((Comparable<Boolean>) (Boolean)left).compareTo((Boolean) right);
result = ((Boolean) left).compareTo((Boolean) right);
} else {
throw new ODataApplicationException("Class " + left.getClass().getCanonicalName() + " not expected",
HttpStatusCode.INTERNAL_SERVER_ERROR.getStatusCode(), Locale.ENGLISH);
@ -207,7 +203,7 @@ public class FilterExpressionVisitor implements ExpressionVisitor<Object> {
}
} else {
throw new ODataApplicationException("Comparision needs two equal types",
throw new ODataApplicationException("Comparison needs two equal types",
HttpStatusCode.BAD_REQUEST.getStatusCode(), Locale.ENGLISH);
}
}
@ -239,8 +235,7 @@ public class FilterExpressionVisitor implements ExpressionVisitor<Object> {
}
}
@Override
public Object visitMethodCall(MethodKind methodCall, List<Object> parameters)
public Object visitMethodCall(MethodKind methodCall, List<Object> parameters)
throws ExpressionVisitException, ODataApplicationException {
// To keep this tutorial small and simple, we implement only one method call
@ -248,7 +243,7 @@ public class FilterExpressionVisitor implements ExpressionVisitor<Object> {
// "Contains" gets two parameters, both have to be of type String
// e.g. /Products?$filter=contains(Description, '1024 MB')
//
// First the method visistMember is called, which returns the current String value of the property.
// First the method visitMember is called, which returns the current String value of the property.
// After that the method visitLiteral is called with the string literal '1024 MB',
// which returns a String
//
@ -259,7 +254,7 @@ public class FilterExpressionVisitor implements ExpressionVisitor<Object> {
return valueParam1.contains(valueParam2);
} else {
throw new ODataApplicationException("Contains needs two parametes of type Edm.String",
throw new ODataApplicationException("Contains needs two parameters of type Edm.String",
HttpStatusCode.BAD_REQUEST.getStatusCode(), Locale.ENGLISH);
}
} else {
@ -268,34 +263,29 @@ public class FilterExpressionVisitor implements ExpressionVisitor<Object> {
}
}
@Override
public Object visitTypeLiteral(EdmType type) throws ExpressionVisitException, ODataApplicationException {
throw new ODataApplicationException("Type literals are not implemented",
HttpStatusCode.NOT_IMPLEMENTED.getStatusCode(), Locale.ENGLISH);
}
@Override
public Object visitAlias(String aliasName) throws ExpressionVisitException, ODataApplicationException {
public Object visitAlias(String aliasName) throws ExpressionVisitException, ODataApplicationException {
throw new ODataApplicationException("Aliases are not implemented",
HttpStatusCode.NOT_IMPLEMENTED.getStatusCode(), Locale.ENGLISH);
}
@Override
public Object visitEnum(EdmEnumType type, List<String> enumValues)
public Object visitEnum(EdmEnumType type, List<String> enumValues)
throws ExpressionVisitException, ODataApplicationException {
throw new ODataApplicationException("Enums are not implemented",
HttpStatusCode.NOT_IMPLEMENTED.getStatusCode(), Locale.ENGLISH);
}
@Override
public Object visitLambdaExpression(String lambdaFunction, String lambdaVariable, Expression expression)
public Object visitLambdaExpression(String lambdaFunction, String lambdaVariable, Expression expression)
throws ExpressionVisitException, ODataApplicationException {
throw new ODataApplicationException("Lamdba expressions are not implemented",
HttpStatusCode.NOT_IMPLEMENTED.getStatusCode(), Locale.ENGLISH);
}
@Override
public Object visitLambdaReference(String variableName)
public Object visitLambdaReference(String variableName)
throws ExpressionVisitException, ODataApplicationException {
throw new ODataApplicationException("Lamdba references are not implemented",
HttpStatusCode.NOT_IMPLEMENTED.getStatusCode(), Locale.ENGLISH);

View File

@ -1,24 +1,129 @@
/*
* 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.
*/
<!--
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>
<h2>OData Olingo V4 Demo Service</h2>
<a href="DemoService.svc/">OData Olingo V4 Demo Service</a>
<h3>Sample Links</h3>
<ul>
<li>
<h4>Read Entities</h4>
<ul>
<li>
<a href="DemoService.svc/Products(1)">Product Entity - /Products(1)</a>
</li>
<li>
<a href="DemoService.svc/Categories(1)">Category Entity - /Categories(1)</a>
</li>
</ul>
</li>
<li>
<h4>Read Entity Sets</h4>
<ul>
<li>
<a href="DemoService.svc/Products">Products Entities - /Products</a>
</li>
<li>
<a href="DemoService.svc/Categories">Category Entities - /Categories</a>
</li>
</ul>
</li>
<li>
<h4>Navigation between Entity and Entity Sets</h4>
<ul>
<li>
<a href="DemoService.svc/Products(1)/Category">Category of first Product - /Products(1)/Category</a>
</li>
<li>
<a href="DemoService.svc/Categories(1)/Products">Products of first Category - /Categories(1)/Products</a>
</li>
</ul>
</li>
<li>
<h4>Top, Count, Skip for Entity Sets</h4>
<ul>
<li>
<a href="DemoService.svc/Products/?$top=3">Top three of Products - /Products/?$top=3</a>
</li>
<li>
<a href="DemoService.svc/Products/?$count=true">Products with count - /Products/?$count=true</a>
</li>
<li>
<a href="DemoService.svc/Products/?$skip=2">Skip two Products - /Products/?$skip=2</a>
</li>
<li>
<a href="DemoService.svc/Products/?$skip=2&$top=2&$count=true">Skip two, get first two and count all
Products - /Products/?$skip=2&$top=2&$count=true</a>
</li>
</ul>
</li>
<li>
<h4>Order by ... of Entity Sets</h4>
<ul>
<li>
<a href="DemoService.svc/Products/?$orderby=Name">Products ordered by name -
/Products/?$orderby=Name</a>
</li>
<li>
<a href="DemoService.svc/Products/?$orderby=Name&$select=Name">Products ordered by name and select
name only - /Products/?$orderby=Name&$select=Name</a>
</li>
</ul>
</li>
<li>
<h4>Filtered Entity Sets</h4>
<ul>
<li>
<a href="DemoService.svc/Products?$filter=contains(Name,%27Screen%27)">Products which name contains
screen - /Products?$filter=contains(Name,%27Screen%27)</a>
</li>
<li>
<a href="DemoService.svc/Products/?$filter=ID%20gt%204">Products which id is greater then 4 -
/Products/?$filter=ID%20gt%204x</a>
</li>
</ul>
</li>
<li>
<h4>Expand of Entities and Entity Sets</h4>
<ul>
<li>
<a href="DemoService.svc/Products(1)/?$expand=Category">Expand - /Products(1)/?$expand=Category</a>
</li>
<li>
<a href="DemoService.svc/Products/?$expand=Category">Expand - /Products/?$expand=Category</a>
</li>
<li>
<a href="DemoService.svc/Products(1)/?$expand=*">Expand - /Products(1)/?$expand=*</a>
</li>
<li>
<a href="DemoService.svc/Categories(1)/?$expand=Products">Expand - /Categories(1)/?$expand=Products</a>
</li>
<li>
<a href="DemoService.svc/Categories/?$expand=Products">Expand - /Categories/?$expand=Products</a>
</li>
<li>
<a href="DemoService.svc/Categories/?$expand=*">Expand - /Categories/?$expand=*</a>
</li>
</ul>
</li>
</ul>
</body>
</html>