<?xml version='1.0' encoding='UTF-8'?><?xml-stylesheet href="http://www.blogger.com/styles/atom.css" type="text/css"?><feed xmlns='http://www.w3.org/2005/Atom' xmlns:openSearch='http://a9.com/-/spec/opensearchrss/1.0/' xmlns:georss='http://www.georss.org/georss' xmlns:gd='http://schemas.google.com/g/2005' xmlns:thr='http://purl.org/syndication/thread/1.0'><id>tag:blogger.com,1999:blog-6496358939342448107</id><updated>2012-01-28T21:45:45.869+01:00</updated><category term='SVG'/><category term='GAE'/><category term='XML'/><category term='GWT'/><category term='Piriti'/><category term='Security'/><category term='JSON'/><category term='Velocity'/><category term='Restlet'/><category term='Guice'/><category term='GWTP'/><title type='text'>Random Thoughts</title><subtitle type='html'>Harald Pehls Journal of Java Development</subtitle><link rel='http://schemas.google.com/g/2005#feed' type='application/atom+xml' href='http://haraldpehl.blogspot.com/feeds/posts/default'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/6496358939342448107/posts/default?max-results=100'/><link rel='alternate' type='text/html' href='http://haraldpehl.blogspot.com/'/><link rel='hub' href='http://pubsubhubbub.appspot.com/'/><author><name>Harald Pehl</name><uri>https://profiles.google.com/112941298216109713269</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='32' height='32' src='//lh6.googleusercontent.com/-2g4YuDsTmkA/AAAAAAAAAAI/AAAAAAAACAA/dJrc8s_TFxs/s512-c/photo.jpg'/></author><generator version='7.00' uri='http://www.blogger.com'>Blogger</generator><openSearch:totalResults>17</openSearch:totalResults><openSearch:startIndex>1</openSearch:startIndex><openSearch:itemsPerPage>100</openSearch:itemsPerPage><entry><id>tag:blogger.com,1999:blog-6496358939342448107.post-8566405231727368827</id><published>2012-01-28T21:44:00.000+01:00</published><updated>2012-01-28T21:45:45.886+01:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='Velocity'/><category scheme='http://www.blogger.com/atom/ns#' term='GWT'/><category scheme='http://www.blogger.com/atom/ns#' term='Piriti'/><title type='text'>How to use Velocity to generate code in GWT</title><content type='html'>The JSON/XML mapper &lt;a href="http://code.google.com/p/piriti/"&gt;Piriti&lt;/a&gt;&amp;nbsp;is heavily based on deferred binding and code generation. As I started to implement code generators in Piriti I looked around how other projects deal with it and read thru the &lt;a href="http://code.google.com/intl/de-DE/webtoolkit/doc/latest/DevGuideCodingBasicsDeferred.html#generators"&gt;ofiicial documentation&lt;/a&gt; on the GWT site. The usual way to generate code is to extend &lt;code&gt;com.google.gwt.core.ext.Generator&lt;/code&gt; and then call &lt;code&gt;GeneratorContext.tryCreate(TreeLogger, String, String)&lt;/code&gt;. The returned PrintWriter is then often wrapped into somekind of IndentedWriter like the one &lt;a href="http://code.google.com/p/google-web-toolkit/source/browse/trunk/user/src/com/google/gwt/uibinder/rebind/IndentedWriter.java"&gt;used by GWT itself&lt;/a&gt;. This class adds methods to indent and unindent code and supports printf() like behaviour. Finally the writer is used to generate all code. This in turn results in code which looks like that:&lt;pre class="brush:java"&gt;writer.write("%s %s = null;", parameterizedValueType, value);&lt;br /&gt;writer.write("List&amp;lt;Element&amp;gt; %s = filterElements(element.selectNodes(\"%s\"));", elements, property.getPathOrName());&lt;br /&gt;writer.write("if (!%s.isEmpty()) {", elements);&lt;br /&gt;writer.indent();&lt;br /&gt;writer.write("%s = new %s&amp;lt;%s&amp;gt;();", value, collectionImplementation, elementType);&lt;br /&gt;if (property.isConverter()) {&lt;br /&gt;  // even more writer.write() statements&lt;br /&gt;}&lt;br /&gt;writer.write("for (Element currentElement : %s) {", elements);&lt;br /&gt;writer.indent();&lt;br /&gt;writer.write("%s currentValue = null;", elementType);&lt;br /&gt;writer.write("XmlReader&amp;lt;%1$s&amp;gt; currentReader = xmlRegistry.getReader(%1$s.class);", elementType);&lt;br /&gt;writer.write("if (currentReader != null) {");&lt;br /&gt;writer.indent();&lt;br /&gt;writer.write("currentValue = currentReader.read(currentElement);");&lt;br /&gt;writer.outdent();&lt;br /&gt;writer.write("}");&lt;br /&gt;writer.write("if (currentValue != null) {");&lt;br /&gt;writer.indent();&lt;br /&gt;writer.write("%s.add(currentValue);", value);&lt;br /&gt;writer.outdent();&lt;br /&gt;writer.write("}");&lt;br /&gt;writer.outdent();&lt;br /&gt;writer.write("}");&lt;br /&gt;writer.outdent();&lt;br /&gt;writer.write("}");&lt;/pre&gt;I can't help, but this code somehow reminds me of the old times, where we generated HTML code in servlets. This approach might work as long as the amount of generated code is small. In Piriti the code generation process is somewhat complex and distributed over several classes. Changing the generated code became very difficult and error-prone. Only the correct use of writer.indent() and writer.outdent() is not a trivial task. To some extent this problem can be solved by the use of an abstract base class, which contains common code. The generated class would extend from the abstract base class. But at the end of the day you have to generate some code in the concrete subclass.&lt;br /&gt;&lt;br/&gt;&lt;b&gt;Velocity to the rescue&lt;/b&gt;&lt;br/&gt;&lt;a href="http://velocity.apache.org/engine/releases/velocity-1.7/"&gt;Velocity&lt;/a&gt; is a Java-based template engine. It permits anyone to use a simple yet powerful template language to reference objects defined in Java code. Velocity supports for loops, if-then-else conditions and custom macros. Templates can include other templates. This way you can put common code in extra templates and reuse it in other templates. Velocity is mainly used in web projects for HTML generation. Another common use case is to generate email bodies. But there's no reason not to use Velocity for code generation in GWT.&lt;br /&gt;&lt;br /&gt;Doing so the above code snippet becomes something like that:&lt;br /&gt;&lt;pre class="brush:java"&gt;$parameterizedValueType $value = null;&lt;br /&gt;List&amp;lt;Element&amp;gt; $elements = filterElements(element.selectNodes("$property.pathOrName"));&lt;br /&gt;if (!${elements}.isEmpty()) {&lt;br /&gt;  $value = new $collectionImplementation&lt;$elementType&gt;();&lt;br /&gt;  #if ($property.converter) #createConverter() #end&lt;br /&gt;  for (Element currentElement : $elements) {&lt;br /&gt;    $elementType currentValue = null;&lt;br /&gt;    XmlReader&amp;lt;$elementType&amp;gt; currentReader = xmlRegistry.getReader(${elementType}.class);&lt;br /&gt;    if (currentReader != null) {&lt;br /&gt;      currentValue = currentReader.read(currentElement);&lt;br /&gt;    }&lt;br /&gt;    if (currentValue != null) {&lt;br /&gt;      ${value}.add(currentValue);&lt;br /&gt;    }&lt;br /&gt;  }&lt;br /&gt;}&lt;br /&gt;&lt;/pre&gt;If you compare the two code snippets you get the idea! The velocity based code is much more readable. As you can see the velocity template contains variable references like &lt;code&gt;$elements&lt;/code&gt;. Before the template is rendered all necessary variables must be put into the so-called Velocity context which is more or less a big map. If the variable refers to a java object you can use its properties and even call methods.&lt;br/&gt;&lt;br/&gt;To use Velocity for code generation you have to setup the Velocity engine, create the Velocity context and merge the template. In Piriti the engine is configured with the following properties:&lt;pre class="brush:text"&gt;&lt;br /&gt;velocimacro.library = name/pehl/piriti/rebind/propertyMacros.vm&lt;br /&gt;runtime.log.logsystem.class = name.pehl.piriti.rebind.VelocityLogger&lt;br /&gt;input.encoding = UTF-8&lt;br /&gt;output.encoding = UTF-8&lt;br /&gt;resource.manager.logwhenfound = true&lt;br /&gt;resource.manager.defaultcache.size = 0&lt;br /&gt;resource.loader = cp&lt;br /&gt;cp.resource.loader.class = org.apache.velocity.runtime.resource.loader.ClasspathResourceLoader&lt;br /&gt;cp.resource.loader.cache = false&lt;br /&gt;&lt;/pre&gt;  Finally the code generation process is reduced to the following lines:&lt;pre class="brush:java"&gt;PrintWriter printWriter = generatorContext.tryCreate(treeLogger, somePackage, implName);&lt;br /&gt;if (printWriter != null)&lt;br /&gt;{&lt;br /&gt;  VelocityContext context = new VelocityContext();&lt;br /&gt;  // Put all neccesarry objects into the velocity context&lt;br /&gt;  context.put("foo", ...);&lt;br /&gt;&lt;br /&gt;  InputStream inputStream = this.getClass().getClassLoader().getResourceAsStream(“name/pehl/piriti/rebind/velocity.properties”);&lt;br /&gt;  Properties properties = new Properties();&lt;br /&gt;  properties.load(inputStream);&lt;br /&gt;  VelocityEngine velocityEngine = new VelocityEngine(properties);&lt;br /&gt;  velocityEngine.mergeTemplate("someTemplate.vm", "UTF-8", context, printWriter);&lt;br /&gt;  generatorContext.commit(treeLogger, printWriter);&lt;br /&gt;}&lt;br /&gt;&lt;/pre&gt;If you want to delve deeper into the code generation process in &lt;a href="http://code.google.com/p/piriti/"&gt;Piriti&lt;/a&gt;, check out the trunk and take a look into the code.&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/6496358939342448107-8566405231727368827?l=haraldpehl.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://haraldpehl.blogspot.com/feeds/8566405231727368827/comments/default' title='Kommentare zum Post'/><link rel='replies' type='text/html' href='http://haraldpehl.blogspot.com/2012/01/how-to-use-velocity-to-generate-code-in.html#comment-form' title='0 Kommentare'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/6496358939342448107/posts/default/8566405231727368827'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/6496358939342448107/posts/default/8566405231727368827'/><link rel='alternate' type='text/html' href='http://haraldpehl.blogspot.com/2012/01/how-to-use-velocity-to-generate-code-in.html' title='How to use Velocity to generate code in GWT'/><author><name>Harald Pehl</name><uri>https://profiles.google.com/112941298216109713269</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='32' height='32' src='//lh6.googleusercontent.com/-2g4YuDsTmkA/AAAAAAAAAAI/AAAAAAAACAA/dJrc8s_TFxs/s512-c/photo.jpg'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-6496358939342448107.post-705696190025403358</id><published>2011-05-09T23:12:00.003+02:00</published><updated>2011-05-09T23:16:01.777+02:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='Piriti'/><title type='text'>Announcement: Piriti 0.7.0b1</title><content type='html'>I'm pleased to announce the first beta of the upcoming Piriti 0.7.0 release. Piriti 0.7.0 is a major release with breaking API changes, lots of new features and bugfixes.&lt;br /&gt;&lt;br /&gt;&lt;b&gt;Breaking API Changes:&lt;/b&gt;&lt;br /&gt;&lt;ul&gt;&lt;li&gt;Piriti requires GWT 2.2 and GIN 1.5&lt;/li&gt;&lt;li&gt;Dropped GXT support&lt;/li&gt;&lt;li&gt;Removed @Json, @JsonMappings, @Xml and @XmlMappings annotations&lt;/li&gt;&lt;/ul&gt;&lt;b&gt;New Features:&lt;/b&gt;&lt;br /&gt;&lt;ul&gt;&lt;li&gt;Devided Piriti into different modules:&lt;/li&gt;&lt;ul&gt;&lt;li&gt;name.pehl.piriti.commons.Commons&lt;/li&gt;&lt;li&gt;name.pehl.piriti.converter.Converter&lt;/li&gt;&lt;li&gt;name.pehl.piriti.json.JSON&lt;/li&gt;&lt;li&gt;name.pehl.piriti.property.Property&lt;/li&gt;&lt;li&gt;name.pehl.piriti.xml.XML&lt;/li&gt;&lt;/ul&gt;&lt;li&gt;Simplified mapping setup: All properties in a POJO hirarchy are now mapped by default&lt;/li&gt;&lt;li&gt;Added new annotations to overide default behaviour:&lt;/li&gt;&lt;ul&gt;&lt;li&gt;@Order&lt;/li&gt;&lt;li&gt;@Path&lt;/li&gt;&lt;li&gt;@Format&lt;/li&gt;&lt;li&gt;@Native&lt;/li&gt;&lt;li&gt;@Transient&lt;/li&gt;&lt;li&gt;@CreateWith&lt;/li&gt;&lt;li&gt;@MapUpTo&lt;/li&gt;&lt;/ul&gt;&lt;li&gt;Added @Mappings and @Mapping annotation for external mappings (JSON and XML)&lt;/li&gt;&lt;li&gt;Added support for polymorhic assoziations&lt;/li&gt;&lt;li&gt;Converters can now be used for any type&lt;/li&gt;&lt;li&gt;Added XML serialisation (not yet implemented, but scheduled for the 0.7.0 release)&lt;/li&gt;&lt;li&gt;Added support for IDs and IDREFs in JSON (not yet implemented, but scheduled for the 0.7.0 release)&lt;/li&gt;&lt;/ul&gt;&lt;b&gt;Bugfixes:&lt;/b&gt;&lt;br /&gt;&lt;ul&gt;&lt;li&gt;Fixed problems when mapping collection implementations&lt;/li&gt;&lt;li&gt;GWT.create() is now used instead of new operator&lt;/li&gt;&lt;/ul&gt;&lt;div&gt;I also restructured the wiki and added a &lt;a href="http://code.google.com/p/piriti/wiki/FAQ"&gt;FAQ&lt;/a&gt; and a &lt;a href="http://code.google.com/p/piriti/wiki/Comparison"&gt;comparison&lt;/a&gt; to other JSON / XML mappers.&amp;nbsp;Feel free to visit&amp;nbsp;&lt;a href="http://code.google.com/p/piriti/"&gt;http://code.google.com/p/piriti&lt;/a&gt;&amp;nbsp;and test the new release.&lt;/div&gt;&lt;div&gt;&lt;div style="-webkit-border-horizontal-spacing: 2px; -webkit-border-vertical-spacing: 2px; font-family: arial, sans-serif; font-size: 13px; line-height: 1.25em; max-width: 64em;"&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/6496358939342448107-705696190025403358?l=haraldpehl.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://haraldpehl.blogspot.com/feeds/705696190025403358/comments/default' title='Kommentare zum Post'/><link rel='replies' type='text/html' href='http://haraldpehl.blogspot.com/2011/05/announcement-piriti-070b1.html#comment-form' title='2 Kommentare'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/6496358939342448107/posts/default/705696190025403358'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/6496358939342448107/posts/default/705696190025403358'/><link rel='alternate' type='text/html' href='http://haraldpehl.blogspot.com/2011/05/announcement-piriti-070b1.html' title='Announcement: Piriti 0.7.0b1'/><author><name>Harald Pehl</name><uri>https://profiles.google.com/112941298216109713269</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='32' height='32' src='//lh6.googleusercontent.com/-2g4YuDsTmkA/AAAAAAAAAAI/AAAAAAAACAA/dJrc8s_TFxs/s512-c/photo.jpg'/></author><thr:total>2</thr:total></entry><entry><id>tag:blogger.com,1999:blog-6496358939342448107.post-7320986018294262725</id><published>2010-12-03T08:48:00.000+01:00</published><updated>2010-12-03T08:48:05.981+01:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='GAE'/><category scheme='http://www.blogger.com/atom/ns#' term='GWT'/><category scheme='http://www.blogger.com/atom/ns#' term='GWTP'/><category scheme='http://www.blogger.com/atom/ns#' term='Restlet'/><title type='text'>Taoki and TiRe mentioned in GWT-GAE-Book</title><content type='html'>&lt;a href="http://code.google.com/p/taoki/"&gt;Taoki&lt;/a&gt; and &lt;a href="http://code.google.com/p/tire-d8/"&gt;TiRe&lt;/a&gt; are mentioned in the free online book on GWT and AppEngine &lt;br /&gt;development by Marius Andreiana.  &lt;br /&gt;&lt;br /&gt;The book covers also a lot of &lt;a href="http://code.google.com/p/gwt-platform/"&gt;GWTP&lt;/a&gt; and its core examples are great illustrations for many features of the framework! It also makes use of Gin, Guice, Twig-Persist, Mockito and many other useful tools. &lt;br /&gt;&lt;br /&gt;Go check it out: &lt;a href="http://code.google.com/p/gwt-gae-book/"&gt;http://code.google.com/p/gwt-gae-book/&lt;/a&gt; &lt;br /&gt;&lt;br /&gt;Many thanks to Marius for such a valuable resource, and congratulations on publishing it!&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/6496358939342448107-7320986018294262725?l=haraldpehl.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://haraldpehl.blogspot.com/feeds/7320986018294262725/comments/default' title='Kommentare zum Post'/><link rel='replies' type='text/html' href='http://haraldpehl.blogspot.com/2010/12/taoki-and-tire-mentioned-in-gwt-gae.html#comment-form' title='0 Kommentare'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/6496358939342448107/posts/default/7320986018294262725'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/6496358939342448107/posts/default/7320986018294262725'/><link rel='alternate' type='text/html' href='http://haraldpehl.blogspot.com/2010/12/taoki-and-tire-mentioned-in-gwt-gae.html' title='Taoki and TiRe mentioned in GWT-GAE-Book'/><author><name>Harald Pehl</name><uri>https://profiles.google.com/112941298216109713269</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='32' height='32' src='//lh6.googleusercontent.com/-2g4YuDsTmkA/AAAAAAAAAAI/AAAAAAAACAA/dJrc8s_TFxs/s512-c/photo.jpg'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-6496358939342448107.post-8323927492504260804</id><published>2010-10-27T15:52:00.000+02:00</published><updated>2010-10-27T15:52:52.360+02:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='Piriti'/><title type='text'>Announcement: Piriti 0.6</title><content type='html'>I'm pleased to announce Piriti 0.6. This is a major update which adds support for JSONPath expressions. Please take a look at the &lt;a href="http://code.google.com/p/piriti/wiki/ReleaseNotes"&gt;release notes&lt;/a&gt; for further info.&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/6496358939342448107-8323927492504260804?l=haraldpehl.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://haraldpehl.blogspot.com/feeds/8323927492504260804/comments/default' title='Kommentare zum Post'/><link rel='replies' type='text/html' href='http://haraldpehl.blogspot.com/2010/10/announcement-piriti-06.html#comment-form' title='2 Kommentare'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/6496358939342448107/posts/default/8323927492504260804'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/6496358939342448107/posts/default/8323927492504260804'/><link rel='alternate' type='text/html' href='http://haraldpehl.blogspot.com/2010/10/announcement-piriti-06.html' title='Announcement: Piriti 0.6'/><author><name>Harald Pehl</name><uri>https://profiles.google.com/112941298216109713269</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='32' height='32' src='//lh6.googleusercontent.com/-2g4YuDsTmkA/AAAAAAAAAAI/AAAAAAAACAA/dJrc8s_TFxs/s512-c/photo.jpg'/></author><thr:total>2</thr:total></entry><entry><id>tag:blogger.com,1999:blog-6496358939342448107.post-7404411292745615649</id><published>2010-10-03T22:53:00.005+02:00</published><updated>2010-10-04T09:07:09.605+02:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='GAE'/><category scheme='http://www.blogger.com/atom/ns#' term='GWT'/><category scheme='http://www.blogger.com/atom/ns#' term='SVG'/><category scheme='http://www.blogger.com/atom/ns#' term='JSON'/><category scheme='http://www.blogger.com/atom/ns#' term='GWTP'/><category scheme='http://www.blogger.com/atom/ns#' term='Guice'/><category scheme='http://www.blogger.com/atom/ns#' term='Restlet'/><category scheme='http://www.blogger.com/atom/ns#' term='Piriti'/><title type='text'>TiRe - Time recording made easy</title><content type='html'>Currently I'm developing a personal time recording tool based on GWT and deployed at Google App Engine. Besides being useful I wanted to use the latest web techniques / frameworks in a real application. TiRe uses the following stack:&lt;br /&gt;&lt;ul&gt;&lt;li&gt;&lt;a href="http://code.google.com/appengine/"&gt;Google App Engine 1.3.x&lt;/a&gt;&lt;br /&gt;&lt;li&gt;&lt;a href="http://code.google.com/p/google-guice/"&gt;Guice / GIN&lt;/a&gt;&lt;br /&gt;&lt;li&gt;&lt;a href="http://code.google.com/p/objectify-appengine/"&gt;Objectify&lt;/a&gt;&lt;br /&gt;&lt;li&gt;&lt;a href="http://www.restlet.org"&gt;Restlet&lt;/a&gt;&lt;br /&gt;&lt;li&gt;&lt;a href="http://code.google.com/p/taoki/"&gt;Taoki&lt;/a&gt;&lt;br /&gt;&lt;li&gt;&lt;a href="http://code.google.com/webtoolkit/"&gt;GWT 2.x&lt;/a&gt;&lt;br /&gt;&lt;li&gt;&lt;a href="http://code.google.com/p/gwt-platform/"&gt;GWTP&lt;/a&gt;&lt;br /&gt;&lt;li&gt;&lt;a href="http://code.google.com/p/piriti/"&gt;Piriti&lt;/a&gt;&lt;br /&gt;&lt;li&gt;&lt;a href="http://raphaeljs.com/"&gt;Raphaël&lt;/a&gt;&lt;br /&gt;&lt;/ul&gt;Work is still in progress. But you can take a first look at TiRe following the link below. One last note: TiRe uses some of the new HTML5 / CSS3 features and therefore requires a modern browser.&lt;p&gt;&lt;a href="http://tire-d8.appspot.com/"&gt;http://tire-d8.appspot.com/&lt;/a&gt;&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/6496358939342448107-7404411292745615649?l=haraldpehl.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://haraldpehl.blogspot.com/feeds/7404411292745615649/comments/default' title='Kommentare zum Post'/><link rel='replies' type='text/html' href='http://haraldpehl.blogspot.com/2010/10/tire-time-recording-made-easy.html#comment-form' title='0 Kommentare'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/6496358939342448107/posts/default/7404411292745615649'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/6496358939342448107/posts/default/7404411292745615649'/><link rel='alternate' type='text/html' href='http://haraldpehl.blogspot.com/2010/10/tire-time-recording-made-easy.html' title='TiRe - Time recording made easy'/><author><name>Harald Pehl</name><uri>https://profiles.google.com/112941298216109713269</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='32' height='32' src='//lh6.googleusercontent.com/-2g4YuDsTmkA/AAAAAAAAAAI/AAAAAAAACAA/dJrc8s_TFxs/s512-c/photo.jpg'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-6496358939342448107.post-4265495842532180593</id><published>2010-09-13T11:21:00.002+02:00</published><updated>2010-09-13T11:28:31.875+02:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='Restlet'/><title type='text'>Paging in resources</title><content type='html'>A common requirement for resources which return large collections of records is paging. Paging can be implemented in many different ways. See the following pages as an entry point to the discussion: &lt;br /&gt;&lt;ul&gt;&lt;li&gt;&lt;a href="http://stackoverflow.com/questions/924472/paging-in-a-rest-collection"&gt;Stackoverflow&lt;/a&gt;&lt;br /&gt;&lt;li&gt;&lt;a href="http://docs.dojocampus.org/dojox/data/JsonRestStore#paging"&gt;DOJO&lt;/a&gt;&lt;br /&gt;&lt;/ul&gt;In the following sections I will introduce three different solutions. All of them are implemented in &lt;a href="http://code.google.com/p/taoki/"&gt;Taoki&lt;/a&gt; - a small extension for &lt;a href="http://www.restlet.org/"&gt;Restlet&lt;/a&gt;.  &lt;h4 style="margin: 1em 0 0 0;"&gt;Template Parameter&lt;/h4&gt;This implementation uses parts of the url to carry the paging information: &lt;pre&gt;GET /books&lt;br /&gt;GET /books/0/50&lt;br /&gt;GET /books/0/50/author/asc&lt;br /&gt;&lt;/pre&gt;The advantage of this implementation is that the resource can be cached by proxies. The drawback is that a lot of template parameters are "wasted". For example &lt;code&gt;/books/report/{quarter}&lt;/code&gt; won't be available as route, since it is occupied by &lt;code&gt;/books/{offset}/{pageSize}&lt;/code&gt;  &lt;h4 style="margin: 1em 0 0 0;"&gt;Query Parameter&lt;/h4&gt;This implementation uses query parameter.  &lt;pre&gt;GET /books&lt;br /&gt;GET /books?offset=0&amp;limit=50&lt;br /&gt;GET /books?offset=0&amp;limit=50&amp;sortField=author&amp;sortDir=asc&lt;br /&gt;&lt;/pre&gt;Most proxies won't cache resources which include parameters, but there are no template parameters wasted.  &lt;h4 style="margin: 1em 0 0 0;"&gt;Custom Header&lt;/h4&gt;This implementation uses the custom header &lt;code&gt;Item-Range&lt;/code&gt;. &lt;pre&gt;GET /books&lt;br /&gt;GET /books&lt;br /&gt;Item-Range: items=0-49&lt;br /&gt;GET /books&lt;br /&gt;Item-Range: items=0-49;author:desc&lt;br /&gt;&lt;/pre&gt;It combines the advantages of the other two implementations. A minor drawback of this solution is that the paging information is no longer visible in the URL.&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/6496358939342448107-4265495842532180593?l=haraldpehl.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://haraldpehl.blogspot.com/feeds/4265495842532180593/comments/default' title='Kommentare zum Post'/><link rel='replies' type='text/html' href='http://haraldpehl.blogspot.com/2010/09/paging-in-resources.html#comment-form' title='0 Kommentare'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/6496358939342448107/posts/default/4265495842532180593'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/6496358939342448107/posts/default/4265495842532180593'/><link rel='alternate' type='text/html' href='http://haraldpehl.blogspot.com/2010/09/paging-in-resources.html' title='Paging in resources'/><author><name>Harald Pehl</name><uri>https://profiles.google.com/112941298216109713269</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='32' height='32' src='//lh6.googleusercontent.com/-2g4YuDsTmkA/AAAAAAAAAAI/AAAAAAAACAA/dJrc8s_TFxs/s512-c/photo.jpg'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-6496358939342448107.post-3079832205718857096</id><published>2010-07-07T16:28:00.000+02:00</published><updated>2010-07-07T16:28:14.944+02:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='Piriti'/><title type='text'>Announcement: Piriti 0.4</title><content type='html'>I'm pleased to announce Piriti 0.4. This is a major update which adds support for namespaces in XML document and XPath expressions. Please take a look at the &lt;a href="http://code.google.com/p/piriti/wiki/ReleaseNotes"&gt;release notes&lt;/a&gt; for further info.&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/6496358939342448107-3079832205718857096?l=haraldpehl.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://haraldpehl.blogspot.com/feeds/3079832205718857096/comments/default' title='Kommentare zum Post'/><link rel='replies' type='text/html' href='http://haraldpehl.blogspot.com/2010/07/announcement-piriti-04.html#comment-form' title='0 Kommentare'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/6496358939342448107/posts/default/3079832205718857096'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/6496358939342448107/posts/default/3079832205718857096'/><link rel='alternate' type='text/html' href='http://haraldpehl.blogspot.com/2010/07/announcement-piriti-04.html' title='Announcement: Piriti 0.4'/><author><name>Harald Pehl</name><uri>https://profiles.google.com/112941298216109713269</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='32' height='32' src='//lh6.googleusercontent.com/-2g4YuDsTmkA/AAAAAAAAAAI/AAAAAAAACAA/dJrc8s_TFxs/s512-c/photo.jpg'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-6496358939342448107.post-8834805877758814611</id><published>2010-07-07T13:37:00.000+02:00</published><updated>2010-07-07T13:37:39.551+02:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='GWT'/><category scheme='http://www.blogger.com/atom/ns#' term='XML'/><title type='text'>New XML parser for GWT</title><content type='html'>I'm pleased to announce the first release of &lt;a href="http://code.google.com/p/totoe/"&gt;Totoe&lt;/a&gt;. Totoe is a XML parser for GWT which comes with XPath and namespace support. It originated from &lt;a href="http://code.google.com/p/piriti/"&gt;Piriti&lt;/a&gt; a JSON and XML mapper for GWT.&lt;br /&gt;&lt;br /&gt;Totoe uses &lt;a href="http://dev.abiss.gr/sarissa/"&gt;Sarissa&lt;/a&gt; for the XML parsing. Sarissa is a great cross browser XML parser for javascript. Essentially Totoe is a GWT port of Sarissa with the goal to offer a similar API as the GWT XML module. Right now the focus is on parsing XML - there are no methods to create, insert or append documents, elements or nodes. Those features might come in later releases. The big advantage over the GWT XML module is IMHO a cleaner API and the support of XPath and namespaces.&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/6496358939342448107-8834805877758814611?l=haraldpehl.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://haraldpehl.blogspot.com/feeds/8834805877758814611/comments/default' title='Kommentare zum Post'/><link rel='replies' type='text/html' href='http://haraldpehl.blogspot.com/2010/07/new-xml-parser-for-gwt.html#comment-form' title='1 Kommentare'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/6496358939342448107/posts/default/8834805877758814611'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/6496358939342448107/posts/default/8834805877758814611'/><link rel='alternate' type='text/html' href='http://haraldpehl.blogspot.com/2010/07/new-xml-parser-for-gwt.html' title='New XML parser for GWT'/><author><name>Harald Pehl</name><uri>https://profiles.google.com/112941298216109713269</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='32' height='32' src='//lh6.googleusercontent.com/-2g4YuDsTmkA/AAAAAAAAAAI/AAAAAAAACAA/dJrc8s_TFxs/s512-c/photo.jpg'/></author><thr:total>1</thr:total></entry><entry><id>tag:blogger.com,1999:blog-6496358939342448107.post-3482848358663742689</id><published>2010-06-18T17:19:00.003+02:00</published><updated>2010-06-18T17:21:47.718+02:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='Piriti'/><title type='text'>Announcement: Piriti 0.3.5</title><content type='html'>I'm pleased to announce Piriti 0.3.5. This is a minor update which fixes some bugs and changes the way JSON data is parsed. Please take a look at the &lt;a href="http://code.google.com/p/piriti/wiki/ReleaseNotes"&gt;release notes&lt;/a&gt; for further info. &lt;br /&gt;&lt;br /&gt;I'm still looking for a clever way to include namespace support into Piriti. So if there's anybody out there with a namespace aware XPath implementation that works in IE, contact me!&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/6496358939342448107-3482848358663742689?l=haraldpehl.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://haraldpehl.blogspot.com/feeds/3482848358663742689/comments/default' title='Kommentare zum Post'/><link rel='replies' type='text/html' href='http://haraldpehl.blogspot.com/2010/06/im-pleased-to-announce-piriti-0.html#comment-form' title='0 Kommentare'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/6496358939342448107/posts/default/3482848358663742689'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/6496358939342448107/posts/default/3482848358663742689'/><link rel='alternate' type='text/html' href='http://haraldpehl.blogspot.com/2010/06/im-pleased-to-announce-piriti-0.html' title='Announcement: Piriti 0.3.5'/><author><name>Harald Pehl</name><uri>https://profiles.google.com/112941298216109713269</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='32' height='32' src='//lh6.googleusercontent.com/-2g4YuDsTmkA/AAAAAAAAAAI/AAAAAAAACAA/dJrc8s_TFxs/s512-c/photo.jpg'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-6496358939342448107.post-6493763525680483600</id><published>2010-03-26T14:07:00.000+01:00</published><updated>2010-03-26T14:07:11.511+01:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='Piriti'/><title type='text'>Announcement: Piriti 0.3.1</title><content type='html'>I'm pleased to announce Piriti 0.3.1. Piriti is a JSON and XML mapper for GWT. It is based on annotations and deferred binding. Here are some of the features: &lt;br /&gt;&lt;ul&gt;&lt;li&gt;Built-in support for many types (primitives, String, Date, Enums, ..) &lt;br /&gt;&lt;li&gt;Possibility to specify date and number formats &lt;br /&gt;&lt;li&gt;Support for mapping arrays and collections &lt;br /&gt;&lt;li&gt;Flexible XML mapping using XPath expressions &lt;br /&gt;&lt;li&gt;GXT extension for mapping to GXT models &lt;br /&gt;&lt;li&gt;Restlet extension built on top of the Restlet GWT edition &lt;br /&gt;&lt;/ul&gt;If you want to learn more about Piriti here are some links where you can start:&lt;ul&gt;&lt;li&gt;Project page: &lt;a href="http://code.google.com/p/piriti/"&gt;http://code.google.com/p/piriti/&lt;/a&gt; &lt;br /&gt;&lt;li&gt;Getting started: &lt;a href="http://code.google.com/p/piriti/wiki/GettingStarted"&gt;http://code.google.com/p/piriti/wiki/GettingStarted&lt;/a&gt; &lt;br /&gt;&lt;li&gt;Sample application: &lt;a href="http://piriti-sample.appspot.com/"&gt;http://piriti-sample.appspot.com/&lt;/a&gt; &lt;br /&gt;&lt;/ul&gt;&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/6496358939342448107-6493763525680483600?l=haraldpehl.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://haraldpehl.blogspot.com/feeds/6493763525680483600/comments/default' title='Kommentare zum Post'/><link rel='replies' type='text/html' href='http://haraldpehl.blogspot.com/2010/03/announcement-piriti-031.html#comment-form' title='1 Kommentare'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/6496358939342448107/posts/default/6493763525680483600'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/6496358939342448107/posts/default/6493763525680483600'/><link rel='alternate' type='text/html' href='http://haraldpehl.blogspot.com/2010/03/announcement-piriti-031.html' title='Announcement: Piriti 0.3.1'/><author><name>Harald Pehl</name><uri>https://profiles.google.com/112941298216109713269</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='32' height='32' src='//lh6.googleusercontent.com/-2g4YuDsTmkA/AAAAAAAAAAI/AAAAAAAACAA/dJrc8s_TFxs/s512-c/photo.jpg'/></author><thr:total>1</thr:total></entry><entry><id>tag:blogger.com,1999:blog-6496358939342448107.post-7194030977532348571</id><published>2010-03-26T12:11:00.001+01:00</published><updated>2010-03-26T14:04:34.837+01:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='Piriti'/><title type='text'>Sample application for Piriti</title><content type='html'>I created a sample application for Piriti which demonstrates its basic features:&lt;br /&gt;&lt;br /&gt;&lt;a href="http://piriti-sample.appspot.com/"&gt;http://piriti-sample.appspot.com/&lt;/a&gt;&lt;br /&gt;&lt;br /&gt;The sample provides a 'books' resources which returns three books. The resource is available in two representations:&lt;br /&gt;&lt;ul&gt;&lt;li&gt;&lt;a href="http://piriti-sample.appspot.com/rest/v1/books"&gt;XML&lt;/a&gt;&lt;/li&gt;&lt;li&gt;JSON. To see the representation use some kind of rest client (e.g. &lt;a href="http://hypertopic.org/index.php/RESTClient"&gt;RESTClient for Firefox&lt;/a&gt;), call 'http://piriti-sample.appspot.com/rest/v1/books' and set the 'Accept' header to 'application/json'&lt;/li&gt;&lt;/ul&gt;&lt;br /&gt;The sample has links to request each representation and convert the results to POJOs and GXT models. For each request the relevant source code plus the processing time (without network traffic) is displayed.&lt;br /&gt;&lt;br /&gt;The full source code of the sample application is available in the subversion &lt;a href="http://code.google.com/p/piriti/source/browse"&gt;repository&lt;/a&gt; or as seperate &lt;a href="http://piriti.googlecode.com/files/piriti-sample-0.3.1.zip"&gt;download&lt;/a&gt;.&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/6496358939342448107-7194030977532348571?l=haraldpehl.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://haraldpehl.blogspot.com/feeds/7194030977532348571/comments/default' title='Kommentare zum Post'/><link rel='replies' type='text/html' href='http://haraldpehl.blogspot.com/2010/03/sample-application-for-piriti.html#comment-form' title='0 Kommentare'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/6496358939342448107/posts/default/7194030977532348571'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/6496358939342448107/posts/default/7194030977532348571'/><link rel='alternate' type='text/html' href='http://haraldpehl.blogspot.com/2010/03/sample-application-for-piriti.html' title='Sample application for Piriti'/><author><name>Harald Pehl</name><uri>https://profiles.google.com/112941298216109713269</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='32' height='32' src='//lh6.googleusercontent.com/-2g4YuDsTmkA/AAAAAAAAAAI/AAAAAAAACAA/dJrc8s_TFxs/s512-c/photo.jpg'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-6496358939342448107.post-5738895896720663040</id><published>2010-03-25T09:49:00.005+01:00</published><updated>2010-03-26T11:39:59.010+01:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='GWT'/><category scheme='http://www.blogger.com/atom/ns#' term='JSON'/><category scheme='http://www.blogger.com/atom/ns#' term='XML'/><category scheme='http://www.blogger.com/atom/ns#' term='Restlet'/><category scheme='http://www.blogger.com/atom/ns#' term='Piriti'/><title type='text'>Restlet extension of Piriti</title><content type='html'>&lt;a href="http://www.restlet.org"&gt;Restlet&lt;/a&gt; is a RESTful Web framework for Java. There's also a &lt;a href="http://blog.noelios.com/2008/07/25/restlet-ported-to-gwt/"&gt;GWT edition&lt;/a&gt; available. The Piriti Restlet extensions is built on top of that edition. Therefore the 2.x version of Restlet is used. There are two representations available which use the Piriti readers to convert JSON and XML data to your model (POJOs and/or GXT models).&lt;br /&gt;&lt;br /&gt;&lt;b&gt;Read and convert JSON&lt;/b&gt;&lt;br /&gt;To read the JSON data you need an instance of &lt;code&gt;JsonReader&amp;lt;T&amp;gt;&lt;/code&gt;:&lt;br /&gt;&lt;pre class="brush: java"&gt;public class Book&lt;br /&gt;{&lt;br /&gt;    interface BookReader extends JsonReader&amp;lt;Book&amp;gt; {}&lt;br /&gt;    public static final BookReader JSON = GWT.create(BookReader.class);&lt;br /&gt;&lt;br /&gt;    // Fields annotated with @JsonField&lt;br /&gt;    ...&lt;br /&gt;}&lt;br /&gt;&lt;/pre&gt;Then you can read the JSON data like this:&lt;br /&gt;&lt;pre class="brush: java"&gt;ClientResource clientResource = &lt;br /&gt;    new ClientResource("/resource/with/json/representation");&lt;br /&gt;clientResource.setOnResponse(new Uniform()&lt;br /&gt;{&lt;br /&gt;    @Override&lt;br /&gt;    public void handle(Request request, Response response)&lt;br /&gt;    {&lt;br /&gt;        PiritiJsonRepresentation&amp;lt;Book&amp;gt; representation = &lt;br /&gt;            new PiritiJsonRepresentation&amp;lt;Book&amp;gt;(Book.JSON, response.getEntity());&lt;br /&gt;        try&lt;br /&gt;        {&lt;br /&gt;            // Depending whether there's one book or an array of books&lt;br /&gt;            // in your JSON data&lt;br /&gt;            List&amp;lt;Book&amp;gt; books = representation.getModels();&lt;br /&gt;            Book book = representation.getModel();&lt;br /&gt;        }&lt;br /&gt;        catch (IOException e)&lt;br /&gt;        {&lt;br /&gt;            e.printStackTrace();&lt;br /&gt;        }&lt;br /&gt;    }&lt;br /&gt;});&lt;br /&gt;clientResource.get(MediaType.APPLICATION_JSON);&lt;br /&gt;&lt;/pre&gt;The entity returned by the resource has to be a valid JSON object. In case you want to read a list of books, the JSON object has to contain one key (name does not matter) with the array of books:&lt;br /&gt;&lt;pre class="brush: js"&gt;{books: [{isbn: "0815", title: "Foo"}, {isbn: "1234", title: "Bar"}]}&lt;br /&gt;&lt;/pre&gt;&lt;br /&gt;&lt;b&gt;Read and convert XML&lt;/b&gt;&lt;br /&gt;To read the XML data you need an instance of &lt;code&gt;XmlReader&amp;lt;T&amp;gt;&lt;/code&gt;&lt;br /&gt;&lt;pre class="brush: java"&gt;public class Book&lt;br /&gt;{&lt;br /&gt;    interface BookReader extends XmlReader&amp;lt;Book&amp;gt; {}&lt;br /&gt;    public static final BookReader XML = GWT.create(BookReader.class);&lt;br /&gt;&lt;br /&gt;    // Fields annotated with @XmlField&lt;br /&gt;    ...&lt;br /&gt;}&lt;br /&gt;&lt;/pre&gt;Then you can read the XML data like this:&lt;br /&gt;&lt;pre class="brush: java"&gt;ClientResource clientResource = &lt;br /&gt;    new ClientResource("/resource/with/xml/representation");&lt;br /&gt;clientResource.setOnResponse(new Uniform()&lt;br /&gt;{&lt;br /&gt;    @Override&lt;br /&gt;    public void handle(Request request, Response response)&lt;br /&gt;    {&lt;br /&gt;        PiritiXmlRepresentation&amp;lt;Book&amp;gt; representation = &lt;br /&gt;            new PiritiXmlRepresentation&amp;lt;Book&amp;gt;(Book.XML, response.getEntity());&lt;br /&gt;        try&lt;br /&gt;        {&lt;br /&gt;            // Depending whether there's one book element or a list of book&lt;br /&gt;            // elements in your XML data&lt;br /&gt;            List&amp;lt;Book&amp;gt; books = representation.getModels();&lt;br /&gt;            Book book = representation.getModel();&lt;br /&gt;        }&lt;br /&gt;        catch (IOException e)&lt;br /&gt;        {&lt;br /&gt;            e.printStackTrace();&lt;br /&gt;        }&lt;br /&gt;    }&lt;br /&gt;});&lt;br /&gt;clientResource.get(MediaType.TEXT_XML);&lt;br /&gt;&lt;/pre&gt;The entity returned by the resource has to be a valid XML document. In case you want to read a list of books, the document must contain a list of book elements as direct children of the root element:&lt;br /&gt;&lt;pre class="brush: xml"&gt;&amp;lt;books&amp;gt;&lt;br /&gt;    &amp;lt;book&amp;gt;&lt;br /&gt;        &amp;lt;isbn&amp;gt;0815&amp;lt;/isbn&amp;gt;&lt;br /&gt;        &amp;lt;title&amp;gt;Foo&amp;lt;/title&amp;gt;&lt;br /&gt;    &amp;lt;/book&amp;gt;&lt;br /&gt;    &amp;lt;book&amp;gt;&lt;br /&gt;        &amp;lt;isbn&amp;gt;1234&amp;lt;/isbn&amp;gt;&lt;br /&gt;        &amp;lt;title&amp;gt;Bar&amp;lt;/title&amp;gt;&lt;br /&gt;    &amp;lt;/book&amp;gt;&lt;br /&gt;&amp;lt;/books&amp;gt;&lt;br /&gt;&lt;/pre&gt;&lt;b&gt;Further information&lt;/b&gt;&lt;br /&gt;If you want to learn more about Piriti and its extensions, please feel free to take a look at it under &lt;a href="http://code.google.com/p/piriti/"&gt;http://code.google.com/p/piriti/&lt;/a&gt;&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/6496358939342448107-5738895896720663040?l=haraldpehl.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://haraldpehl.blogspot.com/feeds/5738895896720663040/comments/default' title='Kommentare zum Post'/><link rel='replies' type='text/html' href='http://haraldpehl.blogspot.com/2010/03/restlet-extension-of-piriti.html#comment-form' title='0 Kommentare'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/6496358939342448107/posts/default/5738895896720663040'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/6496358939342448107/posts/default/5738895896720663040'/><link rel='alternate' type='text/html' href='http://haraldpehl.blogspot.com/2010/03/restlet-extension-of-piriti.html' title='Restlet extension of Piriti'/><author><name>Harald Pehl</name><uri>https://profiles.google.com/112941298216109713269</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='32' height='32' src='//lh6.googleusercontent.com/-2g4YuDsTmkA/AAAAAAAAAAI/AAAAAAAACAA/dJrc8s_TFxs/s512-c/photo.jpg'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-6496358939342448107.post-1223878398311878803</id><published>2010-03-22T12:11:00.004+01:00</published><updated>2012-01-24T21:33:35.922+01:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='GWT'/><category scheme='http://www.blogger.com/atom/ns#' term='JSON'/><category scheme='http://www.blogger.com/atom/ns#' term='Piriti'/><title type='text'>JSON Mapping in Piriti</title><content type='html'>Following a &lt;a href="http://restlet.tigris.org/ds/viewMessage.do?dsForumId=4447&amp;dsMessageId=2450017"&gt;proposal&lt;/a&gt; by Jerome Louvel, I added JSON mapping to &lt;a href="http://code.google.com/p/piriti/"&gt;Piriti&lt;/a&gt;. Piriti is a JSON / XML mapper for GWT based on annotations and deferred binding. &lt;br /&gt;&lt;br /&gt;To map JSON data you have to annotate your model classes with &lt;code&gt;@JsonField&lt;/code&gt; annotations. In case you have the following JSON structure:&lt;br /&gt;&lt;pre class="brush:js"&gt;{&lt;br /&gt;    isbn: "978-0345417954", &lt;br /&gt;    pages: 432,&lt;br /&gt;    title: "The Hotel New Hampshire",&lt;br /&gt;    author: {&lt;br /&gt;        firstname: "John",&lt;br /&gt;        surname: "Irving", &lt;br /&gt;    },&lt;br /&gt;    reviews: [&lt;br /&gt;        "A hectic gaudy saga with the verve of a Marx Brothers movie.", &lt;br /&gt;        "Rejoice! John Irving has written another book according to your world.", &lt;br /&gt;        "Spellbinding, intensely human, a high-wire act of dazzling virtuosity."&lt;br /&gt;    ]&lt;br /&gt;}    &lt;br /&gt;&lt;/pre&gt;&lt;br /&gt;You can use the following code to map the JSON data to your model:&lt;br /&gt;&lt;pre class="brush:java"&gt;public class Book&lt;br /&gt;{&lt;br /&gt;    interface BookReader extends JsonReader&amp;lt;Book&amp;gt; {}&lt;br /&gt;    public static final BookReader JSON = GWT.create(BookReader.class);&lt;br /&gt;&lt;br /&gt;    @JsonField String isbn;&lt;br /&gt;    @JsonField int pages;&lt;br /&gt;    @JsonField String title;&lt;br /&gt;    @JsonField Author author;&lt;br /&gt;    @JsonField List&amp;lt;String&amp;gt; reviews;&lt;br /&gt;}&lt;br /&gt;&lt;br /&gt;...&lt;br /&gt;&lt;br /&gt;public class Author&lt;br /&gt;{&lt;br /&gt;    interface AuthorReader extends JsonReader&amp;lt;Author&amp;gt; {}&lt;br /&gt;    public static final AuthorReader JSON = GWT.create(AuthorReader.class);&lt;br /&gt;&lt;br /&gt;    @JsonField String firstname;&lt;br /&gt;    @JsonField String surname;&lt;br /&gt;}&lt;br /&gt;&lt;br /&gt;...&lt;br /&gt;&lt;br /&gt;String jsonString = ...; // The JSON structure (see above) &lt;br /&gt;Book book = Book.JSON.read(jsonString);&lt;br /&gt;&lt;/pre&gt;&lt;br /&gt;To learn more about piriti take a look at &lt;a href="http://code.google.com/p/piriti/"&gt;code.google.com/p/piriti/&lt;/a&gt;.&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/6496358939342448107-1223878398311878803?l=haraldpehl.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://haraldpehl.blogspot.com/feeds/1223878398311878803/comments/default' title='Kommentare zum Post'/><link rel='replies' type='text/html' href='http://haraldpehl.blogspot.com/2010/03/json-mapping-in-piriti.html#comment-form' title='0 Kommentare'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/6496358939342448107/posts/default/1223878398311878803'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/6496358939342448107/posts/default/1223878398311878803'/><link rel='alternate' type='text/html' href='http://haraldpehl.blogspot.com/2010/03/json-mapping-in-piriti.html' title='JSON Mapping in Piriti'/><author><name>Harald Pehl</name><uri>https://profiles.google.com/112941298216109713269</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='32' height='32' src='//lh6.googleusercontent.com/-2g4YuDsTmkA/AAAAAAAAAAI/AAAAAAAACAA/dJrc8s_TFxs/s512-c/photo.jpg'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-6496358939342448107.post-5661716594536155727</id><published>2010-02-15T17:39:00.001+01:00</published><updated>2010-02-15T17:40:30.383+01:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='GAE'/><category scheme='http://www.blogger.com/atom/ns#' term='GWT'/><category scheme='http://www.blogger.com/atom/ns#' term='Security'/><category scheme='http://www.blogger.com/atom/ns#' term='Guice'/><title type='text'>Restlet and Google Guice</title><content type='html'>In an earlier &lt;a href="http://haraldpehl.blogspot.com/2009/11/google-appengine-restlet.html"&gt;post&lt;/a&gt; I described how to configure resources with Google Guice. I decided to move the relevant code to a small library called "Taoki" (Maori for "rest"). &lt;br /&gt;&lt;br /&gt;Besides the features described in the initial post, I added the possibility to configure security for resources. The details will be described in a separated post. &lt;br /&gt;&lt;br /&gt;For those interested, take a look at &lt;a href="http://code.google.com/p/taoki/"&gt;http://code.google.com/p/taoki/&lt;/a&gt;.&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/6496358939342448107-5661716594536155727?l=haraldpehl.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://haraldpehl.blogspot.com/feeds/5661716594536155727/comments/default' title='Kommentare zum Post'/><link rel='replies' type='text/html' href='http://haraldpehl.blogspot.com/2010/02/restlet-and-google-guice.html#comment-form' title='0 Kommentare'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/6496358939342448107/posts/default/5661716594536155727'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/6496358939342448107/posts/default/5661716594536155727'/><link rel='alternate' type='text/html' href='http://haraldpehl.blogspot.com/2010/02/restlet-and-google-guice.html' title='Restlet and Google Guice'/><author><name>Harald Pehl</name><uri>https://profiles.google.com/112941298216109713269</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='32' height='32' src='//lh6.googleusercontent.com/-2g4YuDsTmkA/AAAAAAAAAAI/AAAAAAAACAA/dJrc8s_TFxs/s512-c/photo.jpg'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-6496358939342448107.post-1595605159498770379</id><published>2010-01-14T17:41:00.004+01:00</published><updated>2012-01-24T21:32:57.178+01:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='GWT'/><category scheme='http://www.blogger.com/atom/ns#' term='XML'/><category scheme='http://www.blogger.com/atom/ns#' term='Piriti'/><title type='text'>XML Mapper for GWT</title><content type='html'>I'm a big fan of RESTful architectures. When using REST resources with XML representations in combination with GWT you have to parse the XML and map it to the model used in the GWT client. The code therefore is tedious and error-prone. So I decided to start a little framework called "piriti" (Maori for bridge). It is hosted on goolge code under &lt;a href="http://code.google.com/p/piriti/"&gt;code.google.com/p/piriti/&lt;/a&gt;. The basic idea behind piriti is to use annotations on your model and generate the parsing / mapping code with the help of deferred binding. &lt;br /&gt;&lt;br /&gt;Let's assume you have a REST resource for a book which produces the following XML representation&lt;br /&gt;&lt;pre class="brush:xml"&gt;&amp;lt;book&amp;gt;&lt;br /&gt;    &amp;lt;isbn&amp;gt;978-0345417954&amp;lt;/isbn&amp;gt;&lt;br /&gt;    &amp;lt;pages&amp;gt;432&amp;lt;/pages&amp;gt;&lt;br /&gt;    &amp;lt;title&amp;gt;The Hotel New Hampshire&amp;lt;/title&amp;gt;&lt;br /&gt;    &amp;lt;author&amp;gt;&lt;br /&gt;        &amp;lt;firstname&amp;gt;John&amp;lt;/firstname&amp;gt;&lt;br /&gt;        &amp;lt;surname&amp;gt;Irving&amp;lt;/surname&amp;gt;&lt;br /&gt;    &amp;lt;/author&amp;gt;&lt;br /&gt;    &amp;lt;reviews&amp;gt;&lt;br /&gt;        &amp;lt;review&amp;gt;A hectic gaudy saga with the verve of a Marx Brothers movie.&amp;lt;/review&amp;gt;&lt;br /&gt;        &amp;lt;review&amp;gt;Rejoice! John Irving has written another book according to your world. You must read this book.&amp;lt;/review&amp;gt;&lt;br /&gt;        &amp;lt;review&amp;gt;Spellbinding, intensely human, a high-wire act of dazzling virtuosity.&amp;lt;/review&amp;gt;&lt;br /&gt;    &amp;lt;/reviews&amp;gt;&lt;br /&gt;&amp;lt;/book&amp;gt;&lt;br /&gt;&lt;/pre&gt;&lt;br /&gt;On the GWT client you have the following model classes&lt;br /&gt;&lt;pre class="brush:java"&gt;public class Book&lt;br /&gt;{&lt;br /&gt;    String isbn;&lt;br /&gt;    int pages;&lt;br /&gt;    String title;&lt;br /&gt;    Author author;&lt;br /&gt;    List&amp;lt;String&amp;gt; reviews;&lt;br /&gt;}&lt;br /&gt;&lt;br /&gt;public class Author&lt;br /&gt;{&lt;br /&gt;    String firstname;&lt;br /&gt;    String surname;&lt;br /&gt;}&lt;br /&gt;&lt;/pre&gt;&lt;br /&gt;To map the XML to your model, all you have to do is annotate the relevant fields in your model and define an interface of type XmlReader&amp;lt;T&amp;gt;&lt;br /&gt;&lt;br /&gt;&lt;pre class="brush:java"&gt;public class Book&lt;br /&gt;{&lt;br /&gt;    interface BookReader extends XmlReader&amp;lt;Book&amp;gt; {}&lt;br /&gt;    public static final BookReader XML = GWT.create(BookReader.class);&lt;br /&gt;&lt;br /&gt;    @XmlField String isbn;&lt;br /&gt;    @XmlField int pages;&lt;br /&gt;    @XmlField String title;&lt;br /&gt;    @XmlField Author author;&lt;br /&gt;    @XmlField("reviews/review") List&amp;lt;String&amp;gt; reviews;&lt;br /&gt;}&lt;br /&gt;&lt;br /&gt;public class Author&lt;br /&gt;{&lt;br /&gt;    interface AuthorReader extends XmlReader&amp;lt;Author&amp;gt; {}&lt;br /&gt;    public static final AuthorReader XML = GWT.create(AuthorReader.class);&lt;br /&gt;&lt;br /&gt;    @XmlField String firstname;&lt;br /&gt;    @XmlField String surname;&lt;br /&gt;}&lt;br /&gt;&lt;/pre&gt;&lt;br /&gt;Now you can map the XML to your model by calling&lt;pre class="brush:java"&gt;Document document = ...; // XML representation of the book resource&lt;br /&gt;Book book = Book.XML.read(document);&lt;br /&gt;&lt;/pre&gt;&lt;br /&gt;To learn more about piriti take a look at &lt;a href="http://code.google.com/p/piriti/"&gt;code.google.com/p/piriti/&lt;/a&gt;.&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/6496358939342448107-1595605159498770379?l=haraldpehl.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://haraldpehl.blogspot.com/feeds/1595605159498770379/comments/default' title='Kommentare zum Post'/><link rel='replies' type='text/html' href='http://haraldpehl.blogspot.com/2010/01/xml-mapper-for-gwt.html#comment-form' title='0 Kommentare'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/6496358939342448107/posts/default/1595605159498770379'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/6496358939342448107/posts/default/1595605159498770379'/><link rel='alternate' type='text/html' href='http://haraldpehl.blogspot.com/2010/01/xml-mapper-for-gwt.html' title='XML Mapper for GWT'/><author><name>Harald Pehl</name><uri>https://profiles.google.com/112941298216109713269</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='32' height='32' src='//lh6.googleusercontent.com/-2g4YuDsTmkA/AAAAAAAAAAI/AAAAAAAACAA/dJrc8s_TFxs/s512-c/photo.jpg'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-6496358939342448107.post-2721655523163383543</id><published>2009-11-24T17:06:00.006+01:00</published><updated>2012-01-24T21:32:22.125+01:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='GAE'/><category scheme='http://www.blogger.com/atom/ns#' term='Security'/><category scheme='http://www.blogger.com/atom/ns#' term='Guice'/><category scheme='http://www.blogger.com/atom/ns#' term='Restlet'/><title type='text'>Google AppEngine, Restlet &amp; Security</title><content type='html'>I was wondering how to secure the resources in my current application. The application is deployed on the Google AppEngine and uses &lt;a href="http://code.google.com/p/google-guice/"&gt;Guice 2.0&lt;/a&gt; and &lt;a href="http://www.restlet.org/"&gt;Restlet 2.0&lt;/a&gt;. Inspired by the &lt;a href="http://turbomanage.wordpress.com/2009/10/07/calling-appengine-securely-from-gwt-with-gwt-dispatch/"&gt;post from David M. Chandler&lt;/a&gt; I decided to use the AppEngine cookie named "ACSID" as a token in each and every url to secure my resources. This way the url to the "projects" resource becomes http://tire-d8.appspot.com/rest/v1/&amp;lt;ACSID&amp;gt;/projects. &lt;br /&gt;&lt;br /&gt;Technically I'm using an aspect together with a custom annotation to secure the resources. Here's the Guice module for the security stuff:&lt;br /&gt;&lt;pre class="brush:java"&gt;public class SecurityModule extends AbstractModule&lt;br /&gt;{&lt;br /&gt;    @Override&lt;br /&gt;    protected void configure()&lt;br /&gt;    {&lt;br /&gt;        SecurityInterceptor interceptor = new SecurityInterceptor();&lt;br /&gt;        bindInterceptor(Matchers.subclassesOf(ServerResource.class), Matchers.annotatedWith(Secured.class), interceptor);&lt;br /&gt;    }&lt;br /&gt;}&lt;br /&gt;&lt;/pre&gt;With the above setup all methodes in subclasses of ServerResource which are annotated with the custom @Secured annotation are handled by the SecurityInterceptor. This class contains the logic to check whether there's a authenticated user and whether the session cookie is correct (that's essentially the code from &lt;a href="http://turbomanage.wordpress.com/2009/10/07/calling-appengine-securely-from-gwt-with-gwt-dispatch/"&gt;David M. Chandlers post&lt;/a&gt;)&lt;br /&gt;&lt;pre class="brush:java"&gt;public class SecurityInterceptor implements MethodInterceptor&lt;br /&gt;{&lt;br /&gt;    private static final String APPENGINE_COOKIE = "ACSID";&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;    @Override&lt;br /&gt;    public Object invoke(MethodInvocation invocation) throws Throwable&lt;br /&gt;    {&lt;br /&gt;        UserService userService = UserServiceFactory.getUserService();&lt;br /&gt;        User user = userService.getCurrentUser();&lt;br /&gt;        if (user == null)&lt;br /&gt;        {&lt;br /&gt;            throw new SecurityException("No user");&lt;br /&gt;        }&lt;br /&gt;&lt;br /&gt;        ServerResource resource = (ServerResource) invocation.getThis();&lt;br /&gt;        String token = (String) resource.getRequest().getAttributes().get("token");&lt;br /&gt;        if (token == null || token.length() == 0)&lt;br /&gt;        {&lt;br /&gt;            throw new SecurityException("No security token");&lt;br /&gt;        }&lt;br /&gt;&lt;br /&gt;        // Skip check on localhost so we can test in AppEngine local dev env&lt;br /&gt;        String sessionId = findSessionId(resource);&lt;br /&gt;        String serverName = resource.getReference().getHostDomain();&lt;br /&gt;        if (!("localhost".equals(serverName)) &amp;amp;&amp;amp; !(token.equals(sessionId)))&lt;br /&gt;        {&lt;br /&gt;            throw new SecurityException("Security token invalid");&lt;br /&gt;        }&lt;br /&gt;&lt;br /&gt;        return invocation.proceed();&lt;br /&gt;    }&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;    private String findSessionId(ServerResource resource)&lt;br /&gt;    {&lt;br /&gt;        String result = null;&lt;br /&gt;        Series&amp;lt;Cookie&amp;gt; cookies = resource.getCookies();&lt;br /&gt;        for (Cookie cookie : cookies)&lt;br /&gt;        {&lt;br /&gt;            if (APPENGINE_COOKIE.equals(cookie.getName()))&lt;br /&gt;            {&lt;br /&gt;                result = cookie.getValue();&lt;br /&gt;                break;&lt;br /&gt;            }&lt;br /&gt;        }&lt;br /&gt;        return result;&lt;br /&gt;    }&lt;br /&gt;}&lt;br /&gt;&lt;/pre&gt;&lt;br /&gt;To make this work the resource mappings have to include a {token} parameter. So inside your Router you should have something like that&lt;br /&gt;&lt;pre class="brush:java"&gt;attach("/{token}/projects", ProjectsResource.class);&lt;br /&gt;&lt;/pre&gt;&lt;br /&gt;Finally the methods you want to protect have to be annotated with the @Secured annotation:&lt;br /&gt;&lt;pre class="brush:java"&gt;public class ProjectsResource extends ServerResource&lt;br /&gt;{&lt;br /&gt;    private final ProjectService service;&lt;br /&gt;    private final TemplateConverter converter;&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;    @Inject&lt;br /&gt;    public ProjectsResource(ProjectService service, TemplateConverter converter)&lt;br /&gt;    {&lt;br /&gt;        this.service = service;&lt;br /&gt;        this.converter = converter;&lt;br /&gt;    }&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;    @Secured&lt;br /&gt;    @Override&lt;br /&gt;    protected Representation get()&lt;br /&gt;    {&lt;br /&gt;        Context context = new Context();&lt;br /&gt;        context.set("projects", service.list());&lt;br /&gt;        String xml = converter.convert("templates/projects.vm", context);&lt;br /&gt;        return new StringRepresentation(xml, MediaType.TEXT_XML);&lt;br /&gt;    }&lt;br /&gt;}&lt;br /&gt;&lt;/pre&gt;&lt;br /&gt;One last note: First I tried to use the @Get annotation from Restlet 2.0 instead of a custom annotation and configured the SecurityInterceptor as follows:&lt;br /&gt;&lt;pre class="brush:java"&gt;bindInterceptor(Matchers.subclassesOf(ServerResource.class), Matchers.annotatedWith(Get.class), interceptor);&lt;br /&gt;&lt;/pre&gt;Unfortunately that didn't work because the @Get annotation is not available in the generated AOP proxy. So Restlet has no way to figure out what method to call for a GET request. Instead you have to override the get method.&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/6496358939342448107-2721655523163383543?l=haraldpehl.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://haraldpehl.blogspot.com/feeds/2721655523163383543/comments/default' title='Kommentare zum Post'/><link rel='replies' type='text/html' href='http://haraldpehl.blogspot.com/2009/11/google-appengine-restlet-security.html#comment-form' title='0 Kommentare'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/6496358939342448107/posts/default/2721655523163383543'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/6496358939342448107/posts/default/2721655523163383543'/><link rel='alternate' type='text/html' href='http://haraldpehl.blogspot.com/2009/11/google-appengine-restlet-security.html' title='Google AppEngine, Restlet &amp; Security'/><author><name>Harald Pehl</name><uri>https://profiles.google.com/112941298216109713269</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='32' height='32' src='//lh6.googleusercontent.com/-2g4YuDsTmkA/AAAAAAAAAAI/AAAAAAAACAA/dJrc8s_TFxs/s512-c/photo.jpg'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-6496358939342448107.post-2237795458352074938</id><published>2009-11-22T13:26:00.030+01:00</published><updated>2012-01-24T21:31:29.698+01:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='GAE'/><category scheme='http://www.blogger.com/atom/ns#' term='Guice'/><category scheme='http://www.blogger.com/atom/ns#' term='Restlet'/><title type='text'>Google AppEngine, Restlet &amp; Guice</title><content type='html'>Currently I'm developing an application for time recording called TiRe. TiRe is deloyed on the Google AppEngine for Java (GAE/J) and uses inter alia the following stack:&lt;br /&gt;&lt;ul&gt;&lt;li&gt;&lt;a href="http://code.google.com/p/google-guice/"&gt;Guice 2.0&lt;/a&gt;&lt;/li&gt;&lt;li&gt;&lt;a href="http://www.restlet.org/"&gt;Restlet 2.0&lt;/a&gt;&lt;/li&gt;&lt;/ul&gt;Basically there are two different ways to go when using the Restlet framework:&lt;br /&gt;&lt;ol&gt;&lt;li&gt;Run as a standalone application&lt;/li&gt;&lt;li&gt;Run in a servlet container&lt;/li&gt;&lt;/ol&gt;For the first approach there's a &lt;a href="http://tembrel.blogspot.com/2008/07/resource-dependency-injection-in.html"&gt;blog entry from Tim Peierls&lt;/a&gt; on how to configure your resources using Guice. &lt;br /&gt;As TiRe is deployed on the GAE/J, I'm using the second approach. Therefore I created a custom servlet in combination with custom Finder and Router classes. All classes are bind together with Guice. This post describes my setup and shows the relevant code. Let's start by looking at the web.xml:&lt;br /&gt;&lt;pre class="brush:xml"&gt;&amp;lt;web-app xmlns="http://java.sun.com/xml/ns/javaee" version="2.5"&amp;gt;&lt;br /&gt;&lt;br /&gt;    &amp;lt;filter&amp;gt;&lt;br /&gt;        &amp;lt;filter-name&amp;gt;guiceFilter&amp;lt;/filter-name&amp;gt;&lt;br /&gt;        &amp;lt;filter-class&amp;gt;com.google.inject.servlet.GuiceFilter&amp;lt;/filter-class&amp;gt;&lt;br /&gt;    &amp;lt;/filter&amp;gt;&lt;br /&gt;    &amp;lt;filter-mapping&amp;gt;&lt;br /&gt;        &amp;lt;filter-name&amp;gt;guiceFilter&amp;lt;/filter-name&amp;gt;&lt;br /&gt;        &amp;lt;url-pattern&amp;gt;/*&amp;lt;/url-pattern&amp;gt;&lt;br /&gt;    &amp;lt;/filter-mapping&amp;gt;&lt;br /&gt;&lt;br /&gt;    &amp;lt;listener&amp;gt;&lt;br /&gt;        &amp;lt;listener-class&amp;gt;name.pehl.tire.server.servlet.ServletConfig&amp;lt;/listener-class&amp;gt;&lt;br /&gt;    &amp;lt;/listener&amp;gt;&lt;br /&gt;&lt;br /&gt;&amp;lt;/web-app&amp;gt;&lt;br /&gt;&lt;/pre&gt;Nothing special here. The main configuration happens in the ServletConfig class:&lt;br /&gt;&lt;pre class="brush:java"&gt;public class ServletConfig extends GuiceServletContextListener&lt;br /&gt;{&lt;br /&gt;    @Override&lt;br /&gt;    protected Injector getInjector()&lt;br /&gt;    {&lt;br /&gt;        // Further modules are omitted...&lt;br /&gt;        return Guice.createInjector(new ServletModule(), new RestModule());&lt;br /&gt;    }&lt;br /&gt;}&lt;br /&gt;&lt;/pre&gt;I use two different modules: One for the servlet configuration and one for the setup of the resources. The servlet module registers the custom REST servlet:&lt;br /&gt;&lt;pre class="brush:java"&gt;public class ServletModule extends com.google.inject.servlet.ServletModule&lt;br /&gt;{&lt;br /&gt;    @Override&lt;br /&gt;    protected void configureServlets()&lt;br /&gt;    {&lt;br /&gt;        serve("/rest/v1/*").with(RestletServlet.class);&lt;br /&gt;    }&lt;br /&gt;}&lt;br /&gt;&lt;/pre&gt;All REST requests are handled by the RestletServlet. The url mapping contains a version number. Using this approach you can later on add another servlet with a different interface / version and maintain backward compatibility. Now let's look at the RestletServlet: &lt;br /&gt;&lt;pre class="brush:java"&gt;@Singleton&lt;br /&gt;public class RestletServlet extends HttpServlet&lt;br /&gt;{&lt;br /&gt;    @Inject&lt;br /&gt;    private Injector injector;&lt;br /&gt;    private Context context;&lt;br /&gt;    private ServletAdapter adapter;&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;    @Override&lt;br /&gt;    public void init() throws ServletException&lt;br /&gt;    {&lt;br /&gt;        context = new Context();&lt;br /&gt;        Application application = new Application();&lt;br /&gt;        application.setContext(context);&lt;br /&gt;        application.setInboundRoot(new GuiceRouter(injector, context)&lt;br /&gt;        {&lt;br /&gt;            @Override&lt;br /&gt;            protected void attachRoutes()&lt;br /&gt;            {&lt;br /&gt;                attach("/projects", ProjectsResource.class);&lt;br /&gt;            }&lt;br /&gt;        });&lt;br /&gt;        adapter = new ServletAdapter(getServletContext());&lt;br /&gt;        adapter.setTarget(application);&lt;br /&gt;    }&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;    @Override&lt;br /&gt;    protected void service(HttpServletRequest request, HttpServletResponse response) throws ServletException,&lt;br /&gt;            IOException&lt;br /&gt;    {&lt;br /&gt;        adapter.service(request, response);&lt;br /&gt;    }&lt;br /&gt;}&lt;br /&gt;&lt;/pre&gt;The servlet is normal HttpServlet. The integration with the Restlet framework is not reached by inheritance but by using the ServletAdapter class. The ServletAdapter is configured to use a new Context, Application and our own GuiceRouter. &lt;br /&gt;&lt;br /&gt;Another important aspect is that a reference to the Injector is provided by Guice (see "Injecting the injector" in the &lt;a href="http://code.google.com/docreader/#p=google-guice&amp;amp;s=google-guice&amp;amp;t=ServletRegexKeyMapping"&gt;Guice documentation&lt;/a&gt;). We will need the injector later in the GuiceFinder class. &lt;br /&gt;&lt;br /&gt;The GuiceRouter is responsible for setting up the mappings between the urls and the resources. Therefore it has the abstract method attachRoutes(). The GuiceRouter extends the Router from the Restlet framework and uses a GuiceFinder to create the resource instances: &lt;br /&gt;&lt;pre class="brush:java"&gt;public abstract class GuiceRouter extends Router&lt;br /&gt;{&lt;br /&gt;    private final Injector injector;&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;    public GuiceRouter(Injector injector, Context context)&lt;br /&gt;    {&lt;br /&gt;        super(context);&lt;br /&gt;        this.injector = injector;&lt;br /&gt;        attachRoutes();&lt;br /&gt;    }&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;    @Override&lt;br /&gt;    public Finder createFinder(Class targetClass)&lt;br /&gt;    {&lt;br /&gt;        return new GuiceFinder(injector, getContext(), targetClass);&lt;br /&gt;    }&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;    protected abstract void attachRoutes();&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;    protected Injector getInjector()&lt;br /&gt;    {&lt;br /&gt;        return injector;&lt;br /&gt;    }&lt;br /&gt;}&lt;br /&gt;&lt;/pre&gt;The GuiceFinder is the class where the resources are created. Therefore the method create() is overwritten. By calling Injector.getInstance(targetClass) the resource is created and all its dependencies are injected by Guice:&lt;br /&gt;&lt;pre class="brush:java"&gt;public class GuiceFinder extends Finder&lt;br /&gt;{&lt;br /&gt;    private final Injector injector;&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;    public GuiceFinder(Injector injector, Context context, Class targetClass)&lt;br /&gt;    {&lt;br /&gt;        super(context, targetClass);&lt;br /&gt;        this.injector = injector;&lt;br /&gt;    }&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;    @Override&lt;br /&gt;    public ServerResource create(Class targetClass, Request request, Response response)&lt;br /&gt;    {&lt;br /&gt;        return injector.getInstance(targetClass);&lt;br /&gt;    }&lt;br /&gt;}&lt;br /&gt;&lt;/pre&gt;The following code shows one of the resource used in TiRe. The resource is bound to the url "/projects". So when the url http://server/rest/v1/projects is called a new instance of the ProjectsResource is created by Guice and all dependencies are injected.&lt;br /&gt;&lt;pre class="brush:java"&gt;public class ProjectsResource extends ServerResource&lt;br /&gt;{&lt;br /&gt;    private final ProjectService service;&lt;br /&gt;    private final TemplateConverter converter;&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;    @Inject&lt;br /&gt;    public ProjectsResource(ProjectService service, TemplateConverter converter)&lt;br /&gt;    {&lt;br /&gt;        this.service = service;&lt;br /&gt;        this.converter = converter;&lt;br /&gt;    }&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;    @Get("xml")&lt;br /&gt;    public Representation represent()&lt;br /&gt;    {&lt;br /&gt;        Context context = new Context();&lt;br /&gt;        context.set("projects", service.list());&lt;br /&gt;        String xml = converter.convert("templates/projects.vm", context);&lt;br /&gt;        return new StringRepresentation(xml, MediaType.TEXT_XML);&lt;br /&gt;    }&lt;br /&gt;}&lt;br /&gt;&lt;/pre&gt;As you can see, there's not much code necessary to integrate the Restlet framework with the GAE/J using the servlet approach. Feel free to comment and let me know if this is somewhat useful.&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/6496358939342448107-2237795458352074938?l=haraldpehl.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://haraldpehl.blogspot.com/feeds/2237795458352074938/comments/default' title='Kommentare zum Post'/><link rel='replies' type='text/html' href='http://haraldpehl.blogspot.com/2009/11/google-appengine-restlet.html#comment-form' title='10 Kommentare'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/6496358939342448107/posts/default/2237795458352074938'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/6496358939342448107/posts/default/2237795458352074938'/><link rel='alternate' type='text/html' href='http://haraldpehl.blogspot.com/2009/11/google-appengine-restlet.html' title='Google AppEngine, Restlet &amp; Guice'/><author><name>Harald Pehl</name><uri>https://profiles.google.com/112941298216109713269</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='32' height='32' src='//lh6.googleusercontent.com/-2g4YuDsTmkA/AAAAAAAAAAI/AAAAAAAACAA/dJrc8s_TFxs/s512-c/photo.jpg'/></author><thr:total>10</thr:total></entry></feed>
