You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@olingo.apache.org by mi...@apache.org on 2015/05/19 14:24:49 UTC

svn commit: r1680268 - /olingo/site/trunk/content/doc/odata4/tutorials/read/tutorial_read.mdtext

Author: mibo
Date: Tue May 19 12:24:48 2015
New Revision: 1680268

URL: http://svn.apache.org/r1680268
Log:
Update to beta-03 release

Modified:
    olingo/site/trunk/content/doc/odata4/tutorials/read/tutorial_read.mdtext

Modified: olingo/site/trunk/content/doc/odata4/tutorials/read/tutorial_read.mdtext
URL: http://svn.apache.org/viewvc/olingo/site/trunk/content/doc/odata4/tutorials/read/tutorial_read.mdtext?rev=1680268&r1=1680267&r2=1680268&view=diff
==============================================================================
--- olingo/site/trunk/content/doc/odata4/tutorials/read/tutorial_read.mdtext (original)
+++ olingo/site/trunk/content/doc/odata4/tutorials/read/tutorial_read.mdtext Tue May 19 12:24:48 2015
@@ -18,7 +18,7 @@ Notice:    Licensed to the Apache Softwa
 
 # How to build an OData Service with Olingo V4
 
-This tutorial guides you through the steps required to write an OData Service based on the Olingo OData 4.0 Library for Java (based on current *Olingo 4.0.0-beta-02 release* which can be get via the [Download-Page](../../download.html)).
+This tutorial guides you through the steps required to write an OData Service based on the Olingo OData 4.0 Library for Java (based on current *Olingo 4.0.0-beta-03 release* which can be get via the [Download-Page](../../download.html)).
 
 The final result can be download [here](sample/DemoService_Tutorial_Read.zip) ([md5](sample/DemoService_Tutorial_Read.zip.md5), [sha512](sample/DemoService_Tutorial_Read.zip.sha512), [pgp](sample/DemoService_Tutorial_Read.zip.asc)).
 
@@ -182,7 +182,7 @@ In our example, the pom.xml file looks a
 
     	<properties>
     		<javax.version>2.5</javax.version>
-    		<odata.version>4.0.0-beta-02</odata.version>
+    		<odata.version>4.0.0-beta-03</odata.version>
     		<slf4j.version>1.7.7</slf4j.version>
     	</properties>
 
@@ -363,7 +363,7 @@ First, we need to declare some constants
 
     :::java
     // Service Namespace
-    public static final String NAMESPACE = "com.example.model";
+    public static final String NAMESPACE = "OData.Demo";
 
     // EDM Container
     public static final String CONTAINER_NAME = "Container";
@@ -382,9 +382,9 @@ First, we need to declare some constants
 
 In our example service, we want to provide a list of products to users who call the OData service.
 The user of our service, for example an app-developer, may ask: What does such a "product" entry look like? How is it structured? Which information about a product is provided? For example, the name of it and which data types can be expected from these properties?  
-Such information is provided by the _EdmProvider_.
+Such information is provided by a `CsdlEdmProvider` (and for convenience we extend the `CsdlAbstractEdmProvider`).
 
-In our example service, for modelling the _EntityType_, we have to provide the following metadata:
+In our example service, for modelling the `CsdlEntityType`, we have to provide the following metadata:
 
 The name of the EntityType: “Product”  
 The properties: name and type and additional info, e.g. “ID” of type “edm.int32”  
@@ -392,61 +392,59 @@ Which of the properties is the “key
 
 
     :::java
-    @Override
-    public EntityType getEntityType(FullQualifiedName entityTypeName) throws ODataException {
+    public CsdlEntityType getEntityType(FullQualifiedName entityTypeName) throws ODataException {
 
-    	// this method is called for one of the EntityTypes that are configured in the Schema
-    	if(entityTypeName.equals(ET_PRODUCT_FQN)){
+      // this method is called for one of the EntityTypes that are configured in the Schema
+      if(entityTypeName.equals(ET_PRODUCT_FQN)){
 
-    		//create EntityType properties
-    		Property id = new Property().setName("ID").setType(EdmPrimitiveTypeKind.Int32.getFullQualifiedName());
-    		Property name = new Property().setName("Name").setType(EdmPrimitiveTypeKind.String.getFullQualifiedName());
-    		Property  description = new Property().setName("Description").setType(EdmPrimitiveTypeKind.String.getFullQualifiedName());
-
-    		// create PropertyRef for Key element
-    		PropertyRef propertyRef = new PropertyRef();
-    		propertyRef.setPropertyName("ID");
-
-    		// configure EntityType
-    		EntityType entityType = new EntityType();
-    		entityType.setName(ET_PRODUCT_NAME);
-    		entityType.setProperties(Arrays.asList(id, name , description));
-    		entityType.setKey(Arrays.asList(propertyRef));
+        //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 CsdlPropertyRef 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 entityType;
+      }
 
-    	return null;
+      return null;
     }
 
 
 **_getEntitySet()_**
 
-The procedure for declaring the _EntitySets_ is similar.
+The procedure for declaring the _Entity Sets_ is similar.
 An _EntitySet_ is a crucial resource, when an OData service is used to request data.
 In our example, we will invoke the following URL, which we expect to provide us a list of products:
 
     :::html
     http://localhost:8080/DemoService/DemoServlet.svc/Products
 
-When declaring an _EntitySet_, we need to define the type of entries which are contained in the list, such as an _EntityType_.
-In our example, we set our previously created _EntityType_, which is referred by a _FullQualifiedName_.
+When declaring an `EntitySet`, we need to define the type of entries which are contained in the list, such as an `CsdlEntityType`.
+In our example, we set our previously created `CsdlEntityType`, which is referred by a _FullQualifiedName_.
 
     :::java
-    @Override
-    public EntitySet getEntitySet(FullQualifiedName entityContainer, String entitySetName) throws ODataException {
+    public CsdlEntitySet getEntitySet(FullQualifiedName entityContainer, String entitySetName) throws ODataException {
 
-    	if(entityContainer.equals(CONTAINER)){
-    		if(entitySetName.equals(ES_PRODUCTS_NAME)){
-    			EntitySet entitySet = new EntitySet();
-    			entitySet.setName(ES_PRODUCTS_NAME);
-    			entitySet.setType(ET_PRODUCT_FQN);
-
-    			return entitySet;
-    		}
-    	}
+      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;
+      return null;
     }
 
 
@@ -476,35 +474,34 @@ In our example, we have only one _Entity
 
 **_getSchemas()_**
 
-Up to this point, we have declared the type of our data (_EntityType_) and our list (_EntitySet_), and we have put it into a container (_EntityContainer_).  
-Now we are required to put all these elements into a _Schema_.  
+Up to this point, we have declared the type of our data (`CsdlEntityType`) and our list (`CsdlEntitySet`), and we have put it into a container (`CsdlEntityContainer`).  
+Now we are required to put all these elements into a `CsdlSchema`.  
 While the model of an OData service can have several schemas, in most cases there will probably be only one schema.  
-So, in our example, we create a list of schemas, where we add one new _Schema_ object.  
+So, in our example, we create a list of schemas, where we add one new `CsdlSchema` object.  
 The schema is configured with a _Namespace_, which serves to uniquely identify all elements.  
 Then our elements are added to the Schema.
 
 
     :::java
-    @Override
-    public List<Schema> getSchemas() throws ODataException {
+    public List<CsdlSchema> getSchemas() throws ODataException {
 
-    	// create Schema
-    	Schema schema = new Schema();
-    	schema.setNamespace(NAMESPACE);
+      // create Schema
+      CsdlSchema schema = new CsdlSchema();
+      schema.setNamespace(NAMESPACE);
 
-    	// add EntityTypes
-    	List<EntityType> entityTypes = new ArrayList<EntityType>();
-    	entityTypes.add(getEntityType(ET_PRODUCT_FQN));
-    	schema.setEntityTypes(entityTypes);
+      // add EntityTypes
+      List<CsdlEntityType> entityTypes = new ArrayList<CsdlEntityType>();
+      entityTypes.add(getEntityType(ET_PRODUCT_FQN));
+      schema.setEntityTypes(entityTypes);
 
-    	// add EntityContainer
-    	schema.setEntityContainer(getEntityContainer());
+      // add EntityContainer
+      schema.setEntityContainer(getEntityContainer());
 
-    	// finally
-    	List<Schema> schemas = new ArrayList<Schema>();
-    	schemas.add(schema);
+      // finally
+      List<CsdlSchema> schemas = new ArrayList<CsdlSchema>();
+      schemas.add(schema);
 
-    	return schemas;
+      return schemas;
     }
 
 
@@ -512,23 +509,24 @@ Then our elements are added to the Schem
 
 
     :::java
-    @Override
-    public EntityContainerInfo getEntityContainerInfo(FullQualifiedName entityContainerName) throws ODataException {
+    public CsdlEntityContainer getEntityContainer() 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)){
-    		EntityContainerInfo entityContainerInfo = new EntityContainerInfo();
-    		entityContainerInfo.setContainerName(CONTAINER);
-    		return entityContainerInfo;
-    	}
+      // 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 null;
+      return entityContainer;
     }
 
 
 **Summary:**  
 We have created a class that declares the metadata of our OData service.
-We have declared the main elements of an OData service: _EntityType_, _EntitySet_, _EntityContainer_ and _Schema_.
+We have declared the main elements of an OData service: _EntityType_, _EntitySet_, _EntityContainer_ and _Schema_ (with us of the according Olingo classes `CsdlEntityType`, `CsdlEntitySet`, `CsdlEntityContainer` and `CsdlSchema`).
 
 At runtime of an OData service, such metadata can be viewed by invoking the Metadata Document.
 
@@ -586,16 +584,17 @@ He invokes a URL and gets a list of prod
 Providing the list of products is the task that we are going to implement in this chapter.
 
 The work that we have to do in this chapter can be divided into 4 tasks:
-1. Check the URI  
-    We need to identify the requested resource and have to consider Query Options (if available)
-2. Provide the data  
-    Based on the URI info, we have to obtain the data from our data store (can be e.g. a Database)
-3. Serialize the data  
-    The data has to be transformed into the required format
-4. Configure the response  
-    Since we are implementing a “processor”, the last step is to provide the response object
 
-These 4 steps will be considered in the implementation of the _readEntityCollection()_  method.
+  1. Check the URI  
+      We need to identify the requested resource and have to consider Query Options (if available)
+  2. Provide the data  
+      Based on the URI info, we have to obtain the data from our data store (can be e.g. a Database)
+  3. Serialize the data  
+      The data has to be transformed into the required format
+  4. Configure the response  
+      Since we are implementing a “processor”, the last step is to provide the response object
+
+These 4 steps will be considered in the implementation of the `readEntityCollection()` method.
 
 
 ### 4.2.1. Background
@@ -608,8 +607,8 @@ Example:
 In our example, we have stated in our metadata document that We will provide a list of “products” whenever the _EntitySet_ with name “Products” is invoked.  
 This means that the user of our OData service will append the _EntitySet_ name to the root URL of the service and then invoke the full URL.  
 This is http://localhost:8080/ExampleService1/ExampleServlet1.svc/Products
-So, whenever this URL is fired, Olingo will invoke the _EntityCollectionProcessor_ implementation of our OData service.
-Then our _EntityCollectionProcessor_ implementation is expected to provide a list of products.
+So, whenever this URL is fired, Olingo will invoke the `EntityCollectionProcessor` implementation of our OData service.
+Then our `EntityCollectionProcessor` implementation is expected to provide a list of products.
 
 As we have already mentioned, the metadata document is the contract for providing data.
 This means that when it comes to provide the actual data, we have to do it according to the specified metadata.  
@@ -618,7 +617,7 @@ For example, the property names have to
 
 ### 4.2.2. Create class
 
-Within our package _myservice.mynamespace.service_, we create a Java class _DemoEntityCollectionProcessor_  that implements the interface _org.apache.olingo.server.api.processor.EntityCollectionProcessor_.
+Within our package `myservice.mynamespace.service`, we create a Java class `DemoEntityCollectionProcessor`  that implements the interface `org.apache.olingo.server.api.processor.EntityCollectionProcessor`.
 
 ![createJavaClass](createJavaClass.png "The Eclipse dialog for creating a Java class")
 
@@ -657,11 +656,11 @@ Don’t forget to declare the member
 
 **_readEntityCollection()_**
 
-The _EntityCollectionProcessor_ exposes only one method:  
-_readEntityCollection()_  
-Here we have to understand that this _readEntityCollection_-method is invoked, when the OData service is called with an HTTP GET operation for an entity collection.
+The `EntityCollectionProcessor` exposes only one method: `readEntityCollection(...)`  
 
-The _readEntityCollection_ method is used to “read” the data in the backend (this can be e.g. a database) and to deliver it to the user who calls the OData service.
+Here we have to understand that this `readEntityCollection(...)`-method is invoked, when the OData service is called with an HTTP GET operation for an entity collection.
+
+The `readEntityCollection(...)` method is used to “read” the data in the backend (this can be e.g. a database) and to deliver it to the user who calls the OData service.
 
 The method signature:
 
@@ -671,19 +670,19 @@ With the second parameter, the “res
 
 The third parameter, the “uriInfo”, contains information about the relevant part of the URL. This means, the segments starting after the service name.  
 
-Example:  
+**Example:**  
 If the user calls the following URL:  
 `http://localhost:8080/DemoService/DemoService.svc/Products`  
-The _readEntityCollection_ method is invoked and the _uriInfo_ object contains one segment: “Products”  
+The `readEntityCollection(...)` method is invoked and the _uriInfo_ object contains one segment: “Products”  
 
 If the user calls the following URL:  
 `http://localhost:8080/DemoService/DemoService.svc/Products?$filter=ID eq 1`  
-Then the _readEntityCollection_ method is invoked and the _uriInfo_ contains the information about the entity set and furthermore the system query option $filter and its value.
+Then the `readEntityCollection(...)` method is invoked and the _uriInfo_ contains the information about the entity set and furthermore the system query option $filter and its value.
 
 The last parameter, the “responseFormat”, contains information about the content type that is requested by the user.  
 This means that the user has the choice to receive the data either in XML or in JSON.  
 
-Example:  
+**Example:**  
 If the user calls the following URL:  
 `http://localhost:8080/DemoService/DemoService.svc/Products?$format=application/json;odata.metadata=minimal`
 
@@ -700,97 +699,98 @@ In this case as well, our readEntityColl
 If the user doesn’t specify any content type, then the default is JSON.
 
 Why is this parameter needed?  
-Because the _readEntityCollection_ method is supposed to deliver the data in the format that is requested by the user. We will use this parameter when creating a serializer based on it.
+Because the `readEntityCollection(...)` method is supposed to deliver the data in the format that is requested by the user. We will use this parameter when creating a serializer based on it.
 
 
-The steps for implementating the method _readEntityCollection_ are:
+The steps for implementating the method `readEntityCollection(...)` are:
 
   1. Which data is requested?  
-  Usually, an OData service provides different _EntitySets_, so first it is required to identify which _EntitySet_ has been requested. This information can be retrieved from the _uriInfo_ object
+    Usually, an OData service provides different _EntitySets_, so first it is required to identify which _EntitySet_ has been requested. This information can be retrieved from the _uriInfo_ object.
 
   2. Fetch the data
-  As a developer of the OData service, you have to know how and where the data is stored. In many cases, this would be a database. At this point, you would connect to your database and fetch the requested data with an appropriate SQL statement. The data that is fetched from the data storage has to be put into an _EntitySet_ object.
-  Note that this object has to be of type _EntitySet_, not _EdmEntitySet_  
-  The package _org.apache.olingo.commons.api.data_ provides interfaces that describe the actual data, not the metadata.
+    As a developer of the OData service, you have to know how and where the data is stored. In many cases, this would be a database. At this point, you would connect to your database and fetch the requested data with an appropriate SQL statement. The data that is fetched from the data storage has to be put into an _EntityCollection_ object.
+    The package `org.apache.olingo.commons.api.data` provides interfaces that describe the actual data, not the metadata.
 
-    ![datapackage](datapackage.png "The package containing the interfaces for handling runtime data")
+      ![datapackage](datapackage.png "The package containing the interfaces for handling runtime data")
 
   3. Transform the data  
-  _Olingo_ expects us to provide the data as low-level _InputStream_ object. However, _Olingo_ supports us in doing so, by providing us with a proper "serializer".
-  So what we have to do is create the serializer based on the requested content type, configure it and call it.
+    _Olingo_ expects us to provide the data as low-level _InputStream_ object. However, _Olingo_ supports us in doing so, by providing us with a proper "serializer".
+    So what we have to do is create the serializer based on the requested content type, configure it and call it.
 
   4. Configure the response  
-  The response object has been passed to us in the method signature. We use it to set the serialized data (the _InputStream_ object).  
-  Furthermore, we have to set the HTTP status code, which means that we have the opportunity to do proper error handling.  
-  And finally we have to set the content type.  
+    The response object has been passed to us in the method signature. We use it to set the serialized data (the `InputStream` object).  
+    Furthermore, we have to set the HTTP status code, which means that we have the opportunity to do proper error handling.  
+    And finally we have to set the content type.  
 
 
-Sample:
+**Sample:**
 
     :::java
     public void readEntityCollection(ODataRequest request, ODataResponse response, UriInfo uriInfo, ContentType responseFormat)
-                         throws ODataApplicationException, SerializerException {
+        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 delivere as EntitySet
-    	EntitySet entitySet = getData(edmEntitySet);
-
-    	// 3rd: 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).build();
-    	InputStream serializedContent = serializer.entityCollection(edmEntityType, entitySet, opts);
-
-    	// 4th: 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());
-      }
+      // 1st we have retrieve the requested EntitySet from the uriInfo object (representation of the parsed service URI)
+      List<UriResource> resourcePaths = uriInfo.getUriResourceParts();
+      UriResourceEntitySet uriResourceEntitySet = (UriResourceEntitySet) resourcePaths.get(0); // in our example, the first segment is the EntitySet
+      EdmEntitySet edmEntitySet = uriResourceEntitySet.getEntitySet();
+
+      // 2nd: fetch the data from backend for this requested EntitySetName
+      // it has to be delivered as EntitySet object
+      EntityCollection entitySet = getData(edmEntitySet);
+
+      // 3rd: create a serializer based on the requested format (json)
+      ODataFormat format = ODataFormat.fromContentType(responseFormat);
+      ODataSerializer serializer = odata.createSerializer(format);
+
+      // 4th: Now 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).build();
+      SerializerResult serializedContent = serializer.entityCollection(serviceMetadata, edmEntityType, entitySet, opts);
+
+      // Finally: configure the response object: set the body, headers and status code
+      response.setContent(serializedContent.getContent());
+      response.setStatusCode(HttpStatusCode.OK.getStatusCode());
+      response.setHeader(HttpHeader.CONTENT_TYPE, responseFormat.toContentTypeString());
+    }
 
 
 **_getData()_**
 
 We have not elaborated on fetching the actual data.
 In our tutorial, to keep the code as simple as possible, we use a little helper method that delivers some hardcoded entries.  
-Since we are supposed to deliver the data inside an _EntitySet_ instance, we create the instance, ask it for the (initially empty) list of entities and add some new entities to it.  
-We create the entities and their properties according to what we declared in our _ExampleEdmProvider_ class. So we have to take care to provide the correct names to the new property objects.
+Since we are supposed to deliver the data inside an `EntityCollection` instance, we create the instance, ask it for the (initially empty) list of entities and add some new entities to it.  
+We create the entities and their properties according to what we declared in our `DemoEdmProvider` class. So we have to take care to provide the correct names to the new property objects.
 
 
     :::java
-    private EntitySet getData(EdmEntitySet edmEntitySet){
+    private EntityCollection getData(EdmEntitySet edmEntitySet){
 
-    	EntitySet entitySet = new EntitySetImpl();
-    	List<Entity> entityList = entitySet.getEntities();
+      EntityCollection entityCollection = new EntityCollection();
+      // check for which EdmEntitySet the data is requested
+      if(DemoEdmProvider.ES_PRODUCTS_NAME.equals(edmEntitySet.getName())) {
+        List<Entity> entityList = entityCollection.getEntities();
 
-    	// add some sample product entities
-    	entityList.add(new EntityImpl()
-    		.addProperty(new PropertyImpl(null, "ID", ValueType.PRIMITIVE, 1))
-    		.addProperty(new PropertyImpl(null, "Name", ValueType.PRIMITIVE, "Notebook Basic 15"))
-    		.addProperty(new PropertyImpl(null, "Description", ValueType.PRIMITIVE, "Notebook Basic, 1.7GHz - 15 XGA - 1024MB DDR2 SDRAM - 40GB")));
-    	entityList.add(new EntityImpl()
-    		.addProperty(new PropertyImpl(null, "ID", ValueType.PRIMITIVE, 2))
-    		.addProperty(new PropertyImpl(null, "Name", ValueType.PRIMITIVE, "1UMTS PDA"))
-    		.addProperty(new PropertyImpl(null, "Description", ValueType.PRIMITIVE, "Ultrafast 3G UMTS/HSDPA Pocket PC, supports GSM network")));
+        // add some sample product entities
+        entityList.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")));
 
-    	entityList.add(new EntityImpl()
-    		.addProperty(new PropertyImpl(null, "ID", ValueType.PRIMITIVE, 3))
-    		.addProperty(new PropertyImpl(null, "Name", ValueType.PRIMITIVE, "Ergo Screen"))
-    		.addProperty(new PropertyImpl(null, "Description", ValueType.PRIMITIVE, "17 Optimum Resolution 1024 x 768 @ 85Hz, resolution 1280 x 960")));
+        entityList.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")));
 
-    	return entitySet;
-    }
+        entityList.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, "17 Optimum Resolution 1024 x 768 @ 85Hz, resolution 1280 x 960")));
+      }
 
+      return entityCollection;
+    }
 
 
 ## 4.3. Web Application
@@ -809,12 +809,12 @@ Let’s quickly do the remaining step
 ### 4.3.1. Create and implement the Servlet
 
 Create a new package _myservice.mynamespace.web_.
-Create Java class with name _DemoServlet_ that inherits from _HttpServlet_.
+Create Java class with name `DemoServlet` that inherits from `HttpServlet`.
 
 ![createJavaServletClass](createJavaServletClass.png "Creating the servlet class")
 
 Override the `service()` method.  
-Basically, what we are doing here is to create an _ODataHttpHandler_, which is a class that is provided by _Olingo_.
+Basically, what we are doing here is to create an `ODataHttpHandler`, which is a class that is provided by _Olingo_.
 It receives the user request and if the URL conforms to the OData specification, the request is delegated to the processor implementation of the OData service.
 This means that the handler has to be configured with all processor implementations that have been created along with the OData service (in our example, only one processor).
 Furthermore, the `ODataHttpHandler` needs to carry the knowledge about the `EdmProvider`.
@@ -823,32 +823,29 @@ This is where our two implemented classe
 
 
     :::java
-    // This class represents a standard HttpServlet implementation.
-    // It is used as main entry point for the web application that carries the OData service.
-    // The implementation of this HttpServlet simply delegates the user requests to the ODataHttpHandler
     public class DemoServlet extends HttpServlet {
 
-    	private static final long serialVersionUID = 1L;
-    	private static final Logger LOG = LoggerFactory.getLogger(DemoServlet.class);
+      private static final long serialVersionUID = 1L;
+      private static final Logger LOG = LoggerFactory.getLogger(DemoServlet.class);
 
-    	@Override
-    	protected void service(final HttpServletRequest req, final HttpServletResponse resp) throws ServletException, IOException {
+      @Override
+      protected void service(final HttpServletRequest req, final HttpServletResponse resp) throws ServletException, IOException {
 
-    		try {
-    			// create odata handler and configure it with EdmProvider and Processor
-    			OData odata = OData.newInstance();
-    			ServiceMetadata edm = odata.createServiceMetadata(new ExampleEdmProvider(), new ArrayList<EdmxReference>());
-    			ODataHttpHandler handler = odata.createHandler(edm);
-    			handler.register(new DemoEntityCollectionProcessor());
-
-    			// let the handler do the work
-    			handler.process(req, resp);
-
-    		} catch (RuntimeException e) {
-    			LOG.error("Server Error ocurred in DemoServlet", e);
-    			throw new ServletException(e);
-    		}
-    	}
+        try {
+          // 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());
+
+          // 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);
+        }
+      }
     }
 
 
@@ -1008,13 +1005,13 @@ The project as final result can be downl
 
 Further topics to be covered by follow-up tutorials:  
 
-  * READ scenario: reading single entity, reading property  
-  * WRITE scenario: executing POST, PUT, PATCH and DELETE requests  
-  * Navigation: navigating from one entity to a corresponding second entity
-  * Data types
+  * Tutorial OData V4 service part 2: [Read Entity, Read Property (this page)](/doc/odata4/tutorials/readep/tutorial_readep.html) | [sample project zip](/doc/odata4/tutorials/readep/sample/DemoService_Tutorial_Readep.zip)  
+  * Tutorial OData V4 service part 3: [Write (Create, Update, Delete Entity)](/doc/odata4/tutorials/write/tutorial_write.html) | [sample project zip](/doc/odata4/tutorials/write/sample/DemoService_Tutorial_Write.zip)  
+  * Work in progress: Tutorial OData V4 service part 4: [Navigation](/doc/odata4/index.html) | [sample project zip](/doc/odata4/index.html)  
+  * Work in progress: Tutorial OData V4 service part 5: [System Query Options](/doc/odata4/index.html) | [sample project zip](/doc/odata4/index.html)  
 
 
 **Further reading**
 
 OData specification: <http://odata.org/>  
-Olingo Javadoc: <http://olingo.apache.org/javadoc/odata4/index.html>
+Olingo Javadoc: [http://olingo.apache.org/javadoc/odata4/index.html](/javadoc/odata4/index.html)