Author: chrish
Date: Tue Oct 13 10:37:14 2015
New Revision: 1708321

URL: http://svn.apache.org/viewvc?rev=1708321&view=rev
Log:
CMS commit to olingo by chrish

Added:
    olingo/site/trunk/content/doc/odata4/tutorials/media/tutorial_media.mdtext  
 (with props)

Added: 
olingo/site/trunk/content/doc/odata4/tutorials/media/tutorial_media.mdtext
URL: 
http://svn.apache.org/viewvc/olingo/site/trunk/content/doc/odata4/tutorials/media/tutorial_media.mdtext?rev=1708321&view=auto
==============================================================================
--- olingo/site/trunk/content/doc/odata4/tutorials/media/tutorial_media.mdtext 
(added)
+++ olingo/site/trunk/content/doc/odata4/tutorials/media/tutorial_media.mdtext 
Tue Oct 13 10:37:14 2015
@@ -0,0 +1,378 @@
+Title:
+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 7: Media Entities
+
+## Introduction
+
+
+In the present tutorial, we’ll implement a function import and an action 
import as well.
+
+**Note:**
+The final source code can be found in the project [git 
repository](https://git-wip-us.apache.org/repos/asf/olingo-odata4).
+A detailed description how to checkout the tutorials can be found 
[here](/doc/odata4/tutorials/prerequisites/prerequisites.html).   
+This tutorial can be found in subdirectory /samples/tutorials/p10_media
+
+
+**Table of Contents**
+
+   1. Introduction
+   2. Preparation
+   3. Implementation
+   4. Run the implemented service
+   5. Links
+
+## Preparation
+
+You should read the previous tutorials first to have an idea how to read 
entities and entity collections. In addition the following code is based on the 
write tutorial merged with the navigation tutorial.
+
+As a shortcut you should checkout the prepared tutorial project in the git 
repository in folder /samples/tutorials/p9_action_preparation.
+
+Afterwards do a Deploy and run: it should be working. At this state you can 
perform CRUD operations and do navigations between products and categories.
+
+## Implementation
+
+In this tutorial we will implement a media entity set. The idea is to store 
advertisments and a related image. The metadata document have to be extended by 
the following elements:
+
+       ::::xml
+       <EntityType Name="Advertisment" HasStream="true">
+        <Key>
+            <PropertyRef Name="ID"/>
+        </Key>
+        <Property Name="ID" Type="Edm.Guid"/>
+        <Property Name="Name" Type="Edm.String"/>
+        <Property Name="AirDate" Type="Edm.DateTimeOffset"/>
+    </EntityType>
+
+       <EntityContainer Name="Container">
+        <EntitySet Name="Advertisments" EntityType="OData.Demo.Advertisment"/>
+    </EntityContainer>
+
+As you can see, the XML tag `EntityType` has a property `HasStream`, which 
tells us that this entity has an associated media stream. Such an Entity 
consists of common properties like *ID* and *Name* and the media stream.
+
+**Tasks**
+
+ * Extend the metadata document
+ * Enable the data store to handle media entities
+ * Implement the interface `MediaEntityProcessor`
+
+### Extend the metadata document
+
+If you have read the prevois tutorials, you should be familiar with the 
definition entity types. The only difference to regular (Non media enties) is, 
that they have a `hasStream` Property. If this property is not provided it 
defaults to false. So add the following code to class `DemoEdmProvider`:
+
+We start with method `DemoEdmProvider.getEntityType`
+
+       ::::java
+       public CsdlEntityType getEntityType(FullQualifiedName entityTypeName) {
+               CsdlEntityType entityType = null;
+
+               if (entityTypeName.equals(ET_PRODUCT_FQN)) {
+                       // Definition of entity type Product
+                       // ...
+               } else if (entityTypeName.equals(ET_CATEGORY_FQN)) {
+                       // Definition of entity type Category
+                       // ...
+               } else if(entityTypeName.equals(ET_ADVERTISMENT_FQN)) {
+                       CsdlProperty id = new CsdlProperty().setName("ID")
+                                                                               
          .setType(EdmPrimitiveTypeKind.Guid.getFullQualifiedName());
+                       CsdlProperty name = new CsdlProperty().setName("Name")
+                                                                               
          .setType(EdmPrimitiveTypeKind.String.getFullQualifiedName());
+                       CsdlProperty airDate = new 
CsdlProperty().setName("AirDate")
+                                                                               
                    
.setType(EdmPrimitiveTypeKind.DateTimeOffset.getFullQualifiedName());
+
+                       CsdlPropertyRef propertyRef = new CsdlPropertyRef();
+                       propertyRef.setName("ID");
+
+                       entityType = new CsdlEntityType();
+                       entityType.setName(ET_ADVERTISMENT_NAME);
+                       entityType.setProperties(Arrays.asList(id, name, 
airDate));
+                       
entityType.setKey(Collections.singletonList(propertyRef));
+                       entityType.setHasStream(true);  // <- Enable the media 
entity stream
+               }
+
+               return entityType;
+       }
+
+Further a have to create a new entity set. Add the following snipped to 
`DemoEdmProvider.getEntitySet`
+
+       @Override
+       public CsdlEntitySet getEntitySet(FullQualifiedName entityContainer, 
String entitySetName) {
+               CsdlEntitySet entitySet = null;
+
+               if (entityContainer.equals(CONTAINER)) {
+                       if (entitySetName.equals(ES_PRODUCTS_NAME)) {
+                               // Definition of entity set Products
+                       } else if (entitySetName.equals(ES_CATEGORIES_NAME)) {
+                               // Definition if entity set Categories
+                       } else if (entitySetName.equals(ES_ADVERTISMENTS_NAME)) 
{
+                               entitySet = new CsdlEntitySet();
+                               entitySet.setName(ES_ADVERTISMENTS_NAME);
+                               entitySet.setType(ET_ADVERTISMENT_FQN);
+                       }
+               }
+
+               return entitySet;
+       }
+
+And finally announce the entity type and entity set:
+
+       @Override
+       public List<CsdlSchema> getSchemas() {
+
+               // ...
+               entityTypes.add(getEntityType(ET_ADVERTISMENT_FQN));
+               // ...
+
+               return schemas;
+       }
+       
+       public CsdlEntityContainer getEntityContainer() {
+               // ...
+               entitySets.add(getEntitySet(CONTAINER, ES_ADVERTISMENTS_NAME));
+       }
+
+### Enable the data store to handle media entities
+
+In this tutorial, we will keep things simple. To store the value of media 
entities, we create a special property *$value*. Note this is not a valid OData 
Identifier.
+
+To read the content to a media entity, we simple return the value of the 
property *$value*.
+       ::::java
+        private static final String MEDIA_PROPERTY_NAME = "$value";
+
+       public byte[] readMedia(final Entity entity) {
+               return (byte[]) 
entity.getProperty(MEDIA_PROPERTY_NAME).asPrimitive();
+       }
+
+If we update the content of a media entity, we must also the the Content Type 
of the content.  
+
+       ::::java
+       public void updateMedia(final Entity entity, final String 
mediaContentType, final byte[] data) {
+               
entity.getProperties().remove(entity.getProperty(MEDIA_PROPERTY_NAME));
+               entity.addProperty(new Property(null, MEDIA_PROPERTY_NAME, 
ValueType.PRIMITIVE, data));
+               entity.setMediaContentType(mediaContentType);
+       }
+
+If a client creates a new media entity, the body of the requet contains the 
content of the media entity instead the regualr properties! So the other 
regular properties defaults to `null`. The Content Type of the  media content 
must also be set up.
+
+       ::::java
+       public Entity createMediaEntity(final EdmEntityType edmEntityType, 
final String mediaContentType, final byte[] data) {
+               Entity entity = null;
+
+               
if(edmEntityType.getName().equals(DemoEdmProvider.ET_ADVERTISMENT_NAME)) {
+                       entity = new Entity();
+                       entity.addProperty(new Property(null, "ID", 
ValueType.PRIMITIVE, UUID.randomUUID()));
+                       entity.addProperty(new Property(null, "Name", 
ValueType.PRIMITIVE, null));
+                       entity.addProperty(new Property(null, "AirDate", 
ValueType.PRIMITIVE, null));
+
+                       entity.setMediaContentType(mediaContentType);
+                       entity.addProperty(new Property(null, 
MEDIA_PROPERTY_NAME, ValueType.PRIMITIVE, data));
+
+                       advertisments.add(entity);
+               }
+
+               return entity;
+       }
+
+### Implement the interface `MediaEntityProcessor`
+
+As you can see the 
[`MediaEntityProcessor`](http://olingo.apache.org/javadoc/odata4/org/apache/olingo/server/api/processor/MediaEntityProcessor.html)
 extends 
[`EntityProcessor`](http://olingo.apache.org/javadoc/odata4/org/apache/olingo/server/api/processor/EntityProcessor.html),
 therefore we will implement `MediaEntityProcessor` in class 
`DemoEntityProcessor`.
+
+The easiest part is to delete an media entity. The method `deleteMediaEntity` 
is delegated to the method `deleteEntity(...)`.
+
+       ::::java
+       @Override
+       public void deleteMediaEntity(ODataRequest request, ODataResponse 
response, UriInfo uriInfo)
+                       throws ODataApplicationException, ODataLibraryException 
{
+
+               deleteEntity(request, response, uriInfo);
+       }
+
+Next implement the creation of media entites. First we fetch the addressed 
entity set and convert the body of the request to a byte array. Remember the 
whole body of the request contains the content of the media entity.
+
+       ::::java
+       @Override
+       public void createMediaEntity(ODataRequest request, ODataResponse 
response, UriInfo uriInfo,
+                       ContentType requestFormat, ContentType responseFormat)
+                       throws ODataApplicationException, ODataLibraryException 
{
+
+               final EdmEntitySet edmEntitySet = Util.getEdmEntitySet(uriInfo);
+               final byte[] mediaContent = 
odata.createFixedFormatDeserializer().binary(request.getBody());
+               ///...
+
+After that we call the data store to create the new media entity. The [OData 
Specification](http://docs.oasis-open.org/odata/odata/v4.0/errata02/os/complete/part1-protocol/odata-v4.0-errata02-os-part1-protocol-complete.html#_Toc406398337)
 tells us, that we have to set the location header to the edit URL of the 
entity. Since we do not support Prefer Headers we have to return the entity 
itself.
+
+       :::java
+               final Entity entity = 
storage.createMediaEntity(edmEntitySet.getEntityType(),
+                                                                               
                                requestFormat.toContentTypeString(),
+                                                                               
                                mediaContent);
+
+               final ContextURL contextUrl = 
ContextURL.with().entitySet(edmEntitySet).suffix(Suffix.ENTITY).build();
+               final EntitySerializerOptions opts = 
EntitySerializerOptions.with().contextURL(contextUrl).build();
+               final SerializerResult serializerResult = 
odata.createSerializer(responseFormat)
+                                                                          
.entity(serviceMetadata, edmEntitySet.getEntityType(), entity, opts);
+
+               final String location = request.getRawBaseUri() + '/' 
+                                                                       + 
odata.createUriHelper().buildCanonicalURL(edmEntitySet, entity);
+
+               response.setContent(serializerResult.getContent());
+               response.setStatusCode(HttpStatusCode.CREATED.getStatusCode());
+               response.setHeader(HttpHeader.LOCATION, location);
+               response.setHeader(HttpHeader.CONTENT_TYPE, 
responseFormat.toContentTypeString());
+       }
+
+To keep things simple, our scenario do not support navigation to media 
entities. Because of this, the implementation to read a media entity is quite 
simple. First analayse the URI and fetch the entity. Than take the content of 
our specical property, serialize them and return the serialized content. The 
serializer converts the byte array to an `InputStream`.
+
+       ::::java
+       @Override
+       public void readMediaEntity(ODataRequest request, ODataResponse 
response, UriInfo uriInfo, ContentType responseFormat)
+                       throws ODataApplicationException, ODataLibraryException 
{
+
+               // Since our scenario do not contain navigations from media 
entities. We can keep things simple and
+               // check only the first resource path of the URI.
+               final UriResource firstResoucePart = 
uriInfo.getUriResourceParts().get(0);
+               if(firstResoucePart instanceof UriResourceEntitySet) {
+                       final EdmEntitySet edmEntitySet = 
Util.getEdmEntitySet(uriInfo);
+                       final UriResourceEntitySet uriResourceEntitySet = 
(UriResourceEntitySet) firstResoucePart;
+
+                       final Entity entity = 
storage.readEntityData(edmEntitySet, uriResourceEntitySet.getKeyPredicates());
+                       if(entity == null) {
+                       throw new ODataApplicationException("Entity not found",
+                                                               
HttpStatusCode.NOT_FOUND.getStatusCode(), Locale.ENGLISH);
+                       }
+
+                       final byte[] mediaContent = storage.readMedia(entity);
+                       final InputStream responseContent = 
odata.createFixedFormatSerializer().binary(mediaContent);
+
+                       
response.setStatusCode(HttpStatusCode.OK.getStatusCode());
+                       response.setContent(responseContent);
+                       response.setHeader(HttpHeader.CONTENT_TYPE, 
entity.getMediaContentType());
+               } else {
+                       throw new ODataApplicationException("Not implemented",
+                                                               
HttpStatusCode.BAD_REQUEST.getStatusCode(), Locale.ENGLISH);
+               }
+       }
+
+Updating a media entity in our scenario is quite similar to read an entity. 
The first step is to analyse the URI, than fetch the entity from data store. 
Afer that we call the `updateMediaEntity` method. In our case we do not return 
any content. If we would return content, we must return the recently uploaded 
content of the media entity.
+       
+       :::java
+       @Override
+       public void updateMediaEntity(ODataRequest request, ODataResponse 
response, UriInfo uriInfo,
+                       ContentType requestFormat, ContentType responseFormat) 
+                       throws ODataApplicationException, ODataLibraryException 
{
+
+               final UriResource firstResoucePart = 
uriInfo.getUriResourceParts().get(0);
+               if (firstResoucePart instanceof UriResourceEntitySet) {
+                       final EdmEntitySet edmEntitySet = 
Util.getEdmEntitySet(uriInfo);
+                       final UriResourceEntitySet uriResourceEntitySet = 
(UriResourceEntitySet) firstResoucePart;
+
+                       final Entity entity = 
storage.readEntityData(edmEntitySet, uriResourceEntitySet.getKeyPredicates());
+                       if (entity == null) {
+                               throw new ODataApplicationException("Entity not 
found",
+                                               
HttpStatusCode.NOT_FOUND.getStatusCode(), Locale.ENGLISH);
+                       }
+
+                       final byte[] mediaContent = 
odata.createFixedFormatDeserializer().binary(request.getBody());
+                       storage.updateMedia(entity, 
requestFormat.toContentTypeString(), mediaContent);
+
+                       
response.setStatusCode(HttpStatusCode.NO_CONTENT.getStatusCode());
+               } else {
+                       throw new ODataApplicationException("Not implemented",
+                                       
HttpStatusCode.NOT_IMPLEMENTED.getStatusCode(), Locale.ENGLISH);
+               }
+       }
+
+## Run the implemented service
+
+After building and deploying the project, we can invoke our OData service.
+
+Read media entity set
+**GET** 
[http://localhost:8080/DemoService-Media/DemoService.svc/Advertisments](http://localhost:8080/DemoService-Media/DemoService.svc/Advertisments)
+
+Read media entity
+**GET** 
[http://localhost:8080/DemoService-Media/DemoService.svc/Advertisments(f89dee73-af9f-4cd4-b330-db93c25ff3c7)](http://localhost:8080/DemoService-Media/DemoService.svc/Advertisments(f89dee73-af9f-4cd4-b330-db93c25ff3c7))
+
+Read media entity content
+**GET** 
[http://localhost:8080/DemoService-Media/DemoService.svc/Advertisments(f89dee73-af9f-4cd4-b330-db93c25ff3c7)/$value](http://localhost:8080/DemoService-Media/DemoService.svc/Advertisments(f89dee73-af9f-4cd4-b330-db93c25ff3c7)/$value)
+
+Create a new Media Entity
+**POST** [http://localhost:8080/DemoService-Media/DemoService.svc/Advertisments
+Content-Type: image/svg+xml]()
+
+       ::::xml
+       <?xml version="1.0" encoding="UTF-8"?>
+       <svg xmlns="http://www.w3.org/2000/svg"; version="1.1" viewBox="0 0 100 
100">
+               <g stroke="darkmagenta" stroke-width="16" fill="crimson">
+                       <circle cx="50" cy="50" r="42"/>
+               </g>
+       </svg>
+
+
+Update the content of a media entity
+**PUT**  
[http://localhost:8080/DemoService-Media/DemoService.svc/Advertisments(f89dee73-af9f-4cd4-b330-db93c25ff3c7)/$value](http://localhost:8080/DemoService-Media/DemoService.svc/Advertisments(f89dee73-af9f-4cd4-b330-db93c25ff3c7)/$value)
+Content-Type: text/plain
+
+       ::::text
+       Super super nice content
+
+Update the properties of a media entity
+**PUT** 
[http://localhost:8080/DemoService-Media/DemoService.svc/Advertisments(f89dee73-af9f-4cd4-b330-db93c25ff3c7)](http://localhost:8080/DemoService-Media/DemoService.svc/Advertisments(f89dee73-af9f-4cd4-b330-db93c25ff3c7))
+Content-Type: application/json
+
+       ::::json
+       {
+               "Name": "New Name",
+               "AirDate": "2020-06-05T23:00"
+       }
+
+
+
+Delete a media entity
+**DELETE** 
[http://localhost:8080/DemoService-Media/DemoService.svc/Advertisments(f89dee73-af9f-4cd4-b330-db93c25ff3c7)](http://localhost:8080/DemoService-Media/DemoService.svc/Advertisments(f89dee73-af9f-4cd4-b330-db93c25ff3c7))
+
+Delete a media entity
+**DELETE** 
[http://localhost:8080/DemoService-Media/DemoService.svc/Advertisments(db2d2186-1c29-4d1e-88ef-127f521b9c67)/$value](http://localhost:8080/DemoService-Media/DemoService.svc/Advertisments(db2d2186-1c29-4d1e-88ef-127f521b9c67)/$value)
+
+# 5. Links
+
+### Tutorials
+
+Further topics to be covered by follow-up tutorials:
+
+  * Tutorial OData V4 service part 1: [Read Entity 
Collection](/doc/odata4/tutorials/read/tutorial_read.html)
+  * Tutorial OData V4 service part 2: [Read Entity, Read 
Property](/doc/odata4/tutorials/readep/tutorial_readep.html) 
+  * Tutorial OData V4 service part 3: [Write (Create, Update, Delete 
Entity)](/doc/odata4/tutorials/write/tutorial_write.html)
+  * Tutorial OData V4 service, part 4: 
[Navigation](/doc/odata4/tutorials/navigation/tutorial_navigation.html)
+  * Tutorial OData V4 service, part 5.1: [System Query Options $top, $skip, 
$count (this page)](/doc/odata4/tutorials/sqo_tcs/tutorial_sqo_tcs.html)
+  * Tutorial OData V4 service, part 5.2: [System Query Options $select, 
$expand](/doc/odata4/tutorials/sqo_es/tutorial_sqo_es.html)
+  * Tutorial OData V4 service, part 5.3: [System Query Options 
$orderby](/doc/odata4/tutorials/sqo_o/tutorial_sqo_o.html)
+  * Tutorial OData V4 service, part 5.4: [System Query Options 
$filter](/doc/odata4/tutorials/sqo_f/tutorial_sqo_f.html)
+  * Tutorial ODATA V4 service, part 6: [Action and Function 
Imports](/doc/odata4/tutorials/action/tutorial_action.html)
+  * Tutorial ODATA V4 service, part 7: Media Entities
+
+### Code and Repository
+  * [Git Repository](https://git-wip-us.apache.org/repos/asf/olingo-odata4)
+  * [Guide - To fetch the tutorial 
sources](/doc/odata4/tutorials/prerequisites/prerequisites.html)
+  * [Demo Service source code as zip file (contains all 
tutorials)](http://www.apache.org/dyn/closer.lua/olingo/odata4/4.0.0/DemoService_Tutorial.zip)
+
+### Further reading
+
+  * [Official OData Homepage](http://odata.org/)
+  * [OData documentation](http://www.odata.org/documentation/)
+  * [Olingo Javadoc](/javadoc/odata4/index.html)
\ No newline at end of file

Propchange: 
olingo/site/trunk/content/doc/odata4/tutorials/media/tutorial_media.mdtext
------------------------------------------------------------------------------
    svn:eol-style = native


Reply via email to