Author: buildbot
Date: Tue Nov 10 14:44:24 2015
New Revision: 971987
Log:
Staging update by buildbot for olingo
Added:
websites/staging/olingo/trunk/content/doc/odata4/tutorials/batch/
websites/staging/olingo/trunk/content/doc/odata4/tutorials/batch/tutorial_batch.html
Modified:
websites/staging/olingo/trunk/content/ (props changed)
Propchange: websites/staging/olingo/trunk/content/
------------------------------------------------------------------------------
--- cms:source-revision (original)
+++ cms:source-revision Tue Nov 10 14:44:24 2015
@@ -1 +1 @@
-1713645
+1713650
Added:
websites/staging/olingo/trunk/content/doc/odata4/tutorials/batch/tutorial_batch.html
==============================================================================
---
websites/staging/olingo/trunk/content/doc/odata4/tutorials/batch/tutorial_batch.html
(added)
+++
websites/staging/olingo/trunk/content/doc/odata4/tutorials/batch/tutorial_batch.html
Tue Nov 10 14:44:24 2015
@@ -0,0 +1,480 @@
+<!DOCTYPE html PUBLIC "-//W3C//DTD HTML 4.01//EN">
+<html lang="en">
+ <head>
+ <meta http-equiv="content-type" content="text/html; charset=utf-8">
+ <meta http-equiv="X-UA-Compatible" content="IE=edge">
+ <meta name="viewport" content="width=device-width, initial-scale=1">
+ <meta name="description" content="Apache Olingo provides libraries which
enable developers to implement OData producers and OData consumers. The
available OData Java library implements OData version 2.0. In future on goal is
to provide an OData 4.0 compliant library once the OData standard is published
at OASIS. The focus within the community is currently on the Java technology
but it is up to the community to discuss if other environments find interest.">
+ <meta name="author" content="">
+ <link rel="icon" href="/favicon.ico">
+ <title>
+ Apache Olingo Library
+ </title><!-- Bootstrap core CSS -->
+ <link href="/css/bootstrap.css" rel="stylesheet" type="text/css"><!--
Custom styles for this template -->
+ <link href="/css/navbar.css" rel="stylesheet" type="text/css"><!-- Just
for debugging purposes. Don't actually copy these 2 lines! -->
+ <link href="/css/offcanvas.css" rel="stylesheet" type="text/css"><!--
Custom styles for this template -->
+ <link rel="stylesheet" href="/css/main.css">
+ <!--[if lt IE 9]><script
src="/js/ie8-responsive-file-warning.js"></script><![endif]-->
+
+ <script src="/js/ie-emulation-modes-warning.js" type="text/javascript">
+</script><!-- IE10 viewport hack for Surface/desktop Windows 8 bug -->
+
+ <script src="/js/ie10-viewport-bug-workaround.js" type="text/javascript">
+</script><!-- HTML5 shim and Respond.js IE8 support of HTML5 elements and
media queries -->
+ <!--[if lt IE 9]>
+ <script src="/js/html5shiv.min.js"></script>
+ <script src="/js/respond.min.js"></script>
+ <![endif]-->
+ </head>
+
+ <body>
+ <div class="container">
+ <!-- Static navbar -->
+ <div class="navbar navbar-default" role="navigation">
+ <div class="container-fluid">
+ <div class="navbar-header">
+ <button type="button" class="navbar-toggle" data-toggle="collapse"
data-target=".navbar-collapse">
+ <span class="sr-only">Toggle navigation</span>
+ <span class="icon-bar"></span>
+ <span class="icon-bar"></span>
+ <span class="icon-bar"></span>
+ </button>
+ <img class="navbar-brand" src="/img/OlingoOrangeTM.png"
style="width:62px;" >
+ <a class="navbar-brand" href="#">Apache Olingoâ¢</a>
+ </div>
+ <div class="navbar-collapse collapse">
+ <ul class="nav navbar-nav">
+
+ <li><a href="/">Home</a></li>
+ <li class="dropdown">
+ <a href="#" class="dropdown-toggle"
data-toggle="dropdown">ASF <b class="caret"></b></a>
+ <ul class="dropdown-menu">
+ <li><a href="http://www.apache.org/foundation/">ASF
Home</a></li>
+ <li><a
href="http://projects.apache.org/">Projects</a></li>
+ <li><a href="http://people.apache.org/">People</a></li>
+ <li><a
href="http://www.apache.org/foundation/getinvolved.html">Get Involved</a></li>
+ <li><a
href="http://www.apache.org/dyn/closer.cgi">Download</a></li>
+ <li><a
href="http://www.apache.org/security/">Security</a></li>
+ <li><a
href="http://www.apache.org/foundation/sponsorship.html">Support Apache</a></li>
+ </ul>
+ </li>
+
+ <li><a href="http://www.apache.org/licenses/">License</a></li>
+
+ <li class="dropdown">
+ <a href="#" class="dropdown-toggle"
data-toggle="dropdown">Download <b class="caret"></b></a>
+ <ul class="dropdown-menu">
+ <li><a href="/doc/odata2/download.html">Download OData
2.0 Java</a></li>
+ <li><a href="/doc/odata4/download.html">Download OData
4.0 Java</a></li>
+ <li><a href="/doc/javascript/download.html">Download
OData 4.0 JavaScript</a></li>
+ </ul>
+ </li>
+
+ <li class="dropdown">
+ <a href="#" class="dropdown-toggle"
data-toggle="dropdown">Documentation <b class="caret"></b></a>
+ <ul class="dropdown-menu">
+ <li><a href="/doc/odata2/index.html">Documentation OData
2.0 Java</a></li>
+ <li><a href="/doc/odata4/index.html">Documentation OData
4.0 Java</a></li>
+ <li><a href="/doc/javascript/index.html">Documentation
OData 4.0 JavaScript</a></li>
+ </ul>
+ </li>
+ <li><a href="/support.html">Support</a></li>
+
+ </ul>
+
+ <img class="navbar-right" height="50px"
src="/img/asf-logo.gif">
+
+ </div><!--/.nav-collapse -->
+ </div><!--/.container-fluid -->
+ </div><!-- Main component for a primary marketing message or call to
action --><style type="text/css">
+/* The following code is added by mdx_elementid.py
+ It was originally lifted from http://subversion.apache.org/style/site.css */
+/*
+ * Hide class="elementid-permalink", except when an enclosing heading
+ * has the :hover property.
+ */
+.headerlink, .elementid-permalink {
+ visibility: hidden;
+}
+h2:hover > .headerlink, h3:hover > .headerlink, h1:hover > .headerlink,
h6:hover > .headerlink, h4:hover > .headerlink, h5:hover > .headerlink,
dt:hover > .elementid-permalink { visibility: visible }</style>
+<h1 id="how-to-build-an-odata-service-with-olingo-v4">How to build an OData
Service with Olingo V4<a class="headerlink"
href="#how-to-build-an-odata-service-with-olingo-v4" title="Permanent
link">¶</a></h1>
+<h1 id="part-7-batch-request-support">Part 7: Batch Request Support<a
class="headerlink" href="#part-7-batch-request-support" title="Permanent
link">¶</a></h1>
+<h2 id="introduction">Introduction<a class="headerlink" href="#introduction"
title="Permanent link">¶</a></h2>
+<p>In the present tutorial, weâll implement batch requests.</p>
+<p><strong>Note:</strong>
+The final source code can be found in the project <a
href="https://git-wip-us.apache.org/repos/asf/olingo-odata4">git repository</a>.
+A detailed description how to checkout the tutorials can be found <a
href="/doc/odata4/tutorials/prerequisites/prerequisites.html">here</a>. <br />
+This tutorial can be found in subdirectory /samples/tutorials/p11_batch</p>
+<p><strong>Table of Contents</strong></p>
+<ol>
+<li>Introduction</li>
+<li>Preparation</li>
+<li>Implementation</li>
+<li>Run the implemented service</li>
+<li>Links</li>
+</ol>
+<h1 id="1-introduction">1. Introduction<a class="headerlink"
href="#1-introduction" title="Permanent link">¶</a></h1>
+<p>Batch requests <a
href="http://docs.oasis-open.org/odata/odata/v4.0/errata02/os/complete/part1-protocol/odata-v4.0-errata02-os-part1-protocol-complete.html#_Toc406398359">(OData
Version 4.0 Part 1: Protocol Plus Errata 02)</a> allow grouping multiple
operations into a single HTTP request payload. A batch request is represented
as a Multipart MIME v1.0 message <a
href="https://www.ietf.org/rfc/rfc2046.txt">(RFC2046)</a>.
+Each part of a Multipart MINE message can have a differtent content type. For
example you can mix OData requests with Content-Type an
<code>application/json</code> and Media Ressource Requests with Content Type
<code>image/png</code>.</p>
+<p>The content of batch requests can consist of a series of individual
requests and Change Sets, each represented as a distinct MIME part. In
difference to OData V2 an individual request can be a Data Request, Data
Modification Request, Action invocation request or a Function invocation
request. So all kinds of OData requests are allowed at top level. The order of
individual requests and Change Set sets in significant. Within a Change Set you
can use Data Modification requests and Action invocation requests. Due to the
fact that all requests within a Change Set are unordered, GET requests must not
be used within a Change Set. All operations in a change set represent a single
change unit so a service must successfully process and apply all the requests
in the change set or else apply none of them.</p>
+<p><strong>Example</strong></p>
+<p>The request below consists of a individual request (upper red box),
actually a GET request(the upper blue box) to the Entity Set
<code>Products</code> and a Change Set (lower red box). The Change Set contains
a single POST request (lower blue box) to create a new <code>Procuct</code>.
Please note that the <em>boundary delimiter</em> <code>abc123</code> is used in
the request below. The whole content must be wrapped in a single POST request
issued againest the resource <code>/$batch</code>. The Content-Type of the POST
request is consequently <code>Content-Type:
multipart/mixed;boundary=abc123</code></p>
+<p><img alt="Test" src="request.png" /></p>
+<h1 id="2-preparation">2. Preparation<a class="headerlink"
href="#2-preparation" title="Permanent link">¶</a></h1>
+<p>You should read the previous tutorials first to have an idea how to read
and write entities entities. In addition the following code is based on the
write tutorial tutorial.</p>
+<p>As a shortcut you should checkout the prepared tutorial project in the <a
href="https://git-wip-us.apache.org/repos/asf/olingo-odata4">git repository</a>
in folder /samples/tutorials/p3_write.</p>
+<p>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.</p>
+<h1 id="2-implementation">2. Implementation<a class="headerlink"
href="#2-implementation" title="Permanent link">¶</a></h1>
+<p>The main idea of the following implementation is to reuse the existing
processors.
+To do so, we will implement a new processor, which takes a batch request and
dispatches the single requests to the responsible processors.</p>
+<p>The folling steps have to be performed:
+ * Modify the data store
+ * Implement the interface <code>BatchProcessor</code></p>
+<h2 id="add-transactional-behaviour-to-the-data-store">Add transactional
behaviour to the data store<a class="headerlink"
href="#add-transactional-behaviour-to-the-data-store" title="Permanent
link">¶</a></h2>
+<p>Before we start with the actual processor implementation the data store has
to be modified to provide transactional behavior. In real world service the
underlaying database may supports transactional handling. This tutorial is not
based on a database so we have implement a simple transaction handling by
ourself.</p>
+<p>Add the folling methods to the class
<code>myservice.mynamespace.data.Storage</code>. When a new transaction has
been begun the data of the service is copied and stored in an instance
variable. If <code>rollbackTransaction</code> has been called the current data
is replaced with the previous copied one.</p>
+<div class="codehilite"><pre><span class="kd">private</span> <span
class="n">List</span><span class="o"><</span><span
class="n">Entity</span><span class="o">></span> <span
class="n">productListBeforeTransaction</span><span class="o">;</span>
+
+<span class="kd">public</span> <span class="kt">void</span> <span
class="nf">beginTransaction</span><span class="o">()</span> <span
class="o">{</span>
+ <span class="k">if</span><span class="o">(</span><span
class="n">productListBeforeTransaction</span> <span class="o">==</span> <span
class="kc">null</span><span class="o">)</span> <span class="o">{</span>
+ <span class="n">productListBeforeTransaction</span> <span
class="o">=</span> <span class="n">cloneEntityCollection</span><span
class="o">(</span><span class="n">productList</span><span class="o">);</span>
+ <span class="o">}</span> <span class="k">else</span> <span
class="o">{</span>
+ <span class="k">throw</span> <span class="k">new</span> <span
class="nf">UnsupportedOperationException</span><span class="o">(</span><span
class="s">"Transaction already in process"</span><span
class="o">);</span>
+ <span class="o">}</span>
+<span class="o">}</span>
+
+<span class="kd">public</span> <span class="kt">void</span> <span
class="nf">commitTransaction</span><span class="o">()</span> <span
class="o">{</span>
+ <span class="k">if</span><span class="o">(</span><span
class="n">productListBeforeTransaction</span> <span class="o">==</span> <span
class="kc">null</span><span class="o">)</span> <span class="o">{</span>
+ <span class="k">throw</span> <span class="k">new</span> <span
class="nf">UnsupportedOperationException</span><span class="o">(</span><span
class="s">"No Transaction active"</span><span class="o">);</span>
+ <span class="o">}</span> <span class="k">else</span> <span
class="o">{</span>
+ <span class="n">productListBeforeTransaction</span> <span
class="o">=</span> <span class="kc">null</span><span class="o">;</span>
+ <span class="o">}</span>
+<span class="o">}</span>
+
+<span class="kd">public</span> <span class="kt">void</span> <span
class="nf">rollbackTranscation</span><span class="o">()</span> <span
class="o">{</span>
+ <span class="k">if</span><span class="o">(</span><span
class="n">productListBeforeTransaction</span> <span class="o">==</span> <span
class="kc">null</span><span class="o">)</span> <span class="o">{</span>
+ <span class="k">throw</span> <span class="k">new</span> <span
class="nf">UnsupportedOperationException</span><span class="o">(</span><span
class="s">"No Transaction active"</span><span class="o">);</span>
+ <span class="o">}</span> <span class="k">else</span> <span
class="o">{</span>
+ <span class="n">productList</span> <span class="o">=</span> <span
class="n">productListBeforeTransaction</span><span class="o">;</span>
+ <span class="n">productListBeforeTransaction</span> <span
class="o">=</span> <span class="kc">null</span><span class="o">;</span>
+ <span class="o">}</span>
+<span class="o">}</span>
+
+<span class="kd">private</span> <span class="n">List</span><span
class="o"><</span><span class="n">Entity</span><span class="o">></span>
<span class="n">cloneEntityCollection</span><span class="o">(</span><span
class="kd">final</span> <span class="n">List</span><span
class="o"><</span><span class="n">Entity</span><span class="o">></span>
<span class="n">entities</span><span class="o">)</span> <span class="o">{</span>
+ <span class="kd">final</span> <span class="n">List</span><span
class="o"><</span><span class="n">Entity</span><span class="o">></span>
<span class="n">clonedEntities</span> <span class="o">=</span> <span
class="k">new</span> <span class="n">ArrayList</span><span
class="o"><</span><span class="n">Entity</span><span class="o">>();</span>
+
+ <span class="k">for</span><span class="o">(</span><span
class="kd">final</span> <span class="n">Entity</span> <span
class="n">entity</span> <span class="o">:</span> <span
class="n">entities</span><span class="o">)</span> <span class="o">{</span>
+ <span class="kd">final</span> <span class="n">Entity</span> <span
class="n">clonedEntity</span> <span class="o">=</span> <span
class="k">new</span> <span class="n">Entity</span><span class="o">();</span>
+
+ <span class="n">clonedEntity</span><span class="o">.</span><span
class="na">setId</span><span class="o">(</span><span
class="n">entity</span><span class="o">.</span><span
class="na">getId</span><span class="o">());</span>
+ <span class="k">for</span><span class="o">(</span><span
class="kd">final</span> <span class="n">Property</span> <span
class="n">property</span> <span class="o">:</span> <span
class="n">entity</span><span class="o">.</span><span
class="na">getProperties</span><span class="o">())</span> <span
class="o">{</span>
+ <span class="n">clonedEntity</span><span class="o">.</span><span
class="na">addProperty</span><span class="o">(</span><span class="k">new</span>
<span class="n">Property</span><span class="o">(</span><span
class="n">property</span><span class="o">.</span><span
class="na">getType</span><span class="o">(),</span>
+ <span class="n">property</span><span class="o">.</span><span
class="na">getName</span><span class="o">(),</span>
+ <span class="n">property</span><span class="o">.</span><span
class="na">getValueType</span><span class="o">(),</span>
+ <span class="n">property</span><span class="o">.</span><span
class="na">getValue</span><span class="o">()));</span>
+ <span class="o">}</span>
+
+ <span class="n">clonedEntities</span><span class="o">.</span><span
class="na">add</span><span class="o">(</span><span
class="n">clonedEntity</span><span class="o">);</span>
+ <span class="o">}</span>
+
+ <span class="k">return</span> <span class="n">clonedEntities</span><span
class="o">;</span>
+<span class="o">}</span>
+</pre></div>
+
+
+<h2 id="implement-the-interface-batchprocessor">Implement the interface
<code>BatchProcessor</code><a class="headerlink"
href="#implement-the-interface-batchprocessor" title="Permanent
link">¶</a></h2>
+<p>Create a new class
<code>myservice.mynamespace.service.DemoBatchProcessor</code>. The class should
implement the interface
<code>org.apache.olingo.server.api.processor.BatchProcessor</code>.</p>
+<p>Create a constructor and pass the data store to the procesoor.</p>
+<div class="codehilite"><pre><span class="kd">public</span> <span
class="kd">class</span> <span class="nc">DemoBatchProcessor</span> <span
class="kd">implements</span> <span class="n">BatchProcessor</span> <span
class="o">{</span>
+
+ <span class="kd">private</span> <span class="n">OData</span> <span
class="n">odata</span><span class="o">;</span>
+ <span class="kd">private</span> <span class="n">Storage</span> <span
class="n">storage</span><span class="o">;</span>
+
+ <span class="kd">public</span> <span
class="nf">DemoBatchProcessor</span><span class="o">(</span><span
class="kd">final</span> <span class="n">Storage</span> <span
class="n">storage</span><span class="o">)</span> <span class="o">{</span>
+ <span class="k">this</span><span class="o">.</span><span
class="na">storage</span> <span class="o">=</span> <span
class="n">storage</span><span class="o">;</span>
+ <span class="o">}</span>
+
+ <span class="nd">@Override</span>
+ <span class="kd">public</span> <span class="kt">void</span> <span
class="nf">init</span><span class="o">(</span><span class="kd">final</span>
<span class="n">OData</span> <span class="n">odata</span><span
class="o">,</span> <span class="kd">final</span> <span
class="n">ServiceMetadata</span> <span class="n">serviceMetadata</span><span
class="o">)</span> <span class="o">{</span>
+ <span class="k">this</span><span class="o">.</span><span
class="na">odata</span> <span class="o">=</span> <span
class="n">odata</span><span class="o">;</span>
+ <span class="o">}</span>
+ <span class="o">...</span>
+</pre></div>
+
+
+<h3 id="implement-batch-handling">Implement batch handling<a
class="headerlink" href="#implement-batch-handling" title="Permanent
link">¶</a></h3>
+<p>Batch requests will be dispatched to the method <code>processBatch</code>.
First, the boundary have to be extract from the Content-Type of the POST
request.</p>
+<div class="codehilite"><pre> <span class="nd">@Override</span>
+ <span class="kd">public</span> <span class="kt">void</span> <span
class="nf">processBatch</span><span class="o">(</span><span
class="kd">final</span> <span class="n">BatchFacade</span> <span
class="n">facade</span><span class="o">,</span> <span class="kd">final</span>
<span class="n">ODataRequest</span> <span class="n">request</span><span
class="o">,</span> <span class="kd">final</span> <span
class="n">ODataResponse</span> <span class="n">response</span><span
class="o">)</span>
+ <span class="kd">throws</span> <span
class="n">ODataApplicationException</span><span class="o">,</span> <span
class="n">ODataLibraryException</span> <span class="o">{</span>
+
+ <span class="c1">// 1. Extract the boundary</span>
+ <span class="kd">final</span> <span class="n">String</span> <span
class="n">boundary</span> <span class="o">=</span> <span
class="n">facade</span><span class="o">.</span><span
class="na">extractBoundaryFromContentType</span><span class="o">(</span><span
class="n">request</span><span class="o">.</span><span
class="na">getHeader</span><span class="o">(</span><span
class="n">HttpHeader</span><span class="o">.</span><span
class="na">CONTENT_TYPE</span><span class="o">));</span>
+</pre></div>
+
+
+<p>After that we are able to parse the multipart mixed body. The parser needs
to know what the base uri and the service resolution paths are. The result of
the parser is a list of BatchRequestParts. Each of these parts represents
either a single request or a Change Set (Collection of one or more
requests).</p>
+<div class="codehilite"><pre> <span class="c1">// 2. Prepare the batch
options</span>
+ <span class="kd">final</span> <span class="n">BatchOptions</span> <span
class="n">options</span> <span class="o">=</span> <span
class="n">BatchOptions</span><span class="o">.</span><span
class="na">with</span><span class="o">().</span><span
class="na">rawBaseUri</span><span class="o">(</span><span
class="n">request</span><span class="o">.</span><span
class="na">getRawBaseUri</span><span class="o">())</span>
+ <span
class="o">.</span><span class="na">rawServiceResolutionUri</span><span
class="o">(</span><span class="n">request</span><span class="o">.</span><span
class="na">getRawServiceResolutionUri</span><span class="o">())</span>
+ <span
class="o">.</span><span class="na">build</span><span class="o">();</span>
+
+ <span class="c1">// 3. Deserialize the batch request</span>
+ <span class="kd">final</span> <span class="n">List</span><span
class="o"><</span><span class="n">BatchRequestPart</span><span
class="o">></span> <span class="n">requestParts</span> <span
class="o">=</span> <span class="n">odata</span><span class="o">.</span><span
class="na">createFixedFormatDeserializer</span><span class="o">()</span>
+ <span
class="o">.</span><span class="na">parseBatchRequest</span><span
class="o">(</span><span class="n">request</span><span class="o">.</span><span
class="na">getBody</span><span class="o">(),</span> <span
class="n">boundary</span><span class="o">,</span> <span
class="n">options</span><span class="o">);</span>
+</pre></div>
+
+
+<p>Now the requests have to be executed by our service. If you like, you can
do it by our own or simply call the method <code>handleBatchRequest</code>.
This method dispatches individual requests directly to the responsible
processor. If a Change Set is passed to <code>handleBatchRequest</code> the
implementation dispaches the request to the method
<code>processChangeSet</code> of our <code>DemoBatchProcessor</code>.</p>
+<div class="codehilite"><pre> <span class="c1">// 4. Execute the batch
request parts</span>
+ <span class="kd">final</span> <span class="n">List</span><span
class="o"><</span><span class="n">ODataResponsePart</span><span
class="o">></span> <span class="n">responseParts</span> <span
class="o">=</span> <span class="k">new</span> <span
class="n">ArrayList</span><span class="o"><</span><span
class="n">ODataResponsePart</span><span class="o">>();</span>
+ <span class="k">for</span> <span class="o">(</span><span
class="kd">final</span> <span class="n">BatchRequestPart</span> <span
class="n">part</span> <span class="o">:</span> <span
class="n">requestParts</span><span class="o">)</span> <span class="o">{</span>
+ <span class="n">responseParts</span><span class="o">.</span><span
class="na">add</span><span class="o">(</span><span class="n">facade</span><span
class="o">.</span><span class="na">handleBatchRequest</span><span
class="o">(</span><span class="n">part</span><span class="o">));</span>
+ <span class="o">}</span>
+</pre></div>
+
+
+<p>The last steps are to serialize the responses and setup the reponse of the
batch request.</p>
+<div class="codehilite"><pre> <span class="c1">// 5. Serialize the response
content</span>
+ <span class="kd">final</span> <span class="n">InputStream</span> <span
class="n">responseContent</span> <span class="o">=</span> <span
class="n">odata</span><span class="o">.</span><span
class="na">createFixedFormatSerializer</span><span class="o">().</span><span
class="na">batchResponse</span><span class="o">(</span><span
class="n">responseParts</span><span class="o">,</span> <span
class="n">boundary</span><span class="o">);</span>
+
+ <span class="c1">// 6. Create a new boundary for the response</span>
+ <span class="kd">final</span> <span class="n">String</span> <span
class="n">responseBoundary</span> <span class="o">=</span> <span
class="s">"batch_"</span> <span class="o">+</span> <span
class="n">UUID</span><span class="o">.</span><span
class="na">randomUUID</span><span class="o">().</span><span
class="na">toString</span><span class="o">();</span>
+
+ <span class="c1">// 7. Setup response</span>
+ <span class="n">response</span><span class="o">.</span><span
class="na">setHeader</span><span class="o">(</span><span
class="n">HttpHeader</span><span class="o">.</span><span
class="na">CONTENT_TYPE</span><span class="o">,</span> <span
class="n">ContentType</span><span class="o">.</span><span
class="na">MULTIPART_MIXED</span> <span class="o">+</span> <span
class="s">";boundary="</span> <span class="o">+</span> <span
class="n">responseBoundary</span><span class="o">);</span>
+ <span class="n">response</span><span class="o">.</span><span
class="na">setContent</span><span class="o">(</span><span
class="n">responseContent</span><span class="o">);</span>
+ <span class="n">response</span><span class="o">.</span><span
class="na">setStatusCode</span><span class="o">(</span><span
class="n">HttpStatusCode</span><span class="o">.</span><span
class="na">ACCEPTED</span><span class="o">.</span><span
class="na">getStatusCode</span><span class="o">());</span>
+<span class="o">}</span>
+</pre></div>
+
+
+<h3 id="implement-change-set-handling">Implement Change Set handling<a
class="headerlink" href="#implement-change-set-handling" title="Permanent
link">¶</a></h3>
+<p>As mentioned above Change Sets are dispatched to the method
<code>processChangeSet</code>.
+In this tutorial the implementation is quite simple. First we begin a new
transaction. After that we try to execute all requests of the Change Set. If
one of the requests fail all changes have to be rolled back.
+The comments in the source code give a detailed explaination about the steps
done in this mehtod.</p>
+<div class="codehilite"><pre><span class="nd">@Override</span>
+<span class="kd">public</span> <span class="n">ODataResponsePart</span> <span
class="nf">processChangeSet</span><span class="o">(</span><span
class="kd">final</span> <span class="n">BatchFacade</span> <span
class="n">facade</span><span class="o">,</span> <span class="kd">final</span>
<span class="n">List</span><span class="o"><</span><span
class="n">ODataRequest</span><span class="o">></span> <span
class="n">requests</span><span class="o">)</span>
+ <span class="kd">throws</span> <span
class="n">ODataApplicationException</span><span class="o">,</span> <span
class="n">ODataLibraryException</span> <span class="o">{</span>
+ <span class="cm">/* </span>
+<span class="cm"> * OData Version 4.0 Part 1: Protocol Plus Errata 02</span>
+<span class="cm"> * 11.7.4 Responding to a Batch Request</span>
+<span class="cm"> * </span>
+<span class="cm"> * All operations in a change set represent a single
change unit so a service MUST successfully process and </span>
+<span class="cm"> * apply all the requests in the change set or else
apply none of them. It is up to the service implementation </span>
+<span class="cm"> * to define rollback semantics to undo any requests
within a change set that may have been applied before </span>
+<span class="cm"> * another request in that same change set failed and
thereby apply this all-or-nothing requirement. </span>
+<span class="cm"> * The service MAY execute the requests within a
change set in any order and MAY return the responses to the </span>
+<span class="cm"> * individual requests in any order. The service
MUST include the Content-ID header in each response with the </span>
+<span class="cm"> * same value that the client specified in the
corresponding request, so clients can correlate requests </span>
+<span class="cm"> * and responses.</span>
+<span class="cm"> * </span>
+<span class="cm"> * To keep things simple, we dispatch the requests within
the Change Set to the other processor interfaces.</span>
+<span class="cm"> */</span>
+ <span class="kd">final</span> <span class="n">List</span><span
class="o"><</span><span class="n">ODataResponse</span><span
class="o">></span> <span class="n">responses</span> <span class="o">=</span>
<span class="k">new</span> <span class="n">ArrayList</span><span
class="o"><</span><span class="n">ODataResponse</span><span
class="o">>();</span>
+
+ <span class="k">try</span> <span class="o">{</span>
+ <span class="n">storage</span><span class="o">.</span><span
class="na">beginTransaction</span><span class="o">();</span>
+
+ <span class="k">for</span><span class="o">(</span><span
class="kd">final</span> <span class="n">ODataRequest</span> <span
class="n">request</span> <span class="o">:</span> <span
class="n">requests</span><span class="o">)</span> <span class="o">{</span>
+ <span class="c1">// Actual request dispatching to the other
processor interfaces.</span>
+ <span class="kd">final</span> <span class="n">ODataResponse</span>
<span class="n">response</span> <span class="o">=</span> <span
class="n">facade</span><span class="o">.</span><span
class="na">handleODataRequest</span><span class="o">(</span><span
class="n">request</span><span class="o">);</span>
+
+ <span class="c1">// Determine if an error occurred while executing
the request.</span>
+ <span class="c1">// Exceptions thrown by the processors get caught
and result in a proper OData response.</span>
+ <span class="kd">final</span> <span class="kt">int</span> <span
class="n">statusCode</span> <span class="o">=</span> <span
class="n">response</span><span class="o">.</span><span
class="na">getStatusCode</span><span class="o">();</span>
+ <span class="k">if</span><span class="o">(</span><span
class="n">statusCode</span> <span class="o"><</span> <span
class="mi">400</span><span class="o">)</span> <span class="o">{</span>
+ <span class="c1">// The request has been executed
successfully. Return the response as a part of the change set</span>
+ <span class="n">responses</span><span class="o">.</span><span
class="na">add</span><span class="o">(</span><span
class="n">response</span><span class="o">);</span>
+ <span class="o">}</span> <span class="k">else</span> <span
class="o">{</span>
+ <span class="c1">// Something went wrong. Undo all previous
requests in this Change Set</span>
+ <span class="n">storage</span><span class="o">.</span><span
class="na">rollbackTranscation</span><span class="o">();</span>
+
+ <span class="cm">/*</span>
+<span class="cm"> * In addition the response must be provided
as follows:</span>
+<span class="cm"> * </span>
+<span class="cm"> * OData Version 4.0 Part 1: Protocol Plus
Errata 02</span>
+<span class="cm"> * 11.7.4 Responding to a Batch
Request</span>
+<span class="cm"> *</span>
+<span class="cm"> * When a request within a change set
fails, the change set response is not represented using</span>
+<span class="cm"> * the multipart/mixed media type.
Instead, a single response, using the application/http media type</span>
+<span class="cm"> * and a Content-Transfer-Encoding header
with a value of binary, is returned that</span>
+<span class="cm"> * applies to all requests in the change
set and MUST be formatted according to the Error Handling</span>
+<span class="cm"> * defined for the particular response
format.</span>
+<span class="cm"> * </span>
+<span class="cm"> * This can be simply done by passing the
response of the failed ODataRequest to a new instance of </span>
+<span class="cm"> * ODataResponsePart and setting the second
parameter "isChangeSet" to false.</span>
+<span class="cm"> */</span>
+ <span class="k">return</span> <span class="k">new</span> <span
class="nf">ODataResponsePart</span><span class="o">(</span><span
class="n">response</span><span class="o">,</span> <span
class="kc">false</span><span class="o">);</span>
+ <span class="o">}</span>
+ <span class="o">}</span>
+
+ <span class="c1">// Everything went well, so commit the changes.</span>
+ <span class="n">storage</span><span class="o">.</span><span
class="na">commitTransaction</span><span class="o">();</span>
+ <span class="k">return</span> <span class="k">new</span> <span
class="nf">ODataResponsePart</span><span class="o">(</span><span
class="n">responses</span><span class="o">,</span> <span
class="kc">true</span><span class="o">);</span>
+
+ <span class="o">}</span> <span class="k">catch</span><span
class="o">(</span><span class="n">ODataApplicationException</span> <span
class="n">e</span><span class="o">)</span> <span class="o">{</span>
+ <span class="c1">// See below</span>
+ <span class="n">storage</span><span class="o">.</span><span
class="na">rollbackTranscation</span><span class="o">();</span>
+ <span class="k">throw</span> <span class="n">e</span><span
class="o">;</span>
+ <span class="o">}</span> <span class="k">catch</span><span
class="o">(</span><span class="n">ODataLibraryException</span> <span
class="n">e</span><span class="o">)</span> <span class="o">{</span>
+ <span class="c1">// The batch request is malformed or the processor
implementation is not correct.</span>
+ <span class="c1">// Throwing an exception will stop the whole batch
request not only the Change Set!</span>
+ <span class="n">storage</span><span class="o">.</span><span
class="na">rollbackTranscation</span><span class="o">();</span>
+ <span class="k">throw</span> <span class="n">e</span><span
class="o">;</span>
+ <span class="o">}</span>
+<span class="o">}</span>
+</pre></div>
+
+
+<h1 id="4-run-the-implemented-service">4. Run the implemented service<a
class="headerlink" href="#4-run-the-implemented-service" title="Permanent
link">¶</a></h1>
+<p>After building and deploying your service to your server, you can try the
following requests:</p>
+<p>All requests are issued againest <a
href="http://localhost:8080/DemoService-Action/DemoService.svc/$batch">http://localhost:8080/DemoService-Action/DemoService.svc/$batch</a>
+Set the Content-Type header to <code>Content-Type:
multipart/mixed;boundary=abc123</code></p>
+<p><strong>Example 1</strong>
+Please note that the second request in the Change Set references the first
request of the Change Set.
+This is done by by prefixing the Content-Id of the referenced request with a
$. e.g. <code>$abc</code></p>
+<div class="codehilite"><pre><span class="o">--</span><span
class="n">abc123</span>
+<span class="n">Content</span><span class="o">-</span><span
class="n">Type</span><span class="p">:</span> <span
class="n">application</span><span class="o">/</span><span class="n">http</span>
+<span class="n">Content</span><span class="o">-</span><span
class="n">Transfer</span><span class="o">-</span><span
class="n">Encoding</span><span class="p">:</span> <span class="n">binary</span>
+
+<span class="n">GET</span> <span class="n">Products</span> <span
class="n">HTTP</span><span class="o">/</span>1<span class="p">.</span>1
+<span class="n">Content</span><span class="o">-</span><span
class="n">Type</span><span class="p">:</span> <span
class="n">application</span><span class="o">/</span><span class="n">json</span>
+
+<span class="o">--</span><span class="n">abc123</span>
+<span class="n">Content</span><span class="o">-</span><span
class="n">Type</span><span class="p">:</span> <span
class="n">multipart</span><span class="o">/</span><span
class="n">mixed</span><span class="p">;</span><span
class="n">boundary</span><span class="p">=</span><span
class="n">changeset_abc</span>
+
+<span class="o">--</span><span class="n">changeset_abc</span>
+<span class="n">Content</span><span class="o">-</span><span
class="n">Type</span><span class="p">:</span> <span
class="n">application</span><span class="o">/</span><span class="n">http</span>
+<span class="n">Content</span><span class="o">-</span><span
class="n">Transfer</span><span class="o">-</span><span
class="n">Encoding</span><span class="p">:</span><span class="n">binary</span>
+<span class="n">Content</span><span class="o">-</span><span
class="n">Id</span><span class="p">:</span> 1
+
+<span class="n">POST</span> <span class="n">Products</span> <span
class="n">HTTP</span><span class="o">/</span>1<span class="p">.</span>1
+<span class="n">Content</span><span class="o">-</span><span
class="n">Type</span><span class="p">:</span> <span
class="n">application</span><span class="o">/</span><span class="n">json</span>
+
+<span class="p">{</span>"<span class="n">Name</span>"<span
class="p">:</span> "<span class="n">Test</span> <span
class="n">Product</span>"<span class="p">,</span> "<span
class="n">Description</span>"<span class="p">:</span> "<span
class="n">This</span> <span class="n">is</span> <span class="n">a</span> <span
class="n">test</span> <span class="n">product</span>"<span
class="p">}</span>
+
+<span class="o">--</span><span class="n">changeset_abc</span>
+<span class="n">Content</span><span class="o">-</span><span
class="n">Type</span><span class="p">:</span> <span
class="n">application</span><span class="o">/</span><span class="n">http</span>
+<span class="n">Content</span><span class="o">-</span><span
class="n">Transfer</span><span class="o">-</span><span
class="n">Encoding</span><span class="p">:</span><span class="n">binary</span>
+<span class="n">Content</span><span class="o">-</span><span
class="n">ID</span><span class="p">:</span> 2
+
+<span class="n">PATCH</span> $1 <span class="n">HTTP</span><span
class="o">/</span>1<span class="p">.</span>1
+<span class="n">Content</span><span class="o">-</span><span
class="n">Type</span><span class="p">:</span> <span
class="n">application</span><span class="o">/</span><span class="n">json</span>
+<span class="n">Accept</span><span class="p">:</span> <span
class="n">application</span><span class="o">/</span><span class="n">json</span>
+
+<span class="p">{</span>"<span class="n">Description</span>"<span
class="p">:</span> "<span class="n">With</span> <span class="n">a</span>
<span class="n">changed</span> <span class="n">Description</span>"<span
class="p">}</span>
+
+<span class="o">--</span><span class="n">changeset_abc</span><span
class="o">--</span>
+
+<span class="o">--</span><span class="n">abc123</span>
+<span class="n">Content</span><span class="o">-</span><span
class="n">Type</span><span class="p">:</span> <span
class="n">application</span><span class="o">/</span><span class="n">http</span>
+<span class="n">Content</span><span class="o">-</span><span
class="n">Transfer</span><span class="o">-</span><span
class="n">Encoding</span><span class="p">:</span> <span class="n">binary</span>
+
+<span class="n">GET</span> <span class="n">Products</span> <span
class="n">HTTP</span><span class="o">/</span>1<span class="p">.</span>1
+<span class="n">Content</span><span class="o">-</span><span
class="n">Type</span><span class="p">:</span> <span
class="n">application</span><span class="o">/</span><span class="n">json</span>
+
+<span class="o">--</span><span class="n">abc123</span><span class="o">--</span>
+</pre></div>
+
+
+<p>Now have a look at the response. As you can see a new product has been
created and the desciption has been updated to 'With a changed Description'</p>
+<div class="codehilite"><pre><span class="p">{</span>
+ "<span class="p">@</span><span class="n">odata</span><span
class="p">.</span><span class="n">context</span>"<span class="p">:</span>
"$<span class="n">metadata</span>#<span
class="n">Products</span>"<span class="p">,</span>
+ "<span class="n">value</span>"<span class="p">:</span> <span
class="p">[</span>
+ <span class="p">...</span>
+ <span class="p">{</span>
+ "<span class="n">ID</span>"<span class="p">:</span>
4<span class="p">,</span>
+ "<span class="n">Name</span>"<span class="p">:</span>
"<span class="n">Test</span> <span class="n">Product</span>"<span
class="p">,</span>
+ "<span class="n">Description</span>"<span
class="p">:</span> "<span class="n">With</span> <span class="n">a</span>
<span class="n">changed</span> <span class="n">Description</span>"
+ <span class="p">}</span>
+ <span class="p">]</span>
+<span class="p">}</span>
+</pre></div>
+
+
+<p><strong>Example 2</strong>
+Let us try what is happing if the send a invalid request within a Change Set.
Use the same URI and Content Type as before and use the folling body:</p>
+<div class="codehilite"><pre><span class="o">--</span><span
class="n">abc123</span>
+<span class="n">Content</span><span class="o">-</span><span
class="n">Type</span><span class="p">:</span> <span
class="n">multipart</span><span class="o">/</span><span
class="n">mixed</span><span class="p">;</span><span
class="n">boundary</span><span class="p">=</span><span
class="n">changeset_abc</span>
+
+<span class="o">--</span><span class="n">changeset_abc</span>
+<span class="n">Content</span><span class="o">-</span><span
class="n">Type</span><span class="p">:</span> <span
class="n">application</span><span class="o">/</span><span class="n">http</span>
+<span class="n">Content</span><span class="o">-</span><span
class="n">Transfer</span><span class="o">-</span><span
class="n">Encoding</span><span class="p">:</span><span class="n">binary</span>
+<span class="n">Content</span><span class="o">-</span><span
class="n">Id</span><span class="p">:</span> 1
+
+<span class="n">POST</span> <span class="n">Products</span> <span
class="n">HTTP</span><span class="o">/</span>1<span class="p">.</span>1
+<span class="n">Content</span><span class="o">-</span><span
class="n">Type</span><span class="p">:</span> <span
class="n">application</span><span class="o">/</span><span class="n">json</span>
+
+<span class="p">{</span>"<span class="n">Name</span>"<span
class="p">:</span> "<span class="n">Test</span> <span
class="n">Product2</span>"<span class="p">,</span> "<span
class="n">Description</span>"<span class="p">:</span> "<span
class="n">This</span> <span class="n">is</span> <span class="n">a</span> <span
class="n">test</span> <span class="n">product</span>"<span
class="p">}</span>
+
+<span class="o">--</span><span class="n">changeset_abc</span>
+<span class="n">Content</span><span class="o">-</span><span
class="n">Type</span><span class="p">:</span> <span
class="n">application</span><span class="o">/</span><span class="n">http</span>
+<span class="n">Content</span><span class="o">-</span><span
class="n">Transfer</span><span class="o">-</span><span
class="n">Encoding</span><span class="p">:</span><span class="n">binary</span>
+<span class="n">Content</span><span class="o">-</span><span
class="n">ID</span><span class="p">:</span> 2
+
+<span class="n">PATCH</span> $1 <span class="n">HTTP</span><span
class="o">/</span>1<span class="p">.</span>1
+<span class="n">Content</span><span class="o">-</span><span
class="n">Type</span><span class="p">:</span> <span
class="n">application</span><span class="o">/</span><span class="n">json</span>
+<span class="n">Accept</span><span class="p">:</span> <span
class="n">application</span><span class="o">/</span><span class="n">json</span>
+
+<span class="p">{</span>"<span class="n">Description</span>"<span
class="p">:</span> "<span class="n">Invalid</span><span
class="p">....</span>
+
+<span class="o">--</span><span class="n">changeset_abc</span><span
class="o">--</span>
+<span class="o">--</span><span class="n">abc123</span><span class="o">--</span>
+</pre></div>
+
+
+<p>As you can see the reponse contains a single request response instead of a
Change Set response. The error message in stored in the response body.</p>
+<h1 id="5-links">5. Links<a class="headerlink" href="#5-links"
title="Permanent link">¶</a></h1>
+<h3 id="tutorials">Tutorials<a class="headerlink" href="#tutorials"
title="Permanent link">¶</a></h3>
+<p>Further topics to be covered by follow-up tutorials:</p>
+<ul>
+<li>Tutorial OData V4 service part 1: <a
href="/doc/odata4/tutorials/read/tutorial_read.html">Read Entity
Collection</a></li>
+<li>Tutorial OData V4 service part 2: <a
href="/doc/odata4/tutorials/readep/tutorial_readep.html">Read Entity, Read
Property</a> </li>
+<li>Tutorial OData V4 service part 3: <a
href="/doc/odata4/tutorials/write/tutorial_write.html">Write (Create, Update,
Delete Entity)</a></li>
+<li>Tutorial OData V4 service, part 4: <a
href="/doc/odata4/tutorials/navigation/tutorial_navigation.html">Navigation</a></li>
+<li>Tutorial OData V4 service, part 5.1: <a
href="/doc/odata4/tutorials/sqo_tcs/tutorial_sqo_tcs.html">System Query Options
$top, $skip, $count (this page)</a></li>
+<li>Tutorial OData V4 service, part 5.2: <a
href="/doc/odata4/tutorials/sqo_es/tutorial_sqo_es.html">System Query Options
$select, $expand</a></li>
+<li>Tutorial OData V4 service, part 5.3: <a
href="/doc/odata4/tutorials/sqo_o/tutorial_sqo_o.html">System Query Options
$orderby</a></li>
+<li>Tutorial OData V4 service, part 5.4: <a
href="/doc/odata4/tutorials/sqo_f/tutorial_sqo_f.html">System Query Options
$filter</a></li>
+<li>Tutoral ODATA V4 service, part 6: <a
href="/doc/odata4/tutorials/action/tutorial_action.html">Action and Function
Imports</a></li>
+<li>Tutoral ODATA V4 service, part 6: Batch Request support</li>
+</ul>
+<h3 id="code-and-repository">Code and Repository<a class="headerlink"
href="#code-and-repository" title="Permanent link">¶</a></h3>
+<ul>
+<li><a href="https://git-wip-us.apache.org/repos/asf/olingo-odata4">Git
Repository</a></li>
+<li><a href="/doc/odata4/tutorials/prerequisites/prerequisites.html">Guide -
To fetch the tutorial sources</a></li>
+<li><a
href="http://www.apache.org/dyn/closer.lua/olingo/odata4/4.0.0/DemoService_Tutorial.zip">Demo
Service source code as zip file (contains all tutorials)</a></li>
+</ul>
+<h3 id="further-reading">Further reading<a class="headerlink"
href="#further-reading" title="Permanent link">¶</a></h3>
+<ul>
+<li><a href="http://odata.org/">Official OData Homepage</a></li>
+<li><a href="http://www.odata.org/documentation/">OData documentation</a></li>
+<li><a href="/javadoc/odata4/index.html">Olingo Javadoc</a></li>
+</ul><div align="center">
+<p>Copyright © 2013-2015, The Apache Software Foundation<br>
+ Apache Olingo, Olingo, Apache,
the Apache feather, and
+ the Apache Olingo project logo are trademarks
of the Apache Software
+ Foundation.</p>
+ <small><a href="/doc/odata2/privacy.html">Privacy</a></small>
+ </div>
+ </div><!-- /container -->
+ <!-- Bootstrap core JavaScript
+ ================================================== -->
+ <!-- Placed at the end of the document so the pages load faster -->
+ <script src="/js/jquery.js" type="text/javascript">
+</script>
+ <script src="/js/bootstrap.js" type="text/javascript">
+ <script src="/js/offcanvas.js" type="text/javascript">
+</script>
+ <!-- Google Analytics: change UA-XXXXX-X to be your site's ID. -->
+ <script>
+ (function(b,o,i,l,e,r){b.GoogleAnalyticsObject=l;b[l]||(b[l]=
+ function(){(b[l].q=b[l].q||[]).push(arguments)});b[l].l=+new Date;
+ e=o.createElement(i);r=o.getElementsByTagName(i)[0];
+ e.src='//www.google-analytics.com/analytics.js';
+ r.parentNode.insertBefore(e,r)}(window,document,'script','ga'));
+ ga('create','UA-44963757-1');ga('send','pageview');
+ </script>
+ </body>
+</html>