Author: buildbot
Date: Wed Oct 25 05:03:57 2017
New Revision: 1020009
Log:
Staging update by buildbot for olingo
Added:
websites/staging/olingo/trunk/content/doc/odata4/tutorials/action/tutorial_bound_action.html
Modified:
websites/staging/olingo/trunk/content/ (props changed)
Propchange: websites/staging/olingo/trunk/content/
------------------------------------------------------------------------------
--- cms:source-revision (original)
+++ cms:source-revision Wed Oct 25 05:03:57 2017
@@ -1 +1 @@
-1807358
+1813248
Added:
websites/staging/olingo/trunk/content/doc/odata4/tutorials/action/tutorial_bound_action.html
==============================================================================
---
websites/staging/olingo/trunk/content/doc/odata4/tutorials/action/tutorial_bound_action.html
(added)
+++
websites/staging/olingo/trunk/content/doc/odata4/tutorials/action/tutorial_bound_action.html
Wed Oct 25 05:03:57 2017
@@ -0,0 +1,706 @@
+<!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 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>
+ <li><a href="/contribute.html">Contribute</a></li>
+
+ </ul>
+
+ <a class="navbar-right"
href="http://www.apache.org/foundation/" target="_blank">
+ <img class="navbar-right" height="50px" src="/img/asf_logo_url.svg"
alt="Apache Software Foundation">
+ </a>
+
+ </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-6-action-imports-and-function-imports">Part 6: Action Imports and
Function Imports<a class="headerlink"
href="#part-6-action-imports-and-function-imports" title="Permanent
link">¶</a></h1>
+<p><strong>Table of Contents</strong></p>
+<div class="toc">
+<ul>
+<li><a href="#how-to-build-an-odata-service-with-olingo-v4">How to build an
OData Service with Olingo V4</a></li>
+<li><a href="#part-6-action-imports-and-function-imports">Part 6: Action
Imports and Function Imports</a><ul>
+<li><a href="#introduction">Introduction</a></li>
+<li><a href="#preparation">Preparation</a></li>
+<li><a href="#implementation">Implementation</a><ul>
+<li><a href="#extend-the-metadata-model">Extend the Metadata model</a></li>
+<li><a href="#extend-the-data-store">Extend the data store</a></li>
+<li><a
href="#extend-the-entity-collection-and-the-entity-processor-to-handle-function-imports">Extend
the entity collection and the entity processor to handle function
imports</a></li>
+<li><a href="#implement-an-action-processor">Implement an action
processor</a></li>
+</ul>
+</li>
+<li><a href="#run-the-implemented-service">Run the implemented service</a></li>
+</ul>
+</li>
+<li><a href="#links">Links</a><ul>
+<li><a href="#tutorials">Tutorials</a></li>
+<li><a href="#code-and-repository">Code and Repository</a></li>
+<li><a href="#further-reading">Further reading</a></li>
+</ul>
+</li>
+</ul>
+</div>
+<h2 id="introduction">Introduction<a class="headerlink" href="#introduction"
title="Permanent link">¶</a></h2>
+<p>In the present tutorial, weâll implement a function import and an action
import as well.</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
<code>/samples/tutorials/p9_action</code></p>
+<p>The <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#_Toc406398201">OData
V4 specification</a> gives us a definition what <em>Functions</em>,
<em>Actions</em> are:</p>
+<blockquote>
+<p>Operations allow the execution of custom logic on parts of a data
+model. Functions are operations that do not have side effects and may
+support further composition, for example, with additional filter
+operations, functions or an action. Actions are operations that allow
+side effects, such as data modification, and cannot be further
+composed in order to avoid non-deterministic behavior. Actions and
+functions are either bound to a type, enabling them to be called as
+members of an instance of that type, or unbound, in which case they
+are called as static operations. Action imports and function imports
+enable unbound actions and functions to be called from the service
+root.</p>
+</blockquote>
+<p>In this short definition are several terms which are to be explained first.
As you might expect operation is the superordinate of functions and actions.
The result of operations can be:</p>
+<ul>
+<li>An <em>entity</em> or a <em>collection of entities</em></li>
+<li>A <em>primitive property</em> or a <em>collection of primitive
properties</em></li>
+<li>A <em>complex property</em> or a <em>collection of complex
properties</em></li>
+</ul>
+<p>In addition an <em>Action</em> can return void that means there is no
return value. A <em>Function</em> must return a value.</p>
+<p>The definition gives us some parts where function and actions can be used.
First an <em>Operation</em> can be bound or unbound. In this tutorial we will
focus on unbound operations. Unbound operations are something like static
methods in Java, so if one of these operations have parameters we have to pass
all of them explicit to the operation.</p>
+<p><strong>Example</strong></p>
+<p>For example there could be a function that calculates the VAT. The result
depends on the one hand from the net price and on the other hand from the
country in which the customer lives.</p>
+<p>Such a function can be expressed in the metadata document as follows</p>
+<div class="codehilite"><pre><span class="nt"><Function</span> <span
class="na">Name=</span><span class="s">"CalculateVAT"</span><span
class="nt">></span>
+ <span class="nt"><Parameter</span> <span class="na">Name=</span><span
class="s">"NetPrice"</span> <span class="na">Type=</span><span
class="s">"Edm.Decimal"</span> <span class="na">Nullable=</span><span
class="s">"false"</span><span class="nt">/></span>
+ <span class="nt"><Parameter</span> <span class="na">Name=</span><span
class="s">"Country"</span> <span class="na">Type=</span><span
class="s">"Edm.String"</span> <span class="na">Nullable=</span><span
class="s">"false"</span><span class="nt">/></span>
+
+ <span class="nt"><ReturnType</span> <span class="na">Type=</span><span
class="s">"Edm.Decimal"</span><span class="nt">/></span>
+<span class="nt"></Function></span>
+</pre></div>
+
+
+<p>To make this function statically callable we have to define a Function
Import.</p>
+<div class="codehilite"><pre><span class="nt"><EntityContainer</span> <span
class="na">Name=</span><span class="s">"Container"</span><span
class="nt">></span>
+ <span class="nt"><FunctionImport</span> <span
class="na">Name=</span><span class="s">"StaticCalculateVAT"</span>
+ <span class="na">Function=</span><span
class="s">"CalculateVAT"</span>
+ <span class="na">IncludeInServiceDocument=</span><span
class="s">"true"</span><span class="nt">/></span>
+<span class="nt"></EntityContainer></span>
+</pre></div>
+
+
+<p>To call such a Function Import the client issues a GET requests to a URL
identifying the function import. The parameters are passed by using the so
called inline parameter syntax. In this simple case such a call could look like
this:</p>
+<div class="codehilite"><pre><span class="n">http</span><span
class="p">:</span><span class="o">//</span><span class="n">host</span><span
class="o">/</span><span class="n">myService</span><span class="o">/</span><span
class="n">StaticCalculateVAT</span><span class="p">(</span><span
class="n">NetPrice</span><span class="p">=</span>123<span
class="p">.</span>00<span class="p">,</span><span class="n">Country</span><span
class="p">=</span>â<span class="n">US</span>â<span class="p">)</span>
+</pre></div>
+
+
+<p>The definition talks about composing of functions. By default every
function is Composable=false, that means there must be no further resource
parts after the function call and there must also be no system query options.
If a function is composable you are be able to use system query options. Which
options are allowed in particular is based on the return type of the function.
Further you can navigate to properties and use Navigation Properties to
navigate to related entities as well.</p>
+<p>The definition of Actions / Action Imports in metadata document is similar
to functions.</p>
+<div class="codehilite"><pre><span class="nt"><Action</span> <span
class="na">Name=</span><span class="s">"Reset"</span><span
class="nt">></span>
+ <span class="nt"><Parameter</span> <span class="na">Name=</span><span
class="s">"Amount"</span> <span class="na">Type=</span><span
class="s">"Edm.Int32"</span><span class="nt">/></span>
+<span class="nt"></Action></span>
+
+<span class="nt"><EntityContainer</span> <span class="na">Name=</span><span
class="s">"Container"</span><span class="nt">></span>
+ <span class="nt"><ActionImport</span> <span
class="na">Name=</span><span class="s">"StaticReset"</span> <span
class="na">Action=</span><span class="s">"Reset"</span><span
class="nt">/></span>
+<span class="nt"></EntityContainer></span>
+</pre></div>
+
+
+<p>As you can see, this function does not return any value and takes one
parameter â<em>Amount</em>â To call this action import, you have to issue
an POST request to</p>
+<div class="codehilite"><pre><span class="n">http</span><span
class="p">:</span><span class="o">//</span><span class="n">host</span><span
class="o">/</span><span class="n">myService</span><span class="o">/</span><span
class="n">StaticReset</span>
+</pre></div>
+
+
+<p>The parameters are passed within the body of the request. In this case such
a body could look like the following (JSON - Syntax):</p>
+<div class="codehilite"><pre><span class="p">{</span>
+ <span class="nt">"Amount"</span><span class="p">:</span> <span
class="mi">2</span>
+<span class="p">}</span>
+</pre></div>
+
+
+<p>As you read in the definition, actions can have side effects (modifying the
data) but cannot be composed like functions.</p>
+<h2 id="preparation">Preparation<a class="headerlink" href="#preparation"
title="Permanent link">¶</a></h2>
+<p>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.</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/p9_action_preparation.</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>
+<h2 id="implementation">Implementation<a class="headerlink"
href="#implementation" title="Permanent link">¶</a></h2>
+<p>We use the given data model you are familiar with. To keep things simple we
implement one function import and one action import.</p>
+<p><strong>Function Import: CountCategories</strong> <br />
+This function takes a mandatory parameter â<em>Amount</em>â. The function
returns a collection of categories with the very same number of related
products.</p>
+<p>After finishing the implementation the definition of the function should
look like this:</p>
+<div class="codehilite"><pre><span class="nt"><Function</span> <span
class="na">Name=</span><span class="s">"CountCategories"</span><span
class="nt">></span>
+ <span class="nt"><Parameter</span> <span class="na">Name=</span><span
class="s">"Amount"</span> <span class="na">Type=</span><span
class="s">"Edm.Int32"</span> <span class="na">Nullable=</span><span
class="s">"false"</span><span class="nt">/></span>
+ <span class="nt"><ReturnType</span> <span
class="na">Type=</span><span
class="s">"Collection(OData.Demo.Category)"</span><span
class="nt">/></span>
+<span class="nt"></Function></span>
+</pre></div>
+
+
+<p>As described in the previous tutorials, the type of the response determines
which processor interface will be called by the Olingo library. It is
<strong>important to know, that functions are dispatched to the traditional
processor interfaces</strong>.
+That means there are no special "FunctionProcessors". In our case, the
function returns a collection of Categories. So we have to extend the
<code>DemoEntityCollectionProcessor</code>. As you will see it is possible to
address a single entity by its key. So we have to extend the
<code>DemoEntityProcessor</code> as well to handle requests which responds a
single entity.</p>
+<p><strong>Action Import: Reset</strong> <br />
+This action takes an optional parameter â<em>Amount</em>â. The actions
resets the whole data of the service and creates <em># of Amount</em> products
with the related categories.</p>
+<p>After finishing the implementation the definition of the action should be
like this:</p>
+<div class="codehilite"><pre><span class="nt"><Action</span> <span
class="na">Name=</span><span class="s">"Reset"</span> <span
class="na">IsBound=</span><span class="s">"false"</span><span
class="nt">></span>
+ <span class="nt"><Parameter</span> <span class="na">Name=</span><span
class="s">"Amount"</span> <span class="na">Type=</span><span
class="s">"Edm.Int32"</span><span class="nt">/></span>
+<span class="nt"></Action></span>
+</pre></div>
+
+
+<p>While actions are called by using HTTP Method POST is nessesary to
introduce new processor interfaces for actions. So there exists a bunch of
interfaces, for each return type strictly one.</p>
+<p><strong>Steps</strong> </p>
+<ul>
+<li>Extend the Metadata model</li>
+<li>Extend the data store</li>
+<li>Extend the entity collection and the entity processor to handle function
imports</li>
+<li>Implement an action processor</li>
+</ul>
+<h3 id="extend-the-metadata-model">Extend the Metadata model<a
class="headerlink" href="#extend-the-metadata-model" title="Permanent
link">¶</a></h3>
+<p>Create the following constants in the DemoEdmProvider. These constants are
used to address the operations.</p>
+<div class="codehilite"><pre><span class="c1">// Action</span>
+<span class="kd">public</span> <span class="kd">static</span> <span
class="kd">final</span> <span class="n">String</span> <span
class="n">ACTION_RESET</span> <span class="o">=</span> <span
class="s">"Reset"</span><span class="o">;</span>
+<span class="kd">public</span> <span class="kd">static</span> <span
class="kd">final</span> <span class="n">FullQualifiedName</span> <span
class="n">ACTION_RESET_FQN</span> <span class="o">=</span> <span
class="k">new</span> <span class="n">FullQualifiedName</span><span
class="o">(</span><span class="n">NAMESPACE</span><span class="o">,</span>
<span class="n">ACTION_RESET</span><span class="o">);</span>
+
+<span class="c1">// Function</span>
+<span class="kd">public</span> <span class="kd">static</span> <span
class="kd">final</span> <span class="n">String</span> <span
class="n">FUNCTION_COUNT_CATEGORIES</span> <span class="o">=</span> <span
class="s">"CountCategories"</span><span class="o">;</span>
+<span class="kd">public</span> <span class="kd">static</span> <span
class="kd">final</span> <span class="n">FullQualifiedName</span> <span
class="n">FUNCTION_COUNT_CATEGORIES_FQN</span> <span class="o">=</span> <span
class="k">new</span> <span class="n">FullQualifiedName</span><span
class="o">(</span><span class="n">NAMESPACE</span><span class="o">,</span>
<span class="n">FUNCTION_COUNT_CATEGORIES</span><span class="o">);</span>
+
+<span class="c1">// Function/Action Parameters</span>
+<span class="kd">public</span> <span class="kd">static</span> <span
class="kd">final</span> <span class="n">String</span> <span
class="n">PARAMETER_AMOUNT</span> <span class="o">=</span> <span
class="s">"Amount"</span><span class="o">;</span>
+</pre></div>
+
+
+<p>The way to announce the operations is very similar to announcing
EntityTypes. We have to override some methods. Those methods provide the
definition of the Edm elements. We need methods for:</p>
+<ul>
+<li>Actions</li>
+<li>Functions</li>
+<li>Action Imports</li>
+<li>Function Imports</li>
+</ul>
+<p>The code is simple and straight forward. First, we check which function we
have to return. Then, a list of parameters and the return type are created. At
the end all parts are fit together and get returned as new
<code>CsdlFunction</code> Object.</p>
+<div class="codehilite"><pre><span class="nd">@Override</span>
+<span class="kd">public</span> <span class="n">List</span><span
class="o"><</span><span class="n">CsdlFunction</span><span
class="o">></span> <span class="n">getFunctions</span><span
class="o">(</span><span class="kd">final</span> <span
class="n">FullQualifiedName</span> <span class="n">functionName</span><span
class="o">)</span> <span class="o">{</span>
+ <span class="k">if</span> <span class="o">(</span><span
class="n">functionName</span><span class="o">.</span><span
class="na">equals</span><span class="o">(</span><span
class="n">FUNCTION_COUNT_CATEGORIES_FQN</span><span class="o">))</span> <span
class="o">{</span>
+ <span class="c1">// It is allowed to overload functions, so we have to
provide a list of functions for each function name</span>
+ <span class="kd">final</span> <span class="n">List</span><span
class="o"><</span><span class="n">CsdlFunction</span><span
class="o">></span> <span class="n">functions</span> <span class="o">=</span>
<span class="k">new</span> <span class="n">ArrayList</span><span
class="o"><</span><span class="n">CsdlFunction</span><span
class="o">>();</span>
+
+ <span class="c1">// Create the parameter for the function</span>
+ <span class="kd">final</span> <span class="n">CsdlParameter</span> <span
class="n">parameterAmount</span> <span class="o">=</span> <span
class="k">new</span> <span class="n">CsdlParameter</span><span
class="o">();</span>
+ <span class="n">parameterAmount</span><span class="o">.</span><span
class="na">setName</span><span class="o">(</span><span
class="n">PARAMETER_AMOUNT</span><span class="o">);</span>
+ <span class="n">parameterAmount</span><span class="o">.</span><span
class="na">setNullable</span><span class="o">(</span><span
class="kc">false</span><span class="o">);</span>
+ <span class="n">parameterAmount</span><span class="o">.</span><span
class="na">setType</span><span class="o">(</span><span
class="n">EdmPrimitiveTypeKind</span><span class="o">.</span><span
class="na">Int32</span><span class="o">.</span><span
class="na">getFullQualifiedName</span><span class="o">());</span>
+
+ <span class="c1">// Create the return type of the function</span>
+ <span class="kd">final</span> <span class="n">CsdlReturnType</span> <span
class="n">returnType</span> <span class="o">=</span> <span class="k">new</span>
<span class="n">CsdlReturnType</span><span class="o">();</span>
+ <span class="n">returnType</span><span class="o">.</span><span
class="na">setCollection</span><span class="o">(</span><span
class="kc">true</span><span class="o">);</span>
+ <span class="n">returnType</span><span class="o">.</span><span
class="na">setType</span><span class="o">(</span><span
class="n">ET_CATEGORY_FQN</span><span class="o">);</span>
+
+ <span class="c1">// Create the function</span>
+ <span class="kd">final</span> <span class="n">CsdlFunction</span> <span
class="n">function</span> <span class="o">=</span> <span class="k">new</span>
<span class="n">CsdlFunction</span><span class="o">();</span>
+ <span class="n">function</span><span class="o">.</span><span
class="na">setName</span><span class="o">(</span><span
class="n">FUNCTION_COUNT_CATEGORIES_FQN</span><span class="o">.</span><span
class="na">getName</span><span class="o">())</span>
+ <span class="o">.</span><span class="na">setParameters</span><span
class="o">(</span><span class="n">Arrays</span><span class="o">.</span><span
class="na">asList</span><span class="o">(</span><span
class="n">parameterAmount</span><span class="o">))</span>
+ <span class="o">.</span><span class="na">setReturnType</span><span
class="o">(</span><span class="n">returnType</span><span class="o">);</span>
+ <span class="n">functions</span><span class="o">.</span><span
class="na">add</span><span class="o">(</span><span
class="n">function</span><span class="o">);</span>
+
+ <span class="k">return</span> <span class="n">functions</span><span
class="o">;</span>
+ <span class="o">}</span>
+
+ <span class="k">return</span> <span class="kc">null</span><span
class="o">;</span>
+<span class="o">}</span>
+</pre></div>
+
+
+<p>We have created the function itself. To express that function can be called
statically we have to override the method <code>getFunctionImport()</code>.</p>
+<div class="codehilite"><pre><span class="nd">@Override</span>
+<span class="kd">public</span> <span class="n">CsdlFunctionImport</span> <span
class="nf">getFunctionImport</span><span class="o">(</span><span
class="n">FullQualifiedName</span> <span class="n">entityContainer</span><span
class="o">,</span> <span class="n">String</span> <span
class="n">functionImportName</span><span class="o">)</span> <span
class="o">{</span>
+ <span class="k">if</span><span class="o">(</span><span
class="n">entityContainer</span><span class="o">.</span><span
class="na">equals</span><span class="o">(</span><span
class="n">CONTAINER</span><span class="o">))</span> <span class="o">{</span>
+ <span class="k">if</span><span class="o">(</span><span
class="n">functionImportName</span><span class="o">.</span><span
class="na">equals</span><span class="o">(</span><span
class="n">FUNCTION_COUNT_CATEGORIES_FQN</span><span class="o">.</span><span
class="na">getName</span><span class="o">()))</span> <span class="o">{</span>
+ <span class="k">return</span> <span class="k">new</span> <span
class="nf">CsdlFunctionImport</span><span class="o">()</span>
+ <span class="o">.</span><span class="na">setName</span><span
class="o">(</span><span class="n">functionImportName</span><span
class="o">)</span>
+ <span class="o">.</span><span
class="na">setFunction</span><span class="o">(</span><span
class="n">FUNCTION_COUNT_CATEGORIES_FQN</span><span class="o">)</span>
+ <span class="o">.</span><span
class="na">setEntitySet</span><span class="o">(</span><span
class="n">ES_CATEGORIES_NAME</span><span class="o">)</span>
+ <span class="o">.</span><span
class="na">setIncludeInServiceDocument</span><span class="o">(</span><span
class="kc">true</span><span class="o">);</span>
+ <span class="o">}</span>
+ <span class="o">}</span>
+
+ <span class="k">return</span> <span class="kc">null</span><span
class="o">;</span>
+<span class="o">}</span>
+</pre></div>
+
+
+<p>To define the actions and the action imports the <code>getActions()</code>
and <code>getActionImport()</code> methods have to be overriden and the
necessary code is quite similar to the functions sample above:</p>
+<div class="codehilite"><pre><span class="nd">@Override</span>
+<span class="kd">public</span> <span class="n">List</span><span
class="o"><</span><span class="n">CsdlAction</span><span
class="o">></span> <span class="n">getActions</span><span
class="o">(</span><span class="kd">final</span> <span
class="n">FullQualifiedName</span> <span class="n">actionName</span><span
class="o">)</span> <span class="o">{</span>
+ <span class="k">if</span><span class="o">(</span><span
class="n">actionName</span><span class="o">.</span><span
class="na">equals</span><span class="o">(</span><span
class="n">ACTION_RESET_FQN</span><span class="o">))</span> <span
class="o">{</span>
+ <span class="c1">// It is allowed to overload actions, so we have to
provide a list of Actions for each action name</span>
+ <span class="kd">final</span> <span class="n">List</span><span
class="o"><</span><span class="n">CsdlAction</span><span
class="o">></span> <span class="n">actions</span> <span class="o">=</span>
<span class="k">new</span> <span class="n">ArrayList</span><span
class="o"><</span><span class="n">CsdlAction</span><span
class="o">>();</span>
+
+ <span class="c1">// Create parameters</span>
+ <span class="kd">final</span> <span class="n">List</span><span
class="o"><</span><span class="n">CsdlParameter</span><span
class="o">></span> <span class="n">parameters</span> <span
class="o">=</span> <span class="k">new</span> <span
class="n">ArrayList</span><span class="o"><</span><span
class="n">CsdlParameter</span><span class="o">>();</span>
+ <span class="kd">final</span> <span class="n">CsdlParameter</span> <span
class="n">parameter</span> <span class="o">=</span> <span class="k">new</span>
<span class="n">CsdlParameter</span><span class="o">();</span>
+ <span class="n">parameter</span><span class="o">.</span><span
class="na">setName</span><span class="o">(</span><span
class="n">PARAMETER_AMOUNT</span><span class="o">);</span>
+ <span class="n">parameter</span><span class="o">.</span><span
class="na">setType</span><span class="o">(</span><span
class="n">EdmPrimitiveTypeKind</span><span class="o">.</span><span
class="na">Int32</span><span class="o">.</span><span
class="na">getFullQualifiedName</span><span class="o">());</span>
+ <span class="n">parameters</span><span class="o">.</span><span
class="na">add</span><span class="o">(</span><span
class="n">parameter</span><span class="o">);</span>
+
+ <span class="c1">// Create the Csdl Action</span>
+ <span class="kd">final</span> <span class="n">CsdlAction</span> <span
class="n">action</span> <span class="o">=</span> <span class="k">new</span>
<span class="n">CsdlAction</span><span class="o">();</span>
+ <span class="n">action</span><span class="o">.</span><span
class="na">setName</span><span class="o">(</span><span
class="n">ACTION_RESET_FQN</span><span class="o">.</span><span
class="na">getName</span><span class="o">());</span>
+ <span class="n">action</span><span class="o">.</span><span
class="na">setParameters</span><span class="o">(</span><span
class="n">parameters</span><span class="o">);</span>
+ <span class="n">actions</span><span class="o">.</span><span
class="na">add</span><span class="o">(</span><span class="n">action</span><span
class="o">);</span>
+
+ <span class="k">return</span> <span class="n">actions</span><span
class="o">;</span>
+ <span class="o">}</span>
+
+ <span class="k">return</span> <span class="kc">null</span><span
class="o">;</span>
+<span class="o">}</span>
+
+<span class="nd">@Override</span>
+<span class="kd">public</span> <span class="n">CsdlActionImport</span> <span
class="nf">getActionImport</span><span class="o">(</span><span
class="kd">final</span> <span class="n">FullQualifiedName</span> <span
class="n">entityContainer</span><span class="o">,</span> <span
class="kd">final</span> <span class="n">String</span> <span
class="n">actionImportName</span><span class="o">)</span> <span
class="o">{</span>
+ <span class="k">if</span><span class="o">(</span><span
class="n">entityContainer</span><span class="o">.</span><span
class="na">equals</span><span class="o">(</span><span
class="n">CONTAINER</span><span class="o">))</span> <span class="o">{</span>
+ <span class="k">if</span><span class="o">(</span><span
class="n">actionImportName</span><span class="o">.</span><span
class="na">equals</span><span class="o">(</span><span
class="n">ACTION_RESET_FQN</span><span class="o">.</span><span
class="na">getName</span><span class="o">()))</span> <span class="o">{</span>
+ <span class="k">return</span> <span class="k">new</span> <span
class="nf">CsdlActionImport</span><span class="o">()</span>
+ <span class="o">.</span><span class="na">setName</span><span
class="o">(</span><span class="n">actionImportName</span><span
class="o">)</span>
+ <span class="o">.</span><span class="na">setAction</span><span
class="o">(</span><span class="n">ACTION_RESET_FQN</span><span
class="o">);</span>
+ <span class="o">}</span>
+ <span class="o">}</span>
+
+ <span class="k">return</span> <span class="kc">null</span><span
class="o">;</span>
+<span class="o">}</span>
+</pre></div>
+
+
+<p>Finally we have to announce these operations to the schema and the entity
container.
+Add the following lines to the method <code>getSchemas()</code>:</p>
+<div class="codehilite"><pre><span class="c1">// add actions</span>
+<span class="n">List</span><span class="o"><</span><span
class="n">CsdlAction</span><span class="o">></span> <span
class="n">actions</span> <span class="o">=</span> <span class="k">new</span>
<span class="n">ArrayList</span><span class="o"><</span><span
class="n">CsdlAction</span><span class="o">>();</span>
+<span class="n">actions</span><span class="o">.</span><span
class="na">addAll</span><span class="o">(</span><span
class="n">getActions</span><span class="o">(</span><span
class="n">ACTION_RESET_FQN</span><span class="o">));</span>
+<span class="n">schema</span><span class="o">.</span><span
class="na">setActions</span><span class="o">(</span><span
class="n">actions</span><span class="o">);</span>
+
+<span class="c1">// add functions</span>
+<span class="n">List</span><span class="o"><</span><span
class="n">CsdlFunction</span><span class="o">></span> <span
class="n">functions</span> <span class="o">=</span> <span class="k">new</span>
<span class="n">ArrayList</span><span class="o"><</span><span
class="n">CsdlFunction</span><span class="o">>();</span>
+<span class="n">functions</span><span class="o">.</span><span
class="na">addAll</span><span class="o">(</span><span
class="n">getFunctions</span><span class="o">(</span><span
class="n">FUNCTION_COUNT_CATEGORIES_FQN</span><span class="o">));</span>
+<span class="n">schema</span><span class="o">.</span><span
class="na">setFunctions</span><span class="o">(</span><span
class="n">functions</span><span class="o">);</span>
+</pre></div>
+
+
+<p>Also add the following lines to the method
<code>getEntityContainer()</code></p>
+<div class="codehilite"><pre><span class="c1">// Create function imports</span>
+<span class="n">List</span><span class="o"><</span><span
class="n">CsdlFunctionImport</span><span class="o">></span> <span
class="n">functionImports</span> <span class="o">=</span> <span
class="k">new</span> <span class="n">ArrayList</span><span
class="o"><</span><span class="n">CsdlFunctionImport</span><span
class="o">>();</span>
+<span class="n">functionImports</span><span class="o">.</span><span
class="na">add</span><span class="o">(</span><span
class="n">getFunctionImport</span><span class="o">(</span><span
class="n">CONTAINER</span><span class="o">,</span> <span
class="n">FUNCTION_COUNT_CATEGORIES</span><span class="o">));</span>
+
+<span class="c1">// Create action imports</span>
+<span class="n">List</span><span class="o"><</span><span
class="n">CsdlActionImport</span><span class="o">></span> <span
class="n">actionImports</span> <span class="o">=</span> <span
class="k">new</span> <span class="n">ArrayList</span><span
class="o"><</span><span class="n">CsdlActionImport</span><span
class="o">>();</span>
+<span class="n">actionImports</span><span class="o">.</span><span
class="na">add</span><span class="o">(</span><span
class="n">getActionImport</span><span class="o">(</span><span
class="n">CONTAINER</span><span class="o">,</span> <span
class="n">ACTION_RESET</span><span class="o">));</span>
+
+<span class="n">entityContainer</span><span class="o">.</span><span
class="na">setFunctionImports</span><span class="o">(</span><span
class="n">functionImports</span><span class="o">);</span>
+<span class="n">entityContainer</span><span class="o">.</span><span
class="na">setActionImports</span><span class="o">(</span><span
class="n">actionImports</span><span class="o">);</span>
+</pre></div>
+
+
+<h3 id="extend-the-data-store">Extend the data store<a class="headerlink"
href="#extend-the-data-store" title="Permanent link">¶</a></h3>
+<p>We need two methods in the data store to read the function import
<code>CountCategories</code>.</p>
+<p>The first method returns a collection of entites and the second returns a
single entity of this collection.</p>
+<div class="codehilite"><pre><span class="kd">public</span> <span
class="n">EntityCollection</span> <span
class="nf">readFunctionImportCollection</span><span class="o">(</span><span
class="kd">final</span> <span class="n">UriResourceFunction</span> <span
class="n">uriResourceFunction</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="kd">throws</span> <span class="n">ODataApplicationException</span> <span
class="o">{</span>
+
+ <span class="k">if</span><span class="o">(</span><span
class="n">DemoEdmProvider</span><span class="o">.</span><span
class="na">FUNCTION_COUNT_CATEGORIES</span><span class="o">.</span><span
class="na">equals</span><span class="o">(</span><span
class="n">uriResourceFunction</span><span class="o">.</span><span
class="na">getFunctionImport</span><span class="o">().</span><span
class="na">getName</span><span class="o">()))</span> <span class="o">{</span>
+ <span class="c1">// Get the parameter of the function</span>
+ <span class="kd">final</span> <span class="n">UriParameter</span> <span
class="n">parameterAmount</span> <span class="o">=</span> <span
class="n">uriResourceFunction</span><span class="o">.</span><span
class="na">getParameters</span><span class="o">().</span><span
class="na">get</span><span class="o">(</span><span class="mi">0</span><span
class="o">);</span>
+
+ <span class="c1">// Try to convert the parameter to an Integer.</span>
+ <span class="c1">// We have to take care, that the type of parameter fits
to its EDM declaration</span>
+ <span class="kt">int</span> <span class="n">amount</span><span
class="o">;</span>
+ <span class="k">try</span> <span class="o">{</span>
+ <span class="n">amount</span> <span class="o">=</span> <span
class="n">Integer</span><span class="o">.</span><span
class="na">parseInt</span><span class="o">(</span><span
class="n">parameterAmount</span><span class="o">.</span><span
class="na">getText</span><span class="o">());</span>
+ <span class="o">}</span> <span class="k">catch</span><span
class="o">(</span><span class="n">NumberFormatException</span> <span
class="n">e</span><span class="o">)</span> <span class="o">{</span>
+ <span class="k">throw</span> <span class="k">new</span> <span
class="nf">ODataApplicationException</span><span class="o">(</span><span
class="s">"Type of parameter Amount must be Edm.Int32"</span><span
class="o">,</span>
+ <span class="n">HttpStatusCode</span><span class="o">.</span><span
class="na">BAD_REQUEST</span><span class="o">.</span><span
class="na">getStatusCode</span><span class="o">(),</span> <span
class="n">Locale</span><span class="o">.</span><span
class="na">ENGLISH</span><span class="o">);</span>
+ <span class="o">}</span>
+
+ <span class="kd">final</span> <span class="n">EdmEntityType</span> <span
class="n">productEntityType</span> <span class="o">=</span> <span
class="n">serviceMetadata</span><span class="o">.</span><span
class="na">getEdm</span><span class="o">().</span><span
class="na">getEntityType</span><span class="o">(</span><span
class="n">DemoEdmProvider</span><span class="o">.</span><span
class="na">ET_PRODUCT_FQN</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">resultEntityList</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="c1">// Loop over all categories and check how many products
are linked</span>
+ <span class="k">for</span><span class="o">(</span><span
class="kd">final</span> <span class="n">Entity</span> <span
class="n">category</span> <span class="o">:</span> <span
class="n">categoryList</span><span class="o">)</span> <span class="o">{</span>
+ <span class="kd">final</span> <span class="n">EntityCollection</span>
<span class="n">products</span> <span class="o">=</span> <span
class="n">getRelatedEntityCollection</span><span class="o">(</span><span
class="n">category</span><span class="o">,</span> <span
class="n">productEntityType</span><span class="o">);</span>
+ <span class="k">if</span><span class="o">(</span><span
class="n">products</span><span class="o">.</span><span
class="na">getEntities</span><span class="o">().</span><span
class="na">size</span><span class="o">()</span> <span class="o">==</span> <span
class="n">amount</span><span class="o">)</span> <span class="o">{</span>
+ <span class="n">resultEntityList</span><span class="o">.</span><span
class="na">add</span><span class="o">(</span><span
class="n">category</span><span class="o">);</span>
+ <span class="o">}</span>
+ <span class="o">}</span>
+
+ <span class="kd">final</span> <span class="n">EntityCollection</span>
<span class="n">resultCollection</span> <span class="o">=</span> <span
class="k">new</span> <span class="n">EntityCollection</span><span
class="o">();</span>
+ <span class="n">resultCollection</span><span class="o">.</span><span
class="na">getEntities</span><span class="o">().</span><span
class="na">addAll</span><span class="o">(</span><span
class="n">resultEntityList</span><span class="o">);</span>
+ <span class="k">return</span> <span class="n">resultCollection</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">ODataApplicationException</span><span class="o">(</span><span
class="s">"Function not implemented"</span><span class="o">,</span>
<span class="n">HttpStatusCode</span><span class="o">.</span><span
class="na">NOT_IMPLEMENTED</span><span class="o">.</span><span
class="na">getStatusCode</span><span class="o">(),</span>
+ <span class="n">Locale</span><span class="o">.</span><span
class="na">ROOT</span><span class="o">);</span>
+ <span class="o">}</span>
+<span class="o">}</span>
+
+<span class="kd">public</span> <span class="n">Entity</span> <span
class="nf">readFunctionImportEntity</span><span class="o">(</span><span
class="kd">final</span> <span class="n">UriResourceFunction</span> <span
class="n">uriResourceFunction</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="kd">throws</span> <span class="n">ODataApplicationException</span> <span
class="o">{</span>
+
+ <span class="kd">final</span> <span class="n">EntityCollection</span> <span
class="n">entityCollection</span> <span class="o">=</span> <span
class="n">readFunctionImportCollection</span><span class="o">(</span><span
class="n">uriResourceFunction</span><span class="o">,</span> <span
class="n">serviceMetadata</span><span class="o">);</span>
+ <span class="kd">final</span> <span class="n">EdmEntityType</span> <span
class="n">edmEntityType</span> <span class="o">=</span> <span
class="o">(</span><span class="n">EdmEntityType</span><span class="o">)</span>
<span class="n">uriResourceFunction</span><span class="o">.</span><span
class="na">getFunction</span><span class="o">().</span><span
class="na">getReturnType</span><span class="o">().</span><span
class="na">getType</span><span class="o">();</span>
+
+ <span class="k">return</span> <span class="n">Util</span><span
class="o">.</span><span class="na">findEntity</span><span
class="o">(</span><span class="n">edmEntityType</span><span class="o">,</span>
<span class="n">entityCollection</span><span class="o">,</span> <span
class="n">uriResourceFunction</span><span class="o">.</span><span
class="na">getKeyPredicates</span><span class="o">());</span>
+<span class="o">}</span>
+</pre></div>
+
+
+<p>We also create two methods to reset the data of our service.</p>
+<div class="codehilite"><pre><span class="kd">public</span> <span
class="kt">void</span> <span class="nf">resetDataSet</span><span
class="o">(</span><span class="kd">final</span> <span class="kt">int</span>
<span class="n">amount</span><span class="o">)</span> <span class="o">{</span>
+ <span class="c1">// Replace the old lists with empty ones</span>
+ <span class="n">productList</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="n">categoryList</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="c1">// Create new sample data</span>
+ <span class="n">initProductSampleData</span><span class="o">();</span>
+ <span class="n">initCategorySampleData</span><span class="o">();</span>
+
+ <span class="c1">// Truncate the lists</span>
+ <span class="k">if</span><span class="o">(</span><span
class="n">amount</span> <span class="o"><</span> <span
class="n">productList</span><span class="o">.</span><span
class="na">size</span><span class="o">())</span> <span class="o">{</span>
+ <span class="n">productList</span> <span class="o">=</span> <span
class="n">productList</span><span class="o">.</span><span
class="na">subList</span><span class="o">(</span><span class="mi">0</span><span
class="o">,</span> <span class="n">amount</span><span class="o">);</span>
+ <span class="c1">// Products 0, 1 are linked to category 0</span>
+ <span class="c1">// Products 2, 3 are linked to category 1</span>
+ <span class="c1">// Products 4, 5 are linked to category 2</span>
+ <span class="n">categoryList</span> <span class="o">=</span> <span
class="n">categoryList</span><span class="o">.</span><span
class="na">subList</span><span class="o">(</span><span class="mi">0</span><span
class="o">,</span> <span class="o">(</span><span class="n">amount</span> <span
class="o">/</span> <span class="mi">2</span><span class="o">)</span> <span
class="o">+</span> <span class="mi">1</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">resetDataSet</span><span class="o">()</span> <span class="o">{</span>
+ <span class="n">resetDataSet</span><span class="o">(</span><span
class="n">Integer</span><span class="o">.</span><span
class="na">MAX_VALUE</span><span class="o">);</span>
+<span class="o">}</span>
+</pre></div>
+
+
+<h3
id="extend-the-entity-collection-and-the-entity-processor-to-handle-function-imports">Extend
the entity collection and the entity processor to handle function imports<a
class="headerlink"
href="#extend-the-entity-collection-and-the-entity-processor-to-handle-function-imports"
title="Permanent link">¶</a></h3>
+<p>We start with the entity collection processor
<code>DemoEntityCollectionProcessor</code>.
+To keep things simple, the first steps is to distinguish between entity
collections and function imports.
+A cleverer implementation can handle both cases in one method to avoid
duplicated code.</p>
+<p>The recent implementation of the <code>readEntityCollection()</code> has
been moved to <code>readEntityCollectionInternal()</code></p>
+<div class="codehilite"><pre><span class="kd">public</span> <span
class="kt">void</span> <span class="nf">readEntityCollection</span><span
class="o">(</span><span class="n">ODataRequest</span> <span
class="n">request</span><span class="o">,</span> <span
class="n">ODataResponse</span> <span class="n">response</span><span
class="o">,</span> <span class="n">UriInfo</span> <span
class="n">uriInfo</span><span class="o">,</span> <span
class="n">ContentType</span> <span class="n">responseFormat</span><span
class="o">)</span> <span class="kd">throws</span> <span
class="n">ODataApplicationException</span><span class="o">,</span> <span
class="n">SerializerException</span> <span class="o">{</span>
+
+ <span class="kd">final</span> <span class="n">UriResource</span> <span
class="n">firstResourceSegment</span> <span class="o">=</span> <span
class="n">uriInfo</span><span class="o">.</span><span
class="na">getUriResourceParts</span><span class="o">().</span><span
class="na">get</span><span class="o">(</span><span class="mi">0</span><span
class="o">);</span>
+
+ <span class="k">if</span><span class="o">(</span><span
class="n">firstResourceSegment</span> <span class="k">instanceof</span> <span
class="n">UriResourceEntitySet</span><span class="o">)</span> <span
class="o">{</span>
+ <span class="n">readEntityCollectionInternal</span><span
class="o">(</span><span class="n">request</span><span class="o">,</span> <span
class="n">response</span><span class="o">,</span> <span
class="n">uriInfo</span><span class="o">,</span> <span
class="n">responseFormat</span><span class="o">);</span>
+ <span class="o">}</span> <span class="k">else</span> <span
class="k">if</span><span class="o">(</span><span
class="n">firstResourceSegment</span> <span class="k">instanceof</span> <span
class="n">UriResourceFunction</span><span class="o">)</span> <span
class="o">{</span>
+ <span class="n">readFunctionImportCollection</span><span
class="o">(</span><span class="n">request</span><span class="o">,</span> <span
class="n">response</span><span class="o">,</span> <span
class="n">uriInfo</span><span class="o">,</span> <span
class="n">responseFormat</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">ODataApplicationException</span><span class="o">(</span><span
class="s">"Not implemented"</span><span class="o">,</span>
+ <span class="n">HttpStatusCode</span><span class="o">.</span><span
class="na">NOT_IMPLEMENTED</span><span class="o">.</span><span
class="na">getStatusCode</span><span class="o">(),</span>
+ <span class="n">Locale</span><span class="o">.</span><span
class="na">ENGLISH</span><span class="o">);</span>
+ <span class="o">}</span>
+<span class="o">}</span>
+</pre></div>
+
+
+<p>Like by reading <em>entity collections</em>, the first step is to analyze
the URI and then fetch the data (of the function import).</p>
+<div class="codehilite"><pre><span class="kd">private</span> <span
class="kt">void</span> <span
class="nf">readFunctionImportCollection</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">final</span> <span class="n">UriInfo</span> <span
class="n">uriInfo</span><span class="o">,</span> <span class="kd">final</span>
<span class="n">ContentType</span> <span class="n">responseFormat</span><span
class="o">)</span> <span class="kd">throws</span> <span
class="n">ODataApplicationException</span><span class="o">,</span> <span
class="n">SerializerException</span> <span class="o">{</span>
+
+ <span class="c1">// 1st step: Analyze the URI and fetch the entity
collection returned by the function import</span>
+ <span class="c1">// Function Imports are always the first segment of the
resource path</span>
+ <span class="kd">final</span> <span class="n">UriResource</span> <span
class="n">firstSegment</span> <span class="o">=</span> <span
class="n">uriInfo</span><span class="o">.</span><span
class="na">getUriResourceParts</span><span class="o">().</span><span
class="na">get</span><span class="o">(</span><span class="mi">0</span><span
class="o">);</span>
+
+ <span class="k">if</span><span class="o">(!(</span><span
class="n">firstSegment</span> <span class="k">instanceof</span> <span
class="n">UriResourceFunction</span><span class="o">))</span> <span
class="o">{</span>
+ <span class="k">throw</span> <span class="k">new</span> <span
class="nf">ODataApplicationException</span><span class="o">(</span><span
class="s">"Not implemented"</span><span class="o">,</span>
+ <span class="n">HttpStatusCode</span><span class="o">.</span><span
class="na">NOT_IMPLEMENTED</span><span class="o">.</span><span
class="na">getStatusCode</span><span class="o">(),</span> <span
class="n">Locale</span><span class="o">.</span><span
class="na">ENGLISH</span><span class="o">);</span>
+ <span class="o">}</span>
+
+ <span class="kd">final</span> <span class="n">UriResourceFunction</span>
<span class="n">uriResourceFunction</span> <span class="o">=</span> <span
class="o">(</span><span class="n">UriResourceFunction</span><span
class="o">)</span> <span class="n">firstSegment</span><span class="o">;</span>
+ <span class="kd">final</span> <span class="n">EntityCollection</span> <span
class="n">entityCol</span> <span class="o">=</span> <span
class="n">storage</span><span class="o">.</span><span
class="na">readFunctionImportCollection</span><span class="o">(</span><span
class="n">uriResourceFunction</span><span class="o">,</span> <span
class="n">serviceMetadata</span><span class="o">);</span>
+</pre></div>
+
+
+<p>Then the result has to be serialized. The only difference to entity sets is
the way how the <code>EdmEntityType</code> is determined.</p>
+<div class="codehilite"><pre> <span class="c1">// 2nd step: Serialize the
response entity</span>
+ <span class="kd">final</span> <span class="n">EdmEntityType</span> <span
class="n">edmEntityType</span> <span class="o">=</span> <span
class="o">(</span><span class="n">EdmEntityType</span><span class="o">)</span>
<span class="n">uriResourceFunction</span><span class="o">.</span><span
class="na">getFunction</span><span class="o">().</span><span
class="na">getReturnType</span><span class="o">().</span><span
class="na">getType</span><span class="o">();</span>
+ <span class="kd">final</span> <span class="n">ContextURL</span> <span
class="n">contextURL</span> <span class="o">=</span> <span
class="n">ContextURL</span><span class="o">.</span><span
class="na">with</span><span class="o">().</span><span
class="na">asCollection</span><span class="o">().</span><span
class="na">type</span><span class="o">(</span><span
class="n">edmEntityType</span><span class="o">).</span><span
class="na">build</span><span class="o">();</span>
+ <span class="n">EntityCollectionSerializerOptions</span> <span
class="n">opts</span> <span class="o">=</span> <span
class="n">EntityCollectionSerializerOptions</span><span class="o">.</span><span
class="na">with</span><span class="o">().</span><span
class="na">contextURL</span><span class="o">(</span><span
class="n">contextURL</span><span class="o">).</span><span
class="na">build</span><span class="o">();</span>
+ <span class="kd">final</span> <span class="n">ODataSerializer</span> <span
class="n">serializer</span> <span class="o">=</span> <span
class="n">odata</span><span class="o">.</span><span
class="na">createSerializer</span><span class="o">(</span><span
class="n">responseFormat</span><span class="o">);</span>
+ <span class="kd">final</span> <span class="n">SerializerResult</span> <span
class="n">serializerResult</span> <span class="o">=</span> <span
class="n">serializer</span><span class="o">.</span><span
class="na">entityCollection</span><span class="o">(</span><span
class="n">serviceMetadata</span><span class="o">,</span> <span
class="n">edmEntityType</span><span class="o">,</span> <span
class="n">entityCol</span><span class="o">,</span> <span
class="n">opts</span><span class="o">);</span>
+
+ <span class="c1">// 3rd configure the response object</span>
+ <span class="n">response</span><span class="o">.</span><span
class="na">setContent</span><span class="o">(</span><span
class="n">serializerResult</span><span class="o">.</span><span
class="na">getContent</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">OK</span><span class="o">.</span><span
class="na">getStatusCode</span><span class="o">());</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">responseFormat</span><span class="o">.</span><span
class="na">toContentTypeString</span><span class="o">());</span>
+<span class="o">}</span>
+</pre></div>
+
+
+<p>Next we will implement the processor to read a <em>single entity</em>. The
implementation is quite similar to the implementation of the collection
processor.</p>
+<div class="codehilite"><pre><span class="kd">public</span> <span
class="kt">void</span> <span class="nf">readEntity</span><span
class="o">(</span><span class="n">ODataRequest</span> <span
class="n">request</span><span class="o">,</span> <span
class="n">ODataResponse</span> <span class="n">response</span><span
class="o">,</span> <span class="n">UriInfo</span> <span
class="n">uriInfo</span><span class="o">,</span> <span
class="n">ContentType</span> <span class="n">responseFormat</span><span
class="o">)</span>
+ <span class="kd">throws</span> <span
class="n">ODataApplicationException</span><span class="o">,</span> <span
class="n">SerializerException</span> <span class="o">{</span>
+
+ <span class="c1">// The sample service supports only functions imports and
entity sets.</span>
+ <span class="c1">// We do not care about bound functions and composable
functions.</span>
+
+ <span class="n">UriResource</span> <span class="n">uriResource</span> <span
class="o">=</span> <span class="n">uriInfo</span><span class="o">.</span><span
class="na">getUriResourceParts</span><span class="o">().</span><span
class="na">get</span><span class="o">(</span><span class="mi">0</span><span
class="o">);</span>
+
+ <span class="k">if</span><span class="o">(</span><span
class="n">uriResource</span> <span class="k">instanceof</span> <span
class="n">UriResourceEntitySet</span><span class="o">)</span> <span
class="o">{</span>
+ <span class="n">readEntityInternal</span><span class="o">(</span><span
class="n">request</span><span class="o">,</span> <span
class="n">response</span><span class="o">,</span> <span
class="n">uriInfo</span><span class="o">,</span> <span
class="n">responseFormat</span><span class="o">);</span>
+ <span class="o">}</span> <span class="k">else</span> <span
class="k">if</span><span class="o">(</span><span class="n">uriResource</span>
<span class="k">instanceof</span> <span
class="n">UriResourceFunction</span><span class="o">)</span> <span
class="o">{</span>
+ <span class="n">readFunctionImportInternal</span><span
class="o">(</span><span class="n">request</span><span class="o">,</span> <span
class="n">response</span><span class="o">,</span> <span
class="n">uriInfo</span><span class="o">,</span> <span
class="n">responseFormat</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">ODataApplicationException</span><span class="o">(</span><span
class="s">"Only EntitySet is supported"</span><span class="o">,</span>
+ <span class="n">HttpStatusCode</span><span class="o">.</span><span
class="na">NOT_IMPLEMENTED</span><span class="o">.</span><span
class="na">getStatusCode</span><span class="o">(),</span> <span
class="n">Locale</span><span class="o">.</span><span
class="na">ENGLISH</span><span class="o">);</span>
+ <span class="o">}</span>
+<span class="o">}</span>
+
+<span class="kd">private</span> <span class="kt">void</span> <span
class="nf">readFunctionImportInternal</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">final</span> <span class="n">UriInfo</span> <span
class="n">uriInfo</span><span class="o">,</span> <span class="kd">final</span>
<span class="n">ContentType</span> <span class="n">responseFormat</span><span
class="o">)</span> <span class="kd">throws</span> <span
class="n">ODataApplicationException</span><span class="o">,</span> <span
class="n">SerializerException</span> <span class="o">{</span>
+
+ <span class="c1">// 1st step: Analyze the URI and fetch the entity returned
by the function import</span>
+ <span class="c1">// Function Imports are always the first segment of the
resource path</span>
+ <span class="kd">final</span> <span class="n">UriResource</span> <span
class="n">firstSegment</span> <span class="o">=</span> <span
class="n">uriInfo</span><span class="o">.</span><span
class="na">getUriResourceParts</span><span class="o">().</span><span
class="na">get</span><span class="o">(</span><span class="mi">0</span><span
class="o">);</span>
+
+ <span class="k">if</span><span class="o">(!(</span><span
class="n">firstSegment</span> <span class="k">instanceof</span> <span
class="n">UriResourceFunction</span><span class="o">))</span> <span
class="o">{</span>
+ <span class="k">throw</span> <span class="k">new</span> <span
class="nf">ODataApplicationException</span><span class="o">(</span><span
class="s">"Not implemented"</span><span class="o">,</span>
+ <span class="n">HttpStatusCode</span><span class="o">.</span><span
class="na">NOT_IMPLEMENTED</span><span class="o">.</span><span
class="na">getStatusCode</span><span class="o">(),</span> <span
class="n">Locale</span><span class="o">.</span><span
class="na">ENGLISH</span><span class="o">);</span>
+ <span class="o">}</span>
+
+ <span class="kd">final</span> <span class="n">UriResourceFunction</span>
<span class="n">uriResourceFunction</span> <span class="o">=</span> <span
class="o">(</span><span class="n">UriResourceFunction</span><span
class="o">)</span> <span class="n">firstSegment</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">storage</span><span class="o">.</span><span
class="na">readFunctionImportEntity</span><span class="o">(</span><span
class="n">uriResourceFunction</span><span class="o">,</span> <span
class="n">serviceMetadata</span><span class="o">);</span>
+
+ <span class="k">if</span><span class="o">(</span><span
class="n">entity</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">ODataApplicationException</span><span class="o">(</span><span
class="s">"Nothing found."</span><span class="o">,</span>
+ <span class="n">HttpStatusCode</span><span class="o">.</span><span
class="na">NOT_FOUND</span><span class="o">.</span><span
class="na">getStatusCode</span><span class="o">(),</span> <span
class="n">Locale</span><span class="o">.</span><span
class="na">ROOT</span><span class="o">);</span>
+ <span class="o">}</span>
+
+ <span class="c1">// 2nd step: Serialize the response entity</span>
+ <span class="kd">final</span> <span class="n">EdmEntityType</span> <span
class="n">edmEntityType</span> <span class="o">=</span> <span
class="o">(</span><span class="n">EdmEntityType</span><span class="o">)</span>
<span class="n">uriResourceFunction</span><span class="o">.</span><span
class="na">getFunction</span><span class="o">().</span><span
class="na">getReturnType</span><span class="o">().</span><span
class="na">getType</span><span class="o">();</span>
+ <span class="kd">final</span> <span class="n">ContextURL</span> <span
class="n">contextURL</span> <span class="o">=</span> <span
class="n">ContextURL</span><span class="o">.</span><span
class="na">with</span><span class="o">().</span><span
class="na">type</span><span class="o">(</span><span
class="n">edmEntityType</span><span class="o">).</span><span
class="na">build</span><span class="o">();</span>
+ <span class="kd">final</span> <span class="n">EntitySerializerOptions</span>
<span class="n">opts</span> <span class="o">=</span> <span
class="n">EntitySerializerOptions</span><span class="o">.</span><span
class="na">with</span><span class="o">().</span><span
class="na">contextURL</span><span class="o">(</span><span
class="n">contextURL</span><span class="o">).</span><span
class="na">build</span><span class="o">();</span>
+ <span class="kd">final</span> <span class="n">ODataSerializer</span> <span
class="n">serializer</span> <span class="o">=</span> <span
class="n">odata</span><span class="o">.</span><span
class="na">createSerializer</span><span class="o">(</span><span
class="n">responseFormat</span><span class="o">);</span>
+ <span class="kd">final</span> <span class="n">SerializerResult</span> <span
class="n">serializerResult</span> <span class="o">=</span> <span
class="n">serializer</span><span class="o">.</span><span
class="na">entity</span><span class="o">(</span><span
class="n">serviceMetadata</span><span class="o">,</span> <span
class="n">edmEntityType</span><span class="o">,</span> <span
class="n">entity</span><span class="o">,</span> <span
class="n">opts</span><span class="o">);</span>
+
+ <span class="c1">// 3rd configure the response object</span>
+ <span class="n">response</span><span class="o">.</span><span
class="na">setContent</span><span class="o">(</span><span
class="n">serializerResult</span><span class="o">.</span><span
class="na">getContent</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">OK</span><span class="o">.</span><span
class="na">getStatusCode</span><span class="o">());</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">responseFormat</span><span class="o">.</span><span
class="na">toContentTypeString</span><span class="o">());</span>
+<span class="o">}</span>
+</pre></div>
+
+
+<h3 id="implement-an-action-processor">Implement an action processor<a
class="headerlink" href="#implement-an-action-processor" title="Permanent
link">¶</a></h3>
+<p>Create a new class <code>DemoActionProcessor</code> make them implement the
interface <code>ActionVoidProcessor</code>.</p>
+<div class="codehilite"><pre><span class="kd">public</span> <span
class="kd">class</span> <span class="nc">DemoActionProcessor</span> <span
class="kd">implements</span> <span class="n">ActionVoidProcessor</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">DemoActionProcessor</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>
+</pre></div>
+
+
+<p>First analyze the uri.</p>
+<div class="codehilite"><pre><span class="kd">public</span> <span
class="kt">void</span> <span class="nf">processActionVoid</span><span
class="o">(</span><span class="n">ODataRequest</span> <span
class="n">request</span><span class="o">,</span> <span
class="n">ODataResponse</span> <span class="n">response</span><span
class="o">,</span> <span class="n">UriInfo</span> <span
class="n">uriInfo</span><span class="o">,</span>
+ <span class="n">ContentType</span> <span
class="n">requestFormat</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">// 1st Get the action from the resource path</span>
+ <span class="kd">final</span> <span class="n">EdmAction</span> <span
class="n">edmAction</span> <span class="o">=</span> <span
class="o">((</span><span class="n">UriResourceAction</span><span
class="o">)</span> <span class="n">uriInfo</span><span class="o">.</span><span
class="na">asUriInfoResource</span><span class="o">().</span><span
class="na">getUriResourceParts</span><span class="o">()</span>
+ <span class="o">.</span><span
class="na">get</span><span class="o">(</span><span class="mi">0</span><span
class="o">)).</span><span class="na">getAction</span><span class="o">();</span>
+</pre></div>
+
+
+<p>Then deserialize the <em>action parameters</em>.</p>
+<div class="codehilite"><pre> <span class="c1">// 2nd Deserialize the
parameter</span>
+ <span class="c1">// In our case there is only one action. So we can be sure
that parameter "Amount" has been provided by the client</span>
+ <span class="k">if</span> <span class="o">(</span><span
class="n">requestFormat</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">ODataApplicationException</span><span class="o">(</span><span
class="s">"The content type has not been set in the
request."</span><span class="o">,</span>
+ <span class="n">HttpStatusCode</span><span class="o">.</span><span
class="na">BAD_REQUEST</span><span class="o">.</span><span
class="na">getStatusCode</span><span class="o">(),</span> <span
class="n">Locale</span><span class="o">.</span><span
class="na">ROOT</span><span class="o">);</span>
+ <span class="o">}</span>
+
+ <span class="kd">final</span> <span class="n">ODataDeserializer</span> <span
class="n">deserializer</span> <span class="o">=</span> <span
class="n">odata</span><span class="o">.</span><span
class="na">createDeserializer</span><span class="o">(</span><span
class="n">requestFormat</span><span class="o">);</span>
+ <span class="kd">final</span> <span class="n">Map</span><span
class="o"><</span><span class="n">String</span><span class="o">,</span>
<span class="n">Parameter</span><span class="o">></span> <span
class="n">actionParameter</span> <span class="o">=</span> <span
class="n">deserializer</span><span class="o">.</span><span
class="na">actionParameters</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">edmAction</span><span class="o">)</span>
+ <span class="o">.</span><span
class="na">getActionParameters</span><span class="o">();</span>
+ <span class="kd">final</span> <span class="n">Parameter</span> <span
class="n">parameterAmount</span> <span class="o">=</span> <span
class="n">actionParameter</span><span class="o">.</span><span
class="na">get</span><span class="o">(</span><span
class="n">DemoEdmProvider</span><span class="o">.</span><span
class="na">PARAMETER_AMOUNT</span><span class="o">);</span>
+</pre></div>
+
+
+<p>Execute the action and set the response code.</p>
+<div class="codehilite"><pre> <span class="c1">// The parameter amount is
nullable</span>
+ <span class="k">if</span><span class="o">(</span><span
class="n">parameterAmount</span><span class="o">.</span><span
class="na">isNull</span><span class="o">())</span> <span class="o">{</span>
+ <span class="n">storage</span><span class="o">.</span><span
class="na">resetDataSet</span><span class="o">();</span>
+ <span class="o">}</span> <span class="k">else</span> <span class="o">{</span>
+ <span class="kd">final</span> <span class="n">Integer</span> <span
class="n">amount</span> <span class="o">=</span> <span class="o">(</span><span
class="n">Integer</span><span class="o">)</span> <span
class="n">parameterAmount</span><span class="o">.</span><span
class="na">asPrimitive</span><span class="o">();</span>
+ <span class="n">storage</span><span class="o">.</span><span
class="na">resetDataSet</span><span class="o">(</span><span
class="n">amount</span><span class="o">);</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">NO_CONTENT</span><span class="o">.</span><span
class="na">getStatusCode</span><span class="o">());</span>
+<span class="o">}</span>
+</pre></div>
+
+
+<h2 id="run-the-implemented-service">Run the implemented service<a
class="headerlink" href="#run-the-implemented-service" title="Permanent
link">¶</a></h2>
+<p>After building and deploying your service to your server, you can try the
following requests:</p>
+<p><strong>Functions (Called via GET)</strong> </p>
+<ul>
+<li><a
href="http://localhost:8080/DemoService-Action/DemoService.svc/CountCategories(Amount=2)">http://localhost:8080/DemoService-Action/DemoService.svc/CountCategories(Amount=2)</a></li>
+<li><a
href="http://localhost:8080/DemoService-Action/DemoService.svc/CountCategories(Amount=2)(0)">http://localhost:8080/DemoService-Action/DemoService.svc/CountCategories(Amount=2)(0)</a></li>
+</ul>
+<p><strong>Actions (Called via POST)</strong> <br />
+<em>Note:</em> Set the Content-Type header to: <code>Content-Type:
application/json</code></p>
+<ul>
+<li>
+<p><a
href="http://localhost:8080/DemoService-Action/DemoService.svc/Reset">http://localhost:8080/DemoService-Action/DemoService.svc/Reset</a></p>
+<p>Content:</p>
+<p>{ }</p>
+</li>
+<li>
+<p><a
href="http://localhost:8080/DemoService-Action/DemoService.svc/Reset">http://localhost:8080/DemoService-Action/DemoService.svc/Reset</a></p>
+<p>Content:</p>
+<p>{ "Amount": 1 }</p>
+</li>
+</ul>
+<p>To verify that the service has been reseted, you can request the collection
of products</p>
+<ul>
+<li><a
href="http://localhost:8080/DemoService-Action/DemoService.svc/Products">http://localhost:8080/DemoService-Action/DemoService.svc/Products</a></li>
+</ul>
+<h1 id="links">Links<a class="headerlink" href="#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>Tutorial ODATA V4 service, part 6: Action and Function Imports</li>
+<li>Tutorial ODATA V4 service, part 7: <a
href="/doc/odata4/tutorials/media/tutorial_media.html">Media Entities</a></li>
+<li>Tutorial OData V4 service, part 8: <a
href="/doc/odata4/tutorials/batch/tutorial_batch.html">Batch Request
support</a></li>
+<li>Tutorial OData V4 service, part 9: <a
href="/doc/odata4/tutorials/deep_insert/tutorial_deep_insert.html">Handling
"Deep Insert" requests</a></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>