olingo-commits mailing list archives

Site index · List index
Message view « Date » · « Thread »
Top « Date » · « Thread »
From m...@apache.org
Subject svn commit: r1680207 - in /olingo/site/trunk/content/doc/odata4/tutorials/write: ./ tutorial_write.mdtext
Date Tue, 19 May 2015 09:19:55 GMT
Author: mibo
Date: Tue May 19 09:19:54 2015
New Revision: 1680207

URL: http://svn.apache.org/r1680207
Log:
Part 3: Write

Added:
    olingo/site/trunk/content/doc/odata4/tutorials/write/
    olingo/site/trunk/content/doc/odata4/tutorials/write/tutorial_write.mdtext

Added: olingo/site/trunk/content/doc/odata4/tutorials/write/tutorial_write.mdtext
URL: http://svn.apache.org/viewvc/olingo/site/trunk/content/doc/odata4/tutorials/write/tutorial_write.mdtext?rev=1680207&view=auto
==============================================================================
--- olingo/site/trunk/content/doc/odata4/tutorials/write/tutorial_write.mdtext (added)
+++ olingo/site/trunk/content/doc/odata4/tutorials/write/tutorial_write.mdtext Tue May 19
09:19:54 2015
@@ -0,0 +1,390 @@
+Title:    Tutorial - Write service with Olingo V4
+Notice:    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.
+
+# How to build an OData Service with Olingo V4
+
+# Part 3: Write operations
+
+## Introduction
+
+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](/doc/odata4/download.html)).
+
+In the first two tutorials ([Read Collection](/doc/odata4/tutorials/read/tutorial_read.html)
and [Read Entity](/doc/odata4/tutorials/readep/tutorial_readep.html)), we’ve learned
how to build a simple OData service that supports read operations for collection, single entity
and property.
+
+In the present tutorial, will cover the write operations, which means creating an entity,
modifying an existing entity and deleting an existing entity.
+
+Note:  
+The full implementation of the OData service as described in the present tutorial can be
found in the [attached zip file](/doc/odata4/tutorials/write/sample/DemoService_Tutorial_Write.zip)
([md5](/doc/odata4/tutorials/write/sample/DemoService_Tutorial_Write.zip.md5), [sha512](/doc/odata4/tutorials/write/sample/DemoService_Tutorial_Write.zip.sha512),
[pgp](/doc/odata4/tutorials/write/sample/DemoService_Tutorial_Write.zip.asc)) that contains
an Eclipse project that can be imported into your Eclipse workspace.
+
+Disclaimer:
+Again, in the present tutorial, will focus only on the relevant implementation, in order
to keep the code small and simple.
+The sample code shouldn't be reused for advanced scenarios.
+
+---
+
+# 1. Prerequisites
+
+Same prerequisites as in [Tutorial Part 1: Read Entity Collection](http://olingo.apache.org/doc/odata4/tutorials/read/tutorial_read.html)
and [Tutorial Part 2: Read Entity](http://olingo.apache.org/doc/odata4/tutorials/readep/tutorial_readep.html)
as well as basic knowledge about the concepts presented in both tutorials.
+
+---
+
+# 2. Preparation
+
+Follow [Tutorial Part 1: Read Entity Collection](http://olingo.apache.org/doc/odata4/tutorials/read/tutorial_read.html)
and [Tutorial Part 2: Read Entity](http://olingo.apache.org/doc/odata4/tutorials/readep/tutorial_readep.html)
or as shortcut import the project attached to *Tutorial Part 2* into your Eclipse workspace.
+
+Afterwards do a *Deploy and run*: it should be working.
+
+---
+
+# 3. Implementation
+
+In our sample scenario, we want to create a product, to be added to the list of available
products that we maintain in our database-mock.
+This product that we want to create will have a name and a description that the user of our
service will specify in his HTTP request.
+The Olingo library takes this user request, serializes the request body and invokes the corresponding
method of our processor class.
+
+In the previous tutorial 2, we’ve already implemented the `EntityProcessor` interface
and registered our class in the servlet, but we have not written the implementation for the
callback methods that are responsible for the write operations.
+This is what we are going to do in the below sections.
+
+## 3.1. Implement the createEntity(...) method
+
+Open the class `myservice.mynamespace.service.DemoEntityProcessor`  
+Go to the method `createEntity(...)`  
+The method body should be empty, otherwise delete any content.
+
+**Now, how to implement the method?**  
+Basically, we have to do the same that we did in the `readEntity(...)` method, but the other
way ‘round.  
+In the `createEntity(...)` method, we have to retrieve the payload from the request and then
write it to our mock-database.  
+Furthermore, we have to return the created entity in the response payload.
+
+Again, we can divide our work into 4 steps:
+
+  1. Analyze the URI
+  1. Handle data in backend
+  1. Serialize
+  1. Configure the response
+
+
+**In detail**
+
+We have to keep in mind that -for creation - the URL that is executed in our example is the
following:
+
+    http://localhost:8080/DemoService/DemoService.svc/Products
+
+It is executed as POST request and contains a request body which looks as follows:
+
+    :::json
+    {
+      "ID":4,
+      "Name":"Gamer Mouse",
+      "Description":"optical mouse - gamer edition"
+    }
+
+
+**Steps**
+
+  1. In the implementation, we have to first retrieve the `EntityCollection` and `EntityType`
metadata from the `UriInfo` object.
+  1. The next step is to create the data in our backend.  
+  For this purpose, we have to retrieve the data from the HTTP request payload.  
+  We get the payload from the `ODataRequest` instance as `InputStream`, which can then be
deserialized.
+  Our `Storage` class is responsible for creating the new product in the backend.
+  And for returning the newly created instance.  
+  The reason is that our OData service has to return the newly created entity in the response
body.  
+  1. From now on the procedure is the same like in the `readEntity(...)` method
+  1. The only difference is the status code, that has to be set to **201 - created** in case
of success
+
+Please find below the sample code for the *createEntity()* method
+
+    :::java
+    public void createEntity(ODataRequest request, ODataResponse response, UriInfo uriInfo,
+         ContentType requestFormat, ContentType responseFormat)
+        throws ODataApplicationException, DeserializerException, SerializerException {
+
+      // 1. Retrieve the entity type from the URI
+      EdmEntitySet edmEntitySet = Util.getEdmEntitySet(uriInfo);
+      EdmEntityType edmEntityType = edmEntitySet.getEntityType();
+
+      // 2. create the data in backend
+      // 2.1. retrieve the payload from the POST request for the entity to create and deserialize
it
+      InputStream requestInputStream = request.getBody();
+      ODataFormat requestODataFormat = ODataFormat.fromContentType(requestFormat);
+      ODataDeserializer deserializer = this.odata.createDeserializer(requestODataFormat);
+      DeserializerResult result = deserializer.entity(requestInputStream, edmEntityType);
+      Entity requestEntity = result.getEntity();
+      // 2.2 do the creation in backend, which returns the newly created entity
+      Entity createdEntity = storage.createEntityData(edmEntitySet, requestEntity);
+
+      // 3. serialize the response (we have to return the created entity)
+      ContextURL contextUrl = ContextURL.with().entitySet(edmEntitySet).build();
+        // 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 serializedResponse = serializer.entity(serviceMetadata, edmEntityType,
createdEntity, options);
+
+      //4. configure the response object
+      response.setContent(serializedResponse.getContent());
+      response.setStatusCode(HttpStatusCode.CREATED.getStatusCode());
+      response.setHeader(HttpHeader.CONTENT_TYPE, responseFormat.toContentTypeString());
+    }
+
+
+
+
+## 3.2. Implement the updateEntity(...) method
+
+Example URL
+
+    http://localhost:8080/DemoService/DemoService.svc/Products(3)
+
+Example request body:
+
+    :::json
+    {
+      "ID":3,
+      "Name":"Ergo Screen updated Name",
+      "Description":"updated description"
+    }
+
+
+The `updateEntity(...)` method is similar.  
+Again, we have to retrieve the payload from the HTTP request and use it for modifying the
data in backend.
+The difference is that case of update operation, the OData service is not expected to return
any response payload. So we can skip the serialize-step and simply set the HTTP status code
to **204 – no content**
+
+    :::java
+    public void updateEntity(ODataRequest request, ODataResponse response, UriInfo uriInfo,
+    ContentType requestFormat, ContentType responseFormat)
+        throws ODataApplicationException, DeserializerException, SerializerException {
+
+      // 1. Retrieve the entity set which belongs to the requested entity
+      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();
+      EdmEntityType edmEntityType = edmEntitySet.getEntityType();
+
+      // 2. update the data in backend
+      // 2.1. retrieve the payload from the PUT request for the entity to be updated
+      InputStream requestInputStream = request.getBody();
+      ODataFormat requestODataFormat = ODataFormat.fromContentType(requestFormat);
+      ODataDeserializer deserializer = this.odata.createDeserializer(requestODataFormat);
+      DeserializerResult result = deserializer.entity(requestInputStream, edmEntityType);
+      Entity requestEntity = result.getEntity();
+      // 2.2 do the modification in backend
+      List<UriParameter> keyPredicates = uriResourceEntitySet.getKeyPredicates();
+      // Note that this updateEntity()-method is invoked for both PUT or PATCH operations
+      HttpMethod httpMethod = request.getMethod();
+      storage.updateEntityData(edmEntitySet, keyPredicates, requestEntity, httpMethod);
+
+      //3. configure the response object
+      response.setStatusCode(HttpStatusCode.NO_CONTENT.getStatusCode());
+    }
+
+
+In case of update, we have to consider the following:  
+The update of an entity can be realized in 2 ways: either a **PATCH** or a **PUT** request.
 
+(See the online specification in section [11.4.3 Update an Entity](http://docs.oasis-open.org/odata/odata/v4.0/odata-v4.0-part1-protocol.html)
for more details.
+For both HTTP methods, our `updateEntity(...)` will be invoked.  
+But we have to treat the data-modification differently.  
+Therefore, we have to first retrieve the used HTTP method and in the backend-logic, we have
to distinguish between **PATCH** and **PUT**.  
+The difference becomes relevant only in case if the user doesn’t send all the properties
in the request body.  
+
+Example: if we modify the above example request body to look as follows:  
+
+    :::json
+    {
+      "Description":"updated description"
+    }
+
+
+Note that in this case, only one of three properties is sent in the request body.
+
+  - If the HTTP method is **PATCH**:  
+    The value of the *Description* property is updated in the backend.  
+    The values of the other properties remain untouched.
+  - If the HTTP method is **PUT**:  
+    The value of the *Description* property is updated in the backend.  
+    The value of the other properties is set to null (exception: key properties can never
be null).  
+
+
+So let’s have a look at our sample implementation in the `Storage` class (see below
for full sample code and also see the attached zip file containing the whole sample project)
+
+    :::java
+    private void updateProduct(EdmEntityType edmEntityType, List<UriParameter> keyParams,
Entity entity, HttpMethod httpMethod)
+                                throws ODataApplicationException{
+
+      Entity productEntity = getProduct(edmEntityType, keyParams);
+      if(productEntity == null){
+        throw new ODataApplicationException("Entity not found",
+                            HttpStatusCode.NOT_FOUND.getStatusCode(), Locale.ENGLISH);
+      }
+
+      // loop over all properties and replace the values with the values of the given payload
+      // Note: ignoring ComplexType, as we don't have it in our odata model
+      List<Property> existingProperties = productEntity.getProperties();
+      for(Property existingProp : existingProperties){
+        String propName = existingProp.getName();
+
+        // ignore the key properties, they aren't updateable
+        if(isKey(edmEntityType, propName)){
+          continue;
+        }
+
+        Property updateProperty = entity.getProperty(propName);
+        // the request payload might not consider ALL properties, so it can be null
+        if(updateProperty == null){
+          // if a property has NOT been added to the request payload
+          // depending on the HttpMethod, our behavior is different
+          if(httpMethod.equals(HttpMethod.PATCH)){
+            // in case of PATCH, the existing property is not touched
+            continue; // do nothing
+          }else if(httpMethod.equals(HttpMethod.PUT)){
+            // in case of PUT, the existing property is set to null
+            existingProp.setValue(existingProp.getValueType(), null);
+            continue;
+          }
+        }
+
+        // change the value of the properties
+        existingProp.setValue(existingProp.getValueType(), updateProperty.getValue());
+      }
+    }
+
+
+## 3.3. Implement the deleteEntity(...) method
+
+In case of **DELETE** operation, the URL is the same like for the **GET** operation, but
the request body is empty.
+
+Example URL:
+
+    http://localhost:8080/DemoService/DemoService.svc/Products(3)
+
+The implementation is rather simple:  
+
+  - As usual, determine the entity set.  
+  - Delete the data in backend.  
+  - Configure the response object with the proper status code **204 – no content**.
 
+
+        :::java
+        public void deleteEntity(ODataRequest request, ODataResponse response, UriInfo uriInfo)
+                                throws ODataApplicationException {
+
+          // 1. Retrieve the entity set which belongs to the requested entity
+          List<UriResource> resourcePaths = uriInfo.getUriResourceParts();
+          // Note: only in our example we can assume that the first segment is the EntitySet
+          UriResourceEntitySet uriResourceEntitySet = (UriResourceEntitySet) resourcePaths.get(0);
+          EdmEntitySet edmEntitySet = uriResourceEntitySet.getEntitySet();
+
+          // 2. delete the data in backend
+          List<UriParameter> keyPredicates = uriResourceEntitySet.getKeyPredicates();
+          storage.deleteEntityData(edmEntitySet, keyPredicates);
+
+          //3. configure the response object
+          response.setStatusCode(HttpStatusCode.NO_CONTENT.getStatusCode());
+        }
+
+
+
+## 3.4. Run the service
+
+After building and deploying the project, we can invoke our OData service.
+
+In order to test the write operations of our OData service, we need a tool that is able to
execute the following required HTTP requests: **POST**, **PUT**, **PATCH**, **DELETE**  
+This is usually done with any REST client tool that can be installed into the browser of
your choice.  
+
+Examples:  
+    - Firefox: “RESTClient, a debugger for RESTful web services”  
+    - Chrome: “Advanced REST client”  
+
+The following sections provide examples for executing the requests:
+
+### 3.4.1. Example for **CREATE**:
+
+  - URL: <http://localhost:8080/DemoService/DemoService.svc/Products>  
+  - HTTP verb: **POST**
+  - Header: `Content-Type: application/json; odata.metadata=minimal`  
+  - Request body:  
+
+        :::json
+        {  
+          "ID":6,  
+          "Name":"Gamer Mouse",  
+          "Description":"optical mouse - gamer edition"  
+        }
+
+
+Note:
+The value for the ID property is arbitrary, as it will be generated by our OData service
implementation
+
+
+### 3.4.2. Example for UPDATE (PUT):
+
+  - URL: <http://localhost:8080/DemoService/DemoService.svc/Products(3)>  
+  - HTTP verb: **PUT**
+  - Header: `Content-Type: application/json; odata.metadata=minimal`  
+  - Request body:  
+
+        :::json
+        {  
+          "ID":3,  
+          "Name":"Ergo Screen updated Name",  
+          "Description":"updated description"  
+        }
+
+
+
+### 3.4.3. Example for UPDATE (PATCH):
+
+  - URL: <http://localhost:8080/DemoService/DemoService.svc/Products(3)>  
+  - HTTP verb: **PATCH**  
+  - Header: `Content-Type: application/json; odata.metadata=minimal`  
+  - Request body:  
+
+        :::json
+        {  
+          "Description": "patched description"  
+        }  
+
+
+###3.4.4. Example for DELETE:
+
+  - URL: <http://localhost:8080/DemoService/DemoService.svc/Products(3)>  
+  - HTTP verb: **DELETE**  
+  - Header: Content-Type: application/json; odata.metadata=minimal  
+  - Request body:  `<empty>`
+
+---
+
+# 4. Summary
+
+In this tutorial we have learned how to implement the creation, update and deletion of an
entity.  
+It has been based on a simple OData model, focusing on simple sample code and sample data.
 
+
+In the next tutorial (Part 4: Navigation) we will learn how to implement navigation, i.e.
the linking of resources.
+
+---
+
+# 5. Links
+
+Tutorial OData V4 service part 1: [Read Entity Collection](/doc/odata4/tutorials/read/tutorial_read.html)
| [sample project zip](/doc/odata4/tutorials/read/sample/DemoService_Tutorial_Read.zip)  
+Tutorial OData V4 service part 2: [Read Entity, Read Property](/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) - (this page)](/doc/odata4/tutorials/write/tutorial_write.html)
| [sample project zip](/doc/odata4/tutorials/write/sample/DemoService_Tutorial_Write.zip)
 
+Tutorial OData V4 service, part 4: [Navigation - (To Be Announced)](...)
+
+OData specification: <http://odata.org/>
+Olingo Javadoc: <http://olingo.apache.org/javadoc/odata4/index.html>



Mime
View raw message