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 2013/09/26 06:11:23 UTC

svn commit: r1526369 - /incubator/olingo/site/trunk/content/doc/tutorials/read_expand.mdtext

Author: mibo
Date: Thu Sep 26 04:11:23 2013
New Revision: 1526369

URL: http://svn.apache.org/r1526369
Log:
CMS commit to olingo by mibo

Modified:
    incubator/olingo/site/trunk/content/doc/tutorials/read_expand.mdtext

Modified: incubator/olingo/site/trunk/content/doc/tutorials/read_expand.mdtext
URL: http://svn.apache.org/viewvc/incubator/olingo/site/trunk/content/doc/tutorials/read_expand.mdtext?rev=1526369&r1=1526368&r2=1526369&view=diff
==============================================================================
--- incubator/olingo/site/trunk/content/doc/tutorials/read_expand.mdtext (original)
+++ incubator/olingo/site/trunk/content/doc/tutorials/read_expand.mdtext Thu Sep 26 04:11:23 2013
@@ -21,3 +21,216 @@ Notice:    Licensed to the Apache Softwa
 ---
 
 ## How To Guide - Extend basic read scenario with support for `$expand`
+
+This How To Guide shows how to extend the basic read scenario with support for the $expand system query option.
+It shows how to call the `EntityProvider.writeEntry(...)` and `EntityProvider.writeEntrySet(...)` methods with the necessary `EntityProviderWriteProperties` set and how to implement the necessary `OnWriteEntryContent OnWriteFeedContent` callbacks.
+
+## Prerequisites
+Setup of [Basic Read Scenario](basicread)
+
+## Shortcut 
+If you like to directly experiment with the results of the extented basic read scenario, you can use this shortcut: 
+
+  - Download and unzip [Olingo Tutorial 'Basic Read with $expand extension' Project](apache-olingo-tutorial-adv_read_expand) to your local drive 
+  - Start the command line tool and execute the following command in the folder *olingo.odata2.sample* 
+    - `mvn eclipse:eclipse clean install` 
+  - Go into Eclipse and import the project into your workspace by... 
+    - Menue *File -> Import*... 
+    - *Existing projects into workspace*, then choose the *olingo.odata2.sample* folder 
+   - Select both projects *olingo.odata2.sample.service* and *olingo.odata2.sample.web* and press *Finish*. 
+
+## Set Up your development project 
+If ***Basic Read Scenario*** is already set up nothing additional is to do. Otherwise please follow the Setup section of the ***Basic Read Scenario***.
+
+**[links: tbd]**
+
+## Extend Basic Read Scenario
+The steps to extend the basic read with $expand support for the Car and Manufacturer entities (not entity sets) are to provide the expanded data via ODataCallbacks and register these for the corresponding navigation properties. 
+
+### Implement OnWriteEntryContent and OnWriteFeedContent callbacks
+Implementation for `$expand` for a single entry
+To support `$expand` for a single entry the interface `org.apache.olingo.odata2.api.ep.callback.OnWriteEntryContent` must be implemented. This provides the method `WriteEntryCallbackResult retrieveEntryResult(WriteEntryCallbackContext context) throws ODataApplicationException;` which is called during processing from the `EntityProvider` to receive the necessary data which than is inlined in the response.
+
+In our sample we create a class `MyCallback` which implements `org.apache.olingo.odata2.api.ep.callback.OnWriteEntryContent` in following way:
+
+#### Sample Code
+
+    @Override
+    public WriteEntryCallbackResult retrieveEntryResult(WriteEntryCallbackContext context) throws ODataApplicationException {
+    WriteEntryCallbackResult result = new WriteEntryCallbackResult();
+
+      try {
+        if (isNavigationFromTo(context, ENTITY_SET_NAME_CARS, ENTITY_NAME_MANUFACTURER)) {
+        EntityProviderWriteProperties inlineProperties = EntityProviderWriteProperties.serviceRoot(serviceRoot)
+            .expandSelectTree(context.getCurrentExpandSelectTreeNode())
+            .build();
+
+          Map<String, Object> keys = context.extractKeyFromEntryData();
+          Integer carId = (Integer) keys.get("Id");
+          result.setEntryData(dataStore.getManufacturerFor(carId));
+          result.setInlineProperties(inlineProperties);
+        }
+      } catch (EdmException e) {
+      // TODO: should be handled and not only logged
+      LOG.error("Error in $expand handling.", e);
+      } catch (EntityProviderException e) {
+      // TODO: should be handled and not only logged
+      LOG.error("Error in $expand handling.", e);
+      }
+    
+      return result;
+    }
+
+Within this method we first check if the source entity and navigation property are correct for our case (via the method `isNavigationFromTo(...):boolean)`, then we create the `EntityProviderWriteProperties` with the new (current) `ExpandSelectTreeNode`, receive the data from our `DataStore` and put all into the result which then will be further processed by the `EntityProvider`.
+
+### Implementation for $expand for an entity set
+To support `$expand` for a feed of entries (entity set) the interface `org.apache.olingo.odata2.api.ep.callback.OnWriteFeedContent` must be implemented. These provides the method `WriteFeedCallbackResult retrieveFeedResult(WriteFeedCallbackContext context) throws ODataApplicationException;` which is called during processing from the `EntityProvider` to receive the necessary data which than is inlined in the response.
+
+It is possible to create an additional callback class but for convenience we expand our already created callback (`MyCallback`) to implement `org.apache.olingo.odata2.api.ep.callback.OnWriteFeedContent` and provide the method implementation in following way:
+
+#### Sample Code
+
+    @Override
+    public WriteFeedCallbackResult retrieveFeedResult(WriteFeedCallbackContext context) throws ODataApplicationException {
+    WriteFeedCallbackResult result = new WriteFeedCallbackResult();
+      try {
+        if(isNavigationFromTo(context, ENTITY_SET_NAME_MANUFACTURERS, ENTITY_SET_NAME_CARS)) {
+        EntityProviderWriteProperties inlineProperties = EntityProviderWriteProperties.serviceRoot(serviceRoot)
+            .expandSelectTree(context.getCurrentExpandSelectTreeNode())
+            .selfLink(context.getSelfLink())
+            .build();
+
+          Map<String, Object> keys = context.extractKeyFromEntryData();
+          Integer manufacturerId = (Integer) keys.get("Id");
+          result.setFeedData(dataStore.getCarsFor(manufacturerId));
+          result.setInlineProperties(inlineProperties);
+        }
+      } catch (EdmException e) {
+      // TODO: should be handled and not only logged
+      LOG.error("Error in $expand handling.", e);
+      } catch (EntityProviderException e) {
+      // TODO: should be handled and not only logged
+      LOG.error("Error in $expand handling.", e);
+      }
+      return result;
+    }
+
+Within this method we first check if the source entity and navigation property are correct for our case (via the method `isNavigationFromTo(...):boolean)`, then we create the `EntityProviderWriteProperties` with the new (current) `ExpandSelectTreeNode`, receive the data from our `DataStore` and put all into the result which then will be further processed by the `EntityProvider`.
+
+This example shows that the basic callback logic between `OnWriteEntryConten`t and `OnWriteFeedContent` is very similar. Validation of current element (optional), preparing of `EntityProviderWriteProperties`, receive of data and putting all together into corresponding result object (`WriteEntryCallbackResult` or `WriteFeedCallbackResult`).
+
+To improve code readability the `isNavigationFromTo(...):boolean` method was also added to the class. The method is used to check if the retrieved request is related to given entity set and navigation:
+
+#### Sample Code
+
+    private boolean isNavigationFromTo(WriteCallbackContext context, String entitySetName, String navigationPropertyName) throws EdmException {
+      if(entitySetName == null || navigationPropertyName == null) {
+      return false;
+      }
+      EdmEntitySet sourceEntitySet = context.getSourceEntitySet();
+      EdmNavigationProperty navigationProperty = context.getNavigationProperty();
+      return entitySetName.equals(sourceEntitySet.getName()) && navigationPropertyName.equals(navigationProperty.getName());
+    }
+
+### Extend ODataSingleProcessor.readEntity(...)
+The necessary callbacks (`MyCallback` class) now has to be registered during the corresponding `readEntity(...)` call. Therefore we first create a map with the property name as key and the according callback as value. Additional we need to create the `ExpandSelectTreeNode` based on current element position. Both then have to be set in the `EntityProviderWritePropertiesBuilder`. 
+
+The following code show the few lines we need for extending the read of a car with its expanded manufacturer.
+
+    // create and register callback
+    Map<String, ODataCallback> callbacks = new HashMap<String, ODataCallback>();
+    callbacks.put(ENTITY_NAME_MANUFACTURER, new MyCallback(dataStore, serviceRoot));
+    ExpandSelectTreeNode expandSelectTreeNode = UriParser.createExpandSelectTree(uriInfo.getSelect(), uriInfo.getExpand());
+    propertiesBuilder.expandSelectTree(expandSelectTreeNode).callbacks(callbacks);
+
+
+The following code show the few lines we need for extending the read of a manufacturer with its expanded cars.
+
+    // create and register callback
+    Map<String, ODataCallback> callbacks = new HashMap<String, ODataCallback>();
+    callbacks.put(ENTITY_SET_NAME_CARS, new MyCallback(dataStore, serviceRoot));
+    ExpandSelectTreeNode expandSelectTreeNode = UriParser.createExpandSelectTree(uriInfo.getSelect(), uriInfo.getExpand());
+    propertiesBuilder.expandSelectTree(expandSelectTreeNode).callbacks(callbacks);
+
+
+The complete `readEntity(...)` method should now look like:
+
+    public ODataResponse readEntity(GetEntityUriInfo uriInfo, String contentType) throws ODataException {
+    
+      if (uriInfo.getNavigationSegments().size() == 0) {
+      EdmEntitySet entitySet = uriInfo.getStartEntitySet();
+
+        if (ENTITY_SET_NAME_CARS.equals(entitySet.getName())) {
+        int id = getKeyValue(uriInfo.getKeyPredicates().get(0));
+        Map<String, Object> data = dataStore.getCar(id);
+        
+          if (data != null) {
+          URI serviceRoot = getContext().getPathInfo().getServiceRoot();
+          ODataEntityProviderPropertiesBuilder propertiesBuilder = EntityProviderWriteProperties.serviceRoot(serviceRoot);
+          
+            // create and register callback
+          Map<String, ODataCallback> callbacks = new HashMap<String, ODataCallback>();
+          callbacks.put(ENTITY_NAME_MANUFACTURER, new MyCallback(dataStore, serviceRoot));
+          ExpandSelectTreeNode expandSelectTreeNode = UriParser.createExpandSelectTree(uriInfo.getSelect(), uriInfo.getExpand());
+            //
+            propertiesBuilder.expandSelectTree(expandSelectTreeNode).callbacks(callbacks);
+
+             return EntityProvider.writeEntry(contentType, entitySet, data, propertiesBuilder.build());
+          }
+        } else if (ENTITY_SET_NAME_MANUFACTURERS.equals(entitySet.getName())) {
+          int id = getKeyValue(uriInfo.getKeyPredicates().get(0));
+          Map<String, Object> data = dataStore.getManufacturer(id);
+        
+          if (data != null) {
+            URI serviceRoot = getContext().getPathInfo().getServiceRoot();
+            ODataEntityProviderPropertiesBuilder propertiesBuilder = EntityProviderWriteProperties.serviceRoot(serviceRoot);
+  
+            // create and register callback
+            Map<String, ODataCallback> callbacks = new HashMap<String, ODataCallback>();
+            callbacks.put(ENTITY_SET_NAME_CARS, new MyCallback(dataStore, serviceRoot));
+            ExpandSelectTreeNode expandSelectTreeNode = UriParser.createExpandSelectTree(uriInfo.getSelect(), uriInfo.getExpand());
+            //
+            propertiesBuilder.expandSelectTree(expandSelectTreeNode).callbacks(callbacks);
+
+            return EntityProvider.writeEntry(contentType, entitySet, data, propertiesBuilder.build());
+          }
+        }
+
+        throw new ODataNotFoundException(ODataNotFoundException.ENTITY);
+
+      } else if (uriInfo.getNavigationSegments().size() == 1) {
+        //navigation first level, simplified example for illustration purposes only
+        EdmEntitySet entitySet = uriInfo.getTargetEntitySet();
+        if (ENTITY_SET_NAME_MANUFACTURERS.equals(entitySet.getName())) {
+          int carKey = getKeyValue(uriInfo.getKeyPredicates().get(0));
+          return EntityProvider.writeEntry(contentType, uriInfo.getTargetEntitySet(), dataStore.getManufacturer(carKey),   EntityProviderWriteProperties.serviceRoot(getContext().getPathInfo().getServiceRoot()).build());
+        }
+
+        throw new ODataNotFoundException(ODataNotFoundException.ENTITY);
+      }
+
+      throw new ODataNotImplementedException();
+    }
+
+Now we can test out `$expand` extension in the web application.
+
+### Deploy, run and test $expand
+Like in the basic read scenario follow these steps:
+
+  - Build your project: `mvn clean install` 
+  - When build finished in Eclipse, run the Web Application via *Run As -> Run on Server* 
+  - After successful server start and deployment the following uris from the basic read sample work as before: 
+    - Show the Manufacturers: [http://localhost:8080/olingo.odata2.sample.cars.web/MyODataSample.svc/Manufacturers](http://localhost:8080/olingo.odata2.sample.cars.web/MyODataSample.svc/Manufacturers) 
+    - Show one Manufacturer: [http://localhost:8080/olingo.odata2.sample.cars.web/MyODataSample.svc/Manufacturers(1)](http://localhost:8080/olingo.odata2.sample.cars.web/MyODataSample.svc/Manufacturers(1)) 
+    - Show the Cars: [http://localhost:8080/olingo.odata2.sample.cars.web/MyODataSample.svc/Cars](http://localhost:8080/olingo.odata2.sample.cars.web/MyODataSample.svc/Cars) 
+    - Show one Car: [http://localhost:8080/olingo.odata2.sample.cars.web/MyODataSample.svc/Cars(2)](http://localhost:8080/olingo.odata2.sample.cars.web/MyODataSample.svc/Cars(2)) 
+    - Show the related Manufacturer of a Car: [http://localhost:8080/olingo.odata2.sample.cars.web/MyODataSample.svc/Cars(2)/Manufacturer](http://localhost:8080/olingo.odata2.sample.cars.web/MyODataSample.svc/Cars(2)/Manufacturer) 
+    - Show the related Cars of a Manufacturer: [http://localhost:8080/olingo.odata2.sample.cars.web/MyODataSample.svc/Manufacturers(1)/Cars](http://localhost:8080/olingo.odata2.sample.cars.web/MyODataSample.svc/Manufacturers(1)/Cars) 
+  - And in addition we can now expand the car and manufacturer with each other: 
+    - Show Car with its Manufacturer: [http://localhost:8080/olingo.odata2.sample.cars.web/MyODataSample.svc/Cars(2)?$expand=Manufacturer ](http://localhost:8080/olingo.odata2.sample.cars.web/MyODataSample.svc/Cars(2)?$expand=Manufacturer )
+    - Show Manufacturer with its Cars: [http://localhost:8080/olingo.odata2.sample.cars.web/MyODataSample.svc/Manufacturers(1)?$expand=Cars](http://localhost:8080/olingo.odata2.sample.cars.web/MyODataSample.svc/Manufacturers(1)?$expand=Cars) 
+
+## Further Information
+Next extension step for read scenario are read of [Media Resources](read_mediaresource). 
+
+  
\ No newline at end of file