blob: ea01519a6c93957ba464504dec8d85facedc6a52 [file] [log] [blame]
<!--
/***************************************************************************************************************************
* Licensed to the Apache Software Foundation (ASF) under one or more contributor license agreements. See the NOTICE file
* distributed with this work for additional information regarding copyright ownership. The ASF licenses this file
* to you under the Apache License, Version 2.0 (the "License"); you may not use this file except in compliance
* with the License. You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software distributed under the License is distributed on an
* "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the License for the
* specific language governing permissions and limitations under the License.
***************************************************************************************************************************/
-->
PhotosResource
<p>
The <l>PhotosResource</l> class shows examples of the following:
</p>
<ul class='spaced-list'>
<li>
How to define custom serializers and parsers at the method level.
In this case, you define a serializer and parser to handle images.
</ul>
<p>
The resource consists of a simple registry of images with integer IDs.
</p>
<p class='bpcode w800'>
http://localhost:10000/photos
</p>
<img class='bordered w800' src='doc-files/juneau-examples-rest.PhotosResource.1.png'>
<p>
It is initialized with a single entry, which can be accessed through a GET request.
</p>
<p class='bpcode w800'>
http://localhost:10000/photos/cat
</p>
<img class='bordered w800' src='doc-files/juneau-examples-rest.PhotosResource.2.png'>
<h5 class='figure'>PhotosResource.java</h5>
<p class='bpcode w800'>
<jd>/**
* Sample resource that allows images to be uploaded and retrieved.
*/</jd>
<ja>@RestResource</ja>(
path=<js>"/photos"</js>,
messages=<js>"nls/PhotosResource"</js>,
title=<js>"Photo REST service"</js>,
description=<js>"Sample resource that allows images to be uploaded and retrieved."</js>,
htmldoc=<ja>@HtmlDoc</ja>(
navlinks={
<js>"up: request:/.."</js>,
<js>"options: servlet:/?method=OPTIONS"</js>,
<js>"source: $C{Source/gitHub}/org/apache/juneau/examples/rest/$R{servletClassSimple}.java"</js>
},
aside={
<js>"&lt;div style='max-width:400px;min-width:200px' class='text'&gt;"</js>,
<js>" &lt;p&gt;Shows an example of using custom serializers and parsers to create REST interfaces over binary resources.&lt;/p&gt;"</js>,
<js>" &lt;p&gt;In this case, our resources are marshalled jpeg and png binary streams and are stored in an in-memory 'database' (also known as a &lt;code&gt;TreeMap&lt;/code&gt;).&lt;/p&gt;"</js>,
<js>"&lt;/div&gt;"</js>
}
),
properties={
<jc>// Make the anchor text on URLs be just the path relative to the servlet.</jc>
<ja>@Property</ja>(name=<jsf>HTML_uriAnchorText</jsf>, value=<js>"SERVLET_RELATIVE"</js>)
}
)
<jk>public class</jk> PhotosResource <jk>extends</jk> BasicRestServlet {
<jc>// Our cache of photos</jc>
<jk>private</jk> Map&lt;String,Photo&gt; <jf>photos</jf> = <jk>new</jk> TreeMap&lt;&gt;();
<ja>@Override</ja> <jc>/* Servlet */</jc>
<jk>public void</jk> init() {
<jk>try</jk> (InputStream is = getClass().getResourceAsStream(<js>"averycutecat.jpg"</js>)) {
BufferedImage image = ImageIO.<jsm>read</jsm>(is);
Photo photo = <jk>new</jk> Photo(<js>"cat"</js>, image);
<jf>photos</jf>.put(photo.<jf>id</jf>, photo);
} <jk>catch</jk> (IOException e) {
<jk>throw new</jk> RuntimeException(e);
}
}
<jd>/** Bean class for storing photos */</jd>
<jk>public static class</jk> Photo {
<jk>private</jk> String <jf>id</jf>;
BufferedImage <jf>image</jf>;
Photo(String id, BufferedImage image) {
<jk>this</jk>.<jf>id</jf> = id;
<jk>this</jk>.<jf>image</jf> = image;
}
<jk>public</jk> URI getURI() <jk>throws</jk> URISyntaxException {
<jk>return new</jk> URI(<js>"servlet:/"</js> + <jf>id</jf>);
}
}
<jd>/** GET request handler for list of all photos */</jd>
<ja>@RestMethod</ja>(name=<jsf>GET</jsf>, path=<js>"/"</js>, summary=<js>"Show the list of all currently loaded photos"</js>)
<jk>public</jk> Collection&lt;Photo&gt; getAllPhotos() <jk>throws</jk> Exception {
<jk>return</jk> <jf>photos</jf>.values();
}
<jd>/** GET request handler for single photo */</jd>
<ja>@RestMethod</ja>(name=<jsf>GET</jsf>, path=<js>"/{id}"</js>, serializers=ImageSerializer.<jk>class</jk>, summary=<js>"Get a photo by ID"</js>)
<jk>public</jk> BufferedImage getPhoto(<ja>@Path</ja>(<js>"id"</js>) String id) <jk>throws</jk> Exception {
Photo p = <jf>photos</jf>.get(id);
<jk>if</jk> (p == <jk>null</jk>)
<jk>throw new</jk> RestException(<jsf>SC_NOT_FOUND</jsf>, <js>"Photo not found"</js>);
<jk>return</jk> p.<jf>image</jf>;
}
<jd>/** PUT request handler */</jd>
<ja>@RestMethod</ja>(name=<jsf>PUT</jsf>, path=<js>"/{id}"</js>, parsers=ImageParser.<jk>class</jk>, summary=<js>"Add or overwrite a photo"</js>)
<jk>public</jk> String addPhoto(<ja>@Path</ja>(<js>"id"</js>) String id, <ja>@Body</ja> BufferedImage image) <jk>throws</jk> Exception {
<jf>photos</jf>.put(id, <jk>new</jk> Photo(id, image));
<jk>return</jk> <js>"OK"</js>;
}
<jd>/** POST request handler */</jd>
<ja>@RestMethod</ja>(name=<jsf>POST</jsf>, path=<js>"/"</js>, parsers=ImageParser.<jk>class</jk>, summary=<js>"Add a photo"</js>)
<jk>public</jk> Photo setPhoto(<ja>@Body</ja> BufferedImage image) <jk>throws</jk> Exception {
Photo p = <jk>new</jk> Photo(UUID.<jsm>randomUUID</jsm>().toString(), image);
<jf>photos</jf>.put(p.<jf>id</jf>, p);
<jk>return</jk> p;
}
<jd>/** DELETE request handler */</jd>
<ja>@RestMethod</ja>(name=<jsf>DELETE</jsf>, path=<js>"/{id}"</js>, summary=<js>"Delete a photo by ID"</js>)
<jk>public</jk> String deletePhoto(<ja>@Path</ja>(<js>"id"</js>) String id) <jk>throws</jk> Exception {
Photo p = <jf>photos</jf>.remove(id);
<jk>if</jk> (p == <jk>null</jk>)
<jk>throw new</jk> RestException(<jsf>SC_NOT_FOUND</jsf>, <js>"Photo not found"</js>);
<jk>return</jk> <js>"OK"</js>;
}
<jd>/** Serializer for converting images to byte streams */</jd>
<jk>public static class</jk> ImageSerializer <jk>extends</jk> OutputStreamSerializer {
<jd>/**
* Constructor.
* <ja>@param</ja> ps The property store containing all the settings for this object.
*/</jd>
<jk>public</jk> ImageSerializer(PropertyStore ps) {
<jk>super</jk>(ps, <jk>null</jk>, <js>"image/png"</js>, <js>"image/jpeg"</js>);
}
<ja>@Override</ja> <jc>/* Serializer */</jc>
<jk>public</jk> OutputStreamSerializerSession createSession(SerializerSessionArgs args) {
<jk>return new</jk> OutputStreamSerializerSession(args) {
<ja>@Override</ja> <jc>/* SerializerSession */</jc>
<jk>protected void</jk> doSerialize(SerializerPipe out, Object o) <jk>throws</jk> Exception {
RenderedImage image = (RenderedImage)o;
String mediaType = getProperty(<js>"mediaType"</js>, String.<jk>class</jk>, (String)<jk>null</jk>);
ImageIO.<jsm>write</jsm>(image, mediaType.substring(mediaType.indexOf(<js>'/'</js>)+1), out.getOutputStream());
}
};
}
}
<jd>/** Parser for converting byte streams to images */</jd>
<jk>public static class</jk> ImageParser <jk>extends</jk> InputStreamParser {
<jd>/**
* Constructor.
* <ja>@param</ja> ps The property store containing all the settings for this object.
*/</jd>
<jk>public</jk> ImageParser(PropertyStore ps) {
<jk>super</jk>(ps, <js>"image/png"</js>, <js>"image/jpeg"</js>);
}
<ja>@Override</ja> <jc>/* Parser */</jc>
<jk>public</jk> InputStreamParserSession createSession(<jk>final</jk> ParserSessionArgs args) {
<jk>return new</jk> InputStreamParserSession(args) {
<ja>@Override</ja> <jc>/* ParserSession */</jc>
<ja>@SuppressWarnings</ja>(<js>"unchecked"</js>)
<jk>protected</jk> &lt;T&gt; T doParse(ParserPipe pipe, ClassMeta&lt;T&gt; type) <jk>throws</jk> Exception {
<jk>return</jk> (T)ImageIO.<jsm>read</jsm>(pipe.getInputStream());
}
};
}
}
}
</p>