415 lines
68 KiB
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="Strolch"><link rel=icon href=/favicon.ico type=image/ico><title>CRUD Book - Strolch</title><link href=/css/nucleus.css?1660743390 rel=stylesheet><link href=/css/fontawesome-all.min.css?1660743390 rel=stylesheet><link href=/css/hybrid.css?1660743390 rel=stylesheet><link href=/css/featherlight.min.css?1660743390 rel=stylesheet><link href=/css/perfect-scrollbar.min.css?1660743390 rel=stylesheet><link href=/css/auto-complete.css?1660743390 rel=stylesheet><link href=/css/atom-one-dark-reasonable.css?1660743390 rel=stylesheet><link href=/css/theme.css?1660743390 rel=stylesheet><link href=/css/hugo-theme.css?1660743390 rel=stylesheet><link href=/css/theme-green.css?1660743390 rel=stylesheet><script src=/js/jquery-3.3.1.min.js?1660743390></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?1660743390></script><script type=text/javascript src=/js/auto-complete.js?1660743390></script><script type=text/javascript>var baseurl="https:\/\/strolch.li\/";</script><script type=text/javascript src=/js/search.js?1660743390></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-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 target=_blank><i class="fab fa-github"></i>GitHub project</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’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’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>"rest"</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>"ALL"</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>"TRACE"</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>"books"</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’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>"books"</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>"query"</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>"offset"</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>"limit"</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’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>"Book"</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><</span>U<span style=color:#f92672>></span> <span style=color:#66d9ef>extends</span> ResourceSearch<span style=color:#f92672><</span>U<span style=color:#f92672>></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>" "</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><Role</span> <span style=color:#a6e22e>name=</span><span style=color:#e6db74>"User"</span><span style=color:#f92672>></span>
|
|
<span style=color:#f92672><Privilege</span> <span style=color:#a6e22e>name=</span><span style=color:#e6db74>"li.strolch.search.StrolchSearch"</span> <span style=color:#a6e22e>policy=</span><span style=color:#e6db74>"DefaultPrivilege"</span><span style=color:#f92672>></span>
|
|
<span style=color:#f92672><Allow></span>internal<span style=color:#f92672></Allow></span>
|
|
<span style=color:#f92672><Allow></span>li.strolch.bookshop.search.BookSearch<span style=color:#f92672></Allow></span>
|
|
<span style=color:#f92672></Privilege></span>
|
|
<span style=color:#f92672></Role></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>"books"</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>"query"</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>"offset"</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>"limit"</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><</span>Resource<span style=color:#f92672>></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><</span>JsonObject<span style=color:#f92672>></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>-></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’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>"{id}"</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>"id"</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>"Book "</span> <span style=color:#f92672>+</span> id <span style=color:#f92672>+</span> <span style=color:#e6db74>" does not exist!"</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’t validated against the
|
|
user’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><</span>JsonServiceArgument<span style=color:#f92672>,</span> JsonServiceResult<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>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 "instance" 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><Role</span> <span style=color:#a6e22e>name=</span><span style=color:#e6db74>"User"</span><span style=color:#f92672>></span>
|
|
...
|
|
<span style=color:#f92672><Privilege</span> <span style=color:#a6e22e>name=</span><span style=color:#e6db74>"li.strolch.service.api.Service"</span> <span style=color:#a6e22e>policy=</span><span style=color:#e6db74>"DefaultPrivilege"</span><span style=color:#f92672>></span>
|
|
<span style=color:#f92672><Allow></span>li.strolch.bookshop.service.CreateBookService<span style=color:#f92672></Allow></span>
|
|
<span style=color:#f92672></Privilege></span>
|
|
...
|
|
<span style=color:#f92672></Role></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>"{id}"</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>"id"</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><</span>JsonServiceArgument<span style=color:#f92672>,</span> JsonServiceResult<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>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>"ObjectId and given Id must be same!"</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><Role</span> <span style=color:#a6e22e>name=</span><span style=color:#e6db74>"User"</span><span style=color:#f92672>></span>
|
|
...
|
|
<span style=color:#f92672><Privilege</span> <span style=color:#a6e22e>name=</span><span style=color:#e6db74>"li.strolch.service.api.Service"</span> <span style=color:#a6e22e>policy=</span><span style=color:#e6db74>"DefaultPrivilege"</span><span style=color:#f92672>></span>
|
|
...
|
|
<span style=color:#f92672><Allow></span>li.strolch.bookshop.service.UpdateBookService<span style=color:#f92672></Allow></span>
|
|
...
|
|
<span style=color:#f92672></Privilege></span>
|
|
...
|
|
<span style=color:#f92672></Role></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>"{id}"</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>"id"</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><</span>StringServiceArgument<span style=color:#f92672>,</span> ServiceResult<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>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><Role</span> <span style=color:#a6e22e>name=</span><span style=color:#e6db74>"User"</span><span style=color:#f92672>></span>
|
|
...
|
|
<span style=color:#f92672><Privilege</span> <span style=color:#a6e22e>name=</span><span style=color:#e6db74>"li.strolch.service.api.Service"</span> <span style=color:#a6e22e>policy=</span><span style=color:#e6db74>"DefaultPrivilege"</span><span style=color:#f92672>></span>
|
|
...
|
|
<span style=color:#f92672><Allow></span>li.strolch.bookshop.service.RemoveBookService<span style=color:#f92672></Allow></span>
|
|
...
|
|
<span style=color:#f92672></Privilege></span>
|
|
...
|
|
<span style=color:#f92672></Role></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?1660743390></script><script src=/js/perfect-scrollbar.min.js?1660743390></script><script src=/js/perfect-scrollbar.jquery.min.js?1660743390></script><script src=/js/jquery.sticky.js?1660743390></script><script src=/js/featherlight.min.js?1660743390></script><script src=/js/highlight.pack.js?1660743390></script><script>hljs.initHighlightingOnLoad();</script><script src=/js/modernizr.custom-3.6.0.js?1660743390></script><script src=/js/learn.js?1660743390></script><script src=/js/hugo-learn.js?1660743390></script><script src=/mermaid/mermaid.js?1660743390></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> |