Repository: incubator-juneau-website Updated Branches: refs/heads/asf-site 5d9adf951 -> 38b4b4437
http://git-wip-us.apache.org/repos/asf/incubator-juneau-website/blob/e87529b2/content/rest-server.html ---------------------------------------------------------------------- diff --git a/content/rest-server.html b/content/rest-server.html new file mode 100644 index 0000000..aa1965d --- /dev/null +++ b/content/rest-server.html @@ -0,0 +1,748 @@ +<!DOCTYPE html> +<html> +<head> +<style> + @import url("styles/juneau-code.css"); + @import url("styles/juneau-doc.css"); +</style> +</head> +<body> + + <!-- ======================================================================================================= --> + <!-- === JUNEAU-REST-SERVER ================================================================================ --> + <!-- ======================================================================================================= --> + + <h5 class='toc' id='juneau-rest-server'>juneau-rest-server</h5> + <div> + <h6 class='figure'>Maven Dependency</h6> + <p class='bcode' style='width:500px;'> + <xt><dependency></xt> + <xt><groupId></xt>org.apache.juneau<xt></groupId></xt> + <xt><artifactId></xt>juneau-rest-server<xt></artifactId></xt> + <xt><version></xt>6.4.0-incubating<xt></version></xt> + <xt></dependency></xt> + </p> + + <h6 class='figure'>Java Library</h6> + <p class='bcode' style='width:500px;'> + juneau-rest-server-6.4.0-incubating.jar + </p> + + <h6 class='figure'>OSGi Module</h6> + <p class='bcode' style='width:500px;'> + org.apache.juneau.rest.server_6.4.0-incubating.jar + </p> + + <p> + The REST server API builds upon the <code>SerializerGroup</code> and <code>ParserGroup</code> classes + to provide annotated REST servlets that automatically negotiate the HTTP media types for you. + <br>Developers simply work with requests, responses, headers, path variables, query parameters, and form data as POJOs. + <br>It allows you to create sophisticated REST interfaces using tiny amounts of code. + </p> + <p> + The end goal is to provide simple and flexible yet sophisticated REST interfaces that allow POJOs to be automatically represented as + different content types depending on whatever the particular need: + </p> + <ul class='spaced-list'> + <li>HTML for viewing POJOs in easy-to-read format in a browser. + <li>JSON for interacting through Javascript. + <li>XML for interacting with other applications. + <li>RDF for interacting with triple stores. + <li>URL-Encoding for interacting through HTML forms. + <li>MessagePack for efficiently transmitting large amounts of data. + </ul> + <p> + A simple example that supports all languages: + </p> + <p class='bcode'> + <ja>@RestResource</ja>( + path=<js>"/systemProperties"</js>, + title=<js>"System properties resource"</js> + ) + <jk>public class</jk> SystemPropertiesResource <jk>extends</jk> RestServletDefault { + + <ja>@RestMethod</ja>(name=<jsf>GET</jsf>, path=<js>"/"</js>) + <jk>public</jk> Map getSystemProperties(<ja>@Query</ja>(<js>"sort"</js>) <jk>boolean</jk> sort) <jk>throws</jk> Throwable { + <jk>if</jk> (sort) + <jk>return new</jk> TreeMap(System.<jsm>getProperties</jsm>()); + <jk>return</jk> System.<jsm>getProperties</jsm>(); + } + + <ja>@RestMethod</ja>(name=<jsf>GET</jsf>, path=<js>"/{propertyName}"</js>) + <jk>public</jk> String getSystemProperty(<ja>@Path</ja> String propertyName) <jk>throws</jk> Throwable { + <jk>return</jk> System.<jsm>getProperty</jsm>(propertyName); + } + + <ja>@RestMethod</ja>(name=<jsf>PUT</jsf>, path=<js>"/{propertyName}"</js>, guards=AdminGuard.<jk>class</jk>) + <jk>public</jk> String setSystemProperty(<ja>@Path</ja> String propertyName, <ja>@Body</ja> String value) { + System.<jsm>setProperty</jsm>(propertyName, value); + <jk>return</jk> <js>"OK"</js>; + } + + <ja>@RestMethod</ja>(name=<jsf>POST</jsf>, path=<js>"/"</js>, guards=AdminGuard.<jk>class</jk>) + <jk>public</jk> String setSystemProperties(<ja>@Body</ja> java.util.Properties newProperties) { + System.<jsm>setProperties</jsm>(newProperties); + <jk>return</jk> <js>"OK"</js>; + } + + <ja>@RestMethod</ja>(name=<jsf>DELETE</jsf>, path=<js>"/{propertyName}"</js>, guards=AdminGuard.<jk>class</jk>) + <jk>public</jk> String deleteSystemProperty(<ja>@Path</ja> String propertyName) { + System.<jsm>clearProperty</jsm>(propertyName); + <jk>return</jk> <js>"OK"</js>; + } + } + </p> + <p> + A more sophisticated example of the same resource using various features, including information + for fully populating the Swagger documentation, guards for restricting access to particular + methods, customizing supported content types and serialization options, adding g-zip compression, + and adding customized branding for the HTML views. + </p> + <p class='bcode'> + <ja>@RestResource</ja>( + path=<js>"/systemProperties"</js>, + title=<js>"System properties resource"</js>, + description=<js>"REST interface for performing CRUD operations on system properties."</js>, + messages=<js>"nls/SystemPropertiesResource"</js>, <jc>// Location of localized messages.</jc> + + <jc>// Widget used for content-type pull-down menu.</jc> + widgets={ + ContentTypeMenuItem.<jk>class</jk> + }, + + <jc>// Links on the HTML rendition page. + // "request:/..." URIs are relative to the request URI. + // "servlet:/..." URIs are relative to the servlet URI.</jc> + htmldoc=<ja>@HtmlDoc</ja>( + + <jc>// Custom navigation links.</jc> + links={ + <js>"up: request:/.."</js>, + <js>"options: servlet:/?method=OPTIONS"</js>, + <js>"form: servlet:/formPage"</js>, + <js>"$W{ContentTypeMenuItem}"</js>, + <js>"source: $C{Source/gitHub}/org/apache/juneau/examples/rest/SystemPropertiesResource.java"</js> + }, + + <jc>// Custom page text in aside section.</jc> + aside={ + <js>"<div style='max-width:800px' class='text'>"</js>, + <js>" <p>Shows standard GET/PUT/POST/DELETE operations and use of Swagger annotations.</p>"</js>, + <js>"</div>"</js> + }, + + <jc>// Custom CSS styles applied to HTML view.</jc> + style={ + <js>"aside {display:table-caption;}"</js> + } + ), + + <jc>// Set serializer, parser, and REST context properties.</jc> + properties={ + <ja>@Property</ja>(name=<jsf>SERIALIZER_quoteChar</jsf>, value=<js>"'"</js>) + }, + + <jc>// Add compression support.</jc> + encoders=GzipEncoder.<jk>class</jk>, + + <jc>// Augment generated Swagger information.</jc> + swagger=<ja>@ResourceSwagger</ja>( + contact=<js>"{name:'John Smith',email:'[email protected]'}"</js>, + license=<js>"{name:'Apache 2.0',url:'http://www.apache.org/licenses/LICENSE-2.0.html'}"</js>, + version=<js>"2.0"</js>, + termsOfService=<js>"You're on your own."</js>, + tags=<js>"[{name:'Java',description:'Java utility',externalDocs:{description:'Home page',url:'http://juneau.apache.org'}}]"</js>, + externalDocs=<js>"{description:'Home page',url:'http://juneau.apache.org'}"</js> + ) + ) + <jk>public class</jk> SystemPropertiesResource <jk>extends</jk> RestServlet { + + <ja>@RestMethod</ja>( + name=<jsf>GET</jsf>, path=<js>"/"</js>, + summary=<js>"Show all system properties"</js>, + description=<js>"Returns all system properties defined in the JVM."</js>, + + <jc>// Augment generated Swagger information.</jc> + swagger=<ja>@MethodSwagger</ja>( + parameters={ + <ja>@Parameter</ja>(in=<js>"query"</js>, name=<js>"sort"</js>, description=<js>"Sort results alphabetically."</js>, _default=<js>"false"</js>) + }, + responses={ + <ja>@Response</ja>(value=200, description=<js>"Returns a map of key/value pairs."</js>) + } + ) + ) + <jk>public</jk> Map getSystemProperties(<ja>@Query</ja>(<js>"sort"</js>) <jk>boolean</jk> sort) <jk>throws</jk> Throwable { + <jk>if</jk> (sort) + <jk>return new</jk> TreeMap(System.<jsm>getProperties</jsm>()); + <jk>return</jk> System.<jsm>getProperties</jsm>(); + } + + ... + } + </p> + + <p> + In HTML, our resource looks like this: + </p> + <img class='bordered' src='images/SystemPropertiesResource.png' width="800px"> + + <p> + When combined with the support for HTML5 beans, simple HTML forms can be constructed for easy input and output + using nothing more than Java: + </p> + <p class='bcode'> + <jk>import static</jk> org.apache.juneau.dto.html5.HtmlBuilder.*; + + <ja>@RestMethod</ja>( + name=<jsf>GET</jsf>, path=<js>"/formPage"</js>, + summary=<js>"Form entry page"</js>, + description=<js>"A form post page for setting a single system property value."</js>, + guards=AdminGuard.<jk>class</jk> + ) + <jk>public</jk> Form getFormPage() { + <jk>return</jk> <jsm>form</jsm>().method(<jsf>POST</jsf>).action(<js>"formPagePost"</js>).children( + <jsm>table</jsm>( + <jsm>tr</jsm>( + <jsm>th</jsm>(<js>"Set system property"</js>).colspan(2) + ), + <jsm>tr</jsm>( + <jsm>td</jsm>(<js>"Name: "</js>), <jsm>td</jsm>(<jsm>input</jsm>(<js>"text"</js>).name(<js>"name"</js>)) + ), + <jsm>tr</jsm>( + <jsm>td</jsm>(<js>"Value: "</js>), <jsm>td</jsm>(<jsm>input</jsm>(<js>"text"</js>).name(<js>"value"</js>)) + ) + ), + <jsm>button</jsm>(<js>"submit"</js>,<js>"Click me!"</js>).<jsm>style</jsm>(<js>"float:right"</js>) + ); + } + + <ja>@RestMethod</ja>( + name=<jsf>POST</jsf>, path=<js>"/formPagePost"</js>, + description=<js>"Accepts a simple form post of a system property name/value pair."</js>, + guards=AdminGuard.<jk>class</jk> + ) + <jk>public</jk> Redirect formPagePost(<ja>@FormData</ja>(<js>"name"</js>) String name, <ja>@FormData</ja>(<js>"value"</js>) String value) { + System.<jsm>setProperty</jsm>(name, value); + <jk>return new</jk> Redirect(<js>"servlet:/"</js>); <jc>// Redirect to the servlet top page.</jc> + } + </p> + <img class='bordered' src='images/SystemPropertiesForm.png' width="800px"> + <p> + The REST API is built on top of Servlets, making them easy to deploy in any JEE environment. + </p> + <p> + REST Java methods can return any of the following objects: + <br>POJOs, <code>Readers</code>, <code>InputStreams</code>, <code>ZipFiles</code>, <code>Redirects</code>, <code>Streamables</code>, and <code>Writables</code>. + </p> + <p> + Or add your own handlers for other types. + </p> + <p> + REST Java methods can be passed any of the following objects in any order: + </p> + <ul class='spaced-list'> + <li>Low-level request/response objects: + <br><code>HttpServletRequest</code>, <code>HttpServletResponse</code>, <code>RestRequest</code>, <code>RestResponse</code>. + <li>Intermediate-level objects: + <br><code>RequestHeaders</code>, <code>RequestQuery</code>, <code>RequestFormData</code>, <code>RequestPathMatch</code>, <code>RequestBody</code>. + <li>All RFC 2616 request header objects: + <br><code>Accept</code>, <code>AcceptLanguage</code>, <code>AcceptEncoding</code>... + <li>Annotated parameters: + <br><ja>@Header</ja>, <ja>@Query</ja>, <ja>@FormData</ja>, <ja>@Path</ja>, <ja>@PathRemainder</ja>, <ja>@Body</ja>. + <li>Other objects: + <br><code>Locale</code>, <code>ResourceBundle</code>, <code>MessageBundle</code>, <code>InputStream</code>, <code>OutputStream</code>, <code>Reader</code>, <code>Writer</code>... + <li>User-defined parameter types. + </ul> + <p> + It's up to you how you want to define your REST methods. + As a general rule, there are 3 broad approaches typically used: + </p> + + <h5 class='topic'>Methodology #1 - Annotated parameters</h5> + <p> + This approach uses annotated parameters for retrieving input from the request. + </p> + <p class='bcode'> + <ja>@RestMethod</ja>(name=<jsf>GET</jsf>, path=<js>"/example1/{p1}/{p2}/{p3}/*"</js>) + <jk>public</jk> String example1( + <ja>@Method</ja> String method, <jc>// HTTP method.</jc> + <ja>@Path</ja> String p1, <jc>// Path variables.</jc> + <ja>@Path</ja> <jk>int</jk> p2, + <ja>@Path</ja> UUID p3, + <ja>@Query</ja>(<js>"q1"</js>) <jk>int</jk> q1, <jc>// Query parameters.</jc> + <ja>@Query</ja>(<js>"q2"</js>) String q2, + <ja>@Query</ja>(<js>"q3"</js>) UUID q3, + <ja>@PathRemainder</ja> String remainder, <jc>// Path remainder after pattern match.</jc> + <ja>@Header</ja>(<js>"Accept-Language"</js>) String lang, <jc>// Headers.</jc> + <ja>@Header</ja>(<js>"Accept"</js>) String accept, + <ja>@Header</ja>(<js>"DNT"</js>) <jk>int</jk> doNotTrack + ) { + + <jc>// Send back a simple String response</jc> + String output = String.<jsm>format</jsm>( + <js>"method=%s, p1=%s, p2=%d, p3=%s, remainder=%s, q1=%d, q2=%s, q3=%s, lang=%s, accept=%s, dnt=%d"</js>, + method, p1, p2, p3, remainder, q1, q2, q3, lang, accept, doNotTrack); + <jk>return</jk> output; + } + </p> + + <h5 class='topic'>Methodology #2 - Low-level request/response objects</h5> + <p> + This approach uses low-level request/response objects to perform the same as above. + </p> + <p class='bcode'> + <ja>@RestMethod</ja>(name=<jsf>GET</jsf>, path=<js>"/example2/{p1}/{p2}/{p3}/*"</js>) + <jk>public</jk> String example2( + RestRequest req, <jc>// A direct subclass of HttpServletRequest.</jc> + RestResponse res <jc>// A direct subclass of HttpServletResponse.</jc> + ) { + + <jc>// HTTP method.</jc> + String method = req.getMethod(); + + <jc>// Path variables.</jc> + RequestPathMatch path = req.getPathMatch(); + String p1 = path.get(<js>"p1"</js>, String.<jk>class</jk>); + <jk>int</jk> p2 = path.get(<js>"p2"</js>, <jk>int</jk>.<jk>class</jk>); + UUID p3 = path.get(<js>"p3"</js>, UUID.<jk>class</jk>); + + <jc>// Query parameters.</jc> + RequestQuery query = req.getQuery(); + <jk>int</jk> q1 = query.get(<js>"q1"</js>, 0, <jk>int</jk>.<jk>class</jk>); + String q2 = query.get(<js>"q2"</js>, String.<jk>class</jk>); + UUID q3 = query.get(<js>"q3"</js>, UUID.<jk>class</jk>); + + <jc>// Path remainder after pattern match.</jc> + String remainder = req.getPathMatch().getRemainder(); + + <jc>// Headers.</jc> + String lang = req.getHeader(<js>"Accept-Language"</js>); + String accept = req.getHeader(<js>"Accept"</js>); + <jk>int</jk> doNotTrack = req.getHeaders().get(<js>"DNT"</js>, <jk>int</jk>.<jk>class</jk>); + + <jc>// Send back a simple String response</jc> + String output = String.format( + <js>"method=%s, p1=%s, p2=%d, p3=%s, remainder=%s, q1=%d, q2=%s, q3=%s, lang=%s, accept=%s, dnt=%d"</js>, + method, p1, p2, p3, remainder, q1, q2, q3, lang, accept, doNotTrack); + res.setOutput(output); <jc>// Or use getWriter().</jc> + } + </p> + + <h5 class='topic'>Methodology #3 - Intermediate-level API objects</h5> + <p> + This approach is sort of the middle ground where you get access functional area APIs. + </p> + <p class='bcode'> + <ja>@RestMethod</ja>(name=<jsf>GET</jsf>, path=<js>"/example3/{p1}/{p2}/{p3}/*"</js>) + <jk>public</jk> String example3( + HttpMethod method, <jc>// HTTP method.</jc> + RequestPathMatch path, <jc>// Path variables.</jc> + RequestQuery query, <jc>// Query parameters.</jc> + RequestHeaders headers, <jc>// Headers.</jc> + AcceptLanguage lang, <jc>// Specific header classes.</jc> + Accept accept + ) { + + <jc>// Path variables.</jc> + String p1 = path.get(<js>"p1"</js>, String.<jk>class</jk>); + <jk>int</jk> p2 = path.get(<js>"p2"</js>, <jk>int</jk>.<jk>class</jk>); + UUID p3 = path.get(<js>"p3"</js>, UUID.<jk>class</jk>); + + <jc>// Query parameters.</jc> + <jk>int</jk> q1 = query.get(<js>"q1"</js>, 0, <jk>int</jk>.<jk>class</jk>); + String q2 = query.get(<js>"q2"</js>, String.<jk>class</jk>); + UUID q3 = query.get(<js>"q3"</js>, UUID.<jk>class</jk>); + + <jc>// Path remainder after pattern match.</jc> + String remainder = path.getRemainder(); + + <jc>// Headers.</jc> + int doNotTrack = headers.get(<js>"DNT"</js>, <jk>int</jk>.<jk>class</jk>); + + <jc>// Send back a simple String response</jc> + String output = String.format( + <js>"method=%s, p1=%s, p2=%d, p3=%s, remainder=%s, q1=%d, q2=%s, q3=%s, lang=%s, accept=%s, dnt=%d"</js>, + method, p1, p2, p3, remainder, q1, q2, q3, lang, accept, doNotTrack); + res.setOutput(output); + } + </p> + <p> + All three are completely equivalent. It's up to your own coding preferences which methodology you use. + </p> + <br><hr> + <p> + Lifecycle hooks allow you to hook into lifecycle events of the servlet or REST call. + Like <ja>@RestMethod</ja> methods, the list of parameters are specified by the developer. + </p> + <p> + For example, if you want to add an initialization method to your resource: + </p> + <p class='bcode'> + <ja>@RestResource</ja>(...) + <jk>public class</jk> MyResource { + + <jc>// Our database.</jc> + <jk>private</jk> Map<Integer,Object> <jf>myDatabase</jf>; + + <ja>@RestHook</ja>(<jsf>INIT</jsf>) + <jk>public void</jk> initMyDatabase(RestConfig config) <jk>throws</jk> Exception { + <jf>myDatabase</jf> = <jk>new</jk> LinkedHashMap<>(); + } + } + </p> + <p> + Or if you want to intercept REST calls: + </p> + <p class='bcode'> + <ja>@RestResource</ja>(...) + <jk>public class</jk> MyResource { + + <jc>// Add a request attribute to all incoming requests.</jc> + <ja>@RestHook</ja>(<jsf>PRE_CALL</jsf>) + <jk>public void</jk> onPreCall(RestRequest req) { + req.setAttribute(<js>"foo"</js>, <js>"bar"</js>); + } + } + </p> + <p> + The hook events can be broken down into two categories: + </p> + <ul class='spaced-list'> + <li>Resource lifecycle events: + <ul> + <li><jsf>INIT</jsf> - Right before initialization. + <li><jsf>POST_INIT</jsf> - Right after initialization. + <li><jsf>POST_INIT_CHILD_FIRST</jsf> - Right after initialization, but run child methods first. + <li><jsf>DESTROY</jsf> - Right before servlet destroy. + </ul> + <li>REST call lifecycle events: + <ul> + <li><jsf>START_CALL</jsf> - At the beginning of a REST call. + <li><jsf>PRE_CALL</jsf> - Right before the <ja>@RestMethod</ja> method is invoked. + <li><jsf>POST_CALL</jsf> - Right after the <ja>@RestMethod</ja> method is invoked. + <li><jsf>END_CALL</jsf> - At the end of the REST call after the response has been flushed. + </ul> + </ul> + <br><hr> + <p> + Auto-generated OPTIONS pages are constructed from Swagger DTO beans, here shown serialized as HTML: + </p> + <img class='bordered' src='images/Swagger.png' width="800px"> + <p> + Swagger documentation can be populated from annotations (as above), resource bundles, or Swagger JSON files. + </p> + <p> + The page shown above is implemented on the RestServletDefault class in the method below which shows that it's doing nothing more than + serializing a Swagger bean which is constructed in the RestRequest object: + </p> + <p class='bcode'> + <ja>@RestMethod</ja>(name=<jsf>OPTIONS</jsf>, path=<js>"/*"</js>) + <jk>public</jk> Swagger getOptions(RestRequest req) { + <jk>return</jk> req.getSwagger(); + } + </p> + <br><br><hr> + <p> + Navigable hierarchies of REST resources are easy to set up either programmatically or through annotations. + <br> + The following example is the <code>RootResources</code> class from the REST examples showing how to construct + a grouping of resources using the <code>children()</code> annotation: + </p> + <p class='bcode'> + <ja>@RestResource</ja>( + path=<js>"/"</js>, + title=<js>"Root resources"</js>, + description=<js>"Example of a router resource page."</js>, + widgets={ + PoweredByApache.<jk>class</jk>, + ContentTypeMenuItem.<jk>class</jk> + }, + htmldoc=<ja>@HtmlDoc</ja>( + links={ + <js>"options: ?method=OPTIONS"</js>, + <js>"$W{ContentTypeMenuItem}"</js>, + <js>"source: $C{Source/gitHub}/org/apache/juneau/examples/rest/RootResources.java"</js> + }, + aside={ + <js>"<div style='max-width:400px' class='text'>"</js>, + <js>" <p>This is an example of a 'router' page that serves as a jumping-off point to child resources.</p>"</js>, + <js>" <p>Resources can be nested arbitrarily deep through router pages.</p>"</js>, + <js>" <p>Note the options link provided that lets you see the generated swagger doc for this page.</p>"</js>, + <js>" <p>Also note the source link on these pages to view the source code for the page.</p>"</js>, + <js>" <p>All content on pages in the UI are serialized POJOs. In this case, it's a serialized array of beans with 2 properties, 'name' and 'description'.</p>"</js>, + <js>" <p>Other features (such as this aside) are added through annotations.</p>"</js>, + <js>"</div>"</js> + }, + footer=<js>"$W{PoweredByApache}"</js> + ), + children={ + HelloWorldResource.<jk>class</jk>, + PetStoreResource.<jk>class</jk>, + SystemPropertiesResource.<jk>class</jk>, + MethodExampleResource.<jk>class</jk>, + RequestEchoResource.<jk>class</jk>, + TempDirResource.<jk>class</jk>, + AddressBookResource.<jk>class</jk>, + SampleRemoteableServlet.<jk>class</jk>, + PhotosResource.<jk>class</jk>, + AtomFeedResource.<jk>class</jk>, + JsonSchemaResource.<jk>class</jk>, + SqlQueryResource.<jk>class</jk>, + TumblrParserResource.<jk>class</jk>, + CodeFormatterResource.<jk>class</jk>, + UrlEncodedFormResource.<jk>class</jk>, + ConfigResource.<jk>class</jk>, + LogsResource.<jk>class</jk>, + DockerRegistryResource.<jk>class</jk>, + ShutdownResource.<jk>class</jk> + } + ) + <jk>public class</jk> RootResources <jk>extends</jk> RestServletGroupDefault { <jc>/* No code needed! */</jc> } + </p> + <p> + The above resource when rendered in HTML shows how easy it is to discover and navigate to child resources using a browser: + </p> + <img class='bordered' src='images/Samples_RootResources.png' width="800px"> + <p> + Resources can be nested arbitrarily deep. + The <ja>@RestResource</ja> and <ja>@RestMethod</ja> annotations can be applied to any classes, not just + servlets. The only requirement is that the top-level resource be a subclass of <code>RestServlet</code> as a hook into + the servlet container. + </p> + + <p> + The <code>juneau-examples-rest</code> project includes various other examples that highlight some of the + capabilities of the REST servlet API. + <br> + For example, the <code>PetStoreResource</code> class shows some advanced features such as using POJO renders + and converters, and HTML widgets. + </p> + <img class='bordered' src='images/PetStore.png' width="1000px"> + + <p> + The beans being serialized are shown here: + </p> + <p class='bcode'> + <jc>// Our bean class.</jc> + <jk>public class</jk> Pet { + + <ja>@Html</ja>(link=<js>"servlet:/{id}"</js>) <jc>// Creates a hyperlink in HTML view.</jc> + <ja>@NameProperty</ja> <jc>// Links the parent key to this bean.</jc> + <jk>public int</jk> <jf>id</jf>; + + <jk>public</jk> String <jf>name</jf>; + <jk>public</jk> Kind <jf>kind</jf>; + + <ja>@BeanProperty</ja>(format=<js>"$%.2f"</js>) <jc>// Renders price in dollars.</jc> + <jk>public float</jk> <jf>price</jf>; + + <ja>@BeanProperty</ja>(swap=DateSwap.<jsf>RFC2822D</jsf>.<jk>class</jk>) <jc>// Renders dates in RFC2822 format.</jc> + <jk>public</jk> Date <jf>birthDate</jf>; + + <jk>public int</jk> getAge() { + Calendar c = <jk>new</jk> GregorianCalendar(); + c.setTime(<jf>birthDate</jf>); + <jk>return new</jk> GregorianCalendar().get(Calendar.<jsf>YEAR</jsf>) - c.get(Calendar.<jsf>YEAR</jsf>); + } + } + + <ja>@Html</ja>(render=KindRender.<jk>class</jk>) <jc>// Render as an icon in HTML.</jc> + <jk>public static enum</jk> Kind { + <jsf>CAT</jsf>, <jsf>DOG</jsf>, <jsf>BIRD</jsf>, <jsf>FISH</jsf>, <jsf>MOUSE</jsf>, <jsf>RABBIT</jsf>, <jsf>SNAKE</jsf> + } + + <jk>public static class</jk> KindRender <jk>extends</jk> HtmlRender<Kind> { + <ja>@Override</ja> + <jk>public</jk> Object getContent(SerializerSession session, Kind value) { + <jk>return new</jk> Img().src(<js>"servlet:/htdocs/"</js>+value.toString().toLowerCase()+<js>".png"</js>); + } + <ja>@Override</ja> + <jk>public</jk> String getStyle(SerializerSession session, Kind value) { + <jk>return</jk> <js>"background-color:#FDF2E9"</js>; + } + } + </p> + + <p> + The <code>QUERY</code> menu item shows the capabilities of Converters which are post-processors that + work to filter POJOs after they've been returned by your Java method. + <br> + In this case, we're using the <code>Queryable</code> converter that allows us to perform search/view/sort/paging + against collections of beans: + </p> + <img class='bordered' src='images/PetStore_Query.png' width="1000px"> + + <p> + The drop-down menu items are implemented through "widgets" which allow you to embed arbitrary HTML, Javascript, + and CSS in the HTML view of the page. + </p> + <p class='bcode'> + <ja>@RestMethod</ja>( + name=<jsf>GET</jsf>, + path=<js>"/"</js>, + summary=<js>"The complete list of pets in the store"</js>, + + <jc>// Add 'query' and 'content-types' menu items.</jc> + widgets={ + QueryMenuItem.<jk>class</jk>, + ContentTypeMenuItem.<jk>class</jk>, + StyleMenuItem.<jk>class</jk> + }, + + <jc>// Add our converter for POJO query support.</jc> + converters=Queryable.<jk>class</jk>, + + <jc>// Add our menu items in the nav links.</jc> + htmldoc=<ja>@HtmlDoc</ja>( + links={ + <js>"up: request:/.."</js>, + <js>"options: servlet:/?method=OPTIONS"</js>, + <js>"$W{QueryMenuItem}"</js>, + <js>"$W{ContentTypeMenuItem}"</js>, + <js>"$W{StyleMenuItem}"</js>, + <js>"source: $C{Source/gitHub}/org/apache/juneau/examples/rest/PetStoreResource.java"</js> + } + ) + ) + <jk>public</jk> Collection<Pet> getPets() { + </p> + + <p> + HTML views are highly customizable with abilities such as defining your own look-and-feel and even allowing + you to define your own templates. + </p> + <p> + For example, the PetStore page above rendered in one of the other predefined stylesheets: + </p> + <img class='bordered' src='images/PetStore_light.png'> + <br><hr> + <p> + Automatic error handling is provided for a variety of conditions: + </p> + <ul> + <li>Automatic 401 errors (Unauthorized) on failed guards. + <li>Automatic 404 errors (Not Found) on unmatched path patterns. + <li>Automatic 405 errors (Method Not Implemented) on unimplemented methods. + <li>Automatic 406 errors (Not Acceptable) when no matching serializer was found to handle the <l>Accept</l> header. + <li>Automatic 412 errors (Precondition Failed) when all matchers failed to match. + <li>Automatic 415 errors (Unsupported Media Type) when no matching parser was found was found to handle the <l>Content-Type</l> header. + <li>Automatic 500 errors on uncaught exceptions. + <li>Throw your own runtime RestException with HTTP status and response object. + </ul> + <p> + Other features include: + </p> + <ul class='spaced-list'> + <li>Extremely simple debuggability using nothing more than your browser. + <li>Simplified localization support. + <li>Configurability through external INI files. + <li>Client-versioned responses (and other customizable heuristic matching APIs). + <li>Define and use your own HTML stylesheets. + <li>Lots of up-to-date documentation and examples. + <li>MUCH MORE!.... + </ul> + + <ul class='doctree'> + <li class='link'>See <a class='doclink' href='http://juneau.incubator.apache.org/site/apidocs/overview-summary.html#juneau-rest-server'>juneau-rest-server</a> for more information. + </ul> + + <h6 class='toc' id='juneau-rest-server.UIvsDI'>5.1.1 - User Interfaces (UI) vs. Developer Interfaces (DI)</h6> + <div> + <p> + An important distinction needs to be made about the HTML representations produced by the REST + API. These should not be considered User Interfaces, but rather Developer Interfaces. + </p> + <p> + UIs should hide the end-user from the underlying architecture. + The audience generally consists of non-technical people not interested in how the UI works. + </p> + <p> + DIs, on the other hand, should NOT hide the end-user from the underlying architecture. + Instead, it's a thin veneer over the REST interface with the following goals: + </p> + <ul class='spaced-list'> + <li>Make it easy for the developer to explore and understand the REST API. + <li>Make it easy for the developer to debug the REST API using simple tools (hopefully just a browser). + </ul> + <p> + As a result, the following guidelines are recommended: + </p> + <ul class='spaced-list'> + <li> + Use titles/descriptions/asides to describe why the REST interface exists. + A developer knowing little about it should be able to access it with a browser and quickly + understand what it is and how to use it. + <li> + Don't hide the raw data! + The HTML view should simply be considered an easier-to-read representation of the data normally + rendered in JSON or some other format. + <li> + Limit your use of Javascript! + You can use it sparingly if you want to implement something simple like a pull-down menu to + simplify some debug task, but remember that your audience cares more about interacting with your + service programmatically using REST. + Remember that the HTML is just icing on the cake. + <li> + Don't use it to implement a Web 2.0 interface! + If you want a Web 2.0 UI, implement it separately ON TOP OF this REST interface. + The architecture is flexible enough that you could in theory pull in and use jQuery, React, + Angular, or any number of sophisticated Javascript UI frameworks. Resist the urge to do so. + </ul> + </div> + </div> + + <!-- ======================================================================================================= --> + <!-- === JUNEAU-REST-SERVER-JAXRS ========================================================================== --> + <!-- ======================================================================================================= --> + + <h5 class='toc' id='juneau-rest-server-jaxrs'>juneau-rest-server-jaxrs</h5> + <div> + <h6 class='figure'>Maven Dependency</h6> + <p class='bcode' style='width:500px;'> + <xt><dependency></xt> + <xt><groupId></xt>org.apache.juneau<xt></groupId></xt> + <xt><artifactId></xt>juneau-rest-server-jaxrs<xt></artifactId></xt> + <xt><version></xt>6.4.0-incubating<xt></version></xt> + <xt></dependency></xt> + </p> + + <h6 class='figure'>Java Library</h6> + <p class='bcode' style='width:500px;'> + juneau-rest-server-jaxrs-6.4.0-incubating.jar + </p> + + <h6 class='figure'>OSGi Module</h6> + <p class='bcode' style='width:500px;'> + org.apache.juneau.rest.server.jaxrs_6.4.0-incubating.jar + </p> + + <p> + The <code>juneau-rest-server-jaxrs</code> module defines predefined <code>MessageBodyReader</code> and + <code>MessageBodyWriter</code> implementations for using Juneau serializers and parsers in JAX-RS environments. + It consists of the following classes: + </p> + <ul class='spaced-list'> + <li> + <code>org.apache.juneau.rest.jaxrs.BaseProvider</code> - The base provider class that implements the JAX-RS + <code>MessageBodyReader</code> and <code>MessageBodyWriter</code> interfaces. + <li> + <code>org.apache.juneau.rest.jaxrs.JuneauProvider</code> - Annotation that is applied to subclasses of <code>BaseProvider</code> + to specify the serializers/parsers associated with a provider, and optionally filters and properties to + apply to those serializers and parsers. + <li> + <code>org.apache.juneau.rest.jaxrs.DefaultProvider</code> - A default provider that provides the same level + of media type support as the <code>RestServletDefault</code> class. + </ul> + <p> + The JAX/RS support does provide you will the full marshalling capabilities of Juneau. + However, it should be noted that you lose some sophisticated functionality by not using the REST servlet + API (such as the Developer Interfaces, guards, path matchers, localization, auto-generated Swagger docs, etc...). + </p> + + <ul class='doctree'> + <li class='link'>See <a class='doclink' href='http://juneau.incubator.apache.org/site/apidocs/overview-summary.html#juneau-rest-server-jaxrs'>juneau-rest-server-jaxrs</a> for more information. + </ul>Ã + </div> +</body> +</html> \ No newline at end of file http://git-wip-us.apache.org/repos/asf/incubator-juneau-website/blob/e87529b2/content/svl.html ---------------------------------------------------------------------- diff --git a/content/svl.html b/content/svl.html new file mode 100644 index 0000000..1a5e714 --- /dev/null +++ b/content/svl.html @@ -0,0 +1,89 @@ +<!DOCTYPE html> +<html> +<head> +<style> + @import url("styles/juneau-code.css"); + @import url("styles/juneau-doc.css"); +</style> +</head> +<body> + <!-- ======================================================================================================= --> + <!-- === JUNEAU-SVL ======================================================================================== --> + <!-- ======================================================================================================= --> + + <h5 class='toc' id='juneau-svl'>juneau-svl</h5> + <div> + <h6 class='figure'>Maven Dependency</h6> + <p class='bcode' style='width:500px;'> + <xt><dependency></xt> + <xt><groupId></xt>org.apache.juneau<xt></groupId></xt> + <xt><artifactId></xt>juneau-svl<xt></artifactId></xt> + <xt><version></xt>6.4.0-incubating<xt></version></xt> + <xt></dependency></xt> + </p> + + <h6 class='figure'>Java Library</h6> + <p class='bcode' style='width:500px;'> + juneau-svl-6.4.0-incubating.jar + </p> + + <h6 class='figure'>OSGi Module</h6> + <p class='bcode' style='width:500px;'> + org.apache.juneau.svl_6.4.0-incubating.jar + </p> + + <p> + The <code>juneau-svl</code> module defines an API for a language called "Simple Variable Language". + In a nutshell, Simple Variable Language (or SVL) is text that contains variables of the form + <js>"$varName{varKey}"</js>. + </p> + <p> + Variables can be recursively nested within the varKey (e.g. <js>"$FOO{$BAR{xxx},$BAZ{xxx}}"</js>). + Variables can also return values that themselves contain more variables. + </p> + <p class='bcode'> + <jc>// Use the default variable resolver to resolve a string that contains $S (system property) variables</jc> + String myProperty = VarResolver.<jsf>DEFAULT</jsf>.resolve(<js>"The Java home directory is $S{java.home}"</js>); + </p> + <p> + The following shows how variables can be arbitrarily nested... + </p> + <p class='bcode'> + <jc>// Look up a property in the following order: + // 1) MYPROPERTY environment variable. + // 2) 'my.property' system property if environment variable not found. + // 3) 'not found' string if system property not found.</jc> + String myproperty = VarResolver.<jsf>DEFAULT</jsf>.resolve(<js>"$E{MYPROPERTY,$S{my.property,not found}}"</js>); + </p> + <p> + SVL is a large topic on it's own. + It is used extensively in the ConfigFile, REST and Microservice APIs. + </p> + <p> + The following is the default list of supported variables: + </p> + <ul> + <li><code>$ARG{keyOrIndex[,defaultValue]}</code> - Command-line argument. + <li><code>$C{key[,defaultValue]}</code> - Config file entry. + <li><code>$E{envVar[,defaultValue]}</code> - Environment variable. + <li><code>$F{path[,defaultValue]}</code> - File resource. + <li><code>$I{name[,defaultValue]}</code> - Servlet init parameter. + <li><code>$L{key[,args...]}</code> - Localized message. + <li><code>$MF{key[,defaultValue]}</code> - Manifest file entry. + <li><code>$R{key[,args...]}</code> - Request variable. + <li><code>$S{systemProperty[,defaultValue]}</code> - System property. + <li><code>$SA{contentType,key[,defaultValue]}</code> - Serialized request attribute. + <li><code>$U{uri}</code> - URI resolver. + <li><code>$UE{uriPart}</code> - URL-Encoder. + <li><code>$W{widgetName}</code> - HTML widget variable. + </ul> + <p> + Plugging in your own variables is also easy. + </p> + + <ul class='doctree'> + <li class='link'>See <a class='doclink' href='http://juneau.incubator.apache.org/site/apidocs/overview-summary.html#juneau-svl'>juneau-svl</a> for more information. + </ul> + </div> +</body> +</html> \ No newline at end of file
