strolch-website/docs/tutorial/crud-book/index.html

415 lines
68 KiB
HTML

<!doctype html><html lang=en class="js csstransforms3d"><head><meta charset=utf-8><meta name=viewport content="width=device-width,initial-scale=1"><meta name=generator content="Hugo 0.80.0"><meta name=description content="Strolch is a parameterized framework for use on servers and IoT"><meta name=author content="Robert von Burg"><link rel=icon href=/favicon.ico type=image/ico><title>CRUD Book - Strolch</title><link href=/css/nucleus.css?1678977092 rel=stylesheet><link href=/css/fontawesome-all.min.css?1678977092 rel=stylesheet><link href=/css/hybrid.css?1678977092 rel=stylesheet><link href=/css/featherlight.min.css?1678977092 rel=stylesheet><link href=/css/perfect-scrollbar.min.css?1678977092 rel=stylesheet><link href=/css/auto-complete.css?1678977092 rel=stylesheet><link href=/css/atom-one-dark-reasonable.css?1678977092 rel=stylesheet><link href=/css/theme.css?1678977092 rel=stylesheet><link href=/css/hugo-theme.css?1678977092 rel=stylesheet><link href=/css/theme-green.css?1678977092 rel=stylesheet><script src=/js/jquery-3.3.1.min.js?1678977092></script><style>:root #header+#content>#left>#rlblock_left{display:none!important}</style></head><body data-url=/tutorial/crud-book/><nav id=sidebar><div id=header-wrapper><div id=header><a id=logo href=/><img src=/logo.png></a></div><div class=searchbox><label for=search-by><i class="fas fa-search"></i></label><input data-search-input id=search-by type=search placeholder=Search...>
<span data-search-clear><i class="fas fa-times"></i></span></div><script type=text/javascript src=/js/lunr.min.js?1678977092></script><script type=text/javascript src=/js/auto-complete.js?1678977092></script><script type=text/javascript>var baseurl="https:\/\/strolch.li\/";</script><script type=text/javascript src=/js/search.js?1678977092></script></div><section id=homelinks><ul><li><a class=padding href=/><i class="fas fa-home"></i>Home</a></li></ul></section><div class=highlightable><ul class=topics><li data-nav-id=/api/ title=API class=dd-item><a href=/api/>API</a></li><li data-nav-id=/documentation/ title=Documentation class=dd-item><a href=/documentation/>Documentation</a><ul><li data-nav-id=/documentation/architecture/ title=Architecture class=dd-item><a href=/documentation/architecture/>Architecture</a></li><li data-nav-id=/documentation/model/ title=Model class=dd-item><a href=/documentation/model/>Model</a></li><li data-nav-id=/documentation/do-and-donts/ title="Do and Don't" class=dd-item><a href=/documentation/do-and-donts/>Do and Don't</a></li><li data-nav-id=/documentation/runtime-configuration/ title="Runtime Configuration" class=dd-item><a href=/documentation/runtime-configuration/>Runtime Configuration</a></li><li data-nav-id=/documentation/realms/ title=Realms class=dd-item><a href=/documentation/realms/>Realms</a></li><li data-nav-id=/documentation/components/ title=Components class=dd-item><a href=/documentation/components/>Components</a></li><li data-nav-id=/documentation/services-and-commands/ title="Services and Commands" class=dd-item><a href=/documentation/services-and-commands/>Services and Commands</a></li><li data-nav-id=/documentation/searches/ title=Searches class=dd-item><a href=/documentation/searches/>Searches</a></li><li data-nav-id=/documentation/queries/ title=Queries class=dd-item><a href=/documentation/queries/>Queries</a></li><li data-nav-id=/documentation/transactions/ title=Transactions class=dd-item><a href=/documentation/transactions/>Transactions</a></li><li data-nav-id=/documentation/policies/ title=Policies class=dd-item><a href=/documentation/policies/>Policies</a></li><li data-nav-id=/documentation/observers/ title=Observers class=dd-item><a href=/documentation/observers/>Observers</a></li><li data-nav-id=/documentation/versioning/ title=Versioning class=dd-item><a href=/documentation/versioning/>Versioning</a></li><li data-nav-id=/documentation/reports/ title=Reports class=dd-item><a href=/documentation/reports/>Reports</a></li><li data-nav-id=/documentation/priviles/ title=Privileges class=dd-item><a href=/documentation/priviles/>Privileges</a></li></ul></li><li data-nav-id=/plc/ title=PLC class=dd-item><a href=/plc/>PLC</a><ul><li data-nav-id=/plc/architecture/ title=Architecture class=dd-item><a href=/plc/architecture/>Architecture</a></li><li data-nav-id=/plc/example-set-up/ title="Example Set-Up" class=dd-item><a href=/plc/example-set-up/>Example Set-Up</a></li></ul></li><li data-nav-id=/tutorial/ title=Tutorial class="dd-item
parent"><a href=/tutorial/>Tutorial</a><ul><li data-nav-id=/tutorial/configuration/ title=Configuration class=dd-item><a href=/tutorial/configuration/>Configuration</a></li><li data-nav-id=/tutorial/model/ title=Model class=dd-item><a href=/tutorial/model/>Model</a></li><li data-nav-id=/tutorial/crud-book/ title="CRUD Book" class="dd-item active"><a href=/tutorial/crud-book/>CRUD Book</a></li></ul></li><li data-nav-id=/download/ title=Download class=dd-item><a href=/download/>Download</a></li><li data-nav-id=/development/ title=Development class=dd-item><a href=/development/>Development</a><ul><li data-nav-id=/development/prerequisites/ title=Prerequisites class=dd-item><a href=/development/prerequisites/>Prerequisites</a></li><li data-nav-id=/development/building/ title="Building Strolch" class=dd-item><a href=/development/building/>Building Strolch</a></li><li data-nav-id=/development/maven-archetypes/ title="Maven Archetypes" class=dd-item><a href=/development/maven-archetypes/>Maven Archetypes</a></li><li data-nav-id=/development/web-app/ title="Web App" class=dd-item><a href=/development/web-app/>Web App</a></li><li data-nav-id=/development/main-class-app/ title="Main Class App" class=dd-item><a href=/development/main-class-app/>Main Class App</a></li><li data-nav-id=/development/converting-existing/ title="Converting Existing App" class=dd-item><a href=/development/converting-existing/>Converting Existing App</a></li></ul></li><li data-nav-id=/blog/ title=Blog class=dd-item><a href=/blog/>Blog</a><ul><li data-nav-id=/blog/post-00018/ title="Strolch PLC 1.2.3 released" class=dd-item><a href=/blog/post-00018/>Strolch PLC 1.2.3 released</a></li><li data-nav-id=/blog/post-00017/ title="Strolch 1.8.5 and PLC 1.2.2 are out" class=dd-item><a href=/blog/post-00017/>Strolch 1.8.5 and PLC 1.2.2 are out</a></li><li data-nav-id=/blog/post-00016/ title="Strolch PLC now also on Maven Central" class=dd-item><a href=/blog/post-00016/>Strolch PLC now also on Maven Central</a></li><li data-nav-id=/blog/post-00015/ title="Release of Strolch 1.6.100" class=dd-item><a href=/blog/post-00015/>Release of Strolch 1.6.100</a></li><li data-nav-id=/blog/post-00014/ title="Strolch Reports" class=dd-item><a href=/blog/post-00014/>Strolch Reports</a></li><li data-nav-id=/blog/post-00013/ title="Strolch Searches" class=dd-item><a href=/blog/post-00013/>Strolch Searches</a></li><li data-nav-id=/blog/post-00012/ title="Wow, the many changes!" class=dd-item><a href=/blog/post-00012/>Wow, the many changes!</a></li><li data-nav-id=/blog/post-00011/ title="Strolch now on Maven Central" class=dd-item><a href=/blog/post-00011/>Strolch now on Maven Central</a></li><li data-nav-id=/blog/post-00010/ title="Versioning of objects" class=dd-item><a href=/blog/post-00010/>Versioning of objects</a></li><li data-nav-id=/blog/post-00009/ title="Release 1.2.0" class=dd-item><a href=/blog/post-00009/>Release 1.2.0</a></li><li data-nav-id=/blog/post-00008/ title="Strolch Update" class=dd-item><a href=/blog/post-00008/>Strolch Update</a></li><li data-nav-id=/blog/post-00007/ title="Activities: Beginning of the planning engine" class=dd-item><a href=/blog/post-00007/>Activities: Beginning of the planning engine</a></li><li data-nav-id=/blog/post-00006/ title="Strolch Documentation" class=dd-item><a href=/blog/post-00006/>Strolch Documentation</a></li><li data-nav-id=/blog/post-00005/ title="Strolch Release 1.0.0" class=dd-item><a href=/blog/post-00005/>Strolch Release 1.0.0</a></li><li data-nav-id=/blog/post-00004/ title="DurationParameter and other minor changes: Release 1.0.0-RC4" class=dd-item><a href=/blog/post-00004/>DurationParameter and other minor changes: Release 1.0.0-RC4</a></li><li data-nav-id=/blog/post-00003/ title="DB Initialization: Release 1.0.0-RC3" class=dd-item><a href=/blog/post-00003/>DB Initialization: Release 1.0.0-RC3</a></li><li data-nav-id=/blog/post-00002/ title="Release 1.0.0-RC2" class=dd-item><a href=/blog/post-00002/>Release 1.0.0-RC2</a></li><li data-nav-id=/blog/post-00001/ title="Release 1.0.0-RC1" class=dd-item><a href=/blog/post-00001/>Release 1.0.0-RC1</a></li></ul></li></ul><section id=shortcuts><h3>More</h3><ul><li><a class=padding href=https://strolch.li/tags><i class="fas fa-tags"></i>Tags</a></li><li><a class=padding href=https://github.com/strolch-li><i class="fab fa-github"></i>GitHub project</a></li><li><a rel=me class=padding href=https://mstdn.gsi.li/@eitch target=_blank><i class="fab fa-mastodon"></i>Mastodon</a></li></ul></section><section id=footer><p>Built with <a href=https://github.com/matcornic/hugo-theme-learn target=_blank><i class="fas fa-heart"></i></a>from <a href=https://getgrav.org target=_blank>Grav</a> and <a href=https://gohugo.io/ target=_blank>Hugo</a></p></section></div></nav><section id=body><div id=overlay></div><div class="padding highlightable"><div><div id=top-bar><div id=top-github-link><a class=github-link title="Edit this page" href=https://github.com/strolch-li/strolch-website/tree/develop/content/tutorial/crud-book.md target=blank><i class="fas fa-code-branch"></i><span id=top-github-link-text>Edit this page</span></a></div><div id=breadcrumbs itemscope itemtype=http://data-vocabulary.org/Breadcrumb><span id=sidebar-toggle-span><a href=# id=sidebar-toggle data-sidebar-toggle><i class="fas fa-bars"></i></a></span><span id=toc-menu><i class="fas fa-list-alt"></i></span><span class=links><a href=/>Strolch Overview</a> > <a href=/tutorial/>Tutorial</a> > CRUD Book</span></div><div class=progress><div class=wrapper><nav id=TableOfContents><ul><li><a href=#preparation>Preparation</a></li><li><a href=#search>Search</a></li><li><a href=#get>Get</a></li><li><a href=#create>Create</a></li><li><a href=#update>Update</a></li><li><a href=#remove>Remove</a></li><li><a href=#notes>Notes</a></li></ul></nav></div></div></div></div><div id=head-tags></div><div id=body-inner><h1>CRUD Book</h1><h2 id=preparation>Preparation</h2><p>Since Books are central to the bookshop, we&rsquo;ll first create the CRUD REST API
for them. The API will be as follows:</p><div class=highlight><pre style=color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4><code class=language-text data-lang=text>GET ../rest/books?query=,offset=,limit=
GET ../rest/books/{id}
POST ../rest/books
PUT ../rest/books/{id}
DELETE ../rest/books/{id}
</code></pre></div><p>Thus corresponding with querying, getting, creating, updating and removing of
books. So let&rsquo;s go ahead and add these REST APIs to our project.</p><p>Our project is using JAX-RS 2.0 as the API and Jersey 2.x as the implementation,
thus first we need to configure JAX-RS. Thus create the following class:</p><div class=highlight><pre style=color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4><code class=language-java data-lang=java><span style=color:#a6e22e>@ApplicationPath</span><span style=color:#f92672>(</span><span style=color:#e6db74>&#34;rest&#34;</span><span style=color:#f92672>)</span>
<span style=color:#66d9ef>public</span> <span style=color:#66d9ef>class</span> <span style=color:#a6e22e>RestfulApplication</span> <span style=color:#66d9ef>extends</span> ResourceConfig <span style=color:#f92672>{</span>
<span style=color:#66d9ef>public</span> <span style=color:#a6e22e>RestfulApplication</span><span style=color:#f92672>()</span> <span style=color:#f92672>{</span>
<span style=color:#75715e>// add strolch resources
</span><span style=color:#75715e></span> register<span style=color:#f92672>(</span>AuthenticationService<span style=color:#f92672>.</span><span style=color:#a6e22e>class</span><span style=color:#f92672>);</span>
register<span style=color:#f92672>(</span>ModelQuery<span style=color:#f92672>.</span><span style=color:#a6e22e>class</span><span style=color:#f92672>);</span>
register<span style=color:#f92672>(</span>Inspector<span style=color:#f92672>.</span><span style=color:#a6e22e>class</span><span style=color:#f92672>);</span>
<span style=color:#75715e>// add project resources by package name
</span><span style=color:#75715e></span> packages<span style=color:#f92672>(</span>BooksResource<span style=color:#f92672>.</span><span style=color:#a6e22e>class</span><span style=color:#f92672>.</span><span style=color:#a6e22e>getPackage</span><span style=color:#f92672>().</span><span style=color:#a6e22e>getName</span><span style=color:#f92672>());</span>
<span style=color:#75715e>// filters
</span><span style=color:#75715e></span> register<span style=color:#f92672>(</span>AuthenticationRequestFilter<span style=color:#f92672>.</span><span style=color:#a6e22e>class</span><span style=color:#f92672>,</span> Priorities<span style=color:#f92672>.</span><span style=color:#a6e22e>AUTHENTICATION</span><span style=color:#f92672>);</span>
register<span style=color:#f92672>(</span>AccessControlResponseFilter<span style=color:#f92672>.</span><span style=color:#a6e22e>class</span><span style=color:#f92672>);</span>
register<span style=color:#f92672>(</span>AuthenticationResponseFilter<span style=color:#f92672>.</span><span style=color:#a6e22e>class</span><span style=color:#f92672>);</span>
register<span style=color:#f92672>(</span>HttpCacheResponseFilter<span style=color:#f92672>.</span><span style=color:#a6e22e>class</span><span style=color:#f92672>);</span>
<span style=color:#75715e>// log exceptions and return them as plain text to the caller
</span><span style=color:#75715e></span> register<span style=color:#f92672>(</span>StrolchRestfulExceptionMapper<span style=color:#f92672>.</span><span style=color:#a6e22e>class</span><span style=color:#f92672>);</span>
<span style=color:#75715e>// the JSON generated is in UTF-8
</span><span style=color:#75715e></span> register<span style=color:#f92672>(</span>CharsetResponseFilter<span style=color:#f92672>.</span><span style=color:#a6e22e>class</span><span style=color:#f92672>);</span>
RestfulStrolchComponent restfulComponent <span style=color:#f92672>=</span> RestfulStrolchComponent<span style=color:#f92672>.</span><span style=color:#a6e22e>getInstance</span><span style=color:#f92672>();</span>
<span style=color:#66d9ef>if</span> <span style=color:#f92672>(</span>restfulComponent<span style=color:#f92672>.</span><span style=color:#a6e22e>isRestLogging</span><span style=color:#f92672>())</span> <span style=color:#f92672>{</span>
register<span style=color:#f92672>(</span><span style=color:#66d9ef>new</span> LoggingFeature<span style=color:#f92672>(</span>java<span style=color:#f92672>.</span><span style=color:#a6e22e>util</span><span style=color:#f92672>.</span><span style=color:#a6e22e>logging</span><span style=color:#f92672>.</span><span style=color:#a6e22e>Logger</span><span style=color:#f92672>.</span><span style=color:#a6e22e>getLogger</span><span style=color:#f92672>(</span>LoggingFeature<span style=color:#f92672>.</span><span style=color:#a6e22e>DEFAULT_LOGGER_NAME</span><span style=color:#f92672>),</span>
Level<span style=color:#f92672>.</span><span style=color:#a6e22e>SEVERE</span><span style=color:#f92672>,</span> LoggingFeature<span style=color:#f92672>.</span><span style=color:#a6e22e>Verbosity</span><span style=color:#f92672>.</span><span style=color:#a6e22e>PAYLOAD_ANY</span><span style=color:#f92672>,</span> Integer<span style=color:#f92672>.</span><span style=color:#a6e22e>MAX_VALUE</span><span style=color:#f92672>));</span>
property<span style=color:#f92672>(</span>ServerProperties<span style=color:#f92672>.</span><span style=color:#a6e22e>TRACING</span><span style=color:#f92672>,</span> <span style=color:#e6db74>&#34;ALL&#34;</span><span style=color:#f92672>);</span>
property<span style=color:#f92672>(</span>ServerProperties<span style=color:#f92672>.</span><span style=color:#a6e22e>TRACING_THRESHOLD</span><span style=color:#f92672>,</span> <span style=color:#e6db74>&#34;TRACE&#34;</span><span style=color:#f92672>);</span>
<span style=color:#f92672>}</span>
<span style=color:#f92672>}</span>
<span style=color:#f92672>}</span>
</code></pre></div><p>As we add new resources they will be automatically since we register the entire package.</p><p>Now add the books resource class:</p><div class=highlight><pre style=color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4><code class=language-java data-lang=java><span style=color:#a6e22e>@Path</span><span style=color:#f92672>(</span><span style=color:#e6db74>&#34;books&#34;</span><span style=color:#f92672>)</span>
<span style=color:#66d9ef>public</span> <span style=color:#66d9ef>class</span> <span style=color:#a6e22e>BooksResource</span> <span style=color:#f92672>{</span>
<span style=color:#f92672>}</span>
</code></pre></div><h2 id=search>Search</h2><p>The first service we&rsquo;ll add is to query, or search for the existing books. The
API defines three parameters, with which the result can be controlled. The
method can be defined as follows:</p><div class=highlight><pre style=color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4><code class=language-java data-lang=java>
<span style=color:#a6e22e>@Path</span><span style=color:#f92672>(</span><span style=color:#e6db74>&#34;books&#34;</span><span style=color:#f92672>)</span>
<span style=color:#66d9ef>public</span> <span style=color:#66d9ef>class</span> <span style=color:#a6e22e>BooksResource</span> <span style=color:#f92672>{</span>
<span style=color:#a6e22e>@GET</span>
<span style=color:#a6e22e>@Produces</span><span style=color:#f92672>(</span>MediaType<span style=color:#f92672>.</span><span style=color:#a6e22e>APPLICATION_JSON</span><span style=color:#f92672>)</span>
<span style=color:#66d9ef>public</span> Response <span style=color:#a6e22e>query</span><span style=color:#f92672>(</span><span style=color:#a6e22e>@Context</span> HttpServletRequest request<span style=color:#f92672>,</span>
<span style=color:#a6e22e>@QueryParam</span><span style=color:#f92672>(</span><span style=color:#e6db74>&#34;query&#34;</span><span style=color:#f92672>)</span> String queryS<span style=color:#f92672>,</span>
<span style=color:#a6e22e>@QueryParam</span><span style=color:#f92672>(</span><span style=color:#e6db74>&#34;offset&#34;</span><span style=color:#f92672>)</span> String offsetS<span style=color:#f92672>,</span>
<span style=color:#a6e22e>@QueryParam</span><span style=color:#f92672>(</span><span style=color:#e6db74>&#34;limit&#34;</span><span style=color:#f92672>)</span> String limitS<span style=color:#f92672>)</span> <span style=color:#f92672>{</span>
<span style=color:#75715e>// TODO
</span><span style=color:#75715e></span> <span style=color:#f92672>}</span>
<span style=color:#f92672>}</span>
</code></pre></div><p>To fill this method we need a few things. First let&rsquo;s define a constants class where we keep String constants which we used in the model file:</p><div class=highlight><pre style=color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4><code class=language-java data-lang=java><span style=color:#66d9ef>public</span> <span style=color:#66d9ef>class</span> <span style=color:#a6e22e>BookShopConstants</span> <span style=color:#f92672>{</span>
<span style=color:#66d9ef>public</span> <span style=color:#66d9ef>static</span> <span style=color:#66d9ef>final</span> String TYPE_BOOK <span style=color:#f92672>=</span> <span style=color:#e6db74>&#34;Book&#34;</span><span style=color:#f92672>;</span>
<span style=color:#f92672>}</span>
</code></pre></div><p>As this tutorial progresses, more and more constants will be added here. This
class helps with two issues: Through the constants we can easily reason over
where certain fields, and types are used and of course String literals in code
are a rather bad thing.</p><p>In Strolch there are multiple way to access objects. The old way was using
Queries, the new search API is much more fluent and easier to read and write.
The search API, as well as the deprecated query API allows us to implement
privilege validation and thus one should create corresponding classes for each
type of search. Book entities are Resources, thus we will be creating a
<code>ResourceSearch</code>. The search is for Resources of type Book thus the resulting
search looks as follows:</p><div class=highlight><pre style=color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4><code class=language-java data-lang=java><span style=color:#66d9ef>public</span> <span style=color:#66d9ef>class</span> <span style=color:#a6e22e>BooksSearch</span><span style=color:#f92672>&lt;</span>U<span style=color:#f92672>&gt;</span> <span style=color:#66d9ef>extends</span> ResourceSearch<span style=color:#f92672>&lt;</span>U<span style=color:#f92672>&gt;</span> <span style=color:#f92672>{</span>
<span style=color:#66d9ef>public</span> <span style=color:#a6e22e>BookSearch</span><span style=color:#f92672>()</span> <span style=color:#f92672>{</span>
types<span style=color:#f92672>(</span>TYPE_BOOK<span style=color:#f92672>);</span>
<span style=color:#f92672>}</span>
<span style=color:#66d9ef>public</span> BookSearch <span style=color:#a6e22e>stringQuery</span><span style=color:#f92672>(</span>String value<span style=color:#f92672>)</span> <span style=color:#f92672>{</span>
<span style=color:#66d9ef>if</span> <span style=color:#f92672>(</span>isEmpty<span style=color:#f92672>(</span>value<span style=color:#f92672>))</span>
<span style=color:#66d9ef>return</span> <span style=color:#66d9ef>this</span><span style=color:#f92672>;</span>
<span style=color:#75715e>// split by spaces
</span><span style=color:#75715e></span> value <span style=color:#f92672>=</span> value<span style=color:#f92672>.</span><span style=color:#a6e22e>trim</span><span style=color:#f92672>();</span>
String<span style=color:#f92672>[]</span> values <span style=color:#f92672>=</span> value<span style=color:#f92672>.</span><span style=color:#a6e22e>split</span><span style=color:#f92672>(</span><span style=color:#e6db74>&#34; &#34;</span><span style=color:#f92672>);</span>
<span style=color:#75715e>// add where clauses for id, name and description
</span><span style=color:#75715e></span> where<span style=color:#f92672>(</span>id<span style=color:#f92672>().</span><span style=color:#a6e22e>containsIgnoreCase</span><span style=color:#f92672>(</span>values<span style=color:#f92672>)</span> <span style=color:#75715e>//
</span><span style=color:#75715e></span> <span style=color:#f92672>.</span><span style=color:#a6e22e>or</span><span style=color:#f92672>(</span>name<span style=color:#f92672>().</span><span style=color:#a6e22e>containsIgnoreCase</span><span style=color:#f92672>(</span>values<span style=color:#f92672>))</span> <span style=color:#75715e>//
</span><span style=color:#75715e></span> <span style=color:#f92672>.</span><span style=color:#a6e22e>or</span><span style=color:#f92672>(</span>param<span style=color:#f92672>(</span>BAG_PARAMETERS<span style=color:#f92672>,</span> PARAM_DESCRIPTION<span style=color:#f92672>).</span><span style=color:#a6e22e>containsIgnoreCase</span><span style=color:#f92672>(</span>values<span style=color:#f92672>)));</span>
<span style=color:#66d9ef>return</span> <span style=color:#66d9ef>this</span><span style=color:#f92672>;</span>
<span style=color:#f92672>}</span>
<span style=color:#f92672>}</span>
</code></pre></div><p>Note how we added a special <code>stringQuery(String)</code>-method. This method defines
where a search string entered by the user will be used to match a book. In this
case for <code>id</code>, <code>name</code> and the <code>description</code> parameter.</p><p>So that our users can call this query, we must give them this as a privilege.
This is done by adding the full class name to the <code>PrivilegeRoles.xml</code> file as
follows:</p><div class=highlight><pre style=color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4><code class=language-xml data-lang=xml>...
<span style=color:#f92672>&lt;Role</span> <span style=color:#a6e22e>name=</span><span style=color:#e6db74>&#34;User&#34;</span><span style=color:#f92672>&gt;</span>
<span style=color:#f92672>&lt;Privilege</span> <span style=color:#a6e22e>name=</span><span style=color:#e6db74>&#34;li.strolch.search.StrolchSearch&#34;</span> <span style=color:#a6e22e>policy=</span><span style=color:#e6db74>&#34;DefaultPrivilege&#34;</span><span style=color:#f92672>&gt;</span>
<span style=color:#f92672>&lt;Allow&gt;</span>internal<span style=color:#f92672>&lt;/Allow&gt;</span>
<span style=color:#f92672>&lt;Allow&gt;</span>li.strolch.bookshop.search.BookSearch<span style=color:#f92672>&lt;/Allow&gt;</span>
<span style=color:#f92672>&lt;/Privilege&gt;</span>
<span style=color:#f92672>&lt;/Role&gt;</span>
...
</code></pre></div><div class="notices tip"><p>Note: The <code>internal</code> allow value is a special privilege which
is used internally when a service or something performs internal queries. This
means that a service can perform a query for object to which the user might not
have access, but without which the service could not be completed. We will use
this in a later stage.</p></div><p>Now we have all parts we need to implement the query method. The method will
include opening a transaction, instantiating the search, executing the search,
and returning the result:</p><div class=highlight><pre style=color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4><code class=language-java data-lang=java>
<span style=color:#a6e22e>@Path</span><span style=color:#f92672>(</span><span style=color:#e6db74>&#34;books&#34;</span><span style=color:#f92672>)</span>
<span style=color:#66d9ef>public</span> <span style=color:#66d9ef>class</span> <span style=color:#a6e22e>BooksResource</span> <span style=color:#f92672>{</span>
<span style=color:#a6e22e>@GET</span>
<span style=color:#a6e22e>@Produces</span><span style=color:#f92672>(</span>MediaType<span style=color:#f92672>.</span><span style=color:#a6e22e>APPLICATION_JSON</span><span style=color:#f92672>)</span>
<span style=color:#66d9ef>public</span> Response <span style=color:#a6e22e>query</span><span style=color:#f92672>(</span><span style=color:#a6e22e>@Context</span> HttpServletRequest request<span style=color:#f92672>,</span>
<span style=color:#a6e22e>@QueryParam</span><span style=color:#f92672>(</span><span style=color:#e6db74>&#34;query&#34;</span><span style=color:#f92672>)</span> String queryS<span style=color:#f92672>,</span>
<span style=color:#a6e22e>@QueryParam</span><span style=color:#f92672>(</span><span style=color:#e6db74>&#34;offset&#34;</span><span style=color:#f92672>)</span> String offsetS<span style=color:#f92672>,</span>
<span style=color:#a6e22e>@QueryParam</span><span style=color:#f92672>(</span><span style=color:#e6db74>&#34;limit&#34;</span><span style=color:#f92672>)</span> String limitS<span style=color:#f92672>)</span> <span style=color:#f92672>{</span>
<span style=color:#75715e>// this is an authenticated method call, thus we can get the certificate from the request:
</span><span style=color:#75715e></span> Certificate cert <span style=color:#f92672>=</span> <span style=color:#f92672>(</span>Certificate<span style=color:#f92672>)</span> request
<span style=color:#f92672>.</span><span style=color:#a6e22e>getAttribute</span><span style=color:#f92672>(</span>StrolchRestfulConstants<span style=color:#f92672>.</span><span style=color:#a6e22e>STROLCH_CERTIFICATE</span><span style=color:#f92672>);</span>
<span style=color:#66d9ef>int</span> offset <span style=color:#f92672>=</span> StringHelper<span style=color:#f92672>.</span><span style=color:#a6e22e>isNotEmpty</span><span style=color:#f92672>(</span>offsetS<span style=color:#f92672>)</span> <span style=color:#f92672>?</span> Integer<span style=color:#f92672>.</span><span style=color:#a6e22e>parseInt</span><span style=color:#f92672>(</span>offsetS<span style=color:#f92672>)</span> <span style=color:#f92672>:</span> 0<span style=color:#f92672>;</span>
<span style=color:#66d9ef>int</span> limit <span style=color:#f92672>=</span> StringHelper<span style=color:#f92672>.</span><span style=color:#a6e22e>isNotEmpty</span><span style=color:#f92672>(</span>limitS<span style=color:#f92672>)</span> <span style=color:#f92672>?</span> Integer<span style=color:#f92672>.</span><span style=color:#a6e22e>parseInt</span><span style=color:#f92672>(</span>limitS<span style=color:#f92672>)</span> <span style=color:#f92672>:</span> 0<span style=color:#f92672>;</span>
<span style=color:#75715e>// open the TX with the certificate, using this class as context
</span><span style=color:#75715e></span> Paging<span style=color:#f92672>&lt;</span>Resource<span style=color:#f92672>&gt;</span> paging<span style=color:#f92672>;</span>
<span style=color:#66d9ef>try</span> <span style=color:#f92672>(</span>StrolchTransaction tx <span style=color:#f92672>=</span> RestfulStrolchComponent<span style=color:#f92672>.</span><span style=color:#a6e22e>getInstance</span><span style=color:#f92672>()</span>
<span style=color:#f92672>.</span><span style=color:#a6e22e>openTx</span><span style=color:#f92672>(</span>cert<span style=color:#f92672>,</span> getClass<span style=color:#f92672>()))</span> <span style=color:#f92672>{</span>
<span style=color:#75715e>// perform a book search
</span><span style=color:#75715e></span> paging <span style=color:#f92672>=</span> <span style=color:#66d9ef>new</span> BookSearch<span style=color:#f92672>()</span> <span style=color:#75715e>//
</span><span style=color:#75715e></span> <span style=color:#f92672>.</span><span style=color:#a6e22e>stringQuery</span><span style=color:#f92672>(</span>queryS<span style=color:#f92672>)</span> <span style=color:#75715e>//
</span><span style=color:#75715e></span> <span style=color:#f92672>.</span><span style=color:#a6e22e>search</span><span style=color:#f92672>(</span>tx<span style=color:#f92672>)</span> <span style=color:#75715e>//
</span><span style=color:#75715e></span> <span style=color:#f92672>.</span><span style=color:#a6e22e>orderByName</span><span style=color:#f92672>(</span><span style=color:#66d9ef>false</span><span style=color:#f92672>)</span> <span style=color:#75715e>//
</span><span style=color:#75715e></span> <span style=color:#f92672>.</span><span style=color:#a6e22e>toPaging</span><span style=color:#f92672>(</span>offset<span style=color:#f92672>,</span> limit<span style=color:#f92672>);</span>
<span style=color:#f92672>}</span>
ResourceVisitor<span style=color:#f92672>&lt;</span>JsonObject<span style=color:#f92672>&gt;</span> visitor <span style=color:#f92672>=</span> <span style=color:#66d9ef>new</span> StrolchRootElementToJsonVisitor<span style=color:#f92672>()</span>
<span style=color:#f92672>.</span><span style=color:#a6e22e>flat</span><span style=color:#f92672>().</span><span style=color:#a6e22e>asResourceVisitor</span><span style=color:#f92672>();</span>
<span style=color:#66d9ef>return</span> ResponseUtil<span style=color:#f92672>.</span><span style=color:#a6e22e>toResponse</span><span style=color:#f92672>(</span>paging<span style=color:#f92672>,</span> e <span style=color:#f92672>-&gt;</span> e<span style=color:#f92672>.</span><span style=color:#a6e22e>accept</span><span style=color:#f92672>(</span>visitor<span style=color:#f92672>));</span>
<span style=color:#f92672>}</span>
<span style=color:#f92672>}</span>
</code></pre></div><div class="notices tip"><p>Note: We automatically transform the Resource objects to JSON
using the <code>StrolchElementToJsonVisitor</code>. By calling the method <code>.flat()</code>-method we have a
more compact JSON format. Paging is handled by a util class.</p></div><p>The helper class <code>ResponseUtil</code> takes care of creating the <code>JsonObject</code> and the
proper page. As a rule we use the format where we return two fields: <code>msg</code> is a
dash if all is ok, otherwise an error message will be present. Data is always in
the <code>data</code> field. This is just a personal taste, and can be changed to one&rsquo;s own
taste.</p><h2 id=get>Get</h2><p>We have all we need now to implement the GET method:</p><div class=highlight><pre style=color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4><code class=language-java data-lang=java><span style=color:#a6e22e>@GET</span>
<span style=color:#a6e22e>@Path</span><span style=color:#f92672>(</span><span style=color:#e6db74>&#34;{id}&#34;</span><span style=color:#f92672>)</span>
<span style=color:#a6e22e>@Produces</span><span style=color:#f92672>(</span>MediaType<span style=color:#f92672>.</span><span style=color:#a6e22e>APPLICATION_JSON</span><span style=color:#f92672>)</span>
<span style=color:#66d9ef>public</span> Response <span style=color:#a6e22e>get</span><span style=color:#f92672>(</span><span style=color:#a6e22e>@Context</span> HttpServletRequest request<span style=color:#f92672>,</span> <span style=color:#a6e22e>@PathParam</span><span style=color:#f92672>(</span><span style=color:#e6db74>&#34;id&#34;</span><span style=color:#f92672>)</span> String id<span style=color:#f92672>)</span> <span style=color:#f92672>{</span>
<span style=color:#75715e>// this is an authenticated method call, thus we can get the certificate from the request:
</span><span style=color:#75715e></span> Certificate cert <span style=color:#f92672>=</span> <span style=color:#f92672>(</span>Certificate<span style=color:#f92672>)</span> request<span style=color:#f92672>.</span><span style=color:#a6e22e>getAttribute</span><span style=color:#f92672>(</span>StrolchRestfulConstants<span style=color:#f92672>.</span><span style=color:#a6e22e>STROLCH_CERTIFICATE</span><span style=color:#f92672>);</span>
<span style=color:#75715e>// open the TX with the certificate, using this class as context
</span><span style=color:#75715e></span> <span style=color:#66d9ef>try</span> <span style=color:#f92672>(</span>StrolchTransaction tx <span style=color:#f92672>=</span> RestfulStrolchComponent<span style=color:#f92672>.</span><span style=color:#a6e22e>getInstance</span><span style=color:#f92672>().</span><span style=color:#a6e22e>openTx</span><span style=color:#f92672>(</span>cert<span style=color:#f92672>,</span> getClass<span style=color:#f92672>()))</span> <span style=color:#f92672>{</span>
<span style=color:#75715e>// get the book
</span><span style=color:#75715e></span> Resource book <span style=color:#f92672>=</span> tx<span style=color:#f92672>.</span><span style=color:#a6e22e>getResourceBy</span><span style=color:#f92672>(</span>BookShopConstants<span style=color:#f92672>.</span><span style=color:#a6e22e>TYPE_BOOK</span><span style=color:#f92672>,</span> id<span style=color:#f92672>);</span>
<span style=color:#66d9ef>if</span> <span style=color:#f92672>(</span>book <span style=color:#f92672>==</span> <span style=color:#66d9ef>null</span><span style=color:#f92672>)</span>
<span style=color:#66d9ef>return</span> ResponseUtil<span style=color:#f92672>.</span><span style=color:#a6e22e>toResponse</span><span style=color:#f92672>(</span>Status<span style=color:#f92672>.</span><span style=color:#a6e22e>NOT_FOUND</span><span style=color:#f92672>,</span> <span style=color:#e6db74>&#34;Book &#34;</span> <span style=color:#f92672>+</span> id <span style=color:#f92672>+</span> <span style=color:#e6db74>&#34; does not exist!&#34;</span><span style=color:#f92672>);</span>
<span style=color:#75715e>// transform to JSON
</span><span style=color:#75715e></span> JsonObject bookJ <span style=color:#f92672>=</span> book<span style=color:#f92672>.</span><span style=color:#a6e22e>accept</span><span style=color:#f92672>(</span><span style=color:#66d9ef>new</span> StrolchRootElementToJsonVisitor<span style=color:#f92672>().</span><span style=color:#a6e22e>flat</span><span style=color:#f92672>());</span>
<span style=color:#75715e>// return
</span><span style=color:#75715e></span> <span style=color:#66d9ef>return</span> ResponseUtil<span style=color:#f92672>.</span><span style=color:#a6e22e>toResponse</span><span style=color:#f92672>(</span>StrolchRestfulConstants<span style=color:#f92672>.</span><span style=color:#a6e22e>DATA</span><span style=color:#f92672>,</span> bookJ<span style=color:#f92672>);</span>
<span style=color:#f92672>}</span>
<span style=color:#f92672>}</span>
</code></pre></div><div class="notices tip"><p>Note how we simply retrieve the book as a Resource from the
TX. This is a good moment to familiarize yourself with the API of the
<code>StrolchTransaction</code>. There are methods to retrieve elements, and also perform
searches. We will use more of these methods later.</p></div><p>Further it can be noted that a simple retrieval isn&rsquo;t validated against the
user&rsquo;s privileges, the user is authenticated, which is enough for the moment.</p><h2 id=create>Create</h2><p>To create a new book we need to implement a <code>Service</code>. This service will be called
<code>CreateBookService</code>. A Service always has a <code>ServiceArgument</code> and a <code>ServiceResult</code>.
Our service will use the <code>JsonServiceArgument</code> and the <code>JsonServiceResult</code>. The
implementation of the POST method is as follows:</p><div class=highlight><pre style=color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4><code class=language-java data-lang=java><span style=color:#a6e22e>@POST</span>
<span style=color:#a6e22e>@Produces</span><span style=color:#f92672>(</span>MediaType<span style=color:#f92672>.</span><span style=color:#a6e22e>APPLICATION_JSON</span><span style=color:#f92672>)</span>
<span style=color:#66d9ef>public</span> Response <span style=color:#a6e22e>create</span><span style=color:#f92672>(</span><span style=color:#a6e22e>@Context</span> HttpServletRequest request<span style=color:#f92672>,</span> String data<span style=color:#f92672>)</span> <span style=color:#f92672>{</span>
<span style=color:#75715e>// this is an authenticated method call, thus we can get the certificate from the request:
</span><span style=color:#75715e></span> Certificate cert <span style=color:#f92672>=</span> <span style=color:#f92672>(</span>Certificate<span style=color:#f92672>)</span> request<span style=color:#f92672>.</span><span style=color:#a6e22e>getAttribute</span><span style=color:#f92672>(</span>StrolchRestfulConstants<span style=color:#f92672>.</span><span style=color:#a6e22e>STROLCH_CERTIFICATE</span><span style=color:#f92672>);</span>
<span style=color:#75715e>// parse data to JSON
</span><span style=color:#75715e></span> JsonObject jsonData <span style=color:#f92672>=</span> JsonParser<span style=color:#f92672>.</span><span style=color:#a6e22e>parseString</span><span style=color:#f92672>(</span>data<span style=color:#f92672>).</span><span style=color:#a6e22e>getAsJsonObject</span><span style=color:#f92672>();</span>
<span style=color:#75715e>// instantiate the service with the argument
</span><span style=color:#75715e></span> CreateBookService svc <span style=color:#f92672>=</span> <span style=color:#66d9ef>new</span> CreateBookService<span style=color:#f92672>();</span>
JsonServiceArgument arg <span style=color:#f92672>=</span> svc<span style=color:#f92672>.</span><span style=color:#a6e22e>getArgumentInstance</span><span style=color:#f92672>();</span>
arg<span style=color:#f92672>.</span><span style=color:#a6e22e>jsonElement</span> <span style=color:#f92672>=</span> jsonData<span style=color:#f92672>;</span>
<span style=color:#75715e>// perform the service
</span><span style=color:#75715e></span> ServiceHandler serviceHandler <span style=color:#f92672>=</span> RestfulStrolchComponent<span style=color:#f92672>.</span><span style=color:#a6e22e>getInstance</span><span style=color:#f92672>().</span><span style=color:#a6e22e>getServiceHandler</span><span style=color:#f92672>();</span>
JsonServiceResult result <span style=color:#f92672>=</span> serviceHandler<span style=color:#f92672>.</span><span style=color:#a6e22e>doService</span><span style=color:#f92672>(</span>cert<span style=color:#f92672>,</span> svc<span style=color:#f92672>,</span> arg<span style=color:#f92672>);</span>
<span style=color:#75715e>// return depending on the result state
</span><span style=color:#75715e></span> <span style=color:#66d9ef>if</span> <span style=color:#f92672>(</span>result<span style=color:#f92672>.</span><span style=color:#a6e22e>isOk</span><span style=color:#f92672>())</span>
<span style=color:#66d9ef>return</span> ResponseUtil<span style=color:#f92672>.</span><span style=color:#a6e22e>toResponse</span><span style=color:#f92672>(</span>StrolchRestfulConstants<span style=color:#f92672>.</span><span style=color:#a6e22e>DATA</span><span style=color:#f92672>,</span> result<span style=color:#f92672>.</span><span style=color:#a6e22e>getResult</span><span style=color:#f92672>());</span>
<span style=color:#66d9ef>return</span> ResponseUtil<span style=color:#f92672>.</span><span style=color:#a6e22e>toResponse</span><span style=color:#f92672>(</span>result<span style=color:#f92672>);</span>
<span style=color:#f92672>}</span>
</code></pre></div><div class="notices tip"><p>Note: We return the created object again as JSON in its own data field.</p></div><p>The service is implemented as follows:</p><div class=highlight><pre style=color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4><code class=language-java data-lang=java><span style=color:#66d9ef>public</span> <span style=color:#66d9ef>class</span> <span style=color:#a6e22e>CreateBookService</span> <span style=color:#66d9ef>extends</span> AbstractService<span style=color:#f92672>&lt;</span>JsonServiceArgument<span style=color:#f92672>,</span> JsonServiceResult<span style=color:#f92672>&gt;</span> <span style=color:#f92672>{</span>
<span style=color:#a6e22e>@Override</span>
<span style=color:#66d9ef>protected</span> JsonServiceResult <span style=color:#a6e22e>getResultInstance</span><span style=color:#f92672>()</span> <span style=color:#f92672>{</span>
<span style=color:#66d9ef>return</span> <span style=color:#66d9ef>new</span> JsonServiceResult<span style=color:#f92672>();</span>
<span style=color:#f92672>}</span>
<span style=color:#a6e22e>@Override</span>
<span style=color:#66d9ef>public</span> JsonServiceArgument <span style=color:#a6e22e>getArgumentInstance</span><span style=color:#f92672>()</span> <span style=color:#f92672>{</span>
<span style=color:#66d9ef>return</span> <span style=color:#66d9ef>new</span> JsonServiceArgument<span style=color:#f92672>();</span>
<span style=color:#f92672>}</span>
<span style=color:#a6e22e>@Override</span>
<span style=color:#66d9ef>protected</span> JsonServiceResult <span style=color:#a6e22e>internalDoService</span><span style=color:#f92672>(</span>JsonServiceArgument arg<span style=color:#f92672>)</span> <span style=color:#66d9ef>throws</span> Exception <span style=color:#f92672>{</span>
<span style=color:#75715e>// open a new transaction, using the realm from the argument, or the certificate
</span><span style=color:#75715e></span> Resource book<span style=color:#f92672>;</span>
<span style=color:#66d9ef>try</span> <span style=color:#f92672>(</span>StrolchTransaction tx <span style=color:#f92672>=</span> openArgOrUserTx<span style=color:#f92672>(</span>arg<span style=color:#f92672>))</span> <span style=color:#f92672>{</span>
<span style=color:#75715e>// get a new book &#34;instance&#34; from the template
</span><span style=color:#75715e></span> book <span style=color:#f92672>=</span> tx<span style=color:#f92672>.</span><span style=color:#a6e22e>getResourceTemplate</span><span style=color:#f92672>(</span>BookShopConstants<span style=color:#f92672>.</span><span style=color:#a6e22e>TYPE_BOOK</span><span style=color:#f92672>);</span>
<span style=color:#75715e>// map all values from the JSON object into the new book element
</span><span style=color:#75715e></span> book<span style=color:#f92672>.</span><span style=color:#a6e22e>accept</span><span style=color:#f92672>(</span><span style=color:#66d9ef>new</span> FromFlatJsonVisitor<span style=color:#f92672>(</span>arg<span style=color:#f92672>.</span><span style=color:#a6e22e>jsonElement</span><span style=color:#f92672>.</span><span style=color:#a6e22e>getAsJsonObject</span><span style=color:#f92672>()).</span><span style=color:#a6e22e>ignoreBag</span><span style=color:#f92672>(</span>BAG_RELATIONS<span style=color:#f92672>));</span>
<span style=color:#75715e>// save changes
</span><span style=color:#75715e></span> tx<span style=color:#f92672>.</span><span style=color:#a6e22e>add</span><span style=color:#f92672>(</span>book<span style=color:#f92672>);</span>
<span style=color:#75715e>// notify the TX that it should commit on close
</span><span style=color:#75715e></span> tx<span style=color:#f92672>.</span><span style=color:#a6e22e>commitOnClose</span><span style=color:#f92672>();</span>
<span style=color:#f92672>}</span>
<span style=color:#75715e>// map the return value to JSON
</span><span style=color:#75715e></span> JsonObject result <span style=color:#f92672>=</span> book<span style=color:#f92672>.</span><span style=color:#a6e22e>accept</span><span style=color:#f92672>(</span><span style=color:#66d9ef>new</span> StrolchElementToJsonVisitor<span style=color:#f92672>().</span><span style=color:#a6e22e>flat</span><span style=color:#f92672>());</span>
<span style=color:#75715e>// and return the result
</span><span style=color:#75715e></span> <span style=color:#66d9ef>return</span> <span style=color:#66d9ef>new</span> JsonServiceResult<span style=color:#f92672>(</span>result<span style=color:#f92672>);</span>
<span style=color:#f92672>}</span>
<span style=color:#f92672>}</span>
</code></pre></div><div class="notices tip"><p>Note: For the authenticated user to be able to perform this service, we must add it to their privileges:</p></div><div class=highlight><pre style=color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4><code class=language-xml data-lang=xml>...
<span style=color:#f92672>&lt;Role</span> <span style=color:#a6e22e>name=</span><span style=color:#e6db74>&#34;User&#34;</span><span style=color:#f92672>&gt;</span>
...
<span style=color:#f92672>&lt;Privilege</span> <span style=color:#a6e22e>name=</span><span style=color:#e6db74>&#34;li.strolch.service.api.Service&#34;</span> <span style=color:#a6e22e>policy=</span><span style=color:#e6db74>&#34;DefaultPrivilege&#34;</span><span style=color:#f92672>&gt;</span>
<span style=color:#f92672>&lt;Allow&gt;</span>li.strolch.bookshop.service.CreateBookService<span style=color:#f92672>&lt;/Allow&gt;</span>
<span style=color:#f92672>&lt;/Privilege&gt;</span>
...
<span style=color:#f92672>&lt;/Role&gt;</span>
...
</code></pre></div><h2 id=update>Update</h2><p>Updating of a book is basically the same as the creation, we just use PUT,
verify that the book exists and give the user the privilege.</p><p><strong>PUT Method:</strong></p><div class=highlight><pre style=color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4><code class=language-java data-lang=java><span style=color:#a6e22e>@PUT</span>
<span style=color:#a6e22e>@Path</span><span style=color:#f92672>(</span><span style=color:#e6db74>&#34;{id}&#34;</span><span style=color:#f92672>)</span>
<span style=color:#a6e22e>@Produces</span><span style=color:#f92672>(</span>MediaType<span style=color:#f92672>.</span><span style=color:#a6e22e>APPLICATION_JSON</span><span style=color:#f92672>)</span>
<span style=color:#66d9ef>public</span> Response <span style=color:#a6e22e>update</span><span style=color:#f92672>(</span><span style=color:#a6e22e>@Context</span> HttpServletRequest request<span style=color:#f92672>,</span> <span style=color:#a6e22e>@PathParam</span><span style=color:#f92672>(</span><span style=color:#e6db74>&#34;id&#34;</span><span style=color:#f92672>)</span> String id<span style=color:#f92672>,</span> String data<span style=color:#f92672>)</span> <span style=color:#f92672>{</span>
<span style=color:#75715e>// this is an authenticated method call, thus we can get the certificate from the request:
</span><span style=color:#75715e></span> Certificate cert <span style=color:#f92672>=</span> <span style=color:#f92672>(</span>Certificate<span style=color:#f92672>)</span> request<span style=color:#f92672>.</span><span style=color:#a6e22e>getAttribute</span><span style=color:#f92672>(</span>StrolchRestfulConstants<span style=color:#f92672>.</span><span style=color:#a6e22e>STROLCH_CERTIFICATE</span><span style=color:#f92672>);</span>
<span style=color:#75715e>// parse data to JSON
</span><span style=color:#75715e></span> JsonObject jsonData <span style=color:#f92672>=</span> JsonParser<span style=color:#f92672>.</span><span style=color:#a6e22e>parseString</span><span style=color:#f92672>(</span>data<span style=color:#f92672>).</span><span style=color:#a6e22e>getAsJsonObject</span><span style=color:#f92672>();</span>
<span style=color:#75715e>// instantiate the service with the argument
</span><span style=color:#75715e></span> UpdateBookService svc <span style=color:#f92672>=</span> <span style=color:#66d9ef>new</span> UpdateBookService<span style=color:#f92672>();</span>
JsonServiceArgument arg <span style=color:#f92672>=</span> svc<span style=color:#f92672>.</span><span style=color:#a6e22e>getArgumentInstance</span><span style=color:#f92672>();</span>
arg<span style=color:#f92672>.</span><span style=color:#a6e22e>objectId</span> <span style=color:#f92672>=</span> id<span style=color:#f92672>;</span>
arg<span style=color:#f92672>.</span><span style=color:#a6e22e>jsonElement</span> <span style=color:#f92672>=</span> jsonData<span style=color:#f92672>;</span>
<span style=color:#75715e>// perform the service
</span><span style=color:#75715e></span> ServiceHandler serviceHandler <span style=color:#f92672>=</span> RestfulStrolchComponent<span style=color:#f92672>.</span><span style=color:#a6e22e>getInstance</span><span style=color:#f92672>().</span><span style=color:#a6e22e>getServiceHandler</span><span style=color:#f92672>();</span>
JsonServiceResult result <span style=color:#f92672>=</span> serviceHandler<span style=color:#f92672>.</span><span style=color:#a6e22e>doService</span><span style=color:#f92672>(</span>cert<span style=color:#f92672>,</span> svc<span style=color:#f92672>,</span> arg<span style=color:#f92672>);</span>
<span style=color:#75715e>// return depending on the result state
</span><span style=color:#75715e></span> <span style=color:#66d9ef>if</span> <span style=color:#f92672>(</span>result<span style=color:#f92672>.</span><span style=color:#a6e22e>isOk</span><span style=color:#f92672>())</span>
<span style=color:#66d9ef>return</span> ResponseUtil<span style=color:#f92672>.</span><span style=color:#a6e22e>toResponse</span><span style=color:#f92672>(</span>StrolchRestfulConstants<span style=color:#f92672>.</span><span style=color:#a6e22e>DATA</span><span style=color:#f92672>,</span> result<span style=color:#f92672>.</span><span style=color:#a6e22e>getResult</span><span style=color:#f92672>());</span>
<span style=color:#66d9ef>return</span> ResponseUtil<span style=color:#f92672>.</span><span style=color:#a6e22e>toResponse</span><span style=color:#f92672>(</span>result<span style=color:#f92672>);</span>
<span style=color:#f92672>}</span>
</code></pre></div><p><strong>Update Service:</strong></p><div class=highlight><pre style=color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4><code class=language-java data-lang=java><span style=color:#66d9ef>public</span> <span style=color:#66d9ef>class</span> <span style=color:#a6e22e>UpdateBookService</span> <span style=color:#66d9ef>extends</span> AbstractService<span style=color:#f92672>&lt;</span>JsonServiceArgument<span style=color:#f92672>,</span> JsonServiceResult<span style=color:#f92672>&gt;</span> <span style=color:#f92672>{</span>
<span style=color:#a6e22e>@Override</span>
<span style=color:#66d9ef>protected</span> JsonServiceResult <span style=color:#a6e22e>getResultInstance</span><span style=color:#f92672>()</span> <span style=color:#f92672>{</span>
<span style=color:#66d9ef>return</span> <span style=color:#66d9ef>new</span> JsonServiceResult<span style=color:#f92672>();</span>
<span style=color:#f92672>}</span>
<span style=color:#a6e22e>@Override</span>
<span style=color:#66d9ef>public</span> JsonServiceArgument <span style=color:#a6e22e>getArgumentInstance</span><span style=color:#f92672>()</span> <span style=color:#f92672>{</span>
<span style=color:#66d9ef>return</span> <span style=color:#66d9ef>new</span> JsonServiceArgument<span style=color:#f92672>();</span>
<span style=color:#f92672>}</span>
<span style=color:#a6e22e>@Override</span>
<span style=color:#66d9ef>protected</span> JsonServiceResult <span style=color:#a6e22e>internalDoService</span><span style=color:#f92672>(</span>JsonServiceArgument arg<span style=color:#f92672>)</span> <span style=color:#66d9ef>throws</span> Exception <span style=color:#f92672>{</span>
<span style=color:#75715e>// verify same book
</span><span style=color:#75715e></span> DBC<span style=color:#f92672>.</span><span style=color:#a6e22e>PRE</span><span style=color:#f92672>.</span><span style=color:#a6e22e>assertEquals</span><span style=color:#f92672>(</span><span style=color:#e6db74>&#34;ObjectId and given Id must be same!&#34;</span><span style=color:#f92672>,</span> arg<span style=color:#f92672>.</span><span style=color:#a6e22e>objectId</span><span style=color:#f92672>,</span>
arg<span style=color:#f92672>.</span><span style=color:#a6e22e>jsonElement</span><span style=color:#f92672>.</span><span style=color:#a6e22e>getAsJsonObject</span><span style=color:#f92672>().</span><span style=color:#a6e22e>get</span><span style=color:#f92672>(</span>Json<span style=color:#f92672>.</span><span style=color:#a6e22e>ID</span><span style=color:#f92672>).</span><span style=color:#a6e22e>getAsString</span><span style=color:#f92672>());</span>
<span style=color:#75715e>// open a new transaction, using the realm from the argument, or the certificate
</span><span style=color:#75715e></span> Resource book<span style=color:#f92672>;</span>
<span style=color:#66d9ef>try</span> <span style=color:#f92672>(</span>StrolchTransaction tx <span style=color:#f92672>=</span> openArgOrUserTx<span style=color:#f92672>(</span>arg<span style=color:#f92672>))</span> <span style=color:#f92672>{</span>
<span style=color:#75715e>// get the existing book
</span><span style=color:#75715e></span> book <span style=color:#f92672>=</span> tx<span style=color:#f92672>.</span><span style=color:#a6e22e>getResourceBy</span><span style=color:#f92672>(</span>BookShopConstants<span style=color:#f92672>.</span><span style=color:#a6e22e>TYPE_BOOK</span><span style=color:#f92672>,</span> arg<span style=color:#f92672>.</span><span style=color:#a6e22e>objectId</span><span style=color:#f92672>,</span> <span style=color:#66d9ef>true</span><span style=color:#f92672>);</span>
<span style=color:#75715e>// map all values from the JSON object into the new book element
</span><span style=color:#75715e></span> book<span style=color:#f92672>.</span><span style=color:#a6e22e>accept</span><span style=color:#f92672>(</span><span style=color:#66d9ef>new</span> FromFlatJsonVisitor<span style=color:#f92672>(</span>arg<span style=color:#f92672>.</span><span style=color:#a6e22e>jsonElement</span><span style=color:#f92672>.</span><span style=color:#a6e22e>getAsJsonObject</span><span style=color:#f92672>()).</span><span style=color:#a6e22e>ignoreBag</span><span style=color:#f92672>(</span>BAG_RELATIONS<span style=color:#f92672>));</span>
<span style=color:#75715e>// save changes
</span><span style=color:#75715e></span> tx<span style=color:#f92672>.</span><span style=color:#a6e22e>update</span><span style=color:#f92672>(</span>book<span style=color:#f92672>);</span>
<span style=color:#75715e>// notify the TX that it should commit on close
</span><span style=color:#75715e></span> tx<span style=color:#f92672>.</span><span style=color:#a6e22e>commitOnClose</span><span style=color:#f92672>();</span>
<span style=color:#f92672>}</span>
<span style=color:#75715e>// map the return value to JSON
</span><span style=color:#75715e></span> JsonObject result <span style=color:#f92672>=</span> book<span style=color:#f92672>.</span><span style=color:#a6e22e>accept</span><span style=color:#f92672>(</span><span style=color:#66d9ef>new</span> StrolchElementToJsonVisitor<span style=color:#f92672>().</span><span style=color:#a6e22e>flat</span><span style=color:#f92672>());</span>
<span style=color:#75715e>// and return the result
</span><span style=color:#75715e></span> <span style=color:#66d9ef>return</span> <span style=color:#66d9ef>new</span> JsonServiceResult<span style=color:#f92672>(</span>result<span style=color:#f92672>);</span>
<span style=color:#f92672>}</span>
<span style=color:#f92672>}</span>
</code></pre></div><p><strong>Privilege</strong></p><div class=highlight><pre style=color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4><code class=language-xml data-lang=xml>...
<span style=color:#f92672>&lt;Role</span> <span style=color:#a6e22e>name=</span><span style=color:#e6db74>&#34;User&#34;</span><span style=color:#f92672>&gt;</span>
...
<span style=color:#f92672>&lt;Privilege</span> <span style=color:#a6e22e>name=</span><span style=color:#e6db74>&#34;li.strolch.service.api.Service&#34;</span> <span style=color:#a6e22e>policy=</span><span style=color:#e6db74>&#34;DefaultPrivilege&#34;</span><span style=color:#f92672>&gt;</span>
...
<span style=color:#f92672>&lt;Allow&gt;</span>li.strolch.bookshop.service.UpdateBookService<span style=color:#f92672>&lt;/Allow&gt;</span>
...
<span style=color:#f92672>&lt;/Privilege&gt;</span>
...
<span style=color:#f92672>&lt;/Role&gt;</span>
...
</code></pre></div><h2 id=remove>Remove</h2><p>To remove a book, we need a DELETE method, a remove service and the associated
privilege.</p><p><strong>DELETE Method:</strong></p><div class=highlight><pre style=color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4><code class=language-java data-lang=java><span style=color:#a6e22e>@DELETE</span>
<span style=color:#a6e22e>@Path</span><span style=color:#f92672>(</span><span style=color:#e6db74>&#34;{id}&#34;</span><span style=color:#f92672>)</span>
<span style=color:#a6e22e>@Produces</span><span style=color:#f92672>(</span>MediaType<span style=color:#f92672>.</span><span style=color:#a6e22e>APPLICATION_JSON</span><span style=color:#f92672>)</span>
<span style=color:#66d9ef>public</span> Response <span style=color:#a6e22e>update</span><span style=color:#f92672>(</span><span style=color:#a6e22e>@Context</span> HttpServletRequest request<span style=color:#f92672>,</span> <span style=color:#a6e22e>@PathParam</span><span style=color:#f92672>(</span><span style=color:#e6db74>&#34;id&#34;</span><span style=color:#f92672>)</span> String id<span style=color:#f92672>)</span> <span style=color:#f92672>{</span>
<span style=color:#75715e>// this is an authenticated method call, thus we can get the certificate from the request:
</span><span style=color:#75715e></span> Certificate cert <span style=color:#f92672>=</span> <span style=color:#f92672>(</span>Certificate<span style=color:#f92672>)</span> request<span style=color:#f92672>.</span><span style=color:#a6e22e>getAttribute</span><span style=color:#f92672>(</span>StrolchRestfulConstants<span style=color:#f92672>.</span><span style=color:#a6e22e>STROLCH_CERTIFICATE</span><span style=color:#f92672>);</span>
<span style=color:#75715e>// instantiate the service with the argument
</span><span style=color:#75715e></span> RemoveBookService svc <span style=color:#f92672>=</span> <span style=color:#66d9ef>new</span> RemoveBookService<span style=color:#f92672>();</span>
StringServiceArgument arg <span style=color:#f92672>=</span> svc<span style=color:#f92672>.</span><span style=color:#a6e22e>getArgumentInstance</span><span style=color:#f92672>();</span>
arg<span style=color:#f92672>.</span><span style=color:#a6e22e>value</span> <span style=color:#f92672>=</span> id<span style=color:#f92672>;</span>
<span style=color:#75715e>// perform the service
</span><span style=color:#75715e></span> ServiceHandler serviceHandler <span style=color:#f92672>=</span> RestfulStrolchComponent<span style=color:#f92672>.</span><span style=color:#a6e22e>getInstance</span><span style=color:#f92672>().</span><span style=color:#a6e22e>getServiceHandler</span><span style=color:#f92672>();</span>
ServiceResult result <span style=color:#f92672>=</span> serviceHandler<span style=color:#f92672>.</span><span style=color:#a6e22e>doService</span><span style=color:#f92672>(</span>cert<span style=color:#f92672>,</span> svc<span style=color:#f92672>,</span> arg<span style=color:#f92672>);</span>
<span style=color:#75715e>// return depending on the result state
</span><span style=color:#75715e></span> <span style=color:#66d9ef>return</span> ResponseUtil<span style=color:#f92672>.</span><span style=color:#a6e22e>toResponse</span><span style=color:#f92672>(</span>result<span style=color:#f92672>);</span>
<span style=color:#f92672>}</span>
</code></pre></div><p><strong>Remove Service:</strong></p><div class=highlight><pre style=color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4><code class=language-java data-lang=java><span style=color:#66d9ef>public</span> <span style=color:#66d9ef>class</span> <span style=color:#a6e22e>RemoveBookService</span> <span style=color:#66d9ef>extends</span> AbstractService<span style=color:#f92672>&lt;</span>StringServiceArgument<span style=color:#f92672>,</span> ServiceResult<span style=color:#f92672>&gt;</span> <span style=color:#f92672>{</span>
<span style=color:#a6e22e>@Override</span>
<span style=color:#66d9ef>protected</span> ServiceResult <span style=color:#a6e22e>getResultInstance</span><span style=color:#f92672>()</span> <span style=color:#f92672>{</span>
<span style=color:#66d9ef>return</span> <span style=color:#66d9ef>new</span> ServiceResult<span style=color:#f92672>();</span>
<span style=color:#f92672>}</span>
<span style=color:#a6e22e>@Override</span>
<span style=color:#66d9ef>public</span> StringServiceArgument <span style=color:#a6e22e>getArgumentInstance</span><span style=color:#f92672>()</span> <span style=color:#f92672>{</span>
<span style=color:#66d9ef>return</span> <span style=color:#66d9ef>new</span> StringServiceArgument<span style=color:#f92672>();</span>
<span style=color:#f92672>}</span>
<span style=color:#a6e22e>@Override</span>
<span style=color:#66d9ef>protected</span> ServiceResult <span style=color:#a6e22e>internalDoService</span><span style=color:#f92672>(</span>StringServiceArgument arg<span style=color:#f92672>)</span> <span style=color:#66d9ef>throws</span> Exception <span style=color:#f92672>{</span>
<span style=color:#75715e>// open a new transaction, using the realm from the argument, or the certificate
</span><span style=color:#75715e></span> <span style=color:#66d9ef>try</span> <span style=color:#f92672>(</span>StrolchTransaction tx <span style=color:#f92672>=</span> openArgOrUserTx<span style=color:#f92672>(</span>arg<span style=color:#f92672>))</span> <span style=color:#f92672>{</span>
<span style=color:#75715e>// get the existing book
</span><span style=color:#75715e></span> Resource book <span style=color:#f92672>=</span> tx<span style=color:#f92672>.</span><span style=color:#a6e22e>getResourceBy</span><span style=color:#f92672>(</span>BookShopConstants<span style=color:#f92672>.</span><span style=color:#a6e22e>TYPE_BOOK</span><span style=color:#f92672>,</span> arg<span style=color:#f92672>.</span><span style=color:#a6e22e>value</span><span style=color:#f92672>,</span> <span style=color:#66d9ef>true</span><span style=color:#f92672>);</span>
<span style=color:#75715e>// save changes
</span><span style=color:#75715e></span> tx<span style=color:#f92672>.</span><span style=color:#a6e22e>remove</span><span style=color:#f92672>(</span>book<span style=color:#f92672>);</span>
<span style=color:#75715e>// notify the TX that it should commit on close
</span><span style=color:#75715e></span> tx<span style=color:#f92672>.</span><span style=color:#a6e22e>commitOnClose</span><span style=color:#f92672>();</span>
<span style=color:#f92672>}</span>
<span style=color:#75715e>// and return the result
</span><span style=color:#75715e></span> <span style=color:#66d9ef>return</span> ServiceResult<span style=color:#f92672>.</span><span style=color:#a6e22e>success</span><span style=color:#f92672>();</span>
<span style=color:#f92672>}</span>
<span style=color:#f92672>}</span>
</code></pre></div><p><strong>Privilege:</strong></p><div class=highlight><pre style=color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4><code class=language-xml data-lang=xml>...
<span style=color:#f92672>&lt;Role</span> <span style=color:#a6e22e>name=</span><span style=color:#e6db74>&#34;User&#34;</span><span style=color:#f92672>&gt;</span>
...
<span style=color:#f92672>&lt;Privilege</span> <span style=color:#a6e22e>name=</span><span style=color:#e6db74>&#34;li.strolch.service.api.Service&#34;</span> <span style=color:#a6e22e>policy=</span><span style=color:#e6db74>&#34;DefaultPrivilege&#34;</span><span style=color:#f92672>&gt;</span>
...
<span style=color:#f92672>&lt;Allow&gt;</span>li.strolch.bookshop.service.RemoveBookService<span style=color:#f92672>&lt;/Allow&gt;</span>
...
<span style=color:#f92672>&lt;/Privilege&gt;</span>
...
<span style=color:#f92672>&lt;/Role&gt;</span>
...
</code></pre></div><h2 id=notes>Notes</h2><p>One should now see a pattern emerge:</p><ul><li>The REST API delegates to the Services, or Searches, with the exception of the
retrieval of a single object by id.</li><li>Services should do initial validation of the input. Not much validation was
done here, but more could be done.</li><li>Commands are reusable objects to perform recurring work.</li><li>Searches and Services are privileged actions for which a user must have the
privilege to perform the action.</li></ul><p>The book services are quite simple, but as more requirements arise, it should be
easy to implement them in the service layer. Thus should a service be required
to be performed by an integration layer, then they can simply call the services,
since the input is defined and validation is done there (i.e. NOT in the REST
API).</p><p>This concludes the CRUD of books.</p><footer class=footline></footer></div></div><div id=navigation><a class="nav nav-prev" href=/tutorial/model/ title=Model><i class="fa fa-chevron-left"></i></a><a class="nav nav-next" href=/download/ title=Download style=margin-right:0><i class="fa fa-chevron-right"></i></a></div></section><div style=left:-1000px;overflow:scroll;position:absolute;top:-1000px;border:none;box-sizing:content-box;height:200px;margin:0;padding:0;width:200px><div style=border:none;box-sizing:content-box;height:200px;margin:0;padding:0;width:200px></div></div><script src=/js/clipboard.min.js?1678977092></script><script src=/js/perfect-scrollbar.min.js?1678977092></script><script src=/js/perfect-scrollbar.jquery.min.js?1678977092></script><script src=/js/jquery.sticky.js?1678977092></script><script src=/js/featherlight.min.js?1678977092></script><script src=/js/highlight.pack.js?1678977092></script><script>hljs.initHighlightingOnLoad();</script><script src=/js/modernizr.custom-3.6.0.js?1678977092></script><script src=/js/learn.js?1678977092></script><script src=/js/hugo-learn.js?1678977092></script><script src=/mermaid/mermaid.js?1678977092></script><script>mermaid.initialize({startOnLoad:true});</script><script type=text/javascript>var _paq=window._paq=window._paq||[];_paq.push(["setDocumentTitle",document.domain+"/"+document.title]);_paq.push(["setCookieDomain","*.strolch.li"]);_paq.push(['trackPageView']);_paq.push(['enableLinkTracking']);(function(){var u="https://piwik.eitchnet.ch/";_paq.push(['setTrackerUrl',u+'matomo.php']);_paq.push(['setSiteId','2']);var d=document,g=d.createElement('script'),s=d.getElementsByTagName('script')[0];g.type='text/javascript';g.async=true;g.src=u+'matomo.js';s.parentNode.insertBefore(g,s);})();</script></body></html>