<?xml version="1.0" encoding="utf-8"?>
<feed xmlns="http://www.w3.org/2005/Atom">
  <title>amateur in motion - Code articles</title>
  <subtitle>Code articles</subtitle>
  <link href="http://www.amateurinmotion.com/feeds/category/code.xml" rel="self"/>
  <link href="http://www.amateurinmotion.com/categories/code.html"/>
  <updated>2011-07-13T22:05:11+03:00</updated>
  <author>
    <name>ampatspell</name>
    <email>ampatspell@gmail.com</email>
  </author>
  <id>http://www.amateurinmotion.com//feeds/category/code.xml</id>
  
  <entry>
  <title>Drawing Custom NSButton in Cocoa</title>
  <link href="/articles/2010/05/06/drawing-custom-nsbutton-in-cocoa.html" />
  <id>tag:www.amateurinmotion.com,2010-05-06:1273155426</id>
  <updated>2010-05-06T17:17:06+03:00</updated>
  <content type="html">&lt;p&gt;In my spare time I&amp;#8217;m designing my first &amp;#8220;real&amp;#8221; Cocoa appplication and I&amp;#8217;ve decided to be rather open about this app and it&amp;#8217;s implementation details prior and after the release.&lt;/p&gt;
&lt;p&gt;I&amp;#8217;m not going to disclose anything about the app just yet. Well, maybe only that it will come with open-source cloud component deployable (or automatically deployed) to &lt;a href=&quot;http://code.google.com/appengine/&quot;&gt;AppEngine&lt;/a&gt;.&lt;/p&gt;
&lt;p&gt;While I&amp;#8217;m still siting in Photoshop trying to come up with interface design, I wanted to create actual clickable buttons from mockup. Here is more or less step-by-step guide of drawing them.&lt;/p&gt;
&lt;p&gt;But now about &lt;code&gt;NSButton&lt;/code&gt; custom drawing.&lt;/p&gt;
&lt;p&gt;&lt;img src=&quot;http://www.amateurinmotion.com/articles/2010/05/06/buttons.png&quot; class=&quot;clean nomargin  &quot; title=&quot;buttons.png&quot; alt=&quot;buttons.png&quot;/&gt;&lt;/p&gt;
&lt;p&gt;In Cocoa &lt;code&gt;NSButton&lt;/code&gt; is subclass of &lt;code&gt;NSControl&lt;/code&gt; which are drawn using &lt;code&gt;NSCells&lt;/code&gt;. So we need a new &lt;code&gt;NSButtonCell&lt;/code&gt; subclass to do our drawing:&lt;/p&gt;
&lt;div class=&quot;uv&quot;&gt;&lt;pre class=&quot;lazy&quot;&gt;
#&lt;span class=&quot;Keyword&quot;&gt;import&lt;/span&gt; &lt;span class=&quot;String&quot;&gt;&lt;span class=&quot;String&quot;&gt;&amp;quot;&lt;/span&gt;AMDarkButtonCell.h&lt;span class=&quot;String&quot;&gt;&amp;quot;&lt;/span&gt;&lt;/span&gt;

&lt;span class=&quot;Keyword&quot;&gt;&lt;span class=&quot;Keyword&quot;&gt;@&lt;/span&gt;implementation&lt;/span&gt; &lt;span class=&quot;Entity&quot;&gt;AMDarkButtonCell&lt;/span&gt;

- (&lt;span class=&quot;Keyword&quot;&gt;void&lt;/span&gt;)&lt;span class=&quot;Entity&quot;&gt;drawImage&lt;/span&gt;&lt;span class=&quot;Entity&quot;&gt;&lt;span class=&quot;Entity&quot;&gt;:&lt;/span&gt;&lt;/span&gt;(&lt;span class=&quot;Support&quot;&gt;NSImage&lt;/span&gt;*)&lt;span class=&quot;Variable&quot;&gt;image&lt;/span&gt; 
        &lt;span class=&quot;Entity&quot;&gt;withFrame&lt;/span&gt;&lt;span class=&quot;Entity&quot;&gt;&lt;span class=&quot;Entity&quot;&gt;:&lt;/span&gt;&lt;/span&gt;(&lt;span class=&quot;Support&quot;&gt;NSRect&lt;/span&gt;)&lt;span class=&quot;Variable&quot;&gt;frame&lt;/span&gt; 
           &lt;span class=&quot;Entity&quot;&gt;inView&lt;/span&gt;&lt;span class=&quot;Entity&quot;&gt;&lt;span class=&quot;Entity&quot;&gt;:&lt;/span&gt;&lt;/span&gt;(&lt;span class=&quot;Support&quot;&gt;NSView&lt;/span&gt;*)&lt;span class=&quot;Variable&quot;&gt;controlView&lt;/span&gt;
{
}

- (&lt;span class=&quot;Support&quot;&gt;NSRect&lt;/span&gt;)&lt;span class=&quot;Entity&quot;&gt;drawTitle&lt;/span&gt;&lt;span class=&quot;Entity&quot;&gt;&lt;span class=&quot;Entity&quot;&gt;:&lt;/span&gt;&lt;/span&gt;(&lt;span class=&quot;Support&quot;&gt;NSAttributedString&lt;/span&gt;*)&lt;span class=&quot;Variable&quot;&gt;title&lt;/span&gt; 
          &lt;span class=&quot;Entity&quot;&gt;withFrame&lt;/span&gt;&lt;span class=&quot;Entity&quot;&gt;&lt;span class=&quot;Entity&quot;&gt;:&lt;/span&gt;&lt;/span&gt;(&lt;span class=&quot;Support&quot;&gt;NSRect&lt;/span&gt;)&lt;span class=&quot;Variable&quot;&gt;frame&lt;/span&gt; 
             &lt;span class=&quot;Entity&quot;&gt;inView&lt;/span&gt;&lt;span class=&quot;Entity&quot;&gt;&lt;span class=&quot;Entity&quot;&gt;:&lt;/span&gt;&lt;/span&gt;(&lt;span class=&quot;Support&quot;&gt;NSView&lt;/span&gt;*)&lt;span class=&quot;Variable&quot;&gt;controlView&lt;/span&gt;
{
}

- (&lt;span class=&quot;Keyword&quot;&gt;void&lt;/span&gt;)&lt;span class=&quot;Entity&quot;&gt;drawBezelWithFrame&lt;/span&gt;&lt;span class=&quot;Entity&quot;&gt;&lt;span class=&quot;Entity&quot;&gt;:&lt;/span&gt;&lt;/span&gt;(&lt;span class=&quot;Support&quot;&gt;NSRect&lt;/span&gt;)&lt;span class=&quot;Variable&quot;&gt;frame&lt;/span&gt; 
                    &lt;span class=&quot;Entity&quot;&gt;inView&lt;/span&gt;&lt;span class=&quot;Entity&quot;&gt;&lt;span class=&quot;Entity&quot;&gt;:&lt;/span&gt;&lt;/span&gt;(&lt;span class=&quot;Support&quot;&gt;NSView&lt;/span&gt; *)&lt;span class=&quot;Variable&quot;&gt;controlView&lt;/span&gt;
{
}

&lt;span class=&quot;Keyword&quot;&gt;&lt;span class=&quot;Keyword&quot;&gt;@&lt;/span&gt;end&lt;/span&gt;
&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;My not so great custom button consists of only of image and bezel so I&amp;#8217;m not going to override &lt;code&gt;-drawTitle:withFrame:inView:&lt;/code&gt;.&lt;/p&gt;
&lt;p&gt;Lets start with bezel. It&amp;#8217;s composed from:&lt;/p&gt;
&lt;ul&gt;
	&lt;li&gt;Outer gradient stroke&lt;/li&gt;
	&lt;li&gt;Background gradient&lt;/li&gt;
	&lt;li&gt;Border dark stroke&lt;/li&gt;
	&lt;li&gt;Inner light stroke&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;Cocoa provides:&lt;/p&gt;
&lt;ul&gt;
	&lt;li&gt;&lt;code&gt;NSBezierPath&lt;/code&gt; for drawing, stroking and clipping-to rounded rectangles&lt;/li&gt;
	&lt;li&gt;&lt;code&gt;NSGradient&lt;/code&gt; for drawing multiple point gradients&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;That&amp;#8217;s basically all we need to draw whole background composite.&lt;/p&gt;
&lt;div class=&quot;uv&quot;&gt;&lt;pre class=&quot;lazy&quot;&gt;
- (&lt;span class=&quot;Keyword&quot;&gt;void&lt;/span&gt;)drawBezelWithFrame:(&lt;span class=&quot;Support&quot;&gt;NSRect&lt;/span&gt;)frame inView:(&lt;span class=&quot;Support&quot;&gt;NSView&lt;/span&gt; *)controlView
{
  &lt;span class=&quot;Support&quot;&gt;NSGraphicsContext&lt;/span&gt; *ctx = [&lt;span class=&quot;Support&quot;&gt;NSGraphicsContext&lt;/span&gt; &lt;span class=&quot;Support&quot;&gt;currentContext&lt;/span&gt;];

  CGFloat roundedRadius = &lt;span class=&quot;Constant&quot;&gt;3.0f&lt;/span&gt;;

  &lt;span class=&quot;Comment&quot;&gt;&lt;span class=&quot;Comment&quot;&gt;//&lt;/span&gt; Outer stroke (drawn as gradient)&lt;/span&gt;

  [ctx &lt;span class=&quot;Support&quot;&gt;saveGraphicsState&lt;/span&gt;];
  &lt;span class=&quot;Support&quot;&gt;NSBezierPath&lt;/span&gt; *outerClip = [&lt;span class=&quot;Support&quot;&gt;NSBezierPath&lt;/span&gt; &lt;span class=&quot;Support&quot;&gt;bezierPathWithRoundedRect&lt;span class=&quot;Support&quot;&gt;:&lt;/span&gt;&lt;/span&gt;frame 
                                                            &lt;span class=&quot;Support&quot;&gt;xRadius&lt;span class=&quot;Support&quot;&gt;:&lt;/span&gt;&lt;/span&gt;roundedRadius 
                                                            &lt;span class=&quot;Support&quot;&gt;yRadius&lt;span class=&quot;Support&quot;&gt;:&lt;/span&gt;&lt;/span&gt;roundedRadius];
  [outerClip &lt;span class=&quot;Support&quot;&gt;setClip&lt;/span&gt;];

  NSGradient *outerGradient = [[NSGradient &lt;span class=&quot;Support&quot;&gt;alloc&lt;/span&gt;] &lt;span class=&quot;Support&quot;&gt;initWithColorsAndLocations&lt;span class=&quot;Support&quot;&gt;:&lt;/span&gt;&lt;/span&gt;
                               [&lt;span class=&quot;Support&quot;&gt;NSColor&lt;/span&gt; &lt;span class=&quot;Support&quot;&gt;colorWithDeviceWhite&lt;span class=&quot;Support&quot;&gt;:&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;Constant&quot;&gt;0.20f&lt;/span&gt; &lt;span class=&quot;Support&quot;&gt;alpha&lt;span class=&quot;Support&quot;&gt;:&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;Constant&quot;&gt;1.0f&lt;/span&gt;], &lt;span class=&quot;Constant&quot;&gt;0.0f&lt;/span&gt;, 
                               [&lt;span class=&quot;Support&quot;&gt;NSColor&lt;/span&gt; &lt;span class=&quot;Support&quot;&gt;colorWithDeviceWhite&lt;span class=&quot;Support&quot;&gt;:&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;Constant&quot;&gt;0.21f&lt;/span&gt; &lt;span class=&quot;Support&quot;&gt;alpha&lt;span class=&quot;Support&quot;&gt;:&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;Constant&quot;&gt;1.0f&lt;/span&gt;], &lt;span class=&quot;Constant&quot;&gt;1.0f&lt;/span&gt;, 
                               &lt;span class=&quot;Constant&quot;&gt;nil&lt;/span&gt;];

  [outerGradient &lt;span class=&quot;Support&quot;&gt;drawInRect&lt;span class=&quot;Support&quot;&gt;:&lt;/span&gt;&lt;/span&gt;[outerClip &lt;span class=&quot;Support&quot;&gt;bounds&lt;/span&gt;] &lt;span class=&quot;Support&quot;&gt;angle&lt;span class=&quot;Support&quot;&gt;:&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;Constant&quot;&gt;90.0f&lt;/span&gt;];
  [outerGradient &lt;span class=&quot;Support&quot;&gt;release&lt;/span&gt;];
  [ctx &lt;span class=&quot;Support&quot;&gt;restoreGraphicsState&lt;/span&gt;];
 
  &lt;span class=&quot;Comment&quot;&gt;&lt;span class=&quot;Comment&quot;&gt;//&lt;/span&gt; Background gradient&lt;/span&gt;

  [ctx &lt;span class=&quot;Support&quot;&gt;saveGraphicsState&lt;/span&gt;];
  &lt;span class=&quot;Support&quot;&gt;NSBezierPath&lt;/span&gt; *backgroundPath = 
    [&lt;span class=&quot;Support&quot;&gt;NSBezierPath&lt;/span&gt; &lt;span class=&quot;Support&quot;&gt;bezierPathWithRoundedRect&lt;span class=&quot;Support&quot;&gt;:&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;Support&quot;&gt;NSInsetRect&lt;/span&gt;(frame, &lt;span class=&quot;Constant&quot;&gt;2.0f&lt;/span&gt;, &lt;span class=&quot;Constant&quot;&gt;2.0f&lt;/span&gt;) 
                                    &lt;span class=&quot;Support&quot;&gt;xRadius&lt;span class=&quot;Support&quot;&gt;:&lt;/span&gt;&lt;/span&gt;roundedRadius 
                                    &lt;span class=&quot;Support&quot;&gt;yRadius&lt;span class=&quot;Support&quot;&gt;:&lt;/span&gt;&lt;/span&gt;roundedRadius];
  [backgroundPath &lt;span class=&quot;Support&quot;&gt;setClip&lt;/span&gt;];

  NSGradient *backgroundGradient = [[NSGradient &lt;span class=&quot;Support&quot;&gt;alloc&lt;/span&gt;] &lt;span class=&quot;Support&quot;&gt;initWithColorsAndLocations&lt;span class=&quot;Support&quot;&gt;:&lt;/span&gt;&lt;/span&gt;
                                    [&lt;span class=&quot;Support&quot;&gt;NSColor&lt;/span&gt; &lt;span class=&quot;Support&quot;&gt;colorWithDeviceWhite&lt;span class=&quot;Support&quot;&gt;:&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;Constant&quot;&gt;0.17f&lt;/span&gt; &lt;span class=&quot;Support&quot;&gt;alpha&lt;span class=&quot;Support&quot;&gt;:&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;Constant&quot;&gt;1.0f&lt;/span&gt;], &lt;span class=&quot;Constant&quot;&gt;0.0f&lt;/span&gt;, 
                                    [&lt;span class=&quot;Support&quot;&gt;NSColor&lt;/span&gt; &lt;span class=&quot;Support&quot;&gt;colorWithDeviceWhite&lt;span class=&quot;Support&quot;&gt;:&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;Constant&quot;&gt;0.20f&lt;/span&gt; &lt;span class=&quot;Support&quot;&gt;alpha&lt;span class=&quot;Support&quot;&gt;:&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;Constant&quot;&gt;1.0f&lt;/span&gt;], &lt;span class=&quot;Constant&quot;&gt;0.12f&lt;/span&gt;, 
                                    [&lt;span class=&quot;Support&quot;&gt;NSColor&lt;/span&gt; &lt;span class=&quot;Support&quot;&gt;colorWithDeviceWhite&lt;span class=&quot;Support&quot;&gt;:&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;Constant&quot;&gt;0.27f&lt;/span&gt; &lt;span class=&quot;Support&quot;&gt;alpha&lt;span class=&quot;Support&quot;&gt;:&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;Constant&quot;&gt;1.0f&lt;/span&gt;], &lt;span class=&quot;Constant&quot;&gt;0.5f&lt;/span&gt;, 
                                    [&lt;span class=&quot;Support&quot;&gt;NSColor&lt;/span&gt; &lt;span class=&quot;Support&quot;&gt;colorWithDeviceWhite&lt;span class=&quot;Support&quot;&gt;:&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;Constant&quot;&gt;0.30f&lt;/span&gt; &lt;span class=&quot;Support&quot;&gt;alpha&lt;span class=&quot;Support&quot;&gt;:&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;Constant&quot;&gt;1.0f&lt;/span&gt;], &lt;span class=&quot;Constant&quot;&gt;0.5f&lt;/span&gt;, 
                                    [&lt;span class=&quot;Support&quot;&gt;NSColor&lt;/span&gt; &lt;span class=&quot;Support&quot;&gt;colorWithDeviceWhite&lt;span class=&quot;Support&quot;&gt;:&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;Constant&quot;&gt;0.42f&lt;/span&gt; &lt;span class=&quot;Support&quot;&gt;alpha&lt;span class=&quot;Support&quot;&gt;:&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;Constant&quot;&gt;1.0f&lt;/span&gt;], &lt;span class=&quot;Constant&quot;&gt;0.98f&lt;/span&gt;, 
                                    [&lt;span class=&quot;Support&quot;&gt;NSColor&lt;/span&gt; &lt;span class=&quot;Support&quot;&gt;colorWithDeviceWhite&lt;span class=&quot;Support&quot;&gt;:&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;Constant&quot;&gt;0.50f&lt;/span&gt; &lt;span class=&quot;Support&quot;&gt;alpha&lt;span class=&quot;Support&quot;&gt;:&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;Constant&quot;&gt;1.0f&lt;/span&gt;], &lt;span class=&quot;Constant&quot;&gt;1.0f&lt;/span&gt;, 
                                    &lt;span class=&quot;Constant&quot;&gt;nil&lt;/span&gt;];

  [backgroundGradient &lt;span class=&quot;Support&quot;&gt;drawInRect&lt;span class=&quot;Support&quot;&gt;:&lt;/span&gt;&lt;/span&gt;[backgroundPath &lt;span class=&quot;Support&quot;&gt;bounds&lt;/span&gt;] &lt;span class=&quot;Support&quot;&gt;angle&lt;span class=&quot;Support&quot;&gt;:&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;Constant&quot;&gt;270.0f&lt;/span&gt;];
  [backgroundGradient &lt;span class=&quot;Support&quot;&gt;release&lt;/span&gt;];
  [ctx &lt;span class=&quot;Support&quot;&gt;restoreGraphicsState&lt;/span&gt;];

  &lt;span class=&quot;Comment&quot;&gt;&lt;span class=&quot;Comment&quot;&gt;//&lt;/span&gt; Dark stroke&lt;/span&gt;

  [ctx &lt;span class=&quot;Support&quot;&gt;saveGraphicsState&lt;/span&gt;];
  [[&lt;span class=&quot;Support&quot;&gt;NSColor&lt;/span&gt; &lt;span class=&quot;Support&quot;&gt;colorWithDeviceWhite&lt;span class=&quot;Support&quot;&gt;:&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;Constant&quot;&gt;0.12f&lt;/span&gt; &lt;span class=&quot;Support&quot;&gt;alpha&lt;span class=&quot;Support&quot;&gt;:&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;Constant&quot;&gt;1.0f&lt;/span&gt;] &lt;span class=&quot;Support&quot;&gt;setStroke&lt;/span&gt;];
  [[&lt;span class=&quot;Support&quot;&gt;NSBezierPath&lt;/span&gt; &lt;span class=&quot;Support&quot;&gt;bezierPathWithRoundedRect&lt;span class=&quot;Support&quot;&gt;:&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;Support&quot;&gt;NSInsetRect&lt;/span&gt;(frame, &lt;span class=&quot;Constant&quot;&gt;1.5f&lt;/span&gt;, &lt;span class=&quot;Constant&quot;&gt;1.5f&lt;/span&gt;) 
                                   &lt;span class=&quot;Support&quot;&gt;xRadius&lt;span class=&quot;Support&quot;&gt;:&lt;/span&gt;&lt;/span&gt;roundedRadius 
                                   &lt;span class=&quot;Support&quot;&gt;yRadius&lt;span class=&quot;Support&quot;&gt;:&lt;/span&gt;&lt;/span&gt;roundedRadius] &lt;span class=&quot;Support&quot;&gt;stroke&lt;/span&gt;];
  [ctx &lt;span class=&quot;Support&quot;&gt;restoreGraphicsState&lt;/span&gt;];

  &lt;span class=&quot;Comment&quot;&gt;&lt;span class=&quot;Comment&quot;&gt;//&lt;/span&gt; Inner light stroke&lt;/span&gt;

  [ctx &lt;span class=&quot;Support&quot;&gt;saveGraphicsState&lt;/span&gt;];
  [[&lt;span class=&quot;Support&quot;&gt;NSColor&lt;/span&gt; &lt;span class=&quot;Support&quot;&gt;colorWithDeviceWhite&lt;span class=&quot;Support&quot;&gt;:&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;Constant&quot;&gt;1.0f&lt;/span&gt; &lt;span class=&quot;Support&quot;&gt;alpha&lt;span class=&quot;Support&quot;&gt;:&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;Constant&quot;&gt;0.05f&lt;/span&gt;] &lt;span class=&quot;Support&quot;&gt;setStroke&lt;/span&gt;];
  [[&lt;span class=&quot;Support&quot;&gt;NSBezierPath&lt;/span&gt; &lt;span class=&quot;Support&quot;&gt;bezierPathWithRoundedRect&lt;span class=&quot;Support&quot;&gt;:&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;Support&quot;&gt;NSInsetRect&lt;/span&gt;(frame, &lt;span class=&quot;Constant&quot;&gt;2.5f&lt;/span&gt;, &lt;span class=&quot;Constant&quot;&gt;2.5f&lt;/span&gt;) 
                                   &lt;span class=&quot;Support&quot;&gt;xRadius&lt;span class=&quot;Support&quot;&gt;:&lt;/span&gt;&lt;/span&gt;roundedRadius 
                                   &lt;span class=&quot;Support&quot;&gt;yRadius&lt;span class=&quot;Support&quot;&gt;:&lt;/span&gt;&lt;/span&gt;roundedRadius] &lt;span class=&quot;Support&quot;&gt;stroke&lt;/span&gt;];
  [ctx &lt;span class=&quot;Support&quot;&gt;restoreGraphicsState&lt;/span&gt;];        

  &lt;span class=&quot;Comment&quot;&gt;&lt;span class=&quot;Comment&quot;&gt;//&lt;/span&gt; Draw darker overlay if button is pressed&lt;/span&gt;

  &lt;span class=&quot;Keyword&quot;&gt;if&lt;/span&gt;([&lt;span class=&quot;Variable&quot;&gt;self&lt;/span&gt; &lt;span class=&quot;Support&quot;&gt;isHighlighted&lt;/span&gt;]) {
    [ctx &lt;span class=&quot;Support&quot;&gt;saveGraphicsState&lt;/span&gt;];
    [[&lt;span class=&quot;Support&quot;&gt;NSBezierPath&lt;/span&gt; &lt;span class=&quot;Support&quot;&gt;bezierPathWithRoundedRect&lt;span class=&quot;Support&quot;&gt;:&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;Support&quot;&gt;NSInsetRect&lt;/span&gt;(frame, &lt;span class=&quot;Constant&quot;&gt;2.0f&lt;/span&gt;, &lt;span class=&quot;Constant&quot;&gt;2.0f&lt;/span&gt;) 
                                     &lt;span class=&quot;Support&quot;&gt;xRadius&lt;span class=&quot;Support&quot;&gt;:&lt;/span&gt;&lt;/span&gt;roundedRadius 
                                     &lt;span class=&quot;Support&quot;&gt;yRadius&lt;span class=&quot;Support&quot;&gt;:&lt;/span&gt;&lt;/span&gt;roundedRadius] &lt;span class=&quot;Support&quot;&gt;setClip&lt;/span&gt;];
    [[&lt;span class=&quot;Support&quot;&gt;NSColor&lt;/span&gt; &lt;span class=&quot;Support&quot;&gt;colorWithCalibratedWhite&lt;span class=&quot;Support&quot;&gt;:&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;Constant&quot;&gt;0.0f&lt;/span&gt; &lt;span class=&quot;Support&quot;&gt;alpha&lt;span class=&quot;Support&quot;&gt;:&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;Constant&quot;&gt;0.35&lt;/span&gt;] &lt;span class=&quot;Support&quot;&gt;setFill&lt;/span&gt;];
    &lt;span class=&quot;Support&quot;&gt;NSRectFillUsingOperation&lt;/span&gt;(frame, &lt;span class=&quot;Support&quot;&gt;NSCompositeSourceOver&lt;/span&gt;);
    [ctx &lt;span class=&quot;Support&quot;&gt;restoreGraphicsState&lt;/span&gt;];
  }
}
&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;To draw image I&amp;#8217;ve chosen to use it only as a mask for 2 draw operations:&lt;/p&gt;
&lt;ul&gt;
	&lt;li&gt;Image as solid color&lt;/li&gt;
	&lt;li&gt;It&amp;#8217;s shadow as solid color&lt;/li&gt;
&lt;/ul&gt;
&lt;div class=&quot;uv&quot;&gt;&lt;pre class=&quot;lazy&quot;&gt;
- (&lt;span class=&quot;Keyword&quot;&gt;void&lt;/span&gt;)drawImage:(&lt;span class=&quot;Support&quot;&gt;NSImage&lt;/span&gt;*)image withFrame:(&lt;span class=&quot;Support&quot;&gt;NSRect&lt;/span&gt;)frame inView:(&lt;span class=&quot;Support&quot;&gt;NSView&lt;/span&gt;*)controlView
{
  &lt;span class=&quot;Support&quot;&gt;NSGraphicsContext&lt;/span&gt; *ctx = [&lt;span class=&quot;Support&quot;&gt;NSGraphicsContext&lt;/span&gt; &lt;span class=&quot;Support&quot;&gt;currentContext&lt;/span&gt;];
  CGContextRef contextRef = [ctx &lt;span class=&quot;Support&quot;&gt;graphicsPort&lt;/span&gt;];
  
  &lt;span class=&quot;Support&quot;&gt;NSData&lt;/span&gt; *data = [image &lt;span class=&quot;Support&quot;&gt;TIFFRepresentation&lt;/span&gt;]; &lt;span class=&quot;Comment&quot;&gt;&lt;span class=&quot;Comment&quot;&gt;//&lt;/span&gt; open for suggestions&lt;/span&gt;
  CGImageSourceRef source = CGImageSourceCreateWithData((CFDataRef)data, &lt;span class=&quot;Constant&quot;&gt;NULL&lt;/span&gt;);
  &lt;span class=&quot;Keyword&quot;&gt;if&lt;/span&gt;(source) {
    CGImageRef imageRef = CGImageSourceCreateImageAtIndex(source, &lt;span class=&quot;Constant&quot;&gt;0&lt;/span&gt;, &lt;span class=&quot;Constant&quot;&gt;NULL&lt;/span&gt;);
    CFRelease(source);
    
    &lt;span class=&quot;Comment&quot;&gt;&lt;span class=&quot;Comment&quot;&gt;//&lt;/span&gt; Draw shadow 1px below image&lt;/span&gt;
    
    CGContextSaveGState(contextRef);
    {
      &lt;span class=&quot;Support&quot;&gt;NSRect&lt;/span&gt; rect = &lt;span class=&quot;Support&quot;&gt;NSOffsetRect&lt;/span&gt;(frame, &lt;span class=&quot;Constant&quot;&gt;0.0f&lt;/span&gt;, &lt;span class=&quot;Constant&quot;&gt;1.0f&lt;/span&gt;);
      CGFloat white = [&lt;span class=&quot;Variable&quot;&gt;self&lt;/span&gt; &lt;span class=&quot;Support&quot;&gt;isHighlighted&lt;/span&gt;] ? &lt;span class=&quot;Constant&quot;&gt;0.2f&lt;/span&gt; : &lt;span class=&quot;Constant&quot;&gt;0.35f&lt;/span&gt;;
      CGContextClipToMask(contextRef, NSRectToCGRect(rect), imageRef);
      [[&lt;span class=&quot;Support&quot;&gt;NSColor&lt;/span&gt; &lt;span class=&quot;Support&quot;&gt;colorWithDeviceWhite&lt;span class=&quot;Support&quot;&gt;:&lt;/span&gt;&lt;/span&gt;white &lt;span class=&quot;Support&quot;&gt;alpha&lt;span class=&quot;Support&quot;&gt;:&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;Constant&quot;&gt;1.0f&lt;/span&gt;] &lt;span class=&quot;Support&quot;&gt;setFill&lt;/span&gt;];
      &lt;span class=&quot;Support&quot;&gt;NSRectFill&lt;/span&gt;(rect);
    } 
    CGContextRestoreGState(contextRef);
    
    &lt;span class=&quot;Comment&quot;&gt;&lt;span class=&quot;Comment&quot;&gt;//&lt;/span&gt; Draw image&lt;/span&gt;
    
    CGContextSaveGState(contextRef);
    {
      &lt;span class=&quot;Support&quot;&gt;NSRect&lt;/span&gt; rect = frame;
      CGContextClipToMask(contextRef, NSRectToCGRect(rect), imageRef);
      [[&lt;span class=&quot;Support&quot;&gt;NSColor&lt;/span&gt; &lt;span class=&quot;Support&quot;&gt;colorWithDeviceWhite&lt;span class=&quot;Support&quot;&gt;:&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;Constant&quot;&gt;0.1f&lt;/span&gt; &lt;span class=&quot;Support&quot;&gt;alpha&lt;span class=&quot;Support&quot;&gt;:&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;Constant&quot;&gt;1.0f&lt;/span&gt;] &lt;span class=&quot;Support&quot;&gt;setFill&lt;/span&gt;];
      &lt;span class=&quot;Support&quot;&gt;NSRectFill&lt;/span&gt;(rect);
    } 
    CGContextRestoreGState(contextRef);        
    
    CFRelease(imageRef);
  }
}
&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;Ok, now we have drawing code in place, lets move to Interface Builder and wire up this custom &lt;code&gt;NSButtonCell&lt;/code&gt; for buttons which should be drawn with this style.&lt;/p&gt;
&lt;p&gt;Add some buttons:&lt;/p&gt;
&lt;p&gt;&lt;img src=&quot;http://www.amateurinmotion.com/articles/2010/05/06/button_window.png&quot; class=&quot;clean nomargin  &quot; title=&quot;button_window.png&quot; alt=&quot;button_window.png&quot;/&gt;&lt;/p&gt;
&lt;p&gt;Set Image attribute in &amp;#8220;Button Attributes&amp;#8221; panel:&lt;/p&gt;
&lt;p&gt;&lt;img src=&quot;http://www.amateurinmotion.com/articles/2010/05/06/button_attrs.png&quot; class=&quot;clean nomargin  &quot; title=&quot;button_attrs.png&quot; alt=&quot;button_attrs.png&quot;/&gt;&lt;/p&gt;
&lt;p&gt;Click one more time on button in window to select it&amp;#8217;s &lt;strong&gt;Cell Identity&lt;/strong&gt;:&lt;/p&gt;
&lt;p&gt;&lt;img src=&quot;http://www.amateurinmotion.com/articles/2010/05/06/cell_window.png&quot; class=&quot;clean nomargin  &quot; title=&quot;cell_window.png&quot; alt=&quot;cell_window.png&quot;/&gt;&lt;/p&gt;
&lt;p&gt;And set cell Class to our custom implementation:&lt;/p&gt;
&lt;p&gt;&lt;img src=&quot;http://www.amateurinmotion.com/articles/2010/05/06/cell_attrs.png&quot; class=&quot;clean nomargin  &quot; title=&quot;cell_attrs.png&quot; alt=&quot;cell_attrs.png&quot;/&gt;&lt;/p&gt;
&lt;p&gt;That&amp;#8217;s it.&lt;/p&gt;
&lt;p&gt;&lt;a href=&quot;Button.zip&quot; class=&quot;download&quot;&gt;Download example Xcode project (64Kb)&lt;/a&gt;&lt;/p&gt;</content>
</entry>


  <entry>
  <title>hi, i make macintosh software.</title>
  <link href="/articles/2010/05/06/macintosh-software.html" />
  <id>tag:www.amateurinmotion.com,2010-05-06:1273100530</id>
  <updated>2010-05-06T02:02:10+03:00</updated>
  <content type="html">&lt;p&gt;&lt;a href=&quot;http://www.panic.com/goods/&quot;&gt;&lt;img src=&quot;http://www.amateurinmotion.com/articles/2010/05/06/mininfo-1.gif&quot; class=&quot;clean nomargin hw  &quot; title=&quot;mininfo-1.gif&quot; alt=&quot;mininfo-1.gif&quot;/&gt;&lt;/a&gt;&lt;/p&gt;
&lt;p&gt;Few weeks ago I finished my first Mac application &amp;#8212; &lt;strong&gt;Saucejas.app&lt;/strong&gt;. It is small (about 1000 lines of code) app which renders pretty image and video slideshow to secondary display using CoreAnimation.&lt;/p&gt;
&lt;p&gt;&lt;a href=&quot;saucejas-app.png&quot;&gt;&lt;img src=&quot;http://www.amateurinmotion.com/articles/2010/05/06/saucejas-app.png&quot; class=&quot;clean nomargin fw  &quot; title=&quot;saucejas-app.png&quot; alt=&quot;saucejas-app.png&quot;/&gt;&lt;/a&gt;&lt;/p&gt;
&lt;p&gt;Application itself doesn&amp;#8217;t have notably pretty UI or implementation. It was written basically in one day for use in &lt;a href=&quot;http://www.saucejas.lv&quot;&gt;Saucejas&lt;/a&gt; show as a informative &amp;amp; mood-setting background. Here is video featuring Saucejas and previous version of app in background which I wrote earlier in &lt;a href=&quot;http://www.processing.org/&quot;&gt;Processing&lt;/a&gt;.&lt;/p&gt;
&lt;p&gt;&lt;object width=&quot;480&quot; height=&quot;385&quot; style=&quot;border: 1px solid #ddd&quot;&gt;&lt;param name=&quot;movie&quot; value=&quot;http://www.youtube.com/v/dAS4sFzZfjk&amp;hl=en_US&amp;fs=1&amp;rel=0&quot;&gt;&lt;/param&gt;&lt;param name=&quot;allowFullScreen&quot; value=&quot;true&quot;&gt;&lt;/param&gt;&lt;param name=&quot;allowscriptaccess&quot; value=&quot;always&quot;&gt;&lt;/param&gt;&lt;embed src=&quot;http://www.youtube.com/v/dAS4sFzZfjk&amp;hl=en_US&amp;fs=1&amp;rel=0&quot; type=&quot;application/x-shockwave-flash&quot; allowscriptaccess=&quot;always&quot; allowfullscreen=&quot;true&quot; width=&quot;480&quot; height=&quot;385&quot;&gt;&lt;/embed&gt;&lt;/object&gt;&lt;/p&gt;
&lt;p&gt;Nevertheless it was a really good exercise for me and here are few things I&amp;#8217;ve learned:&lt;/p&gt;
&lt;h2&gt;General tips&lt;/h2&gt;
&lt;ul&gt;
	&lt;li&gt;Use Bindings &amp;#8212; they&amp;#8217;re great!&lt;/li&gt;
	&lt;li&gt;Objective-C is not Java (I&amp;#8217;m still primary a Java person), do not try to organize code in Java style&lt;/li&gt;
	&lt;li&gt;Xcode &lt;code&gt;plist&lt;/code&gt; editor is not the easiest to use tool for &lt;code&gt;NSArray&lt;/code&gt; of &lt;code&gt;NSDictionaries&lt;/code&gt; of 2-3 key-value pairs &amp;#8212; consider different format for large lists or create custom editor for plist&lt;/li&gt;
&lt;/ul&gt;
&lt;h2&gt;Scaling NSImage (proportionally)&lt;/h2&gt;
&lt;div class=&quot;uv&quot;&gt;&lt;pre class=&quot;lazy&quot;&gt;
&lt;span class=&quot;Support&quot;&gt;NSSize&lt;/span&gt; SCProportionalSizeForTargetSize(&lt;span class=&quot;Support&quot;&gt;NSSize&lt;/span&gt; size, &lt;span class=&quot;Support&quot;&gt;NSSize&lt;/span&gt; target) {
   &lt;span class=&quot;Keyword&quot;&gt;if&lt;/span&gt;(&lt;span class=&quot;Support&quot;&gt;NSEqualSizes&lt;/span&gt;(size, target)) {
      &lt;span class=&quot;Keyword&quot;&gt;return&lt;/span&gt; size;
   }

   &lt;span class=&quot;Keyword&quot;&gt;float&lt;/span&gt; widthFactor  = target.width  / size.width;
   &lt;span class=&quot;Keyword&quot;&gt;float&lt;/span&gt; heightFactor = target.height / size.height;

   &lt;span class=&quot;Keyword&quot;&gt;float&lt;/span&gt; scalingFactor;

   &lt;span class=&quot;Keyword&quot;&gt;if&lt;/span&gt; (widthFactor &amp;lt; heightFactor) {
      scalingFactor = widthFactor;
   } &lt;span class=&quot;Keyword&quot;&gt;else&lt;/span&gt; {
      scalingFactor = heightFactor;
   }

   &lt;span class=&quot;Keyword&quot;&gt;return&lt;/span&gt; &lt;span class=&quot;Support&quot;&gt;NSMakeSize&lt;/span&gt;(size.width  * scalingFactor, size.height * scalingFactor);
}

&lt;span class=&quot;Keyword&quot;&gt;&lt;span class=&quot;Keyword&quot;&gt;@&lt;/span&gt;implementation&lt;/span&gt; &lt;span class=&quot;Entity&quot;&gt;NSImage&lt;/span&gt; (SCAdditions)

  - (&lt;span class=&quot;Support&quot;&gt;NSImage&lt;/span&gt; *)imageByScalingProportionallyToSize:(&lt;span class=&quot;Support&quot;&gt;NSSize&lt;/span&gt;)target
  {
     &lt;span class=&quot;Support&quot;&gt;NSSize&lt;/span&gt; size = &lt;span class=&quot;Variable&quot;&gt;self&lt;/span&gt;.size;

     &lt;span class=&quot;Support&quot;&gt;NSSize&lt;/span&gt; proportionalSize = SCProportionalSizeForTargetSize(size, target);
     &lt;span class=&quot;Support&quot;&gt;NSImage&lt;/span&gt; *scaledImage = [[&lt;span class=&quot;Support&quot;&gt;NSImage&lt;/span&gt; &lt;span class=&quot;Support&quot;&gt;alloc&lt;/span&gt;] &lt;span class=&quot;Support&quot;&gt;initWithSize&lt;span class=&quot;Support&quot;&gt;:&lt;/span&gt;&lt;/span&gt;proportionalSize];
     [scaledImage &lt;span class=&quot;Support&quot;&gt;setCacheMode&lt;span class=&quot;Support&quot;&gt;:&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;Support&quot;&gt;NSImageCacheNever&lt;/span&gt;];

     [scaledImage &lt;span class=&quot;Support&quot;&gt;lockFocus&lt;/span&gt;];
     [[&lt;span class=&quot;Support&quot;&gt;NSGraphicsContext&lt;/span&gt; &lt;span class=&quot;Support&quot;&gt;currentContext&lt;/span&gt;] &lt;span class=&quot;Support&quot;&gt;setImageInterpolation&lt;span class=&quot;Support&quot;&gt;:&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;Support&quot;&gt;NSImageInterpolationHigh&lt;/span&gt;];
     [&lt;span class=&quot;Variable&quot;&gt;self&lt;/span&gt; &lt;span class=&quot;Support&quot;&gt;drawInRect&lt;span class=&quot;Support&quot;&gt;:&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;Support&quot;&gt;NSMakeRect&lt;/span&gt;(.&lt;span class=&quot;Constant&quot;&gt;0f&lt;/span&gt;, .&lt;span class=&quot;Constant&quot;&gt;0f&lt;/span&gt;, proportionalSize.width, proportionalSize.height) 
             &lt;span class=&quot;Support&quot;&gt;fromRect&lt;span class=&quot;Support&quot;&gt;:&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;Support&quot;&gt;NSMakeRect&lt;/span&gt;(.&lt;span class=&quot;Constant&quot;&gt;0f&lt;/span&gt;, .&lt;span class=&quot;Constant&quot;&gt;0f&lt;/span&gt;, size.width, size.height) 
            &lt;span class=&quot;Support&quot;&gt;operation&lt;span class=&quot;Support&quot;&gt;:&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;Support&quot;&gt;NSCompositeSourceOver&lt;/span&gt; 
             &lt;span class=&quot;Support&quot;&gt;fraction&lt;span class=&quot;Support&quot;&gt;:&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;Constant&quot;&gt;1.0f&lt;/span&gt;];
     [scaledImage &lt;span class=&quot;Support&quot;&gt;unlockFocus&lt;/span&gt;];

     &lt;span class=&quot;Keyword&quot;&gt;return&lt;/span&gt; [scaledImage &lt;span class=&quot;Support&quot;&gt;autorelease&lt;/span&gt;];
  }

&lt;span class=&quot;Keyword&quot;&gt;&lt;span class=&quot;Keyword&quot;&gt;@&lt;/span&gt;end&lt;/span&gt;
&lt;/pre&gt;&lt;/div&gt;&lt;ul&gt;
	&lt;li&gt;Drawing to &lt;code&gt;NSImage&lt;/code&gt; can also be done in background thread&lt;/li&gt;
	&lt;li&gt;Cache mode must be &lt;code&gt;NSImageCacheNever&lt;/code&gt; otherwise all scaled &lt;code&gt;NSImages&lt;/code&gt; are cached&lt;/li&gt;
	&lt;li&gt;Set graphics context interpolation mode to High for better results&lt;br /&gt;
    &lt;br /&gt;
h2. Disabling screensaver&lt;/li&gt;
&lt;/ul&gt;
&lt;div class=&quot;uv&quot;&gt;&lt;pre class=&quot;lazy&quot;&gt;
&lt;span class=&quot;Comment&quot;&gt;&lt;span class=&quot;Comment&quot;&gt;//&lt;/span&gt; Periodically called by NSTimer&lt;/span&gt;
- (&lt;span class=&quot;Keyword&quot;&gt;void&lt;/span&gt;)disableScreenSaverTimerDidUpdate:(&lt;span class=&quot;Support&quot;&gt;NSTimer&lt;/span&gt; *)timer
{
   UpdateSystemActivity(OverallAct);
}
&lt;/pre&gt;&lt;/div&gt;&lt;h2&gt;Getting all connected displays&lt;/h2&gt;
&lt;div class=&quot;uv&quot;&gt;&lt;pre class=&quot;lazy&quot;&gt;
#&lt;span class=&quot;Keyword&quot;&gt;import&lt;/span&gt; &lt;span class=&quot;String&quot;&gt;&lt;span class=&quot;String&quot;&gt;&amp;lt;&lt;/span&gt;IOKit/graphics/IOGraphicsLib.h&lt;span class=&quot;String&quot;&gt;&amp;gt;&lt;/span&gt;&lt;/span&gt;
  
&lt;span class=&quot;Keyword&quot;&gt;&lt;span class=&quot;Keyword&quot;&gt;@&lt;/span&gt;implementation&lt;/span&gt; &lt;span class=&quot;Entity&quot;&gt;SCDisplay&lt;/span&gt;

+ (&lt;span class=&quot;Support&quot;&gt;NSArray&lt;/span&gt; *)&lt;span class=&quot;Entity&quot;&gt;displays&lt;/span&gt;
{
   &lt;span class=&quot;Support&quot;&gt;NSMutableArray&lt;/span&gt; *displays = [&lt;span class=&quot;Support&quot;&gt;NSMutableArray&lt;/span&gt; &lt;span class=&quot;Support&quot;&gt;array&lt;/span&gt;];
   
   CGDirectDisplayID *onlineDisplays = &lt;span class=&quot;Support&quot;&gt;malloc&lt;/span&gt;(
      &lt;span class=&quot;Keyword&quot;&gt;sizeof&lt;/span&gt;(CGDirectDisplayID) * 
      &lt;span class=&quot;Constant&quot;&gt;kSCMaxDisplayCount&lt;/span&gt;);

   CGDisplayCount displayCount;
   CGDisplayErr listErr = CGGetActiveDisplayList(&lt;span class=&quot;Constant&quot;&gt;kSCMaxDisplayCount&lt;/span&gt;, 
                                                 onlineDisplays, 
                                                 &amp;amp;displayCount);

   &lt;span class=&quot;Keyword&quot;&gt;if&lt;/span&gt;(listErr == &lt;span class=&quot;Constant&quot;&gt;kCGErrorSuccess&lt;/span&gt;) {
      &lt;span class=&quot;Keyword&quot;&gt;for&lt;/span&gt;(&lt;span class=&quot;Keyword&quot;&gt;int&lt;/span&gt; i=&lt;span class=&quot;Constant&quot;&gt;0&lt;/span&gt;; i&amp;lt;displayCount; i++) {
         CGDirectDisplayID displayId = onlineDisplays[i];

         CGRect bounds = CGDisplayBounds(displayId);
         
         &lt;span class=&quot;Support&quot;&gt;NSString&lt;/span&gt; *name = &lt;span class=&quot;Constant&quot;&gt;nil&lt;/span&gt;;
         io_service_t port = CGDisplayIOServicePort(displayId);
         
         CFDictionaryRef infoRef = IODisplayCreateInfoDictionary(port, 
                                   &lt;span class=&quot;Constant&quot;&gt;kIODisplayOnlyPreferredName&lt;/span&gt;);
         
         &lt;span class=&quot;Keyword&quot;&gt;if&lt;/span&gt;(infoRef != &lt;span class=&quot;Constant&quot;&gt;NULL&lt;/span&gt;) {
            CFDictionaryRef productNameDictionaryRef = CFDictionaryGetValue(infoRef, 
                                                       CFSTR(&lt;span class=&quot;Constant&quot;&gt;kDisplayProductName&lt;/span&gt;));
            &lt;span class=&quot;Keyword&quot;&gt;if&lt;/span&gt;(productNameDictionaryRef != &lt;span class=&quot;Constant&quot;&gt;NULL&lt;/span&gt;) {
               CFIndex count = CFDictionaryGetCount(productNameDictionaryRef);
               &lt;span class=&quot;Keyword&quot;&gt;if&lt;/span&gt;(count &amp;gt; &lt;span class=&quot;Constant&quot;&gt;0&lt;/span&gt;) {
                  &lt;span class=&quot;Keyword&quot;&gt;const&lt;/span&gt; &lt;span class=&quot;Keyword&quot;&gt;void&lt;/span&gt; **values = (&lt;span class=&quot;Keyword&quot;&gt;const&lt;/span&gt; &lt;span class=&quot;Keyword&quot;&gt;void&lt;/span&gt; **)&lt;span class=&quot;Support&quot;&gt;malloc&lt;/span&gt; (&lt;span class=&quot;Keyword&quot;&gt;sizeof&lt;/span&gt;(&lt;span class=&quot;Keyword&quot;&gt;void&lt;/span&gt; *) * count);
                  CFDictionaryGetKeysAndValues(productNameDictionaryRef, &lt;span class=&quot;Constant&quot;&gt;NULL&lt;/span&gt;, values);
                  
                  CFTypeRef nameRef = (CFTypeRef)values[&lt;span class=&quot;Constant&quot;&gt;0&lt;/span&gt;];
                  name = [&lt;span class=&quot;Support&quot;&gt;NSString&lt;/span&gt; &lt;span class=&quot;Support&quot;&gt;stringWithString&lt;span class=&quot;Support&quot;&gt;:&lt;/span&gt;&lt;/span&gt;(&lt;span class=&quot;Support&quot;&gt;NSString&lt;/span&gt; *)nameRef];
                  
                  &lt;span class=&quot;Support&quot;&gt;free&lt;/span&gt;(values);
               }
            }
            CFRelease(infoRef);
         }
         
         &lt;span class=&quot;Keyword&quot;&gt;if&lt;/span&gt;(!name) {
            name = &lt;span class=&quot;String&quot;&gt;&lt;span class=&quot;String&quot;&gt;@&amp;quot;&lt;/span&gt;Unknown&lt;span class=&quot;String&quot;&gt;&amp;quot;&lt;/span&gt;&lt;/span&gt;;
         }
         
         SCDisplay *display = [[SCDisplay &lt;span class=&quot;Support&quot;&gt;alloc&lt;/span&gt;] &lt;span class=&quot;Support&quot;&gt;initWithDirectDisplayId&lt;span class=&quot;Support&quot;&gt;:&lt;/span&gt;&lt;/span&gt;displayId 
                                                                  &lt;span class=&quot;Support&quot;&gt;bounds&lt;span class=&quot;Support&quot;&gt;:&lt;/span&gt;&lt;/span&gt;bounds 
                                                                    &lt;span class=&quot;Support&quot;&gt;name&lt;span class=&quot;Support&quot;&gt;:&lt;/span&gt;&lt;/span&gt;name];
         [displays &lt;span class=&quot;Support&quot;&gt;addObject&lt;span class=&quot;Support&quot;&gt;:&lt;/span&gt;&lt;/span&gt;display];
         [display &lt;span class=&quot;Support&quot;&gt;release&lt;/span&gt;];
      }
   } &lt;span class=&quot;Keyword&quot;&gt;else&lt;/span&gt; {
      &lt;span class=&quot;Support&quot;&gt;NSLog&lt;/span&gt;(&lt;span class=&quot;String&quot;&gt;&lt;span class=&quot;String&quot;&gt;@&amp;quot;&lt;/span&gt;%@ %s • CGGetOnlineDisplayList failed: %u&lt;span class=&quot;String&quot;&gt;&amp;quot;&lt;/span&gt;&lt;/span&gt;, [&lt;span class=&quot;Variable&quot;&gt;self&lt;/span&gt; &lt;span class=&quot;Support&quot;&gt;className&lt;/span&gt;], &lt;span class=&quot;Variable&quot;&gt;_cmd&lt;/span&gt;, listErr);
   }
   &lt;span class=&quot;Support&quot;&gt;free&lt;/span&gt;(onlineDisplays);
   
   &lt;span class=&quot;Keyword&quot;&gt;return&lt;/span&gt; displays;
}

&lt;span class=&quot;Keyword&quot;&gt;&lt;span class=&quot;Keyword&quot;&gt;@&lt;/span&gt;end&lt;/span&gt;
&lt;/pre&gt;&lt;/div&gt;&lt;h2&gt;Capturing and releasing a display&lt;/h2&gt;
&lt;div class=&quot;uv&quot;&gt;&lt;pre class=&quot;lazy&quot;&gt;
&lt;span class=&quot;Comment&quot;&gt;&lt;span class=&quot;Comment&quot;&gt;//&lt;/span&gt; CGDirectDisplayID displayId_; from CGGetActiveDisplayList&lt;/span&gt;

&lt;span class=&quot;Comment&quot;&gt;&lt;span class=&quot;Comment&quot;&gt;//&lt;/span&gt; Caputure&lt;/span&gt;
CGDisplayErr captureErr = CGDisplayCapture(self.displayId);
&lt;span class=&quot;Keyword&quot;&gt;if&lt;/span&gt;(captureErr == &lt;span class=&quot;Constant&quot;&gt;kCGErrorSuccess&lt;/span&gt;) {
   self.captured = &lt;span class=&quot;Constant&quot;&gt;YES&lt;/span&gt;;
} &lt;span class=&quot;Keyword&quot;&gt;else&lt;/span&gt; {
   &lt;span class=&quot;Support&quot;&gt;NSLog&lt;/span&gt;(&lt;span class=&quot;String&quot;&gt;&lt;span class=&quot;String&quot;&gt;@&amp;quot;&lt;/span&gt;%@ %s • CGDisplayCapture failed: %u&lt;span class=&quot;String&quot;&gt;&amp;quot;&lt;/span&gt;&lt;/span&gt;, [&lt;span class=&quot;Variable&quot;&gt;self&lt;/span&gt; &lt;span class=&quot;Support&quot;&gt;className&lt;/span&gt;], _cmd, captureErr);
}

&lt;span class=&quot;Comment&quot;&gt;&lt;span class=&quot;Comment&quot;&gt;//&lt;/span&gt; Release&lt;/span&gt;
CGDisplayErr err = CGDisplayRelease(self.displayId);
&lt;span class=&quot;Keyword&quot;&gt;if&lt;/span&gt;(err == &lt;span class=&quot;Constant&quot;&gt;kCGErrorSuccess&lt;/span&gt;) {
   self.captured = &lt;span class=&quot;Constant&quot;&gt;NO&lt;/span&gt;;
   released = &lt;span class=&quot;Constant&quot;&gt;YES&lt;/span&gt;;
} &lt;span class=&quot;Keyword&quot;&gt;else&lt;/span&gt; {
   &lt;span class=&quot;Support&quot;&gt;NSLog&lt;/span&gt;(&lt;span class=&quot;String&quot;&gt;&lt;span class=&quot;String&quot;&gt;@&amp;quot;&lt;/span&gt;%@ %s • CGDisplayRelease failed: %u&lt;span class=&quot;String&quot;&gt;&amp;quot;&lt;/span&gt;&lt;/span&gt;, [&lt;span class=&quot;Variable&quot;&gt;self&lt;/span&gt; &lt;span class=&quot;Support&quot;&gt;className&lt;/span&gt;], _cmd, err);
}
&lt;/pre&gt;&lt;/div&gt;&lt;h2&gt;Full-screen &lt;code&gt;NSWindow&lt;/code&gt; on captured display&lt;/h2&gt;
&lt;div class=&quot;uv&quot;&gt;&lt;pre class=&quot;lazy&quot;&gt;
CGFloat mainDisplayHeight = [[&lt;span class=&quot;Support&quot;&gt;NSScreen&lt;/span&gt; &lt;span class=&quot;Support&quot;&gt;mainScreen&lt;/span&gt;] &lt;span class=&quot;Support&quot;&gt;frame&lt;/span&gt;].size.height;
CGRect displayBounds = self.display.bounds; &lt;span class=&quot;Comment&quot;&gt;&lt;span class=&quot;Comment&quot;&gt;//&lt;/span&gt; from CGDisplayBounds&lt;/span&gt;

&lt;span class=&quot;Comment&quot;&gt;&lt;span class=&quot;Comment&quot;&gt;//&lt;/span&gt; secondary displays are &amp;quot;below&amp;quot; main screen&lt;/span&gt;
&lt;span class=&quot;Support&quot;&gt;NSRect&lt;/span&gt; rect = &lt;span class=&quot;Support&quot;&gt;NSMakeRect&lt;/span&gt;(displayBounds.origin.x, 
                         mainDisplayHeight - displayBounds.size.height, 
                         displayBounds.size.width, 
                         displayBounds.size.height);

&lt;span class=&quot;Support&quot;&gt;NSWindow&lt;/span&gt; *window = [[&lt;span class=&quot;Support&quot;&gt;NSWindow&lt;/span&gt; &lt;span class=&quot;Support&quot;&gt;alloc&lt;/span&gt;] &lt;span class=&quot;Support&quot;&gt;initWithContentRect&lt;span class=&quot;Support&quot;&gt;:&lt;/span&gt;&lt;/span&gt;rect
                                               &lt;span class=&quot;Support&quot;&gt;styleMask&lt;span class=&quot;Support&quot;&gt;:&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;Support&quot;&gt;NSBorderlessWindowMask&lt;/span&gt;
                                                 &lt;span class=&quot;Support&quot;&gt;backing&lt;span class=&quot;Support&quot;&gt;:&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;Support&quot;&gt;NSBackingStoreBuffered&lt;/span&gt;
                                                   &lt;span class=&quot;Support&quot;&gt;defer&lt;span class=&quot;Support&quot;&gt;:&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;Constant&quot;&gt;NO&lt;/span&gt;];

[window &lt;span class=&quot;Support&quot;&gt;setLevel&lt;span class=&quot;Support&quot;&gt;:&lt;/span&gt;&lt;/span&gt;CGShieldingWindowLevel()];
&lt;/pre&gt;&lt;/div&gt;&lt;ul&gt;
	&lt;li&gt;See &lt;code&gt;-[NSScreen frame]&lt;/code&gt; &amp;amp; &lt;code&gt;-[NSScreen visibleFrame]&lt;/code&gt; maybe they calculate correct rect for window&lt;/li&gt;
	&lt;li&gt;To get &lt;code&gt;NSScreen&lt;/code&gt; from &lt;code&gt;displayId&lt;/code&gt; I assume &lt;code&gt;-[NSScreen deviceDescription]&lt;/code&gt; can be used&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;References:&lt;/p&gt;
&lt;ul&gt;
	&lt;li&gt;&lt;a href=&quot;http://developer.apple.com&quot;&gt;Apple Documentation&lt;/a&gt;&lt;/li&gt;
	&lt;li&gt;&lt;a href=&quot;http://cocoadevcentral.com/articles/000028.php&quot;&gt;Cocoa Dev Central &amp;mdash; How to Make a Full Screen App&lt;/a&gt;&lt;/li&gt;
	&lt;li&gt;&lt;a href=&quot;http://www.cocoabuilder.com&quot;&gt;Cocoabuilder Cocoa mailing-list archive&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;</content>
</entry>


  <entry>
  <title>Gaeds 1.2 Changes #5 - Query property names</title>
  <link href="/articles/2010/03/18/gaeds-1.2-snapshot-changes-5.html" />
  <id>tag:www.amateurinmotion.com,2010-03-18:1268905511</id>
  <updated>2010-03-18T11:45:11+02:00</updated>
  <content type="html">&lt;p&gt;&lt;a href=&quot;http://bitbucket.org/ampatspell/gaeds/wiki/Home&quot;&gt;Gaeds&lt;/a&gt; is my tiny AppEngine for Java low-level DatastoreService wrapper. This is fifth post about new features that will form 1.2 final release. The previous posts are: &lt;a href=&quot;/articles/2010/03/12/gaeds-1.2-snapshot-changes-4.html&quot;&gt;Inheritance&lt;/a&gt;, &lt;a href=&quot;/articles/2010/03/10/gaeds-1.2-snapshot-changes-3.html&quot;&gt;GaedsKey&lt;T&gt;&lt;/a&gt;, &lt;a href=&quot;/articles/2010/03/04/gaeds-1.2-snapshot-changes-1.html&quot;&gt;Configuration&lt;/a&gt; and &lt;a href=&quot;/articles/2010/03/09/gaeds-1.2-snapshot-changes-2.html&quot;&gt;Converters&lt;/a&gt;.&lt;/p&gt;
&lt;p&gt;Gaeds Model attribute to Entity property mapping is done using &lt;code&gt;@Property&lt;/code&gt; annotation. By default attribute (class field) names are used also as Entity property names but this can be customized using &lt;code&gt;@Property(name = &quot;differentName&quot;)&lt;/code&gt;. So lets consider a small example:&lt;/p&gt;
&lt;div class=&quot;uv&quot;&gt;&lt;pre class=&quot;lazy&quot;&gt;
@&lt;span class=&quot;Keyword&quot;&gt;Model&lt;/span&gt;
&lt;span class=&quot;Keyword&quot;&gt;public &lt;/span&gt;&lt;span class=&quot;Keyword&quot;&gt;class&lt;/span&gt; &lt;span class=&quot;Entity&quot;&gt;User&lt;/span&gt; {

  @&lt;span class=&quot;Keyword&quot;&gt;PrimaryKey&lt;/span&gt;
  &lt;span class=&quot;Keyword&quot;&gt;private&lt;/span&gt; &lt;span class=&quot;Keyword&quot;&gt;GaedsKey&lt;/span&gt;&lt;span class=&quot;Keyword&quot;&gt;&amp;lt;&lt;/span&gt;&lt;span class=&quot;Keyword&quot;&gt;User&lt;/span&gt;&lt;span class=&quot;Keyword&quot;&gt;&amp;gt;&lt;/span&gt; key;
  
  @&lt;span class=&quot;Keyword&quot;&gt;Property&lt;/span&gt;(name = &lt;span class=&quot;String&quot;&gt;&lt;span class=&quot;String&quot;&gt;&amp;quot;&lt;/span&gt;fullName&lt;span class=&quot;String&quot;&gt;&amp;quot;&lt;/span&gt;&lt;/span&gt;)
  &lt;span class=&quot;Keyword&quot;&gt;private&lt;/span&gt; &lt;span class=&quot;Support&quot;&gt;String&lt;/span&gt; login;
  
  @&lt;span class=&quot;Keyword&quot;&gt;Property&lt;/span&gt;
  &lt;span class=&quot;Keyword&quot;&gt;private&lt;/span&gt; &lt;span class=&quot;Support&quot;&gt;String&lt;/span&gt; password;

}

&lt;span class=&quot;Keyword&quot;&gt;User&lt;/span&gt; user = &lt;span class=&quot;Keyword&quot;&gt;new&lt;/span&gt; &lt;span class=&quot;Keyword&quot;&gt;User&lt;/span&gt;();
user.setLogin(&lt;span class=&quot;String&quot;&gt;&lt;span class=&quot;String&quot;&gt;&amp;quot;&lt;/span&gt;ampatspell&lt;span class=&quot;String&quot;&gt;&amp;quot;&lt;/span&gt;&lt;/span&gt;);
user.setPassword(&lt;span class=&quot;String&quot;&gt;&lt;span class=&quot;String&quot;&gt;&amp;quot;&lt;/span&gt;zeebaneighba&lt;span class=&quot;String&quot;&gt;&amp;quot;&lt;/span&gt;&lt;/span&gt;);

sess.put(user);
&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;Entities will have the following properties:&lt;/p&gt;
&lt;div class=&quot;uv&quot;&gt;&lt;pre class=&quot;lazy&quot;&gt;
&lt;span class=&quot;Keyword&quot;&gt;User&lt;/span&gt; user = sess.get(user);
&lt;span class=&quot;Support&quot;&gt;Entity&lt;/span&gt; entity = &lt;span class=&quot;Keyword&quot;&gt;Gaeds&lt;/span&gt;.asModel(user).getEntity(); &lt;span class=&quot;Comment&quot;&gt;&lt;span class=&quot;Comment&quot;&gt;//&lt;/span&gt; accessing Entity directly&lt;/span&gt;

assertEquals(&lt;span class=&quot;String&quot;&gt;&lt;span class=&quot;String&quot;&gt;&amp;quot;&lt;/span&gt;ampatspell&lt;span class=&quot;String&quot;&gt;&amp;quot;&lt;/span&gt;&lt;/span&gt;, entity.getProperty(&lt;span class=&quot;String&quot;&gt;&lt;span class=&quot;String&quot;&gt;&amp;quot;&lt;/span&gt;fullName&lt;span class=&quot;String&quot;&gt;&amp;quot;&lt;/span&gt;&lt;/span&gt;));
assertEquals(&lt;span class=&quot;String&quot;&gt;&lt;span class=&quot;String&quot;&gt;&amp;quot;&lt;/span&gt;zeebaneighba&lt;span class=&quot;String&quot;&gt;&amp;quot;&lt;/span&gt;&lt;/span&gt;, entity.getProperty(&lt;span class=&quot;String&quot;&gt;&lt;span class=&quot;String&quot;&gt;&amp;quot;&lt;/span&gt;password&lt;span class=&quot;String&quot;&gt;&amp;quot;&lt;/span&gt;&lt;/span&gt;));
&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;And now the breaking change: &lt;strong&gt;query filters and sort parameters now use attribute names instead of entity property names&lt;/strong&gt;. This means that to filter by &lt;code&gt;login&lt;/code&gt; attribute, the &lt;code&gt;&quot;login&quot;&lt;/code&gt; must be used, not &lt;code&gt;&quot;fullName&quot;&lt;/code&gt;:&lt;/p&gt;
&lt;div class=&quot;uv&quot;&gt;&lt;pre class=&quot;lazy&quot;&gt;
&lt;span class=&quot;Keyword&quot;&gt;User&lt;/span&gt; user;

&lt;span class=&quot;Comment&quot;&gt;&lt;span class=&quot;Comment&quot;&gt;//&lt;/span&gt; SELECT * from User WHERE fullName = ampatspell&lt;/span&gt;
user = sess.query().model(&lt;span class=&quot;Keyword&quot;&gt;User&lt;/span&gt;.&lt;span class=&quot;Keyword&quot;&gt;class&lt;/span&gt;).eq(&lt;span class=&quot;String&quot;&gt;&lt;span class=&quot;String&quot;&gt;&amp;quot;&lt;/span&gt;login&lt;span class=&quot;String&quot;&gt;&amp;quot;&lt;/span&gt;&lt;/span&gt;, &lt;span class=&quot;String&quot;&gt;&lt;span class=&quot;String&quot;&gt;&amp;quot;&lt;/span&gt;ampatspell&lt;span class=&quot;String&quot;&gt;&amp;quot;&lt;/span&gt;&lt;/span&gt;).singleResult();
assertNotNull(user);

&lt;span class=&quot;Comment&quot;&gt;&lt;span class=&quot;Comment&quot;&gt;//&lt;/span&gt; SELECT * from User WHERE password = zeebaneighba&lt;/span&gt;
user = sess.query().model(&lt;span class=&quot;Keyword&quot;&gt;User&lt;/span&gt;.&lt;span class=&quot;Keyword&quot;&gt;class&lt;/span&gt;).eq(&lt;span class=&quot;String&quot;&gt;&lt;span class=&quot;String&quot;&gt;&amp;quot;&lt;/span&gt;password&lt;span class=&quot;String&quot;&gt;&amp;quot;&lt;/span&gt;&lt;/span&gt;, &lt;span class=&quot;String&quot;&gt;&lt;span class=&quot;String&quot;&gt;&amp;quot;&lt;/span&gt;zeebaneighba&lt;span class=&quot;String&quot;&gt;&amp;quot;&lt;/span&gt;&lt;/span&gt;).singleResult();
assertNotNull(user);
&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;Please check your DAO&amp;#8217;s for queries which filter by custom property names and update them to attribute names.&lt;/p&gt;
&lt;p&gt;I&amp;#8217;m sorry that I found this bug only now. The behavior could be left as is but I feel this breaking change is needed.&lt;/p&gt;</content>
</entry>


  <entry>
  <title>Gaeds 1.2 Changes #4 - Inheritance</title>
  <link href="/articles/2010/03/12/gaeds-1.2-snapshot-changes-4.html" />
  <id>tag:www.amateurinmotion.com,2010-03-12:1268413804</id>
  <updated>2010-03-12T19:10:04+02:00</updated>
  <content type="html">&lt;p&gt;&lt;a href=&quot;http://bitbucket.org/ampatspell/gaeds/wiki/Home&quot;&gt;Gaeds&lt;/a&gt; is my tiny AppEngine for Java low-level DatastoreService wrapper. This is forth post about new features that will form 1.2 final release.&lt;/p&gt;
&lt;p&gt;The first three are:&lt;/p&gt;
&lt;ul&gt;
	&lt;li&gt;&lt;a href=&quot;/articles/2010/03/10/gaeds-1.2-snapshot-changes-3.html&quot;&gt;GaedsKey&lt;T&gt;&lt;/a&gt;&lt;/li&gt;
	&lt;li&gt;&lt;a href=&quot;/articles/2010/03/04/gaeds-1.2-snapshot-changes-1.html&quot;&gt;Configuration&lt;/a&gt;&lt;/li&gt;
	&lt;li&gt;&lt;a href=&quot;/articles/2010/03/09/gaeds-1.2-snapshot-changes-2.html&quot;&gt;Converters&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;Both new features are related to inheritance handling so lets start with 3 models:&lt;/p&gt;
&lt;div class=&quot;uv&quot;&gt;&lt;pre class=&quot;lazy&quot;&gt;
@&lt;span class=&quot;Keyword&quot;&gt;Model&lt;/span&gt;
&lt;span class=&quot;Keyword&quot;&gt;public &lt;/span&gt;&lt;span class=&quot;Keyword&quot;&gt;class&lt;/span&gt; &lt;span class=&quot;Entity&quot;&gt;Transaction&lt;/span&gt; {
}

@&lt;span class=&quot;Keyword&quot;&gt;Model&lt;/span&gt;(discriminator = &lt;span class=&quot;String&quot;&gt;&lt;span class=&quot;String&quot;&gt;&amp;quot;&lt;/span&gt;handled&lt;span class=&quot;String&quot;&gt;&amp;quot;&lt;/span&gt;&lt;/span&gt;)
&lt;span class=&quot;Keyword&quot;&gt;public &lt;/span&gt;&lt;span class=&quot;Keyword&quot;&gt;class&lt;/span&gt; &lt;span class=&quot;Entity&quot;&gt;HandledTransaction&lt;/span&gt; &lt;span class=&quot;Keyword&quot;&gt;extends&lt;/span&gt; &lt;span class=&quot;Keyword&quot;&gt;Transaction&lt;/span&gt; {
}

@&lt;span class=&quot;Keyword&quot;&gt;Model&lt;/span&gt;(discriminator = &lt;span class=&quot;String&quot;&gt;&lt;span class=&quot;String&quot;&gt;&amp;quot;&lt;/span&gt;amount&lt;span class=&quot;String&quot;&gt;&amp;quot;&lt;/span&gt;&lt;/span&gt;)
&lt;span class=&quot;Keyword&quot;&gt;public &lt;/span&gt;&lt;span class=&quot;Keyword&quot;&gt;class&lt;/span&gt; &lt;span class=&quot;Entity&quot;&gt;AmountTransaction&lt;/span&gt; &lt;span class=&quot;Keyword&quot;&gt;extends&lt;/span&gt; &lt;span class=&quot;Keyword&quot;&gt;HandledTransaction&lt;/span&gt; {
}
&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;Those three models shares single &lt;code&gt;kind&lt;/code&gt; of &lt;code&gt;&quot;Transaction&quot;&lt;/code&gt;.&lt;/p&gt;
&lt;h2&gt;Query keysOnly() implementation change&lt;/h2&gt;
&lt;p&gt;Now it is possible to query for keysOnly() while getting (more) correct model classes:&lt;/p&gt;
&lt;div class=&quot;uv&quot;&gt;&lt;pre class=&quot;lazy&quot;&gt;
&lt;span class=&quot;Support&quot;&gt;Iterable&lt;/span&gt;&lt;span class=&quot;Keyword&quot;&gt;&amp;lt;&lt;/span&gt;&lt;span class=&quot;Keyword&quot;&gt;HandledTransaction&lt;/span&gt;&lt;span class=&quot;Keyword&quot;&gt;&amp;gt;&lt;/span&gt; iterable = getSession().query().
  &lt;span class=&quot;Entity&quot;&gt;model&lt;/span&gt;(&lt;span class=&quot;Keyword&quot;&gt;HandledTransaction&lt;/span&gt;.class).
  eq(&amp;quot;failed&amp;quot;, false).
  eq(&amp;quot;otherTransactionKey&amp;quot;, null).
  limit(limit).
  keysOnly().
  asIterable();

for (&lt;span class=&quot;Keyword&quot;&gt;HandledTransaction&lt;/span&gt; transaction : iterable) {
  &lt;span class=&quot;Comment&quot;&gt;&lt;span class=&quot;Comment&quot;&gt;//&lt;/span&gt; ...&lt;/span&gt;
}
&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;Prepared query is:&lt;/p&gt;
&lt;div class=&quot;uv&quot;&gt;&lt;pre class=&quot;lazy&quot;&gt;
SELECT __key__ 
  FROM Transaction 
  WHERE _discriminator = handled 
    AND failed = false 
    AND otherTransactionKey = NULL
&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;While &lt;code&gt;keysOnly()&lt;/code&gt; query doesn&amp;#8217;t return actual type (In this case it can also be AmountTransaction &amp;#8212; see next feature why) at least it is not base &lt;code&gt;Transaction&lt;/code&gt; instance anymore.&lt;/p&gt;
&lt;p&gt;Here is all three queries:&lt;/p&gt;
&lt;div class=&quot;uv&quot;&gt;&lt;pre class=&quot;lazy&quot;&gt;
session.query().model(&amp;lt;Model&amp;gt;.class).keysOnly().asList();
&lt;/pre&gt;&lt;/div&gt;&lt;table&gt;
	&lt;tr&gt;
		&lt;th&gt;Model and returned instance class &lt;/th&gt;
		&lt;th&gt;DatastoreService Query &lt;/th&gt;
	&lt;/tr&gt;
	&lt;tr&gt;
		&lt;td&gt; &lt;code&gt;Transaction.class&lt;/code&gt;        &lt;/td&gt;
		&lt;td&gt; &lt;code&gt;SELECT __key__ FROM Transaction&lt;/code&gt; &lt;/td&gt;
	&lt;/tr&gt;
	&lt;tr&gt;
		&lt;td&gt; &lt;code&gt;HandledTransaction.class&lt;/code&gt; &lt;/td&gt;
		&lt;td&gt; &lt;code&gt;SELECT __key__ FROM Transaction WHERE _discriminator = handled&lt;/code&gt; &lt;/td&gt;
	&lt;/tr&gt;
	&lt;tr&gt;
		&lt;td&gt; &lt;code&gt;AmountTransaction.class&lt;/code&gt;  &lt;/td&gt;
		&lt;td&gt; &lt;code&gt;SELECT __key__ FROM Transaction WHERE _discriminator = amount&lt;/code&gt; &lt;/td&gt;
	&lt;/tr&gt;
&lt;/table&gt;
&lt;p&gt;Of course this also works for &lt;code&gt;SELECT * FROM&lt;/code&gt; queries with the difference that returned instance clases will be actual sub-classes:&lt;/p&gt;
&lt;div class=&quot;uv&quot;&gt;&lt;pre class=&quot;lazy&quot;&gt;
session.query().model(&amp;lt;Model&amp;gt;.class).asList();
&lt;/pre&gt;&lt;/div&gt;&lt;table&gt;
	&lt;tr&gt;
		&lt;th&gt;Model and returned instance class &lt;/th&gt;
		&lt;th&gt;DatastoreService Query &lt;/th&gt;
	&lt;/tr&gt;
	&lt;tr&gt;
		&lt;td&gt; &lt;code&gt;Transaction.class&lt;/code&gt;        &lt;/td&gt;
		&lt;td&gt; &lt;code&gt;SELECT * FROM Transaction&lt;/code&gt; &lt;/td&gt;
	&lt;/tr&gt;
	&lt;tr&gt;
		&lt;td&gt; &lt;code&gt;HandledTransaction.class&lt;/code&gt; &lt;/td&gt;
		&lt;td&gt; &lt;code&gt;SELECT * FROM Transaction WHERE _discriminator = handled&lt;/code&gt; &lt;/td&gt;
	&lt;/tr&gt;
	&lt;tr&gt;
		&lt;td&gt; &lt;code&gt;AmountTransaction.class&lt;/code&gt;  &lt;/td&gt;
		&lt;td&gt; &lt;code&gt;SELECT * FROM Transaction WHERE _discriminator = amount&lt;/code&gt; &lt;/td&gt;
	&lt;/tr&gt;
&lt;/table&gt;
&lt;h2&gt;Discriminator as list property (when needed)&lt;/h2&gt;
&lt;p&gt;As we saw previously to query any &lt;code&gt;HandledTransaction&lt;/code&gt; (this includes all &lt;code&gt;HandledTransaction&lt;/code&gt; and &lt;strong&gt;also&lt;/strong&gt; &lt;code&gt;AmountTransaction&lt;/code&gt; entities) we need to query with two different &lt;code&gt;&quot;_discriminator&quot;&lt;/code&gt; values. This is not supported in AppEngine Datastore. Instead if given model is subclass of model which is already a model what has &lt;code&gt;discriminator&lt;/code&gt; value set, the &lt;code&gt;&quot;_discriminator&quot;&lt;/code&gt; property becomes list property listing &lt;strong&gt;all&lt;/strong&gt; discriminators:&lt;/p&gt;
&lt;table&gt;
	&lt;tr&gt;
		&lt;th&gt;Model &lt;/th&gt;
		&lt;th&gt;Discriminators &lt;/th&gt;
	&lt;/tr&gt;
	&lt;tr&gt;
		&lt;td&gt; &lt;code&gt;Transaction.class&lt;/code&gt;        &lt;/td&gt;
		&lt;td&gt; &amp;#8212; &lt;/td&gt;
	&lt;/tr&gt;
	&lt;tr&gt;
		&lt;td&gt; &lt;code&gt;HandledTransaction.class&lt;/code&gt; &lt;/td&gt;
		&lt;td&gt; &amp;#8220;handled&amp;#8221; &amp;#8212; &lt;code&gt;String&lt;/code&gt; &lt;/td&gt;
	&lt;/tr&gt;
	&lt;tr&gt;
		&lt;td&gt; &lt;code&gt;AmountTransaction.class&lt;/code&gt;  &lt;/td&gt;
		&lt;td&gt; [&amp;#8220;amount&amp;#8221;, &amp;#8220;handled&amp;#8221;] &amp;#8212; &lt;code&gt;List&amp;lt;String&amp;gt;&lt;/code&gt; &lt;/td&gt;
	&lt;/tr&gt;
&lt;/table&gt;
&lt;p&gt;This allows to query any entity that is &lt;code&gt;HandledTransaction&lt;/code&gt; or &lt;code&gt;AmountTransaction&lt;/code&gt;.&lt;/p&gt;
&lt;h2&gt;Upgrading Entities (if needed, optional)&lt;/h2&gt;
&lt;p&gt;To take advantage of those new features, enties what has parent entity with discriminator set (in this example only &lt;code&gt;AmountTransaction&lt;/code&gt;), needs to be migrated.&lt;/p&gt;
&lt;p&gt;To migrate just get or query them followed by put afterwards:&lt;/p&gt;
&lt;div class=&quot;uv&quot;&gt;&lt;pre class=&quot;lazy&quot;&gt;
&lt;span class=&quot;Keyword&quot;&gt;Session&lt;/span&gt; session = getSession();

&lt;span class=&quot;Comment&quot;&gt;&lt;span class=&quot;Comment&quot;&gt;//&lt;/span&gt; Query will work because this was the _discriminator value that was saved before&lt;/span&gt;
&lt;span class=&quot;Comment&quot;&gt;&lt;span class=&quot;Comment&quot;&gt;//&lt;/span&gt; SELECT * FROM Transaction WHERE _discriminator = amount&lt;/span&gt;
&lt;span class=&quot;Support&quot;&gt;Iterable&lt;/span&gt;&lt;span class=&quot;Keyword&quot;&gt;&amp;lt;&lt;/span&gt;&lt;span class=&quot;Keyword&quot;&gt;AmountTransaction&lt;/span&gt;&lt;span class=&quot;Keyword&quot;&gt;&amp;gt;&lt;/span&gt; list = session.query().
  &lt;span class=&quot;Entity&quot;&gt;model&lt;/span&gt;(&lt;span class=&quot;Keyword&quot;&gt;AmountTransaction&lt;/span&gt;.class).
  limit(500).
  asIterable();

&lt;span class=&quot;Comment&quot;&gt;&lt;span class=&quot;Comment&quot;&gt;//&lt;/span&gt; gaeds will re-populate _discriminator value&lt;/span&gt;
session.put(list);
&lt;/pre&gt;&lt;/div&gt;</content>
</entry>


  <entry>
  <title>Gaeds 1.2 Changes #3 - GaedsKey&lt;T&gt;</title>
  <link href="/articles/2010/03/10/gaeds-1.2-snapshot-changes-3.html" />
  <id>tag:www.amateurinmotion.com,2010-03-10:1268225773</id>
  <updated>2010-03-10T14:56:13+02:00</updated>
  <content type="html">&lt;p&gt;&lt;a href=&quot;http://bitbucket.org/ampatspell/gaeds/wiki/Home&quot;&gt;Gaeds&lt;/a&gt; is my tiny AppEngine for Java low-level DatastoreService wrapper. This is third post in three post series about new features that will form 1.2 final release.&lt;/p&gt;
&lt;p&gt;The first two are:&lt;/p&gt;
&lt;ul&gt;
	&lt;li&gt;&lt;a href=&quot;/articles/2010/03/04/gaeds-1.2-snapshot-changes-1.html&quot;&gt;Configuration&lt;/a&gt;&lt;/li&gt;
	&lt;li&gt;&lt;a href=&quot;/articles/2010/03/09/gaeds-1.2-snapshot-changes-2.html&quot;&gt;Converters&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;Google AppEngine Datastore &lt;code&gt;Entity&lt;/code&gt; primary keys are &lt;code&gt;Key&lt;/code&gt; instances. Each &lt;code&gt;Key&lt;/code&gt; is composed from &lt;code&gt;String kind&lt;/code&gt; and either &lt;code&gt;long id&lt;/code&gt; or &lt;code&gt;String keyName&lt;/code&gt;. Also &lt;code&gt;Key&lt;/code&gt; can be encoded as &lt;code&gt;String&lt;/code&gt; and then decoded back to &lt;code&gt;Key&lt;/code&gt; instance using &lt;code&gt;KeyFactory&lt;/code&gt;.&lt;/p&gt;
&lt;p&gt;For me the most important new gaeds feature is &lt;code&gt;GaedsKey&amp;lt;T&amp;gt;&lt;/code&gt; generic class that wraps Key &lt;strong&gt;and&lt;/strong&gt; respective model class. It is impossible to create GaedsKey with mismatched model class (see notes below about inheritance).&lt;/p&gt;
&lt;p&gt;GaedsKey&lt;T&gt; interface is declared like this:&lt;/p&gt;
&lt;div class=&quot;uv&quot;&gt;&lt;pre class=&quot;lazy&quot;&gt;
&lt;span class=&quot;Keyword&quot;&gt;public &lt;/span&gt;&lt;span class=&quot;Keyword&quot;&gt;interface&lt;/span&gt; &lt;span class=&quot;Entity&quot;&gt;GaedsKey&lt;/span&gt;&amp;lt;T&amp;gt; &lt;span class=&quot;Keyword&quot;&gt;extends&lt;/span&gt; &lt;span class=&quot;Support&quot;&gt;Comparable&lt;/span&gt;&amp;lt;&lt;span class=&quot;Keyword&quot;&gt;GaedsKey&lt;/span&gt;&amp;lt;T&amp;gt;&amp;gt; {

  &lt;span class=&quot;Support&quot;&gt;Key&lt;/span&gt; getKey();

  &lt;span class=&quot;Support&quot;&gt;Class&lt;/span&gt;&lt;span class=&quot;Keyword&quot;&gt;&amp;lt;&lt;/span&gt;? &lt;span class=&quot;Keyword&quot;&gt;extends&lt;/span&gt; T&lt;span class=&quot;Keyword&quot;&gt;&amp;gt;&lt;/span&gt; getModelClass();

  &lt;span class=&quot;Keyword&quot;&gt;&amp;lt;&lt;/span&gt;R&lt;span class=&quot;Keyword&quot;&gt;&amp;gt;&lt;/span&gt; &lt;span class=&quot;Keyword&quot;&gt;GaedsKey&lt;/span&gt;&lt;span class=&quot;Keyword&quot;&gt;&amp;lt;&lt;/span&gt;R&lt;span class=&quot;Keyword&quot;&gt;&amp;gt;&lt;/span&gt; cast(&lt;span class=&quot;Support&quot;&gt;Class&lt;/span&gt;&lt;span class=&quot;Keyword&quot;&gt;&amp;lt;&lt;/span&gt;R&lt;span class=&quot;Keyword&quot;&gt;&amp;gt;&lt;/span&gt; type);

  &lt;span class=&quot;Keyword&quot;&gt;&amp;lt;&lt;/span&gt;P&lt;span class=&quot;Keyword&quot;&gt;&amp;gt;&lt;/span&gt; &lt;span class=&quot;Keyword&quot;&gt;GaedsKey&lt;/span&gt;&lt;span class=&quot;Keyword&quot;&gt;&amp;lt;&lt;/span&gt;P&lt;span class=&quot;Keyword&quot;&gt;&amp;gt;&lt;/span&gt; getParent(&lt;span class=&quot;Support&quot;&gt;Class&lt;/span&gt;&lt;span class=&quot;Keyword&quot;&gt;&amp;lt;&lt;/span&gt;? &lt;span class=&quot;Keyword&quot;&gt;extends&lt;/span&gt; P&lt;span class=&quot;Keyword&quot;&gt;&amp;gt;&lt;/span&gt; model);

  &lt;span class=&quot;Support&quot;&gt;String&lt;/span&gt; encode();
  
  &lt;span class=&quot;Comment&quot;&gt;&lt;span class=&quot;Comment&quot;&gt;//&lt;/span&gt; and few other methods&lt;/span&gt;

}
&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;To create &lt;code&gt;GaedsKey&lt;/code&gt; from &lt;code&gt;Key&lt;/code&gt; or from encoded &lt;code&gt;String&lt;/code&gt; &lt;code&gt;GaedsKeyFactory&lt;/code&gt; must be used:&lt;/p&gt;
&lt;div class=&quot;uv&quot;&gt;&lt;pre class=&quot;lazy&quot;&gt;
&lt;span class=&quot;Keyword&quot;&gt;GaedsKeyFactory&lt;/span&gt; kf = session.key(); &lt;span class=&quot;Comment&quot;&gt;&lt;span class=&quot;Comment&quot;&gt;//&lt;/span&gt; or @Inject GaedsKeyFactory directly&lt;/span&gt;

&lt;span class=&quot;Comment&quot;&gt;&lt;span class=&quot;Comment&quot;&gt;//&lt;/span&gt; from String or Key&lt;/span&gt;
&lt;span class=&quot;Keyword&quot;&gt;GaedsKey&lt;/span&gt;&lt;span class=&quot;Keyword&quot;&gt;&amp;lt;&lt;/span&gt;&lt;span class=&quot;Keyword&quot;&gt;Task&lt;/span&gt;&lt;span class=&quot;Keyword&quot;&gt;&amp;gt;&lt;/span&gt; key = kf.create(string, &lt;span class=&quot;Keyword&quot;&gt;Task&lt;/span&gt;.&lt;span class=&quot;Keyword&quot;&gt;class&lt;/span&gt;);       &lt;span class=&quot;Comment&quot;&gt;&lt;span class=&quot;Comment&quot;&gt;//&lt;/span&gt; from encoded datastore key&lt;/span&gt;
&lt;span class=&quot;Keyword&quot;&gt;GaedsKey&lt;/span&gt;&lt;span class=&quot;Keyword&quot;&gt;&amp;lt;&lt;/span&gt;&lt;span class=&quot;Keyword&quot;&gt;Task&lt;/span&gt;&lt;span class=&quot;Keyword&quot;&gt;&amp;gt;&lt;/span&gt; key = kf.create(datastoreKey, &lt;span class=&quot;Keyword&quot;&gt;Task&lt;/span&gt;.&lt;span class=&quot;Keyword&quot;&gt;class&lt;/span&gt;); &lt;span class=&quot;Comment&quot;&gt;&lt;span class=&quot;Comment&quot;&gt;//&lt;/span&gt; from datastore key&lt;/span&gt;

&lt;span class=&quot;Comment&quot;&gt;&lt;span class=&quot;Comment&quot;&gt;//&lt;/span&gt; Root keys&lt;/span&gt;
&lt;span class=&quot;Keyword&quot;&gt;GaedsKey&lt;/span&gt;&lt;span class=&quot;Keyword&quot;&gt;&amp;lt;&lt;/span&gt;&lt;span class=&quot;Keyword&quot;&gt;Task&lt;/span&gt;&lt;span class=&quot;Keyword&quot;&gt;&amp;gt;&lt;/span&gt; key = kf.create(&lt;span class=&quot;Keyword&quot;&gt;Task&lt;/span&gt;.&lt;span class=&quot;Keyword&quot;&gt;class&lt;/span&gt;, &lt;span class=&quot;String&quot;&gt;&lt;span class=&quot;String&quot;&gt;&amp;quot;&lt;/span&gt;something&lt;span class=&quot;String&quot;&gt;&amp;quot;&lt;/span&gt;&lt;/span&gt;);  &lt;span class=&quot;Comment&quot;&gt;&lt;span class=&quot;Comment&quot;&gt;//&lt;/span&gt; with keyName&lt;/span&gt;
&lt;span class=&quot;Keyword&quot;&gt;GaedsKey&lt;/span&gt;&lt;span class=&quot;Keyword&quot;&gt;&amp;lt;&lt;/span&gt;&lt;span class=&quot;Keyword&quot;&gt;Task&lt;/span&gt;&lt;span class=&quot;Keyword&quot;&gt;&amp;gt;&lt;/span&gt; key = kf.create(&lt;span class=&quot;Keyword&quot;&gt;Task&lt;/span&gt;.&lt;span class=&quot;Keyword&quot;&gt;class&lt;/span&gt;, &lt;span class=&quot;Constant&quot;&gt;102l&lt;/span&gt;);         &lt;span class=&quot;Comment&quot;&gt;&lt;span class=&quot;Comment&quot;&gt;//&lt;/span&gt; with id&lt;/span&gt;

&lt;span class=&quot;Comment&quot;&gt;&lt;span class=&quot;Comment&quot;&gt;//&lt;/span&gt; Keys with parent Key or GaedsKey&lt;/span&gt;
&lt;span class=&quot;Keyword&quot;&gt;GaedsKey&lt;/span&gt;&lt;span class=&quot;Keyword&quot;&gt;&amp;lt;&lt;/span&gt;&lt;span class=&quot;Keyword&quot;&gt;Task&lt;/span&gt;&lt;span class=&quot;Keyword&quot;&gt;&amp;gt;&lt;/span&gt; key = kf.create(parent, &lt;span class=&quot;Keyword&quot;&gt;Task&lt;/span&gt;.&lt;span class=&quot;Keyword&quot;&gt;class&lt;/span&gt;, &lt;span class=&quot;String&quot;&gt;&lt;span class=&quot;String&quot;&gt;&amp;quot;&lt;/span&gt;something&lt;span class=&quot;String&quot;&gt;&amp;quot;&lt;/span&gt;&lt;/span&gt;); &lt;span class=&quot;Comment&quot;&gt;&lt;span class=&quot;Comment&quot;&gt;//&lt;/span&gt; with keyName&lt;/span&gt;
&lt;span class=&quot;Keyword&quot;&gt;GaedsKey&lt;/span&gt;&lt;span class=&quot;Keyword&quot;&gt;&amp;lt;&lt;/span&gt;&lt;span class=&quot;Keyword&quot;&gt;Task&lt;/span&gt;&lt;span class=&quot;Keyword&quot;&gt;&amp;gt;&lt;/span&gt; key = kf.create(parent, &lt;span class=&quot;Keyword&quot;&gt;Task&lt;/span&gt;.&lt;span class=&quot;Keyword&quot;&gt;class&lt;/span&gt;, &lt;span class=&quot;Constant&quot;&gt;102l&lt;/span&gt;);        &lt;span class=&quot;Comment&quot;&gt;&lt;span class=&quot;Comment&quot;&gt;//&lt;/span&gt; with id&lt;/span&gt;
&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;First two &lt;code&gt;DatastoreKeyFactory#create&lt;/code&gt; calls ensures that provided key &lt;strong&gt;matches&lt;/strong&gt; model class by comparing Key kind to kind declared for model. If kind don&amp;#8217;t match, &lt;code&gt;GaedsKeyRuntimeException&lt;/code&gt; is thrown. This behavior ensures that encoded keys coming from web request matches expected model kind. If kinds doesn&amp;#8217;t match, exception is thrown before Datastore get/put/query operation (fail fast). By using &lt;code&gt;Key&lt;/code&gt; directly &lt;code&gt;get&lt;/code&gt; operations would quite possibly just fail with &lt;code&gt;ClassCastException&lt;/code&gt; after touching Datastore.&lt;/p&gt;
&lt;div class=&quot;uv&quot;&gt;&lt;pre class=&quot;lazy&quot;&gt;
&lt;span class=&quot;Support&quot;&gt;String&lt;/span&gt; string = keyToString(createKey(&lt;span class=&quot;String&quot;&gt;&lt;span class=&quot;String&quot;&gt;&amp;quot;&lt;/span&gt;User&lt;span class=&quot;String&quot;&gt;&amp;quot;&lt;/span&gt;&lt;/span&gt;, &lt;span class=&quot;Constant&quot;&gt;101&lt;/span&gt;));

&lt;span class=&quot;Comment&quot;&gt;&lt;span class=&quot;Comment&quot;&gt;//&lt;/span&gt; Creates &amp;quot;User(101)&amp;quot; key&lt;/span&gt;
&lt;span class=&quot;Support&quot;&gt;Key&lt;/span&gt; key = stringToKey(string);
&lt;span class=&quot;Comment&quot;&gt;&lt;span class=&quot;Comment&quot;&gt;//&lt;/span&gt; Throws ModelNotFoundException or ClassCastException after get.&lt;/span&gt;
&lt;span class=&quot;Keyword&quot;&gt;Task&lt;/span&gt; task = sess.get(key);

&lt;span class=&quot;Comment&quot;&gt;&lt;span class=&quot;Comment&quot;&gt;//&lt;/span&gt; Throws GaedsKeyRuntimeException&lt;/span&gt;
&lt;span class=&quot;Keyword&quot;&gt;GaedsKey&lt;/span&gt;&lt;span class=&quot;Keyword&quot;&gt;&amp;lt;&lt;/span&gt;&lt;span class=&quot;Keyword&quot;&gt;Task&lt;/span&gt;&lt;span class=&quot;Keyword&quot;&gt;&amp;gt;&lt;/span&gt; key = kf.create(string, &lt;span class=&quot;Keyword&quot;&gt;Task&lt;/span&gt;.&lt;span class=&quot;Keyword&quot;&gt;class&lt;/span&gt;);
&lt;span class=&quot;Comment&quot;&gt;&lt;span class=&quot;Comment&quot;&gt;//&lt;/span&gt; Not reached&lt;/span&gt;
&lt;span class=&quot;Keyword&quot;&gt;Task&lt;/span&gt; task = sess.get(key);
&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;Gaeds models has direct relationship to &lt;code&gt;Entity&lt;/code&gt; keyNames. It is possible to use &lt;code&gt;GaedsKey&amp;lt;T&amp;gt;&lt;/code&gt; without any changes to &lt;code&gt;Model&lt;/code&gt; classes but more beneficial they are if &lt;code&gt;@PrimaryKey&lt;/code&gt;, &lt;code&gt;@ParentKey&lt;/code&gt; and all &lt;code&gt;@Property Key&lt;/code&gt; declarations also are declared as &lt;code&gt;GaedsKey&amp;lt;T&amp;gt;&lt;/code&gt;. Lets consider 2 models &amp;#8211; &lt;code&gt;Person&lt;/code&gt; and &lt;code&gt;Task&lt;/code&gt;:&lt;/p&gt;
&lt;div class=&quot;uv&quot;&gt;&lt;pre class=&quot;lazy&quot;&gt;
@&lt;span class=&quot;Keyword&quot;&gt;Model&lt;/span&gt;
&lt;span class=&quot;Keyword&quot;&gt;public static &lt;/span&gt;&lt;span class=&quot;Keyword&quot;&gt;class&lt;/span&gt; &lt;span class=&quot;Entity&quot;&gt;Person&lt;/span&gt; {

  @&lt;span class=&quot;Keyword&quot;&gt;PrimaryKey&lt;/span&gt;
  &lt;span class=&quot;Keyword&quot;&gt;private&lt;/span&gt; &lt;span class=&quot;Keyword&quot;&gt;GaedsKey&lt;/span&gt;&lt;span class=&quot;Keyword&quot;&gt;&amp;lt;&lt;/span&gt;&lt;span class=&quot;Keyword&quot;&gt;Person&lt;/span&gt;&lt;span class=&quot;Keyword&quot;&gt;&amp;gt;&lt;/span&gt; key;

  &lt;span class=&quot;Comment&quot;&gt;&lt;span class=&quot;Comment&quot;&gt;//&lt;/span&gt; getters &amp;amp; setters&lt;/span&gt;
  
}

@&lt;span class=&quot;Keyword&quot;&gt;Model&lt;/span&gt;
&lt;span class=&quot;Keyword&quot;&gt;public static &lt;/span&gt;&lt;span class=&quot;Keyword&quot;&gt;class&lt;/span&gt; &lt;span class=&quot;Entity&quot;&gt;Task&lt;/span&gt; {

  @&lt;span class=&quot;Keyword&quot;&gt;PrimaryKey&lt;/span&gt;
  &lt;span class=&quot;Keyword&quot;&gt;private&lt;/span&gt; &lt;span class=&quot;Keyword&quot;&gt;GaedsKey&lt;/span&gt;&lt;span class=&quot;Keyword&quot;&gt;&amp;lt;&lt;/span&gt;&lt;span class=&quot;Keyword&quot;&gt;Task&lt;/span&gt;&lt;span class=&quot;Keyword&quot;&gt;&amp;gt;&lt;/span&gt; key;

  @&lt;span class=&quot;Keyword&quot;&gt;Property&lt;/span&gt;
  &lt;span class=&quot;Keyword&quot;&gt;private&lt;/span&gt; &lt;span class=&quot;Support&quot;&gt;String&lt;/span&gt; title;

  @&lt;span class=&quot;Keyword&quot;&gt;Property&lt;/span&gt;
  &lt;span class=&quot;Keyword&quot;&gt;private&lt;/span&gt; &lt;span class=&quot;Keyword&quot;&gt;GaedsKey&lt;/span&gt;&lt;span class=&quot;Keyword&quot;&gt;&amp;lt;&lt;/span&gt;&lt;span class=&quot;Keyword&quot;&gt;Person&lt;/span&gt;&lt;span class=&quot;Keyword&quot;&gt;&amp;gt;&lt;/span&gt; owner;

  &lt;span class=&quot;Comment&quot;&gt;&lt;span class=&quot;Comment&quot;&gt;//&lt;/span&gt; getters &amp;amp; setters&lt;/span&gt;

}
&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;And some straight-forward operations on them:&lt;/p&gt;
&lt;div class=&quot;uv&quot;&gt;&lt;pre class=&quot;lazy&quot;&gt;
&lt;span class=&quot;Comment&quot;&gt;&lt;span class=&quot;Comment&quot;&gt;//&lt;/span&gt; First request&lt;/span&gt;

&lt;span class=&quot;Comment&quot;&gt;&lt;span class=&quot;Comment&quot;&gt;//&lt;/span&gt; create person&lt;/span&gt;
&lt;span class=&quot;Keyword&quot;&gt;Person&lt;/span&gt; person = &lt;span class=&quot;Keyword&quot;&gt;new&lt;/span&gt; &lt;span class=&quot;Keyword&quot;&gt;Person&lt;/span&gt;();
sess.put(person);

&lt;span class=&quot;Comment&quot;&gt;&lt;span class=&quot;Comment&quot;&gt;//&lt;/span&gt; create task with person set as owner&lt;/span&gt;
&lt;span class=&quot;Keyword&quot;&gt;Task&lt;/span&gt; task = &lt;span class=&quot;Keyword&quot;&gt;new&lt;/span&gt; &lt;span class=&quot;Keyword&quot;&gt;Task&lt;/span&gt;();
task.setTitle(&lt;span class=&quot;String&quot;&gt;&lt;span class=&quot;String&quot;&gt;&amp;quot;&lt;/span&gt;Hello world&lt;span class=&quot;String&quot;&gt;&amp;quot;&lt;/span&gt;&lt;/span&gt;);
task.setOwner(person.getKey());
sess.put(task);

&lt;span class=&quot;Support&quot;&gt;String&lt;/span&gt; encoded = task.getKey().encode();

&lt;span class=&quot;Comment&quot;&gt;&lt;span class=&quot;Comment&quot;&gt;//&lt;/span&gt; Second request&lt;/span&gt;

&lt;span class=&quot;Comment&quot;&gt;&lt;span class=&quot;Comment&quot;&gt;//&lt;/span&gt; Create Task key from encoded string (will throw if encoded Key is not for Task kind)&lt;/span&gt;
&lt;span class=&quot;Keyword&quot;&gt;GaedsKey&lt;/span&gt;&lt;span class=&quot;Keyword&quot;&gt;&amp;lt;&lt;/span&gt;&lt;span class=&quot;Keyword&quot;&gt;Task&lt;/span&gt;&lt;span class=&quot;Keyword&quot;&gt;&amp;gt;&lt;/span&gt; taskKey = sess.key().create(encoded, &lt;span class=&quot;Keyword&quot;&gt;Task&lt;/span&gt;.&lt;span class=&quot;Keyword&quot;&gt;class&lt;/span&gt;);

&lt;span class=&quot;Comment&quot;&gt;&lt;span class=&quot;Comment&quot;&gt;//&lt;/span&gt; get Task, get Person&lt;/span&gt;
&lt;span class=&quot;Keyword&quot;&gt;Task&lt;/span&gt; task = sess.get(taskKey);
&lt;span class=&quot;Keyword&quot;&gt;Person&lt;/span&gt; person = sess.get(task.getOwner());
&lt;/pre&gt;&lt;/div&gt;&lt;div class=&quot;uv&quot;&gt;&lt;pre class=&quot;lazy&quot;&gt;
Task{
  key=GaedsKey{Task(2) com.ampatspell.gaeds.test.Task}, 
  title='Hello world', 
  owner=GaedsKey{Person(1) com.ampatspell.gaeds.test.Person}
}

Person{
  key=GaedsKey{Person(1) com.ampatspell.gaeds.test.Person}
}
&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;As we can see, the GaedsKey Session API is the same as for Key and that we needed to access &lt;code&gt;GaedsKeyFactory&lt;/code&gt; only once &amp;#8212; for string decoding. While GaedsKey API is identical to Key based there are a bit more going on behind the scenes.&lt;/p&gt;
&lt;p&gt;Not only GaedsKey creation is validated to conform model-kind relationship, also all model attributes that has GaedsKey type are validated before &lt;code&gt;put&lt;/code&gt; and after &lt;code&gt;get&lt;/code&gt;, &lt;code&gt;query&lt;/code&gt;.&lt;/p&gt;
&lt;h3&gt;Put&lt;/h3&gt;
&lt;p&gt;Lets consider a bit different example involving &lt;a href=&quot;http://bitbucket.org/ampatspell/gaeds/wiki/SingleEntityInheritance&quot;&gt;gaeds model inheritance&lt;/a&gt;:&lt;/p&gt;
&lt;div class=&quot;uv&quot;&gt;&lt;pre class=&quot;lazy&quot;&gt;
@&lt;span class=&quot;Keyword&quot;&gt;Model&lt;/span&gt;
&lt;span class=&quot;Keyword&quot;&gt;public static &lt;/span&gt;&lt;span class=&quot;Keyword&quot;&gt;class&lt;/span&gt; &lt;span class=&quot;Entity&quot;&gt;Person&lt;/span&gt; {

  @&lt;span class=&quot;Keyword&quot;&gt;PrimaryKey&lt;/span&gt;
  &lt;span class=&quot;Keyword&quot;&gt;private&lt;/span&gt; &lt;span class=&quot;Keyword&quot;&gt;GaedsKey&lt;/span&gt;&lt;span class=&quot;Keyword&quot;&gt;&amp;lt;&lt;/span&gt;? &lt;span class=&quot;Keyword&quot;&gt;extends&lt;/span&gt; &lt;span class=&quot;Keyword&quot;&gt;Person&lt;/span&gt;&lt;span class=&quot;Keyword&quot;&gt;&amp;gt;&lt;/span&gt; key;

}

@&lt;span class=&quot;Keyword&quot;&gt;Model&lt;/span&gt;(discriminator = &lt;span class=&quot;String&quot;&gt;&lt;span class=&quot;String&quot;&gt;&amp;quot;&lt;/span&gt;administrator&lt;span class=&quot;String&quot;&gt;&amp;quot;&lt;/span&gt;&lt;/span&gt;)
&lt;span class=&quot;Keyword&quot;&gt;public static &lt;/span&gt;&lt;span class=&quot;Keyword&quot;&gt;class&lt;/span&gt; &lt;span class=&quot;Entity&quot;&gt;Administrator&lt;/span&gt; &lt;span class=&quot;Keyword&quot;&gt;extends&lt;/span&gt; &lt;span class=&quot;Keyword&quot;&gt;Person&lt;/span&gt; {
}
&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;We have a new class &lt;code&gt;Administrator&lt;/code&gt; which extends &lt;code&gt;Person&lt;/code&gt;. Gaeds implements inheritance by transparently adding &lt;code&gt;&quot;_discriminator&quot;&lt;/code&gt; property to saved entities and because there is no way knowing which entity type is before getting actual &lt;code&gt;Entity&lt;/code&gt;, &lt;code&gt;GaedsKey&lt;/code&gt; can be created with incorrect key+type pair:&lt;/p&gt;
&lt;div class=&quot;uv&quot;&gt;&lt;pre class=&quot;lazy&quot;&gt;
&lt;span class=&quot;Keyword&quot;&gt;Administrator&lt;/span&gt; admin = &lt;span class=&quot;Keyword&quot;&gt;new&lt;/span&gt; &lt;span class=&quot;Keyword&quot;&gt;Administrator&lt;/span&gt;();
sess.put(admin);

&lt;span class=&quot;Keyword&quot;&gt;Person&lt;/span&gt; person = &lt;span class=&quot;Keyword&quot;&gt;new&lt;/span&gt; &lt;span class=&quot;Keyword&quot;&gt;Person&lt;/span&gt;();
sess.put(person);

&lt;span class=&quot;Support&quot;&gt;String&lt;/span&gt; key = person.getKey().encode();

&lt;span class=&quot;Comment&quot;&gt;&lt;span class=&quot;Comment&quot;&gt;//&lt;/span&gt; creating a key with Person Datastore Key and Administrator type&lt;/span&gt;
&lt;span class=&quot;Keyword&quot;&gt;GaedsKey&lt;/span&gt;&lt;span class=&quot;Keyword&quot;&gt;&amp;lt;&lt;/span&gt;&lt;span class=&quot;Keyword&quot;&gt;Administrator&lt;/span&gt;&lt;span class=&quot;Keyword&quot;&gt;&amp;gt;&lt;/span&gt; admin = kf.create(key, &lt;span class=&quot;Keyword&quot;&gt;Administrator&lt;/span&gt;.&lt;span class=&quot;Keyword&quot;&gt;class&lt;/span&gt;);

&lt;span class=&quot;Comment&quot;&gt;&lt;span class=&quot;Comment&quot;&gt;//&lt;/span&gt; Throws an GaedsKeyRuntimeException&lt;/span&gt;
sess.get(admin);
&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;After &lt;code&gt;Entity&lt;/code&gt; is retrieved from Datastore, its type is compared to required type for &lt;code&gt;GaedsKey&lt;/code&gt;, if &lt;code&gt;GaedsKey&lt;/code&gt; type is not the same or subclass of fetched Model&amp;#8217;s class, &lt;code&gt;GaedsKeyRuntimeException&lt;/code&gt; is thrown. This prevents getting &lt;code&gt;ClassCastException&lt;/code&gt; or incorrect Model when &lt;code&gt;sess.get&lt;/code&gt; returns. This also works for messed up &lt;code&gt;GaedsKey&lt;/code&gt; unchecked casts:&lt;/p&gt;
&lt;div class=&quot;uv&quot;&gt;&lt;pre class=&quot;lazy&quot;&gt;
@&lt;span class=&quot;Keyword&quot;&gt;Model&lt;/span&gt;
&lt;span class=&quot;Keyword&quot;&gt;public static &lt;/span&gt;&lt;span class=&quot;Keyword&quot;&gt;class&lt;/span&gt; &lt;span class=&quot;Entity&quot;&gt;Task&lt;/span&gt; {

  &lt;span class=&quot;Comment&quot;&gt;&lt;span class=&quot;Comment&quot;&gt;//&lt;/span&gt; ...&lt;/span&gt;

  @&lt;span class=&quot;Keyword&quot;&gt;Property&lt;/span&gt;
  &lt;span class=&quot;Keyword&quot;&gt;private&lt;/span&gt; &lt;span class=&quot;Keyword&quot;&gt;GaedsKey&lt;/span&gt;&lt;span class=&quot;Keyword&quot;&gt;&amp;lt;&lt;/span&gt;&lt;span class=&quot;Keyword&quot;&gt;Administrator&lt;/span&gt;&lt;span class=&quot;Keyword&quot;&gt;&amp;gt;&lt;/span&gt; owner;

}
&lt;/pre&gt;&lt;/div&gt;&lt;div class=&quot;uv&quot;&gt;&lt;pre class=&quot;lazy&quot;&gt;
&lt;span class=&quot;Keyword&quot;&gt;Person&lt;/span&gt; person = &lt;span class=&quot;Keyword&quot;&gt;new&lt;/span&gt; &lt;span class=&quot;Keyword&quot;&gt;Person&lt;/span&gt;();
sess.put(person);

&lt;span class=&quot;Comment&quot;&gt;&lt;span class=&quot;Comment&quot;&gt;//&lt;/span&gt; Unchecked cast&lt;/span&gt;
&lt;span class=&quot;Keyword&quot;&gt;GaedsKey&lt;/span&gt;&lt;span class=&quot;Keyword&quot;&gt;&amp;lt;&lt;/span&gt;&lt;span class=&quot;Keyword&quot;&gt;Administrator&lt;/span&gt;&lt;span class=&quot;Keyword&quot;&gt;&amp;gt;&lt;/span&gt; ownerKey = (&lt;span class=&quot;Keyword&quot;&gt;GaedsKey&lt;/span&gt;) person.getKey();

&lt;span class=&quot;Keyword&quot;&gt;Task&lt;/span&gt; task = &lt;span class=&quot;Keyword&quot;&gt;new&lt;/span&gt; &lt;span class=&quot;Keyword&quot;&gt;Task&lt;/span&gt;();
task.setOwner(ownerKey);

&lt;span class=&quot;Comment&quot;&gt;&lt;span class=&quot;Comment&quot;&gt;//&lt;/span&gt; throws GaedsKeyRuntimeException&lt;/span&gt;
sess.put(task);
&lt;/pre&gt;&lt;/div&gt;&lt;div class=&quot;uv&quot;&gt;&lt;pre class=&quot;lazy&quot;&gt;
com.ampatspell.gaeds.internal.key.GaedsKeyRuntimeException: 
  GaedsKey{ExamplePerson(2) com.ampatspell.gaeds.test.Person} model class is not assignable 
  to com.ampatspell.gaeds.test.Administrator
&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;Also &lt;code&gt;GaedsKey&lt;/code&gt; exposes &lt;code&gt;cast(T targetType)&lt;/code&gt; method that allows up- and down-casting GaedsKey instances but it enforces that:&lt;/p&gt;
&lt;ul&gt;
	&lt;li&gt;&lt;code&gt;GaedsKey&amp;lt;Person&amp;gt;&lt;/code&gt; cannot be up-casted to &lt;code&gt;GaedsKey&amp;lt;Administrator&amp;gt;&lt;/code&gt;&lt;/li&gt;
	&lt;li&gt;&lt;code&gt;GaedsKey&amp;lt;Administrator&amp;gt;&lt;/code&gt; can be down-casted to &lt;code&gt;GaedsKey&amp;lt;Person&amp;gt;&lt;/code&gt; and then up-casted back to &lt;code&gt;GaedsKey&amp;lt;Administrator&amp;gt;&lt;/code&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;&lt;strong&gt;But note:&lt;/strong&gt; it is possible to create &lt;code&gt;GaedsKey&amp;lt;Administrator&amp;gt;&lt;/code&gt; with &lt;code&gt;Person&lt;/code&gt; &lt;code&gt;Key&lt;/code&gt; and &lt;code&gt;Administrator&lt;/code&gt; type, save it in Datastore as &lt;code&gt;GaedsKey&amp;lt;Administrator&amp;gt;&lt;/code&gt;. Try fetching entity using that &lt;code&gt;GaedsKey&lt;/code&gt; before, only if fetch succeeds, we can be confident that given &lt;code&gt;GaedsKey&amp;lt;Administrator&amp;gt;&lt;/code&gt; actually points to &lt;code&gt;Administrator&lt;/code&gt;.&lt;/p&gt;
&lt;h3&gt;Get &amp;amp; Query&lt;/h3&gt;
&lt;p&gt;For gets and queries, model &lt;code&gt;@Property&lt;/code&gt; attributes there is a bit different story. Lets start with creating Task with &lt;code&gt;Zeeba&lt;/code&gt; as an owner instead of &lt;code&gt;Administrator&lt;/code&gt;:&lt;/p&gt;
&lt;div class=&quot;uv&quot;&gt;&lt;pre class=&quot;lazy&quot;&gt;
&lt;span class=&quot;Support&quot;&gt;Entity&lt;/span&gt; task = &lt;span class=&quot;Keyword&quot;&gt;new&lt;/span&gt; &lt;span class=&quot;Support&quot;&gt;Entity&lt;/span&gt;(&lt;span class=&quot;String&quot;&gt;&lt;span class=&quot;String&quot;&gt;&amp;quot;&lt;/span&gt;Task&lt;span class=&quot;String&quot;&gt;&amp;quot;&lt;/span&gt;&lt;/span&gt;);
task.setProperty(&lt;span class=&quot;String&quot;&gt;&lt;span class=&quot;String&quot;&gt;&amp;quot;&lt;/span&gt;owner&lt;span class=&quot;String&quot;&gt;&amp;quot;&lt;/span&gt;&lt;/span&gt;, createKey(&lt;span class=&quot;String&quot;&gt;&lt;span class=&quot;String&quot;&gt;&amp;quot;&lt;/span&gt;Zeeba&lt;span class=&quot;String&quot;&gt;&amp;quot;&lt;/span&gt;&lt;/span&gt;, &lt;span class=&quot;String&quot;&gt;&lt;span class=&quot;String&quot;&gt;&amp;quot;&lt;/span&gt;fake&lt;span class=&quot;String&quot;&gt;&amp;quot;&lt;/span&gt;&lt;/span&gt;));
&lt;span class=&quot;Support&quot;&gt;Key&lt;/span&gt; dsKey = ds.put(task);

&lt;span class=&quot;Keyword&quot;&gt;GaedsKey&lt;/span&gt;&lt;span class=&quot;Keyword&quot;&gt;&amp;lt;&lt;/span&gt;&lt;span class=&quot;Keyword&quot;&gt;Task&lt;/span&gt;&lt;span class=&quot;Keyword&quot;&gt;&amp;gt;&lt;/span&gt; key = kf.create(dsKey, &lt;span class=&quot;Keyword&quot;&gt;Task&lt;/span&gt;.&lt;span class=&quot;Keyword&quot;&gt;class&lt;/span&gt;);
&lt;span class=&quot;Keyword&quot;&gt;Task&lt;/span&gt; model = sess.get(key);

assertTrue(&lt;span class=&quot;Keyword&quot;&gt;Gaeds&lt;/span&gt;.asModel(model).getIncompatibleProperties().contains(&lt;span class=&quot;String&quot;&gt;&lt;span class=&quot;String&quot;&gt;&amp;quot;&lt;/span&gt;owner&lt;span class=&quot;String&quot;&gt;&amp;quot;&lt;/span&gt;&lt;/span&gt;));
&lt;/pre&gt;&lt;/div&gt;&lt;div class=&quot;uv&quot;&gt;&lt;pre class=&quot;lazy&quot;&gt;
WARNING: Entity to model mapping cast errors
Model:  com.ampatspell.gaeds.test.Task
Entity: Task(1)
 * 'owner' 
      com.google.appengine.api.datastore.Key =&amp;gt; 
      com.ampatspell.gaeds.GaedsKey com.ampatspell.gaeds.test.Administrator (Zeeba(&amp;quot;fake&amp;quot;))
&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;As we can see, this is also considered incompatibility because Session wouldn&amp;#8217;t allow persisting &lt;code&gt;GaedsKey&amp;lt;Zeeba&amp;gt;&lt;/code&gt; instead of &lt;code&gt;GaedsKey&amp;lt;Administrator&amp;gt;&lt;/code&gt;. Useful for Entity migration.&lt;/p&gt;
&lt;h2&gt;API&lt;/h2&gt;
&lt;ul&gt;
	&lt;li&gt;All &lt;code&gt;Session&lt;/code&gt; and &lt;code&gt;Session#query()&lt;/code&gt; methods now takes either &lt;code&gt;Key&lt;/code&gt; or &lt;code&gt;GaedsKey&lt;/code&gt;&lt;/li&gt;
	&lt;li&gt;&lt;code&gt;GaedsKeyFactory&lt;/code&gt; can be injected (&lt;code&gt;@Inject&lt;/code&gt;) directly or accessed from &lt;code&gt;Session#key()&lt;/code&gt;&lt;/li&gt;
	&lt;li&gt;&lt;code&gt;GaedsBpSupport&lt;/code&gt; and &lt;code&gt;GaedsDaoSupport&lt;/code&gt; inherits from &lt;code&gt;AbstractGaedsSupport&lt;/code&gt; which also implements &lt;code&gt;#key()&lt;/code&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;GaedsKey &lt;code&gt;@Property&lt;/code&gt;, &lt;code&gt;@PrimaryKey&lt;/code&gt; and &lt;code&gt;@ParentKey&lt;/code&gt; can be declared as:&lt;/p&gt;
&lt;ul&gt;
	&lt;li&gt;&lt;code&gt;GaedsKey&amp;lt;Task&amp;gt;&lt;/code&gt;&lt;/li&gt;
	&lt;li&gt;&lt;code&gt;GaedsKey&amp;lt;? extends Task&amp;gt;&lt;/code&gt;&lt;/li&gt;
	&lt;li&gt;&lt;code&gt;GaedsKey&amp;lt;T&amp;gt;&lt;/code&gt; for generic classes (&lt;code&gt;@Model class Task&amp;lt;T&amp;gt; { ... }&lt;/code&gt;)&lt;/li&gt;
&lt;/ul&gt;
&lt;h2&gt;Release&lt;/h2&gt;
&lt;p&gt;I&amp;#8217;ve migrated 10 or so models to &lt;code&gt;GaedsKey&lt;/code&gt; for one of the projects I&amp;#8217;m currently working on. All tests pass, everything looks fine but I&amp;#8217;ll wait few more days before releasing 1.2 final.&lt;/p&gt;</content>
</entry>


  <entry>
  <title>Gaeds 1.2 Changes #2 - Converters</title>
  <link href="/articles/2010/03/09/gaeds-1.2-snapshot-changes-2.html" />
  <id>tag:www.amateurinmotion.com,2010-03-09:1268169201</id>
  <updated>2010-03-09T23:13:21+02:00</updated>
  <content type="html">&lt;p&gt;&lt;a href=&quot;http://bitbucket.org/ampatspell/gaeds/wiki/Home&quot;&gt;Gaeds&lt;/a&gt; is my tiny AppEngine for Java low-level DatastoreService wrapper. This is second post in three post series about new features that will form 1.2 final release.&lt;/p&gt;
&lt;p&gt;Since first release of gaeds it has &lt;code&gt;Model&lt;/code&gt; property value conversion support from-to &lt;code&gt;Entity&lt;/code&gt; properties using &lt;code&gt;Converter&lt;/code&gt;. There are few default converters and its easy to write additional ones. To declare that property needs converter, &lt;code&gt;@Property&lt;/code&gt; annotation has type setting:&lt;/p&gt;
&lt;div class=&quot;uv&quot;&gt;&lt;pre class=&quot;lazy&quot;&gt;
@&lt;span class=&quot;Keyword&quot;&gt;Model&lt;/span&gt;
&lt;span class=&quot;Keyword&quot;&gt;public &lt;/span&gt;&lt;span class=&quot;Keyword&quot;&gt;class&lt;/span&gt; &lt;span class=&quot;Entity&quot;&gt;Something&lt;/span&gt; {

  @&lt;span class=&quot;Keyword&quot;&gt;Property&lt;/span&gt;(type = &lt;span class=&quot;Keyword&quot;&gt;Text&lt;/span&gt;.&lt;span class=&quot;Keyword&quot;&gt;class&lt;/span&gt;)
  &lt;span class=&quot;Keyword&quot;&gt;private&lt;/span&gt; &lt;span class=&quot;Support&quot;&gt;String&lt;/span&gt; text;

}
&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;For &lt;code&gt;Something.text&lt;/code&gt; property before creating or updating &lt;code&gt;Entity&lt;/code&gt; &lt;code&gt;Converter&amp;lt;String, Text&amp;gt;&lt;/code&gt; will kick in and convert &lt;code&gt;String&lt;/code&gt; value to &lt;code&gt;Text&lt;/code&gt; and after get or query operations, the same converter will convert &lt;code&gt;Text&lt;/code&gt; back to &lt;code&gt;String&lt;/code&gt; and set it to model property.&lt;/p&gt;
&lt;p&gt;But now lets consider the following property:&lt;/p&gt;
&lt;div class=&quot;uv&quot;&gt;&lt;pre class=&quot;lazy&quot;&gt;
@&lt;span class=&quot;Keyword&quot;&gt;Model&lt;/span&gt;
&lt;span class=&quot;Keyword&quot;&gt;public &lt;/span&gt;&lt;span class=&quot;Keyword&quot;&gt;class&lt;/span&gt; &lt;span class=&quot;Entity&quot;&gt;Something&lt;/span&gt; {

  @&lt;span class=&quot;Keyword&quot;&gt;Property&lt;/span&gt;(field = &lt;span class=&quot;Support&quot;&gt;Serializable&lt;/span&gt;.&lt;span class=&quot;Keyword&quot;&gt;class&lt;/span&gt;, type = &lt;span class=&quot;Support&quot;&gt;Blob&lt;/span&gt;.&lt;span class=&quot;Keyword&quot;&gt;class&lt;/span&gt;)
  &lt;span class=&quot;Keyword&quot;&gt;private&lt;/span&gt; &lt;span class=&quot;Support&quot;&gt;Map&lt;/span&gt;&lt;span class=&quot;Keyword&quot;&gt;&amp;lt;&lt;/span&gt;&lt;span class=&quot;Support&quot;&gt;String&lt;/span&gt;, &lt;span class=&quot;Support&quot;&gt;Integer&lt;/span&gt;&lt;span class=&quot;Keyword&quot;&gt;&amp;gt;&lt;/span&gt; paymentDetails;

}
&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;The &lt;code&gt;Converter&lt;/code&gt; lookup is done using newly added &lt;code&gt;@Property.field&lt;/code&gt;, if it is not provided, using actual field type. Because in this example &lt;code&gt;@Property.field&lt;/code&gt; is set, the &lt;code&gt;Converter&amp;lt;Serializable, Blob&amp;gt;&lt;/code&gt; is used instead of &lt;code&gt;Converter&amp;lt;Map, Blob&amp;gt;&lt;/code&gt;.&lt;/p&gt;
&lt;p&gt;Also see &lt;a href=&quot;/articles/2010/03/04/gaeds-1.2-snapshot-changes-1.html&quot;&gt;Gaeds 1.2-SNAPSHOT Changes #2 &amp;#8212; Converters&lt;/a&gt; to learn about changes in &lt;code&gt;Converter&lt;/code&gt; configuration.&lt;/p&gt;</content>
</entry>


  <entry>
  <title>Gaeds 1.2 Changes #1 - Configuration</title>
  <link href="/articles/2010/03/04/gaeds-1.2-snapshot-changes-1.html" />
  <id>tag:www.amateurinmotion.com,2010-03-04:1267739927</id>
  <updated>2010-03-04T23:58:47+02:00</updated>
  <content type="html">&lt;p&gt;&lt;a href=&quot;http://bitbucket.org/ampatspell/gaeds/wiki/Home&quot;&gt;Gaeds&lt;/a&gt; is my tiny AppEngine for Java low-level DatastoreService wrapper. I&amp;#8217;ve started the work on version 1.2 what will have few nice additions but for now a small breaking change.&lt;/p&gt;
&lt;p&gt;Previous versions was configured something like this:&lt;/p&gt;
&lt;div class=&quot;uv&quot;&gt;&lt;pre class=&quot;lazy&quot;&gt;
&lt;span class=&quot;Keyword&quot;&gt;public &lt;/span&gt;&lt;span class=&quot;Keyword&quot;&gt;class&lt;/span&gt; &lt;span class=&quot;Entity&quot;&gt;GaedsModule&lt;/span&gt; &lt;span class=&quot;Keyword&quot;&gt;extends&lt;/span&gt; &lt;span class=&quot;Keyword&quot;&gt;AbstractModule&lt;/span&gt; {

  @&lt;span class=&quot;Support&quot;&gt;Override&lt;/span&gt;
  &lt;span class=&quot;Keyword&quot;&gt;protected &lt;/span&gt;&lt;span class=&quot;Keyword&quot;&gt;void&lt;/span&gt; &lt;span class=&quot;Entity&quot;&gt;configure&lt;/span&gt;() {
    install(&lt;span class=&quot;Keyword&quot;&gt;new&lt;/span&gt; &lt;span class=&quot;Keyword&quot;&gt;GaedsBaseModule&lt;/span&gt;());
    
    &lt;span class=&quot;Entity&quot;&gt;bind&lt;/span&gt;(&lt;span class=&quot;Keyword&quot;&gt;DatastoreService&lt;/span&gt;.class).annotatedWith(&lt;span class=&quot;Keyword&quot;&gt;Gaeds&lt;/span&gt;.class).
      toProvider(&lt;span class=&quot;Keyword&quot;&gt;DatastoreServiceProvider&lt;/span&gt;.class);
      
    bind(&lt;span class=&quot;Keyword&quot;&gt;IncompatiblePropertiesLogger&lt;/span&gt;.class).
      to(&lt;span class=&quot;Keyword&quot;&gt;IncompatiblePropertiesLoggerImpl&lt;/span&gt;.class);
  }

  @Provides
  @Singleton
  public List&amp;lt;Converter&amp;gt; provideConverters(
      @&lt;span class=&quot;Keyword&quot;&gt;Named&lt;/span&gt;(&amp;quot;default&amp;quot;) List&amp;lt;Converter&amp;gt; defaultConverters) {
      
    &lt;span class=&quot;Keyword&quot;&gt;return&lt;/span&gt; defaultConverters;
  }

  @&lt;span class=&quot;Keyword&quot;&gt;Provides&lt;/span&gt;
  @&lt;span class=&quot;Keyword&quot;&gt;ModelClasses&lt;/span&gt;
  @&lt;span class=&quot;Keyword&quot;&gt;Singleton&lt;/span&gt;
  &lt;span class=&quot;Keyword&quot;&gt;public&lt;/span&gt; &lt;span class=&quot;Support&quot;&gt;List&lt;/span&gt;&lt;span class=&quot;Keyword&quot;&gt;&amp;lt;&lt;/span&gt;&lt;span class=&quot;Support&quot;&gt;Class&lt;/span&gt;&lt;span class=&quot;Keyword&quot;&gt;&amp;lt;&lt;/span&gt;?&lt;span class=&quot;Keyword&quot;&gt;&amp;gt;&lt;/span&gt;&lt;span class=&quot;Keyword&quot;&gt;&amp;gt;&lt;/span&gt; provideModelClasses() {
    &lt;span class=&quot;Support&quot;&gt;List&lt;/span&gt;&lt;span class=&quot;Keyword&quot;&gt;&amp;lt;&lt;/span&gt;&lt;span class=&quot;Support&quot;&gt;Class&lt;/span&gt;&lt;span class=&quot;Keyword&quot;&gt;&amp;lt;&lt;/span&gt;?&lt;span class=&quot;Keyword&quot;&gt;&amp;gt;&lt;/span&gt;&lt;span class=&quot;Keyword&quot;&gt;&amp;gt;&lt;/span&gt; classes = &lt;span class=&quot;Keyword&quot;&gt;new&lt;/span&gt; &lt;span class=&quot;Support&quot;&gt;ArrayList&lt;/span&gt;&lt;span class=&quot;Keyword&quot;&gt;&amp;lt;&lt;/span&gt;&lt;span class=&quot;Support&quot;&gt;Class&lt;/span&gt;&lt;span class=&quot;Keyword&quot;&gt;&amp;lt;&lt;/span&gt;?&lt;span class=&quot;Keyword&quot;&gt;&amp;gt;&lt;/span&gt;&lt;span class=&quot;Keyword&quot;&gt;&amp;gt;&lt;/span&gt;();

    classes.add(&lt;span class=&quot;Keyword&quot;&gt;Zeeba&lt;/span&gt;.&lt;span class=&quot;Keyword&quot;&gt;class&lt;/span&gt;);
    classes.add(&lt;span class=&quot;Keyword&quot;&gt;Larry&lt;/span&gt;.&lt;span class=&quot;Keyword&quot;&gt;class&lt;/span&gt;);

    &lt;span class=&quot;Keyword&quot;&gt;return&lt;/span&gt; classes;
  }

}
&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;Now configuration looks a lot better:&lt;/p&gt;
&lt;div class=&quot;uv&quot;&gt;&lt;pre class=&quot;lazy&quot;&gt;
&lt;span class=&quot;Keyword&quot;&gt;public &lt;/span&gt;&lt;span class=&quot;Keyword&quot;&gt;class&lt;/span&gt; &lt;span class=&quot;Entity&quot;&gt;GaedsModule&lt;/span&gt; &lt;span class=&quot;Keyword&quot;&gt;extends&lt;/span&gt; &lt;span class=&quot;Keyword&quot;&gt;AbstractGaedsModelsModule&lt;/span&gt; {

  @&lt;span class=&quot;Support&quot;&gt;Override&lt;/span&gt;
  &lt;span class=&quot;Keyword&quot;&gt;protected &lt;/span&gt;&lt;span class=&quot;Keyword&quot;&gt;void&lt;/span&gt; &lt;span class=&quot;Entity&quot;&gt;configureModels&lt;/span&gt;() {
    install(&lt;span class=&quot;Keyword&quot;&gt;new&lt;/span&gt; &lt;span class=&quot;Keyword&quot;&gt;GaedsBaseModule&lt;/span&gt;());

    &lt;span class=&quot;Entity&quot;&gt;bind&lt;/span&gt;(&lt;span class=&quot;Keyword&quot;&gt;DatastoreService&lt;/span&gt;.class).annotatedWith(&lt;span class=&quot;Keyword&quot;&gt;Gaeds&lt;/span&gt;.class).
      toProvider(&lt;span class=&quot;Keyword&quot;&gt;DatastoreServiceProvider&lt;/span&gt;.class);
    
    bind(&lt;span class=&quot;Keyword&quot;&gt;IncompatiblePropertiesLogger&lt;/span&gt;.class).
      to(&lt;span class=&quot;Keyword&quot;&gt;IncompatiblePropertiesLoggerImpl&lt;/span&gt;.class);

    &lt;span class=&quot;Comment&quot;&gt;&lt;span class=&quot;Comment&quot;&gt;//&lt;/span&gt; Models&lt;/span&gt;

    model(&lt;span class=&quot;Keyword&quot;&gt;Zeeba&lt;/span&gt;.class);
    model(&lt;span class=&quot;Keyword&quot;&gt;Larry&lt;/span&gt;.class);

    &lt;span class=&quot;Comment&quot;&gt;&lt;span class=&quot;Comment&quot;&gt;//&lt;/span&gt; Converters&lt;/span&gt;

    useDefaultConverters(true);

    converter(&lt;span class=&quot;Keyword&quot;&gt;SomeCustomConverter&lt;/span&gt;.class);
  }

}
&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;In addition to to cleaner gaeds module, model classes and converters are bound using &lt;a href=&quot;http://code.google.com/p/google-guice/wiki/Multibindings&quot;&gt;Multibinder&lt;/a&gt; so it&amp;#8217;s perfectly fine to install multiple &lt;code&gt;AbstractGaedsModule&lt;/code&gt; derived modules in one Guice Injector. There are only two things to keep in mind:&lt;/p&gt;
&lt;ul&gt;
	&lt;li&gt;&lt;code&gt;Model&lt;/code&gt; class and &lt;code&gt;Converter&lt;/code&gt; duplicates are not allowed (guice will complain)&lt;/li&gt;
	&lt;li&gt;you may call &lt;code&gt;useDefaultConverters(boolean)&lt;/code&gt; only once (in one &lt;code&gt;AbstractGaedsModule&lt;/code&gt;)&lt;/li&gt;
&lt;/ul&gt;</content>
</entry>


  <entry>
  <title>Models Library Current Status</title>
  <link href="/articles/2010/03/04/models-library-current-status.html" />
  <id>tag:www.amateurinmotion.com,2010-03-04:1267661288</id>
  <updated>2010-03-04T02:08:08+02:00</updated>
  <content type="html">&lt;p&gt;This post is about Models &amp;#8212; the GWT library which hopefully will greatly help to build client-server communication, model properties-to-view binding and in application architecture in general by simplifying all boilderplate code needed to manage downloaded object graphs, presenting them to users and allowing users to act on them. What I have currently is initial implementation of &lt;code&gt;KVC&lt;/code&gt;, &lt;code&gt;KVO&lt;/code&gt;, &lt;code&gt;Bindings&lt;/code&gt;, &lt;code&gt;ForwardingModel&lt;/code&gt;, &lt;code&gt;ListController&lt;/code&gt;, &lt;code&gt;ObjectController&lt;/code&gt; and &lt;code&gt;DataSource&lt;/code&gt; (with &lt;code&gt;DataStore&lt;/code&gt;). Nothing are release ready. Controllers and DataSource are so badly implemented I&amp;#8217;m a bit ashamed to show them.&lt;/p&gt;
&lt;p&gt;The main purpose of post (aside from loud-thinking) is to try to get some feedback before API is locked. So if you have some comments, critique or just want to say hi, feel free to mail me to ampatspell@gmail.com.&lt;/p&gt;
&lt;p&gt;Lets start from lowest level API &amp;#8212; Key-Value Coding and Key-Value Observing (the terms come from Foundation framework in Cocoa). Basically this is easy to use property change observation and property value setting by name support for classes. In whole Model library context the classes are model objects either fetched from &lt;code&gt;DataSource&lt;/code&gt; (server) or created locally.&lt;/p&gt;
&lt;h2&gt;Observing&lt;/h2&gt;
&lt;p&gt;The basic model property change observation looks like this:&lt;/p&gt;
&lt;div class=&quot;uv&quot;&gt;&lt;pre class=&quot;lazy&quot;&gt;
&lt;span class=&quot;Keyword&quot;&gt;User&lt;/span&gt; user = &lt;span class=&quot;Constant&quot;&gt;GWT&lt;/span&gt;.create(&lt;span class=&quot;Keyword&quot;&gt;User&lt;/span&gt;.&lt;span class=&quot;Keyword&quot;&gt;class&lt;/span&gt;);

&lt;span class=&quot;Keyword&quot;&gt;ObserverRegistration&lt;/span&gt; registration = asReflection(user).observe(&lt;span class=&quot;String&quot;&gt;&lt;span class=&quot;String&quot;&gt;&amp;quot;&lt;/span&gt;address.country&lt;span class=&quot;String&quot;&gt;&amp;quot;&lt;/span&gt;&lt;/span&gt;, 
  &lt;span class=&quot;Support&quot;&gt;String&lt;/span&gt;.&lt;span class=&quot;Keyword&quot;&gt;class&lt;/span&gt;, 
  &lt;span class=&quot;Keyword&quot;&gt;new&lt;/span&gt; &lt;span class=&quot;Support&quot;&gt;Observer&lt;/span&gt;&lt;span class=&quot;Keyword&quot;&gt;&amp;lt;&lt;/span&gt;&lt;span class=&quot;Support&quot;&gt;String&lt;/span&gt;&lt;span class=&quot;Keyword&quot;&gt;&amp;gt;&lt;/span&gt;() {
    &lt;span class=&quot;Keyword&quot;&gt;public &lt;/span&gt;&lt;span class=&quot;Keyword&quot;&gt;void&lt;/span&gt; &lt;span class=&quot;Entity&quot;&gt;onValueChange&lt;/span&gt;(&lt;span class=&quot;Keyword&quot;&gt;KeyPath&lt;/span&gt; keyPath, &lt;span class=&quot;Support&quot;&gt;Operation&lt;/span&gt; operation, &lt;span class=&quot;Keyword&quot;&gt;IndexSet&lt;/span&gt; indexes, 
                              &lt;span class=&quot;Support&quot;&gt;String&lt;/span&gt; oldValue, 
                              &lt;span class=&quot;Support&quot;&gt;String&lt;/span&gt; newValue) {
      &lt;span class=&quot;Comment&quot;&gt;&lt;span class=&quot;Comment&quot;&gt;//&lt;/span&gt; called after value change&lt;/span&gt;
    }
  });

registration.remove();

&lt;span class=&quot;Keyword&quot;&gt;ObservableReflection&lt;/span&gt; reflection = ((&lt;span class=&quot;Support&quot;&gt;Observable&lt;/span&gt;) entry).getReflection();
&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;&lt;code&gt;Observer&amp;lt;T&amp;gt;&lt;/code&gt; callback is called when either of following are called:&lt;/p&gt;
&lt;ul&gt;
	&lt;li&gt;&lt;code&gt;user.setAddress(newAddress);&lt;/code&gt;&lt;/li&gt;
	&lt;li&gt;&lt;code&gt;user.getAddress().setCountry(&quot;New country&quot;);&lt;/code&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;Callback is &lt;em&gt;not&lt;/em&gt; called with initial value. See bindings why this is not needed.&lt;/p&gt;
&lt;p&gt;Operation can be one of &lt;code&gt;SET&lt;/code&gt;, &lt;code&gt;INSERT&lt;/code&gt;, &lt;code&gt;REMOVE&lt;/code&gt;, &lt;code&gt;CLEAR&lt;/code&gt; and so on (&lt;code&gt;SET&lt;/code&gt; for properties, others for &lt;code&gt;List&lt;/code&gt; operations).&lt;/p&gt;
&lt;p&gt;&lt;code&gt;IndexSet&lt;/code&gt; is &lt;code&gt;Range&lt;/code&gt; like class for defining &lt;code&gt;List&lt;/code&gt; operation indexes (&lt;code&gt;list.addAll(int index, E element)&lt;/code&gt; notifies observers about &lt;code&gt;INSERT&lt;/code&gt; operation and &lt;code&gt;IndexSet&lt;/code&gt; with single index).&lt;/p&gt;
&lt;p&gt;&lt;code&gt;asReflection(Object)&lt;/code&gt; is statically imported helper method what just casts user instance to &lt;code&gt;Observable&lt;/code&gt;.&lt;/p&gt;
&lt;h2&gt;Value setting by keypath&lt;/h2&gt;
&lt;p&gt;The second low-level building block is Key-Value Coding that allows to set &lt;code&gt;Observable&lt;/code&gt; object properties not only by using setters directly but also by key path. &amp;#8220;address.country&amp;#8221; in previous code snippet is key path.&lt;/p&gt;
&lt;p&gt;Lets look at small example using the same user entity:&lt;/p&gt;
&lt;div class=&quot;uv&quot;&gt;&lt;pre class=&quot;lazy&quot;&gt;
asReflection(user).setValueForKeyPath(&lt;span class=&quot;String&quot;&gt;&lt;span class=&quot;String&quot;&gt;&amp;quot;&lt;/span&gt;address.country&lt;span class=&quot;String&quot;&gt;&amp;quot;&lt;/span&gt;&lt;/span&gt;, &lt;span class=&quot;String&quot;&gt;&lt;span class=&quot;String&quot;&gt;&amp;quot;&lt;/span&gt;Zeebaburg&lt;span class=&quot;String&quot;&gt;&amp;quot;&lt;/span&gt;&lt;/span&gt;);
&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;this is the same as calling &lt;code&gt;user.getAddress().setCountry(&quot;Zeebaburg&quot;)&lt;/code&gt; (with null checking) but can be used to dynamically set values for arbitrary keys (properties).&lt;/p&gt;
&lt;h2&gt;GWT.create&lt;/h2&gt;
&lt;p&gt;Of course for both of those things to work GWT generator is used. This is the reason why &lt;code&gt;GWT.create()&lt;/code&gt; is required and so this code will only work in GWT runtime and unittests run with &lt;code&gt;GWTTestCase&lt;/code&gt;. Currently I don&amp;#8217;t have Java reflection and cglib based implementations for &lt;code&gt;Observable&lt;/code&gt; but it can be created to support standalone &lt;code&gt;JUnit&lt;/code&gt; unittests. For now I&amp;#8217;m ignoring this while I&amp;#8217;m not finished with API design.&lt;/p&gt;
&lt;h2&gt;Bindings&lt;/h2&gt;
&lt;p&gt;Next low-level API is Bindings. This feature allows to &amp;#8220;bind&amp;#8221; two targets (&lt;code&gt;BindingTarget&lt;/code&gt;) so if one of them is changed, the other is notified with new optionally converted value. Also when binding is created initial value is set from &amp;#8220;left&amp;#8221; target to &amp;#8220;right&amp;#8221;.&lt;/p&gt;
&lt;p&gt;Currently I have three notable binding targets:&lt;/p&gt;
&lt;ul&gt;
	&lt;li&gt;&lt;code&gt;ObservableTarget&lt;/code&gt; &amp;#8212; for Observable models&lt;/li&gt;
	&lt;li&gt;&lt;code&gt;HasValueTarget&amp;lt;T&amp;gt;&lt;/code&gt; &amp;#8212; for view bindings&lt;/li&gt;
	&lt;li&gt;&lt;code&gt;HasTextTarget&lt;/code&gt; &amp;#8212; for view bindings&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;Others are easy to write.&lt;/p&gt;
&lt;p&gt;As you might guessed this main purpose is to bind model properties to GWT Widgets. But actually it turns out that binding &lt;code&gt;ObservableTarget&lt;/code&gt; to other &lt;code&gt;ObservableTarget&lt;/code&gt; is as important as &lt;code&gt;Widget&lt;/code&gt; targeted ones.&lt;/p&gt;
&lt;p&gt;Lets look at two low-level Bindings usage examples:&lt;/p&gt;
&lt;h3&gt;Observable to Observable:&lt;/h3&gt;
&lt;div class=&quot;uv&quot;&gt;&lt;pre class=&quot;lazy&quot;&gt;
bindings.bind(
  &lt;span class=&quot;Entity&quot;&gt;observable&lt;/span&gt;(list, &amp;quot;selection&amp;quot;, &lt;span class=&quot;Keyword&quot;&gt;BlogEntry&lt;/span&gt;.class), 
  observable(selected, &amp;quot;content&amp;quot;, &lt;span class=&quot;Keyword&quot;&gt;BlogEntry&lt;/span&gt;.class)
);
&lt;/pre&gt;&lt;/div&gt;&lt;h3&gt;Observable to HasValue&lt;/h3&gt;
&lt;div class=&quot;uv&quot;&gt;&lt;pre class=&quot;lazy&quot;&gt;
bindings.bind(
  &lt;span class=&quot;Entity&quot;&gt;observable&lt;/span&gt;(model, &amp;quot;key&amp;quot;, &lt;span class=&quot;Support&quot;&gt;String&lt;/span&gt;.class), 
  hasText(view.key())
);

&lt;span class=&quot;Comment&quot;&gt;&lt;span class=&quot;Comment&quot;&gt;//&lt;/span&gt; transformer is required because binding target types differ&lt;/span&gt;
&lt;span class=&quot;Comment&quot;&gt;&lt;span class=&quot;Comment&quot;&gt;//&lt;/span&gt; otherwide the code won't compile&lt;/span&gt;
bindings.bind(
  observable(model, &amp;quot;status&amp;quot;, &lt;span class=&quot;Support&quot;&gt;Integer&lt;/span&gt;.class), 
  hasText(view.status()), 
  new StatusToStringArrayTransformer()
);
&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;&lt;code&gt;&quot;bindings&quot;&lt;/code&gt; variable is instance of &lt;code&gt;Bindings&lt;/code&gt; which allows to &lt;code&gt;create&lt;/code&gt; and &lt;code&gt;bind&lt;/code&gt; new bindings (and store them in &lt;code&gt;DeferredCollection&lt;/code&gt; which allows concurrent modifications by deferring adds, removes, clear after iterator has finished) and &lt;code&gt;unbind&lt;/code&gt; them with one &lt;code&gt;bindings.clear()&lt;/code&gt; call.&lt;/p&gt;
&lt;p&gt;The binding itself is created like this:&lt;/p&gt;
&lt;div class=&quot;uv&quot;&gt;&lt;pre class=&quot;lazy&quot;&gt;
&lt;span class=&quot;Support&quot;&gt;Binding&lt;/span&gt;&lt;span class=&quot;Keyword&quot;&gt;&amp;lt;&lt;/span&gt;L, R&lt;span class=&quot;Keyword&quot;&gt;&amp;gt;&lt;/span&gt; binding = &lt;span class=&quot;Keyword&quot;&gt;new&lt;/span&gt; &lt;span class=&quot;Support&quot;&gt;Binding&lt;/span&gt;&lt;span class=&quot;Keyword&quot;&gt;&amp;lt;&lt;/span&gt;L, R&lt;span class=&quot;Keyword&quot;&gt;&amp;gt;&lt;/span&gt;(left, right, transformer);
binding.bind();
&lt;span class=&quot;Comment&quot;&gt;&lt;span class=&quot;Comment&quot;&gt;//&lt;/span&gt; ...&lt;/span&gt;
binding.unbind();
&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;&lt;code&gt;Bindings&lt;/code&gt; and &lt;code&gt;Binding&lt;/code&gt; by themselselves doesn&amp;#8217;t require &lt;code&gt;GWT.create&lt;/code&gt; at least now but &lt;code&gt;ObservableTarget&lt;/code&gt; needs &lt;code&gt;Observable&lt;/code&gt; of course.&lt;/p&gt;
&lt;h2&gt;Forwarding&lt;/h2&gt;
&lt;p&gt;The last low-level tool is &lt;code&gt;Forwarding&lt;/code&gt; which is &lt;code&gt;Observable&lt;/code&gt; proxy object that represents other &lt;code&gt;Observable&lt;/code&gt; object while trying to be invisible for its clients. This is sometimes needed for current &lt;code&gt;DataSource&lt;/code&gt; API implementation and I think this won&amp;#8217;t change.&lt;/p&gt;
&lt;p&gt;To create &lt;code&gt;Model&lt;/code&gt; (&lt;code&gt;Observable&lt;/code&gt;) and it&amp;#8217;s &lt;code&gt;Forwarding&lt;/code&gt; instance we start with 2 classes. &lt;code&gt;GWT.create&lt;/code&gt; doesn&amp;#8217;t take parameters so &lt;code&gt;Forwarding&lt;/code&gt; must be additional class (or better yet interface. But for now it is class.)&lt;/p&gt;
&lt;div class=&quot;uv&quot;&gt;&lt;pre class=&quot;lazy&quot;&gt;
&lt;span class=&quot;Keyword&quot;&gt;public &lt;/span&gt;&lt;span class=&quot;Keyword&quot;&gt;class&lt;/span&gt; &lt;span class=&quot;Entity&quot;&gt;BlogEntry&lt;/span&gt; &lt;span class=&quot;Keyword&quot;&gt;implements&lt;/span&gt; &lt;span class=&quot;Keyword&quot;&gt;IsModel&lt;/span&gt; {
  
  &lt;span class=&quot;Support&quot;&gt;String&lt;/span&gt; title;
  
  &lt;span class=&quot;Keyword&quot;&gt;public &lt;/span&gt;&lt;span class=&quot;Keyword&quot;&gt;String&lt;/span&gt; &lt;span class=&quot;Entity&quot;&gt;getTitle&lt;/span&gt;() {
    &lt;span class=&quot;Keyword&quot;&gt;return&lt;/span&gt; title;
  }
  
  &lt;span class=&quot;Keyword&quot;&gt;public &lt;/span&gt;&lt;span class=&quot;Keyword&quot;&gt;void&lt;/span&gt; &lt;span class=&quot;Entity&quot;&gt;setTitle&lt;/span&gt;(&lt;span class=&quot;Support&quot;&gt;String&lt;/span&gt; title) {
    &lt;span class=&quot;Variable&quot;&gt;this&lt;/span&gt;.title = title;
  }
  
}

&lt;span class=&quot;Keyword&quot;&gt;public &lt;/span&gt;&lt;span class=&quot;Keyword&quot;&gt;class&lt;/span&gt; &lt;span class=&quot;Entity&quot;&gt;BlogEntryForwarding&lt;/span&gt; &lt;span class=&quot;Keyword&quot;&gt;extends&lt;/span&gt; &lt;span class=&quot;Keyword&quot;&gt;BlogEntry&lt;/span&gt; &lt;span class=&quot;Keyword&quot;&gt;implements&lt;/span&gt; &lt;span class=&quot;Keyword&quot;&gt;IsModel&lt;/span&gt;, &lt;span class=&quot;Keyword&quot;&gt;IsForwarding&lt;/span&gt; {
}
&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;Now we can &lt;code&gt;GWT.create&lt;/code&gt; them and use:&lt;/p&gt;
&lt;div class=&quot;uv&quot;&gt;&lt;pre class=&quot;lazy&quot;&gt;
&lt;span class=&quot;Keyword&quot;&gt;BlogEntry&lt;/span&gt; model = &lt;span class=&quot;Constant&quot;&gt;GWT&lt;/span&gt;.create(&lt;span class=&quot;Keyword&quot;&gt;BlogEntry&lt;/span&gt;.&lt;span class=&quot;Keyword&quot;&gt;class&lt;/span&gt;);

&lt;span class=&quot;Keyword&quot;&gt;BlogEntry&lt;/span&gt; proxy = &lt;span class=&quot;Constant&quot;&gt;GWT&lt;/span&gt;.create(&lt;span class=&quot;Keyword&quot;&gt;BlogEntryForwarding&lt;/span&gt;.&lt;span class=&quot;Keyword&quot;&gt;class&lt;/span&gt;);
&lt;span class=&quot;Comment&quot;&gt;&lt;span class=&quot;Comment&quot;&gt;//&lt;/span&gt; asForwarding is just &amp;quot;safe&amp;quot; cast to Forwarding w/ assert&lt;/span&gt;

&lt;span class=&quot;Keyword&quot;&gt;Forwarding&lt;/span&gt; proxyForwarding = &lt;span class=&quot;Keyword&quot;&gt;Forwardings&lt;/span&gt;.asForwarding(proxy);
proxyForwarding.setForwardingTarget(model);

&lt;span class=&quot;Comment&quot;&gt;&lt;span class=&quot;Comment&quot;&gt;//&lt;/span&gt; the same for model observers (except setForwardingTarget change)&lt;/span&gt;
&lt;span class=&quot;Keyword&quot;&gt;Observables&lt;/span&gt;.asReflection(proxy).observe(&lt;span class=&quot;String&quot;&gt;&lt;span class=&quot;String&quot;&gt;&amp;quot;&lt;/span&gt;title&lt;span class=&quot;String&quot;&gt;&amp;quot;&lt;/span&gt;&lt;/span&gt;, &lt;span class=&quot;Support&quot;&gt;String&lt;/span&gt;.&lt;span class=&quot;Keyword&quot;&gt;class&lt;/span&gt;, &lt;span class=&quot;Keyword&quot;&gt;new&lt;/span&gt; &lt;span class=&quot;Support&quot;&gt;Observer&lt;/span&gt;&lt;span class=&quot;Keyword&quot;&gt;&amp;lt;&lt;/span&gt;&lt;span class=&quot;Support&quot;&gt;String&lt;/span&gt;&lt;span class=&quot;Keyword&quot;&gt;&amp;gt;&lt;/span&gt;(){
  &lt;span class=&quot;Keyword&quot;&gt;void&lt;/span&gt; &lt;span class=&quot;Entity&quot;&gt;onValueChange&lt;/span&gt;(&lt;span class=&quot;Keyword&quot;&gt;KeyPath&lt;/span&gt; keyPath, &lt;span class=&quot;Support&quot;&gt;Operation&lt;/span&gt; operation, &lt;span class=&quot;Keyword&quot;&gt;IndexSet&lt;/span&gt; indexes, 
                     T oldValue, T newValue) {
                    
    &lt;span class=&quot;Comment&quot;&gt;&lt;span class=&quot;Comment&quot;&gt;//&lt;/span&gt; 1st property change&lt;/span&gt;
    assertEquals(&lt;span class=&quot;Constant&quot;&gt;null&lt;/span&gt;,       oldValue);
    assertEquals(&lt;span class=&quot;String&quot;&gt;&lt;span class=&quot;String&quot;&gt;&amp;quot;&lt;/span&gt;Title #1&lt;span class=&quot;String&quot;&gt;&amp;quot;&lt;/span&gt;&lt;/span&gt;, newValue);
    
    &lt;span class=&quot;Comment&quot;&gt;&lt;span class=&quot;Comment&quot;&gt;//&lt;/span&gt; 2nd property change&lt;/span&gt;
    assertEquals(&lt;span class=&quot;String&quot;&gt;&lt;span class=&quot;String&quot;&gt;&amp;quot;&lt;/span&gt;Title #1&lt;span class=&quot;String&quot;&gt;&amp;quot;&lt;/span&gt;&lt;/span&gt;, oldValue);    
    assertEquals(&lt;span class=&quot;String&quot;&gt;&lt;span class=&quot;String&quot;&gt;&amp;quot;&lt;/span&gt;Title #2&lt;span class=&quot;String&quot;&gt;&amp;quot;&lt;/span&gt;&lt;/span&gt;, newValue);
    
    &lt;span class=&quot;Comment&quot;&gt;&lt;span class=&quot;Comment&quot;&gt;//&lt;/span&gt; result of setForwardingTarget. Old model is _not_ notified about this change obviosly&lt;/span&gt;
    assertEquals(&lt;span class=&quot;String&quot;&gt;&lt;span class=&quot;String&quot;&gt;&amp;quot;&lt;/span&gt;Title #2&lt;span class=&quot;String&quot;&gt;&amp;quot;&lt;/span&gt;&lt;/span&gt;, oldValue);
    assertEquals(&lt;span class=&quot;String&quot;&gt;&lt;span class=&quot;String&quot;&gt;&amp;quot;&lt;/span&gt;New Title&lt;span class=&quot;String&quot;&gt;&amp;quot;&lt;/span&gt;&lt;/span&gt;, newValue);
  }
});

&lt;span class=&quot;Comment&quot;&gt;&lt;span class=&quot;Comment&quot;&gt;//&lt;/span&gt; model property change&lt;/span&gt;

model.setTitle(&lt;span class=&quot;String&quot;&gt;&lt;span class=&quot;String&quot;&gt;&amp;quot;&lt;/span&gt;Title #1&lt;span class=&quot;String&quot;&gt;&amp;quot;&lt;/span&gt;&lt;/span&gt;);
assertEquals(&lt;span class=&quot;String&quot;&gt;&lt;span class=&quot;String&quot;&gt;&amp;quot;&lt;/span&gt;Title #1&lt;span class=&quot;String&quot;&gt;&amp;quot;&lt;/span&gt;&lt;/span&gt;, proxy.getTitle());

&lt;span class=&quot;Comment&quot;&gt;&lt;span class=&quot;Comment&quot;&gt;//&lt;/span&gt; proxy property change&lt;/span&gt;

proxy.setTitle(&lt;span class=&quot;String&quot;&gt;&lt;span class=&quot;String&quot;&gt;&amp;quot;&lt;/span&gt;Title #2&lt;span class=&quot;String&quot;&gt;&amp;quot;&lt;/span&gt;&lt;/span&gt;);
assertEquals(&lt;span class=&quot;String&quot;&gt;&lt;span class=&quot;String&quot;&gt;&amp;quot;&lt;/span&gt;Title #2&lt;span class=&quot;String&quot;&gt;&amp;quot;&lt;/span&gt;&lt;/span&gt;, model.getTitle());

&lt;span class=&quot;Comment&quot;&gt;&lt;span class=&quot;Comment&quot;&gt;//&lt;/span&gt; proxy target change&lt;/span&gt;

&lt;span class=&quot;Keyword&quot;&gt;BlogEntry&lt;/span&gt; newModel = &lt;span class=&quot;Constant&quot;&gt;GWT&lt;/span&gt;.create(&lt;span class=&quot;Keyword&quot;&gt;BlogEntry&lt;/span&gt;.&lt;span class=&quot;Keyword&quot;&gt;class&lt;/span&gt;);
newModel.setTitle(&lt;span class=&quot;String&quot;&gt;&lt;span class=&quot;String&quot;&gt;&amp;quot;&lt;/span&gt;New Title&lt;span class=&quot;String&quot;&gt;&amp;quot;&lt;/span&gt;&lt;/span&gt;);

proxyForwarding.setForwardingTarget(newModel);
&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;And that&amp;#8217;s it. We can move on to Model Controllers.&lt;/p&gt;
&lt;h2&gt;Model Controllers&lt;/h2&gt;
&lt;p&gt;Before we talk about &lt;code&gt;Model&lt;/code&gt; controllers I need to draw a distinction between &lt;code&gt;Observable&lt;/code&gt; and &lt;code&gt;Model&lt;/code&gt;. First &lt;code&gt;Model&lt;/code&gt; is &lt;code&gt;Observable&lt;/code&gt;, second it has &lt;code&gt;status&lt;/code&gt; represented as &lt;code&gt;int&lt;/code&gt; bitfield (yes, not &lt;code&gt;EnumSet&lt;/code&gt; or whatever. This I&amp;#8217;m almost certain should be called premature optimization). Status is observable property.&lt;/p&gt;
&lt;p&gt;Ok, finally model controllers.&lt;/p&gt;
&lt;p&gt;Now API has 2 (really badly implemented) &lt;code&gt;ModelControllers&lt;/code&gt;:&lt;/p&gt;
&lt;ul&gt;
	&lt;li&gt;&lt;code&gt;ListController&lt;/code&gt;&lt;/li&gt;
	&lt;li&gt;&lt;code&gt;ObjectController&lt;/code&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;Both should be created using &lt;code&gt;GWT.create&lt;/code&gt; to enable observation support for them.&lt;/p&gt;
&lt;p&gt;&lt;code&gt;ListController&lt;/code&gt; has &amp;#8220;&lt;code&gt;content&lt;/code&gt;&amp;#8221; and &amp;#8220;&lt;code&gt;selection&lt;/code&gt;&amp;#8221; (only single selection currently). Both properties are observable, both publicly available. When &lt;code&gt;ListController&lt;/code&gt; &lt;code&gt;content&lt;/code&gt; changes, &lt;code&gt;selection&lt;/code&gt; is set to null.&lt;/p&gt;
&lt;p&gt;&lt;code&gt;ObjectController&lt;/code&gt; has observable &amp;#8220;&lt;code&gt;content&lt;/code&gt;&amp;#8221; property.&lt;/p&gt;
&lt;div class=&quot;uv&quot;&gt;&lt;pre class=&quot;lazy&quot;&gt;
&lt;span class=&quot;Comment&quot;&gt;&lt;span class=&quot;Comment&quot;&gt;//&lt;/span&gt; bind ListController.selection to ObjectController.content&lt;/span&gt;
bindings.bind(observable(list, &lt;span class=&quot;String&quot;&gt;&lt;span class=&quot;String&quot;&gt;&amp;quot;&lt;/span&gt;selection&lt;span class=&quot;String&quot;&gt;&amp;quot;&lt;/span&gt;&lt;/span&gt;, &lt;span class=&quot;Keyword&quot;&gt;BlogEntry&lt;/span&gt;.&lt;span class=&quot;Keyword&quot;&gt;class&lt;/span&gt;), observable(selected, &lt;span class=&quot;String&quot;&gt;&lt;span class=&quot;String&quot;&gt;&amp;quot;&lt;/span&gt;content&lt;span class=&quot;String&quot;&gt;&amp;quot;&lt;/span&gt;&lt;/span&gt;, &lt;span class=&quot;Keyword&quot;&gt;BlogEntry&lt;/span&gt;.&lt;span class=&quot;Keyword&quot;&gt;class&lt;/span&gt;));

&lt;span class=&quot;Comment&quot;&gt;&lt;span class=&quot;Comment&quot;&gt;//&lt;/span&gt; observe ObjectController.content changes&lt;/span&gt;
&lt;span class=&quot;Entity&quot;&gt;asReflection&lt;/span&gt;(selected).observe(&amp;quot;content&amp;quot;, &lt;span class=&quot;Keyword&quot;&gt;BlogEntry&lt;/span&gt;.class, new &lt;span class=&quot;Support&quot;&gt;Observer&lt;/span&gt;&amp;lt;&lt;span class=&quot;Keyword&quot;&gt;BlogEntry&lt;/span&gt;&amp;gt;() {
  &lt;span class=&quot;Keyword&quot;&gt;public &lt;/span&gt;&lt;span class=&quot;Keyword&quot;&gt;void&lt;/span&gt; &lt;span class=&quot;Entity&quot;&gt;onValueChange&lt;/span&gt;(&lt;span class=&quot;Keyword&quot;&gt;KeyPath&lt;/span&gt; keyPath, &lt;span class=&quot;Support&quot;&gt;Operation&lt;/span&gt; operation, &lt;span class=&quot;Keyword&quot;&gt;IndexSet&lt;/span&gt; indexes, 
                            &lt;span class=&quot;Keyword&quot;&gt;BlogEntry&lt;/span&gt; oldValue, &lt;span class=&quot;Keyword&quot;&gt;BlogEntry&lt;/span&gt; newValue) {

    &lt;span class=&quot;Keyword&quot;&gt;if&lt;/span&gt; (newValue &lt;span class=&quot;Keyword&quot;&gt;!=&lt;/span&gt; &lt;span class=&quot;Constant&quot;&gt;null&lt;/span&gt;)
      ds.fetchDetails(newValue);
  }
});
&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;Also both controllers allows &lt;code&gt;Presenters&lt;/code&gt; (or whatever else) to add itself as &lt;code&gt;Target&lt;/code&gt;. List controller target has callbacks to:&lt;/p&gt;
&lt;ul&gt;
	&lt;li&gt;&lt;code&gt;clear&lt;/code&gt; – called when list is cleared (maybe speeds up DOM modifications, haven&amp;#8217;t checked)&lt;/li&gt;
	&lt;li&gt;&lt;code&gt;create&lt;/code&gt; – called when Widget for new list controller entry should be created. It is passed to bind afterwards&lt;/li&gt;
	&lt;li&gt;&lt;code&gt;bind&lt;/code&gt; – called when Widget needs to be rebound to new entry (only bound, no rebinding yet)&lt;/li&gt;
	&lt;li&gt;&lt;code&gt;remove&lt;/code&gt;, &lt;code&gt;insert&lt;/code&gt; and other things not exposed yet&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;Here is one &lt;code&gt;ListController&lt;/code&gt; to UI &lt;code&gt;Target&lt;/code&gt; implementation (declared in &lt;code&gt;Presenter&lt;/code&gt;):&lt;/p&gt;
&lt;div class=&quot;uv&quot;&gt;&lt;pre class=&quot;lazy&quot;&gt;
blogEntries.addTarget(&lt;span class=&quot;Keyword&quot;&gt;new&lt;/span&gt; &lt;span class=&quot;Keyword&quot;&gt;ListControllerTarget&lt;/span&gt;&lt;span class=&quot;Keyword&quot;&gt;&amp;lt;&lt;/span&gt;&lt;span class=&quot;Keyword&quot;&gt;BlogEntry&lt;/span&gt;, &lt;span class=&quot;Keyword&quot;&gt;BlogEntryListView&lt;/span&gt;&lt;span class=&quot;Keyword&quot;&gt;&amp;gt;&lt;/span&gt;() {

  &lt;span class=&quot;Keyword&quot;&gt;public &lt;/span&gt;&lt;span class=&quot;Keyword&quot;&gt;void&lt;/span&gt; &lt;span class=&quot;Entity&quot;&gt;clear&lt;/span&gt;() {
    view.clearListEntries();
  }

  &lt;span class=&quot;Keyword&quot;&gt;public &lt;/span&gt;&lt;span class=&quot;Keyword&quot;&gt;BlogEntryListView&lt;/span&gt; &lt;span class=&quot;Entity&quot;&gt;create&lt;/span&gt;() {
    &lt;span class=&quot;Keyword&quot;&gt;return&lt;/span&gt; view.addListEntry();
  }

  &lt;span class=&quot;Keyword&quot;&gt;public &lt;/span&gt;&lt;span class=&quot;Keyword&quot;&gt;void&lt;/span&gt; &lt;span class=&quot;Entity&quot;&gt;bind&lt;/span&gt;(&lt;span class=&quot;Keyword&quot;&gt;Bindings&lt;/span&gt; bindings, &lt;span class=&quot;Keyword&quot;&gt;BlogEntry&lt;/span&gt; model, &lt;span class=&quot;Keyword&quot;&gt;BlogEntryListView&lt;/span&gt; entry) {

    bindings.bind(
      &lt;span class=&quot;Entity&quot;&gt;observable&lt;/span&gt;(model, &amp;quot;title&amp;quot;, &lt;span class=&quot;Support&quot;&gt;String&lt;/span&gt;.class), 
      hasText(entry.subject())
    );
    
    bindings.bind(
      observable(model, &amp;quot;published&amp;quot;, &lt;span class=&quot;Support&quot;&gt;Boolean&lt;/span&gt;.class), 
      hasText(entry.marker()), 
      new BooleanToPublishedStatusTransformer()
    );

    &lt;span class=&quot;Comment&quot;&gt;&lt;span class=&quot;Comment&quot;&gt;//&lt;/span&gt; when rebind will be supported, HandlerRegistration will be managed by ListController&lt;/span&gt;
    entry.selectionClickHandlers().addClickHandler(new &lt;span class=&quot;Keyword&quot;&gt;ClickHandler&lt;/span&gt;() {
      &lt;span class=&quot;Keyword&quot;&gt;public &lt;/span&gt;&lt;span class=&quot;Keyword&quot;&gt;void&lt;/span&gt; &lt;span class=&quot;Entity&quot;&gt;onClick&lt;/span&gt;(&lt;span class=&quot;Keyword&quot;&gt;ClickEvent&lt;/span&gt; clickEvent) {
        &lt;span class=&quot;Keyword&quot;&gt;if&lt;/span&gt; (view &lt;span class=&quot;Keyword&quot;&gt;!=&lt;/span&gt; &lt;span class=&quot;Constant&quot;&gt;null&lt;/span&gt;) {
          &lt;span class=&quot;Keyword&quot;&gt;int&lt;/span&gt; index = view.getListEntryIndex(clickEvent);
          blogEntries.setSelection(index);
        }
      }
    });
  }
});
&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;&lt;code&gt;hasText&lt;/code&gt; is statically imported method which asks &lt;code&gt;HasText&lt;/code&gt; and returns &lt;code&gt;HasTextTarget&lt;/code&gt;.&lt;/p&gt;
&lt;p&gt;While this &lt;code&gt;ListControllerTarget&lt;/code&gt; interface is too specific for controller-view binding it suffices for now.&lt;/p&gt;
&lt;p&gt;From example we can see how easy is to bind to list entries and how terrible current bindings api look. For Model-* related bindings I&amp;#8217;m planning to implement easier to use and reuse API. See below.&lt;/p&gt;
&lt;p&gt;&lt;code&gt;ObjectController&lt;/code&gt; &lt;code&gt;Target&lt;/code&gt; interface is similar:&lt;/p&gt;
&lt;div class=&quot;uv&quot;&gt;&lt;pre class=&quot;lazy&quot;&gt;
registration = selection.addTarget(&lt;span class=&quot;Keyword&quot;&gt;new&lt;/span&gt; &lt;span class=&quot;Keyword&quot;&gt;ObjectControllerTarget&lt;/span&gt;&lt;span class=&quot;Keyword&quot;&gt;&amp;lt;&lt;/span&gt;&lt;span class=&quot;Keyword&quot;&gt;BlogEntry&lt;/span&gt;&lt;span class=&quot;Keyword&quot;&gt;&amp;gt;&lt;/span&gt;() {
  &lt;span class=&quot;Keyword&quot;&gt;public &lt;/span&gt;&lt;span class=&quot;Keyword&quot;&gt;void&lt;/span&gt; &lt;span class=&quot;Entity&quot;&gt;bind&lt;/span&gt;(&lt;span class=&quot;Keyword&quot;&gt;Bindings&lt;/span&gt; bindings, final &lt;span class=&quot;Keyword&quot;&gt;BlogEntry&lt;/span&gt; model) {

    &lt;span class=&quot;Comment&quot;&gt;&lt;span class=&quot;Comment&quot;&gt;//&lt;/span&gt; general info&lt;/span&gt;

    bindings.bind(
      &lt;span class=&quot;Entity&quot;&gt;observable&lt;/span&gt;(model, &amp;quot;key&amp;quot;, &lt;span class=&quot;Support&quot;&gt;String&lt;/span&gt;.class), 
      hasText(view.key())
    );
    
    bindings.bind(
      observable(model, &amp;quot;status&amp;quot;, &lt;span class=&quot;Support&quot;&gt;Integer&lt;/span&gt;.class), 
      hasText(view.status()), 
      new StatusToStringArrayTransformer()
    );
    
    bindings.bind(
      observable(model, &amp;quot;title&amp;quot;, &lt;span class=&quot;Support&quot;&gt;String&lt;/span&gt;.class), 
      hasText(view.title())
    );

    &lt;span class=&quot;Comment&quot;&gt;&lt;span class=&quot;Comment&quot;&gt;//&lt;/span&gt; &lt;/span&gt;
    bindings.bind(
      observable(model, &amp;quot;hasDetails&amp;quot;, &lt;span class=&quot;Support&quot;&gt;Boolean&lt;/span&gt;.class), 
      hasBoolean(view.showDetails())
    );
      
    &lt;span class=&quot;Comment&quot;&gt;&lt;span class=&quot;Comment&quot;&gt;//&lt;/span&gt; details&lt;/span&gt;

    bindings.bind(
      observable(model, &amp;quot;body&amp;quot;, &lt;span class=&quot;Support&quot;&gt;String&lt;/span&gt;.class), 
      hasText(view.body())
    );
    
    bindings.bind(
      observable(model, &amp;quot;created&amp;quot;, &lt;span class=&quot;Support&quot;&gt;Date&lt;/span&gt;.class), 
      hasText(view.created()), 
      new DateToStringTransformer()
    );
    
    bindings.bind(
      observable(model, &amp;quot;published&amp;quot;, &lt;span class=&quot;Support&quot;&gt;Boolean&lt;/span&gt;.class), 
      hasText(view.published()), 
      new BooleanToPublishedStatusTransformer()
    );
    
  }
});
&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;Called when &amp;#8220;&lt;code&gt;content&lt;/code&gt;&amp;#8221; is changed. &lt;code&gt;null&lt;/code&gt; value will have separate callback also &lt;code&gt;create&lt;/code&gt; callback will be here to support switching UI from &lt;code&gt;null&lt;/code&gt; placeholder to actual view.&lt;/p&gt;
&lt;p&gt;For general &lt;code&gt;Target&lt;/code&gt; API &amp;#8212; specific user &lt;code&gt;Target&lt;/code&gt; API I&amp;#8217;m thinking of something along those lines:&lt;/p&gt;
&lt;div class=&quot;uv&quot;&gt;&lt;pre class=&quot;lazy&quot;&gt;
registration = selection.addTarget(simpleBindableTarget(&lt;span class=&quot;Keyword&quot;&gt;new&lt;/span&gt; &lt;span class=&quot;Keyword&quot;&gt;SimpleBindableTarget&lt;/span&gt;&lt;span class=&quot;Keyword&quot;&gt;&amp;lt;&lt;/span&gt;&lt;span class=&quot;Keyword&quot;&gt;BlogEntry&lt;/span&gt;(){
  &lt;span class=&quot;Keyword&quot;&gt;public &lt;/span&gt;&lt;span class=&quot;Keyword&quot;&gt;void&lt;/span&gt; &lt;span class=&quot;Entity&quot;&gt;onBind&lt;/span&gt;(&lt;span class=&quot;Keyword&quot;&gt;Bindings&lt;/span&gt; bindings, &lt;span class=&quot;Keyword&quot;&gt;BlogEntry&lt;/span&gt; model) {
    &lt;span class=&quot;Comment&quot;&gt;&lt;span class=&quot;Comment&quot;&gt;//&lt;/span&gt;/ ...&lt;/span&gt;
  }
}));
&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;where &lt;code&gt;simpleBindableTarget&lt;/code&gt; is statically imported method that takes simplified, more targeted to usage interface and implements general &lt;code&gt;ObjectControllerTarget&lt;/code&gt;.&lt;/p&gt;
&lt;p&gt;The other approach would be just using &lt;code&gt;ObjectController&lt;/code&gt; observation directly (still by using some &lt;code&gt;simpleBindableTarget&lt;/code&gt; as a helper) and to bind UI against &lt;code&gt;ObjectController&lt;/code&gt; itself (which would forward events to and from its &lt;code&gt;content&lt;/code&gt;). Not yet decided.&lt;/p&gt;
&lt;p&gt;So far we have observable models and controllers that helps to map model graph and selection to UI components. Now I&amp;#8217;ll try to describe &lt;code&gt;DataSource&lt;/code&gt; and Model state.&lt;/p&gt;
&lt;h2&gt;DataSource&lt;/h2&gt;
&lt;p&gt;As stated previously, &lt;code&gt;Model&lt;/code&gt; has &lt;code&gt;state&lt;/code&gt; integer. It has the following values:&lt;/p&gt;
&lt;div class=&quot;uv&quot;&gt;&lt;pre class=&quot;lazy&quot;&gt;
&lt;span class=&quot;Keyword&quot;&gt;int&lt;/span&gt; &lt;span class=&quot;Constant&quot;&gt;READY&lt;/span&gt; = &lt;span class=&quot;Constant&quot;&gt;1&lt;/span&gt; &lt;span class=&quot;Keyword&quot;&gt;&amp;lt;&lt;/span&gt;&lt;span class=&quot;Keyword&quot;&gt;&amp;lt;&lt;/span&gt; &lt;span class=&quot;Constant&quot;&gt;1&lt;/span&gt;;
&lt;span class=&quot;Keyword&quot;&gt;int&lt;/span&gt; &lt;span class=&quot;Constant&quot;&gt;DIRTY&lt;/span&gt; = &lt;span class=&quot;Constant&quot;&gt;1&lt;/span&gt; &lt;span class=&quot;Keyword&quot;&gt;&amp;lt;&lt;/span&gt;&lt;span class=&quot;Keyword&quot;&gt;&amp;lt;&lt;/span&gt; &lt;span class=&quot;Constant&quot;&gt;2&lt;/span&gt;;
&lt;span class=&quot;Keyword&quot;&gt;int&lt;/span&gt; &lt;span class=&quot;Constant&quot;&gt;BUSY&lt;/span&gt; = &lt;span class=&quot;Constant&quot;&gt;1&lt;/span&gt; &lt;span class=&quot;Keyword&quot;&gt;&amp;lt;&lt;/span&gt;&lt;span class=&quot;Keyword&quot;&gt;&amp;lt;&lt;/span&gt; &lt;span class=&quot;Constant&quot;&gt;3&lt;/span&gt;;
&lt;span class=&quot;Keyword&quot;&gt;int&lt;/span&gt; &lt;span class=&quot;Constant&quot;&gt;ERROR&lt;/span&gt; = &lt;span class=&quot;Constant&quot;&gt;1&lt;/span&gt; &lt;span class=&quot;Keyword&quot;&gt;&amp;lt;&lt;/span&gt;&lt;span class=&quot;Keyword&quot;&gt;&amp;lt;&lt;/span&gt; &lt;span class=&quot;Constant&quot;&gt;4&lt;/span&gt;;

&lt;span class=&quot;Keyword&quot;&gt;int&lt;/span&gt; &lt;span class=&quot;Constant&quot;&gt;LOADING&lt;/span&gt; = &lt;span class=&quot;Constant&quot;&gt;1&lt;/span&gt; &lt;span class=&quot;Keyword&quot;&gt;&amp;lt;&lt;/span&gt;&lt;span class=&quot;Keyword&quot;&gt;&amp;lt;&lt;/span&gt; &lt;span class=&quot;Constant&quot;&gt;5&lt;/span&gt;;
&lt;span class=&quot;Keyword&quot;&gt;int&lt;/span&gt; &lt;span class=&quot;Constant&quot;&gt;SAVING&lt;/span&gt; = &lt;span class=&quot;Constant&quot;&gt;1&lt;/span&gt; &lt;span class=&quot;Keyword&quot;&gt;&amp;lt;&lt;/span&gt;&lt;span class=&quot;Keyword&quot;&gt;&amp;lt;&lt;/span&gt; &lt;span class=&quot;Constant&quot;&gt;6&lt;/span&gt;;
&lt;span class=&quot;Keyword&quot;&gt;int&lt;/span&gt; &lt;span class=&quot;Constant&quot;&gt;DESTROYING&lt;/span&gt; = &lt;span class=&quot;Constant&quot;&gt;1&lt;/span&gt; &lt;span class=&quot;Keyword&quot;&gt;&amp;lt;&lt;/span&gt;&lt;span class=&quot;Keyword&quot;&gt;&amp;lt;&lt;/span&gt; &lt;span class=&quot;Constant&quot;&gt;7&lt;/span&gt;;
&lt;span class=&quot;Keyword&quot;&gt;int&lt;/span&gt; &lt;span class=&quot;Constant&quot;&gt;REFRESHING&lt;/span&gt; = &lt;span class=&quot;Constant&quot;&gt;1&lt;/span&gt; &lt;span class=&quot;Keyword&quot;&gt;&amp;lt;&lt;/span&gt;&lt;span class=&quot;Keyword&quot;&gt;&amp;lt;&lt;/span&gt; &lt;span class=&quot;Constant&quot;&gt;8&lt;/span&gt;;

&lt;span class=&quot;Keyword&quot;&gt;int&lt;/span&gt; &lt;span class=&quot;Constant&quot;&gt;NEW&lt;/span&gt; = &lt;span class=&quot;Constant&quot;&gt;1&lt;/span&gt; &lt;span class=&quot;Keyword&quot;&gt;&amp;lt;&lt;/span&gt;&lt;span class=&quot;Keyword&quot;&gt;&amp;lt;&lt;/span&gt; &lt;span class=&quot;Constant&quot;&gt;9&lt;/span&gt;;
&lt;span class=&quot;Keyword&quot;&gt;int&lt;/span&gt; &lt;span class=&quot;Constant&quot;&gt;DESTROYED&lt;/span&gt; = &lt;span class=&quot;Constant&quot;&gt;1&lt;/span&gt; &lt;span class=&quot;Keyword&quot;&gt;&amp;lt;&lt;/span&gt;&lt;span class=&quot;Keyword&quot;&gt;&amp;lt;&lt;/span&gt; &lt;span class=&quot;Constant&quot;&gt;10&lt;/span&gt;;
&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;When model is locally created (transient), it has &amp;#8220;&lt;code&gt;NEW | DIRTY&lt;/code&gt;&amp;#8221; state, when it is currently loading from &lt;code&gt;DataSource&lt;/code&gt; (&lt;code&gt;async&lt;/code&gt;), the state is set to &amp;#8220;&lt;code&gt;BUSY | LOADING&lt;/code&gt;&amp;#8221;. The state is observable, so view can show &amp;#8220;Please wait&amp;#8221; while loading, refreshing or deleting model objects.&lt;/p&gt;
&lt;p&gt;&lt;code&gt;DataSource&lt;/code&gt; has a bit different approach managing asynchronous operations. Basically all &lt;code&gt;DataSource&lt;/code&gt; methods are seemingly synchronous. Lets look how the list fetching happens:&lt;/p&gt;
&lt;div class=&quot;uv&quot;&gt;&lt;pre class=&quot;lazy&quot;&gt;
&lt;span class=&quot;Keyword&quot;&gt;public &lt;/span&gt;&lt;span class=&quot;Keyword&quot;&gt;class&lt;/span&gt; &lt;span class=&quot;Entity&quot;&gt;BlogEntryDataSource&lt;/span&gt; &lt;span class=&quot;Keyword&quot;&gt;extends&lt;/span&gt; &lt;span class=&quot;Keyword&quot;&gt;DispatchDataSource&lt;/span&gt;&amp;lt;&lt;span class=&quot;Keyword&quot;&gt;BlogEntry&lt;/span&gt;&amp;gt; {

  &lt;span class=&quot;Keyword&quot;&gt;public &lt;/span&gt;&lt;span class=&quot;Keyword&quot;&gt;List&lt;/span&gt;&lt;span class=&quot;Keyword&quot;&gt;&amp;lt;BlogEntry&amp;gt;&lt;/span&gt; &lt;span class=&quot;Entity&quot;&gt;fetchAll&lt;/span&gt;() {
    &lt;span class=&quot;Keyword&quot;&gt;return&lt;/span&gt; fetchList(
      &lt;span class=&quot;Keyword&quot;&gt;new&lt;/span&gt; &lt;span class=&quot;Keyword&quot;&gt;GetBlogEntriesAction&lt;/span&gt;(), 
      &lt;span class=&quot;Keyword&quot;&gt;new&lt;/span&gt; &lt;span class=&quot;Keyword&quot;&gt;DispatchDataSourceCallback&lt;/span&gt;&lt;span class=&quot;Keyword&quot;&gt;&amp;lt;&lt;/span&gt;&lt;span class=&quot;Keyword&quot;&gt;GetBlogEntriesResult&lt;/span&gt;, &lt;span class=&quot;Keyword&quot;&gt;DataSourceList&lt;/span&gt;&lt;span class=&quot;Keyword&quot;&gt;&amp;lt;&lt;/span&gt;&lt;span class=&quot;Keyword&quot;&gt;BlogEntry&lt;/span&gt;&lt;span class=&quot;Keyword&quot;&gt;&amp;gt;&lt;/span&gt;&lt;span class=&quot;Keyword&quot;&gt;&amp;gt;&lt;/span&gt;() {
        &lt;span class=&quot;Keyword&quot;&gt;public &lt;/span&gt;&lt;span class=&quot;Keyword&quot;&gt;void&lt;/span&gt; &lt;span class=&quot;Entity&quot;&gt;prepare&lt;/span&gt;(&lt;span class=&quot;Keyword&quot;&gt;DataSourceList&lt;/span&gt;&amp;lt;&lt;span class=&quot;Keyword&quot;&gt;BlogEntry&lt;/span&gt;&amp;gt; model, &lt;span class=&quot;Keyword&quot;&gt;GetBlogEntriesResult&lt;/span&gt; result) {
          populateList(model, result.getEntries());
        }
      });
  }

}
&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;As we can see from previous code snippet, &lt;code&gt;fetchAll()&lt;/code&gt; returns immediately. It returns empty &lt;code&gt;ListModel&amp;lt;BlogEntry&amp;gt;&lt;/code&gt; instance which can be set as a content to some &lt;code&gt;ListController&lt;/code&gt;. Also the list implements &lt;code&gt;IsModel&lt;/code&gt; so it has &lt;code&gt;state&lt;/code&gt; property. It is set to &amp;#8220;&lt;code&gt;BUSY | LOADING&lt;/code&gt;&amp;#8221;. When asynchronous call returns, &lt;code&gt;DispatchDataSourceCallback#prepare&lt;/code&gt; is called with &lt;code&gt;Result&lt;/code&gt; (Command pattern) and the same list what method returned previously. Now its time to add entries to the list. When it happens, List &amp;#8594; ListController &amp;#8594; Presenter &amp;#8594; UI chain is invoked so new entries automatically appears in view.&lt;/p&gt;
&lt;p&gt;In similar fashion also single models are fetched:&lt;/p&gt;
&lt;div class=&quot;uv&quot;&gt;&lt;pre class=&quot;lazy&quot;&gt;
&lt;span class=&quot;Keyword&quot;&gt;public &lt;/span&gt;&lt;span class=&quot;Keyword&quot;&gt;class&lt;/span&gt; &lt;span class=&quot;Entity&quot;&gt;BlogEntryDataSource&lt;/span&gt; &lt;span class=&quot;Keyword&quot;&gt;extends&lt;/span&gt; &lt;span class=&quot;Keyword&quot;&gt;DispatchDataSource&lt;/span&gt;&amp;lt;&lt;span class=&quot;Keyword&quot;&gt;BlogEntry&lt;/span&gt;&amp;gt; {

  &lt;span class=&quot;Keyword&quot;&gt;public &lt;/span&gt;&lt;span class=&quot;Keyword&quot;&gt;BlogEntry&lt;/span&gt; &lt;span class=&quot;Entity&quot;&gt;fetchLatestEntry&lt;/span&gt;() {
    &lt;span class=&quot;Keyword&quot;&gt;return&lt;/span&gt; fetchSingle(
      &lt;span class=&quot;Keyword&quot;&gt;new&lt;/span&gt; &lt;span class=&quot;Keyword&quot;&gt;GetLatestBlogEntry&lt;/span&gt;(), 
      &lt;span class=&quot;Keyword&quot;&gt;new&lt;/span&gt; &lt;span class=&quot;Keyword&quot;&gt;DispatchDataSourceCallback&lt;/span&gt;&lt;span class=&quot;Keyword&quot;&gt;&amp;lt;&lt;/span&gt;&lt;span class=&quot;Keyword&quot;&gt;GetBlogEntryResult&lt;/span&gt;, &lt;span class=&quot;Keyword&quot;&gt;BlogEntry&lt;/span&gt;&lt;span class=&quot;Keyword&quot;&gt;&amp;gt;&lt;/span&gt;() {
        &lt;span class=&quot;Keyword&quot;&gt;public &lt;/span&gt;&lt;span class=&quot;Keyword&quot;&gt;void&lt;/span&gt; &lt;span class=&quot;Entity&quot;&gt;prepare&lt;/span&gt;(&lt;span class=&quot;Keyword&quot;&gt;BlogEntry&lt;/span&gt; model, &lt;span class=&quot;Keyword&quot;&gt;GetLatestBlogEntryResult&lt;/span&gt; result) {
          populateModel(model, result.getBlogEntry());
        }
      });
  }

}
&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;Returned &lt;code&gt;BlogEntry&lt;/code&gt; has all properties set to null and state &amp;#8220;&lt;code&gt;BUSY | LOADING&lt;/code&gt;&amp;#8221;. All would be fine but this way if &lt;code&gt;fetchLatestBlogEntry()&lt;/code&gt; is called multiple times, multiple &lt;code&gt;BlogEntry&lt;/code&gt; instances for one actual blog entry row/entity would be created. And not always unique model primary key is known prior fetching it (as in this example).&lt;/p&gt;
&lt;p&gt;So here comes small trick – instead of returning actual &lt;code&gt;BlogEntry&lt;/code&gt;, the &lt;code&gt;BlogEntryForwarding&lt;/code&gt; proxy is returned with null or dummy &lt;code&gt;BlogEntry&lt;/code&gt; as target. When async returns, &lt;code&gt;DispatchDataSourceCallback#populateModel(BlogEntry, GetLatestBlogEntryResult)&lt;/code&gt; is called and it updates &lt;code&gt;BlogEntry&lt;/code&gt; key what can be checked for uniqueness in local &lt;code&gt;DataStore&lt;/code&gt;. If model was already fetched previously, its properties are updated with new ones, &lt;code&gt;BlogEntryForwarding&lt;/code&gt; proxy target is changed to that previous model instance but latest fetched is simply discarded. This process also works for each list item fetched.&lt;/p&gt;
&lt;p&gt;Key comparison is done using &lt;code&gt;IsModel#getKey()&lt;/code&gt; method what must be implemented by each model.&lt;/p&gt;
&lt;p&gt;If model key is known prior fetching (&lt;code&gt;fetchBlogEntryByKey(String key)&lt;/code&gt;), &lt;code&gt;DataSource&lt;/code&gt; returns model instance without creating a proxy.&lt;/p&gt;
&lt;p&gt;The benefits are:&lt;/p&gt;
&lt;ul&gt;
	&lt;li&gt;zero or one model instance for each key (not counting possible proxies)&lt;/li&gt;
	&lt;li&gt;subsequent fetches will automatically notify view about updated model properties&lt;/li&gt;
	&lt;li&gt;&lt;code&gt;DataSource&lt;/code&gt; can transparently cache models&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;The things that needs to be implemented are:&lt;/p&gt;
&lt;ul&gt;
	&lt;li&gt;predicates/query names so list fetching can be cached (&amp;#8220;&lt;code&gt;fetchLatestEntry&lt;/code&gt;&amp;#8221; – &lt;code&gt;DataStore&lt;/code&gt; should know that &amp;#8220;&lt;code&gt;latestEntry&lt;/code&gt;&amp;#8221; is fetched already before fetching it and not only after fetch find out that model with given key already exists in &lt;code&gt;DataStore&lt;/code&gt;. This also applies to lists (&amp;#8220;&lt;code&gt;fetchAllEntries&lt;/code&gt;&amp;#8221; with GAE DataStore cursor or Hibernate/JDBC page number)&lt;/li&gt;
	&lt;li&gt;fetch v.s. refresh (&lt;code&gt;DataSource&lt;/code&gt; should be aware of difference)&lt;/li&gt;
&lt;/ul&gt;
&lt;h2&gt;Prettier Bindings For UI&lt;/h2&gt;
&lt;p&gt;While basic binding api can look so technical, bindings from observable/model to view should have special approach. Firstly bindings are both target type agnostic, for model-view bindings left side is always model.&lt;/p&gt;
&lt;p&gt;Previously I had model-view bindings what looks like this:&lt;/p&gt;
&lt;div class=&quot;uv&quot;&gt;&lt;pre class=&quot;lazy&quot;&gt;
binder.model(&lt;span class=&quot;Keyword&quot;&gt;User&lt;/span&gt;.&lt;span class=&quot;Keyword&quot;&gt;class&lt;/span&gt;).with(model(&lt;span class=&quot;Keyword&quot;&gt;new&lt;/span&gt; &lt;span class=&quot;Keyword&quot;&gt;ModelBuilderDelegate&lt;/span&gt;&lt;span class=&quot;Keyword&quot;&gt;&amp;lt;&lt;/span&gt;&lt;span class=&quot;Keyword&quot;&gt;User&lt;/span&gt;&lt;span class=&quot;Keyword&quot;&gt;&amp;gt;&lt;/span&gt;() {
 &lt;span class=&quot;Keyword&quot;&gt;public &lt;/span&gt;&lt;span class=&quot;Keyword&quot;&gt;void&lt;/span&gt; &lt;span class=&quot;Entity&quot;&gt;bind&lt;/span&gt;(&lt;span class=&quot;Keyword&quot;&gt;ModelBinder&lt;/span&gt;&amp;lt;&lt;span class=&quot;Keyword&quot;&gt;User&lt;/span&gt;&amp;gt; b, &lt;span class=&quot;Keyword&quot;&gt;User&lt;/span&gt; model) {

   b.property(&lt;span class=&quot;String&quot;&gt;&lt;span class=&quot;String&quot;&gt;&amp;quot;&lt;/span&gt;key&lt;span class=&quot;String&quot;&gt;&amp;quot;&lt;/span&gt;&lt;/span&gt;, &lt;span class=&quot;Support&quot;&gt;String&lt;/span&gt;.&lt;span class=&quot;Keyword&quot;&gt;class&lt;/span&gt;).
     &lt;span class=&quot;Entity&quot;&gt;to&lt;/span&gt;(hasValue(view.getKey())).
     to(hasText(view.getKeyValue()));

   b.property(&amp;quot;name&amp;quot;, &lt;span class=&quot;Support&quot;&gt;String&lt;/span&gt;.class).
     to(hasValue(view.getName())).
     to(hasText(view.getNameValue()));

   b.property(&amp;quot;login&amp;quot;, &lt;span class=&quot;Support&quot;&gt;String&lt;/span&gt;.class).
     to(hasValue(view.getLogin())).
     to(hasText(view.getLoginValue()));

   b.model(&amp;quot;address&amp;quot;, &lt;span class=&quot;Keyword&quot;&gt;Address&lt;/span&gt;.class).with(model(new &lt;span class=&quot;Keyword&quot;&gt;ModelBuilderDelegate&lt;/span&gt;&amp;lt;&lt;span class=&quot;Keyword&quot;&gt;Address&lt;/span&gt;&amp;gt;() {
     &lt;span class=&quot;Keyword&quot;&gt;public &lt;/span&gt;&lt;span class=&quot;Keyword&quot;&gt;void&lt;/span&gt; &lt;span class=&quot;Entity&quot;&gt;bind&lt;/span&gt;(&lt;span class=&quot;Keyword&quot;&gt;ModelBinder&lt;/span&gt;&amp;lt;&lt;span class=&quot;Keyword&quot;&gt;Address&lt;/span&gt;&amp;gt; b, &lt;span class=&quot;Keyword&quot;&gt;Address&lt;/span&gt; model) {

       b.property(&lt;span class=&quot;String&quot;&gt;&lt;span class=&quot;String&quot;&gt;&amp;quot;&lt;/span&gt;street&lt;span class=&quot;String&quot;&gt;&amp;quot;&lt;/span&gt;&lt;/span&gt;, &lt;span class=&quot;Support&quot;&gt;String&lt;/span&gt;.&lt;span class=&quot;Keyword&quot;&gt;class&lt;/span&gt;).
         &lt;span class=&quot;Entity&quot;&gt;to&lt;/span&gt;(hasValue(view.getStreet())).
         to(hasText(view.getStreetValue()));

       b.property(&amp;quot;country&amp;quot;, &lt;span class=&quot;Support&quot;&gt;String&lt;/span&gt;.class).
         to(hasValue(view.getCountry())).
         to(hasText(view.getCountryValue()));

       b.model(&amp;quot;details&amp;quot;, &lt;span class=&quot;Keyword&quot;&gt;Details&lt;/span&gt;.class).with(model(new &lt;span class=&quot;Keyword&quot;&gt;ModelBuilderDelegate&lt;/span&gt;&amp;lt;&lt;span class=&quot;Keyword&quot;&gt;Details&lt;/span&gt;&amp;gt;() {
         &lt;span class=&quot;Keyword&quot;&gt;public &lt;/span&gt;&lt;span class=&quot;Keyword&quot;&gt;void&lt;/span&gt; &lt;span class=&quot;Entity&quot;&gt;bind&lt;/span&gt;(&lt;span class=&quot;Keyword&quot;&gt;ModelBinder&lt;/span&gt;&amp;lt;&lt;span class=&quot;Keyword&quot;&gt;Details&lt;/span&gt;&amp;gt; b, &lt;span class=&quot;Keyword&quot;&gt;Details&lt;/span&gt; model) {

           b.property(&lt;span class=&quot;String&quot;&gt;&lt;span class=&quot;String&quot;&gt;&amp;quot;&lt;/span&gt;description&lt;span class=&quot;String&quot;&gt;&amp;quot;&lt;/span&gt;&lt;/span&gt;, &lt;span class=&quot;Support&quot;&gt;String&lt;/span&gt;.&lt;span class=&quot;Keyword&quot;&gt;class&lt;/span&gt;).
             &lt;span class=&quot;Entity&quot;&gt;to&lt;/span&gt;(hasValue(view.getAddressDescription())).
             to(hasText(view.getAddressDescriptionValue()));

         }
       }));
     }
   }));
 }
}));
&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;Now I haven&amp;#8217;t touched that code yet but here is that test form running (also with list handling): &lt;a href=&quot;http://models.latest.ampatspell-test.appspot.com/&quot;&gt;http://models.latest.ampatspell-test.appspot.com/&lt;/a&gt;&lt;/p&gt;
&lt;h2&gt;Few notes about validation&lt;/h2&gt;
&lt;p&gt;While &lt;a href=&quot;http://code.google.com/p/gwt-pectin/&quot;&gt;gwt-pectin&lt;/a&gt; and nearly all other binding frameworks also handle validation I feel that validation support should/must be separated from model-view bindings simply because it would be great to run the same validation definition in server-side. I deem it very useful. Also if validators are not instantiated directly, few validators what can not be run in GWT, can be skipped there and only run at server-side.&lt;/p&gt;
&lt;p&gt;&lt;a href=&quot;http://bitbucket.org/ampatspell/bones-validator/&quot;&gt;bones-validator&lt;/a&gt; does that (but API is far from great).&lt;/p&gt;
&lt;div class=&quot;uv&quot;&gt;&lt;pre class=&quot;lazy&quot;&gt;
&lt;span class=&quot;Keyword&quot;&gt;public &lt;/span&gt;&lt;span class=&quot;Keyword&quot;&gt;class&lt;/span&gt; &lt;span class=&quot;Entity&quot;&gt;UserValidationModule&lt;/span&gt; &lt;span class=&quot;Keyword&quot;&gt;extends&lt;/span&gt; &lt;span class=&quot;Keyword&quot;&gt;AbstractValidationModule&lt;/span&gt;&amp;lt;&lt;span class=&quot;Keyword&quot;&gt;UserDto&lt;/span&gt;&amp;gt; {

  @&lt;span class=&quot;Support&quot;&gt;Override&lt;/span&gt;
  &lt;span class=&quot;Keyword&quot;&gt;public &lt;/span&gt;&lt;span class=&quot;Keyword&quot;&gt;void&lt;/span&gt; &lt;span class=&quot;Entity&quot;&gt;prepare&lt;/span&gt;(&lt;span class=&quot;Keyword&quot;&gt;UserDto&lt;/span&gt; o) {
    field(&lt;span class=&quot;String&quot;&gt;&lt;span class=&quot;String&quot;&gt;&amp;quot;&lt;/span&gt;name&lt;span class=&quot;String&quot;&gt;&amp;quot;&lt;/span&gt;&lt;/span&gt;, o.getName()).with(&lt;span class=&quot;Keyword&quot;&gt;Unique&lt;/span&gt;.&lt;span class=&quot;Keyword&quot;&gt;class&lt;/span&gt;); &lt;span class=&quot;Comment&quot;&gt;&lt;span class=&quot;Comment&quot;&gt;//&lt;/span&gt; runs only in server side&lt;/span&gt;
    field(&lt;span class=&quot;String&quot;&gt;&lt;span class=&quot;String&quot;&gt;&amp;quot;&lt;/span&gt;name&lt;span class=&quot;String&quot;&gt;&amp;quot;&lt;/span&gt;&lt;/span&gt;, o.getName()).with(&lt;span class=&quot;Keyword&quot;&gt;NotBlank&lt;/span&gt;.&lt;span class=&quot;Keyword&quot;&gt;class&lt;/span&gt;);
    &lt;span class=&quot;Comment&quot;&gt;&lt;span class=&quot;Comment&quot;&gt;//&lt;/span&gt; allowBlank() is EmailValidator instance method call for this particular field&lt;/span&gt;
    field(&lt;span class=&quot;String&quot;&gt;&lt;span class=&quot;String&quot;&gt;&amp;quot;&lt;/span&gt;email&lt;span class=&quot;String&quot;&gt;&amp;quot;&lt;/span&gt;&lt;/span&gt;, o.getEmail()).with(&lt;span class=&quot;Keyword&quot;&gt;Email&lt;/span&gt;.&lt;span class=&quot;Keyword&quot;&gt;class&lt;/span&gt;).allowBlank();
  }

}
&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;If model-view bindings are aware of validation (if needs to be), I think it can be done while keeping bindings and validation APIs clean.&lt;/p&gt;</content>
</entry>


  <entry>
  <title>Maven Archetypes Updated</title>
  <link href="/articles/2010/02/24/maven-archetypes-updated.html" />
  <id>tag:www.amateurinmotion.com,2010-02-24:1267011121</id>
  <updated>2010-02-24T13:32:01+02:00</updated>
  <content type="html">&lt;p&gt;Just deployed latest SNAPSHOT of maven archetypes:&lt;/p&gt;
&lt;ul&gt;
	&lt;li&gt;&lt;code&gt;bones-google-quickstart-archetype&lt;/code&gt; (Google GWT &amp;amp; AppEngine Web App With Bones and Gaeds)&lt;/li&gt;
	&lt;li&gt;&lt;code&gt;google-quickstart-archetype&lt;/code&gt; (Google GWT &amp;amp; AppEngine Web App)&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;They&amp;#8217;re finally updated to latest dependencies and even compile and run.&lt;/p&gt;
&lt;p style=&quot;width: 640px; background: #888; color: #000; text-align: center; padding: 5px 10px; text-shadow: 0px 1px 0px #bbb; -webkit-border-radius: 3px&quot;&gt;mvn archetype:generate -DarchetypeCatalog=http://www.amateurinmotion.com/repository&lt;/p&gt;
&lt;p&gt;To try them out make sure you have &lt;a href=&quot;http://maven.apache.org/download.html&quot;&gt;Maven 2.2.1&lt;/a&gt; and run:&lt;/p&gt;
&lt;div class=&quot;uv&quot;&gt;&lt;pre class=&quot;lazy&quot;&gt;
$ mvn archetype:generate -DarchetypeCatalog=http://www.amateurinmotion.com/repository

...

Choose archetype:
1: http://www.amateurinmotion.com/repository -&amp;gt; google-quickstart-archetype               ↩ 
    (Google GWT &amp;amp; AppEngine Web App)
2: http://www.amateurinmotion.com/repository -&amp;gt; bones-google-quickstart-archetype         ↩
    (Google GWT &amp;amp; AppEngine Web App With Bones and Gaeds)
Choose a number:  (1/2): 2

...

Define value for groupId: : com.zeeba
Define value for artifactId: : zeeba
Define value for version:  1.0-SNAPSHOT: : 
Define value for package:  com.zeeba: : 
Confirm properties configuration:
groupId: com.zeeba
artifactId: zeeba
version: 1.0-SNAPSHOT
package: com.zeeba
 Y: : 

...

$ cd zeeba
$ mvn install # compiles GWT module, packs war ready for AppEngine deployment

...

[INFO] ------------------------------------------------------------------------
[INFO] Reactor Summary:
[INFO] ------------------------------------------------------------------------
[INFO] Bones Quickstart ...................................... SUCCESS [1.631s]
[INFO] Quickstart -- Shared .................................. SUCCESS [1.480s]
[INFO] Quickstart -- GWT ..................................... SUCCESS [30.084s]
[INFO] Quickstart -- Server .................................. SUCCESS [2.208s]
[INFO] Quickstart -- War ..................................... SUCCESS [4.255s]
[INFO] ------------------------------------------------------------------------
[INFO] ------------------------------------------------------------------------
[INFO] BUILD SUCCESSFUL
[INFO] ------------------------------------------------------------------------
[INFO] Total time: 40 seconds

...

$ cd zeeba-gwt
$ mvn google:gwt-run          # to run GWT in Development Mode

$ cd zeeba-war
$ mvn google:appengine-run    # to run AppEngine local server with compiled GWT module
&lt;/pre&gt;&lt;/div&gt;&lt;h2&gt;Deploy to AppEngine&lt;/h2&gt;
&lt;p&gt;To deploy app to AppEngine, set your login, password in &lt;code&gt;~/.m2/settings.xml&lt;/code&gt;:&lt;/p&gt;
&lt;div class=&quot;uv&quot;&gt;&lt;pre class=&quot;lazy&quot;&gt;
&lt;span class=&quot;MetaTag&quot;&gt;&lt;span class=&quot;MetaTag&quot;&gt;&amp;lt;&lt;/span&gt;&lt;span class=&quot;MetaTag&quot;&gt;settings&lt;/span&gt; &lt;span class=&quot;MetaTag&quot;&gt;xmlns&lt;/span&gt;=&lt;span class=&quot;String&quot;&gt;&lt;span class=&quot;String&quot;&gt;&amp;quot;&lt;/span&gt;http://maven.apache.org/SETTINGS/1.0.0&lt;span class=&quot;String&quot;&gt;&amp;quot;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;MetaTag&quot;&gt;  &lt;span class=&quot;MetaTag&quot;&gt;xmlns&lt;/span&gt;&lt;span class=&quot;MetaTag&quot;&gt;&lt;span class=&quot;MetaTag&quot;&gt;:&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;MetaTag&quot;&gt;xsi&lt;/span&gt;=&lt;span class=&quot;String&quot;&gt;&lt;span class=&quot;String&quot;&gt;&amp;quot;&lt;/span&gt;http://www.w3.org/2001/XMLSchema-instance&lt;span class=&quot;String&quot;&gt;&amp;quot;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;MetaTag&quot;&gt;  &lt;span class=&quot;MetaTag&quot;&gt;xsi&lt;/span&gt;&lt;span class=&quot;MetaTag&quot;&gt;&lt;span class=&quot;MetaTag&quot;&gt;:&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;MetaTag&quot;&gt;schemaLocation&lt;/span&gt;=&lt;span class=&quot;String&quot;&gt;&lt;span class=&quot;String&quot;&gt;&amp;quot;&lt;/span&gt;http://maven.apache.org/SETTINGS/1.0.0&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;MetaTag&quot;&gt;&lt;span class=&quot;String&quot;&gt;                      http://maven.apache.org/xsd/settings-1.0.0.xsd&lt;span class=&quot;String&quot;&gt;&amp;quot;&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;MetaTag&quot;&gt;&amp;gt;&lt;/span&gt;&lt;/span&gt;
  &lt;span class=&quot;MetaTag&quot;&gt;&lt;span class=&quot;MetaTag&quot;&gt;&amp;lt;&lt;/span&gt;&lt;span class=&quot;MetaTag&quot;&gt;profiles&lt;/span&gt;&lt;span class=&quot;MetaTag&quot;&gt;&amp;gt;&lt;/span&gt;&lt;/span&gt;
    &lt;span class=&quot;MetaTag&quot;&gt;&lt;span class=&quot;MetaTag&quot;&gt;&amp;lt;&lt;/span&gt;&lt;span class=&quot;MetaTag&quot;&gt;profile&lt;/span&gt;&lt;span class=&quot;MetaTag&quot;&gt;&amp;gt;&lt;/span&gt;&lt;/span&gt;
      &lt;span class=&quot;MetaTag&quot;&gt;&lt;span class=&quot;MetaTag&quot;&gt;&amp;lt;&lt;/span&gt;&lt;span class=&quot;MetaTag&quot;&gt;id&lt;/span&gt;&lt;span class=&quot;MetaTag&quot;&gt;&amp;gt;&lt;/span&gt;&lt;/span&gt;appengine&lt;span class=&quot;MetaTag&quot;&gt;&lt;span class=&quot;MetaTag&quot;&gt;&amp;lt;/&lt;/span&gt;&lt;span class=&quot;MetaTag&quot;&gt;id&lt;/span&gt;&lt;span class=&quot;MetaTag&quot;&gt;&amp;gt;&lt;/span&gt;&lt;/span&gt;
      &lt;span class=&quot;MetaTag&quot;&gt;&lt;span class=&quot;MetaTag&quot;&gt;&amp;lt;&lt;/span&gt;&lt;span class=&quot;MetaTag&quot;&gt;properties&lt;/span&gt;&lt;span class=&quot;MetaTag&quot;&gt;&amp;gt;&lt;/span&gt;&lt;/span&gt;
        &lt;span class=&quot;MetaTag&quot;&gt;&lt;span class=&quot;MetaTag&quot;&gt;&amp;lt;&lt;/span&gt;&lt;span class=&quot;MetaTag&quot;&gt;appengine-email&lt;/span&gt;&lt;span class=&quot;MetaTag&quot;&gt;&amp;gt;&lt;/span&gt;&lt;/span&gt; ... &lt;span class=&quot;MetaTag&quot;&gt;&lt;span class=&quot;MetaTag&quot;&gt;&amp;lt;/&lt;/span&gt;&lt;span class=&quot;MetaTag&quot;&gt;appengine-email&lt;/span&gt;&lt;span class=&quot;MetaTag&quot;&gt;&amp;gt;&lt;/span&gt;&lt;/span&gt;
        &lt;span class=&quot;MetaTag&quot;&gt;&lt;span class=&quot;MetaTag&quot;&gt;&amp;lt;&lt;/span&gt;&lt;span class=&quot;MetaTag&quot;&gt;appengine-password&lt;/span&gt;&lt;span class=&quot;MetaTag&quot;&gt;&amp;gt;&lt;/span&gt;&lt;/span&gt; ... &lt;span class=&quot;MetaTag&quot;&gt;&lt;span class=&quot;MetaTag&quot;&gt;&amp;lt;/&lt;/span&gt;&lt;span class=&quot;MetaTag&quot;&gt;appengine-password&lt;/span&gt;&lt;span class=&quot;MetaTag&quot;&gt;&amp;gt;&lt;/span&gt;&lt;/span&gt;
      &lt;span class=&quot;MetaTag&quot;&gt;&lt;span class=&quot;MetaTag&quot;&gt;&amp;lt;/&lt;/span&gt;&lt;span class=&quot;MetaTag&quot;&gt;properties&lt;/span&gt;&lt;span class=&quot;MetaTag&quot;&gt;&amp;gt;&lt;/span&gt;&lt;/span&gt;
    &lt;span class=&quot;MetaTag&quot;&gt;&lt;span class=&quot;MetaTag&quot;&gt;&amp;lt;/&lt;/span&gt;&lt;span class=&quot;MetaTag&quot;&gt;profile&lt;/span&gt;&lt;span class=&quot;MetaTag&quot;&gt;&amp;gt;&lt;/span&gt;&lt;/span&gt;
  &lt;span class=&quot;MetaTag&quot;&gt;&lt;span class=&quot;MetaTag&quot;&gt;&amp;lt;/&lt;/span&gt;&lt;span class=&quot;MetaTag&quot;&gt;profiles&lt;/span&gt;&lt;span class=&quot;MetaTag&quot;&gt;&amp;gt;&lt;/span&gt;&lt;/span&gt;
  &lt;span class=&quot;MetaTag&quot;&gt;&lt;span class=&quot;MetaTag&quot;&gt;&amp;lt;&lt;/span&gt;&lt;span class=&quot;MetaTag&quot;&gt;activeProfiles&lt;/span&gt;&lt;span class=&quot;MetaTag&quot;&gt;&amp;gt;&lt;/span&gt;&lt;/span&gt;
    &lt;span class=&quot;MetaTag&quot;&gt;&lt;span class=&quot;MetaTag&quot;&gt;&amp;lt;&lt;/span&gt;&lt;span class=&quot;MetaTag&quot;&gt;activeProfile&lt;/span&gt;&lt;span class=&quot;MetaTag&quot;&gt;&amp;gt;&lt;/span&gt;&lt;/span&gt;appengine&lt;span class=&quot;MetaTag&quot;&gt;&lt;span class=&quot;MetaTag&quot;&gt;&amp;lt;/&lt;/span&gt;&lt;span class=&quot;MetaTag&quot;&gt;activeProfile&lt;/span&gt;&lt;span class=&quot;MetaTag&quot;&gt;&amp;gt;&lt;/span&gt;&lt;/span&gt;
  &lt;span class=&quot;MetaTag&quot;&gt;&lt;span class=&quot;MetaTag&quot;&gt;&amp;lt;/&lt;/span&gt;&lt;span class=&quot;MetaTag&quot;&gt;activeProfiles&lt;/span&gt;&lt;span class=&quot;MetaTag&quot;&gt;&amp;gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;MetaTag&quot;&gt;&lt;span class=&quot;MetaTag&quot;&gt;&amp;lt;/&lt;/span&gt;&lt;span class=&quot;MetaTag&quot;&gt;settings&lt;/span&gt;&lt;span class=&quot;MetaTag&quot;&gt;&amp;gt;&lt;/span&gt;&lt;/span&gt;
&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;Run:&lt;/p&gt;
&lt;div class=&quot;uv&quot;&gt;&lt;pre class=&quot;lazy&quot;&gt;
$ mvn deploy # needs maven distributionManagement/repository

or 

$ mvn install
$ cd zeeba-war
$ mvn google:appengine-deploy
&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;Info about &lt;code&gt;google-maven-plugin&lt;/code&gt; can be found at &lt;a href=&quot;http://www.amateurinmotion.com/sites/google-maven-plugin/plugin-info.html&quot;&gt;plugin information site&lt;/a&gt;.&lt;/p&gt;
&lt;p&gt;Plugin and Bones also can be used with Springframework outside AppEngine environment.&lt;/p&gt;</content>
</entry>


  <entry>
  <title>ListController 1st Working Prototype</title>
  <link href="/articles/2010/02/24/listcontroller-1st-working-prototype.html" />
  <id>tag:www.amateurinmotion.com,2010-02-24:1266998899</id>
  <updated>2010-02-24T10:08:19+02:00</updated>
  <content type="html">&lt;p&gt;Just got working the first prototype implementation of ListController for GWT (name comes from Cocoa &lt;a href=&quot;http://developer.apple.com/mac/library/DOCUMENTATION/Cocoa/Reference/ApplicationKit/Classes/NSArrayController_Class/Reference/Reference.html&quot;&gt;NSArrayController&lt;/a&gt;).&lt;/p&gt;
&lt;p&gt;Here is small screencast that shows &lt;code&gt;List&amp;lt;BlogEntry&amp;gt;&lt;/code&gt; observation and &amp;#8220;reaction&amp;#8221; to element adds (&lt;code&gt;ListController&lt;/code&gt;) and element property changes (&lt;code&gt;Bindings&lt;/code&gt;). Video has no sound, better viewed full-screen.&lt;/p&gt;
&lt;p&gt;&lt;object classid='clsid:d27cdb6e-ae6d-11cf-96b8-444553540000' codebase='http://download.macromedia.com/pub/shockwave/cabs/flash/swflash.cab#version=9,0,115,0' width='560' height='345'&gt;&lt;param name='movie' value='http://screenr.com/Content/assets/screenr_1116090935.swf' /&gt;&lt;param name='flashvars' value='i=49647' /&gt;&lt;param name='allowFullScreen' value='true' /&gt;&lt;embed src='http://screenr.com/Content/assets/screenr_1116090935.swf' flashvars='i=49647' allowFullScreen='true' width='560' height='345' pluginspage='http://www.macromedia.com/go/getflashplayer'&gt;&lt;/embed&gt;&lt;/object&gt;&lt;/p&gt;
&lt;p&gt;&lt;code&gt;ListController&amp;lt;T&amp;gt;&lt;/code&gt; takes &lt;code&gt;content&lt;/code&gt; observable &lt;code&gt;List&amp;lt;T&amp;gt;&lt;/code&gt; and observes &lt;code&gt;ADD&lt;/code&gt; (later will also handle &lt;code&gt;REMOVE&lt;/code&gt;, &lt;code&gt;REPLACE&lt;/code&gt;, &lt;code&gt;CLEAR&lt;/code&gt;) operations. When it happens, calls:&lt;/p&gt;
&lt;ul&gt;
	&lt;li&gt;&lt;code&gt;ListControllerTarget#create&lt;/code&gt; that should add the widget to the screen&lt;/li&gt;
	&lt;li&gt;&lt;code&gt;ListControllerTarget#bind&lt;/code&gt; that should bind widget to model properties&lt;/li&gt;
&lt;/ul&gt;
&lt;div class=&quot;uv&quot;&gt;&lt;pre class=&quot;lazy&quot;&gt;
blogEntries.addDelegate(&lt;span class=&quot;Keyword&quot;&gt;new&lt;/span&gt; &lt;span class=&quot;Keyword&quot;&gt;ListControllerTarget&lt;/span&gt;&lt;span class=&quot;Keyword&quot;&gt;&amp;lt;&lt;/span&gt;&lt;span class=&quot;Keyword&quot;&gt;BlogEntry&lt;/span&gt;, &lt;span class=&quot;Keyword&quot;&gt;BlogEntryListView&lt;/span&gt;&lt;span class=&quot;Keyword&quot;&gt;&amp;gt;&lt;/span&gt;() {

  &lt;span class=&quot;Keyword&quot;&gt;public &lt;/span&gt;&lt;span class=&quot;Keyword&quot;&gt;BlogEntryListView&lt;/span&gt; &lt;span class=&quot;Entity&quot;&gt;create&lt;/span&gt;() {
    &lt;span class=&quot;Keyword&quot;&gt;return&lt;/span&gt; view.addListEntry();
  }

  &lt;span class=&quot;Keyword&quot;&gt;public &lt;/span&gt;&lt;span class=&quot;Keyword&quot;&gt;void&lt;/span&gt; &lt;span class=&quot;Entity&quot;&gt;bind&lt;/span&gt;(&lt;span class=&quot;Keyword&quot;&gt;Bindings&lt;/span&gt; bindings, &lt;span class=&quot;Keyword&quot;&gt;BlogEntry&lt;/span&gt; model, &lt;span class=&quot;Keyword&quot;&gt;BlogEntryListView&lt;/span&gt; view) {
    &lt;span class=&quot;Comment&quot;&gt;&lt;span class=&quot;Comment&quot;&gt;//&lt;/span&gt; bind BlogEntry#title to HasText subject()&lt;/span&gt;
    bindings.bind(observable(model, &lt;span class=&quot;String&quot;&gt;&lt;span class=&quot;String&quot;&gt;&amp;quot;&lt;/span&gt;title&lt;span class=&quot;String&quot;&gt;&amp;quot;&lt;/span&gt;&lt;/span&gt;, &lt;span class=&quot;Support&quot;&gt;String&lt;/span&gt;.&lt;span class=&quot;Keyword&quot;&gt;class&lt;/span&gt;), hasText(view.subject()));
    
    &lt;span class=&quot;Comment&quot;&gt;&lt;span class=&quot;Comment&quot;&gt;//&lt;/span&gt; bind BlogEntry#published to HasText marker() using boolean to marker text transformer&lt;/span&gt;
    &lt;span class=&quot;Comment&quot;&gt;&lt;span class=&quot;Comment&quot;&gt;//&lt;/span&gt; (which transforms true to &amp;quot;Published&amp;quot; and false to &amp;quot;Draft&amp;quot;)&lt;/span&gt;
    bindings.bind(observable(model, &lt;span class=&quot;String&quot;&gt;&lt;span class=&quot;String&quot;&gt;&amp;quot;&lt;/span&gt;published&lt;span class=&quot;String&quot;&gt;&amp;quot;&lt;/span&gt;&lt;/span&gt;, &lt;span class=&quot;Support&quot;&gt;Boolean&lt;/span&gt;.&lt;span class=&quot;Keyword&quot;&gt;class&lt;/span&gt;), hasText(view.marker()), 
      &lt;span class=&quot;Keyword&quot;&gt;new&lt;/span&gt; &lt;span class=&quot;Keyword&quot;&gt;BooleanToMarkerTransformer&lt;/span&gt;());
  }
});
&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;&lt;code&gt;ObservableList&amp;lt;T&amp;gt;&lt;/code&gt; is an &lt;code&gt;ArrayList&amp;lt;T&amp;gt;&lt;/code&gt; subclass which implements &lt;code&gt;IsObservable&lt;/code&gt; and overrides &lt;code&gt;add&lt;/code&gt;, &lt;code&gt;remove&lt;/code&gt; mutators and notifies about element changes.&lt;/p&gt;
&lt;p&gt;BlogEntry implements &lt;code&gt;IsModel&lt;/code&gt; which extends &lt;code&gt;IsObservable&lt;/code&gt; and also is observable.&lt;/p&gt;
&lt;p&gt;Observation and Bindings are based on &lt;code&gt;IsObservable&lt;/code&gt; » &lt;code&gt;Observable&lt;/code&gt;:&lt;/p&gt;
&lt;div class=&quot;uv&quot;&gt;&lt;pre class=&quot;lazy&quot;&gt;
&lt;span class=&quot;Keyword&quot;&gt;BlogEntry&lt;/span&gt; entry = &lt;span class=&quot;Constant&quot;&gt;GWT&lt;/span&gt;.create(&lt;span class=&quot;Keyword&quot;&gt;BlogEntry&lt;/span&gt;.&lt;span class=&quot;Keyword&quot;&gt;class&lt;/span&gt;) &lt;span class=&quot;Comment&quot;&gt;&lt;span class=&quot;Comment&quot;&gt;//&lt;/span&gt; needs GWT generator&lt;/span&gt;

&lt;span class=&quot;Keyword&quot;&gt;ObserverRegistration&lt;/span&gt; reg = ((&lt;span class=&quot;Support&quot;&gt;Observable&lt;/span&gt;) entry).getReflection().observe(&lt;span class=&quot;String&quot;&gt;&lt;span class=&quot;String&quot;&gt;&amp;quot;&lt;/span&gt;title&lt;span class=&quot;String&quot;&gt;&amp;quot;&lt;/span&gt;&lt;/span&gt;, &lt;span class=&quot;Support&quot;&gt;String&lt;/span&gt;.&lt;span class=&quot;Keyword&quot;&gt;class&lt;/span&gt;, &lt;span class=&quot;Keyword&quot;&gt;new&lt;/span&gt; &lt;span class=&quot;Support&quot;&gt;Observer&lt;/span&gt;&lt;span class=&quot;Keyword&quot;&gt;&amp;lt;&lt;/span&gt;&lt;span class=&quot;Support&quot;&gt;String&lt;/span&gt;&lt;span class=&quot;Keyword&quot;&gt;&amp;gt;&lt;/span&gt;() {
  &lt;span class=&quot;Keyword&quot;&gt;public &lt;/span&gt;&lt;span class=&quot;Keyword&quot;&gt;void&lt;/span&gt; &lt;span class=&quot;Entity&quot;&gt;onValueChange&lt;/span&gt;(&lt;span class=&quot;Keyword&quot;&gt;KeyPath&lt;/span&gt; keyPath, &lt;span class=&quot;Support&quot;&gt;Operation&lt;/span&gt; operation, &lt;span class=&quot;Keyword&quot;&gt;IndexSet&lt;/span&gt; indexes, &lt;span class=&quot;Support&quot;&gt;String&lt;/span&gt; oldValue, &lt;span class=&quot;Support&quot;&gt;String&lt;/span&gt; newValue) {
    &lt;span class=&quot;Comment&quot;&gt;&lt;span class=&quot;Comment&quot;&gt;//&lt;/span&gt; &amp;quot;title&amp;quot; value has changed&lt;/span&gt;
  }
});

reg.remove(); &lt;span class=&quot;Comment&quot;&gt;&lt;span class=&quot;Comment&quot;&gt;//&lt;/span&gt; to remove observer when it is not needed anymore&lt;/span&gt;
&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;&lt;strong&gt;Next:&lt;/strong&gt; &lt;code&gt;ListController&lt;/code&gt; selection, &lt;code&gt;ObjectController&lt;/code&gt;, &lt;code&gt;DataSource&lt;/code&gt; a la &lt;code&gt;NSManagedObjectContext&lt;/code&gt; / SproutCode &lt;code&gt;DataSource&lt;/code&gt; or something like that.&lt;/p&gt;</content>
</entry>


  <entry>
  <title>Regarding GWT-MooTools</title>
  <link href="/articles/2010/02/09/regarding-gwt-mootools.html" />
  <id>tag:www.amateurinmotion.com,2010-02-09:1265746829</id>
  <updated>2010-02-09T22:20:29+02:00</updated>
  <content type="html">&lt;p&gt;For those who don&amp;#8217;t know, after spending a lot of time trying to write my own GWT-only animation framework and after trying to integrate Scriptaculous, later JQuery, I settled to &lt;a href=&quot;http://mootools.net/&quot;&gt;MooTools&lt;/a&gt; as my animation library of choice and wrote small GWT wrapper around it.&lt;/p&gt;
&lt;p&gt;Now along with already existing FX wrappers for:&lt;/p&gt;
&lt;ul&gt;
	&lt;li&gt;Morph&lt;/li&gt;
	&lt;li&gt;Tween&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;Today I upgaded it to mootools 1.2.4 and added:&lt;/p&gt;
&lt;ul&gt;
	&lt;li&gt;Slide&lt;/li&gt;
	&lt;li&gt;Reveal&lt;/li&gt;
	&lt;li&gt;Scroll&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;&lt;a href=&quot;http://mootools.latest.ampatspell-test.appspot.com/&quot; class=&quot;download&quot;&gt;Live demo&lt;/a&gt;&lt;/p&gt;
&lt;p&gt;gwt-mootools can be downloaded from &lt;a href=&quot;http://bitbucket.org/ampatspell/gwt-mootools/downloads/&quot;&gt;project downloads&lt;/a&gt;, other stuff nearby.&lt;/p&gt;</content>
</entry>


  <entry>
  <title>GWT History Management With Places</title>
  <link href="/articles/2010/02/01/gwt-history-management-with-places.html" />
  <id>tag:www.amateurinmotion.com,2010-02-01:1265034388</id>
  <updated>2010-02-01T16:26:28+02:00</updated>
  <content type="html">&lt;p&gt;This is a second post in two post series about History Management in GWT. In &lt;a href=&quot;/2010/01/17/gwt-history-management.html&quot;&gt;first part&lt;/a&gt; I introduced the definition of &lt;code&gt;Place&lt;/code&gt; and few necessary &amp;#8220;design patterns&amp;#8221; which makes it easy to implement history aware rich applications in GWT. The only missing piece of puzzle I left till the next time was cleaning up the implementation of &lt;code&gt;SimpleHistoryManager&lt;/code&gt;.&lt;/p&gt;
&lt;p&gt;In first part the &lt;code&gt;SimpleHistoryManager&lt;/code&gt; is the central compnent in whole application History architecture. It:&lt;/p&gt;
&lt;ul&gt;
	&lt;li&gt;calls &lt;code&gt;History.addItem(String)&lt;/code&gt;&lt;/li&gt;
	&lt;li&gt;handles history token value changes&lt;/li&gt;
	&lt;li&gt;handles application &lt;code&gt;Events&lt;/code&gt; which should be turned in history items&lt;/li&gt;
	&lt;li&gt;fires application &lt;code&gt;Events&lt;/code&gt; for each &lt;code&gt;History Place&lt;/code&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;While for small applications this central history manager class may suffice, it is not flexible enough and it only grows in size as application functionalty grows. This &amp;#8220;doesn&amp;#8217;t scale&amp;#8221;. We need to split &lt;code&gt;HistoryManager&lt;/code&gt; in logical parts that can be easily managed independently. For history management, the smallest part is &lt;code&gt;Place&lt;/code&gt; class and for each application place, &lt;code&gt;Place&lt;/code&gt; implementation should:&lt;/p&gt;
&lt;ul&gt;
	&lt;li&gt;fire application &lt;code&gt;Events&lt;/code&gt; on place change&lt;/li&gt;
	&lt;li&gt;handle application &lt;code&gt;Events&lt;/code&gt; which should be turned in &lt;code&gt;History&lt;/code&gt; items&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;Also there are few things what &lt;code&gt;Place&lt;/code&gt; implementations should &lt;strong&gt;not&lt;/strong&gt; do:&lt;/p&gt;
&lt;ul&gt;
	&lt;li&gt;parse, compare string tokens&lt;/li&gt;
	&lt;li&gt;create new string tokens&lt;/li&gt;
	&lt;li&gt;call &lt;code&gt;History&lt;/code&gt; methods directly&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;Those tasks can be perfectly be abstracted away in Place library that can be reused (and improved separately) between projects.&lt;/p&gt;
&lt;p&gt;It happens I&amp;#8217;ve written &lt;a href=&quot;http://bitbucket.org/ampatspell/places/src/&quot;&gt;Places library&lt;/a&gt; and the following will explain how to setup and use its public API. If you&amp;#8217;re currious about implementation details, feel free to dig in to the &lt;a href=&quot;http://bitbucket.org/ampatspell/places/src/tip/places-client/src/main/java/com/ampatspell/places/client/&quot;&gt;sources&lt;/a&gt;.&lt;/p&gt;
&lt;h2&gt;Downloading&lt;/h2&gt;
&lt;p&gt;Currently Places is at &lt;code&gt;1.0-SNAPSHOT&lt;/code&gt; state. I&amp;#8217;ll be releasing &lt;code&gt;1.0&lt;/code&gt; soon.&lt;/p&gt;
&lt;h3&gt;Using Maven&lt;/h3&gt;
&lt;p&gt;If you&amp;#8217;re using Maven, add the following repository to your pom (or better in your settings.xml / Nexus):&lt;/p&gt;
&lt;div class=&quot;uv&quot;&gt;&lt;pre class=&quot;lazy&quot;&gt;
&lt;span class=&quot;MetaTag&quot;&gt;&lt;span class=&quot;MetaTag&quot;&gt;&amp;lt;&lt;/span&gt;&lt;span class=&quot;MetaTag&quot;&gt;repositories&lt;/span&gt;&lt;span class=&quot;MetaTag&quot;&gt;&amp;gt;&lt;/span&gt;&lt;/span&gt;
  &lt;span class=&quot;MetaTag&quot;&gt;&lt;span class=&quot;MetaTag&quot;&gt;&amp;lt;&lt;/span&gt;&lt;span class=&quot;MetaTag&quot;&gt;repository&lt;/span&gt;&lt;span class=&quot;MetaTag&quot;&gt;&amp;gt;&lt;/span&gt;&lt;/span&gt;
    &lt;span class=&quot;MetaTag&quot;&gt;&lt;span class=&quot;MetaTag&quot;&gt;&amp;lt;&lt;/span&gt;&lt;span class=&quot;MetaTag&quot;&gt;id&lt;/span&gt;&lt;span class=&quot;MetaTag&quot;&gt;&amp;gt;&lt;/span&gt;&lt;/span&gt;amateurinmotion&lt;span class=&quot;MetaTag&quot;&gt;&lt;span class=&quot;MetaTag&quot;&gt;&amp;lt;/&lt;/span&gt;&lt;span class=&quot;MetaTag&quot;&gt;id&lt;/span&gt;&lt;span class=&quot;MetaTag&quot;&gt;&amp;gt;&lt;/span&gt;&lt;/span&gt;
    &lt;span class=&quot;MetaTag&quot;&gt;&lt;span class=&quot;MetaTag&quot;&gt;&amp;lt;&lt;/span&gt;&lt;span class=&quot;MetaTag&quot;&gt;name&lt;/span&gt;&lt;span class=&quot;MetaTag&quot;&gt;&amp;gt;&lt;/span&gt;&lt;/span&gt;amateurinmotion m2 repository&lt;span class=&quot;MetaTag&quot;&gt;&lt;span class=&quot;MetaTag&quot;&gt;&amp;lt;/&lt;/span&gt;&lt;span class=&quot;MetaTag&quot;&gt;name&lt;/span&gt;&lt;span class=&quot;MetaTag&quot;&gt;&amp;gt;&lt;/span&gt;&lt;/span&gt;
    &lt;span class=&quot;MetaTag&quot;&gt;&lt;span class=&quot;MetaTag&quot;&gt;&amp;lt;&lt;/span&gt;&lt;span class=&quot;MetaTag&quot;&gt;url&lt;/span&gt;&lt;span class=&quot;MetaTag&quot;&gt;&amp;gt;&lt;/span&gt;&lt;/span&gt;http://www.amateurinmotion.com/repository&lt;span class=&quot;MetaTag&quot;&gt;&lt;span class=&quot;MetaTag&quot;&gt;&amp;lt;/&lt;/span&gt;&lt;span class=&quot;MetaTag&quot;&gt;url&lt;/span&gt;&lt;span class=&quot;MetaTag&quot;&gt;&amp;gt;&lt;/span&gt;&lt;/span&gt;
  &lt;span class=&quot;MetaTag&quot;&gt;&lt;span class=&quot;MetaTag&quot;&gt;&amp;lt;/&lt;/span&gt;&lt;span class=&quot;MetaTag&quot;&gt;repository&lt;/span&gt;&lt;span class=&quot;MetaTag&quot;&gt;&amp;gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;MetaTag&quot;&gt;&lt;span class=&quot;MetaTag&quot;&gt;&amp;lt;/&lt;/span&gt;&lt;span class=&quot;MetaTag&quot;&gt;repositories&lt;/span&gt;&lt;span class=&quot;MetaTag&quot;&gt;&amp;gt;&lt;/span&gt;&lt;/span&gt;
&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;And add dependencies:&lt;/p&gt;
&lt;div class=&quot;uv&quot;&gt;&lt;pre class=&quot;lazy&quot;&gt;
&lt;span class=&quot;MetaTag&quot;&gt;&lt;span class=&quot;MetaTag&quot;&gt;&amp;lt;&lt;/span&gt;&lt;span class=&quot;MetaTag&quot;&gt;dependency&lt;/span&gt;&lt;span class=&quot;MetaTag&quot;&gt;&amp;gt;&lt;/span&gt;&lt;/span&gt;
  &lt;span class=&quot;MetaTag&quot;&gt;&lt;span class=&quot;MetaTag&quot;&gt;&amp;lt;&lt;/span&gt;&lt;span class=&quot;MetaTag&quot;&gt;groupId&lt;/span&gt;&lt;span class=&quot;MetaTag&quot;&gt;&amp;gt;&lt;/span&gt;&lt;/span&gt;com.ampatspell.places&lt;span class=&quot;MetaTag&quot;&gt;&lt;span class=&quot;MetaTag&quot;&gt;&amp;lt;/&lt;/span&gt;&lt;span class=&quot;MetaTag&quot;&gt;groupId&lt;/span&gt;&lt;span class=&quot;MetaTag&quot;&gt;&amp;gt;&lt;/span&gt;&lt;/span&gt;
  &lt;span class=&quot;MetaTag&quot;&gt;&lt;span class=&quot;MetaTag&quot;&gt;&amp;lt;&lt;/span&gt;&lt;span class=&quot;MetaTag&quot;&gt;artifactId&lt;/span&gt;&lt;span class=&quot;MetaTag&quot;&gt;&amp;gt;&lt;/span&gt;&lt;/span&gt;places-client&lt;span class=&quot;MetaTag&quot;&gt;&lt;span class=&quot;MetaTag&quot;&gt;&amp;lt;/&lt;/span&gt;&lt;span class=&quot;MetaTag&quot;&gt;artifactId&lt;/span&gt;&lt;span class=&quot;MetaTag&quot;&gt;&amp;gt;&lt;/span&gt;&lt;/span&gt;
  &lt;span class=&quot;MetaTag&quot;&gt;&lt;span class=&quot;MetaTag&quot;&gt;&amp;lt;&lt;/span&gt;&lt;span class=&quot;MetaTag&quot;&gt;version&lt;/span&gt;&lt;span class=&quot;MetaTag&quot;&gt;&amp;gt;&lt;/span&gt;&lt;/span&gt;1.0-SNAPSHOT&lt;span class=&quot;MetaTag&quot;&gt;&lt;span class=&quot;MetaTag&quot;&gt;&amp;lt;/&lt;/span&gt;&lt;span class=&quot;MetaTag&quot;&gt;version&lt;/span&gt;&lt;span class=&quot;MetaTag&quot;&gt;&amp;gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;MetaTag&quot;&gt;&lt;span class=&quot;MetaTag&quot;&gt;&amp;lt;/&lt;/span&gt;&lt;span class=&quot;MetaTag&quot;&gt;dependency&lt;/span&gt;&lt;span class=&quot;MetaTag&quot;&gt;&amp;gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;MetaTag&quot;&gt;&lt;span class=&quot;MetaTag&quot;&gt;&amp;lt;&lt;/span&gt;&lt;span class=&quot;MetaTag&quot;&gt;dependency&lt;/span&gt;&lt;span class=&quot;MetaTag&quot;&gt;&amp;gt;&lt;/span&gt;&lt;/span&gt;
  &lt;span class=&quot;MetaTag&quot;&gt;&lt;span class=&quot;MetaTag&quot;&gt;&amp;lt;&lt;/span&gt;&lt;span class=&quot;MetaTag&quot;&gt;groupId&lt;/span&gt;&lt;span class=&quot;MetaTag&quot;&gt;&amp;gt;&lt;/span&gt;&lt;/span&gt;com.ampatspell.places&lt;span class=&quot;MetaTag&quot;&gt;&lt;span class=&quot;MetaTag&quot;&gt;&amp;lt;/&lt;/span&gt;&lt;span class=&quot;MetaTag&quot;&gt;groupId&lt;/span&gt;&lt;span class=&quot;MetaTag&quot;&gt;&amp;gt;&lt;/span&gt;&lt;/span&gt;
  &lt;span class=&quot;MetaTag&quot;&gt;&lt;span class=&quot;MetaTag&quot;&gt;&amp;lt;&lt;/span&gt;&lt;span class=&quot;MetaTag&quot;&gt;artifactId&lt;/span&gt;&lt;span class=&quot;MetaTag&quot;&gt;&amp;gt;&lt;/span&gt;&lt;/span&gt;places-client&lt;span class=&quot;MetaTag&quot;&gt;&lt;span class=&quot;MetaTag&quot;&gt;&amp;lt;/&lt;/span&gt;&lt;span class=&quot;MetaTag&quot;&gt;artifactId&lt;/span&gt;&lt;span class=&quot;MetaTag&quot;&gt;&amp;gt;&lt;/span&gt;&lt;/span&gt;
  &lt;span class=&quot;MetaTag&quot;&gt;&lt;span class=&quot;MetaTag&quot;&gt;&amp;lt;&lt;/span&gt;&lt;span class=&quot;MetaTag&quot;&gt;version&lt;/span&gt;&lt;span class=&quot;MetaTag&quot;&gt;&amp;gt;&lt;/span&gt;&lt;/span&gt;1.0-SNAPSHOT&lt;span class=&quot;MetaTag&quot;&gt;&lt;span class=&quot;MetaTag&quot;&gt;&amp;lt;/&lt;/span&gt;&lt;span class=&quot;MetaTag&quot;&gt;version&lt;/span&gt;&lt;span class=&quot;MetaTag&quot;&gt;&amp;gt;&lt;/span&gt;&lt;/span&gt;
  &lt;span class=&quot;MetaTag&quot;&gt;&lt;span class=&quot;MetaTag&quot;&gt;&amp;lt;&lt;/span&gt;&lt;span class=&quot;MetaTag&quot;&gt;classifier&lt;/span&gt;&lt;span class=&quot;MetaTag&quot;&gt;&amp;gt;&lt;/span&gt;&lt;/span&gt;sources&lt;span class=&quot;MetaTag&quot;&gt;&lt;span class=&quot;MetaTag&quot;&gt;&amp;lt;/&lt;/span&gt;&lt;span class=&quot;MetaTag&quot;&gt;classifier&lt;/span&gt;&lt;span class=&quot;MetaTag&quot;&gt;&amp;gt;&lt;/span&gt;&lt;/span&gt;
  &lt;span class=&quot;MetaTag&quot;&gt;&lt;span class=&quot;MetaTag&quot;&gt;&amp;lt;&lt;/span&gt;&lt;span class=&quot;MetaTag&quot;&gt;scope&lt;/span&gt;&lt;span class=&quot;MetaTag&quot;&gt;&amp;gt;&lt;/span&gt;&lt;/span&gt;compile&lt;span class=&quot;MetaTag&quot;&gt;&lt;span class=&quot;MetaTag&quot;&gt;&amp;lt;/&lt;/span&gt;&lt;span class=&quot;MetaTag&quot;&gt;scope&lt;/span&gt;&lt;span class=&quot;MetaTag&quot;&gt;&amp;gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;MetaTag&quot;&gt;&lt;span class=&quot;MetaTag&quot;&gt;&amp;lt;/&lt;/span&gt;&lt;span class=&quot;MetaTag&quot;&gt;dependency&lt;/span&gt;&lt;span class=&quot;MetaTag&quot;&gt;&amp;gt;&lt;/span&gt;&lt;/span&gt;
&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;&lt;strong&gt;Warning:&lt;/strong&gt; Places library declares few dependencies which are not in central Maven repository like GIN, GWT, Guice version which works in AppEngine. They reside in my Maven repository and will be included in compile classpath. If it is not desired, maven &lt;a href=&quot;http://maven.apache.org/guides/introduction/introduction-to-optional-and-excludes-dependencies.html&quot;&gt;dependency exclusions&lt;/a&gt; are your friends.&lt;/p&gt;
&lt;h3&gt;Manually&lt;/h3&gt;
&lt;p&gt;Places and its dependencies:&lt;/p&gt;
&lt;ul&gt;
	&lt;li&gt;&lt;a href=&quot;http://www.amateurinmotion.com/repository/com/ampatspell/places/places-client/1.0-SNAPSHOT/&quot;&gt;Places&lt;/a&gt; &lt;small&gt;(places-client-1.0-[date]-[rev].jar, places-client-1.0-[date]-[rev]-sources.jar)&lt;/small&gt;&lt;/li&gt;
	&lt;li&gt;&lt;a href=&quot;http://www.amateurinmotion.com/repository/com/ampatspell/bones/bones-core-client/1.0-SNAPSHOT/&quot;&gt;Bones Core Client&lt;/a&gt; &lt;small&gt;same file name patterns&lt;/small&gt;&lt;/li&gt;
	&lt;li&gt;&lt;a href=&quot;http://www.amateurinmotion.com/repository/com/ampatspell/bones/bones-core-shared/1.0-SNAPSHOT/&quot;&gt;Bones Core Shared&lt;/a&gt; &lt;small&gt;same file name patterns&lt;/small&gt;&lt;/li&gt;
	&lt;li&gt;&lt;a href=&quot;http://code.google.com/p/google-gin/&quot;&gt;Google GIN&lt;/a&gt;&lt;/li&gt;
	&lt;li&gt;&lt;a href=&quot;http://code.google.com/p/google-guice/&quot;&gt;Google Guice&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;Now that you have all necessary jars we can move on GWT and GIN configuration.&lt;/p&gt;
&lt;h2&gt;Setup&lt;/h2&gt;
&lt;p&gt;Add the &lt;code&gt;inherits&lt;/code&gt; to &lt;code&gt;gwt.xml&lt;/code&gt;:&lt;/p&gt;
&lt;div class=&quot;uv&quot;&gt;&lt;pre class=&quot;lazy&quot;&gt;
&lt;span class=&quot;MetaTag&quot;&gt;&lt;span class=&quot;MetaTag&quot;&gt;&amp;lt;&lt;/span&gt;&lt;span class=&quot;MetaTag&quot;&gt;module&lt;/span&gt;&lt;span class=&quot;MetaTag&quot;&gt;&amp;gt;&lt;/span&gt;&lt;/span&gt;
  &lt;span class=&quot;MetaTag&quot;&gt;&lt;span class=&quot;MetaTag&quot;&gt;&amp;lt;&lt;/span&gt;&lt;span class=&quot;MetaTag&quot;&gt;inherits&lt;/span&gt; &lt;span class=&quot;MetaTag&quot;&gt;name&lt;/span&gt;=&lt;span class=&quot;String&quot;&gt;&lt;span class=&quot;String&quot;&gt;&amp;quot;&lt;/span&gt;com.ampatspell.bones.core.Core&lt;span class=&quot;String&quot;&gt;&amp;quot;&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;MetaTag&quot;&gt;/&amp;gt;&lt;/span&gt;&lt;/span&gt;
  &lt;span class=&quot;MetaTag&quot;&gt;&lt;span class=&quot;MetaTag&quot;&gt;&amp;lt;&lt;/span&gt;&lt;span class=&quot;MetaTag&quot;&gt;inherits&lt;/span&gt; &lt;span class=&quot;MetaTag&quot;&gt;name&lt;/span&gt;=&lt;span class=&quot;String&quot;&gt;&lt;span class=&quot;String&quot;&gt;&amp;quot;&lt;/span&gt;com.ampatspell.places.Places&lt;span class=&quot;String&quot;&gt;&amp;quot;&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;MetaTag&quot;&gt;/&amp;gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;MetaTag&quot;&gt;&lt;span class=&quot;MetaTag&quot;&gt;&amp;lt;/&lt;/span&gt;&lt;span class=&quot;MetaTag&quot;&gt;module&lt;/span&gt;&lt;span class=&quot;MetaTag&quot;&gt;&amp;gt;&lt;/span&gt;&lt;/span&gt;
&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;Install &lt;code&gt;PlacesModule&lt;/code&gt; in your GIN Module:&lt;/p&gt;
&lt;div class=&quot;uv&quot;&gt;&lt;pre class=&quot;lazy&quot;&gt;
&lt;span class=&quot;Keyword&quot;&gt;public &lt;/span&gt;&lt;span class=&quot;Keyword&quot;&gt;class&lt;/span&gt; &lt;span class=&quot;Entity&quot;&gt;ExampleGinModule&lt;/span&gt; &lt;span class=&quot;Keyword&quot;&gt;extends&lt;/span&gt; &lt;span class=&quot;Keyword&quot;&gt;AbstractGinModule&lt;/span&gt; {

  @&lt;span class=&quot;Support&quot;&gt;Override&lt;/span&gt;
  &lt;span class=&quot;Keyword&quot;&gt;protected &lt;/span&gt;&lt;span class=&quot;Keyword&quot;&gt;void&lt;/span&gt; &lt;span class=&quot;Entity&quot;&gt;configure&lt;/span&gt;() {
    &lt;span class=&quot;Comment&quot;&gt;&lt;span class=&quot;Comment&quot;&gt;//&lt;/span&gt; Bones (optional)&lt;/span&gt;
    install(&lt;span class=&quot;Keyword&quot;&gt;new&lt;/span&gt; &lt;span class=&quot;Keyword&quot;&gt;BonesCoreGinModule&lt;/span&gt;());
    bind(&lt;span class=&quot;Keyword&quot;&gt;DispatchServiceAsync&lt;/span&gt;.&lt;span class=&quot;Keyword&quot;&gt;class&lt;/span&gt;).to(&lt;span class=&quot;Keyword&quot;&gt;DispatchServiceAsyncImpl&lt;/span&gt;.&lt;span class=&quot;Keyword&quot;&gt;class&lt;/span&gt;);
    
    &lt;span class=&quot;Comment&quot;&gt;&lt;span class=&quot;Comment&quot;&gt;//&lt;/span&gt; Places Service&lt;/span&gt;
    install(&lt;span class=&quot;Keyword&quot;&gt;new&lt;/span&gt; &lt;span class=&quot;Keyword&quot;&gt;PlaceServiceModule&lt;/span&gt;());
    bind(&lt;span class=&quot;Keyword&quot;&gt;PlacesLogger&lt;/span&gt;.&lt;span class=&quot;Keyword&quot;&gt;class&lt;/span&gt;).to(&lt;span class=&quot;Keyword&quot;&gt;GWTPlacesLogger&lt;/span&gt;.&lt;span class=&quot;Keyword&quot;&gt;class&lt;/span&gt;);
    bind(&lt;span class=&quot;Keyword&quot;&gt;EventBus&lt;/span&gt;.&lt;span class=&quot;Keyword&quot;&gt;class&lt;/span&gt;).to(&lt;span class=&quot;Keyword&quot;&gt;BaseEventBus&lt;/span&gt;.&lt;span class=&quot;Keyword&quot;&gt;class&lt;/span&gt;); &lt;span class=&quot;Comment&quot;&gt;&lt;span class=&quot;Comment&quot;&gt;//&lt;/span&gt; or your EventBus implementation&lt;/span&gt;
  }
  
  @&lt;span class=&quot;Keyword&quot;&gt;Provides&lt;/span&gt;
  @&lt;span class=&quot;Keyword&quot;&gt;Singleton&lt;/span&gt;
  &lt;span class=&quot;Keyword&quot;&gt;public &lt;/span&gt;&lt;span class=&quot;Keyword&quot;&gt;List&lt;/span&gt;&lt;span class=&quot;Keyword&quot;&gt;&amp;lt;Place&amp;gt;&lt;/span&gt; &lt;span class=&quot;Entity&quot;&gt;providePlaces&lt;/span&gt;() {
    &lt;span class=&quot;Support&quot;&gt;List&lt;/span&gt;&lt;span class=&quot;Keyword&quot;&gt;&amp;lt;&lt;/span&gt;&lt;span class=&quot;Keyword&quot;&gt;Place&lt;/span&gt;&lt;span class=&quot;Keyword&quot;&gt;&amp;gt;&lt;/span&gt; places = &lt;span class=&quot;Keyword&quot;&gt;new&lt;/span&gt; &lt;span class=&quot;Support&quot;&gt;ArrayList&lt;/span&gt;&lt;span class=&quot;Keyword&quot;&gt;&amp;lt;&lt;/span&gt;&lt;span class=&quot;Keyword&quot;&gt;Place&lt;/span&gt;&lt;span class=&quot;Keyword&quot;&gt;&amp;gt;&lt;/span&gt;();
    &lt;span class=&quot;Keyword&quot;&gt;return&lt;/span&gt; places;
  }  

}
&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;If you don&amp;#8217;t want to bring all &lt;a href=&quot;http://bitbucket.org/ampatspell/bones/downloads/&quot;&gt;Bones&lt;/a&gt; functionality (post about Bones library comming soon), you may install only &lt;code&gt;PlacesModule&lt;/code&gt; and bind &lt;code&gt;EventBus.class&lt;/code&gt; to your &lt;code&gt;HandlerManager&lt;/code&gt; implementation that poses as &lt;code&gt;EventBus&lt;/code&gt; in your application. No other dependencies exist.&lt;/p&gt;
&lt;p&gt;Also, as we can see, there&amp;#8217;s binding to empty List of &lt;code&gt;Place&lt;/code&gt; instances bound. There we should list all application places.&lt;/p&gt;
&lt;h2&gt;Place&lt;/h2&gt;
&lt;p&gt;Lets start with &lt;code&gt;Place&lt;/code&gt; interface and talk about what is &lt;code&gt;Place&lt;/code&gt; scope is and what implementations should do:&lt;/p&gt;
&lt;div class=&quot;uv&quot;&gt;&lt;pre class=&quot;lazy&quot;&gt;
&lt;span class=&quot;Keyword&quot;&gt;public &lt;/span&gt;&lt;span class=&quot;Keyword&quot;&gt;interface&lt;/span&gt; &lt;span class=&quot;Entity&quot;&gt;Place&lt;/span&gt; {

&lt;span class=&quot;Comment&quot;&gt;&lt;span class=&quot;Comment&quot;&gt;  /**&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;Comment&quot;&gt;   * History token url sub-pattern for this &lt;span class=&quot;Keyword&quot;&gt;{@link Place}&lt;/span&gt;.&lt;/span&gt;
&lt;span class=&quot;Comment&quot;&gt;   *&lt;/span&gt;
&lt;span class=&quot;Comment&quot;&gt;   * &lt;span class=&quot;Keyword&quot;&gt;@return&lt;/span&gt; string pattern for &lt;span class=&quot;Keyword&quot;&gt;{@link Place}&lt;/span&gt;. May be blank or null&lt;/span&gt;
&lt;span class=&quot;Comment&quot;&gt;   &lt;span class=&quot;Comment&quot;&gt;*/&lt;/span&gt;&lt;/span&gt;
  &lt;span class=&quot;Support&quot;&gt;String&lt;/span&gt; getPattern();

&lt;span class=&quot;Comment&quot;&gt;&lt;span class=&quot;Comment&quot;&gt;  /**&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;Comment&quot;&gt;   * Returns if &lt;span class=&quot;Keyword&quot;&gt;{@link Place#getPattern()}&lt;/span&gt; overrides it's parent pattern.&lt;/span&gt;
&lt;span class=&quot;Comment&quot;&gt;   *&lt;/span&gt;
&lt;span class=&quot;Comment&quot;&gt;   * &lt;span class=&quot;Keyword&quot;&gt;@return&lt;/span&gt; &amp;lt;code&amp;gt;true&amp;lt;/code&amp;gt; if pattern overrides parent, &amp;lt;code&amp;gt;false&amp;lt;/code&amp;gt; otherwise&lt;/span&gt;
&lt;span class=&quot;Comment&quot;&gt;   &lt;span class=&quot;Comment&quot;&gt;*/&lt;/span&gt;&lt;/span&gt;
  &lt;span class=&quot;Keyword&quot;&gt;boolean&lt;/span&gt; overridesParent();

&lt;span class=&quot;Comment&quot;&gt;&lt;span class=&quot;Comment&quot;&gt;  /**&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;Comment&quot;&gt;   * &lt;span class=&quot;Keyword&quot;&gt;@return&lt;/span&gt; parent &lt;span class=&quot;Keyword&quot;&gt;{@link Place}&lt;/span&gt; or null&lt;/span&gt;
&lt;span class=&quot;Comment&quot;&gt;   &lt;span class=&quot;Comment&quot;&gt;*/&lt;/span&gt;&lt;/span&gt;
  &lt;span class=&quot;Keyword&quot;&gt;Place&lt;/span&gt; getParent();

&lt;span class=&quot;Comment&quot;&gt;&lt;span class=&quot;Comment&quot;&gt;  /**&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;Comment&quot;&gt;   * Parameters which will be added to token&lt;/span&gt;
&lt;span class=&quot;Comment&quot;&gt;   *&lt;/span&gt;
&lt;span class=&quot;Comment&quot;&gt;   * &lt;span class=&quot;Keyword&quot;&gt;@return&lt;/span&gt; additional parameter names or null&lt;/span&gt;
&lt;span class=&quot;Comment&quot;&gt;   &lt;span class=&quot;Comment&quot;&gt;*/&lt;/span&gt;&lt;/span&gt;
  &lt;span class=&quot;Support&quot;&gt;String&lt;/span&gt;[] getAdditionalParameters();

&lt;span class=&quot;Comment&quot;&gt;&lt;span class=&quot;Comment&quot;&gt;  /**&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;Comment&quot;&gt;   * Called before first place is invoked&lt;/span&gt;
&lt;span class=&quot;Comment&quot;&gt;   *&lt;/span&gt;
&lt;span class=&quot;Comment&quot;&gt;   * &lt;span class=&quot;Keyword&quot;&gt;@param&lt;/span&gt; binding binding context for moving to next &lt;span class=&quot;Keyword&quot;&gt;{@link Place}&lt;/span&gt; and &lt;/span&gt;
&lt;span class=&quot;Comment&quot;&gt;   *                for registering event handlers&lt;/span&gt;
&lt;span class=&quot;Comment&quot;&gt;   &lt;span class=&quot;Comment&quot;&gt;*/&lt;/span&gt;&lt;/span&gt;
  &lt;span class=&quot;Keyword&quot;&gt;void&lt;/span&gt; bind(&lt;span class=&quot;Keyword&quot;&gt;PlaceBindingContext&lt;/span&gt; binding);

  &lt;span class=&quot;Keyword&quot;&gt;void&lt;/span&gt; unbind();

&lt;span class=&quot;Comment&quot;&gt;&lt;span class=&quot;Comment&quot;&gt;  /**&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;Comment&quot;&gt;   * Called when History token matches given &lt;span class=&quot;Keyword&quot;&gt;{@link Place}&lt;/span&gt; ir one of the &lt;/span&gt;
&lt;span class=&quot;Comment&quot;&gt;   * child &lt;span class=&quot;Keyword&quot;&gt;{@link Place}&lt;/span&gt;s.&lt;/span&gt;
&lt;span class=&quot;Comment&quot;&gt;   * &amp;lt;p/&amp;gt;&lt;/span&gt;
&lt;span class=&quot;Comment&quot;&gt;   * Note: {@code invocation.invoke()} &amp;lt;b&amp;gt;must&amp;lt;/b&amp;gt; be called in each invoke call&lt;/span&gt;
&lt;span class=&quot;Comment&quot;&gt;   *&lt;/span&gt;
&lt;span class=&quot;Comment&quot;&gt;   * &lt;span class=&quot;Keyword&quot;&gt;@param&lt;/span&gt; invocation context for getting current parameters (from pattern or from &lt;/span&gt;
&lt;span class=&quot;Comment&quot;&gt;   *                   additional parameters) and continuing invocation chain&lt;/span&gt;
&lt;span class=&quot;Comment&quot;&gt;   &lt;span class=&quot;Comment&quot;&gt;*/&lt;/span&gt;&lt;/span&gt;
  &lt;span class=&quot;Keyword&quot;&gt;void&lt;/span&gt; invoke(&lt;span class=&quot;Keyword&quot;&gt;PlaceInvocationContext&lt;/span&gt; invocation);

}
&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;&lt;code&gt;Place&lt;/code&gt; implementation does three things (three scopes):&lt;/p&gt;
&lt;ul&gt;
	&lt;li&gt;&lt;strong&gt;Matching&lt;/strong&gt; &amp;#8212; provides information about &lt;code&gt;History&lt;/code&gt; token pattern parts which this place&amp;nbsp;manages&lt;/li&gt;
	&lt;li&gt;&lt;strong&gt;Binding&lt;/strong&gt; &amp;#8212; handles application &lt;code&gt;Events&lt;/code&gt; which should add next &lt;code&gt;History&lt;/code&gt; item&lt;/li&gt;
	&lt;li&gt;&lt;strong&gt;Invocation&lt;/strong&gt; &amp;#8212; fires application &lt;code&gt;Events&lt;/code&gt; to restore place&lt;/li&gt;
&lt;/ul&gt;
&lt;table&gt;
	&lt;tr&gt;
		&lt;th&gt;Scope     &lt;/th&gt;
		&lt;th&gt;Method group &lt;/th&gt;
		&lt;th&gt;Description &lt;/th&gt;
	&lt;/tr&gt;
	&lt;tr&gt;
		&lt;td&gt; Matching   &lt;/td&gt;
		&lt;td&gt; &lt;code&gt;getPattern()&lt;/code&gt; &lt;/td&gt;
		&lt;td&gt; Relative &lt;code&gt;History&lt;/code&gt; token pattern string&lt;br/&gt;(may be blank or null) &lt;/td&gt;
	&lt;/tr&gt;
	&lt;tr&gt;
		&lt;td&gt; Matching   &lt;/td&gt;
		&lt;td&gt; &lt;code&gt;overridesParent()&lt;/code&gt; &lt;/td&gt;
		&lt;td&gt; Whether pattern returned by &lt;code&gt;getPattern()&lt;/code&gt; overrides&lt;br/&gt; its parent pattern &lt;/td&gt;
	&lt;/tr&gt;
	&lt;tr&gt;
		&lt;td&gt; Matching   &lt;/td&gt;
		&lt;td&gt; &lt;code&gt;getParent()&lt;/code&gt; &lt;/td&gt;
		&lt;td&gt; Parent &lt;code&gt;Place&lt;/code&gt; (may be null) &lt;/td&gt;
	&lt;/tr&gt;
	&lt;tr&gt;
		&lt;td&gt; Binding    &lt;/td&gt;
		&lt;td&gt; &lt;code&gt;bind(PlaceBindingContext)&lt;/code&gt; &lt;/td&gt;
		&lt;td&gt; Callback method for adding application Event handlers that should be&lt;br/&gt;turned into new &lt;code&gt;History&lt;/code&gt; items &lt;/td&gt;
	&lt;/tr&gt;
	&lt;tr&gt;
		&lt;td&gt; Binding    &lt;/td&gt;
		&lt;td&gt; &lt;code&gt;unbind()&lt;/code&gt; &lt;/td&gt;
		&lt;td&gt; Invoked on &lt;code&gt;HistoryService&lt;/code&gt; unbind. Nearly always useless &lt;/td&gt;
	&lt;/tr&gt;
	&lt;tr&gt;
		&lt;td&gt; Invocation &lt;/td&gt;
		&lt;td&gt; &lt;code&gt;invoke(PlaceInvocationContext)&lt;/code&gt; &lt;/td&gt;
		&lt;td&gt; Called when new history token matches this &lt;code&gt;Place&lt;/code&gt; pattern &lt;/td&gt;
	&lt;/tr&gt;
	&lt;tr&gt;
		&lt;td&gt; Binding &amp;amp; Invocation   &lt;/td&gt;
		&lt;td&gt; &lt;code&gt;getAdditionalParameters()&lt;/code&gt; &lt;/td&gt;
		&lt;td&gt; Additional parameter names of which values will be stored&lt;br/&gt;after main token as &lt;code&gt;name=value&lt;/code&gt; pairs (a la url parameters)&lt;br/&gt;and should be added for consequent invocations &lt;/td&gt;
	&lt;/tr&gt;
&lt;/table&gt;
&lt;p&gt;And my apologies for over-complicated explanation. As we&amp;#8217;ll see later, this thing is easy to use.&lt;/p&gt;
&lt;h3&gt;Matching&lt;/h3&gt;
&lt;p&gt;Token matching is done using &lt;code&gt;pattern&lt;/code&gt; and &lt;code&gt;parent&lt;/code&gt;. A &lt;code&gt;pattern&lt;/code&gt; can be composed by constant string parts and parameters using &lt;code&gt;{name}&lt;/code&gt; syntax. If &lt;code&gt;Place&lt;/code&gt; declares:&lt;/p&gt;
&lt;table&gt;
	&lt;tr&gt;
		&lt;th&gt;Pattern     &lt;/th&gt;
		&lt;th&gt;Parent &lt;/th&gt;
		&lt;th&gt;Overrides parent &lt;/th&gt;
	&lt;/tr&gt;
	&lt;tr&gt;
		&lt;td&gt; &lt;code&gt;/person/show/{key}&lt;/code&gt; &lt;/td&gt;
		&lt;td&gt; null &lt;/td&gt;
		&lt;td&gt; false &lt;/td&gt;
	&lt;/tr&gt;
&lt;/table&gt;
&lt;p&gt;The place will match:&lt;/p&gt;
&lt;table&gt;
	&lt;tr&gt;
		&lt;th&gt;Token     &lt;/th&gt;
		&lt;th&gt;Matches &lt;/th&gt;
		&lt;th&gt;Key value &lt;/th&gt;
	&lt;/tr&gt;
	&lt;tr&gt;
		&lt;td&gt; &lt;code&gt;/person/show/zeeba&lt;/code&gt; &lt;/td&gt;
		&lt;td&gt; &lt;code&gt;true&lt;/code&gt; &lt;/td&gt;
		&lt;td&gt; &amp;#8220;zeeba&amp;#8221; &lt;/td&gt;
	&lt;/tr&gt;
	&lt;tr&gt;
		&lt;td&gt; &lt;code&gt;/person/show/larry&lt;/code&gt; &lt;/td&gt;
		&lt;td&gt; &lt;code&gt;true&lt;/code&gt; &lt;/td&gt;
		&lt;td&gt; &amp;#8220;larry&amp;#8221; &lt;/td&gt;
	&lt;/tr&gt;
	&lt;tr&gt;
		&lt;td&gt; &lt;code&gt;/person/show/&lt;/code&gt; &lt;/td&gt;
		&lt;td&gt; &lt;code&gt;false&lt;/code&gt; &lt;/td&gt;
		&lt;td&gt; &amp;#8212; &lt;/td&gt;
	&lt;/tr&gt;
	&lt;tr&gt;
		&lt;td&gt; &lt;code&gt;/person/show/zeeba/&lt;/code&gt; &lt;/td&gt;
		&lt;td&gt; &lt;code&gt;false&lt;/code&gt;&lt;sup&gt;1&lt;/sup&gt; &lt;/td&gt;
		&lt;td&gt; &amp;#8212; &lt;/td&gt;
	&lt;/tr&gt;
&lt;/table&gt;
&lt;p&gt;&lt;sup&gt;1&lt;/sup&gt; &amp;#8212; the default parameter matcher uses the &lt;code&gt;/^([a-zA-Z0-9\-_]+)(.*)$/&lt;/code&gt; regex to find parameter value range in string. Let me know if it is too limiting.&lt;/p&gt;
&lt;p&gt;When &lt;code&gt;Place&lt;/code&gt; implementation returns other place as its parent things start to get more interesting. Those are all Place patterns &lt;a href=&quot;http://bitbucket.org/ampatspell/places/src/tip/places-example-gwt/src/main/java/com/ampatspell/places/example/client/place/&quot;&gt;used in demo application&lt;/a&gt;:&lt;/p&gt;
&lt;table&gt;
	&lt;tr&gt;
		&lt;th&gt;Place &lt;/th&gt;
		&lt;th&gt;Pattern     &lt;/th&gt;
		&lt;th&gt;Parent &lt;/th&gt;
		&lt;th&gt;Overrides parent &lt;/th&gt;
	&lt;/tr&gt;
	&lt;tr&gt;
		&lt;td&gt; &lt;code&gt;DefaultRedirectPlace(&quot;/index&quot;)&lt;/code&gt; &lt;/td&gt;
		&lt;td&gt; &lt;code&gt;null&lt;/code&gt; &lt;/td&gt;
		&lt;td&gt; &lt;code&gt;null&lt;/code&gt; &lt;/td&gt;
		&lt;td&gt; false &lt;/td&gt;
	&lt;/tr&gt;
	&lt;tr&gt;
		&lt;td&gt; &lt;code&gt;IndexPlace&lt;/code&gt; &lt;/td&gt;
		&lt;td&gt; &lt;code&gt;/index&lt;/code&gt; &lt;/td&gt;
		&lt;td&gt; &lt;code&gt;SectionPlace&lt;/code&gt; &lt;/td&gt;
		&lt;td&gt; true &lt;/td&gt;
	&lt;/tr&gt;
	&lt;tr&gt;
		&lt;td&gt; &lt;code&gt;PeoplePlace&lt;/code&gt; &lt;/td&gt;
		&lt;td&gt; &lt;code&gt;/people&lt;/code&gt; &lt;/td&gt;
		&lt;td&gt; &lt;code&gt;SectionPlace&lt;/code&gt; &lt;/td&gt;
		&lt;td&gt; true &lt;/td&gt;
	&lt;/tr&gt;
	&lt;tr&gt;
		&lt;td&gt; &lt;code&gt;ShowPersonPlace&lt;/code&gt; &lt;/td&gt;
		&lt;td&gt; &lt;code&gt;/show&lt;/code&gt; &lt;/td&gt;
		&lt;td&gt; &lt;code&gt;PersonKeyPlace&lt;/code&gt; &lt;/td&gt;
		&lt;td&gt; false &lt;/td&gt;
	&lt;/tr&gt;
	&lt;tr&gt;
		&lt;td&gt; &lt;code&gt;EditPersonPlace&lt;/code&gt; &lt;/td&gt;
		&lt;td&gt; &lt;code&gt;/edit&lt;/code&gt; &lt;/td&gt;
		&lt;td&gt; &lt;code&gt;PersonKeyPlace&lt;/code&gt; &lt;/td&gt;
		&lt;td&gt; false &lt;/td&gt;
	&lt;/tr&gt;
	&lt;tr&gt;
		&lt;td&gt; &lt;code&gt;NewPersonPlace&lt;/code&gt; &lt;/td&gt;
		&lt;td&gt; &lt;code&gt;/new&lt;/code&gt; &lt;/td&gt;
		&lt;td&gt; &lt;code&gt;PersonPlace&lt;/code&gt; &lt;/td&gt;
		&lt;td&gt; false &lt;/td&gt;
	&lt;/tr&gt;
	&lt;tr&gt;
		&lt;th colspan=&quot;4&quot;&gt;Parents &lt;/th&gt;
	&lt;/tr&gt;
	&lt;tr&gt;
		&lt;td&gt; &lt;code&gt;BasePlace&lt;/code&gt; &lt;/td&gt;
		&lt;td&gt; &lt;code&gt;null&lt;/code&gt; &lt;/td&gt;
		&lt;td&gt; &lt;code&gt;null&lt;/code&gt; &lt;/td&gt;
		&lt;td&gt; false &lt;/td&gt;
	&lt;/tr&gt;
	&lt;tr&gt;
		&lt;td&gt; &lt;code&gt;SectionPlace&lt;/code&gt; &lt;/td&gt;
		&lt;td&gt; &lt;code&gt;/{section}&lt;/code&gt; &lt;/td&gt;
		&lt;td&gt; &lt;code&gt;BasePlace&lt;/code&gt; &lt;/td&gt;
		&lt;td&gt; false &lt;/td&gt;
	&lt;/tr&gt;
	&lt;tr&gt;
		&lt;td&gt; &lt;code&gt;PersonPlace&lt;/code&gt; &lt;/td&gt;
		&lt;td&gt; &lt;code&gt;/person&lt;/code&gt; &lt;/td&gt;
		&lt;td&gt; &lt;code&gt;BasePlace&lt;/code&gt; &lt;/td&gt;
		&lt;td&gt; false &lt;/td&gt;
	&lt;/tr&gt;
	&lt;tr&gt;
		&lt;td&gt; &lt;code&gt;PersonKeyPlace&lt;/code&gt; &lt;/td&gt;
		&lt;td&gt; &lt;code&gt;/{key}&lt;/code&gt; &lt;/td&gt;
		&lt;td&gt; &lt;code&gt;PersonPlace&lt;/code&gt; &lt;/td&gt;
		&lt;td&gt; false &lt;/td&gt;
	&lt;/tr&gt;
&lt;/table&gt;
&lt;p&gt;The resuling &amp;#8220;full&amp;#8221; place patterns are:&lt;/p&gt;
&lt;p&gt;&lt;a href=&quot;http://history.latest.ampatspell-test.appspot.com/#/index&quot;&gt;&lt;img src=&quot;http://www.amateurinmotion.com/articles/2010/02/01/places.png&quot; class=&quot;clean nomargin  &quot; title=&quot;places.png&quot; alt=&quot;places.png&quot;/&gt;&lt;/a&gt;&lt;/p&gt;
&lt;p class=&quot;light&quot;&gt;By the way, this UI is included in library. See &amp;#8220;Registered Places&amp;#8221; section below.&lt;/p&gt;
&lt;p&gt;Where for example &lt;code&gt;/person/zeeba/show&lt;/code&gt; will match &lt;code&gt;ShowPersonPlace&lt;/code&gt; that has the following full parent-child hierarchy:&lt;/p&gt;
&lt;ul&gt;
	&lt;li&gt;&lt;code&gt;ShowPersonPlace&lt;/code&gt;&lt;/li&gt;
	&lt;li&gt;&lt;code&gt;PersonKeyPlace&lt;/code&gt;&lt;/li&gt;
	&lt;li&gt;&lt;code&gt;PersonPlace&lt;/code&gt;&lt;/li&gt;
	&lt;li&gt;&lt;code&gt;BasePlace&lt;/code&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;Each of parent places takes a part in all three &lt;code&gt;Place&lt;/code&gt; scopes: &lt;code&gt;matching&lt;/code&gt;, &lt;code&gt;binding&lt;/code&gt; and &lt;code&gt;invocation&lt;/code&gt;. It makes sense because this way place binding and invocation can be greatly simplified for end-level &lt;code&gt;Place&lt;/code&gt; implementations. Multiple &lt;code&gt;Places&lt;/code&gt; can share common parent that can also be bound as &lt;code&gt;@Singleton&lt;/code&gt;.&lt;/p&gt;
&lt;p&gt;Also while all shown patterns are &amp;#8220;one-slash with string or parameter&amp;#8221;, its perfectly fine to have pattern with more than one parameter with some delimiter (&amp;#8220;/&amp;#8221; or something else) between (for example &lt;code&gt;/list/{all}/{page}&lt;/code&gt; with &lt;code&gt;PeoplePlace&lt;/code&gt; as parent and few additional parameters will work just fine).&lt;/p&gt;
&lt;h3&gt;Invocation&lt;/h3&gt;
&lt;p&gt;When &lt;code&gt;Place&lt;/code&gt; matches current &lt;code&gt;History&lt;/code&gt; token, &lt;code&gt;invoke(PlaceInvocationContext)&lt;/code&gt; callbacks are invoked for whole this &lt;code&gt;Place&lt;/code&gt; parent-child hierarchy. Invocations are starting with root parent.&lt;/p&gt;
&lt;p&gt;For &lt;code&gt;ShowPersonPlace&lt;/code&gt; invocation chain contents are:&lt;/p&gt;
&lt;div class=&quot;uv&quot;&gt;&lt;pre class=&quot;lazy&quot;&gt;
&lt;span class=&quot;Comment&quot;&gt;&lt;span class=&quot;Comment&quot;&gt;//&lt;/span&gt; BasePlace&lt;/span&gt;
&lt;span class=&quot;Support&quot;&gt;String&lt;/span&gt; title = invocation.get(&lt;span class=&quot;String&quot;&gt;&lt;span class=&quot;String&quot;&gt;&amp;quot;&lt;/span&gt;title&lt;span class=&quot;String&quot;&gt;&amp;quot;&lt;/span&gt;&lt;/span&gt;, &lt;span class=&quot;String&quot;&gt;&lt;span class=&quot;String&quot;&gt;&amp;quot;&lt;/span&gt;Places Example&lt;span class=&quot;String&quot;&gt;&amp;quot;&lt;/span&gt;&lt;/span&gt;);
invocation.fireEvent(&lt;span class=&quot;Keyword&quot;&gt;new&lt;/span&gt; &lt;span class=&quot;Keyword&quot;&gt;SetTitleEvent&lt;/span&gt;(title));
invocation.proceed();

&lt;span class=&quot;Comment&quot;&gt;&lt;span class=&quot;Comment&quot;&gt;//&lt;/span&gt; PersonPlace&lt;/span&gt;
invocation.fireEvent(&lt;span class=&quot;Keyword&quot;&gt;new&lt;/span&gt; &lt;span class=&quot;Keyword&quot;&gt;WorkspaceSetContentEvent&lt;/span&gt;(people, &lt;span class=&quot;Keyword&quot;&gt;new&lt;/span&gt; &lt;span class=&quot;Keyword&quot;&gt;Command&lt;/span&gt;() {
  &lt;span class=&quot;Keyword&quot;&gt;public &lt;/span&gt;&lt;span class=&quot;Keyword&quot;&gt;void&lt;/span&gt; &lt;span class=&quot;Entity&quot;&gt;execute&lt;/span&gt;() {
    invocation.fireEvent(&lt;span class=&quot;Keyword&quot;&gt;new&lt;/span&gt; &lt;span class=&quot;Keyword&quot;&gt;MenuSetActiveEvent&lt;/span&gt;(&lt;span class=&quot;String&quot;&gt;&lt;span class=&quot;String&quot;&gt;&amp;quot;&lt;/span&gt;people&lt;span class=&quot;String&quot;&gt;&amp;quot;&lt;/span&gt;&lt;/span&gt;));
    invocation.proceed();
  }
}));

&lt;span class=&quot;Comment&quot;&gt;&lt;span class=&quot;Comment&quot;&gt;//&lt;/span&gt; PersonKeyPlace&lt;/span&gt;
&lt;span class=&quot;Support&quot;&gt;String&lt;/span&gt; key = invocation.get(&lt;span class=&quot;String&quot;&gt;&lt;span class=&quot;String&quot;&gt;&amp;quot;&lt;/span&gt;key&lt;span class=&quot;String&quot;&gt;&amp;quot;&lt;/span&gt;&lt;/span&gt;);
invocation.fireEvent(&lt;span class=&quot;Keyword&quot;&gt;new&lt;/span&gt; &lt;span class=&quot;Keyword&quot;&gt;ListSetActiveEvent&lt;/span&gt;(key));
invocation.proceed();

&lt;span class=&quot;Comment&quot;&gt;&lt;span class=&quot;Comment&quot;&gt;//&lt;/span&gt; ShowPersonPlace&lt;/span&gt;
&lt;span class=&quot;Keyword&quot;&gt;final&lt;/span&gt; &lt;span class=&quot;Support&quot;&gt;String&lt;/span&gt; key = invocation.get(&lt;span class=&quot;String&quot;&gt;&lt;span class=&quot;String&quot;&gt;&amp;quot;&lt;/span&gt;key&lt;span class=&quot;String&quot;&gt;&amp;quot;&lt;/span&gt;&lt;/span&gt;);
invocation.fireEvent(&lt;span class=&quot;Keyword&quot;&gt;new&lt;/span&gt; &lt;span class=&quot;Keyword&quot;&gt;PeopleSetContentEvent&lt;/span&gt;(show, &lt;span class=&quot;Keyword&quot;&gt;new&lt;/span&gt; &lt;span class=&quot;Keyword&quot;&gt;Command&lt;/span&gt;() {
  &lt;span class=&quot;Keyword&quot;&gt;public &lt;/span&gt;&lt;span class=&quot;Keyword&quot;&gt;void&lt;/span&gt; &lt;span class=&quot;Entity&quot;&gt;execute&lt;/span&gt;() {
    invocation.fireEvent(&lt;span class=&quot;Keyword&quot;&gt;new&lt;/span&gt; &lt;span class=&quot;Keyword&quot;&gt;PersonShowEvent&lt;/span&gt;(key));
  }
}));
&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;&lt;code&gt;PlaceInvocationContext&lt;/code&gt; (&lt;a href=&quot;http://bitbucket.org/ampatspell/places/src/tip/places-client/src/main/java/com/ampatspell/places/client/api/PlaceInvocationContext.java&quot;&gt;source&lt;/a&gt;) has the &lt;code&gt;proceed()&lt;/code&gt; method which needs more clarification.&lt;/p&gt;
&lt;p&gt;As we&amp;#8217;ve seen in post&amp;#8217;s first part, Place setup &lt;code&gt;Events&lt;/code&gt; must not be fired one after another in one &amp;#8220;batch&amp;#8221;, instead next Event should only be fired &lt;strong&gt;after&lt;/strong&gt; previous event is handled and presenter hierarchy is able to handle &lt;code&gt;Events&lt;/code&gt; (see &lt;a href=&quot;/2010/01/17/gwt-history-management.html&quot;&gt;On-Ready Event Callback&lt;/a&gt;).&lt;/p&gt;
&lt;p&gt;For this to work in &lt;code&gt;Place&lt;/code&gt; parent-child hierarchy &lt;code&gt;PlaceService&lt;/code&gt; needs to be notified when next &lt;code&gt;Place.invoke(PlaceInvocationContext)&lt;/code&gt; can be safely called. This is done using &lt;code&gt;proceed()&lt;/code&gt; method.&lt;/p&gt;
&lt;p&gt;So while &lt;code&gt;BasePlace&lt;/code&gt; invokes &lt;code&gt;proceed()&lt;/code&gt; immediately, &lt;code&gt;PersonPlace&lt;/code&gt; invokes it only &lt;strong&gt;after&lt;/strong&gt; &lt;code&gt;PeoplePresenter&lt;/code&gt; is bound and ready to receive events because otherwise &lt;code&gt;ListSetActiveEvent&lt;/code&gt; won&amp;#8217;t be handled.&lt;/p&gt;
&lt;p&gt;Other &lt;code&gt;PlaceInvocationMethods&lt;/code&gt; should be obvious (see javadocs for interface for more info).&lt;/p&gt;
&lt;h3&gt;Binding&lt;/h3&gt;
&lt;p&gt;&lt;code&gt;Place.bind(PlaceBindingContext)&lt;/code&gt; callback is used to register application specific &lt;code&gt;Event&lt;/code&gt; handlers for events which should be turned into the places. This is done using provided &lt;code&gt;PlaceBindingContext&lt;/code&gt; which allows to register to &lt;code&gt;EventBus&lt;/code&gt; and takes care of removing handlers on &lt;code&gt;PlacesService&lt;/code&gt; unbind. Also &lt;code&gt;PlaceBindingContext&lt;/code&gt; (&lt;a href=&quot;http://bitbucket.org/ampatspell/places/src/tip/places-client/src/main/java/com/ampatspell/places/client/api/PlaceBindingContext.java&quot;&gt;sources&lt;/a&gt;) declares &lt;code&gt;StateBuilder state()&lt;/code&gt; method which allows in declared event handlers perform transition to next History place (add new History item). &lt;code&gt;StateBuilder&lt;/code&gt; (&lt;a href=&quot;http://bitbucket.org/ampatspell/places/src/tip/places-client/src/main/java/com/ampatspell/places/client/api/StateBuilder.java&quot;&gt;sources&lt;/a&gt;) allows to set values for declared pattern parameters and also parameters that are added after &amp;#8220;?&amp;#8221; as &lt;code&gt;key=value&lt;/code&gt; pairs).&lt;/p&gt;
&lt;p&gt;One of in &lt;code&gt;ShowPersonPlace.onBind&lt;/code&gt; declared event handlers is:&lt;/p&gt;
&lt;div class=&quot;uv&quot;&gt;&lt;pre class=&quot;lazy&quot;&gt;
binding.addHandler(&lt;span class=&quot;Keyword&quot;&gt;PersonShowPlaceEvent&lt;/span&gt;.getType(), &lt;span class=&quot;Keyword&quot;&gt;new&lt;/span&gt; &lt;span class=&quot;Keyword&quot;&gt;PersonShowPlaceHandler&lt;/span&gt;() {
  &lt;span class=&quot;Keyword&quot;&gt;public &lt;/span&gt;&lt;span class=&quot;Keyword&quot;&gt;void&lt;/span&gt; &lt;span class=&quot;Entity&quot;&gt;onPersonShowPlace&lt;/span&gt;(&lt;span class=&quot;Keyword&quot;&gt;PersonShowPlaceEvent&lt;/span&gt; event) {
    binding.state().set(&lt;span class=&quot;String&quot;&gt;&lt;span class=&quot;String&quot;&gt;&amp;quot;&lt;/span&gt;key&lt;span class=&quot;String&quot;&gt;&amp;quot;&lt;/span&gt;&lt;/span&gt;, event.getKey()).invoke();
  }
});
&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;So when &lt;code&gt;ShowPersonPlaceEvent&lt;/code&gt; is fired, this is handled here and &lt;code&gt;History.newItem&lt;/code&gt; is called with &lt;code&gt;ShowPersonPlace&lt;/code&gt; full history token and event provided person key.&lt;/p&gt;
&lt;div class=&quot;uv&quot;&gt;&lt;pre class=&quot;lazy&quot;&gt;
/person/{key}/show
/person/zeeba/show
&lt;/pre&gt;&lt;/div&gt;&lt;p class=&quot;light&quot;&gt;At some later time &lt;code&gt;StateBuilder&lt;/code&gt; will have &lt;code&gt;invokeCurrent()&lt;/code&gt; method which will allow to stay in &amp;#8220;current&amp;#8221; place and only change some additional parameters.&lt;/p&gt;
&lt;h2&gt;Additional Parameters&lt;/h2&gt;
&lt;p&gt;Sometimes it can be useful to declare some parameters as &amp;#8220;persistent&amp;#8221; between place invocations. &lt;code&gt;grid=true&lt;/code&gt; comes in mind as a decent example. If all &lt;code&gt;Place&lt;/code&gt; implementations share directly or indirectly single &lt;code&gt;BasePlace&lt;/code&gt; parent with &lt;code&gt;grid&lt;/code&gt; as a additional parameter, the &lt;code&gt;grid&lt;/code&gt; value will be added for each and every place invocation and the same &lt;code&gt;BasePlace&lt;/code&gt; can fire &lt;code&gt;SetGridVisible&lt;/code&gt; event in &lt;code&gt;invoke&lt;/code&gt; to show the &lt;a href=&quot;http://www.google.com/search?q=grid%20design&quot;&gt;grid&lt;/a&gt; (useful for laying out UI components).&lt;/p&gt;
&lt;p&gt;Demo application has &lt;code&gt;title&lt;/code&gt; declared as additional parameter in &lt;code&gt;BasePlace&lt;/code&gt; and in invoke it fires &lt;code&gt;SetTitleEvent&lt;/code&gt;:&lt;/p&gt;
&lt;div class=&quot;uv&quot;&gt;&lt;pre class=&quot;lazy&quot;&gt;
@&lt;span class=&quot;Keyword&quot;&gt;Singleton&lt;/span&gt;
&lt;span class=&quot;Keyword&quot;&gt;public &lt;/span&gt;&lt;span class=&quot;Keyword&quot;&gt;class&lt;/span&gt; &lt;span class=&quot;Entity&quot;&gt;BasePlace&lt;/span&gt; &lt;span class=&quot;Keyword&quot;&gt;extends&lt;/span&gt; &lt;span class=&quot;Keyword&quot;&gt;AbstractPlace&lt;/span&gt; {

  @&lt;span class=&quot;Keyword&quot;&gt;Inject&lt;/span&gt;
  &lt;span class=&quot;Keyword&quot;&gt;protected &lt;/span&gt;&lt;span class=&quot;Entity&quot;&gt;BasePlace&lt;/span&gt;() {
    addAdditionalParameter(&lt;span class=&quot;String&quot;&gt;&lt;span class=&quot;String&quot;&gt;&amp;quot;&lt;/span&gt;title&lt;span class=&quot;String&quot;&gt;&amp;quot;&lt;/span&gt;&lt;/span&gt;);
  }

  @&lt;span class=&quot;Support&quot;&gt;Override&lt;/span&gt;
  &lt;span class=&quot;Keyword&quot;&gt;public &lt;/span&gt;&lt;span class=&quot;Keyword&quot;&gt;void&lt;/span&gt; &lt;span class=&quot;Entity&quot;&gt;onBind&lt;/span&gt;(final &lt;span class=&quot;Keyword&quot;&gt;PlaceBindingContext&lt;/span&gt; binding) {
    binding.addHandler(&lt;span class=&quot;Keyword&quot;&gt;SetTitlePlaceEvent&lt;/span&gt;.getType(), &lt;span class=&quot;Keyword&quot;&gt;new&lt;/span&gt; &lt;span class=&quot;Keyword&quot;&gt;SetTitlePlaceHandler&lt;/span&gt;() {
      &lt;span class=&quot;Keyword&quot;&gt;public &lt;/span&gt;&lt;span class=&quot;Keyword&quot;&gt;void&lt;/span&gt; &lt;span class=&quot;Entity&quot;&gt;onSetTitlePlace&lt;/span&gt;(&lt;span class=&quot;Keyword&quot;&gt;SetTitlePlaceEvent&lt;/span&gt; event) {
        binding.state().set(&lt;span class=&quot;String&quot;&gt;&lt;span class=&quot;String&quot;&gt;&amp;quot;&lt;/span&gt;title&lt;span class=&quot;String&quot;&gt;&amp;quot;&lt;/span&gt;&lt;/span&gt;, event.getTitle()).invoke();
      }
    });
  }

  @&lt;span class=&quot;Support&quot;&gt;Override&lt;/span&gt;
  &lt;span class=&quot;Keyword&quot;&gt;public &lt;/span&gt;&lt;span class=&quot;Keyword&quot;&gt;void&lt;/span&gt; &lt;span class=&quot;Entity&quot;&gt;onInvoke&lt;/span&gt;(&lt;span class=&quot;Keyword&quot;&gt;PlaceInvocationContext&lt;/span&gt; invocation) {
    &lt;span class=&quot;Support&quot;&gt;String&lt;/span&gt; title = invocation.get(&lt;span class=&quot;String&quot;&gt;&lt;span class=&quot;String&quot;&gt;&amp;quot;&lt;/span&gt;title&lt;span class=&quot;String&quot;&gt;&amp;quot;&lt;/span&gt;&lt;/span&gt;, &lt;span class=&quot;String&quot;&gt;&lt;span class=&quot;String&quot;&gt;&amp;quot;&lt;/span&gt;Places Example&lt;span class=&quot;String&quot;&gt;&amp;quot;&lt;/span&gt;&lt;/span&gt;);
    invocation.fireEvent(&lt;span class=&quot;Keyword&quot;&gt;new&lt;/span&gt; &lt;span class=&quot;Keyword&quot;&gt;SetTitleEvent&lt;/span&gt;(title));
    invocation.proceed();
  }

}
&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;To see the functionality in action, open demo application with &lt;a href=&quot;http://history.latest.ampatspell-test.appspot.com/#/person/doggy/show?title=Additional%20Parameters&quot;&gt;&amp;#8216;Additional Parameters&amp;#8217; as title&lt;/a&gt; and click on few links. The result is that the string &amp;#8220;Additional Parameters&amp;#8221; follows the place changes without explicit &lt;code&gt;set&lt;/code&gt; in each &lt;code&gt;binding().state()&lt;/code&gt; call.&lt;/p&gt;
&lt;h2&gt;Registered Places&lt;/h2&gt;
&lt;p&gt;Library also contains &amp;#8220;Registered Places&amp;#8221; UI for visualizing currently registered &lt;code&gt;Place&lt;/code&gt; &amp;#8212; &lt;code&gt;pattern&lt;/code&gt; bindings in application. Basic usage:&lt;/p&gt;
&lt;div class=&quot;uv&quot;&gt;&lt;pre class=&quot;lazy&quot;&gt;
&lt;span class=&quot;Keyword&quot;&gt;import&lt;/span&gt; &lt;span class=&quot;Entity&quot;&gt;com.ampatspell.places.client.api.PlacesService&lt;/span&gt;;
&lt;span class=&quot;Keyword&quot;&gt;import&lt;/span&gt; &lt;span class=&quot;Entity&quot;&gt;com.ampatspell.places.client.ui.places.PlacesPresenter&lt;/span&gt;;

&lt;span class=&quot;Keyword&quot;&gt;public &lt;/span&gt;&lt;span class=&quot;Keyword&quot;&gt;class&lt;/span&gt; &lt;span class=&quot;Entity&quot;&gt;Example&lt;/span&gt; &lt;span class=&quot;Keyword&quot;&gt;implements&lt;/span&gt; &lt;span class=&quot;Keyword&quot;&gt;EntryPoint&lt;/span&gt; {

  &lt;span class=&quot;Keyword&quot;&gt;public &lt;/span&gt;&lt;span class=&quot;Keyword&quot;&gt;void&lt;/span&gt; &lt;span class=&quot;Entity&quot;&gt;onModuleLoad&lt;/span&gt;() {
    &lt;span class=&quot;Keyword&quot;&gt;ExampleGinjector&lt;/span&gt; injector = &lt;span class=&quot;Constant&quot;&gt;GWT&lt;/span&gt;.create(&lt;span class=&quot;Keyword&quot;&gt;ExampleGinjector&lt;/span&gt;.&lt;span class=&quot;Keyword&quot;&gt;class&lt;/span&gt;);

    &lt;span class=&quot;Keyword&quot;&gt;PlacesService&lt;/span&gt; placeService = injector.getPlacesService();
    placeService.bind();

    &lt;span class=&quot;Keyword&quot;&gt;PlacesPresenter&lt;/span&gt; placesPresenter = injector.getPlacesPresenter();
    placesPresenter.bind();
    &lt;span class=&quot;Keyword&quot;&gt;RootPanel&lt;/span&gt;.get().add(placesPresenter.getView().getViewWidget());
    placesPresenter.show();
  }

}
&lt;/pre&gt;&lt;/div&gt;&lt;h2&gt;EOF&lt;/h2&gt;
&lt;p&gt;I hope this will help someone at least a bit to understand this approach of GWT History management in general and use of &lt;code&gt;PlacesService&lt;/code&gt;. I&amp;#8217;ve spent a lot of time trying to come up with some simple and useful history management guidelines for my projects and this is best approach I&amp;#8217;m using with good results.&lt;/p&gt;
&lt;p&gt;One more time few links:&lt;/p&gt;
&lt;ul&gt;
	&lt;li&gt;&lt;a href=&quot;http://history.latest.ampatspell-test.appspot.com/&quot;&gt;PlacesService example application live demo&lt;/a&gt;&lt;/li&gt;
	&lt;li&gt;&lt;a href=&quot;http://bitbucket.org/ampatspell/places/src/&quot;&gt;Places library mercurial repository&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;Questions? Feel free to mail me directly to email address which can be found in&amp;nbsp;&lt;a href=&quot;/about.html&quot;&gt;about section&lt;/a&gt;.&lt;/p&gt;</content>
</entry>


  <entry>
  <title>Mercurial Branch in Bash Prompt</title>
  <link href="/articles/2010/01/28/mercurial-branch-in-bash-prompt.html" />
  <id>tag:www.amateurinmotion.com,2010-01-28:1264674536</id>
  <updated>2010-01-28T12:28:56+02:00</updated>
  <content type="html">&lt;p&gt;Git has nice bash function for showing current branch and status in bash prompt. Here is the branch only version for Mercurial:&lt;/p&gt;
&lt;p&gt;&lt;img src=&quot;http://www.amateurinmotion.com/articles/2010/01/28/hg_branch.png&quot; class=&quot;clean nomargin  &quot; title=&quot;hg_branch.png&quot; alt=&quot;hg_branch.png&quot;/&gt;&lt;/p&gt;
&lt;div class=&quot;uv&quot;&gt;&lt;pre class=&quot;lazy&quot;&gt;
__hg_ps1 ()
{
  if [ &amp;quot;$(hg root 2&amp;gt; /dev/null)&amp;quot; ]; then
    printf &amp;quot;$1&amp;quot; &amp;quot;$(hg branch)&amp;quot;
  fi
}

export PS1='\u:\w$(__hg_ps1 &amp;quot; (%s)\$ '
&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;and &lt;code&gt;PS1&lt;/code&gt; version with &lt;a href=&quot;http://tldp.org/HOWTO/Bash-Prompt-HOWTO/x329.html&quot;&gt;colors&lt;/a&gt;:&lt;/p&gt;
&lt;div class=&quot;uv&quot;&gt;&lt;pre class=&quot;lazy&quot;&gt;
export PS1='\u:\w$(__hg_ps1 &amp;quot; \[\033[1;31m\](%s)\[\033[0m\]&amp;quot;)\$ '
&lt;/pre&gt;&lt;/div&gt;</content>
</entry>


  <entry>
  <title>GWT History Management</title>
  <link href="/articles/2010/01/17/gwt-history-management.html" />
  <id>tag:www.amateurinmotion.com,2010-01-17:1263763766</id>
  <updated>2010-01-17T23:29:26+02:00</updated>
  <content type="html">&lt;p&gt;This is a first post in two post series about one history management approach for non-trivial &lt;a href=&quot;http://code.google.com/webtoolkit/&quot;&gt;GWT&lt;/a&gt; applications. This approach I deem &lt;em&gt;done right&lt;/em&gt; (in contrast to &lt;i&gt;good enough&lt;/i&gt;).&lt;/p&gt;
&lt;p&gt;In the following I assume that general application architecture follows &lt;a href=&quot;http://code.google.com/webtoolkit/doc/latest/tutorial/mvp-architecture.html&quot;&gt;MVP&lt;/a&gt; (or similar) design and uses some global event or notification system (for example &lt;a href=&quot;http://bitbucket.org/ampatspell/bones/src/tip/bones-core-client/src/main/java/com/ampatspell/bones/core/client/event/EventBus.java&quot;&gt;&lt;code&gt;EventBus&lt;/code&gt;&lt;/a&gt; based on &lt;a href=&quot;http://google-web-toolkit.googlecode.com/svn/javadoc/2.0/com/google/gwt/event/shared/HandlerManager.html&quot;&gt;&lt;code&gt;HandlerManager&lt;/code&gt;&lt;/a&gt; or something similar to &lt;a href=&quot;http://developer.apple.com/mac/library/documentation/Cocoa/Reference/Foundation/Classes/NSNotificationCenter_Class/Reference/Reference.html&quot;&gt;&lt;code&gt;NSNotificationCenter&lt;/code&gt;&lt;/a&gt;) used in Cocoa applications. Examples has &lt;a href=&quot;http://code.google.com/p/google-gin/&quot;&gt;GIN&lt;/a&gt; annotations where appropriate.&lt;/p&gt;
&lt;h2&gt;Fictional Application&lt;/h2&gt;
&lt;p&gt;Lets agree on one concrete application as a basis of discussion of history and places.&lt;/p&gt;
&lt;p&gt;&lt;a href=&quot;http://history.latest.ampatspell-test.appspot.com/#/person/zeeba/show&quot;&gt;&lt;img src=&quot;http://www.amateurinmotion.com/articles/2010/01/17/history-1/01.png&quot; class=&quot;clean nomargin  &quot; title=&quot;history-1/01.png&quot; alt=&quot;history-1/01.png&quot;/&gt;&lt;/a&gt;&lt;/p&gt;
&lt;p&gt;The application consists of two sections (managed by &amp;#8220;root&amp;#8221; &lt;a href=&quot;http://bitbucket.org/ampatspell/places/src/tip/places-example-gwt/src/main/java/com/ampatspell/places/example/client/workspace/WorkspacePresenterImpl.java&quot;&gt;&lt;code&gt;WorkspacePresenter&lt;/code&gt;&lt;/a&gt;) that are represented with two top tabs, each section has root presenter and people section has nested child presenters:&lt;/p&gt;
&lt;table&gt;
	&lt;tr&gt;
		&lt;th&gt;Section &lt;/th&gt;
		&lt;th&gt;Container &lt;/th&gt;
		&lt;th&gt;Presenter   &lt;/th&gt;
	&lt;/tr&gt;
	&lt;tr&gt;
		&lt;td&gt; Index     &lt;/td&gt;
		&lt;td&gt;   Content   &lt;/td&gt;
		&lt;td&gt;   &lt;a href=&quot;http://bitbucket.org/ampatspell/places/src/121c06b7ec8b/places-example-gwt/src/main/java/com/ampatspell/places/example/client/workspace/section/index/IndexPresenterImpl.java&quot;&gt;Index&lt;/a&gt; &lt;/td&gt;
	&lt;/tr&gt;
	&lt;tr&gt;
		&lt;td rowspan=&quot;4&quot;&gt;People &lt;/td&gt;
		&lt;td&gt;   Master    &lt;/td&gt;
		&lt;td&gt;   &lt;a href=&quot;http://bitbucket.org/ampatspell/places/src/121c06b7ec8b/places-example-gwt/src/main/java/com/ampatspell/places/example/client/workspace/section/people/master/list/ListPresenterImpl.java&quot;&gt;Person list&lt;/a&gt; &lt;/td&gt;
	&lt;/tr&gt;
	&lt;tr&gt;
		&lt;td rowspan=&quot;3&quot;&gt;Detail    &lt;/td&gt;
		&lt;td&gt;   &lt;a href=&quot;http://bitbucket.org/ampatspell/places/src/121c06b7ec8b/places-example-gwt/src/main/java/com/ampatspell/places/example/client/workspace/section/people/detail/blank/BlankPresenterImpl.java&quot;&gt;Blank&lt;/a&gt;       &lt;/td&gt;
	&lt;/tr&gt;
	&lt;tr&gt;
		&lt;td&gt;                             &lt;a href=&quot;http://bitbucket.org/ampatspell/places/src/121c06b7ec8b/places-example-gwt/src/main/java/com/ampatspell/places/example/client/workspace/section/people/detail/show/ShowPresenterImpl.java&quot;&gt;Show person&lt;/a&gt; &lt;/td&gt;
	&lt;/tr&gt;
	&lt;tr&gt;
		&lt;td&gt;                             &lt;a href=&quot;http://bitbucket.org/ampatspell/places/src/121c06b7ec8b/places-example-gwt/src/main/java/com/ampatspell/places/example/client/workspace/section/people/detail/edit/EditPresenterImpl.java&quot;&gt;Edit person&lt;/a&gt; &lt;/td&gt;
	&lt;/tr&gt;
&lt;/table&gt;
&lt;p&gt;Screen shot is shows People section with &amp;#8220;Show person&amp;#8221; detail presenter open, linked site uses &lt;a href=&quot;http://bitbucket.org/ampatspell/places/src/&quot;&gt;Places library&lt;/a&gt; (see &lt;strong&gt;&amp;#8220;Terrible Footnote&amp;#8221;&lt;/strong&gt; below, but basic concepts described here apply).&lt;/p&gt;
&lt;h2&gt;History token &amp;#8212; Place&lt;/h2&gt;
&lt;p&gt;From previous table we can gather a list of application states where permanent links (using history token) are needed. Lets call those states &lt;strong&gt;places&lt;/strong&gt;.&lt;/p&gt;
&lt;table&gt;
	&lt;tr&gt;
		&lt;th&gt;Section    &lt;/th&gt;
		&lt;th&gt;State                  &lt;/th&gt;
		&lt;th&gt;History token / Place pattern &lt;/th&gt;
	&lt;/tr&gt;
	&lt;tr&gt;
		&lt;td&gt; Index        &lt;/td&gt;
		&lt;td&gt; &amp;#8212;                       &lt;/td&gt;
		&lt;td&gt; /index                          &lt;/td&gt;
	&lt;/tr&gt;
	&lt;tr&gt;
		&lt;td rowspan=&quot;3&quot;&gt;People    &lt;/td&gt;
		&lt;td&gt; No person selected       &lt;/td&gt;
		&lt;td&gt; /people                         &lt;/td&gt;
	&lt;/tr&gt;
	&lt;tr&gt;
		&lt;td&gt;                Showing person           &lt;/td&gt;
		&lt;td&gt; /person/&lt;strong&gt;{key}&lt;/strong&gt;/show &lt;sup&gt;1&lt;/sup&gt;        &lt;/td&gt;
	&lt;/tr&gt;
	&lt;tr&gt;
		&lt;td&gt;                Showing edit person form &lt;/td&gt;
		&lt;td&gt; /person/&lt;strong&gt;{key}&lt;/strong&gt;/edit &lt;sup&gt;1&lt;/sup&gt;        &lt;/td&gt;
	&lt;/tr&gt;
&lt;/table&gt;
&lt;p&gt;&lt;sup&gt;1&lt;/sup&gt; where &lt;strong&gt;{key}&lt;/strong&gt; is Person model primary key.&lt;/p&gt;
&lt;p&gt;In GWT the history management can be implemented using &lt;a href=&quot;http://google-web-toolkit.googlecode.com/svn/javadoc/2.0/com/google/gwt/user/client/History.html&quot;&gt;&lt;code&gt;History&lt;/code&gt;&lt;/a&gt; singleton class what manages the part of the URL that comes after &lt;strong&gt;#&lt;/strong&gt;. It allows us to:&lt;/p&gt;
&lt;ul&gt;
	&lt;li&gt;register to token value changes,&lt;/li&gt;
	&lt;li&gt;change token (that will fire value change event) and&lt;/li&gt;
	&lt;li&gt;fire current token state.&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;When &lt;code&gt;History#fireCurrentHistoryState()&lt;/code&gt; is called, it notifies handlers about new token value. Token itself is a String that can be parsed and reacted upon (think routes in Rails applications or Servlet mapping in web.xml).&lt;/p&gt;
&lt;p&gt;This can be done in &lt;code&gt;HistoryService&lt;/code&gt; class that must know about each and every history token pattern used in application and should be able to react on them. This way it is easy to implement &lt;a href=&quot;http://code.google.com/webtoolkit/doc/latest/DevGuideCodeSplitting.html&quot;&gt;GWT.runAsync&lt;/a&gt; based application code splitting where application initial download contains only &lt;code&gt;HistoryService&lt;/code&gt; and &lt;a href=&quot;/articles/2009/11/02/async-with-gin.html&quot;&gt;split point loaders&lt;/a&gt; that initiates additional code loading when needed.&lt;/p&gt;
&lt;h2&gt;SimpleHistoryManager&lt;/h2&gt;
&lt;p&gt;Lets take a look at &lt;code&gt;History&lt;/code&gt; manager simplified implementation (in next blog post this class will be replaced with sane implementation, other concepts still apply):&lt;/p&gt;
&lt;div class=&quot;uv&quot;&gt;&lt;pre class=&quot;lazy&quot;&gt;
@&lt;span class=&quot;Keyword&quot;&gt;Singleton&lt;/span&gt;
&lt;span class=&quot;Keyword&quot;&gt;public &lt;/span&gt;&lt;span class=&quot;Keyword&quot;&gt;class&lt;/span&gt; &lt;span class=&quot;Entity&quot;&gt;SimpleHistoryManager&lt;/span&gt; &lt;span class=&quot;Keyword&quot;&gt;implements&lt;/span&gt; &lt;span class=&quot;Keyword&quot;&gt;ValueChangeHandler&lt;/span&gt;&amp;lt;&lt;span class=&quot;Support&quot;&gt;String&lt;/span&gt;&amp;gt; {

  &lt;span class=&quot;Keyword&quot;&gt;private&lt;/span&gt; &lt;span class=&quot;Keyword&quot;&gt;final&lt;/span&gt; &lt;span class=&quot;Keyword&quot;&gt;EventBus&lt;/span&gt; eventBus;

  @&lt;span class=&quot;Keyword&quot;&gt;Inject&lt;/span&gt;
  &lt;span class=&quot;Keyword&quot;&gt;public &lt;/span&gt;&lt;span class=&quot;Entity&quot;&gt;SimpleHistoryManager&lt;/span&gt;(&lt;span class=&quot;Keyword&quot;&gt;EventBus&lt;/span&gt; eventBus) {
    &lt;span class=&quot;Variable&quot;&gt;this&lt;/span&gt;.eventBus = eventBus;
  }

  &lt;span class=&quot;Keyword&quot;&gt;public &lt;/span&gt;&lt;span class=&quot;Keyword&quot;&gt;void&lt;/span&gt; &lt;span class=&quot;Entity&quot;&gt;bind&lt;/span&gt;() {
    &lt;span class=&quot;Keyword&quot;&gt;History&lt;/span&gt;.addValueChangeHandler(&lt;span class=&quot;Variable&quot;&gt;this&lt;/span&gt;);
    &lt;span class=&quot;Keyword&quot;&gt;History&lt;/span&gt;.fireCurrentHistoryState();
  }

  &lt;span class=&quot;Keyword&quot;&gt;public &lt;/span&gt;&lt;span class=&quot;Keyword&quot;&gt;void&lt;/span&gt; &lt;span class=&quot;Entity&quot;&gt;onValueChange&lt;/span&gt;(&lt;span class=&quot;Keyword&quot;&gt;ValueChangeEvent&lt;/span&gt;&amp;lt;&lt;span class=&quot;Support&quot;&gt;String&lt;/span&gt;&amp;gt; stringValueChangeEvent) {
    &lt;span class=&quot;Support&quot;&gt;String&lt;/span&gt; token = stringValueChangeEvent.getValue();
    onTokenChanged(token);
  }

  &lt;span class=&quot;Keyword&quot;&gt;private &lt;/span&gt;&lt;span class=&quot;Keyword&quot;&gt;void&lt;/span&gt; &lt;span class=&quot;Entity&quot;&gt;onTokenChanged&lt;/span&gt;(&lt;span class=&quot;Support&quot;&gt;String&lt;/span&gt; token) {
    &lt;span class=&quot;Keyword&quot;&gt;if&lt;/span&gt; (token.equals(&lt;span class=&quot;String&quot;&gt;&lt;span class=&quot;String&quot;&gt;&amp;quot;&lt;/span&gt;/index&lt;span class=&quot;String&quot;&gt;&amp;quot;&lt;/span&gt;&lt;/span&gt;) &lt;span class=&quot;Keyword&quot;&gt;||&lt;/span&gt; token.equals(&lt;span class=&quot;String&quot;&gt;&lt;span class=&quot;String&quot;&gt;&amp;quot;&lt;/span&gt;&lt;span class=&quot;String&quot;&gt;&amp;quot;&lt;/span&gt;&lt;/span&gt;)) {
      showIndexSection();
    } &lt;span class=&quot;Keyword&quot;&gt;else&lt;/span&gt; &lt;span class=&quot;Keyword&quot;&gt;if&lt;/span&gt; (token.equals(&lt;span class=&quot;String&quot;&gt;&lt;span class=&quot;String&quot;&gt;&amp;quot;&lt;/span&gt;/people&lt;span class=&quot;String&quot;&gt;&amp;quot;&lt;/span&gt;&lt;/span&gt;)) {
      showPeopleSection();
    } &lt;span class=&quot;Keyword&quot;&gt;else&lt;/span&gt; &lt;span class=&quot;Keyword&quot;&gt;if&lt;/span&gt; (token.startsWith(&lt;span class=&quot;String&quot;&gt;&lt;span class=&quot;String&quot;&gt;&amp;quot;&lt;/span&gt;/person/&lt;span class=&quot;String&quot;&gt;&amp;quot;&lt;/span&gt;&lt;/span&gt;)) {
      &lt;span class=&quot;Support&quot;&gt;String&lt;/span&gt;[] array = token.split(&lt;span class=&quot;String&quot;&gt;&lt;span class=&quot;String&quot;&gt;&amp;quot;&lt;/span&gt;/&lt;span class=&quot;String&quot;&gt;&amp;quot;&lt;/span&gt;&lt;/span&gt;);
      &lt;span class=&quot;Support&quot;&gt;String&lt;/span&gt; key = array[&lt;span class=&quot;Constant&quot;&gt;2&lt;/span&gt;];
      &lt;span class=&quot;Support&quot;&gt;String&lt;/span&gt; action = array[&lt;span class=&quot;Constant&quot;&gt;3&lt;/span&gt;];

      &lt;span class=&quot;Keyword&quot;&gt;if&lt;/span&gt; (action.equals(&lt;span class=&quot;String&quot;&gt;&lt;span class=&quot;String&quot;&gt;&amp;quot;&lt;/span&gt;/show&lt;span class=&quot;String&quot;&gt;&amp;quot;&lt;/span&gt;&lt;/span&gt;)) {
        showPerson(key);
      } &lt;span class=&quot;Keyword&quot;&gt;else&lt;/span&gt; &lt;span class=&quot;Keyword&quot;&gt;if&lt;/span&gt; (action.equals(&lt;span class=&quot;String&quot;&gt;&lt;span class=&quot;String&quot;&gt;&amp;quot;&lt;/span&gt;/edit&lt;span class=&quot;String&quot;&gt;&amp;quot;&lt;/span&gt;&lt;/span&gt;)) {
        showEditPerson(key);
      }
    }
  }

  &lt;span class=&quot;Keyword&quot;&gt;private &lt;/span&gt;&lt;span class=&quot;Keyword&quot;&gt;void&lt;/span&gt; &lt;span class=&quot;Entity&quot;&gt;showIndexSection&lt;/span&gt;() {
  }

  &lt;span class=&quot;Keyword&quot;&gt;private &lt;/span&gt;&lt;span class=&quot;Keyword&quot;&gt;void&lt;/span&gt; &lt;span class=&quot;Entity&quot;&gt;showPeopleSection&lt;/span&gt;() {
  }

  &lt;span class=&quot;Keyword&quot;&gt;private &lt;/span&gt;&lt;span class=&quot;Keyword&quot;&gt;void&lt;/span&gt; &lt;span class=&quot;Entity&quot;&gt;showPerson&lt;/span&gt;(&lt;span class=&quot;Support&quot;&gt;String&lt;/span&gt; key) {
  }

  &lt;span class=&quot;Keyword&quot;&gt;private &lt;/span&gt;&lt;span class=&quot;Keyword&quot;&gt;void&lt;/span&gt; &lt;span class=&quot;Entity&quot;&gt;showEditPerson&lt;/span&gt;(&lt;span class=&quot;Support&quot;&gt;String&lt;/span&gt; key) {
  }

}
&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;When &lt;code&gt;bind()&lt;/code&gt; is called, the instance registers itself as token value change handler and fires first value change event which in turn invokes &lt;code&gt;onTokenChanged()&lt;/code&gt; for the first time in application current life cycle. &lt;code&gt;onTokenChanged&lt;/code&gt; parses (parsing is incomplete and without any error handling) token string and delegates actual work to methods listed below. Fine, what&amp;#8217;s next?&lt;/p&gt;
&lt;p&gt;Events.&lt;/p&gt;
&lt;p&gt;To presenter &amp;#8220;Index section&amp;#8221;:&lt;/p&gt;
&lt;ul&gt;
	&lt;li&gt;&lt;code&gt;WorkspacePresenter&lt;/code&gt; must show &lt;code&gt;IndexPresenter&lt;/code&gt; by setting &lt;code&gt;IndexPresenter#getView()&lt;/code&gt; to it&amp;#8217;s &lt;code&gt;View#setContentView(BaseView)&lt;/code&gt;,&lt;/li&gt;
	&lt;li&gt;&lt;code&gt;MenuPresenter&lt;/code&gt; must set &amp;#8220;index&amp;#8221; as active menu item.&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;Menu is easy:&lt;/p&gt;
&lt;div class=&quot;uv&quot;&gt;&lt;pre class=&quot;lazy&quot;&gt;
eventBus.fireEvent(&lt;span class=&quot;Keyword&quot;&gt;new&lt;/span&gt; &lt;span class=&quot;Keyword&quot;&gt;MenuSetActiveEvent&lt;/span&gt;(&lt;span class=&quot;String&quot;&gt;&lt;span class=&quot;String&quot;&gt;&amp;quot;&lt;/span&gt;index&lt;span class=&quot;String&quot;&gt;&amp;quot;&lt;/span&gt;&lt;/span&gt;));
&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;But before we implement &lt;code&gt;WorkspacePresenter&lt;/code&gt; &amp;#8212; &lt;code&gt;IndexPresenter&lt;/code&gt; relations we have one design decision to make about Presenter hierarchy.&lt;/p&gt;
&lt;h2&gt;Presenter Hierarchy&lt;/h2&gt;
&lt;p&gt;Does &lt;code&gt;WorkspacePresenter&lt;/code&gt; keeps reference to &lt;code&gt;Provider&amp;lt;IndexPresenter&amp;gt;&lt;/code&gt; and all other presenter providers it may need?&lt;/p&gt;
&lt;p&gt;It surely can be done (by using &lt;code&gt;SectionService#getSectionByKey(String)&lt;/code&gt; or something like that) but it unnecessary complicates presenter and sometimes makes it harder to implement history support and &lt;code&gt;GWT.runAsync&lt;/code&gt;&amp;#8217;able code splitting. Instead of &lt;code&gt;WorkspacePresenter&lt;/code&gt; (and presenters in general), &lt;code&gt;HistoryManager&lt;/code&gt; should manage &lt;strong&gt;dynamic&lt;/strong&gt; presenter hierarchy. By dynamic I mean those child presenters that can be replaced by different presenters in application runtime in contrast to &lt;strong&gt;static&lt;/strong&gt; ones that can be safely bound in parent &amp;#8212; for example &lt;code&gt;MenuPresenter&lt;/code&gt; and &lt;code&gt;LogPresenter&lt;/code&gt; is bound directly in &lt;a href=&quot;http://bitbucket.org/ampatspell/places/src/tip/places-example-gwt/src/main/java/com/ampatspell/places/example/client/workspace/WorkspacePresenterImpl.java&quot;&gt;WorkspacePresenterImpl&lt;/a&gt;.&lt;/p&gt;
&lt;p&gt;So now we need an event that &lt;code&gt;SimpleHistoryManager&lt;/code&gt; fires and &lt;code&gt;WorkspacePresenter&lt;/code&gt; handles, gets &lt;code&gt;Presenter&lt;/code&gt; instance from it, calls &lt;code&gt;bind()&lt;/code&gt; and sets in its own &lt;code&gt;View&lt;/code&gt; as sub-view:&lt;/p&gt;
&lt;div class=&quot;uv&quot;&gt;&lt;pre class=&quot;lazy&quot;&gt;
&lt;span class=&quot;Keyword&quot;&gt;BasePresenter&lt;/span&gt;&lt;span class=&quot;Keyword&quot;&gt;&amp;lt;&lt;/span&gt;?&lt;span class=&quot;Keyword&quot;&gt;&amp;gt;&lt;/span&gt; indexPresenter = ...;
eventBus.fireEvent(&lt;span class=&quot;Keyword&quot;&gt;new&lt;/span&gt; &lt;span class=&quot;Keyword&quot;&gt;WorkspaceSetContentEvent&lt;/span&gt;(indexPresenter));
&lt;/pre&gt;&lt;/div&gt;&lt;div class=&quot;uv&quot;&gt;&lt;pre class=&quot;lazy&quot;&gt;
&lt;span class=&quot;Keyword&quot;&gt;public &lt;/span&gt;&lt;span class=&quot;Keyword&quot;&gt;void&lt;/span&gt; &lt;span class=&quot;Entity&quot;&gt;onWorkspaceSetContent&lt;/span&gt;(final &lt;span class=&quot;Keyword&quot;&gt;WorkspaceSetContentEvent&lt;/span&gt; event) {
  setContent(event.getPresenter());
}

&lt;span class=&quot;Keyword&quot;&gt;public &lt;/span&gt;&lt;span class=&quot;Keyword&quot;&gt;void&lt;/span&gt; &lt;span class=&quot;Entity&quot;&gt;setPresenter&lt;/span&gt;(&lt;span class=&quot;Keyword&quot;&gt;BasePresenter&lt;/span&gt;&amp;lt;?&amp;gt; presenter) {
  presenter.bind();
  view.setContentView(presenter.getView());
  presenter.show();
}
&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;But there is one small caveat with &lt;code&gt;HandlerManager&lt;/code&gt; which nearly always is used as &lt;code&gt;EventBus&lt;/code&gt; implementation. &lt;code&gt;WorkspacePresenter&lt;/code&gt; content &lt;code&gt;Presenter&lt;/code&gt; may register itself to &lt;code&gt;@Singleton EventBus&lt;/code&gt; as an event handler. But if event handler is added to &lt;code&gt;HandlerManager&lt;/code&gt; &lt;em&gt;inside&lt;/em&gt; fired event from the same &lt;code&gt;HandlerManager&lt;/code&gt;, that handler will be live only &lt;em&gt;after&lt;/em&gt; original event handler has returned.&lt;/p&gt;
&lt;p&gt;Basically it means that:&lt;/p&gt;
&lt;div class=&quot;uv&quot;&gt;&lt;pre class=&quot;lazy&quot;&gt;
eventBus.addHandler(&lt;span class=&quot;Keyword&quot;&gt;WorkspaceSetContentEvent&lt;/span&gt;.getType(), &lt;span class=&quot;Keyword&quot;&gt;new&lt;/span&gt; &lt;span class=&quot;Keyword&quot;&gt;WorkspaceSetContentHandler&lt;/span&gt;() {
  &lt;span class=&quot;Keyword&quot;&gt;public &lt;/span&gt;&lt;span class=&quot;Keyword&quot;&gt;void&lt;/span&gt; &lt;span class=&quot;Entity&quot;&gt;onWorkspaceSetContent&lt;/span&gt;(&lt;span class=&quot;Keyword&quot;&gt;WorkspaceSetContentEvent&lt;/span&gt; event) {

    &lt;span class=&quot;Comment&quot;&gt;&lt;span class=&quot;Comment&quot;&gt;//&lt;/span&gt; this handler will handle PersonShowEvent only after this &lt;/span&gt;
    &lt;span class=&quot;Comment&quot;&gt;&lt;span class=&quot;Comment&quot;&gt;//&lt;/span&gt; WorkspaceSetContentEvent handler will return&lt;/span&gt;
    eventBus.addHandler(&lt;span class=&quot;Keyword&quot;&gt;PersonShowEvent&lt;/span&gt;.getType(), &lt;span class=&quot;Keyword&quot;&gt;new&lt;/span&gt; &lt;span class=&quot;Keyword&quot;&gt;PersonShowHandler&lt;/span&gt;() {
      &lt;span class=&quot;Keyword&quot;&gt;public &lt;/span&gt;&lt;span class=&quot;Keyword&quot;&gt;void&lt;/span&gt; &lt;span class=&quot;Entity&quot;&gt;onPersonShow&lt;/span&gt;(&lt;span class=&quot;Keyword&quot;&gt;PersonShowEvent&lt;/span&gt; event) {
      }
    });

    &lt;span class=&quot;Comment&quot;&gt;&lt;span class=&quot;Comment&quot;&gt;//&lt;/span&gt; this event won't be handled by previous handler&lt;/span&gt;
    eventBus.fireEvent(&lt;span class=&quot;Keyword&quot;&gt;new&lt;/span&gt; &lt;span class=&quot;Keyword&quot;&gt;PersonShowEvent&lt;/span&gt;(&lt;span class=&quot;String&quot;&gt;&lt;span class=&quot;String&quot;&gt;&amp;quot;&lt;/span&gt;foo&lt;span class=&quot;String&quot;&gt;&amp;quot;&lt;/span&gt;&lt;/span&gt;));
  }
});
&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;To overcome this we need small design pattern. I&amp;#8217;ll even give it a fancy name.&lt;/p&gt;
&lt;h2&gt;On-Ready Event Callback&lt;/h2&gt;
&lt;p&gt;Simply put it is an &lt;code&gt;GwtEvent&lt;/code&gt; with additional &lt;code&gt;Command&lt;/code&gt; parameter. This &lt;code&gt;Command&lt;/code&gt; callback &lt;em&gt;must&lt;/em&gt; be called when presenter&amp;#8217;s &lt;code&gt;bind()&lt;/code&gt; is called &lt;em&gt;and&lt;/em&gt; bound presenter is ready to handle events (by using &lt;a href=&quot;http://google-web-toolkit.googlecode.com/svn/javadoc/2.0/com/google/gwt/user/client/DeferredCommand.html&quot;&gt;&lt;code&gt;DeferredCommand&lt;/code&gt;&lt;/a&gt; if needed).&lt;/p&gt;
&lt;div class=&quot;uv&quot;&gt;&lt;pre class=&quot;lazy&quot;&gt;
&lt;span class=&quot;Keyword&quot;&gt;public &lt;/span&gt;&lt;span class=&quot;Keyword&quot;&gt;class&lt;/span&gt; &lt;span class=&quot;Entity&quot;&gt;WorkspaceSetContentEvent&lt;/span&gt; &lt;span class=&quot;Keyword&quot;&gt;extends&lt;/span&gt; &lt;span class=&quot;Keyword&quot;&gt;GwtEvent&lt;/span&gt;&amp;lt;&lt;span class=&quot;Keyword&quot;&gt;WorkspaceSetContentHandler&lt;/span&gt;&amp;gt; {

  &lt;span class=&quot;Comment&quot;&gt;&lt;span class=&quot;Comment&quot;&gt;//&lt;/span&gt; TYPE, ivars removed -- less noise&lt;/span&gt;

  &lt;span class=&quot;Keyword&quot;&gt;public &lt;/span&gt;&lt;span class=&quot;Entity&quot;&gt;WorkspaceSetContentEvent&lt;/span&gt;(&lt;span class=&quot;Keyword&quot;&gt;PresenterProvider&lt;/span&gt;&amp;lt;?&amp;gt; presenter, &lt;span class=&quot;Keyword&quot;&gt;Command&lt;/span&gt; callback) {
    &lt;span class=&quot;Variable&quot;&gt;this&lt;/span&gt;.presenter = presenter;
    &lt;span class=&quot;Variable&quot;&gt;this&lt;/span&gt;.callback = callback;
  }

  &lt;span class=&quot;Keyword&quot;&gt;public&lt;/span&gt; &lt;span class=&quot;Keyword&quot;&gt;PresenterProvider&lt;/span&gt;&lt;span class=&quot;Keyword&quot;&gt;&amp;lt;&lt;/span&gt;?&lt;span class=&quot;Keyword&quot;&gt;&amp;gt;&lt;/span&gt; getPresenter() {
    &lt;span class=&quot;Keyword&quot;&gt;return&lt;/span&gt; presenter;
  }

  &lt;span class=&quot;Keyword&quot;&gt;public &lt;/span&gt;&lt;span class=&quot;Keyword&quot;&gt;Command&lt;/span&gt; &lt;span class=&quot;Entity&quot;&gt;getCallback&lt;/span&gt;() {
    &lt;span class=&quot;Keyword&quot;&gt;return&lt;/span&gt; callback;
  }

}
&lt;/pre&gt;&lt;/div&gt;&lt;p class=&quot;light&quot;&gt;See &lt;a href=&quot;http://bitbucket.org/ampatspell/places/src/121c06b7ec8b/places-example-gwt/src/main/java/com/ampatspell/places/example/client/workspace/event/WorkspaceSetContentEvent.java&quot;&gt;WorkspaceSetContentEvent&lt;/a&gt; for full source code of this Event.&lt;/p&gt;
&lt;p&gt;Lets ignore &lt;code&gt;PresenterProvider&lt;/code&gt; interface for a moment &amp;#8212; it needs it&amp;#8217;s own small section.&lt;/p&gt;
&lt;p&gt;Now we can implement all &lt;code&gt;SimpleHandlerManager#show*&lt;/code&gt; methods:&lt;/p&gt;
&lt;div class=&quot;uv&quot;&gt;&lt;pre class=&quot;lazy&quot;&gt;
&lt;span class=&quot;Keyword&quot;&gt;private &lt;/span&gt;&lt;span class=&quot;Keyword&quot;&gt;void&lt;/span&gt; &lt;span class=&quot;Entity&quot;&gt;showIndexSection&lt;/span&gt;() {
  fireMenuSetActive(&lt;span class=&quot;String&quot;&gt;&lt;span class=&quot;String&quot;&gt;&amp;quot;&lt;/span&gt;index&lt;span class=&quot;String&quot;&gt;&amp;quot;&lt;/span&gt;&lt;/span&gt;);
  fireWorkspaceSetContent(indexPresenterProvider, &lt;span class=&quot;Constant&quot;&gt;null&lt;/span&gt;);
}

&lt;span class=&quot;Keyword&quot;&gt;private &lt;/span&gt;&lt;span class=&quot;Keyword&quot;&gt;void&lt;/span&gt; &lt;span class=&quot;Entity&quot;&gt;showPeopleSection&lt;/span&gt;() {
  showPeopleSection(blankPresenterProvider, &lt;span class=&quot;Constant&quot;&gt;null&lt;/span&gt;, &lt;span class=&quot;Constant&quot;&gt;null&lt;/span&gt;);
}

&lt;span class=&quot;Keyword&quot;&gt;private &lt;/span&gt;&lt;span class=&quot;Keyword&quot;&gt;void&lt;/span&gt; &lt;span class=&quot;Entity&quot;&gt;showPerson&lt;/span&gt;(final &lt;span class=&quot;Support&quot;&gt;String&lt;/span&gt; key) {
  &lt;span class=&quot;Entity&quot;&gt;showPeopleSection&lt;/span&gt;(showPresenterProvider, key, new &lt;span class=&quot;Keyword&quot;&gt;Command&lt;/span&gt;() {
    &lt;span class=&quot;Keyword&quot;&gt;public &lt;/span&gt;&lt;span class=&quot;Keyword&quot;&gt;void&lt;/span&gt; &lt;span class=&quot;Entity&quot;&gt;execute&lt;/span&gt;() {
      eventBus.fireEvent(&lt;span class=&quot;Keyword&quot;&gt;new&lt;/span&gt; &lt;span class=&quot;Keyword&quot;&gt;PersonShowEvent&lt;/span&gt;(key));
    }
  });
}

&lt;span class=&quot;Keyword&quot;&gt;private &lt;/span&gt;&lt;span class=&quot;Keyword&quot;&gt;void&lt;/span&gt; &lt;span class=&quot;Entity&quot;&gt;showEditPerson&lt;/span&gt;(final &lt;span class=&quot;Support&quot;&gt;String&lt;/span&gt; key) {
  &lt;span class=&quot;Entity&quot;&gt;showPeopleSection&lt;/span&gt;(editPresenterProvider, key, new &lt;span class=&quot;Keyword&quot;&gt;Command&lt;/span&gt;() {
    &lt;span class=&quot;Keyword&quot;&gt;public &lt;/span&gt;&lt;span class=&quot;Keyword&quot;&gt;void&lt;/span&gt; &lt;span class=&quot;Entity&quot;&gt;execute&lt;/span&gt;() {
      eventBus.fireEvent(&lt;span class=&quot;Keyword&quot;&gt;new&lt;/span&gt; &lt;span class=&quot;Keyword&quot;&gt;PersonEditEvent&lt;/span&gt;(key));
    }
  });
}

&lt;span class=&quot;Keyword&quot;&gt;private &lt;/span&gt;&lt;span class=&quot;Keyword&quot;&gt;void&lt;/span&gt; &lt;span class=&quot;Entity&quot;&gt;showPeopleSection&lt;/span&gt;(final &lt;span class=&quot;Keyword&quot;&gt;PresenterProvider&lt;/span&gt;&amp;lt;?&amp;gt; content, final &lt;span class=&quot;Support&quot;&gt;String&lt;/span&gt; key, 
    final &lt;span class=&quot;Keyword&quot;&gt;Command&lt;/span&gt; command) {
    
  fireMenuSetActive(&lt;span class=&quot;String&quot;&gt;&lt;span class=&quot;String&quot;&gt;&amp;quot;&lt;/span&gt;people&lt;span class=&quot;String&quot;&gt;&amp;quot;&lt;/span&gt;&lt;/span&gt;);
  &lt;span class=&quot;Entity&quot;&gt;fireWorkspaceSetContent&lt;/span&gt;(peoplePresenterProvider, new &lt;span class=&quot;Keyword&quot;&gt;Command&lt;/span&gt;() {
    &lt;span class=&quot;Keyword&quot;&gt;public &lt;/span&gt;&lt;span class=&quot;Keyword&quot;&gt;void&lt;/span&gt; &lt;span class=&quot;Entity&quot;&gt;execute&lt;/span&gt;() {
      eventBus.fireEvent(&lt;span class=&quot;Keyword&quot;&gt;new&lt;/span&gt; &lt;span class=&quot;Keyword&quot;&gt;ListSetActiveEvent&lt;/span&gt;(key));
      eventBus.fireEvent(&lt;span class=&quot;Keyword&quot;&gt;new&lt;/span&gt; &lt;span class=&quot;Keyword&quot;&gt;PeopleSetContentEvent&lt;/span&gt;(content, command));
    }
  });
}

&lt;span class=&quot;Keyword&quot;&gt;private &lt;/span&gt;&lt;span class=&quot;Keyword&quot;&gt;void&lt;/span&gt; &lt;span class=&quot;Entity&quot;&gt;fireMenuSetActive&lt;/span&gt;(&lt;span class=&quot;Support&quot;&gt;String&lt;/span&gt; key) {
  eventBus.fireEvent(&lt;span class=&quot;Keyword&quot;&gt;new&lt;/span&gt; &lt;span class=&quot;Keyword&quot;&gt;MenuSetActiveEvent&lt;/span&gt;(key));
}

&lt;span class=&quot;Keyword&quot;&gt;private &lt;/span&gt;&lt;span class=&quot;Keyword&quot;&gt;void&lt;/span&gt; &lt;span class=&quot;Entity&quot;&gt;fireWorkspaceSetContent&lt;/span&gt;(&lt;span class=&quot;Keyword&quot;&gt;PresenterProvider&lt;/span&gt;&amp;lt;?&amp;gt; presenter, &lt;span class=&quot;Keyword&quot;&gt;Command&lt;/span&gt; command) {
  eventBus.fireEvent(&lt;span class=&quot;Keyword&quot;&gt;new&lt;/span&gt; &lt;span class=&quot;Keyword&quot;&gt;WorkspaceSetContentEvent&lt;/span&gt;(presenter, command));
}
&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;And for example &lt;code&gt;WorkspaceSetContentHanlder&lt;/code&gt; inside &lt;code&gt;WorkspacePresenter&lt;/code&gt; looks like this:&lt;/p&gt;
&lt;div class=&quot;uv&quot;&gt;&lt;pre class=&quot;lazy&quot;&gt;
&lt;span class=&quot;Keyword&quot;&gt;public &lt;/span&gt;&lt;span class=&quot;Keyword&quot;&gt;void&lt;/span&gt; &lt;span class=&quot;Entity&quot;&gt;onWorkspaceSetContent&lt;/span&gt;(final &lt;span class=&quot;Keyword&quot;&gt;WorkspaceSetContentEvent&lt;/span&gt; event) {
  content.set(event.getPresenter(), event.getCallback());
}
&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;Next we need to define what is:&lt;/p&gt;
&lt;ul&gt;
	&lt;li&gt;&lt;code&gt;content&lt;/code&gt; from previous handler code listing,&lt;/li&gt;
	&lt;li&gt;&lt;code&gt;PresenterProvider&amp;lt;P extends BasePresenter&amp;lt;?&amp;gt;&amp;gt;&lt;/code&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;They both forms one simple concept described in next section.&lt;/p&gt;
&lt;h2&gt;PresenterProvider &amp;amp; PresenterSwitch&lt;/h2&gt;
&lt;p&gt;Let&amp;#8217;s start with some reasons behind &lt;code&gt;PresenterProvider&lt;/code&gt; interface and what part it plays in overall architecture. Let&amp;#8217;s return to two place implementations: &amp;#8220;showing person&amp;#8221; and &amp;#8220;showing edit person form&amp;#8221;:&lt;/p&gt;
&lt;div class=&quot;uv&quot;&gt;&lt;pre class=&quot;lazy&quot;&gt;
&lt;span class=&quot;Keyword&quot;&gt;private &lt;/span&gt;&lt;span class=&quot;Keyword&quot;&gt;void&lt;/span&gt; &lt;span class=&quot;Entity&quot;&gt;showPerson&lt;/span&gt;(final &lt;span class=&quot;Support&quot;&gt;String&lt;/span&gt; key) {
  &lt;span class=&quot;Entity&quot;&gt;showPeopleSection&lt;/span&gt;(showPresenterProvider, new &lt;span class=&quot;Keyword&quot;&gt;Command&lt;/span&gt;() {
    &lt;span class=&quot;Keyword&quot;&gt;public &lt;/span&gt;&lt;span class=&quot;Keyword&quot;&gt;void&lt;/span&gt; &lt;span class=&quot;Entity&quot;&gt;execute&lt;/span&gt;() {
      eventBus.fireEvent(&lt;span class=&quot;Keyword&quot;&gt;new&lt;/span&gt; &lt;span class=&quot;Keyword&quot;&gt;PersonShowEvent&lt;/span&gt;(key));
    }
  });
}

&lt;span class=&quot;Keyword&quot;&gt;private &lt;/span&gt;&lt;span class=&quot;Keyword&quot;&gt;void&lt;/span&gt; &lt;span class=&quot;Entity&quot;&gt;showEditPerson&lt;/span&gt;(final &lt;span class=&quot;Support&quot;&gt;String&lt;/span&gt; key) {
  &lt;span class=&quot;Entity&quot;&gt;showPeopleSection&lt;/span&gt;(editPresenterProvider, new &lt;span class=&quot;Keyword&quot;&gt;Command&lt;/span&gt;() {
    &lt;span class=&quot;Keyword&quot;&gt;public &lt;/span&gt;&lt;span class=&quot;Keyword&quot;&gt;void&lt;/span&gt; &lt;span class=&quot;Entity&quot;&gt;execute&lt;/span&gt;() {
      eventBus.fireEvent(&lt;span class=&quot;Keyword&quot;&gt;new&lt;/span&gt; &lt;span class=&quot;Keyword&quot;&gt;PersonEditEvent&lt;/span&gt;(key));
    }
  });
}

&lt;span class=&quot;Keyword&quot;&gt;private &lt;/span&gt;&lt;span class=&quot;Keyword&quot;&gt;void&lt;/span&gt; &lt;span class=&quot;Entity&quot;&gt;showPeopleSection&lt;/span&gt;(final &lt;span class=&quot;Keyword&quot;&gt;PresenterProvider&lt;/span&gt;&amp;lt;?&amp;gt; content, final &lt;span class=&quot;Keyword&quot;&gt;Command&lt;/span&gt; command) {
  fireMenuSetActive(&lt;span class=&quot;String&quot;&gt;&lt;span class=&quot;String&quot;&gt;&amp;quot;&lt;/span&gt;people&lt;span class=&quot;String&quot;&gt;&amp;quot;&lt;/span&gt;&lt;/span&gt;);
  &lt;span class=&quot;Entity&quot;&gt;fireWorkspaceSetContent&lt;/span&gt;(peoplePresenterProvider, new &lt;span class=&quot;Keyword&quot;&gt;Command&lt;/span&gt;() {
    &lt;span class=&quot;Keyword&quot;&gt;public &lt;/span&gt;&lt;span class=&quot;Keyword&quot;&gt;void&lt;/span&gt; &lt;span class=&quot;Entity&quot;&gt;execute&lt;/span&gt;() {
      eventBus.fireEvent(&lt;span class=&quot;Keyword&quot;&gt;new&lt;/span&gt; &lt;span class=&quot;Keyword&quot;&gt;PeopleSetContentEvent&lt;/span&gt;(content, command));
    }
  });
}
&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;As we can see from code, both place implementations sets &lt;code&gt;PeoplePresenter&lt;/code&gt; as &lt;code&gt;WorkspacePresenter&lt;/code&gt; content and only changes &lt;code&gt;PeoplePresenter&lt;/code&gt; content.&lt;/p&gt;
&lt;p&gt;For the time being we have taken into consideration only one of two possible times when &lt;code&gt;History&lt;/code&gt; value change handler is invoked:&lt;/p&gt;
&lt;ul&gt;
	&lt;li&gt;after &lt;code&gt;History.fireCurrentHistoryState()&lt;/code&gt; as a part of &lt;code&gt;EntryPoint#onModuleLoad&lt;/code&gt; invocation,&lt;/li&gt;
	&lt;li&gt;any time after &lt;code&gt;History.newItem(String token)&lt;/code&gt; is called.&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;When application is launched, &lt;code&gt;WorkspacePresenter&lt;/code&gt; content view will be empty. It is History manager responsibility to fill it with requested-by-history-token Presenter-View. But when switching for example from &amp;#8220;Showing person&amp;#8221; to &amp;#8220;Showing edit person form&amp;#8221; places only &lt;code&gt;PersonPresenter&lt;/code&gt; content needs to be switched from &lt;code&gt;ShowPresenter&lt;/code&gt; to &lt;code&gt;EditPresenter&lt;/code&gt;. The &lt;code&gt;WorkspacePresenter&lt;/code&gt; content must not be replaced by new instance of the same &lt;code&gt;PersonPresenter&lt;/code&gt; (otherwise content will blink because of &lt;code&gt;DeferredCommand&lt;/code&gt; that is needed after &lt;code&gt;Presenter#bind()&lt;/code&gt; and just because this is simply plain useless).&lt;/p&gt;
&lt;p&gt;Though &lt;code&gt;SimpleHistoryManager&lt;/code&gt; shouldn&amp;#8217;t and doesn&amp;#8217;t keep track of current presenter hierarchy the decision if &amp;#8220;current&amp;#8221; presenter in all presenter hierarchy levels needs to be done Presenters side because it is easier to implement and allows us to modify presenter hierarchy also without history support if such need arises (as not all application states needs history token).&lt;/p&gt;
&lt;h3&gt;PresenterProvider&lt;/h3&gt;
&lt;p&gt;GIN allows to inject class dependencies in two ways:&lt;/p&gt;
&lt;ul&gt;
	&lt;li&gt;Instance directly&lt;/li&gt;
	&lt;li&gt;Instance via provider (using &lt;code&gt;Provider&amp;lt;T&amp;gt;&lt;/code&gt;)&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;The &lt;code&gt;Provider&amp;lt;T&amp;gt;&lt;/code&gt; interface declaration is:&lt;/p&gt;
&lt;div class=&quot;uv&quot;&gt;&lt;pre class=&quot;lazy&quot;&gt;
&lt;span class=&quot;Keyword&quot;&gt;public &lt;/span&gt;&lt;span class=&quot;Keyword&quot;&gt;interface&lt;/span&gt; &lt;span class=&quot;Entity&quot;&gt;Provider&lt;/span&gt;&amp;lt;T&amp;gt; {
  T get();
}
&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;This interface requires us construct a new &lt;code&gt;Presenter&lt;/code&gt; in order to get the instance class that can be used in comparison between &amp;#8220;current&amp;#8221; Presenter and Presenter which is received as a part of &lt;code&gt;*SetContentEvent&lt;/code&gt;. To remove this possibly unnecessary Presenter construction the minor extension to &lt;code&gt;Provider&amp;lt;T&amp;gt;&lt;/code&gt; interface is needed:&lt;/p&gt;
&lt;div class=&quot;uv&quot;&gt;&lt;pre class=&quot;lazy&quot;&gt;
&lt;span class=&quot;Keyword&quot;&gt;public &lt;/span&gt;&lt;span class=&quot;Keyword&quot;&gt;interface&lt;/span&gt; &lt;span class=&quot;Entity&quot;&gt;PresenterProvider&lt;/span&gt;&amp;lt;P &lt;span class=&quot;Keyword&quot;&gt;extends&lt;/span&gt; &lt;span class=&quot;Keyword&quot;&gt;BasePresenter&lt;/span&gt;&amp;lt;?&amp;gt;&amp;gt; 
  extends &lt;span class=&quot;Support&quot;&gt;Provider&lt;/span&gt;&amp;lt;P&amp;gt;, &lt;span class=&quot;Keyword&quot;&gt;HasInstanceClass&lt;/span&gt; {
}

&lt;span class=&quot;Keyword&quot;&gt;public &lt;/span&gt;&lt;span class=&quot;Keyword&quot;&gt;interface&lt;/span&gt; &lt;span class=&quot;Entity&quot;&gt;HasInstanceClass&lt;/span&gt; {
  &lt;span class=&quot;Support&quot;&gt;Class&lt;/span&gt;&lt;span class=&quot;Keyword&quot;&gt;&amp;lt;&lt;/span&gt;?&lt;span class=&quot;Keyword&quot;&gt;&amp;gt;&lt;/span&gt; getInstanceClass();
}
&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;Then by using &lt;code&gt;PresenterProvider&amp;lt;P&amp;gt;&lt;/code&gt; we can efficiently handle &lt;code&gt;*SetContentEvents&lt;/code&gt;:&lt;/p&gt;
&lt;div class=&quot;uv&quot;&gt;&lt;pre class=&quot;lazy&quot;&gt;
&lt;span class=&quot;Keyword&quot;&gt;private&lt;/span&gt; &lt;span class=&quot;Support&quot;&gt;Class&lt;/span&gt;&lt;span class=&quot;Keyword&quot;&gt;&amp;lt;&lt;/span&gt;?&lt;span class=&quot;Keyword&quot;&gt;&amp;gt;&lt;/span&gt; currentPresenterInstanceClass;

&lt;span class=&quot;Keyword&quot;&gt;public &lt;/span&gt;&lt;span class=&quot;Keyword&quot;&gt;void&lt;/span&gt; &lt;span class=&quot;Entity&quot;&gt;onAnySetContentEvent&lt;/span&gt;(&lt;span class=&quot;Keyword&quot;&gt;AnySetContentEvent&lt;/span&gt; event) {
  &lt;span class=&quot;Keyword&quot;&gt;PresenterProvider&lt;/span&gt;&lt;span class=&quot;Keyword&quot;&gt;&amp;lt;&lt;/span&gt;?&lt;span class=&quot;Keyword&quot;&gt;&amp;gt;&lt;/span&gt; presenterProvider = event.getPresenter();

  &lt;span class=&quot;Support&quot;&gt;Class&lt;/span&gt;&lt;span class=&quot;Keyword&quot;&gt;&amp;lt;&lt;/span&gt;?&lt;span class=&quot;Keyword&quot;&gt;&amp;gt;&lt;/span&gt; nextInstanceClass = presenterProvider.getInstanceClass();
  &lt;span class=&quot;Keyword&quot;&gt;if&lt;/span&gt; (currentPresenterInstanceClass &lt;span class=&quot;Keyword&quot;&gt;!=&lt;/span&gt; nextInstanceClass) {
    &lt;span class=&quot;Keyword&quot;&gt;BasePresenter&lt;/span&gt;&lt;span class=&quot;Keyword&quot;&gt;&amp;lt;&lt;/span&gt;?&lt;span class=&quot;Keyword&quot;&gt;&amp;gt;&lt;/span&gt; next = presenterProvider.get();
    currentPresenterInstanceClass = nextInstanceClass;
    &lt;span class=&quot;Comment&quot;&gt;&lt;span class=&quot;Comment&quot;&gt;//&lt;/span&gt; unbind previous presenter&lt;/span&gt;
    &lt;span class=&quot;Comment&quot;&gt;&lt;span class=&quot;Comment&quot;&gt;//&lt;/span&gt; bind, view.setSomethingView(next.getView()), show&lt;/span&gt;
    &lt;span class=&quot;Comment&quot;&gt;&lt;span class=&quot;Comment&quot;&gt;//&lt;/span&gt; DeferredCommand.addCommand(event.getCallback());&lt;/span&gt;
  }
}
&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;Now we can construct and initialize Presenter instance only if it is not the same as current. But there is too much noise in event handler.&lt;/p&gt;
&lt;h3&gt;PresenterSwitch&lt;/h3&gt;
&lt;p&gt;Let&amp;#8217;s create &lt;code&gt;PresenterSwitch&lt;/code&gt; helper class that (fully, comparing to previous code snippet) implements and encapsulates the logic which resides in &lt;code&gt;onAnySetContentEvent&lt;/code&gt; in previous snippet:&lt;/p&gt;
&lt;div class=&quot;uv&quot;&gt;&lt;pre class=&quot;lazy&quot;&gt;
&lt;span class=&quot;Keyword&quot;&gt;public &lt;/span&gt;&lt;span class=&quot;Keyword&quot;&gt;class&lt;/span&gt; &lt;span class=&quot;Entity&quot;&gt;PresenterSwitch&lt;/span&gt; {

  &lt;span class=&quot;Keyword&quot;&gt;public &lt;/span&gt;&lt;span class=&quot;Keyword&quot;&gt;interface&lt;/span&gt; &lt;span class=&quot;Entity&quot;&gt;SwitchCallback&lt;/span&gt; {
    &lt;span class=&quot;Keyword&quot;&gt;void&lt;/span&gt; onSetView(&lt;span class=&quot;Keyword&quot;&gt;BasePresenter&lt;/span&gt;&lt;span class=&quot;Keyword&quot;&gt;&amp;lt;&lt;/span&gt;?&lt;span class=&quot;Keyword&quot;&gt;&amp;gt;&lt;/span&gt; presenter);
  }

  &lt;span class=&quot;Keyword&quot;&gt;private&lt;/span&gt; &lt;span class=&quot;Keyword&quot;&gt;SwitchCallback&lt;/span&gt; callback;
  &lt;span class=&quot;Keyword&quot;&gt;private&lt;/span&gt; &lt;span class=&quot;Support&quot;&gt;Class&lt;/span&gt;&lt;span class=&quot;Keyword&quot;&gt;&amp;lt;&lt;/span&gt;?&lt;span class=&quot;Keyword&quot;&gt;&amp;gt;&lt;/span&gt; presenterClass;
  &lt;span class=&quot;Keyword&quot;&gt;private&lt;/span&gt; &lt;span class=&quot;Keyword&quot;&gt;BasePresenter&lt;/span&gt;&lt;span class=&quot;Keyword&quot;&gt;&amp;lt;&lt;/span&gt;?&lt;span class=&quot;Keyword&quot;&gt;&amp;gt;&lt;/span&gt; presenter;

  &lt;span class=&quot;Keyword&quot;&gt;public &lt;/span&gt;&lt;span class=&quot;Keyword&quot;&gt;void&lt;/span&gt; &lt;span class=&quot;Entity&quot;&gt;bind&lt;/span&gt;(&lt;span class=&quot;Keyword&quot;&gt;SwitchCallback&lt;/span&gt; callback) {
    &lt;span class=&quot;Variable&quot;&gt;this&lt;/span&gt;.callback = callback;
  }

  &lt;span class=&quot;Keyword&quot;&gt;public &lt;/span&gt;&lt;span class=&quot;Keyword&quot;&gt;void&lt;/span&gt; &lt;span class=&quot;Entity&quot;&gt;unbind&lt;/span&gt;() {
    callback = &lt;span class=&quot;Constant&quot;&gt;null&lt;/span&gt;;
    presenterClass = &lt;span class=&quot;Constant&quot;&gt;null&lt;/span&gt;;
    &lt;span class=&quot;Keyword&quot;&gt;if&lt;/span&gt; (presenter &lt;span class=&quot;Keyword&quot;&gt;!=&lt;/span&gt; &lt;span class=&quot;Constant&quot;&gt;null&lt;/span&gt;) {
      presenter.unbind();
      presenter = &lt;span class=&quot;Constant&quot;&gt;null&lt;/span&gt;;
    }
  }

  &lt;span class=&quot;Keyword&quot;&gt;public &lt;/span&gt;&lt;span class=&quot;Keyword&quot;&gt;void&lt;/span&gt; &lt;span class=&quot;Entity&quot;&gt;set&lt;/span&gt;(&lt;span class=&quot;Keyword&quot;&gt;PresenterProvider&lt;/span&gt;&amp;lt;?&amp;gt; provider, &lt;span class=&quot;Keyword&quot;&gt;Command&lt;/span&gt; onBoundCommand) {
    &lt;span class=&quot;Support&quot;&gt;Class&lt;/span&gt;&lt;span class=&quot;Keyword&quot;&gt;&amp;lt;&lt;/span&gt;?&lt;span class=&quot;Keyword&quot;&gt;&amp;gt;&lt;/span&gt; instance = provider &lt;span class=&quot;Keyword&quot;&gt;!=&lt;/span&gt; &lt;span class=&quot;Constant&quot;&gt;null&lt;/span&gt; ? provider.getInstanceClass() : &lt;span class=&quot;Constant&quot;&gt;null&lt;/span&gt;;
    &lt;span class=&quot;Keyword&quot;&gt;if&lt;/span&gt; (presenterClass &lt;span class=&quot;Keyword&quot;&gt;!=&lt;/span&gt; instance) {
      &lt;span class=&quot;Keyword&quot;&gt;final&lt;/span&gt; &lt;span class=&quot;Keyword&quot;&gt;BasePresenter&lt;/span&gt;&lt;span class=&quot;Keyword&quot;&gt;&amp;lt;&lt;/span&gt;?&lt;span class=&quot;Keyword&quot;&gt;&amp;gt;&lt;/span&gt; next = provider &lt;span class=&quot;Keyword&quot;&gt;!=&lt;/span&gt; &lt;span class=&quot;Constant&quot;&gt;null&lt;/span&gt; ? provider.get() : &lt;span class=&quot;Constant&quot;&gt;null&lt;/span&gt;;

      &lt;span class=&quot;Keyword&quot;&gt;if&lt;/span&gt; (presenter &lt;span class=&quot;Keyword&quot;&gt;!=&lt;/span&gt; &lt;span class=&quot;Constant&quot;&gt;null&lt;/span&gt;) {
        presenter.unbind();
      }

      presenter = next;
      presenterClass = instance;

      &lt;span class=&quot;Keyword&quot;&gt;if&lt;/span&gt; (next &lt;span class=&quot;Keyword&quot;&gt;!=&lt;/span&gt; &lt;span class=&quot;Constant&quot;&gt;null&lt;/span&gt;) {
        next.bind();
        callback.onSetView(next);
        next.show();
        &lt;span class=&quot;Keyword&quot;&gt;if&lt;/span&gt; (onBoundCommand &lt;span class=&quot;Keyword&quot;&gt;!=&lt;/span&gt; &lt;span class=&quot;Constant&quot;&gt;null&lt;/span&gt;)
          addDeferredCommand(onBoundCommand);
      } &lt;span class=&quot;Keyword&quot;&gt;else&lt;/span&gt; {
        callback.onSetView(&lt;span class=&quot;Constant&quot;&gt;null&lt;/span&gt;);
        &lt;span class=&quot;Keyword&quot;&gt;if&lt;/span&gt; (onBoundCommand &lt;span class=&quot;Keyword&quot;&gt;!=&lt;/span&gt; &lt;span class=&quot;Constant&quot;&gt;null&lt;/span&gt;)
          onBoundCommand.execute();
      }
    } &lt;span class=&quot;Keyword&quot;&gt;else&lt;/span&gt; {
      &lt;span class=&quot;Keyword&quot;&gt;if&lt;/span&gt; (onBoundCommand &lt;span class=&quot;Keyword&quot;&gt;!=&lt;/span&gt; &lt;span class=&quot;Constant&quot;&gt;null&lt;/span&gt;)
        onBoundCommand.execute();
    }
  }

  &lt;span class=&quot;Keyword&quot;&gt;private &lt;/span&gt;&lt;span class=&quot;Keyword&quot;&gt;void&lt;/span&gt; &lt;span class=&quot;Entity&quot;&gt;addDeferredCommand&lt;/span&gt;(&lt;span class=&quot;Keyword&quot;&gt;Command&lt;/span&gt; command) {
    &lt;span class=&quot;Keyword&quot;&gt;DeferredCommand&lt;/span&gt;.addCommand(command);
  }

}
&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;And bind it inside &lt;code&gt;WorkspacePresenter&lt;/code&gt;:&lt;/p&gt;
&lt;div class=&quot;uv&quot;&gt;&lt;pre class=&quot;lazy&quot;&gt;
&lt;span class=&quot;Keyword&quot;&gt;public &lt;/span&gt;&lt;span class=&quot;Keyword&quot;&gt;class&lt;/span&gt; &lt;span class=&quot;Entity&quot;&gt;WorkspacePresenterImpl&lt;/span&gt; &lt;span class=&quot;Keyword&quot;&gt;extends&lt;/span&gt; &lt;span class=&quot;Keyword&quot;&gt;AbstractBasePresenter&lt;/span&gt;&amp;lt;&lt;span class=&quot;Keyword&quot;&gt;WorkspaceView&lt;/span&gt;&amp;gt; 
  &lt;span class=&quot;Keyword&quot;&gt;implements&lt;/span&gt; &lt;span class=&quot;Keyword&quot;&gt;WorkspacePresenter&lt;/span&gt;, &lt;span class=&quot;Keyword&quot;&gt;WorkspaceSetContentHandler&lt;/span&gt; {

  &lt;span class=&quot;Keyword&quot;&gt;private&lt;/span&gt; &lt;span class=&quot;Keyword&quot;&gt;final&lt;/span&gt; &lt;span class=&quot;Keyword&quot;&gt;PresenterSwitch&lt;/span&gt; content = &lt;span class=&quot;Keyword&quot;&gt;new&lt;/span&gt; &lt;span class=&quot;Keyword&quot;&gt;PresenterSwitch&lt;/span&gt;();

  @&lt;span class=&quot;Keyword&quot;&gt;Inject&lt;/span&gt;
  &lt;span class=&quot;Keyword&quot;&gt;public &lt;/span&gt;&lt;span class=&quot;Entity&quot;&gt;WorkspacePresenterImpl&lt;/span&gt;(&lt;span class=&quot;Keyword&quot;&gt;WorkspaceView&lt;/span&gt; view, &lt;span class=&quot;Keyword&quot;&gt;EventBus&lt;/span&gt; eventBus) {
    &lt;span class=&quot;Variable&quot;&gt;super&lt;/span&gt;(view, eventBus);
  }

  @&lt;span class=&quot;Support&quot;&gt;Override&lt;/span&gt;
  &lt;span class=&quot;Keyword&quot;&gt;public &lt;/span&gt;&lt;span class=&quot;Keyword&quot;&gt;void&lt;/span&gt; &lt;span class=&quot;Entity&quot;&gt;onBind&lt;/span&gt;() {
    register(eventBus.addHandler(&lt;span class=&quot;Keyword&quot;&gt;WorkspaceSetContentEvent&lt;/span&gt;.getType(), &lt;span class=&quot;Variable&quot;&gt;this&lt;/span&gt;));
    content.bind(&lt;span class=&quot;Keyword&quot;&gt;new&lt;/span&gt; &lt;span class=&quot;Keyword&quot;&gt;SwitchCallback&lt;/span&gt;() {
      &lt;span class=&quot;Keyword&quot;&gt;public &lt;/span&gt;&lt;span class=&quot;Keyword&quot;&gt;void&lt;/span&gt; &lt;span class=&quot;Entity&quot;&gt;onSetView&lt;/span&gt;(&lt;span class=&quot;Keyword&quot;&gt;BasePresenter&lt;/span&gt;&amp;lt;?&amp;gt; presenter) {
        view.setContentView(presenter &lt;span class=&quot;Keyword&quot;&gt;!=&lt;/span&gt; &lt;span class=&quot;Constant&quot;&gt;null&lt;/span&gt; ? presenter.getView() : &lt;span class=&quot;Constant&quot;&gt;null&lt;/span&gt;);
      }
    });
  }

  @&lt;span class=&quot;Support&quot;&gt;Override&lt;/span&gt;
  &lt;span class=&quot;Keyword&quot;&gt;public &lt;/span&gt;&lt;span class=&quot;Keyword&quot;&gt;void&lt;/span&gt; &lt;span class=&quot;Entity&quot;&gt;onUnbind&lt;/span&gt;() {
    content.unbind();
  }

  @&lt;span class=&quot;Support&quot;&gt;Override&lt;/span&gt;
  &lt;span class=&quot;Keyword&quot;&gt;public &lt;/span&gt;&lt;span class=&quot;Keyword&quot;&gt;void&lt;/span&gt; &lt;span class=&quot;Entity&quot;&gt;onShow&lt;/span&gt;() {
  }

  &lt;span class=&quot;Keyword&quot;&gt;public &lt;/span&gt;&lt;span class=&quot;Keyword&quot;&gt;void&lt;/span&gt; &lt;span class=&quot;Entity&quot;&gt;onWorkspaceSetContent&lt;/span&gt;(final &lt;span class=&quot;Keyword&quot;&gt;WorkspaceSetContentEvent&lt;/span&gt; event) {
    content.set(event.getPresenter(), event.getCallback());
  }

}
&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;The same goes with &lt;code&gt;PeoplePresenter&lt;/code&gt; and its &lt;code&gt;PeopleSetContentEvent&lt;/code&gt;.&lt;/p&gt;
&lt;p&gt;Lastly we need to construct &lt;code&gt;PresenterProvider&lt;/code&gt; instances for each &lt;code&gt;Presenter&lt;/code&gt; in &lt;code&gt;SimpleHistoryManager&lt;/code&gt; so lets create a &lt;code&gt;PresenterProviderFactory&lt;/code&gt; interface:&lt;/p&gt;
&lt;div class=&quot;uv&quot;&gt;&lt;pre class=&quot;lazy&quot;&gt;
&lt;span class=&quot;Keyword&quot;&gt;public &lt;/span&gt;&lt;span class=&quot;Keyword&quot;&gt;interface&lt;/span&gt; &lt;span class=&quot;Entity&quot;&gt;PresenterProviderFactory&lt;/span&gt; {

  &lt;span class=&quot;Keyword&quot;&gt;&amp;lt;&lt;/span&gt;P &lt;span class=&quot;Keyword&quot;&gt;extends&lt;/span&gt; &lt;span class=&quot;Keyword&quot;&gt;BasePresenter&lt;/span&gt;&lt;span class=&quot;Keyword&quot;&gt;&amp;lt;&lt;/span&gt;?&lt;span class=&quot;Keyword&quot;&gt;&amp;gt;&lt;/span&gt;&lt;span class=&quot;Keyword&quot;&gt;&amp;gt;&lt;/span&gt; &lt;span class=&quot;Keyword&quot;&gt;PresenterProvider&lt;/span&gt;&lt;span class=&quot;Keyword&quot;&gt;&amp;lt;&lt;/span&gt;P&lt;span class=&quot;Keyword&quot;&gt;&amp;gt;&lt;/span&gt; create(&lt;span class=&quot;Support&quot;&gt;Class&lt;/span&gt;&lt;span class=&quot;Keyword&quot;&gt;&amp;lt;&lt;/span&gt;?&lt;span class=&quot;Keyword&quot;&gt;&amp;gt;&lt;/span&gt; clazz, 
                                                           &lt;span class=&quot;Support&quot;&gt;Provider&lt;/span&gt;&lt;span class=&quot;Keyword&quot;&gt;&amp;lt;&lt;/span&gt;P&lt;span class=&quot;Keyword&quot;&gt;&amp;gt;&lt;/span&gt; provider);

}
&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;and define full constructor for &lt;code&gt;SimpleHistoryManager&lt;/code&gt;:&lt;/p&gt;
&lt;div class=&quot;uv&quot;&gt;&lt;pre class=&quot;lazy&quot;&gt;
&lt;span class=&quot;Keyword&quot;&gt;private&lt;/span&gt; &lt;span class=&quot;Keyword&quot;&gt;final&lt;/span&gt; &lt;span class=&quot;Keyword&quot;&gt;EventBus&lt;/span&gt; eventBus;
&lt;span class=&quot;Keyword&quot;&gt;private&lt;/span&gt; &lt;span class=&quot;Keyword&quot;&gt;final&lt;/span&gt; &lt;span class=&quot;Keyword&quot;&gt;PresenterProvider&lt;/span&gt;&lt;span class=&quot;Keyword&quot;&gt;&amp;lt;&lt;/span&gt;&lt;span class=&quot;Keyword&quot;&gt;IndexPresenter&lt;/span&gt;&lt;span class=&quot;Keyword&quot;&gt;&amp;gt;&lt;/span&gt; indexPresenterProvider;
&lt;span class=&quot;Keyword&quot;&gt;private&lt;/span&gt; &lt;span class=&quot;Keyword&quot;&gt;final&lt;/span&gt; &lt;span class=&quot;Keyword&quot;&gt;PresenterProvider&lt;/span&gt;&lt;span class=&quot;Keyword&quot;&gt;&amp;lt;&lt;/span&gt;&lt;span class=&quot;Keyword&quot;&gt;PeoplePresenter&lt;/span&gt;&lt;span class=&quot;Keyword&quot;&gt;&amp;gt;&lt;/span&gt; peoplePresenterProvider;
&lt;span class=&quot;Keyword&quot;&gt;private&lt;/span&gt; &lt;span class=&quot;Keyword&quot;&gt;final&lt;/span&gt; &lt;span class=&quot;Keyword&quot;&gt;PresenterProvider&lt;/span&gt;&lt;span class=&quot;Keyword&quot;&gt;&amp;lt;&lt;/span&gt;&lt;span class=&quot;Keyword&quot;&gt;BlankPresenter&lt;/span&gt;&lt;span class=&quot;Keyword&quot;&gt;&amp;gt;&lt;/span&gt; blankPresenterProvider;
&lt;span class=&quot;Keyword&quot;&gt;private&lt;/span&gt; &lt;span class=&quot;Keyword&quot;&gt;final&lt;/span&gt; &lt;span class=&quot;Keyword&quot;&gt;PresenterProvider&lt;/span&gt;&lt;span class=&quot;Keyword&quot;&gt;&amp;lt;&lt;/span&gt;&lt;span class=&quot;Keyword&quot;&gt;ShowPresenter&lt;/span&gt;&lt;span class=&quot;Keyword&quot;&gt;&amp;gt;&lt;/span&gt; showPresenterProvider;
&lt;span class=&quot;Keyword&quot;&gt;private&lt;/span&gt; &lt;span class=&quot;Keyword&quot;&gt;final&lt;/span&gt; &lt;span class=&quot;Keyword&quot;&gt;PresenterProvider&lt;/span&gt;&lt;span class=&quot;Keyword&quot;&gt;&amp;lt;&lt;/span&gt;&lt;span class=&quot;Keyword&quot;&gt;EditPresenter&lt;/span&gt;&lt;span class=&quot;Keyword&quot;&gt;&amp;gt;&lt;/span&gt; editPresenterProvider;

@&lt;span class=&quot;Keyword&quot;&gt;Inject&lt;/span&gt;
&lt;span class=&quot;Keyword&quot;&gt;public &lt;/span&gt;&lt;span class=&quot;Entity&quot;&gt;SimpleHistoryManager&lt;/span&gt;(&lt;span class=&quot;Keyword&quot;&gt;EventBus&lt;/span&gt; eventBus, &lt;span class=&quot;Keyword&quot;&gt;PresenterProviderFactory&lt;/span&gt; f,
                            &lt;span class=&quot;Support&quot;&gt;Provider&lt;/span&gt;&amp;lt;&lt;span class=&quot;Keyword&quot;&gt;IndexPresenter&lt;/span&gt;&amp;gt; indexPresenterProvider,
                            &lt;span class=&quot;Support&quot;&gt;Provider&lt;/span&gt;&amp;lt;&lt;span class=&quot;Keyword&quot;&gt;PeoplePresenter&lt;/span&gt;&amp;gt; peoplePresenterProvider,
                            &lt;span class=&quot;Support&quot;&gt;Provider&lt;/span&gt;&amp;lt;&lt;span class=&quot;Keyword&quot;&gt;BlankPresenter&lt;/span&gt;&amp;gt; blankPresenterProvider,
                            &lt;span class=&quot;Support&quot;&gt;Provider&lt;/span&gt;&amp;lt;&lt;span class=&quot;Keyword&quot;&gt;ShowPresenter&lt;/span&gt;&amp;gt; showPresenterProvider,
                            &lt;span class=&quot;Support&quot;&gt;Provider&lt;/span&gt;&amp;lt;&lt;span class=&quot;Keyword&quot;&gt;EditPresenter&lt;/span&gt;&amp;gt; editPresenterProvider) {
  &lt;span class=&quot;Variable&quot;&gt;this&lt;/span&gt;.eventBus = eventBus;

  &lt;span class=&quot;Variable&quot;&gt;this&lt;/span&gt;.indexPresenterProvider = f.create(&lt;span class=&quot;Keyword&quot;&gt;IndexPresenter&lt;/span&gt;.&lt;span class=&quot;Keyword&quot;&gt;class&lt;/span&gt;, indexPresenterProvider);
  &lt;span class=&quot;Variable&quot;&gt;this&lt;/span&gt;.peoplePresenterProvider = f.create(&lt;span class=&quot;Keyword&quot;&gt;PeoplePresenter&lt;/span&gt;.&lt;span class=&quot;Keyword&quot;&gt;class&lt;/span&gt;, peoplePresenterProvider);
  &lt;span class=&quot;Variable&quot;&gt;this&lt;/span&gt;.blankPresenterProvider = f.create(&lt;span class=&quot;Keyword&quot;&gt;BlankPresenter&lt;/span&gt;.&lt;span class=&quot;Keyword&quot;&gt;class&lt;/span&gt;, blankPresenterProvider);
  &lt;span class=&quot;Variable&quot;&gt;this&lt;/span&gt;.showPresenterProvider = f.create(&lt;span class=&quot;Keyword&quot;&gt;ShowPresenter&lt;/span&gt;.&lt;span class=&quot;Keyword&quot;&gt;class&lt;/span&gt;, showPresenterProvider);
  &lt;span class=&quot;Variable&quot;&gt;this&lt;/span&gt;.editPresenterProvider = f.create(&lt;span class=&quot;Keyword&quot;&gt;EditPresenter&lt;/span&gt;.&lt;span class=&quot;Keyword&quot;&gt;class&lt;/span&gt;, editPresenterProvider);
}
&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;Looks terrible, doesn&amp;#8217;t it? See &lt;strong&gt;&amp;#8220;Terrible Footnote&amp;#8221;&lt;/strong&gt; below.&lt;/p&gt;
&lt;p&gt;Also note that &lt;code&gt;get()&lt;/code&gt; may or may not be instance of &lt;code&gt;getInstanceClass()&lt;/code&gt;. This actually calls for rename of &lt;code&gt;getInstanceClass()&lt;/code&gt; to something different more adequate.&lt;/p&gt;
&lt;h2&gt;Changing place &amp;#8212; Place Events&lt;/h2&gt;
&lt;p&gt;So we have implemented the complicated side of history management &amp;#8212; reaction to history tokens. Last thing what&amp;#8217;s missing is adding new history items.&lt;/p&gt;
&lt;p&gt;If &lt;code&gt;SimpleHistoryService&lt;/code&gt; parses history token, it also must create new tokens to encapsulate token string related functionality in one place and to hide token strings from other parts of application. If it creates tokens, it needs to know when create them. So we need few new events that can be fired from application presenters and handled by &lt;code&gt;SimpleHistoryService&lt;/code&gt;. Full list for this application is:&lt;/p&gt;
&lt;ul&gt;
	&lt;li&gt;MenuClickEvent&lt;/li&gt;
	&lt;li&gt;PeopleShowPlaceEvent&lt;/li&gt;
	&lt;li&gt;PeopleEditPlaceEvent&lt;/li&gt;
	&lt;li&gt;PersonShowPlaceEvent&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;For example &lt;code&gt;MenuClickEvent&lt;/code&gt; is fired from &lt;a href=&quot;http://bitbucket.org/ampatspell/places/src/121c06b7ec8b/places-example-gwt/src/main/java/com/ampatspell/places/example/client/workspace/menu/MenuPresenterImpl.java&quot;&gt;&lt;code&gt;MenuPresenter&lt;/code&gt;&lt;/a&gt;:&lt;/p&gt;
&lt;div class=&quot;uv&quot;&gt;&lt;pre class=&quot;lazy&quot;&gt;
&lt;span class=&quot;Support&quot;&gt;String&lt;/span&gt; key = ...;
eventBus.fireEvent(&lt;span class=&quot;Keyword&quot;&gt;new&lt;/span&gt; &lt;span class=&quot;Keyword&quot;&gt;MenuClickEvent&lt;/span&gt;(key)); 
&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;And other events are fired similarly. Lets add &lt;code&gt;bindHandlers()&lt;/code&gt; method to service and call it from &lt;code&gt;bind()&lt;/code&gt;:&lt;/p&gt;
&lt;div class=&quot;uv&quot;&gt;&lt;pre class=&quot;lazy&quot;&gt;
&lt;span class=&quot;Keyword&quot;&gt;public &lt;/span&gt;&lt;span class=&quot;Keyword&quot;&gt;void&lt;/span&gt; &lt;span class=&quot;Entity&quot;&gt;bind&lt;/span&gt;() {
  &lt;span class=&quot;Keyword&quot;&gt;History&lt;/span&gt;.addValueChangeHandler(&lt;span class=&quot;Variable&quot;&gt;this&lt;/span&gt;);
  &lt;span class=&quot;Keyword&quot;&gt;History&lt;/span&gt;.fireCurrentHistoryState();

  bindHandlers();
}

&lt;span class=&quot;Keyword&quot;&gt;private &lt;/span&gt;&lt;span class=&quot;Keyword&quot;&gt;void&lt;/span&gt; &lt;span class=&quot;Entity&quot;&gt;bindHandlers&lt;/span&gt;() {
  eventBus.addHandler(&lt;span class=&quot;Keyword&quot;&gt;PeopleShowPlaceEvent&lt;/span&gt;.getType(), &lt;span class=&quot;Keyword&quot;&gt;new&lt;/span&gt; &lt;span class=&quot;Keyword&quot;&gt;PeopleShowPlaceHandler&lt;/span&gt;() {
    &lt;span class=&quot;Keyword&quot;&gt;public &lt;/span&gt;&lt;span class=&quot;Keyword&quot;&gt;void&lt;/span&gt; &lt;span class=&quot;Entity&quot;&gt;onPeopleShowPlace&lt;/span&gt;(&lt;span class=&quot;Keyword&quot;&gt;PeopleShowPlaceEvent&lt;/span&gt; event) {
      newItem(&lt;span class=&quot;String&quot;&gt;&lt;span class=&quot;String&quot;&gt;&amp;quot;&lt;/span&gt;/people&lt;span class=&quot;String&quot;&gt;&amp;quot;&lt;/span&gt;&lt;/span&gt;);
    }
  });
  eventBus.addHandler(&lt;span class=&quot;Keyword&quot;&gt;PersonEditPlaceEvent&lt;/span&gt;.getType(), &lt;span class=&quot;Keyword&quot;&gt;new&lt;/span&gt; &lt;span class=&quot;Keyword&quot;&gt;PersonEditPlaceHandler&lt;/span&gt;() {
    &lt;span class=&quot;Keyword&quot;&gt;public &lt;/span&gt;&lt;span class=&quot;Keyword&quot;&gt;void&lt;/span&gt; &lt;span class=&quot;Entity&quot;&gt;onPersonEditPlace&lt;/span&gt;(&lt;span class=&quot;Keyword&quot;&gt;PersonEditPlaceEvent&lt;/span&gt; event) {
      newItem(&lt;span class=&quot;String&quot;&gt;&lt;span class=&quot;String&quot;&gt;&amp;quot;&lt;/span&gt;/person/&lt;span class=&quot;String&quot;&gt;&amp;quot;&lt;/span&gt;&lt;/span&gt; &lt;span class=&quot;Keyword&quot;&gt;+&lt;/span&gt; event.getKey() &lt;span class=&quot;Keyword&quot;&gt;+&lt;/span&gt; &lt;span class=&quot;String&quot;&gt;&lt;span class=&quot;String&quot;&gt;&amp;quot;&lt;/span&gt;/edit&lt;span class=&quot;String&quot;&gt;&amp;quot;&lt;/span&gt;&lt;/span&gt;);
    }
  });
  eventBus.addHandler(&lt;span class=&quot;Keyword&quot;&gt;PersonShowPlaceEvent&lt;/span&gt;.getType(), &lt;span class=&quot;Keyword&quot;&gt;new&lt;/span&gt; &lt;span class=&quot;Keyword&quot;&gt;PersonShowPlaceHandler&lt;/span&gt;() {
    &lt;span class=&quot;Keyword&quot;&gt;public &lt;/span&gt;&lt;span class=&quot;Keyword&quot;&gt;void&lt;/span&gt; &lt;span class=&quot;Entity&quot;&gt;onPersonShowPlace&lt;/span&gt;(&lt;span class=&quot;Keyword&quot;&gt;PersonShowPlaceEvent&lt;/span&gt; event) {
      newItem(&lt;span class=&quot;String&quot;&gt;&lt;span class=&quot;String&quot;&gt;&amp;quot;&lt;/span&gt;/person/&lt;span class=&quot;String&quot;&gt;&amp;quot;&lt;/span&gt;&lt;/span&gt; &lt;span class=&quot;Keyword&quot;&gt;+&lt;/span&gt; event.getKey() &lt;span class=&quot;Keyword&quot;&gt;+&lt;/span&gt; &lt;span class=&quot;String&quot;&gt;&lt;span class=&quot;String&quot;&gt;&amp;quot;&lt;/span&gt;/show&lt;span class=&quot;String&quot;&gt;&amp;quot;&lt;/span&gt;&lt;/span&gt;);
    }
  });
  eventBus.addHandler(&lt;span class=&quot;Keyword&quot;&gt;MenuClickEvent&lt;/span&gt;.getType(), &lt;span class=&quot;Keyword&quot;&gt;new&lt;/span&gt; &lt;span class=&quot;Keyword&quot;&gt;MenuClickHandler&lt;/span&gt;() {
    &lt;span class=&quot;Keyword&quot;&gt;public &lt;/span&gt;&lt;span class=&quot;Keyword&quot;&gt;void&lt;/span&gt; &lt;span class=&quot;Entity&quot;&gt;onMenuClick&lt;/span&gt;(&lt;span class=&quot;Keyword&quot;&gt;MenuClickEvent&lt;/span&gt; event) {
      newItem(&lt;span class=&quot;String&quot;&gt;&lt;span class=&quot;String&quot;&gt;&amp;quot;&lt;/span&gt;/&lt;span class=&quot;String&quot;&gt;&amp;quot;&lt;/span&gt;&lt;/span&gt; &lt;span class=&quot;Keyword&quot;&gt;+&lt;/span&gt; event.getKey());
    }
  });
}

&lt;span class=&quot;Keyword&quot;&gt;private &lt;/span&gt;&lt;span class=&quot;Keyword&quot;&gt;void&lt;/span&gt; &lt;span class=&quot;Entity&quot;&gt;newItem&lt;/span&gt;(&lt;span class=&quot;Support&quot;&gt;String&lt;/span&gt; token) {
  &lt;span class=&quot;Keyword&quot;&gt;History&lt;/span&gt;.newItem(token);
}
&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;Each of those event handlers will add new History item that will fire &lt;code&gt;History&lt;/code&gt; value change handler logic inside &lt;code&gt;onTokenChanged()&lt;/code&gt; method.&lt;/p&gt;
&lt;p&gt;And this prototype of history aware application is working just fine.&lt;/p&gt;
&lt;h2&gt;That Terrible Footnote&lt;/h2&gt;
&lt;p&gt;Regarding those ugly &lt;code&gt;SimpleHistoryManager&lt;/code&gt; &lt;code&gt;bindHandlers()&lt;/code&gt;, constructor and string parsing: next blog post will be about &lt;a href=&quot;http://bitbucket.org/ampatspell/places/src/tip/places-client/&quot;&gt;Places library&lt;/a&gt; which will replace &lt;code&gt;SimpleHistoryManager&lt;/code&gt; with more sophisticated solution &amp;#8212; list of hierarchic Place instances where each manages only few &lt;code&gt;Presenter&lt;/code&gt; providers, few events and only sub-part of history token pattern with or without parameters.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;Update:&lt;/strong&gt; Second &lt;a href=&quot;/articles/2010/02/01/gwt-history-management-with-places.html&quot;&gt;post is online&lt;/a&gt;&lt;/p&gt;</content>
</entry>


  <entry>
  <title>My GWT &amp; AppEngine Toys</title>
  <link href="/articles/2010/01/06/my-gwt-and-appengine-toys.html" />
  <id>tag:www.amateurinmotion.com,2010-01-06:1262779131</id>
  <updated>2010-01-06T13:58:51+02:00</updated>
  <content type="html">&lt;p&gt;For some time I&amp;#8217;ve been building complete stack of tools for GWT projects hosted on Google AppEngine. This includes:&lt;/p&gt;
&lt;ul&gt;
	&lt;li&gt;&lt;strong&gt;&lt;a href=&quot;http://www.amateurinmotion.com/sites/google-maven-plugin/plugin-info.html&quot;&gt;Maven plugin&lt;/a&gt;&lt;/strong&gt; for AppEngine and GWT 2.0&lt;/li&gt;
	&lt;li&gt;&lt;strong&gt;Maven archetype&lt;/strong&gt; for quick start&lt;/li&gt;
	&lt;li&gt;&lt;strong&gt;&lt;a href=&quot;http://bitbucket.org/ampatspell/gaeds/wiki/Home&quot;&gt;gaeds&lt;/a&gt;&lt;/strong&gt; &amp;#8212; easy to use AppEngine DataStore wrapper library&lt;/li&gt;
	&lt;li&gt;&lt;strong&gt;&lt;a href=&quot;http://bitbucket.org/ampatspell/bones/src/&quot;&gt;bones&lt;/a&gt;&lt;/strong&gt;&lt;strong&gt;-client&lt;/strong&gt; &amp;#8212; library what implements MVP, EventBus and Command pattern (Also known as Action pattern in GWT corner of the world)&lt;/li&gt;
	&lt;li&gt;&lt;strong&gt;&lt;a href=&quot;http://bitbucket.org/ampatspell/bones/src/&quot;&gt;bones&lt;/a&gt;&lt;/strong&gt;&lt;strong&gt;-appengine&lt;/strong&gt; &amp;#8212; library what provides Action server-side part, AppEngine JUnit TestRunner and so on&lt;/li&gt;
	&lt;li&gt;&lt;strong&gt;&lt;a href=&quot;http://bitbucket.org/ampatspell/places/src/&quot;&gt;places&lt;/a&gt;&lt;/strong&gt; &amp;#8212; GWT library for History Management&lt;/li&gt;
	&lt;li&gt;&lt;strong&gt;&lt;a href=&quot;http://bitbucket.org/ampatspell/bones-validator/src/&quot;&gt;bones-validator&lt;/a&gt;&lt;/strong&gt; &amp;#8212; GWT and Server-side Validation framework with &lt;strong&gt;shared&lt;/strong&gt; definition&lt;/li&gt;
	&lt;li&gt;&lt;strong&gt;&lt;a href=&quot;http://bitbucket.org/ampatspell/gwt-mootools/src/&quot;&gt;gwt-mootools&lt;/a&gt;&lt;/strong&gt; &amp;#8212;  GWT Wrapper for &lt;a href=&quot;http://mootools.net/&quot;&gt;MooTools&lt;/a&gt; Animation classes&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;All of those things are still in &lt;code&gt;SNAPSHOT&lt;/code&gt; phase but I&amp;#8217;m using them in multiple projects.&lt;/p&gt;
&lt;p&gt;To try Bones, Gaeds (unfortunately this archetype doesn&amp;#8217;t yet have Places library integrated) make sure you have latest &lt;a href=&quot;http://maven.apache.org/&quot;&gt;Maven&lt;/a&gt; and run:&lt;/p&gt;
&lt;div class=&quot;uv&quot;&gt;&lt;pre class=&quot;lazy&quot;&gt;
mvn archetype:generate -DarchetypeCatalog=http://www.amateurinmotion.com/repository
&lt;/pre&gt;&lt;/div&gt;&lt;div class=&quot;uv&quot;&gt;&lt;pre class=&quot;lazy&quot;&gt;
Choose archetype:
1: http://www.amateurinmotion.com/repository -&amp;gt; google-quickstart-archetype (Google GWT &amp;amp; AppEngine Web App)
2: http://www.amateurinmotion.com/repository -&amp;gt; bones-google-quickstart-archetype (Google GWT &amp;amp; AppEngine Web App With Bones and Gaeds)
Choose a number:  (1/2): 2
Define value for groupId: : som.something
Define value for artifactId: : something
Define value for version:  1.0-SNAPSHOT: : 
Define value for package:  som.something: : 
Confirm properties configuration:
groupId: som.something
artifactId: something
version: 1.0-SNAPSHOT
package: som.something
 Y: : y
&lt;/pre&gt;&lt;/div&gt;&lt;div class=&quot;uv&quot;&gt;&lt;pre class=&quot;lazy&quot;&gt;
cd something
mvn install
&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;At this point you can run project in GWT Development Mode with AppEngine launcher:&lt;/p&gt;
&lt;div class=&quot;uv&quot;&gt;&lt;pre class=&quot;lazy&quot;&gt;
cd something-gwt
mvn google:gwt-run
&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;Or run compiled application in AppEngine Development server alone:&lt;/p&gt;
&lt;div class=&quot;uv&quot;&gt;&lt;pre class=&quot;lazy&quot;&gt;
cd something-war
mvn google:appengine-run
&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;Or deploy to AppEngine (make sure appengine-war.xml has correct id and version)&lt;/p&gt;
&lt;div class=&quot;uv&quot;&gt;&lt;pre class=&quot;lazy&quot;&gt;
cd something-war
mvn google:appengine-deploy
&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;In case you&amp;#8217;re wondering, plugin supports multiple GWT modules.&lt;/p&gt;
&lt;h2&gt;More info&lt;/h2&gt;
&lt;ul&gt;
	&lt;li&gt;google-appengine-plugin &amp;#8212; &lt;a href=&quot;http://www.amateurinmotion.com/sites/google-maven-plugin/plugin-info.html&quot;&gt;site&lt;/a&gt; &lt;a href=&quot;http://bitbucket.org/ampatspell/google-maven-plugin/src/&quot;&gt;sources&lt;/a&gt;&lt;/li&gt;
	&lt;li&gt;bones &amp;#8212; &lt;a href=&quot;http://www.amateurinmotion.com/sites/bones/&quot;&gt;site&lt;/a&gt; &lt;a href=&quot;http://bitbucket.org/ampatspell/bones/src/&quot;&gt;sources&lt;/a&gt;&lt;/li&gt;
	&lt;li&gt;gaeds &amp;#8212; &lt;a href=&quot;http://www.amateurinmotion.com/sites/gaeds/&quot;&gt;site&lt;/a&gt; &lt;a href=&quot;http://bitbucket.org/ampatspell/gaeds/&quot;&gt;docs&lt;/a&gt; &lt;a href=&quot;http://bitbucket.org/ampatspell/gaeds/src&quot;&gt;sources&lt;/a&gt;&lt;/li&gt;
	&lt;li&gt;places &amp;#8212; &lt;a href=&quot;http://history.latest.ampatspell-test.appspot.com/&quot;&gt;demo&lt;/a&gt; &lt;a href=&quot;http://www.amateurinmotion.com/sites/places/places-client/index.html&quot;&gt;site&lt;/a&gt; &lt;a href=&quot;http://bitbucket.org/ampatspell/places/src/&quot; title=&quot;also for demo site&quot;&gt;sources&lt;/a&gt;&lt;/li&gt;
	&lt;li&gt;bones-validator &amp;#8211; &lt;a href=&quot;http://www.amateurinmotion.com/sites/bones-validator/&quot;&gt;site&lt;/a&gt; &lt;a href=&quot;http://bitbucket.org/ampatspell/bones-validator/src/&quot;&gt;sources&lt;/a&gt; &lt;a href=&quot;http://bitbucket.org/ampatspell/propeller/src/tip/src/shared/main/java/com/propeller/shared/validator/PersonValidationModule.java&quot;&gt;example&lt;/a&gt;&lt;/li&gt;
	&lt;li&gt;gwt-mootools &amp;#8211; &lt;a href=&quot;http://www.amateurinmotion.com/sites/gwt-mootools&quot;&gt;site&lt;/a&gt; &lt;a href=&quot;/projects/gwt-mootools.html&quot;&gt;docs&lt;/a&gt; &lt;a href=&quot;http://bitbucket.org/ampatspell/gwt-mootools/src/&quot;&gt;sources&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;Have any questions? Feel free to reach me using twitter &lt;a href=&quot;http://twitter.com/ampatspell&quot;&gt;@ampatspell&lt;/a&gt; or email what can be found in &lt;a href=&quot;/about.html&quot;&gt;about page&lt;/a&gt;.&lt;/p&gt;</content>
</entry>


  <entry>
  <title>GWT History Manager Almost Done</title>
  <link href="/articles/2010/01/04/gwt-history-manager-almost-done.html" />
  <id>tag:www.amateurinmotion.com,2010-01-04:1262567635</id>
  <updated>2010-01-04T03:13:55+02:00</updated>
  <content type="html">&lt;p&gt;The same I &lt;a href=&quot;/articles/2009/12/29/gwt-history-management-idea.html&quot;&gt;wrote&lt;/a&gt; few days ago. Now with better API:&lt;/p&gt;
&lt;div class=&quot;uv&quot;&gt;&lt;pre class=&quot;lazy&quot;&gt;
&lt;span class=&quot;Comment&quot;&gt;&lt;span class=&quot;Comment&quot;&gt;//&lt;/span&gt; One actual &amp;quot;place&amp;quot; in app. This class can handle some events and `invoke` itself &lt;/span&gt;
&lt;span class=&quot;Comment&quot;&gt;&lt;span class=&quot;Comment&quot;&gt;//&lt;/span&gt; then handle it's place request no matter if it comes from History string token or &lt;/span&gt;
&lt;span class=&quot;Comment&quot;&gt;&lt;span class=&quot;Comment&quot;&gt;//&lt;/span&gt; place change in app.&lt;/span&gt;
@&lt;span class=&quot;Keyword&quot;&gt;Singleton&lt;/span&gt;
&lt;span class=&quot;Keyword&quot;&gt;public &lt;/span&gt;&lt;span class=&quot;Keyword&quot;&gt;class&lt;/span&gt; &lt;span class=&quot;Entity&quot;&gt;ShowPersonPlace&lt;/span&gt; &lt;span class=&quot;Keyword&quot;&gt;implements&lt;/span&gt; &lt;span class=&quot;Keyword&quot;&gt;Place&lt;/span&gt; {

  &lt;span class=&quot;Keyword&quot;&gt;private&lt;/span&gt; &lt;span class=&quot;Keyword&quot;&gt;final&lt;/span&gt; &lt;span class=&quot;Keyword&quot;&gt;PresenterProvider&lt;/span&gt;&lt;span class=&quot;Keyword&quot;&gt;&amp;lt;&lt;/span&gt;&lt;span class=&quot;Keyword&quot;&gt;PeoplePresenter&lt;/span&gt;&lt;span class=&quot;Keyword&quot;&gt;&amp;gt;&lt;/span&gt; people;
  &lt;span class=&quot;Keyword&quot;&gt;private&lt;/span&gt; &lt;span class=&quot;Keyword&quot;&gt;final&lt;/span&gt; &lt;span class=&quot;Keyword&quot;&gt;PresenterProvider&lt;/span&gt;&lt;span class=&quot;Keyword&quot;&gt;&amp;lt;&lt;/span&gt;&lt;span class=&quot;Keyword&quot;&gt;ShowPresenter&lt;/span&gt;&lt;span class=&quot;Keyword&quot;&gt;&amp;gt;&lt;/span&gt; show;

  @&lt;span class=&quot;Keyword&quot;&gt;Inject&lt;/span&gt;
  &lt;span class=&quot;Keyword&quot;&gt;public &lt;/span&gt;&lt;span class=&quot;Entity&quot;&gt;ShowPersonPlace&lt;/span&gt;(&lt;span class=&quot;Keyword&quot;&gt;PresenterProviderFactory&lt;/span&gt; f, &lt;span class=&quot;Support&quot;&gt;Provider&lt;/span&gt;&amp;lt;&lt;span class=&quot;Keyword&quot;&gt;PeoplePresenter&lt;/span&gt;&amp;gt; people, 
      &lt;span class=&quot;Support&quot;&gt;Provider&lt;/span&gt;&amp;lt;&lt;span class=&quot;Keyword&quot;&gt;ShowPresenter&lt;/span&gt;&amp;gt; show) {
    &lt;span class=&quot;Comment&quot;&gt;&lt;span class=&quot;Comment&quot;&gt;//&lt;/span&gt; PresenterProvider allows reuse of already bound presenter. More on this later.&lt;/span&gt;
    &lt;span class=&quot;Variable&quot;&gt;this&lt;/span&gt;.people = f.create(&lt;span class=&quot;Keyword&quot;&gt;PeoplePresenter&lt;/span&gt;.&lt;span class=&quot;Keyword&quot;&gt;class&lt;/span&gt;, people);
    &lt;span class=&quot;Variable&quot;&gt;this&lt;/span&gt;.show = f.create(&lt;span class=&quot;Keyword&quot;&gt;ShowPresenter&lt;/span&gt;.&lt;span class=&quot;Keyword&quot;&gt;class&lt;/span&gt;, show);
  }

  &lt;span class=&quot;Keyword&quot;&gt;public &lt;/span&gt;&lt;span class=&quot;Keyword&quot;&gt;String&lt;/span&gt; &lt;span class=&quot;Entity&quot;&gt;getPattern&lt;/span&gt;() {
    &lt;span class=&quot;Comment&quot;&gt;&lt;span class=&quot;Comment&quot;&gt;//&lt;/span&gt; matches for example &amp;quot;/person/show/zeeba&amp;quot; history token and &lt;/span&gt;
    &lt;span class=&quot;Comment&quot;&gt;&lt;span class=&quot;Comment&quot;&gt;//&lt;/span&gt; creates that token from {&amp;quot;key&amp;quot;=&amp;gt;&amp;quot;zeeba&amp;quot;} parameters&lt;/span&gt;
    &lt;span class=&quot;Keyword&quot;&gt;return&lt;/span&gt; &lt;span class=&quot;String&quot;&gt;&lt;span class=&quot;String&quot;&gt;&amp;quot;&lt;/span&gt;/person/show/{key}&lt;span class=&quot;String&quot;&gt;&amp;quot;&lt;/span&gt;&lt;/span&gt;;
  }

  &lt;span class=&quot;Keyword&quot;&gt;public &lt;/span&gt;&lt;span class=&quot;Keyword&quot;&gt;boolean&lt;/span&gt; &lt;span class=&quot;Entity&quot;&gt;isPatternAbsolute&lt;/span&gt;() {
    &lt;span class=&quot;Comment&quot;&gt;&lt;span class=&quot;Comment&quot;&gt;//&lt;/span&gt; Will be useful when parent-child relationships will be implemented in Place.&lt;/span&gt;
    &lt;span class=&quot;Comment&quot;&gt;&lt;span class=&quot;Comment&quot;&gt;//&lt;/span&gt; Place will be able to use &amp;lt;parent pattern&amp;gt; + &amp;lt;this pattern&amp;gt; for matching.&lt;/span&gt;
    &lt;span class=&quot;Keyword&quot;&gt;return&lt;/span&gt; &lt;span class=&quot;Constant&quot;&gt;true&lt;/span&gt;;
  }

  &lt;span class=&quot;Comment&quot;&gt;&lt;span class=&quot;Comment&quot;&gt;//&lt;/span&gt; The &amp;quot;application&amp;quot; side of history. When application fires some event this Place can&lt;/span&gt;
  &lt;span class=&quot;Comment&quot;&gt;&lt;span class=&quot;Comment&quot;&gt;//&lt;/span&gt; handle it and cause History.newItem be called.&lt;/span&gt;
  &lt;span class=&quot;Keyword&quot;&gt;public &lt;/span&gt;&lt;span class=&quot;Keyword&quot;&gt;void&lt;/span&gt; &lt;span class=&quot;Entity&quot;&gt;bind&lt;/span&gt;(final &lt;span class=&quot;Keyword&quot;&gt;PlaceBindingContext&lt;/span&gt; binding) {
    binding.addHandler(&lt;span class=&quot;Keyword&quot;&gt;ListClickEvent&lt;/span&gt;.getType(), &lt;span class=&quot;Keyword&quot;&gt;new&lt;/span&gt; &lt;span class=&quot;Keyword&quot;&gt;ListClickHandler&lt;/span&gt;() {
      &lt;span class=&quot;Keyword&quot;&gt;public &lt;/span&gt;&lt;span class=&quot;Keyword&quot;&gt;void&lt;/span&gt; &lt;span class=&quot;Entity&quot;&gt;onListClick&lt;/span&gt;(&lt;span class=&quot;Keyword&quot;&gt;ListClickEvent&lt;/span&gt; event) {
        navigateTo(binding, event.getKey());
      }
    });

    binding.addHandler(&lt;span class=&quot;Keyword&quot;&gt;ShowPersonEvent&lt;/span&gt;.getType(), &lt;span class=&quot;Keyword&quot;&gt;new&lt;/span&gt; &lt;span class=&quot;Keyword&quot;&gt;ShowPersonHandler&lt;/span&gt;() {
      &lt;span class=&quot;Keyword&quot;&gt;public &lt;/span&gt;&lt;span class=&quot;Keyword&quot;&gt;void&lt;/span&gt; &lt;span class=&quot;Entity&quot;&gt;onShowPerson&lt;/span&gt;(&lt;span class=&quot;Keyword&quot;&gt;ShowPersonEvent&lt;/span&gt; event) {
        navigateTo(binding, event.getKey());
      }
    });
  }

  &lt;span class=&quot;Keyword&quot;&gt;private &lt;/span&gt;&lt;span class=&quot;Keyword&quot;&gt;void&lt;/span&gt; &lt;span class=&quot;Entity&quot;&gt;navigateTo&lt;/span&gt;(&lt;span class=&quot;Keyword&quot;&gt;PlaceBindingContext&lt;/span&gt; binding, &lt;span class=&quot;Support&quot;&gt;String&lt;/span&gt; key) {
    &lt;span class=&quot;Comment&quot;&gt;&lt;span class=&quot;Comment&quot;&gt;//&lt;/span&gt; Takes current history state (no matter if its this Place or some other) and &lt;/span&gt;
    &lt;span class=&quot;Comment&quot;&gt;&lt;span class=&quot;Comment&quot;&gt;//&lt;/span&gt; overwrites parameter(s) then invokes it what calls History.newItem under the hood.&lt;/span&gt;
    binding.state().set(&lt;span class=&quot;String&quot;&gt;&lt;span class=&quot;String&quot;&gt;&amp;quot;&lt;/span&gt;key&lt;span class=&quot;String&quot;&gt;&amp;quot;&lt;/span&gt;&lt;/span&gt;, key).invoke();
  }

  &lt;span class=&quot;Keyword&quot;&gt;public &lt;/span&gt;&lt;span class=&quot;Keyword&quot;&gt;void&lt;/span&gt; &lt;span class=&quot;Entity&quot;&gt;unbind&lt;/span&gt;() {
    &lt;span class=&quot;Comment&quot;&gt;&lt;span class=&quot;Comment&quot;&gt;//&lt;/span&gt; binding.addHandler takes care of HandlerRegistration but if there's need to &lt;/span&gt;
    &lt;span class=&quot;Comment&quot;&gt;&lt;span class=&quot;Comment&quot;&gt;//&lt;/span&gt; unbind something else, this can be done here.&lt;/span&gt;
  }

  &lt;span class=&quot;Comment&quot;&gt;&lt;span class=&quot;Comment&quot;&gt;//&lt;/span&gt; This method is called when History state has changed and requested &lt;/span&gt;
  &lt;span class=&quot;Comment&quot;&gt;&lt;span class=&quot;Comment&quot;&gt;//&lt;/span&gt; token matches given Place.&lt;/span&gt;
  &lt;span class=&quot;Keyword&quot;&gt;public &lt;/span&gt;&lt;span class=&quot;Keyword&quot;&gt;void&lt;/span&gt; &lt;span class=&quot;Entity&quot;&gt;invoke&lt;/span&gt;(final &lt;span class=&quot;Keyword&quot;&gt;PlaceInvocationContext&lt;/span&gt; invocation) {
    &lt;span class=&quot;Comment&quot;&gt;&lt;span class=&quot;Comment&quot;&gt;//&lt;/span&gt; if place pattern has parameters in it (/foo/{bar} -- bar is parameter)&lt;/span&gt;
    &lt;span class=&quot;Keyword&quot;&gt;final&lt;/span&gt; &lt;span class=&quot;Support&quot;&gt;String&lt;/span&gt; key = invocation.get(&lt;span class=&quot;String&quot;&gt;&lt;span class=&quot;String&quot;&gt;&amp;quot;&lt;/span&gt;key&lt;span class=&quot;String&quot;&gt;&amp;quot;&lt;/span&gt;&lt;/span&gt;);

    &lt;span class=&quot;Comment&quot;&gt;&lt;span class=&quot;Comment&quot;&gt;//&lt;/span&gt; Events with Command on completion (sometimes wraps DeferredCommand to &lt;/span&gt;
    &lt;span class=&quot;Comment&quot;&gt;&lt;span class=&quot;Comment&quot;&gt;//&lt;/span&gt; escape current event execution stack).&lt;/span&gt;
    &lt;span class=&quot;Comment&quot;&gt;&lt;span class=&quot;Comment&quot;&gt;//&lt;/span&gt; fireEvent method is delegate to EventBus. here just to simplify things a little.&lt;/span&gt;
    invocation.fireEvent(&lt;span class=&quot;Keyword&quot;&gt;new&lt;/span&gt; &lt;span class=&quot;Keyword&quot;&gt;WorkspaceSetContentEvent&lt;/span&gt;(people, &lt;span class=&quot;Keyword&quot;&gt;new&lt;/span&gt; &lt;span class=&quot;Keyword&quot;&gt;Command&lt;/span&gt;() {
      &lt;span class=&quot;Keyword&quot;&gt;public &lt;/span&gt;&lt;span class=&quot;Keyword&quot;&gt;void&lt;/span&gt; &lt;span class=&quot;Entity&quot;&gt;execute&lt;/span&gt;() {
        &lt;span class=&quot;Comment&quot;&gt;&lt;span class=&quot;Comment&quot;&gt;//&lt;/span&gt; this &amp;quot;people&amp;quot; will come from somewhere when &lt;/span&gt;
        &lt;span class=&quot;Comment&quot;&gt;&lt;span class=&quot;Comment&quot;&gt;//&lt;/span&gt; parent-child relationships will be implemented&lt;/span&gt;
        invocation.fireEvent(&lt;span class=&quot;Keyword&quot;&gt;new&lt;/span&gt; &lt;span class=&quot;Keyword&quot;&gt;MenuSetActiveEvent&lt;/span&gt;(&lt;span class=&quot;String&quot;&gt;&lt;span class=&quot;String&quot;&gt;&amp;quot;&lt;/span&gt;people&lt;span class=&quot;String&quot;&gt;&amp;quot;&lt;/span&gt;&lt;/span&gt;));
        invocation.fireEvent(&lt;span class=&quot;Keyword&quot;&gt;new&lt;/span&gt; &lt;span class=&quot;Keyword&quot;&gt;PeopleSetContentEvent&lt;/span&gt;(show, &lt;span class=&quot;Keyword&quot;&gt;new&lt;/span&gt; &lt;span class=&quot;Keyword&quot;&gt;Command&lt;/span&gt;() {
          &lt;span class=&quot;Keyword&quot;&gt;public &lt;/span&gt;&lt;span class=&quot;Keyword&quot;&gt;void&lt;/span&gt; &lt;span class=&quot;Entity&quot;&gt;execute&lt;/span&gt;() {
            invocation.fireEvent(&lt;span class=&quot;Keyword&quot;&gt;new&lt;/span&gt; &lt;span class=&quot;Keyword&quot;&gt;ListSetActiveEvent&lt;/span&gt;(key));
            invocation.fireEvent(&lt;span class=&quot;Keyword&quot;&gt;new&lt;/span&gt; &lt;span class=&quot;Keyword&quot;&gt;PersonShowEvent&lt;/span&gt;(key));
          }
        }));
      }
    }));
  }

}
&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;On my TODO list:&lt;/p&gt;
&lt;ul&gt;
	&lt;li&gt;Place parent-child relationships (all Place implementations shouldn&amp;#8217;t fire &lt;code&gt;WorkspaceSetContentEvent&lt;/code&gt; for example)&lt;/li&gt;
	&lt;li&gt;100% Test coverage&lt;/li&gt;
	&lt;li&gt;Nice AbstractPlace class what implements Place interface but allows accessing &lt;code&gt;PlaceBindingContext&lt;/code&gt; and &lt;code&gt;PlaceInvocationContext&lt;/code&gt; methods directly.&lt;/li&gt;
	&lt;li&gt;Release as a module in &lt;a href=&quot;http://bitbucket.org/ampatspell/bones/src/&quot;&gt;bones&lt;/a&gt; library.&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;&lt;a href=&quot;http://history.latest.ampatspell-test.appspot.com/&quot; class=&quot;download&quot;&gt;Live demo&lt;/a&gt;&lt;/p&gt;</content>
</entry>


  <entry>
  <title>Running guess-renames on Mac OS X</title>
  <link href="/articles/2010/01/03/running-guess-renames-on-mac-os-x.html" />
  <id>tag:www.amateurinmotion.com,2010-01-03:1262523231</id>
  <updated>2010-01-03T14:53:51+02:00</updated>
  <content type="html">&lt;p&gt;&lt;a href=&quot;http://iamthewalr.us/projects/guess-renames/&quot;&gt;Guess-renames&lt;/a&gt; is nifty Mercurial extension (and standalone tool) written by &lt;a href=&quot;http://iamthewalr.us/about/&quot;&gt;Colin Barrett&lt;/a&gt;.&lt;/p&gt;
&lt;p&gt;I&amp;#8217;m not really that much familiar with Python that&amp;#8217;s why I had a bit of trouble getting it to work so for those like me here is step by step instructions:&lt;/p&gt;
&lt;h2&gt;Get guess-renames&lt;/h2&gt;
&lt;div class=&quot;uv&quot;&gt;&lt;pre class=&quot;lazy&quot;&gt;
hg clone ssh://hg@bitbucket.org/cbarrett/guess-renames/
&lt;/pre&gt;&lt;/div&gt;&lt;h2&gt;Try running tests&lt;/h2&gt;
&lt;div class=&quot;uv&quot;&gt;&lt;pre class=&quot;lazy&quot;&gt;
make tests
&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;If this fails miserably with exceptions mentioning &lt;code&gt;setuptools&lt;/code&gt;, install them.&lt;/p&gt;
&lt;h2&gt;Install Setuptools (if needed)&lt;/h2&gt;
&lt;div class=&quot;uv&quot;&gt;&lt;pre class=&quot;lazy&quot;&gt;
wget http://peak.telecommunity.com/dist/ez_setup.py
sudo python ./ez_setup.py
&lt;/pre&gt;&lt;/div&gt;&lt;h2&gt;Install guess-renames&lt;/h2&gt;
&lt;p&gt;Tests should now pass. If so install:&lt;/p&gt;
&lt;div class=&quot;uv&quot;&gt;&lt;pre class=&quot;lazy&quot;&gt;
make tests
sudo python ./setup.py install
&lt;/pre&gt;&lt;/div&gt;&lt;h2&gt;Add guessrenames.hgext&lt;/h2&gt;
&lt;p&gt;add the following to &lt;code&gt;~/.hgrc&lt;/code&gt;:&lt;/p&gt;
&lt;div class=&quot;uv&quot;&gt;&lt;pre class=&quot;lazy&quot;&gt;
[extensions]
guessrenames.hgext=
&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;Note: If you already have &lt;code&gt;[extensions]&lt;/code&gt; section, just add &lt;code&gt;guessrenames&lt;/code&gt; to that one.&lt;/p&gt;
&lt;h2&gt;Done&lt;/h2&gt;
&lt;div class=&quot;uv&quot;&gt;&lt;pre class=&quot;lazy&quot;&gt;
hg addremove -g
&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;For more information see &lt;a href=&quot;http://iamthewalr.us/projects/guess-renames/&quot;&gt;guess-renames project page&lt;/a&gt;&lt;/p&gt;</content>
</entry>


  <entry>
  <title>GWT History Management (Idea)</title>
  <link href="/articles/2009/12/29/gwt-history-management-idea.html" />
  <id>tag:www.amateurinmotion.com,2009-12-29:1262047540</id>
  <updated>2009-12-29T02:45:40+02:00</updated>
  <content type="html">&lt;p&gt;Still thinking about API. But here is sneak peak of it:&lt;/p&gt;
&lt;div class=&quot;uv&quot;&gt;&lt;pre class=&quot;lazy&quot;&gt;
&lt;span class=&quot;Keyword&quot;&gt;public static &lt;/span&gt;&lt;span class=&quot;Keyword&quot;&gt;class&lt;/span&gt; &lt;span class=&quot;Entity&quot;&gt;ShowSectionRoute&lt;/span&gt; &lt;span class=&quot;Keyword&quot;&gt;implements&lt;/span&gt; &lt;span class=&quot;Keyword&quot;&gt;Route&lt;/span&gt; {

  &lt;span class=&quot;Keyword&quot;&gt;public &lt;/span&gt;&lt;span class=&quot;Keyword&quot;&gt;Route&lt;/span&gt; &lt;span class=&quot;Entity&quot;&gt;getParent&lt;/span&gt;() {
    &lt;span class=&quot;Keyword&quot;&gt;return&lt;/span&gt; &lt;span class=&quot;Constant&quot;&gt;null&lt;/span&gt;;
  }

  &lt;span class=&quot;Keyword&quot;&gt;public &lt;/span&gt;&lt;span class=&quot;Keyword&quot;&gt;String&lt;/span&gt; &lt;span class=&quot;Entity&quot;&gt;getPath&lt;/span&gt;() {
    &lt;span class=&quot;Keyword&quot;&gt;return&lt;/span&gt; &lt;span class=&quot;String&quot;&gt;&lt;span class=&quot;String&quot;&gt;&amp;quot;&lt;/span&gt;/{section}&lt;span class=&quot;String&quot;&gt;&amp;quot;&lt;/span&gt;&lt;/span&gt;;
  }

  &lt;span class=&quot;Keyword&quot;&gt;public &lt;/span&gt;&lt;span class=&quot;Keyword&quot;&gt;void&lt;/span&gt; &lt;span class=&quot;Entity&quot;&gt;handle&lt;/span&gt;(final &lt;span class=&quot;Keyword&quot;&gt;HandleContext&lt;/span&gt; ctx) {
    ctx.register(&lt;span class=&quot;Keyword&quot;&gt;ShowSectionEvent&lt;/span&gt;.getType(), &lt;span class=&quot;Keyword&quot;&gt;new&lt;/span&gt; &lt;span class=&quot;Keyword&quot;&gt;ShowSectionHandler&lt;/span&gt;() {
      &lt;span class=&quot;Keyword&quot;&gt;public &lt;/span&gt;&lt;span class=&quot;Keyword&quot;&gt;void&lt;/span&gt; &lt;span class=&quot;Entity&quot;&gt;onShowSection&lt;/span&gt;(&lt;span class=&quot;Keyword&quot;&gt;ShowSectionEvent&lt;/span&gt; event) {
        ctx.param(&lt;span class=&quot;String&quot;&gt;&lt;span class=&quot;String&quot;&gt;&amp;quot;&lt;/span&gt;section&lt;span class=&quot;String&quot;&gt;&amp;quot;&lt;/span&gt;&lt;/span&gt;, event.getSection().name().toLowerCase());
      }
    });
  }

  &lt;span class=&quot;Keyword&quot;&gt;public &lt;/span&gt;&lt;span class=&quot;Keyword&quot;&gt;void&lt;/span&gt; &lt;span class=&quot;Entity&quot;&gt;perform&lt;/span&gt;(final &lt;span class=&quot;Keyword&quot;&gt;PerformContext&lt;/span&gt; ctx) {
    &lt;span class=&quot;Keyword&quot;&gt;final&lt;/span&gt; &lt;span class=&quot;Keyword&quot;&gt;Section&lt;/span&gt; section = &lt;span class=&quot;Keyword&quot;&gt;Section&lt;/span&gt;.valueOf(ctx.param(&lt;span class=&quot;String&quot;&gt;&lt;span class=&quot;String&quot;&gt;&amp;quot;&lt;/span&gt;section&lt;span class=&quot;String&quot;&gt;&amp;quot;&lt;/span&gt;&lt;/span&gt;).toUpperCase());
    ctx.register(&lt;span class=&quot;Keyword&quot;&gt;SectionShownEvent&lt;/span&gt;.getType(), &lt;span class=&quot;Keyword&quot;&gt;new&lt;/span&gt; &lt;span class=&quot;Keyword&quot;&gt;SectionShownHandler&lt;/span&gt;() {
      &lt;span class=&quot;Keyword&quot;&gt;public &lt;/span&gt;&lt;span class=&quot;Keyword&quot;&gt;void&lt;/span&gt; &lt;span class=&quot;Entity&quot;&gt;onSectionShown&lt;/span&gt;(&lt;span class=&quot;Keyword&quot;&gt;SectionShownEvent&lt;/span&gt; event) {
        &lt;span class=&quot;Keyword&quot;&gt;if&lt;/span&gt; (event.getSection() &lt;span class=&quot;Keyword&quot;&gt;==&lt;/span&gt; section) {

          &lt;span class=&quot;Comment&quot;&gt;&lt;span class=&quot;Comment&quot;&gt;//&lt;/span&gt; invokes ShowPersonRoute as it is child route for this one&lt;/span&gt;
          ctx.next();
        }
      }
    });
    ctx.fire(&lt;span class=&quot;Keyword&quot;&gt;new&lt;/span&gt; &lt;span class=&quot;Keyword&quot;&gt;ShowSectionHistoryEvent&lt;/span&gt;(section));
  }

}
&lt;/pre&gt;&lt;/div&gt;&lt;div class=&quot;uv&quot;&gt;&lt;pre class=&quot;lazy&quot;&gt;
&lt;span class=&quot;Keyword&quot;&gt;public static &lt;/span&gt;&lt;span class=&quot;Keyword&quot;&gt;class&lt;/span&gt; &lt;span class=&quot;Entity&quot;&gt;ShowPersonRoute&lt;/span&gt; &lt;span class=&quot;Keyword&quot;&gt;implements&lt;/span&gt; &lt;span class=&quot;Keyword&quot;&gt;Route&lt;/span&gt; {

  &lt;span class=&quot;Keyword&quot;&gt;private&lt;/span&gt; &lt;span class=&quot;Keyword&quot;&gt;ShowSectionRoute&lt;/span&gt; parent;

  &lt;span class=&quot;Keyword&quot;&gt;public &lt;/span&gt;&lt;span class=&quot;Entity&quot;&gt;ShowPersonRoute&lt;/span&gt;(&lt;span class=&quot;Keyword&quot;&gt;ShowSectionRoute&lt;/span&gt; parent) {
    &lt;span class=&quot;Variable&quot;&gt;this&lt;/span&gt;.parent = parent;
  }

  &lt;span class=&quot;Keyword&quot;&gt;public &lt;/span&gt;&lt;span class=&quot;Keyword&quot;&gt;Route&lt;/span&gt; &lt;span class=&quot;Entity&quot;&gt;getParent&lt;/span&gt;() {
    &lt;span class=&quot;Keyword&quot;&gt;return&lt;/span&gt; parent;
  }

  &lt;span class=&quot;Keyword&quot;&gt;public &lt;/span&gt;&lt;span class=&quot;Keyword&quot;&gt;String&lt;/span&gt; &lt;span class=&quot;Entity&quot;&gt;getPath&lt;/span&gt;() {
    &lt;span class=&quot;Keyword&quot;&gt;return&lt;/span&gt; &lt;span class=&quot;String&quot;&gt;&lt;span class=&quot;String&quot;&gt;&amp;quot;&lt;/span&gt;/show/{key}&lt;span class=&quot;String&quot;&gt;&amp;quot;&lt;/span&gt;&lt;/span&gt;;
  }

  &lt;span class=&quot;Keyword&quot;&gt;public &lt;/span&gt;&lt;span class=&quot;Keyword&quot;&gt;void&lt;/span&gt; &lt;span class=&quot;Entity&quot;&gt;handle&lt;/span&gt;(final &lt;span class=&quot;Keyword&quot;&gt;HandleContext&lt;/span&gt; ctx) {
    ctx.register(&lt;span class=&quot;Keyword&quot;&gt;ShowPersonEvent&lt;/span&gt;.getType(), &lt;span class=&quot;Keyword&quot;&gt;new&lt;/span&gt; &lt;span class=&quot;Keyword&quot;&gt;ShowPersonHandler&lt;/span&gt;() {
      &lt;span class=&quot;Keyword&quot;&gt;public &lt;/span&gt;&lt;span class=&quot;Keyword&quot;&gt;void&lt;/span&gt; &lt;span class=&quot;Entity&quot;&gt;onShowPerson&lt;/span&gt;(&lt;span class=&quot;Keyword&quot;&gt;ShowPersonEvent&lt;/span&gt; event) {
        ctx.param(&lt;span class=&quot;String&quot;&gt;&lt;span class=&quot;String&quot;&gt;&amp;quot;&lt;/span&gt;key&lt;span class=&quot;String&quot;&gt;&amp;quot;&lt;/span&gt;&lt;/span&gt;, event.getKey()).run();
      }
    });
  }

  &lt;span class=&quot;Keyword&quot;&gt;public &lt;/span&gt;&lt;span class=&quot;Keyword&quot;&gt;void&lt;/span&gt; &lt;span class=&quot;Entity&quot;&gt;perform&lt;/span&gt;(final &lt;span class=&quot;Keyword&quot;&gt;PerformContext&lt;/span&gt; ctx) {
    &lt;span class=&quot;Support&quot;&gt;String&lt;/span&gt; key = ctx.param(&lt;span class=&quot;String&quot;&gt;&lt;span class=&quot;String&quot;&gt;&amp;quot;&lt;/span&gt;key&lt;span class=&quot;String&quot;&gt;&amp;quot;&lt;/span&gt;&lt;/span&gt;);
    ctx.fire(&lt;span class=&quot;Keyword&quot;&gt;new&lt;/span&gt; &lt;span class=&quot;Keyword&quot;&gt;ShowPersonHistoryEvent&lt;/span&gt;(key));
  }

}
&lt;/pre&gt;&lt;/div&gt;&lt;div class=&quot;uv&quot;&gt;&lt;pre class=&quot;lazy&quot;&gt;
&lt;span class=&quot;Comment&quot;&gt;&lt;span class=&quot;Comment&quot;&gt;//&lt;/span&gt; Some presenter fires event:&lt;/span&gt;
eventBus.fireEvent(&lt;span class=&quot;Keyword&quot;&gt;new&lt;/span&gt; &lt;span class=&quot;Keyword&quot;&gt;ShowPersonEvent&lt;/span&gt;(personKeyAsString));

&lt;span class=&quot;Comment&quot;&gt;&lt;span class=&quot;Comment&quot;&gt;//&lt;/span&gt; ShowPersonRoute handles it and updates route&lt;/span&gt;
&lt;span class=&quot;Comment&quot;&gt;&lt;span class=&quot;Comment&quot;&gt;//&lt;/span&gt; History.addItem with &amp;quot;/people/show/&amp;lt;personKey&amp;gt;&amp;quot; is set&lt;/span&gt;
&lt;span class=&quot;Comment&quot;&gt;&lt;span class=&quot;Comment&quot;&gt;//&lt;/span&gt; ShowPerson.getParent() route perform() is called what fires ShowSectionHistoryEvent after &lt;/span&gt;
&lt;span class=&quot;Comment&quot;&gt;&lt;span class=&quot;Comment&quot;&gt;//&lt;/span&gt; section is visible (it can be behind GWT.runAsync) ctx.next() is called. &lt;/span&gt;
&lt;span class=&quot;Comment&quot;&gt;&lt;span class=&quot;Comment&quot;&gt;//&lt;/span&gt; It invokes ShowPerson#handle() what fires ShowPersonHistoryEvent with the same person key&lt;/span&gt;

&lt;span class=&quot;Comment&quot;&gt;&lt;span class=&quot;Comment&quot;&gt;//&lt;/span&gt; some persenter handles event:&lt;/span&gt;
&lt;span class=&quot;Keyword&quot;&gt;public &lt;/span&gt;&lt;span class=&quot;Keyword&quot;&gt;void&lt;/span&gt; &lt;span class=&quot;Entity&quot;&gt;onShowPersonHistoryEvent&lt;/span&gt;(&lt;span class=&quot;Keyword&quot;&gt;ShowPersonHistoryEvent&lt;/span&gt; e) {
  &lt;span class=&quot;Support&quot;&gt;String&lt;/span&gt; key = e.getKey();
}
&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;More on this soon.&lt;/p&gt;</content>
</entry>


  <entry>
  <title>AppEngine BlobStore With Guice</title>
  <link href="/articles/2009/12/24/appengine-blobstore-with-guice.html" />
  <id>tag:www.amateurinmotion.com,2009-12-24:1261611918</id>
  <updated>2009-12-24T01:45:18+02:00</updated>
  <content type="html">&lt;p&gt;Today I finally started to play with &lt;a href=&quot;http://code.google.com/appengine/docs/java/blobstore/&quot;&gt;BlobStore&lt;/a&gt; introduced in &lt;a href=&quot;http://code.google.com/p/googleappengine/wiki/SdkForJavaReleaseNotes&quot;&gt;AppEngine 1.3.0&lt;/a&gt;. Currently this service is in &amp;#8220;experimental&amp;#8221; stage (the same is for Task Queue) but works fine.&lt;/p&gt;
&lt;p&gt;The only problem I came across was 404 on BlobStore upload success servlet what I had configured using &lt;a href=&quot;http://code.google.com/p/google-guice/wiki/ServletModule&quot;&gt;Guice Servlet module&lt;/a&gt;:&lt;/p&gt;
&lt;div class=&quot;uv&quot;&gt;&lt;pre class=&quot;lazy&quot;&gt;
serve(&lt;span class=&quot;String&quot;&gt;&lt;span class=&quot;String&quot;&gt;&amp;quot;&lt;/span&gt;/upload/finished&lt;span class=&quot;String&quot;&gt;&amp;quot;&lt;/span&gt;&lt;/span&gt;).with(&lt;span class=&quot;Keyword&quot;&gt;UploadFinishedServlet&lt;/span&gt;.&lt;span class=&quot;Keyword&quot;&gt;class&lt;/span&gt;);
&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;Guice servlet module is bound to Servlet container infrastructure using filter and that filter is routing requests to actual servlets. But for some reason (at least on AppEngine dev server) the request to the callback path bypasses filters and Jetty reports 404. I came up with this solution:&lt;/p&gt;
&lt;h2&gt;1. declare upload URL callback servlet in web.xml&lt;/h2&gt;
&lt;div class=&quot;uv&quot;&gt;&lt;pre class=&quot;lazy&quot;&gt;
&lt;span class=&quot;MetaTag&quot;&gt;&lt;span class=&quot;MetaTag&quot;&gt;&amp;lt;&lt;/span&gt;&lt;span class=&quot;MetaTag&quot;&gt;servlet&lt;/span&gt;&lt;span class=&quot;MetaTag&quot;&gt;&amp;gt;&lt;/span&gt;&lt;/span&gt;
  &lt;span class=&quot;MetaTag&quot;&gt;&lt;span class=&quot;MetaTag&quot;&gt;&amp;lt;&lt;/span&gt;&lt;span class=&quot;MetaTag&quot;&gt;servlet-name&lt;/span&gt;&lt;span class=&quot;MetaTag&quot;&gt;&amp;gt;&lt;/span&gt;&lt;/span&gt;uploadFinished&lt;span class=&quot;MetaTag&quot;&gt;&lt;span class=&quot;MetaTag&quot;&gt;&amp;lt;/&lt;/span&gt;&lt;span class=&quot;MetaTag&quot;&gt;servlet-name&lt;/span&gt;&lt;span class=&quot;MetaTag&quot;&gt;&amp;gt;&lt;/span&gt;&lt;/span&gt;
  &lt;span class=&quot;MetaTag&quot;&gt;&lt;span class=&quot;MetaTag&quot;&gt;&amp;lt;&lt;/span&gt;&lt;span class=&quot;MetaTag&quot;&gt;servlet-class&lt;/span&gt;&lt;span class=&quot;MetaTag&quot;&gt;&amp;gt;&lt;/span&gt;&lt;/span&gt;com.foo.servlet.UploadFinishedServlet&lt;span class=&quot;MetaTag&quot;&gt;&lt;span class=&quot;MetaTag&quot;&gt;&amp;lt;/&lt;/span&gt;&lt;span class=&quot;MetaTag&quot;&gt;servlet-class&lt;/span&gt;&lt;span class=&quot;MetaTag&quot;&gt;&amp;gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;MetaTag&quot;&gt;&lt;span class=&quot;MetaTag&quot;&gt;&amp;lt;/&lt;/span&gt;&lt;span class=&quot;MetaTag&quot;&gt;servlet&lt;/span&gt;&lt;span class=&quot;MetaTag&quot;&gt;&amp;gt;&lt;/span&gt;&lt;/span&gt;

&lt;span class=&quot;MetaTag&quot;&gt;&lt;span class=&quot;MetaTag&quot;&gt;&amp;lt;&lt;/span&gt;&lt;span class=&quot;MetaTag&quot;&gt;servlet-mapping&lt;/span&gt;&lt;span class=&quot;MetaTag&quot;&gt;&amp;gt;&lt;/span&gt;&lt;/span&gt;
  &lt;span class=&quot;MetaTag&quot;&gt;&lt;span class=&quot;MetaTag&quot;&gt;&amp;lt;&lt;/span&gt;&lt;span class=&quot;MetaTag&quot;&gt;servlet-name&lt;/span&gt;&lt;span class=&quot;MetaTag&quot;&gt;&amp;gt;&lt;/span&gt;&lt;/span&gt;uploadFinished&lt;span class=&quot;MetaTag&quot;&gt;&lt;span class=&quot;MetaTag&quot;&gt;&amp;lt;/&lt;/span&gt;&lt;span class=&quot;MetaTag&quot;&gt;servlet-name&lt;/span&gt;&lt;span class=&quot;MetaTag&quot;&gt;&amp;gt;&lt;/span&gt;&lt;/span&gt;
  &lt;span class=&quot;MetaTag&quot;&gt;&lt;span class=&quot;MetaTag&quot;&gt;&amp;lt;&lt;/span&gt;&lt;span class=&quot;MetaTag&quot;&gt;url-pattern&lt;/span&gt;&lt;span class=&quot;MetaTag&quot;&gt;&amp;gt;&lt;/span&gt;&lt;/span&gt;/upload/finished&lt;span class=&quot;MetaTag&quot;&gt;&lt;span class=&quot;MetaTag&quot;&gt;&amp;lt;/&lt;/span&gt;&lt;span class=&quot;MetaTag&quot;&gt;url-pattern&lt;/span&gt;&lt;span class=&quot;MetaTag&quot;&gt;&amp;gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;MetaTag&quot;&gt;&lt;span class=&quot;MetaTag&quot;&gt;&amp;lt;/&lt;/span&gt;&lt;span class=&quot;MetaTag&quot;&gt;servlet-mapping&lt;/span&gt;&lt;span class=&quot;MetaTag&quot;&gt;&amp;gt;&lt;/span&gt;&lt;/span&gt;
&lt;/pre&gt;&lt;/div&gt;&lt;h2&gt;2. create upload URL with that path&lt;/h2&gt;
&lt;div class=&quot;uv&quot;&gt;&lt;pre class=&quot;lazy&quot;&gt;
&lt;span class=&quot;Comment&quot;&gt;&lt;span class=&quot;Comment&quot;&gt;//&lt;/span&gt; bound to &amp;quot;/upload/finished&amp;quot;, see below&lt;/span&gt;
@&lt;span class=&quot;Keyword&quot;&gt;Named&lt;/span&gt;(&lt;span class=&quot;String&quot;&gt;&lt;span class=&quot;String&quot;&gt;&amp;quot;&lt;/span&gt;uploadFinishedPath&lt;span class=&quot;String&quot;&gt;&amp;quot;&lt;/span&gt;&lt;/span&gt;) &lt;span class=&quot;Support&quot;&gt;String&lt;/span&gt; uploadFinishedPath;

&lt;span class=&quot;Keyword&quot;&gt;BlobStoreService&lt;/span&gt; bs = blobStoreServiceProvider.get();
&lt;span class=&quot;Support&quot;&gt;String&lt;/span&gt; url = bs.createUploadUrl(uploadFinishedPath);
&lt;/pre&gt;&lt;/div&gt;&lt;h2&gt;3. in servlet process uploaded BlobKeys and redirect to guice managed servlet&lt;/h2&gt;
&lt;div class=&quot;uv&quot;&gt;&lt;pre class=&quot;lazy&quot;&gt;
&lt;span class=&quot;Keyword&quot;&gt;public &lt;/span&gt;&lt;span class=&quot;Keyword&quot;&gt;class&lt;/span&gt; &lt;span class=&quot;Entity&quot;&gt;UploadFinishedServlet&lt;/span&gt; &lt;span class=&quot;Keyword&quot;&gt;extends&lt;/span&gt; &lt;span class=&quot;Keyword&quot;&gt;HttpServlet&lt;/span&gt; {

  &lt;span class=&quot;Keyword&quot;&gt;public&lt;/span&gt; &lt;span class=&quot;Keyword&quot;&gt;static&lt;/span&gt; &lt;span class=&quot;Keyword&quot;&gt;final&lt;/span&gt; &lt;span class=&quot;Support&quot;&gt;String&lt;/span&gt; &lt;span class=&quot;Constant&quot;&gt;REDIRECT_TO&lt;/span&gt; = &lt;span class=&quot;String&quot;&gt;&lt;span class=&quot;String&quot;&gt;&amp;quot;&lt;/span&gt;/upload/commit&lt;span class=&quot;String&quot;&gt;&amp;quot;&lt;/span&gt;&lt;/span&gt;;
  &lt;span class=&quot;Keyword&quot;&gt;public&lt;/span&gt; &lt;span class=&quot;Keyword&quot;&gt;static&lt;/span&gt; &lt;span class=&quot;Keyword&quot;&gt;final&lt;/span&gt; &lt;span class=&quot;Support&quot;&gt;String&lt;/span&gt; &lt;span class=&quot;Constant&quot;&gt;KEY_PARAMETER&lt;/span&gt; = &lt;span class=&quot;String&quot;&gt;&lt;span class=&quot;String&quot;&gt;&amp;quot;&lt;/span&gt;key&lt;span class=&quot;String&quot;&gt;&amp;quot;&lt;/span&gt;&lt;/span&gt;;
  &lt;span class=&quot;Keyword&quot;&gt;public&lt;/span&gt; &lt;span class=&quot;Keyword&quot;&gt;static&lt;/span&gt; &lt;span class=&quot;Keyword&quot;&gt;final&lt;/span&gt; &lt;span class=&quot;Support&quot;&gt;String&lt;/span&gt; &lt;span class=&quot;Constant&quot;&gt;FILE_FIELD&lt;/span&gt; = &lt;span class=&quot;String&quot;&gt;&lt;span class=&quot;String&quot;&gt;&amp;quot;&lt;/span&gt;file&lt;span class=&quot;String&quot;&gt;&amp;quot;&lt;/span&gt;&lt;/span&gt;;

  @&lt;span class=&quot;Support&quot;&gt;Override&lt;/span&gt;
  &lt;span class=&quot;Keyword&quot;&gt;protected &lt;/span&gt;&lt;span class=&quot;Keyword&quot;&gt;void&lt;/span&gt; &lt;span class=&quot;Entity&quot;&gt;service&lt;/span&gt;(&lt;span class=&quot;Keyword&quot;&gt;HttpServletRequest&lt;/span&gt; req, &lt;span class=&quot;Keyword&quot;&gt;HttpServletResponse&lt;/span&gt; resp) 
      &lt;span class=&quot;Keyword&quot;&gt;throws&lt;/span&gt; &lt;span class=&quot;Keyword&quot;&gt;ServletException&lt;/span&gt;, &lt;span class=&quot;Support&quot;&gt;IOException&lt;/span&gt; {
      
    &lt;span class=&quot;Keyword&quot;&gt;BlobStoreService&lt;/span&gt; blobStoreService = &lt;span class=&quot;Keyword&quot;&gt;BlobstoreServiceFactory&lt;/span&gt;.getBlobstoreService();
    &lt;span class=&quot;Support&quot;&gt;Map&lt;/span&gt;&lt;span class=&quot;Keyword&quot;&gt;&amp;lt;&lt;/span&gt;&lt;span class=&quot;Support&quot;&gt;String&lt;/span&gt;, &lt;span class=&quot;Keyword&quot;&gt;BlobKey&lt;/span&gt;&lt;span class=&quot;Keyword&quot;&gt;&amp;gt;&lt;/span&gt; keys = blobStoreService.getUploadedBlobs(req);
    &lt;span class=&quot;Keyword&quot;&gt;BlobKey&lt;/span&gt; key = keys.get(&lt;span class=&quot;Constant&quot;&gt;FILE_FIELD&lt;/span&gt;);

    &lt;span class=&quot;Support&quot;&gt;String&lt;/span&gt; parameters = getParameters(key);
    resp.sendRedirect(&lt;span class=&quot;Constant&quot;&gt;REDIRECT_TO&lt;/span&gt; &lt;span class=&quot;Keyword&quot;&gt;+&lt;/span&gt; parameters);
  }

  &lt;span class=&quot;Keyword&quot;&gt;private &lt;/span&gt;&lt;span class=&quot;Keyword&quot;&gt;String&lt;/span&gt; &lt;span class=&quot;Entity&quot;&gt;getParameters&lt;/span&gt;(&lt;span class=&quot;Keyword&quot;&gt;BlobKey&lt;/span&gt; key) {
    &lt;span class=&quot;Keyword&quot;&gt;if&lt;/span&gt; (key &lt;span class=&quot;Keyword&quot;&gt;!=&lt;/span&gt; &lt;span class=&quot;Constant&quot;&gt;null&lt;/span&gt;) {
      &lt;span class=&quot;Keyword&quot;&gt;return&lt;/span&gt; format(&lt;span class=&quot;String&quot;&gt;&lt;span class=&quot;String&quot;&gt;&amp;quot;&lt;/span&gt;?%s=%s&lt;span class=&quot;String&quot;&gt;&amp;quot;&lt;/span&gt;&lt;/span&gt;, &lt;span class=&quot;Constant&quot;&gt;KEY_PARAMETER&lt;/span&gt;, key.getKeyString());
    } &lt;span class=&quot;Keyword&quot;&gt;else&lt;/span&gt; {
      &lt;span class=&quot;Keyword&quot;&gt;return&lt;/span&gt; &lt;span class=&quot;String&quot;&gt;&lt;span class=&quot;String&quot;&gt;&amp;quot;&lt;/span&gt;&lt;span class=&quot;String&quot;&gt;&amp;quot;&lt;/span&gt;&lt;/span&gt;;
    }
  }

}
&lt;/pre&gt;&lt;/div&gt;&lt;h2&gt;4. In Guice servlet module bind servlet what responds to redirect url&lt;/h2&gt;
&lt;div class=&quot;uv&quot;&gt;&lt;pre class=&quot;lazy&quot;&gt;
bindConstant().annotatedWith(named(&lt;span class=&quot;String&quot;&gt;&lt;span class=&quot;String&quot;&gt;&amp;quot;&lt;/span&gt;uploadFinishedPath&lt;span class=&quot;String&quot;&gt;&amp;quot;&lt;/span&gt;&lt;/span&gt;)).to(&lt;span class=&quot;String&quot;&gt;&lt;span class=&quot;String&quot;&gt;&amp;quot;&lt;/span&gt;/upload/finished&lt;span class=&quot;String&quot;&gt;&amp;quot;&lt;/span&gt;&lt;/span&gt;);
bindConstant().annotatedWith(named(&lt;span class=&quot;String&quot;&gt;&lt;span class=&quot;String&quot;&gt;&amp;quot;&lt;/span&gt;uploadFileField&lt;span class=&quot;String&quot;&gt;&amp;quot;&lt;/span&gt;&lt;/span&gt;)).to(&lt;span class=&quot;Keyword&quot;&gt;UploadFinishedServlet&lt;/span&gt;.&lt;span class=&quot;Constant&quot;&gt;FILE_FIELD&lt;/span&gt;);
serve(&lt;span class=&quot;Keyword&quot;&gt;UploadedServlet&lt;/span&gt;.&lt;span class=&quot;Constant&quot;&gt;REDIRECT_TO&lt;/span&gt;).with(&lt;span class=&quot;Keyword&quot;&gt;CommitUploadServlet&lt;/span&gt;.&lt;span class=&quot;Keyword&quot;&gt;class&lt;/span&gt;);
&lt;/pre&gt;&lt;/div&gt;&lt;div class=&quot;uv&quot;&gt;&lt;pre class=&quot;lazy&quot;&gt;
@&lt;span class=&quot;Keyword&quot;&gt;Singleton&lt;/span&gt;
&lt;span class=&quot;Keyword&quot;&gt;public &lt;/span&gt;&lt;span class=&quot;Keyword&quot;&gt;class&lt;/span&gt; &lt;span class=&quot;Entity&quot;&gt;CommitUploadServlet&lt;/span&gt; &lt;span class=&quot;Keyword&quot;&gt;extends&lt;/span&gt; &lt;span class=&quot;Keyword&quot;&gt;HttpServlet&lt;/span&gt; {

  @&lt;span class=&quot;Support&quot;&gt;Override&lt;/span&gt;
  &lt;span class=&quot;Keyword&quot;&gt;protected &lt;/span&gt;&lt;span class=&quot;Keyword&quot;&gt;void&lt;/span&gt; &lt;span class=&quot;Entity&quot;&gt;doGet&lt;/span&gt;(&lt;span class=&quot;Keyword&quot;&gt;HttpServletRequest&lt;/span&gt; req, &lt;span class=&quot;Keyword&quot;&gt;HttpServletResponse&lt;/span&gt; resp) 
      &lt;span class=&quot;Keyword&quot;&gt;throws&lt;/span&gt; &lt;span class=&quot;Keyword&quot;&gt;ServletException&lt;/span&gt;, &lt;span class=&quot;Support&quot;&gt;IOException&lt;/span&gt; {

    &lt;span class=&quot;Support&quot;&gt;String&lt;/span&gt; key = req.getParameter(&lt;span class=&quot;Keyword&quot;&gt;UploadFinishedServlet&lt;/span&gt;.&lt;span class=&quot;Constant&quot;&gt;KEY_PARAMETER&lt;/span&gt;);

    resp.setContentType(&lt;span class=&quot;String&quot;&gt;&lt;span class=&quot;String&quot;&gt;&amp;quot;&lt;/span&gt;text/html&lt;span class=&quot;String&quot;&gt;&amp;quot;&lt;/span&gt;&lt;/span&gt;);
    resp.setStatus(&lt;span class=&quot;Constant&quot;&gt;200&lt;/span&gt;);

    &lt;span class=&quot;Support&quot;&gt;String&lt;/span&gt; result = key &lt;span class=&quot;Keyword&quot;&gt;!=&lt;/span&gt; &lt;span class=&quot;Constant&quot;&gt;null&lt;/span&gt; ? key : &lt;span class=&quot;String&quot;&gt;&lt;span class=&quot;String&quot;&gt;&amp;quot;&lt;/span&gt;&lt;span class=&quot;String&quot;&gt;&amp;quot;&lt;/span&gt;&lt;/span&gt;;
    resp.getOutputStream().write(result.getBytes());
  }

}
&lt;/pre&gt;&lt;/div&gt;</content>
</entry>


  <entry>
  <title>LayoutPanel Fill Parent in GWT-2.0</title>
  <link href="/articles/2009/12/09/layoutpanel-fill-parent.html" />
  <id>tag:www.amateurinmotion.com,2009-12-09:1260358926</id>
  <updated>2009-12-09T13:42:06+02:00</updated>
  <content type="html">&lt;p&gt;When I started constructing UI with GWT 2.0 &lt;code&gt;LayoutPanel&lt;/code&gt;s it had &lt;code&gt;Layout&lt;/code&gt; instance publicly available but somewhere between 2.0.0-ms2 and 2.0.0-rc2 the API has changed and now &lt;code&gt;Layout&lt;/code&gt; is available only via &lt;code&gt;LayoutPanel#setWidget*&lt;/code&gt; methods. This left me with non functional UI because I had used &lt;code&gt;getLayout().fillParent()&lt;/code&gt; calls what forces Widget to fill its parent element. Why? Because most of UI is constructed with floating panels what are resizable and has container element for it&amp;#8217;s content what may be LayoutPanel instance.&lt;/p&gt;
&lt;p&gt;I&amp;#8217;m not arguing that &lt;code&gt;fillParent()&lt;/code&gt; &lt;em&gt;should&lt;/em&gt; be publicly available (child widget should not be aware of it&amp;#8217;s parent (in)capabilities but parent should be able to force child &lt;code&gt;LayoutPanel&lt;/code&gt; to fill it&amp;#8217;s content, ideally without knowing it&amp;#8217;s &lt;code&gt;LayoutPanel&lt;/code&gt;).&lt;/p&gt;
&lt;p&gt;So here is kind-of hack to get back &lt;code&gt;fillParent()&lt;/code&gt; in 2.0 release. This is wrapper widget what can be added in for example &lt;code&gt;FloatingPanel&lt;/code&gt;:&lt;/p&gt;
&lt;div class=&quot;uv&quot;&gt;&lt;pre class=&quot;lazy&quot;&gt;
&lt;span class=&quot;Keyword&quot;&gt;package&lt;/span&gt; &lt;span class=&quot;Entity&quot;&gt;com.google.gwt.user.client.ui&lt;/span&gt;;

&lt;span class=&quot;Keyword&quot;&gt;import&lt;/span&gt; &lt;span class=&quot;Entity&quot;&gt;com.google.gwt.dom.client.Style&lt;/span&gt;;

import &lt;span class=&quot;Keyword&quot;&gt;static&lt;/span&gt; &lt;span class=&quot;Keyword&quot;&gt;com.google.gwt.dom.client.Style&lt;/span&gt;.&lt;span class=&quot;Keyword&quot;&gt;Overflow&lt;/span&gt;.&lt;span class=&quot;Constant&quot;&gt;HIDDEN&lt;/span&gt;;
import &lt;span class=&quot;Keyword&quot;&gt;static&lt;/span&gt; &lt;span class=&quot;Keyword&quot;&gt;com.google.gwt.dom.client.Style&lt;/span&gt;.&lt;span class=&quot;Support&quot;&gt;Position&lt;/span&gt;.&lt;span class=&quot;Constant&quot;&gt;RELATIVE&lt;/span&gt;;
import &lt;span class=&quot;Keyword&quot;&gt;static&lt;/span&gt; &lt;span class=&quot;Keyword&quot;&gt;com.google.gwt.dom.client.Style&lt;/span&gt;.&lt;span class=&quot;Keyword&quot;&gt;Unit&lt;/span&gt;.&lt;span class=&quot;Constant&quot;&gt;PCT&lt;/span&gt;;

&lt;span class=&quot;Comment&quot;&gt;&lt;span class=&quot;Comment&quot;&gt;/**&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;Comment&quot;&gt; * Widget what extends &lt;span class=&quot;Keyword&quot;&gt;{@link com.google.gwt.user.client.ui.SimplePanel}&lt;/span&gt; and can be used as &lt;/span&gt;
&lt;span class=&quot;Comment&quot;&gt; * &amp;quot;host&amp;quot; for &lt;span class=&quot;Keyword&quot;&gt;{@link com.google.gwt.user.client.ui.LayoutPanel}&lt;/span&gt; inside &lt;/span&gt;
&lt;span class=&quot;Comment&quot;&gt; * non-&lt;span class=&quot;Keyword&quot;&gt;{@link com.google.gwt.layout.client.Layout}&lt;/span&gt; based UI.&lt;/span&gt;
&lt;span class=&quot;Comment&quot;&gt; * &amp;lt;p/&amp;gt;&lt;/span&gt;
&lt;span class=&quot;Comment&quot;&gt; * This widget forces &lt;span class=&quot;Keyword&quot;&gt;{@link com.google.gwt.user.client.ui.LayoutPanel}&lt;/span&gt; to fill host &lt;/span&gt;
&lt;span class=&quot;Comment&quot;&gt; * dimensions by calling &lt;span class=&quot;Keyword&quot;&gt;{@link com.google.gwt.layout.client.Layout#fillParent()}&lt;/span&gt; in&lt;/span&gt;
&lt;span class=&quot;Comment&quot;&gt; * &lt;span class=&quot;Keyword&quot;&gt;{@link com.google.gwt.user.client.ui.LayoutPanelHost#setWidget(Widget)}&lt;/span&gt;.&lt;/span&gt;
&lt;span class=&quot;Comment&quot;&gt; *&lt;/span&gt;
&lt;span class=&quot;Comment&quot;&gt; * &lt;span class=&quot;Keyword&quot;&gt;@author&lt;/span&gt; ampatspell&lt;/span&gt;
&lt;span class=&quot;Comment&quot;&gt; &lt;span class=&quot;Comment&quot;&gt;*/&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;Keyword&quot;&gt;public &lt;/span&gt;&lt;span class=&quot;Keyword&quot;&gt;class&lt;/span&gt; &lt;span class=&quot;Entity&quot;&gt;LayoutPanelHost&lt;/span&gt; &lt;span class=&quot;Keyword&quot;&gt;extends&lt;/span&gt; &lt;span class=&quot;Keyword&quot;&gt;SimplePanel&lt;/span&gt; &lt;span class=&quot;Keyword&quot;&gt;implements&lt;/span&gt; &lt;span class=&quot;Keyword&quot;&gt;RequiresResize&lt;/span&gt; {

  &lt;span class=&quot;Keyword&quot;&gt;public &lt;/span&gt;&lt;span class=&quot;Entity&quot;&gt;LayoutPanelHost&lt;/span&gt;() {
    &lt;span class=&quot;Variable&quot;&gt;this&lt;/span&gt;(&lt;span class=&quot;Constant&quot;&gt;null&lt;/span&gt;);
  }

&lt;span class=&quot;Comment&quot;&gt;&lt;span class=&quot;Comment&quot;&gt;  /**&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;Comment&quot;&gt;   * Child may be null&lt;/span&gt;
&lt;span class=&quot;Comment&quot;&gt;   *&lt;/span&gt;
&lt;span class=&quot;Comment&quot;&gt;   * &lt;span class=&quot;Keyword&quot;&gt;@param&lt;/span&gt; child widget to set&lt;/span&gt;
&lt;span class=&quot;Comment&quot;&gt;   &lt;span class=&quot;Comment&quot;&gt;*/&lt;/span&gt;&lt;/span&gt;
  &lt;span class=&quot;Keyword&quot;&gt;public &lt;/span&gt;&lt;span class=&quot;Entity&quot;&gt;LayoutPanelHost&lt;/span&gt;(&lt;span class=&quot;Keyword&quot;&gt;Widget&lt;/span&gt; child) {
    &lt;span class=&quot;Support&quot;&gt;Style&lt;/span&gt; style = getElement().getStyle();
    style.setPosition(&lt;span class=&quot;Constant&quot;&gt;RELATIVE&lt;/span&gt;);
    style.setWidth(&lt;span class=&quot;Constant&quot;&gt;100&lt;/span&gt;, &lt;span class=&quot;Constant&quot;&gt;PCT&lt;/span&gt;);
    style.setHeight(&lt;span class=&quot;Constant&quot;&gt;100&lt;/span&gt;, &lt;span class=&quot;Constant&quot;&gt;PCT&lt;/span&gt;);
    &lt;span class=&quot;Comment&quot;&gt;&lt;span class=&quot;Comment&quot;&gt;//&lt;/span&gt; overflow: hidden is to hide ruler element what is added by Layout&lt;/span&gt;
    style.setOverflow(&lt;span class=&quot;Constant&quot;&gt;HIDDEN&lt;/span&gt;);

    &lt;span class=&quot;Keyword&quot;&gt;if&lt;/span&gt; (child &lt;span class=&quot;Keyword&quot;&gt;!=&lt;/span&gt; &lt;span class=&quot;Constant&quot;&gt;null&lt;/span&gt;)
      setWidget(child);
  }

&lt;span class=&quot;Comment&quot;&gt;&lt;span class=&quot;Comment&quot;&gt;  /**&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;Comment&quot;&gt;   * If widget is instanceof &lt;span class=&quot;Keyword&quot;&gt;{@link com.google.gwt.user.client.ui.LayoutPanel}&lt;/span&gt;,&lt;/span&gt;
&lt;span class=&quot;Comment&quot;&gt;   * &lt;span class=&quot;Keyword&quot;&gt;{@link com.google.gwt.layout.client.Layout#fillParent()}&lt;/span&gt; is called for it.&lt;/span&gt;
&lt;span class=&quot;Comment&quot;&gt;   *&lt;/span&gt;
&lt;span class=&quot;Comment&quot;&gt;   * &lt;span class=&quot;Keyword&quot;&gt;@param&lt;/span&gt; w any widget or null&lt;/span&gt;
&lt;span class=&quot;Comment&quot;&gt;   &lt;span class=&quot;Comment&quot;&gt;*/&lt;/span&gt;&lt;/span&gt;
  @&lt;span class=&quot;Support&quot;&gt;Override&lt;/span&gt;
  &lt;span class=&quot;Keyword&quot;&gt;public &lt;/span&gt;&lt;span class=&quot;Keyword&quot;&gt;void&lt;/span&gt; &lt;span class=&quot;Entity&quot;&gt;setWidget&lt;/span&gt;(&lt;span class=&quot;Keyword&quot;&gt;Widget&lt;/span&gt; w) {
    &lt;span class=&quot;Keyword&quot;&gt;LayoutPanel&lt;/span&gt; layoutPanel = cast(w);
    &lt;span class=&quot;Keyword&quot;&gt;if&lt;/span&gt; (layoutPanel &lt;span class=&quot;Keyword&quot;&gt;!=&lt;/span&gt; &lt;span class=&quot;Constant&quot;&gt;null&lt;/span&gt;)
      layoutPanel.getLayout().fillParent();
    &lt;span class=&quot;Variable&quot;&gt;super&lt;/span&gt;.setWidget(w);
  }

&lt;span class=&quot;Comment&quot;&gt;&lt;span class=&quot;Comment&quot;&gt;  /**&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;Comment&quot;&gt;   * Delegates call to &lt;span class=&quot;Keyword&quot;&gt;{@link com.google.gwt.user.client.ui.LayoutPanel}&lt;/span&gt;.&lt;/span&gt;
&lt;span class=&quot;Comment&quot;&gt;   * Should be called whenever this Widget or some of its parents are resized. &lt;/span&gt;
&lt;span class=&quot;Comment&quot;&gt;   * Normally &lt;span class=&quot;Keyword&quot;&gt;{@link LayoutPanel#onResize()}&lt;/span&gt; is called automatically by GWT Layout API &lt;/span&gt;
&lt;span class=&quot;Comment&quot;&gt;   * but here it is impossible as there is no way (except from polling) to get informed &lt;/span&gt;
&lt;span class=&quot;Comment&quot;&gt;   * about Element dimension changes.&lt;/span&gt;
&lt;span class=&quot;Comment&quot;&gt;   *&lt;/span&gt;
&lt;span class=&quot;Comment&quot;&gt;   * Update: Is it really needed? LayoutImplIE6 adds js hook to onresize.&lt;/span&gt;
&lt;span class=&quot;Comment&quot;&gt;   &lt;span class=&quot;Comment&quot;&gt;*/&lt;/span&gt;&lt;/span&gt;
  &lt;span class=&quot;Keyword&quot;&gt;public &lt;/span&gt;&lt;span class=&quot;Keyword&quot;&gt;void&lt;/span&gt; &lt;span class=&quot;Entity&quot;&gt;onResize&lt;/span&gt;() {
    &lt;span class=&quot;Keyword&quot;&gt;LayoutPanel&lt;/span&gt; layoutPanel = cast(getWidget());
    &lt;span class=&quot;Keyword&quot;&gt;if&lt;/span&gt; (layoutPanel &lt;span class=&quot;Keyword&quot;&gt;!=&lt;/span&gt; &lt;span class=&quot;Constant&quot;&gt;null&lt;/span&gt;)
      layoutPanel.onResize();
  }

&lt;span class=&quot;Comment&quot;&gt;&lt;span class=&quot;Comment&quot;&gt;  /**&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;Comment&quot;&gt;   * Casts &lt;span class=&quot;Keyword&quot;&gt;{@link com.google.gwt.user.client.ui.Widget}&lt;/span&gt; or &lt;/span&gt;
&lt;span class=&quot;Comment&quot;&gt;   * &lt;span class=&quot;Keyword&quot;&gt;{@link com.google.gwt.user.client.ui.Composite}&lt;/span&gt; child widget&lt;/span&gt;
&lt;span class=&quot;Comment&quot;&gt;   * to &lt;span class=&quot;Keyword&quot;&gt;{@link com.google.gwt.user.client.ui.LayoutPanel}&lt;/span&gt; if widget is not null and&lt;/span&gt;
&lt;span class=&quot;Comment&quot;&gt;   * is instanceof &lt;span class=&quot;Keyword&quot;&gt;{@link com.google.gwt.user.client.ui.LayoutPanel}&lt;/span&gt;.&lt;/span&gt;
&lt;span class=&quot;Comment&quot;&gt;   *&lt;/span&gt;
&lt;span class=&quot;Comment&quot;&gt;   * &lt;span class=&quot;Keyword&quot;&gt;@param&lt;/span&gt; widget Widget&lt;/span&gt;
&lt;span class=&quot;Comment&quot;&gt;   * &lt;span class=&quot;Keyword&quot;&gt;@return&lt;/span&gt; widget casted to LayoutPanel or null&lt;/span&gt;
&lt;span class=&quot;Comment&quot;&gt;   &lt;span class=&quot;Comment&quot;&gt;*/&lt;/span&gt;&lt;/span&gt;
  &lt;span class=&quot;Keyword&quot;&gt;private &lt;/span&gt;&lt;span class=&quot;Keyword&quot;&gt;LayoutPanel&lt;/span&gt; &lt;span class=&quot;Entity&quot;&gt;cast&lt;/span&gt;(&lt;span class=&quot;Keyword&quot;&gt;Widget&lt;/span&gt; widget) {
    &lt;span class=&quot;Keyword&quot;&gt;Widget&lt;/span&gt; w = getActualWidget(widget);
    &lt;span class=&quot;Keyword&quot;&gt;if&lt;/span&gt; (w &lt;span class=&quot;Keyword&quot;&gt;!=&lt;/span&gt; &lt;span class=&quot;Constant&quot;&gt;null&lt;/span&gt; &lt;span class=&quot;Keyword&quot;&gt;&amp;amp;&amp;amp;&lt;/span&gt; w &lt;span class=&quot;Keyword&quot;&gt;instanceof&lt;/span&gt; &lt;span class=&quot;Keyword&quot;&gt;LayoutPanel&lt;/span&gt;)
      &lt;span class=&quot;Keyword&quot;&gt;return&lt;/span&gt; (&lt;span class=&quot;Keyword&quot;&gt;LayoutPanel&lt;/span&gt;) w;
    &lt;span class=&quot;Keyword&quot;&gt;return&lt;/span&gt; &lt;span class=&quot;Constant&quot;&gt;null&lt;/span&gt;;
  }

  &lt;span class=&quot;Keyword&quot;&gt;private &lt;/span&gt;&lt;span class=&quot;Keyword&quot;&gt;Widget&lt;/span&gt; &lt;span class=&quot;Entity&quot;&gt;getActualWidget&lt;/span&gt;(&lt;span class=&quot;Keyword&quot;&gt;Widget&lt;/span&gt; widget) {
    &lt;span class=&quot;Keyword&quot;&gt;if&lt;/span&gt; (widget &lt;span class=&quot;Keyword&quot;&gt;!=&lt;/span&gt; &lt;span class=&quot;Constant&quot;&gt;null&lt;/span&gt; &lt;span class=&quot;Keyword&quot;&gt;&amp;amp;&amp;amp;&lt;/span&gt; widget &lt;span class=&quot;Keyword&quot;&gt;instanceof&lt;/span&gt; &lt;span class=&quot;Support&quot;&gt;Composite&lt;/span&gt;) {
      &lt;span class=&quot;Keyword&quot;&gt;return&lt;/span&gt; ((&lt;span class=&quot;Support&quot;&gt;Composite&lt;/span&gt;) widget).getWidget();
    }
    &lt;span class=&quot;Keyword&quot;&gt;return&lt;/span&gt; widget;
  }

}
&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;Usage:&lt;/p&gt;
&lt;div class=&quot;uv&quot;&gt;&lt;pre class=&quot;lazy&quot;&gt;
&lt;span class=&quot;Keyword&quot;&gt;FlowPanel&lt;/span&gt; base = &lt;span class=&quot;Keyword&quot;&gt;new&lt;/span&gt; &lt;span class=&quot;Keyword&quot;&gt;FlowPanel&lt;/span&gt;();
base.add(&lt;span class=&quot;Keyword&quot;&gt;new&lt;/span&gt; &lt;span class=&quot;Keyword&quot;&gt;LayoutPanelHost&lt;/span&gt;(content = &lt;span class=&quot;Keyword&quot;&gt;new&lt;/span&gt; &lt;span class=&quot;Keyword&quot;&gt;SomeLayoutPanel&lt;/span&gt;()));
&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;Here &lt;code&gt;SomeLayoutPanel&lt;/code&gt; now fills entire &lt;code&gt;base&lt;/code&gt; element.&lt;/p&gt;
&lt;p&gt;&lt;b&gt;Update:&lt;/b&gt; Forgot to mention that on modern browsers instead of this simple &lt;code&gt;Widget#setSize&lt;/code&gt; should work:&lt;/p&gt;
&lt;div class=&quot;uv&quot;&gt;&lt;pre class=&quot;lazy&quot;&gt;
&lt;span class=&quot;Keyword&quot;&gt;FlowPanel&lt;/span&gt; base = &lt;span class=&quot;Keyword&quot;&gt;new&lt;/span&gt; &lt;span class=&quot;Keyword&quot;&gt;FlowPanel&lt;/span&gt;();
base.add(content = &lt;span class=&quot;Keyword&quot;&gt;new&lt;/span&gt; &lt;span class=&quot;Keyword&quot;&gt;SomeLayoutPanel&lt;/span&gt;());
content.setSize(&lt;span class=&quot;String&quot;&gt;&lt;span class=&quot;String&quot;&gt;&amp;quot;&lt;/span&gt;100%&lt;span class=&quot;String&quot;&gt;&amp;quot;&lt;/span&gt;&lt;/span&gt;, &lt;span class=&quot;String&quot;&gt;&lt;span class=&quot;String&quot;&gt;&amp;quot;&lt;/span&gt;100%&lt;span class=&quot;String&quot;&gt;&amp;quot;&lt;/span&gt;&lt;/span&gt;);
&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;But looking at &lt;code&gt;LayoutImplIE6&lt;/code&gt; it seems that won&amp;#8217;t work reliably in IE6 (if anyone cares). Also see note in &lt;code&gt;LayoutPanelHost#onResize&lt;/code&gt; method docs. Sorry, currently I can&amp;#8217;t test it in IE6 so I&amp;#8217;m not sure.&lt;/p&gt;
&lt;p&gt;&lt;b&gt;Update #2:&lt;/b&gt; LayoutPanelHost#cast now supports Composite and ResizeComposite.&lt;/p&gt;
&lt;h2&gt;With UIBinder&lt;/h2&gt;
&lt;p&gt;It turns out this helper class is also needed to compose Layout-based UIs using &lt;code&gt;UIBinder&lt;/code&gt; while following MVP.&lt;/p&gt;
&lt;p&gt;Let&amp;#8217;s consider simple case. I have &lt;code&gt;Workspace&lt;/code&gt; MVP stack what can contain either &lt;code&gt;Index&lt;/code&gt;, &lt;code&gt;People&lt;/code&gt; or &lt;code&gt;Projects&lt;/code&gt; &amp;#8220;content&amp;#8221; presenter&amp;#8217;s view:&lt;/p&gt;
&lt;div class=&quot;uv&quot;&gt;&lt;pre class=&quot;lazy&quot;&gt;
&lt;span class=&quot;Comment&quot;&gt;&lt;span class=&quot;Comment&quot;&gt;&amp;lt;!--&lt;/span&gt; Workspace.ui.xml &lt;span class=&quot;Comment&quot;&gt;--&amp;gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;MetaTag&quot;&gt;&lt;span class=&quot;MetaTag&quot;&gt;&amp;lt;&lt;/span&gt;&lt;span class=&quot;MetaTag&quot;&gt;g&lt;/span&gt;&lt;span class=&quot;MetaTag&quot;&gt;&lt;span class=&quot;MetaTag&quot;&gt;:&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;MetaTag&quot;&gt;LayoutPanel&lt;/span&gt;&lt;span class=&quot;MetaTag&quot;&gt;&amp;gt;&lt;/span&gt;&lt;/span&gt;
  &lt;span class=&quot;MetaTag&quot;&gt;&lt;span class=&quot;MetaTag&quot;&gt;&amp;lt;&lt;/span&gt;&lt;span class=&quot;MetaTag&quot;&gt;g&lt;/span&gt;&lt;span class=&quot;MetaTag&quot;&gt;&lt;span class=&quot;MetaTag&quot;&gt;:&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;MetaTag&quot;&gt;layer&lt;/span&gt; &lt;span class=&quot;MetaTag&quot;&gt;top&lt;/span&gt;=&lt;span class=&quot;String&quot;&gt;&lt;span class=&quot;String&quot;&gt;&amp;quot;&lt;/span&gt;0px&lt;span class=&quot;String&quot;&gt;&amp;quot;&lt;/span&gt;&lt;/span&gt; &lt;span class=&quot;MetaTag&quot;&gt;height&lt;/span&gt;=&lt;span class=&quot;String&quot;&gt;&lt;span class=&quot;String&quot;&gt;&amp;quot;&lt;/span&gt;30px&lt;span class=&quot;String&quot;&gt;&amp;quot;&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;MetaTag&quot;&gt;&amp;gt;&lt;/span&gt;&lt;/span&gt;
    &lt;span class=&quot;Comment&quot;&gt;&lt;span class=&quot;Comment&quot;&gt;&amp;lt;!--&lt;/span&gt; Some header or whatever &lt;span class=&quot;Comment&quot;&gt;--&amp;gt;&lt;/span&gt;&lt;/span&gt;
  &lt;span class=&quot;MetaTag&quot;&gt;&lt;span class=&quot;MetaTag&quot;&gt;&amp;lt;/&lt;/span&gt;&lt;span class=&quot;MetaTag&quot;&gt;g&lt;/span&gt;&lt;span class=&quot;MetaTag&quot;&gt;&lt;span class=&quot;MetaTag&quot;&gt;:&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;MetaTag&quot;&gt;layer&lt;/span&gt;&lt;span class=&quot;MetaTag&quot;&gt;&amp;gt;&lt;/span&gt;&lt;/span&gt;
  &lt;span class=&quot;MetaTag&quot;&gt;&lt;span class=&quot;MetaTag&quot;&gt;&amp;lt;&lt;/span&gt;&lt;span class=&quot;MetaTag&quot;&gt;g&lt;/span&gt;&lt;span class=&quot;MetaTag&quot;&gt;&lt;span class=&quot;MetaTag&quot;&gt;:&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;MetaTag&quot;&gt;layer&lt;/span&gt; &lt;span class=&quot;MetaTag&quot;&gt;top&lt;/span&gt;=&lt;span class=&quot;String&quot;&gt;&lt;span class=&quot;String&quot;&gt;&amp;quot;&lt;/span&gt;30px&lt;span class=&quot;String&quot;&gt;&amp;quot;&lt;/span&gt;&lt;/span&gt; &lt;span class=&quot;MetaTag&quot;&gt;bottom&lt;/span&gt;=&lt;span class=&quot;String&quot;&gt;&lt;span class=&quot;String&quot;&gt;&amp;quot;&lt;/span&gt;0px&lt;span class=&quot;String&quot;&gt;&amp;quot;&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;MetaTag&quot;&gt;&amp;gt;&lt;/span&gt;&lt;/span&gt;
    &lt;span class=&quot;MetaTag&quot;&gt;&lt;span class=&quot;MetaTag&quot;&gt;&amp;lt;&lt;/span&gt;&lt;span class=&quot;MetaTag&quot;&gt;g&lt;/span&gt;&lt;span class=&quot;MetaTag&quot;&gt;&lt;span class=&quot;MetaTag&quot;&gt;:&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;MetaTag&quot;&gt;LayoutPanelHost&lt;/span&gt; &lt;span class=&quot;MetaTag&quot;&gt;ui&lt;/span&gt;&lt;span class=&quot;MetaTag&quot;&gt;&lt;span class=&quot;MetaTag&quot;&gt;:&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;MetaTag&quot;&gt;field&lt;/span&gt;=&lt;span class=&quot;String&quot;&gt;&lt;span class=&quot;String&quot;&gt;&amp;quot;&lt;/span&gt;content&lt;span class=&quot;String&quot;&gt;&amp;quot;&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;MetaTag&quot;&gt;/&amp;gt;&lt;/span&gt;&lt;/span&gt;
  &lt;span class=&quot;MetaTag&quot;&gt;&lt;span class=&quot;MetaTag&quot;&gt;&amp;lt;/&lt;/span&gt;&lt;span class=&quot;MetaTag&quot;&gt;g&lt;/span&gt;&lt;span class=&quot;MetaTag&quot;&gt;&lt;span class=&quot;MetaTag&quot;&gt;:&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;MetaTag&quot;&gt;layer&lt;/span&gt;&lt;span class=&quot;MetaTag&quot;&gt;&amp;gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;MetaTag&quot;&gt;&lt;span class=&quot;MetaTag&quot;&gt;&amp;lt;/&lt;/span&gt;&lt;span class=&quot;MetaTag&quot;&gt;g&lt;/span&gt;&lt;span class=&quot;MetaTag&quot;&gt;&lt;span class=&quot;MetaTag&quot;&gt;:&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;MetaTag&quot;&gt;LayoutPanel&lt;/span&gt;&lt;span class=&quot;MetaTag&quot;&gt;&amp;gt;&lt;/span&gt;&lt;/span&gt;
&lt;/pre&gt;&lt;/div&gt;&lt;div class=&quot;uv&quot;&gt;&lt;pre class=&quot;lazy&quot;&gt;
&lt;span class=&quot;Comment&quot;&gt;&lt;span class=&quot;Comment&quot;&gt;//&lt;/span&gt; WorkspacePresenterImpl&lt;/span&gt;
view.setContentView(presenter.getView());
&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;Where given presenter instance has view based on &lt;code&gt;LayoutPanel&lt;/code&gt;:&lt;/p&gt;
&lt;div class=&quot;uv&quot;&gt;&lt;pre class=&quot;lazy&quot;&gt;
&lt;span class=&quot;MetaTag&quot;&gt;&lt;span class=&quot;MetaTag&quot;&gt;&amp;lt;&lt;/span&gt;&lt;span class=&quot;MetaTag&quot;&gt;g&lt;/span&gt;&lt;span class=&quot;MetaTag&quot;&gt;&lt;span class=&quot;MetaTag&quot;&gt;:&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;MetaTag&quot;&gt;LayoutPanel&lt;/span&gt;&lt;span class=&quot;MetaTag&quot;&gt;&amp;gt;&lt;/span&gt;&lt;/span&gt;
  &lt;span class=&quot;MetaTag&quot;&gt;&lt;span class=&quot;MetaTag&quot;&gt;&amp;lt;&lt;/span&gt;&lt;span class=&quot;MetaTag&quot;&gt;g&lt;/span&gt;&lt;span class=&quot;MetaTag&quot;&gt;&lt;span class=&quot;MetaTag&quot;&gt;:&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;MetaTag&quot;&gt;layer&lt;/span&gt; &lt;span class=&quot;MetaTag&quot;&gt;top&lt;/span&gt;=&lt;span class=&quot;String&quot;&gt;&lt;span class=&quot;String&quot;&gt;&amp;quot;&lt;/span&gt;0px&lt;span class=&quot;String&quot;&gt;&amp;quot;&lt;/span&gt;&lt;/span&gt; &lt;span class=&quot;MetaTag&quot;&gt;height&lt;/span&gt;=&lt;span class=&quot;String&quot;&gt;&lt;span class=&quot;String&quot;&gt;&amp;quot;&lt;/span&gt;50px&lt;span class=&quot;String&quot;&gt;&amp;quot;&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;MetaTag&quot;&gt;&amp;gt;&lt;/span&gt;&lt;/span&gt;
  &lt;span class=&quot;MetaTag&quot;&gt;&lt;span class=&quot;MetaTag&quot;&gt;&amp;lt;/&lt;/span&gt;&lt;span class=&quot;MetaTag&quot;&gt;g&lt;/span&gt;&lt;span class=&quot;MetaTag&quot;&gt;&lt;span class=&quot;MetaTag&quot;&gt;:&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;MetaTag&quot;&gt;layer&lt;/span&gt;&lt;span class=&quot;MetaTag&quot;&gt;&amp;gt;&lt;/span&gt;&lt;/span&gt;
  &lt;span class=&quot;MetaTag&quot;&gt;&lt;span class=&quot;MetaTag&quot;&gt;&amp;lt;&lt;/span&gt;&lt;span class=&quot;MetaTag&quot;&gt;g&lt;/span&gt;&lt;span class=&quot;MetaTag&quot;&gt;&lt;span class=&quot;MetaTag&quot;&gt;:&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;MetaTag&quot;&gt;layer&lt;/span&gt; &lt;span class=&quot;MetaTag&quot;&gt;top&lt;/span&gt;=&lt;span class=&quot;String&quot;&gt;&lt;span class=&quot;String&quot;&gt;&amp;quot;&lt;/span&gt;50px&lt;span class=&quot;String&quot;&gt;&amp;quot;&lt;/span&gt;&lt;/span&gt; &lt;span class=&quot;MetaTag&quot;&gt;bottom&lt;/span&gt;=&lt;span class=&quot;String&quot;&gt;&lt;span class=&quot;String&quot;&gt;&amp;quot;&lt;/span&gt;0px&lt;span class=&quot;String&quot;&gt;&amp;quot;&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;MetaTag&quot;&gt;&amp;gt;&lt;/span&gt;&lt;/span&gt;
  &lt;span class=&quot;MetaTag&quot;&gt;&lt;span class=&quot;MetaTag&quot;&gt;&amp;lt;/&lt;/span&gt;&lt;span class=&quot;MetaTag&quot;&gt;g&lt;/span&gt;&lt;span class=&quot;MetaTag&quot;&gt;&lt;span class=&quot;MetaTag&quot;&gt;:&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;MetaTag&quot;&gt;layer&lt;/span&gt;&lt;span class=&quot;MetaTag&quot;&gt;&amp;gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;MetaTag&quot;&gt;&lt;span class=&quot;MetaTag&quot;&gt;&amp;lt;/&lt;/span&gt;&lt;span class=&quot;MetaTag&quot;&gt;g&lt;/span&gt;&lt;span class=&quot;MetaTag&quot;&gt;&lt;span class=&quot;MetaTag&quot;&gt;:&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;MetaTag&quot;&gt;LayoutPanel&lt;/span&gt;&lt;span class=&quot;MetaTag&quot;&gt;&amp;gt;&lt;/span&gt;&lt;/span&gt;
&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;If &lt;code&gt;Layout#fillParent()&lt;/code&gt; is not called for workspace content widget the widget must set it&amp;#8217;s height explicitly (i.e. for example &lt;code&gt;bottom=&quot;0px&quot;&lt;/code&gt; doesn&amp;#8217;t work).&lt;/p&gt;</content>
</entry>


  <entry>
  <title>Attaching Artifacts to Maven Project in Mojo</title>
  <link href="/articles/2009/11/26/attaching-artifacts-to-maven-project.html" />
  <id>tag:www.amateurinmotion.com,2009-11-26:1259219841</id>
  <updated>2009-11-26T09:17:21+02:00</updated>
  <content type="html">&lt;p&gt;While writing a GWT &amp;amp; AppEngine plugin for Maven I came across the Maven concept of &amp;#8220;attached&amp;#8221; artifacts. While project in Maven can have one &amp;#8220;main&amp;#8221; artifact, it also can have unlimited count of &amp;#8220;attached&amp;#8221; artifacts like &lt;code&gt;sources&lt;/code&gt; or &lt;code&gt;javadoc&lt;/code&gt;. For GWT compile mojo I wanted to attach &lt;code&gt;gwt&lt;/code&gt; artifact what would be jar with compiled GWT module(s). This artifact then could be dependency for war project (module) and unpacked in appropriate folder in package phase.&lt;/p&gt;
&lt;p&gt;So, to create a jar and attach it as a attached artifact to maven project:&lt;/p&gt;
&lt;div class=&quot;uv&quot;&gt;&lt;pre class=&quot;lazy&quot;&gt;
&lt;span class=&quot;Keyword&quot;&gt;public &lt;/span&gt;&lt;span class=&quot;Keyword&quot;&gt;class&lt;/span&gt; &lt;span class=&quot;Entity&quot;&gt;DirectoryArtifactService&lt;/span&gt; {

  &lt;span class=&quot;Keyword&quot;&gt;private&lt;/span&gt; &lt;span class=&quot;Keyword&quot;&gt;final&lt;/span&gt; &lt;span class=&quot;Keyword&quot;&gt;Log&lt;/span&gt; log;
  &lt;span class=&quot;Keyword&quot;&gt;private&lt;/span&gt; &lt;span class=&quot;Keyword&quot;&gt;final&lt;/span&gt; &lt;span class=&quot;Keyword&quot;&gt;ArchiverManager&lt;/span&gt; archiverManager;
  &lt;span class=&quot;Keyword&quot;&gt;private&lt;/span&gt; &lt;span class=&quot;Keyword&quot;&gt;final&lt;/span&gt; &lt;span class=&quot;Keyword&quot;&gt;MavenProjectHelper&lt;/span&gt; mavenProjectHelper;
  &lt;span class=&quot;Keyword&quot;&gt;private&lt;/span&gt; &lt;span class=&quot;Keyword&quot;&gt;final&lt;/span&gt; &lt;span class=&quot;Keyword&quot;&gt;MavenProject&lt;/span&gt; mavenProject;

  &lt;span class=&quot;Keyword&quot;&gt;public &lt;/span&gt;&lt;span class=&quot;Entity&quot;&gt;DirectoryArtifactService&lt;/span&gt;(&lt;span class=&quot;Keyword&quot;&gt;Log&lt;/span&gt; log, &lt;span class=&quot;Keyword&quot;&gt;ArchiverManager&lt;/span&gt; archiverManager, 
      &lt;span class=&quot;Keyword&quot;&gt;MavenProjectHelper&lt;/span&gt; mavenProjectHelper, &lt;span class=&quot;Keyword&quot;&gt;MavenProject&lt;/span&gt; mavenProject) {
    &lt;span class=&quot;Variable&quot;&gt;this&lt;/span&gt;.log = log;
    &lt;span class=&quot;Variable&quot;&gt;this&lt;/span&gt;.archiverManager = archiverManager;
    &lt;span class=&quot;Variable&quot;&gt;this&lt;/span&gt;.mavenProjectHelper = mavenProjectHelper;
    &lt;span class=&quot;Variable&quot;&gt;this&lt;/span&gt;.mavenProject = mavenProject;
  }

  &lt;span class=&quot;Keyword&quot;&gt;public &lt;/span&gt;&lt;span class=&quot;Keyword&quot;&gt;File&lt;/span&gt; &lt;span class=&quot;Entity&quot;&gt;attachDirectoryArchive&lt;/span&gt;(&lt;span class=&quot;Support&quot;&gt;String&lt;/span&gt; finalName, &lt;span class=&quot;Support&quot;&gt;String&lt;/span&gt; classifier, 
      &lt;span class=&quot;Support&quot;&gt;File&lt;/span&gt; outputDirectory, &lt;span class=&quot;Support&quot;&gt;File&lt;/span&gt; moduleDirectory) &lt;span class=&quot;Keyword&quot;&gt;throws&lt;/span&gt; &lt;span class=&quot;Keyword&quot;&gt;MojoExecutionException&lt;/span&gt; {
    &lt;span class=&quot;Support&quot;&gt;String&lt;/span&gt; type = &lt;span class=&quot;String&quot;&gt;&lt;span class=&quot;String&quot;&gt;&amp;quot;&lt;/span&gt;jar&lt;span class=&quot;String&quot;&gt;&amp;quot;&lt;/span&gt;&lt;/span&gt;;
    &lt;span class=&quot;Support&quot;&gt;File&lt;/span&gt; output = &lt;span class=&quot;Keyword&quot;&gt;new&lt;/span&gt; &lt;span class=&quot;Support&quot;&gt;File&lt;/span&gt;(outputDirectory, 
      format(&lt;span class=&quot;String&quot;&gt;&lt;span class=&quot;String&quot;&gt;&amp;quot;&lt;/span&gt;%s-%s.%s&lt;span class=&quot;String&quot;&gt;&amp;quot;&lt;/span&gt;&lt;/span&gt;, finalName, classifier, type));
    createArchive(output, moduleDirectory);
    attachArchive(output, type, classifier);
    &lt;span class=&quot;Keyword&quot;&gt;return&lt;/span&gt; output;
  }

  &lt;span class=&quot;Keyword&quot;&gt;private &lt;/span&gt;&lt;span class=&quot;Keyword&quot;&gt;void&lt;/span&gt; &lt;span class=&quot;Entity&quot;&gt;createArchive&lt;/span&gt;(&lt;span class=&quot;Support&quot;&gt;File&lt;/span&gt; output, &lt;span class=&quot;Support&quot;&gt;File&lt;/span&gt; directory) &lt;span class=&quot;Keyword&quot;&gt;throws&lt;/span&gt; &lt;span class=&quot;Keyword&quot;&gt;MojoExecutionException&lt;/span&gt; {
    &lt;span class=&quot;Keyword&quot;&gt;try&lt;/span&gt; {
      log.info(&lt;span class=&quot;String&quot;&gt;&lt;span class=&quot;String&quot;&gt;&amp;quot;&lt;/span&gt;Creating archive &lt;span class=&quot;String&quot;&gt;&amp;quot;&lt;/span&gt;&lt;/span&gt; &lt;span class=&quot;Keyword&quot;&gt;+&lt;/span&gt; output &lt;span class=&quot;Keyword&quot;&gt;+&lt;/span&gt; &lt;span class=&quot;String&quot;&gt;&lt;span class=&quot;String&quot;&gt;&amp;quot;&lt;/span&gt; from &lt;span class=&quot;String&quot;&gt;&amp;quot;&lt;/span&gt;&lt;/span&gt; &lt;span class=&quot;Keyword&quot;&gt;+&lt;/span&gt; directory);
      &lt;span class=&quot;Keyword&quot;&gt;Archiver&lt;/span&gt; archiver = archiverManager.getArchiver(output);
      archiver.setDestFile(output);
      archiver.addDirectory(directory);
      archiver.createArchive();
    } &lt;span class=&quot;Keyword&quot;&gt;catch&lt;/span&gt; (&lt;span class=&quot;Keyword&quot;&gt;NoSuchArchiverException&lt;/span&gt; e) {
      &lt;span class=&quot;Keyword&quot;&gt;throw&lt;/span&gt; &lt;span class=&quot;Keyword&quot;&gt;new&lt;/span&gt; &lt;span class=&quot;Keyword&quot;&gt;MojoExecutionException&lt;/span&gt;(&lt;span class=&quot;String&quot;&gt;&lt;span class=&quot;String&quot;&gt;&amp;quot;&lt;/span&gt;Failed to create archive &lt;span class=&quot;String&quot;&gt;&amp;quot;&lt;/span&gt;&lt;/span&gt; &lt;span class=&quot;Keyword&quot;&gt;+&lt;/span&gt; output, e);
    } &lt;span class=&quot;Keyword&quot;&gt;catch&lt;/span&gt; (&lt;span class=&quot;Keyword&quot;&gt;ArchiverException&lt;/span&gt; e) {
      &lt;span class=&quot;Keyword&quot;&gt;throw&lt;/span&gt; &lt;span class=&quot;Keyword&quot;&gt;new&lt;/span&gt; &lt;span class=&quot;Keyword&quot;&gt;MojoExecutionException&lt;/span&gt;(&lt;span class=&quot;String&quot;&gt;&lt;span class=&quot;String&quot;&gt;&amp;quot;&lt;/span&gt;Failed to create archive &lt;span class=&quot;String&quot;&gt;&amp;quot;&lt;/span&gt;&lt;/span&gt; &lt;span class=&quot;Keyword&quot;&gt;+&lt;/span&gt; output, e);
    } &lt;span class=&quot;Keyword&quot;&gt;catch&lt;/span&gt; (&lt;span class=&quot;Support&quot;&gt;IOException&lt;/span&gt; e) {
      &lt;span class=&quot;Keyword&quot;&gt;throw&lt;/span&gt; &lt;span class=&quot;Keyword&quot;&gt;new&lt;/span&gt; &lt;span class=&quot;Keyword&quot;&gt;MojoExecutionException&lt;/span&gt;(&lt;span class=&quot;String&quot;&gt;&lt;span class=&quot;String&quot;&gt;&amp;quot;&lt;/span&gt;Failed to create archive &lt;span class=&quot;String&quot;&gt;&amp;quot;&lt;/span&gt;&lt;/span&gt; &lt;span class=&quot;Keyword&quot;&gt;+&lt;/span&gt; output, e);
    }
  }

  &lt;span class=&quot;Keyword&quot;&gt;private &lt;/span&gt;&lt;span class=&quot;Keyword&quot;&gt;void&lt;/span&gt; &lt;span class=&quot;Entity&quot;&gt;attachArchive&lt;/span&gt;(&lt;span class=&quot;Support&quot;&gt;File&lt;/span&gt; output, &lt;span class=&quot;Support&quot;&gt;String&lt;/span&gt; type, &lt;span class=&quot;Support&quot;&gt;String&lt;/span&gt; classifier) {
    mavenProjectHelper.attachArtifact(mavenProject, type, classifier, output);
  }

}
&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;Where &lt;code&gt;ArchiverManager&lt;/code&gt; is &lt;code&gt;plexus-archiver&lt;/code&gt;:&lt;/p&gt;
&lt;div class=&quot;uv&quot;&gt;&lt;pre class=&quot;lazy&quot;&gt;
&lt;span class=&quot;MetaTag&quot;&gt;&lt;span class=&quot;MetaTag&quot;&gt;&amp;lt;&lt;/span&gt;&lt;span class=&quot;MetaTag&quot;&gt;dependency&lt;/span&gt;&lt;span class=&quot;MetaTag&quot;&gt;&amp;gt;&lt;/span&gt;&lt;/span&gt;
  &lt;span class=&quot;MetaTag&quot;&gt;&lt;span class=&quot;MetaTag&quot;&gt;&amp;lt;&lt;/span&gt;&lt;span class=&quot;MetaTag&quot;&gt;groupId&lt;/span&gt;&lt;span class=&quot;MetaTag&quot;&gt;&amp;gt;&lt;/span&gt;&lt;/span&gt;org.codehaus.plexus&lt;span class=&quot;MetaTag&quot;&gt;&lt;span class=&quot;MetaTag&quot;&gt;&amp;lt;/&lt;/span&gt;&lt;span class=&quot;MetaTag&quot;&gt;groupId&lt;/span&gt;&lt;span class=&quot;MetaTag&quot;&gt;&amp;gt;&lt;/span&gt;&lt;/span&gt;
  &lt;span class=&quot;MetaTag&quot;&gt;&lt;span class=&quot;MetaTag&quot;&gt;&amp;lt;&lt;/span&gt;&lt;span class=&quot;MetaTag&quot;&gt;artifactId&lt;/span&gt;&lt;span class=&quot;MetaTag&quot;&gt;&amp;gt;&lt;/span&gt;&lt;/span&gt;plexus-archiver&lt;span class=&quot;MetaTag&quot;&gt;&lt;span class=&quot;MetaTag&quot;&gt;&amp;lt;/&lt;/span&gt;&lt;span class=&quot;MetaTag&quot;&gt;artifactId&lt;/span&gt;&lt;span class=&quot;MetaTag&quot;&gt;&amp;gt;&lt;/span&gt;&lt;/span&gt;
  &lt;span class=&quot;MetaTag&quot;&gt;&lt;span class=&quot;MetaTag&quot;&gt;&amp;lt;&lt;/span&gt;&lt;span class=&quot;MetaTag&quot;&gt;version&lt;/span&gt;&lt;span class=&quot;MetaTag&quot;&gt;&amp;gt;&lt;/span&gt;&lt;/span&gt;1.0-alpha-9&lt;span class=&quot;MetaTag&quot;&gt;&lt;span class=&quot;MetaTag&quot;&gt;&amp;lt;/&lt;/span&gt;&lt;span class=&quot;MetaTag&quot;&gt;version&lt;/span&gt;&lt;span class=&quot;MetaTag&quot;&gt;&amp;gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;MetaTag&quot;&gt;&lt;span class=&quot;MetaTag&quot;&gt;&amp;lt;/&lt;/span&gt;&lt;span class=&quot;MetaTag&quot;&gt;dependency&lt;/span&gt;&lt;span class=&quot;MetaTag&quot;&gt;&amp;gt;&lt;/span&gt;&lt;/span&gt;
&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;And all dependencies are injected from plexus container in mojo:&lt;/p&gt;
&lt;div class=&quot;uv&quot;&gt;&lt;pre class=&quot;lazy&quot;&gt;
&lt;span class=&quot;Comment&quot;&gt;&lt;span class=&quot;Comment&quot;&gt;/**&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;Comment&quot;&gt; * @component&lt;/span&gt;
&lt;span class=&quot;Comment&quot;&gt; &lt;span class=&quot;Comment&quot;&gt;*/&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;Keyword&quot;&gt;public&lt;/span&gt; &lt;span class=&quot;Keyword&quot;&gt;ArchiverManager&lt;/span&gt; archiverManager;

&lt;span class=&quot;Comment&quot;&gt;&lt;span class=&quot;Comment&quot;&gt;/**&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;Comment&quot;&gt; * @component&lt;/span&gt;
&lt;span class=&quot;Comment&quot;&gt; &lt;span class=&quot;Comment&quot;&gt;*/&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;Keyword&quot;&gt;public&lt;/span&gt; &lt;span class=&quot;Keyword&quot;&gt;MavenProjectHelper&lt;/span&gt; mavenProjectHelper;

&lt;span class=&quot;Comment&quot;&gt;&lt;span class=&quot;Comment&quot;&gt;/**&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;Comment&quot;&gt; * @parameter default-value=&amp;quot;${project}&amp;quot;&lt;/span&gt;
&lt;span class=&quot;Comment&quot;&gt; &lt;span class=&quot;Comment&quot;&gt;*/&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;Keyword&quot;&gt;public&lt;/span&gt; &lt;span class=&quot;Keyword&quot;&gt;MavenProject&lt;/span&gt; mavenProject;

&lt;span class=&quot;Keyword&quot;&gt;public &lt;/span&gt;&lt;span class=&quot;Keyword&quot;&gt;DirectoryArtifactService&lt;/span&gt; &lt;span class=&quot;Entity&quot;&gt;getDirectoryArtifactService&lt;/span&gt;() {
  &lt;span class=&quot;Keyword&quot;&gt;return&lt;/span&gt; &lt;span class=&quot;Keyword&quot;&gt;new&lt;/span&gt; &lt;span class=&quot;Keyword&quot;&gt;DirectoryArtifactService&lt;/span&gt;(getLog(), archiverManager, mavenProjectHelper, 
    mavenProject);
}
&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;After running mojo we can see that Maven also installs &lt;code&gt;gwt&lt;/code&gt; artifact:&lt;/p&gt;
&lt;div class=&quot;uv&quot;&gt;&lt;pre class=&quot;lazy&quot;&gt;
[INFO] [install:install {execution: default-install}]
[INFO] Installing app/app-gwt/target/app-gwt-1.0-SNAPSHOT.jar to                          ↩
  ~/.m2/repository/com/app/app-gwt/1.0-SNAPSHOT/app-gwt-1.0-SNAPSHOT.jar
[INFO] Installing app/app-gwt/target/app-gwt-1.0-SNAPSHOT-gwt.jar to                      ↩
  ~/.m2/repository/com/app/app-gwt/1.0-SNAPSHOT/app-gwt-1.0-SNAPSHOT-gwt.jar
[INFO] Installing app/app-gwt/target/app-gwt-1.0-SNAPSHOT-sources.jar to                  ↩
  ~/.m2/repository/com/app/app-gwt/1.0-SNAPSHOT/app-gwt-1.0-SNAPSHOT-sources.jar
&lt;/pre&gt;&lt;/div&gt;</content>
</entry>


  <entry>
  <title>Running a Separate Java Process from Maven Mojo</title>
  <link href="/articles/2009/11/11/running-a-separate-java-process-from-maven-mojo.html" />
  <id>tag:www.amateurinmotion.com,2009-11-11:1257891394</id>
  <updated>2009-11-11T00:16:34+02:00</updated>
  <content type="html">&lt;p&gt;While digging in various existing Maven Mojos and looking for easiest way to run a separate java process from Maven Mojo, in &lt;a href=&quot;http://mojo.codehaus.org/exec-maven-plugin/&quot;&gt;&lt;code&gt;exec-maven-plugin&lt;/code&gt;&lt;/a&gt; I&amp;#8217;ve found reference to nice helper class from &lt;a href=&quot;http://plexus.codehaus.org/plexus-utils/&quot;&gt;Plexus Common Utilities&lt;/a&gt; named &lt;code&gt;Commandline&lt;/code&gt;.&lt;/p&gt;
&lt;p&gt;So, to run java (or any other) process using &lt;code&gt;CommandLine&lt;/code&gt; and &lt;code&gt;CommandLineUtils&lt;/code&gt; classes:&lt;/p&gt;
&lt;div class=&quot;uv&quot;&gt;&lt;pre class=&quot;lazy&quot;&gt;
&lt;span class=&quot;Keyword&quot;&gt;import&lt;/span&gt; &lt;span class=&quot;Entity&quot;&gt;org.codehaus.plexus.util.cli.Commandline&lt;/span&gt;;

&lt;span class=&quot;Comment&quot;&gt;&lt;span class=&quot;Comment&quot;&gt;/**&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;Comment&quot;&gt; * @parameter expression=&amp;quot;${java.home}&amp;quot;&lt;/span&gt;
&lt;span class=&quot;Comment&quot;&gt; * @required&lt;/span&gt;
&lt;span class=&quot;Comment&quot;&gt; &lt;span class=&quot;Comment&quot;&gt;*/&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;Keyword&quot;&gt;protected&lt;/span&gt; &lt;span class=&quot;Support&quot;&gt;File&lt;/span&gt; javaHome;

&lt;span class=&quot;Keyword&quot;&gt;public &lt;/span&gt;&lt;span class=&quot;Keyword&quot;&gt;void&lt;/span&gt; &lt;span class=&quot;Entity&quot;&gt;run&lt;/span&gt;() {
  &lt;span class=&quot;Keyword&quot;&gt;Commandline&lt;/span&gt; cmd = &lt;span class=&quot;Keyword&quot;&gt;new&lt;/span&gt; &lt;span class=&quot;Keyword&quot;&gt;Commandline&lt;/span&gt;();
  cmd.setExecutable(getJavaExecutable().getAbsolutePath());
  cmd.setWorkingDirectory( ... );
  cmd.addArguments( ... );

  &lt;span class=&quot;Keyword&quot;&gt;StreamConsumer&lt;/span&gt; stdout = ...
  &lt;span class=&quot;Keyword&quot;&gt;int&lt;/span&gt; result = &lt;span class=&quot;Keyword&quot;&gt;CommandLineUtils&lt;/span&gt;.executeCommandLine(cmd, stdout, stdout);
}

&lt;span class=&quot;Keyword&quot;&gt;private &lt;/span&gt;&lt;span class=&quot;Keyword&quot;&gt;File&lt;/span&gt; &lt;span class=&quot;Entity&quot;&gt;getJavaExecutable&lt;/span&gt;() {
  &lt;span class=&quot;Keyword&quot;&gt;return&lt;/span&gt; &lt;span class=&quot;Keyword&quot;&gt;new&lt;/span&gt; &lt;span class=&quot;Support&quot;&gt;File&lt;/span&gt;(&lt;span class=&quot;Keyword&quot;&gt;new&lt;/span&gt; &lt;span class=&quot;Support&quot;&gt;File&lt;/span&gt;(javaHome, &lt;span class=&quot;String&quot;&gt;&lt;span class=&quot;String&quot;&gt;&amp;quot;&lt;/span&gt;bin&lt;span class=&quot;String&quot;&gt;&amp;quot;&lt;/span&gt;&lt;/span&gt;), &lt;span class=&quot;String&quot;&gt;&lt;span class=&quot;String&quot;&gt;&amp;quot;&lt;/span&gt;java&lt;span class=&quot;String&quot;&gt;&amp;quot;&lt;/span&gt;&lt;/span&gt;);
}
&lt;/pre&gt;&lt;/div&gt;&lt;div class=&quot;uv&quot;&gt;&lt;pre class=&quot;lazy&quot;&gt;
&lt;span class=&quot;MetaTag&quot;&gt;&lt;span class=&quot;MetaTag&quot;&gt;&amp;lt;&lt;/span&gt;&lt;span class=&quot;MetaTag&quot;&gt;dependency&lt;/span&gt;&lt;span class=&quot;MetaTag&quot;&gt;&amp;gt;&lt;/span&gt;&lt;/span&gt;
  &lt;span class=&quot;MetaTag&quot;&gt;&lt;span class=&quot;MetaTag&quot;&gt;&amp;lt;&lt;/span&gt;&lt;span class=&quot;MetaTag&quot;&gt;groupId&lt;/span&gt;&lt;span class=&quot;MetaTag&quot;&gt;&amp;gt;&lt;/span&gt;&lt;/span&gt;org.codehaus.plexus&lt;span class=&quot;MetaTag&quot;&gt;&lt;span class=&quot;MetaTag&quot;&gt;&amp;lt;/&lt;/span&gt;&lt;span class=&quot;MetaTag&quot;&gt;groupId&lt;/span&gt;&lt;span class=&quot;MetaTag&quot;&gt;&amp;gt;&lt;/span&gt;&lt;/span&gt;
  &lt;span class=&quot;MetaTag&quot;&gt;&lt;span class=&quot;MetaTag&quot;&gt;&amp;lt;&lt;/span&gt;&lt;span class=&quot;MetaTag&quot;&gt;artifactId&lt;/span&gt;&lt;span class=&quot;MetaTag&quot;&gt;&amp;gt;&lt;/span&gt;&lt;/span&gt;plexus-utils&lt;span class=&quot;MetaTag&quot;&gt;&lt;span class=&quot;MetaTag&quot;&gt;&amp;lt;/&lt;/span&gt;&lt;span class=&quot;MetaTag&quot;&gt;artifactId&lt;/span&gt;&lt;span class=&quot;MetaTag&quot;&gt;&amp;gt;&lt;/span&gt;&lt;/span&gt;
  &lt;span class=&quot;MetaTag&quot;&gt;&lt;span class=&quot;MetaTag&quot;&gt;&amp;lt;&lt;/span&gt;&lt;span class=&quot;MetaTag&quot;&gt;version&lt;/span&gt;&lt;span class=&quot;MetaTag&quot;&gt;&amp;gt;&lt;/span&gt;&lt;/span&gt;1.5.15&lt;span class=&quot;MetaTag&quot;&gt;&lt;span class=&quot;MetaTag&quot;&gt;&amp;lt;/&lt;/span&gt;&lt;span class=&quot;MetaTag&quot;&gt;version&lt;/span&gt;&lt;span class=&quot;MetaTag&quot;&gt;&amp;gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;MetaTag&quot;&gt;&lt;span class=&quot;MetaTag&quot;&gt;&amp;lt;/&lt;/span&gt;&lt;span class=&quot;MetaTag&quot;&gt;dependency&lt;/span&gt;&lt;span class=&quot;MetaTag&quot;&gt;&amp;gt;&lt;/span&gt;&lt;/span&gt;
&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;I&amp;#8217;m not sure if it is the &amp;#8220;Maven way&amp;#8221; of getting path to java executable but it should work just fine in all Java-supported OS&amp;#8217;es.&lt;/p&gt;</content>
</entry>


  <entry>
  <title>Publishing Maven Artifacts</title>
  <link href="/articles/2009/11/08/publishing-maven-artifacts.html" />
  <id>tag:www.amateurinmotion.com,2009-11-08:1257707123</id>
  <updated>2009-11-08T21:05:23+02:00</updated>
  <content type="html">&lt;p&gt;While &lt;code&gt;mvn install&lt;/code&gt; publishes artifact to local &lt;code&gt;~/.m2/repository&lt;/code&gt; there is certainly good rationale to create a remote &amp;#8220;company&amp;#8221; maven repository (either using cool tools like &lt;a href=&quot;http://nexus.sonatype.org/&quot;&gt;nexus&lt;/a&gt; or with just simple HTTP server) to share built artifacts.&lt;/p&gt;
&lt;p&gt;If you&amp;#8217;re like me &amp;#8212; just starting with Maven, plain old HTTP will be fine and when repository is ready (when &lt;code&gt;mkdir /var/www/repository&lt;/code&gt; has done it&amp;#8217;s job) then the next question is how to publish artifacts.&lt;/p&gt;
&lt;p&gt;There are 2 ways (I&amp;#8217;m aware of) to get built artifacts in repository:&lt;/p&gt;
&lt;ul&gt;
	&lt;li&gt;&lt;code&gt;maven-release-plugin&lt;/code&gt;&lt;/li&gt;
	&lt;li&gt;&lt;code&gt;maven-deploy-plugin&lt;/code&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;Before diving in both of them &lt;code&gt;pom.xml&lt;/code&gt; needs a tweaks.&lt;/p&gt;
&lt;h2&gt;Settings&lt;/h2&gt;
&lt;p&gt;Maven needs to know where your repository is. We need to add &lt;code&gt;distributionManagement&lt;/code&gt; element:&lt;/p&gt;
&lt;div class=&quot;uv&quot;&gt;&lt;pre class=&quot;lazy&quot;&gt;
&lt;span class=&quot;MetaTag&quot;&gt;&lt;span class=&quot;MetaTag&quot;&gt;&amp;lt;&lt;/span&gt;&lt;span class=&quot;MetaTag&quot;&gt;distributionManagement&lt;/span&gt;&lt;span class=&quot;MetaTag&quot;&gt;&amp;gt;&lt;/span&gt;&lt;/span&gt;
  &lt;span class=&quot;MetaTag&quot;&gt;&lt;span class=&quot;MetaTag&quot;&gt;&amp;lt;&lt;/span&gt;&lt;span class=&quot;MetaTag&quot;&gt;repository&lt;/span&gt;&lt;span class=&quot;MetaTag&quot;&gt;&amp;gt;&lt;/span&gt;&lt;/span&gt;
    &lt;span class=&quot;MetaTag&quot;&gt;&lt;span class=&quot;MetaTag&quot;&gt;&amp;lt;&lt;/span&gt;&lt;span class=&quot;MetaTag&quot;&gt;id&lt;/span&gt;&lt;span class=&quot;MetaTag&quot;&gt;&amp;gt;&lt;/span&gt;&lt;/span&gt;company-repository&lt;span class=&quot;MetaTag&quot;&gt;&lt;span class=&quot;MetaTag&quot;&gt;&amp;lt;/&lt;/span&gt;&lt;span class=&quot;MetaTag&quot;&gt;id&lt;/span&gt;&lt;span class=&quot;MetaTag&quot;&gt;&amp;gt;&lt;/span&gt;&lt;/span&gt;
    &lt;span class=&quot;MetaTag&quot;&gt;&lt;span class=&quot;MetaTag&quot;&gt;&amp;lt;&lt;/span&gt;&lt;span class=&quot;MetaTag&quot;&gt;name&lt;/span&gt;&lt;span class=&quot;MetaTag&quot;&gt;&amp;gt;&lt;/span&gt;&lt;/span&gt;company m2 repository&lt;span class=&quot;MetaTag&quot;&gt;&lt;span class=&quot;MetaTag&quot;&gt;&amp;lt;/&lt;/span&gt;&lt;span class=&quot;MetaTag&quot;&gt;name&lt;/span&gt;&lt;span class=&quot;MetaTag&quot;&gt;&amp;gt;&lt;/span&gt;&lt;/span&gt;
    &lt;span class=&quot;MetaTag&quot;&gt;&lt;span class=&quot;MetaTag&quot;&gt;&amp;lt;&lt;/span&gt;&lt;span class=&quot;MetaTag&quot;&gt;url&lt;/span&gt;&lt;span class=&quot;MetaTag&quot;&gt;&amp;gt;&lt;/span&gt;&lt;/span&gt;scp://deploy@company.server.com/var/www/repository&lt;span class=&quot;MetaTag&quot;&gt;&lt;span class=&quot;MetaTag&quot;&gt;&amp;lt;/&lt;/span&gt;&lt;span class=&quot;MetaTag&quot;&gt;url&lt;/span&gt;&lt;span class=&quot;MetaTag&quot;&gt;&amp;gt;&lt;/span&gt;&lt;/span&gt;
  &lt;span class=&quot;MetaTag&quot;&gt;&lt;span class=&quot;MetaTag&quot;&gt;&amp;lt;/&lt;/span&gt;&lt;span class=&quot;MetaTag&quot;&gt;repository&lt;/span&gt;&lt;span class=&quot;MetaTag&quot;&gt;&amp;gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;MetaTag&quot;&gt;&lt;span class=&quot;MetaTag&quot;&gt;&amp;lt;/&lt;/span&gt;&lt;span class=&quot;MetaTag&quot;&gt;distributionManagement&lt;/span&gt;&lt;span class=&quot;MetaTag&quot;&gt;&amp;gt;&lt;/span&gt;&lt;/span&gt;
&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;Example uses &lt;code&gt;scp&lt;/code&gt;, few &lt;a href=&quot;http://maven.apache.org/wagon/&quot;&gt;other protocols&lt;/a&gt; are supported.&lt;/p&gt;
&lt;p&gt;And for &lt;code&gt;maven-release-plugin&lt;/code&gt; we also need &lt;code&gt;scm&lt;/code&gt; settings in place:&lt;/p&gt;
&lt;div class=&quot;uv&quot;&gt;&lt;pre class=&quot;lazy&quot;&gt;
&lt;span class=&quot;MetaTag&quot;&gt;&lt;span class=&quot;MetaTag&quot;&gt;&amp;lt;&lt;/span&gt;&lt;span class=&quot;MetaTag&quot;&gt;scm&lt;/span&gt;&lt;span class=&quot;MetaTag&quot;&gt;&amp;gt;&lt;/span&gt;&lt;/span&gt;
  &lt;span class=&quot;MetaTag&quot;&gt;&lt;span class=&quot;MetaTag&quot;&gt;&amp;lt;&lt;/span&gt;&lt;span class=&quot;MetaTag&quot;&gt;connection&lt;/span&gt;&lt;span class=&quot;MetaTag&quot;&gt;&amp;gt;&lt;/span&gt;&lt;/span&gt;scm:hg:ssh://hg@company.server.com/hg/project&lt;span class=&quot;MetaTag&quot;&gt;&lt;span class=&quot;MetaTag&quot;&gt;&amp;lt;/&lt;/span&gt;&lt;span class=&quot;MetaTag&quot;&gt;connection&lt;/span&gt;&lt;span class=&quot;MetaTag&quot;&gt;&amp;gt;&lt;/span&gt;&lt;/span&gt;
  &lt;span class=&quot;MetaTag&quot;&gt;&lt;span class=&quot;MetaTag&quot;&gt;&amp;lt;&lt;/span&gt;&lt;span class=&quot;MetaTag&quot;&gt;developerConnection&lt;/span&gt;&lt;span class=&quot;MetaTag&quot;&gt;&amp;gt;&lt;/span&gt;&lt;/span&gt;scm:hg:ssh://hg@company.server.com/hg/project&lt;span class=&quot;MetaTag&quot;&gt;&lt;span class=&quot;MetaTag&quot;&gt;&amp;lt;/&lt;/span&gt;&lt;span class=&quot;MetaTag&quot;&gt;developerConnection&lt;/span&gt;&lt;span class=&quot;MetaTag&quot;&gt;&amp;gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;MetaTag&quot;&gt;&lt;span class=&quot;MetaTag&quot;&gt;&amp;lt;/&lt;/span&gt;&lt;span class=&quot;MetaTag&quot;&gt;scm&lt;/span&gt;&lt;span class=&quot;MetaTag&quot;&gt;&amp;gt;&lt;/span&gt;&lt;/span&gt;
&lt;/pre&gt;&lt;/div&gt;&lt;h2&gt;Deploy&lt;/h2&gt;
&lt;p&gt;Fine, lets deploy a &lt;code&gt;SNAPSHOT&lt;/code&gt; release:&lt;/p&gt;
&lt;div class=&quot;uv&quot;&gt;&lt;pre class=&quot;lazy&quot;&gt;
mvn clean deploy
&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;This will clean, build and deploy artifact with current version (event if it is not marked as a &lt;code&gt;SNAPSHOT&lt;/code&gt;). Note that it will also overwrite existing artifacts in repository if they exist.&lt;/p&gt;
&lt;h2&gt;Release&lt;/h2&gt;
&lt;p&gt;The release plugin is a lot smarter. The release process is divided in two steps&amp;nbsp;&amp;#8212; &lt;code&gt;prepare&lt;/code&gt; and &lt;code&gt;perform&lt;/code&gt;. Prepare works something like this (assuming &lt;code&gt;artifactId&lt;/code&gt; is &amp;#8220;zeeba&amp;#8221;):&lt;/p&gt;
&lt;ul&gt;
	&lt;li&gt;Updates current artifact version from &lt;code&gt;1.0-SNAPSHOT&lt;/code&gt; to &lt;code&gt;1.0&lt;/code&gt;&lt;/li&gt;
	&lt;li&gt;Creates a tag &lt;code&gt;zeeba-1.0&lt;/code&gt;&lt;/li&gt;
	&lt;li&gt;Updates the version from &lt;code&gt;1.0&lt;/code&gt; to &lt;code&gt;1.1-SNAPSHOT&lt;/code&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;After each of those tasks &lt;code&gt;release:prepare&lt;/code&gt; also commits and pushes the change to scm. So after single release:prepare you&amp;#8217;ll get 3 change-sets in scm&lt;/p&gt;
&lt;p&gt;The &lt;code&gt;perform&lt;/code&gt; side of the plugin is cloning repository based on saved release scm tag name in &lt;code&gt;release.properties&lt;/code&gt;, rebuilding (goal &amp;#8216;deploy&amp;#8217;) and finally performing the actual release. So if &lt;code&gt;release:perform&lt;/code&gt; fails it can be safely retried until it succeeds.&lt;/p&gt;
&lt;div class=&quot;uv&quot;&gt;&lt;pre class=&quot;lazy&quot;&gt;
mvn release:prepare
mvn release:perform
&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;Note, this plugin requires project to currently have &lt;code&gt;SNAPSHOT&lt;/code&gt; version.&lt;/p&gt;
&lt;table class=&quot;clean pt&quot;&gt;
&lt;tr&gt;
&lt;td&gt;
&lt;img src=&quot;http://www.amateurinmotion.com/articles/2009/11/08/publishing/sonatype_maven_book.jpeg&quot; class=&quot;fl  &quot; title=&quot;publishing/sonatype_maven_book.jpeg&quot; alt=&quot;publishing/sonatype_maven_book.jpeg&quot;/&gt;
&lt;/td&gt;
&lt;td class=&quot;wide top&quot;&gt;
And I can&amp;#8217;t recommend more the &lt;a href=&quot;http://www.sonatype.com/books/maven-book/reference/&quot;&gt;Maven: The Definitive Guide&lt;/a&gt;.&lt;br/&gt;
It is really good getting started guide for newcomers to maven.
&lt;/td&gt;
&lt;/tr&gt;
&lt;/table&gt;</content>
</entry>


  <entry>
  <title>Creating Classpath From Compile Scope Elements in Maven Mojo</title>
  <link href="/articles/2009/11/04/creating-classpath-from-compile-scope-elements-in-maven-mojo.html" />
  <id>tag:www.amateurinmotion.com,2009-11-04:1257285738</id>
  <updated>2009-11-04T00:02:18+02:00</updated>
  <content type="html">&lt;p&gt;Lets suppose we have the pom with following (shortened) structure:&lt;/p&gt;
&lt;div class=&quot;uv&quot;&gt;&lt;pre class=&quot;lazy&quot;&gt;
&lt;span class=&quot;MetaTag&quot;&gt;&lt;span class=&quot;MetaTag&quot;&gt;&amp;lt;?&lt;/span&gt;&lt;span class=&quot;MetaTag&quot;&gt;xml&lt;/span&gt;&lt;span class=&quot;MetaTag&quot;&gt; version&lt;/span&gt;=&lt;span class=&quot;String&quot;&gt;&lt;span class=&quot;String&quot;&gt;&amp;quot;&lt;/span&gt;1.0&lt;span class=&quot;String&quot;&gt;&amp;quot;&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;MetaTag&quot;&gt; encoding&lt;/span&gt;=&lt;span class=&quot;String&quot;&gt;&lt;span class=&quot;String&quot;&gt;&amp;quot;&lt;/span&gt;UTF-8&lt;span class=&quot;String&quot;&gt;&amp;quot;&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;MetaTag&quot;&gt;?&amp;gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;MetaTag&quot;&gt;&lt;span class=&quot;MetaTag&quot;&gt;&amp;lt;&lt;/span&gt;&lt;span class=&quot;MetaTag&quot;&gt;project&lt;/span&gt; &lt;span class=&quot;MetaTag&quot;&gt;xmlns&lt;/span&gt;=&lt;span class=&quot;String&quot;&gt;&lt;span class=&quot;String&quot;&gt;&amp;quot;&lt;/span&gt;http://maven.apache.org/POM/4.0.0&lt;span class=&quot;String&quot;&gt;&amp;quot;&lt;/span&gt;&lt;/span&gt; &lt;/span&gt;
&lt;span class=&quot;MetaTag&quot;&gt;  &lt;span class=&quot;MetaTag&quot;&gt;xmlns&lt;/span&gt;&lt;span class=&quot;MetaTag&quot;&gt;&lt;span class=&quot;MetaTag&quot;&gt;:&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;MetaTag&quot;&gt;xsi&lt;/span&gt;=&lt;span class=&quot;String&quot;&gt;&lt;span class=&quot;String&quot;&gt;&amp;quot;&lt;/span&gt;http://www.w3.org/2001/XMLSchema-instance&lt;span class=&quot;String&quot;&gt;&amp;quot;&lt;/span&gt;&lt;/span&gt; &lt;/span&gt;
&lt;span class=&quot;MetaTag&quot;&gt;  &lt;span class=&quot;MetaTag&quot;&gt;xsi&lt;/span&gt;&lt;span class=&quot;MetaTag&quot;&gt;&lt;span class=&quot;MetaTag&quot;&gt;:&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;MetaTag&quot;&gt;schemaLocation&lt;/span&gt;=&lt;span class=&quot;String&quot;&gt;&lt;span class=&quot;String&quot;&gt;&amp;quot;&lt;/span&gt;http://maven.apache.org/POM/4.0.0 &lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;MetaTag&quot;&gt;&lt;span class=&quot;String&quot;&gt;  http://maven.apache.org/maven-v4_0_0.xsd&lt;span class=&quot;String&quot;&gt;&amp;quot;&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;MetaTag&quot;&gt;&amp;gt;&lt;/span&gt;&lt;/span&gt;
  &lt;span class=&quot;MetaTag&quot;&gt;&lt;span class=&quot;MetaTag&quot;&gt;&amp;lt;&lt;/span&gt;&lt;span class=&quot;MetaTag&quot;&gt;modelVersion&lt;/span&gt;&lt;span class=&quot;MetaTag&quot;&gt;&amp;gt;&lt;/span&gt;&lt;/span&gt;4.0.0&lt;span class=&quot;MetaTag&quot;&gt;&lt;span class=&quot;MetaTag&quot;&gt;&amp;lt;/&lt;/span&gt;&lt;span class=&quot;MetaTag&quot;&gt;modelVersion&lt;/span&gt;&lt;span class=&quot;MetaTag&quot;&gt;&amp;gt;&lt;/span&gt;&lt;/span&gt;
  
  &lt;span class=&quot;MetaTag&quot;&gt;&lt;span class=&quot;MetaTag&quot;&gt;&amp;lt;&lt;/span&gt;&lt;span class=&quot;MetaTag&quot;&gt;groupId&lt;/span&gt;&lt;span class=&quot;MetaTag&quot;&gt;&amp;gt;&lt;/span&gt;&lt;/span&gt;com.ampatspell.skeleton&lt;span class=&quot;MetaTag&quot;&gt;&lt;span class=&quot;MetaTag&quot;&gt;&amp;lt;/&lt;/span&gt;&lt;span class=&quot;MetaTag&quot;&gt;groupId&lt;/span&gt;&lt;span class=&quot;MetaTag&quot;&gt;&amp;gt;&lt;/span&gt;&lt;/span&gt;
  &lt;span class=&quot;MetaTag&quot;&gt;&lt;span class=&quot;MetaTag&quot;&gt;&amp;lt;&lt;/span&gt;&lt;span class=&quot;MetaTag&quot;&gt;artifactId&lt;/span&gt;&lt;span class=&quot;MetaTag&quot;&gt;&amp;gt;&lt;/span&gt;&lt;/span&gt;frontend&lt;span class=&quot;MetaTag&quot;&gt;&lt;span class=&quot;MetaTag&quot;&gt;&amp;lt;/&lt;/span&gt;&lt;span class=&quot;MetaTag&quot;&gt;artifactId&lt;/span&gt;&lt;span class=&quot;MetaTag&quot;&gt;&amp;gt;&lt;/span&gt;&lt;/span&gt;
  &lt;span class=&quot;MetaTag&quot;&gt;&lt;span class=&quot;MetaTag&quot;&gt;&amp;lt;&lt;/span&gt;&lt;span class=&quot;MetaTag&quot;&gt;version&lt;/span&gt;&lt;span class=&quot;MetaTag&quot;&gt;&amp;gt;&lt;/span&gt;&lt;/span&gt;0.1-SNAPSHOT&lt;span class=&quot;MetaTag&quot;&gt;&lt;span class=&quot;MetaTag&quot;&gt;&amp;lt;/&lt;/span&gt;&lt;span class=&quot;MetaTag&quot;&gt;version&lt;/span&gt;&lt;span class=&quot;MetaTag&quot;&gt;&amp;gt;&lt;/span&gt;&lt;/span&gt;
  &lt;span class=&quot;MetaTag&quot;&gt;&lt;span class=&quot;MetaTag&quot;&gt;&amp;lt;&lt;/span&gt;&lt;span class=&quot;MetaTag&quot;&gt;packaging&lt;/span&gt;&lt;span class=&quot;MetaTag&quot;&gt;&amp;gt;&lt;/span&gt;&lt;/span&gt;jar&lt;span class=&quot;MetaTag&quot;&gt;&lt;span class=&quot;MetaTag&quot;&gt;&amp;lt;/&lt;/span&gt;&lt;span class=&quot;MetaTag&quot;&gt;packaging&lt;/span&gt;&lt;span class=&quot;MetaTag&quot;&gt;&amp;gt;&lt;/span&gt;&lt;/span&gt;

  &lt;span class=&quot;MetaTag&quot;&gt;&lt;span class=&quot;MetaTag&quot;&gt;&amp;lt;&lt;/span&gt;&lt;span class=&quot;MetaTag&quot;&gt;dependencies&lt;/span&gt;&lt;span class=&quot;MetaTag&quot;&gt;&amp;gt;&lt;/span&gt;&lt;/span&gt;
    &lt;span class=&quot;MetaTag&quot;&gt;&lt;span class=&quot;MetaTag&quot;&gt;&amp;lt;&lt;/span&gt;&lt;span class=&quot;MetaTag&quot;&gt;dependency&lt;/span&gt;&lt;span class=&quot;MetaTag&quot;&gt;&amp;gt;&lt;/span&gt;&lt;/span&gt;
      &lt;span class=&quot;MetaTag&quot;&gt;&lt;span class=&quot;MetaTag&quot;&gt;&amp;lt;&lt;/span&gt;&lt;span class=&quot;MetaTag&quot;&gt;groupId&lt;/span&gt;&lt;span class=&quot;MetaTag&quot;&gt;&amp;gt;&lt;/span&gt;&lt;/span&gt;com.google.webtoolkit&lt;span class=&quot;MetaTag&quot;&gt;&lt;span class=&quot;MetaTag&quot;&gt;&amp;lt;/&lt;/span&gt;&lt;span class=&quot;MetaTag&quot;&gt;groupId&lt;/span&gt;&lt;span class=&quot;MetaTag&quot;&gt;&amp;gt;&lt;/span&gt;&lt;/span&gt;
      &lt;span class=&quot;MetaTag&quot;&gt;&lt;span class=&quot;MetaTag&quot;&gt;&amp;lt;&lt;/span&gt;&lt;span class=&quot;MetaTag&quot;&gt;artifactId&lt;/span&gt;&lt;span class=&quot;MetaTag&quot;&gt;&amp;gt;&lt;/span&gt;&lt;/span&gt;gwt-user&lt;span class=&quot;MetaTag&quot;&gt;&lt;span class=&quot;MetaTag&quot;&gt;&amp;lt;/&lt;/span&gt;&lt;span class=&quot;MetaTag&quot;&gt;artifactId&lt;/span&gt;&lt;span class=&quot;MetaTag&quot;&gt;&amp;gt;&lt;/span&gt;&lt;/span&gt;
      &lt;span class=&quot;MetaTag&quot;&gt;&lt;span class=&quot;MetaTag&quot;&gt;&amp;lt;&lt;/span&gt;&lt;span class=&quot;MetaTag&quot;&gt;version&lt;/span&gt;&lt;span class=&quot;MetaTag&quot;&gt;&amp;gt;&lt;/span&gt;&lt;/span&gt;${gwt-version}&lt;span class=&quot;MetaTag&quot;&gt;&lt;span class=&quot;MetaTag&quot;&gt;&amp;lt;/&lt;/span&gt;&lt;span class=&quot;MetaTag&quot;&gt;version&lt;/span&gt;&lt;span class=&quot;MetaTag&quot;&gt;&amp;gt;&lt;/span&gt;&lt;/span&gt;
      &lt;span class=&quot;MetaTag&quot;&gt;&lt;span class=&quot;MetaTag&quot;&gt;&amp;lt;&lt;/span&gt;&lt;span class=&quot;MetaTag&quot;&gt;scope&lt;/span&gt;&lt;span class=&quot;MetaTag&quot;&gt;&amp;gt;&lt;/span&gt;&lt;/span&gt;compile&lt;span class=&quot;MetaTag&quot;&gt;&lt;span class=&quot;MetaTag&quot;&gt;&amp;lt;/&lt;/span&gt;&lt;span class=&quot;MetaTag&quot;&gt;scope&lt;/span&gt;&lt;span class=&quot;MetaTag&quot;&gt;&amp;gt;&lt;/span&gt;&lt;/span&gt;
    &lt;span class=&quot;MetaTag&quot;&gt;&lt;span class=&quot;MetaTag&quot;&gt;&amp;lt;/&lt;/span&gt;&lt;span class=&quot;MetaTag&quot;&gt;dependency&lt;/span&gt;&lt;span class=&quot;MetaTag&quot;&gt;&amp;gt;&lt;/span&gt;&lt;/span&gt;
    &lt;span class=&quot;MetaTag&quot;&gt;&lt;span class=&quot;MetaTag&quot;&gt;&amp;lt;&lt;/span&gt;&lt;span class=&quot;MetaTag&quot;&gt;dependency&lt;/span&gt;&lt;span class=&quot;MetaTag&quot;&gt;&amp;gt;&lt;/span&gt;&lt;/span&gt;
      &lt;span class=&quot;MetaTag&quot;&gt;&lt;span class=&quot;MetaTag&quot;&gt;&amp;lt;&lt;/span&gt;&lt;span class=&quot;MetaTag&quot;&gt;groupId&lt;/span&gt;&lt;span class=&quot;MetaTag&quot;&gt;&amp;gt;&lt;/span&gt;&lt;/span&gt;com.google.webtoolkit&lt;span class=&quot;MetaTag&quot;&gt;&lt;span class=&quot;MetaTag&quot;&gt;&amp;lt;/&lt;/span&gt;&lt;span class=&quot;MetaTag&quot;&gt;groupId&lt;/span&gt;&lt;span class=&quot;MetaTag&quot;&gt;&amp;gt;&lt;/span&gt;&lt;/span&gt;
      &lt;span class=&quot;MetaTag&quot;&gt;&lt;span class=&quot;MetaTag&quot;&gt;&amp;lt;&lt;/span&gt;&lt;span class=&quot;MetaTag&quot;&gt;artifactId&lt;/span&gt;&lt;span class=&quot;MetaTag&quot;&gt;&amp;gt;&lt;/span&gt;&lt;/span&gt;gwt-dev&lt;span class=&quot;MetaTag&quot;&gt;&lt;span class=&quot;MetaTag&quot;&gt;&amp;lt;/&lt;/span&gt;&lt;span class=&quot;MetaTag&quot;&gt;artifactId&lt;/span&gt;&lt;span class=&quot;MetaTag&quot;&gt;&amp;gt;&lt;/span&gt;&lt;/span&gt;
      &lt;span class=&quot;MetaTag&quot;&gt;&lt;span class=&quot;MetaTag&quot;&gt;&amp;lt;&lt;/span&gt;&lt;span class=&quot;MetaTag&quot;&gt;version&lt;/span&gt;&lt;span class=&quot;MetaTag&quot;&gt;&amp;gt;&lt;/span&gt;&lt;/span&gt;${gwt-version}&lt;span class=&quot;MetaTag&quot;&gt;&lt;span class=&quot;MetaTag&quot;&gt;&amp;lt;/&lt;/span&gt;&lt;span class=&quot;MetaTag&quot;&gt;version&lt;/span&gt;&lt;span class=&quot;MetaTag&quot;&gt;&amp;gt;&lt;/span&gt;&lt;/span&gt;
      &lt;span class=&quot;MetaTag&quot;&gt;&lt;span class=&quot;MetaTag&quot;&gt;&amp;lt;&lt;/span&gt;&lt;span class=&quot;MetaTag&quot;&gt;scope&lt;/span&gt;&lt;span class=&quot;MetaTag&quot;&gt;&amp;gt;&lt;/span&gt;&lt;/span&gt;compile&lt;span class=&quot;MetaTag&quot;&gt;&lt;span class=&quot;MetaTag&quot;&gt;&amp;lt;/&lt;/span&gt;&lt;span class=&quot;MetaTag&quot;&gt;scope&lt;/span&gt;&lt;span class=&quot;MetaTag&quot;&gt;&amp;gt;&lt;/span&gt;&lt;/span&gt;
    &lt;span class=&quot;MetaTag&quot;&gt;&lt;span class=&quot;MetaTag&quot;&gt;&amp;lt;/&lt;/span&gt;&lt;span class=&quot;MetaTag&quot;&gt;dependency&lt;/span&gt;&lt;span class=&quot;MetaTag&quot;&gt;&amp;gt;&lt;/span&gt;&lt;/span&gt;
  &lt;span class=&quot;MetaTag&quot;&gt;&lt;span class=&quot;MetaTag&quot;&gt;&amp;lt;/&lt;/span&gt;&lt;span class=&quot;MetaTag&quot;&gt;dependencies&lt;/span&gt;&lt;span class=&quot;MetaTag&quot;&gt;&amp;gt;&lt;/span&gt;&lt;/span&gt;
  
  &lt;span class=&quot;MetaTag&quot;&gt;&lt;span class=&quot;MetaTag&quot;&gt;&amp;lt;&lt;/span&gt;&lt;span class=&quot;MetaTag&quot;&gt;build&lt;/span&gt;&lt;span class=&quot;MetaTag&quot;&gt;&amp;gt;&lt;/span&gt;&lt;/span&gt;
    &lt;span class=&quot;MetaTag&quot;&gt;&lt;span class=&quot;MetaTag&quot;&gt;&amp;lt;&lt;/span&gt;&lt;span class=&quot;MetaTag&quot;&gt;plugins&lt;/span&gt;&lt;span class=&quot;MetaTag&quot;&gt;&amp;gt;&lt;/span&gt;&lt;/span&gt;
      &lt;span class=&quot;MetaTag&quot;&gt;&lt;span class=&quot;MetaTag&quot;&gt;&amp;lt;&lt;/span&gt;&lt;span class=&quot;MetaTag&quot;&gt;plugin&lt;/span&gt;&lt;span class=&quot;MetaTag&quot;&gt;&amp;gt;&lt;/span&gt;&lt;/span&gt;
        &lt;span class=&quot;MetaTag&quot;&gt;&lt;span class=&quot;MetaTag&quot;&gt;&amp;lt;&lt;/span&gt;&lt;span class=&quot;MetaTag&quot;&gt;groupId&lt;/span&gt;&lt;span class=&quot;MetaTag&quot;&gt;&amp;gt;&lt;/span&gt;&lt;/span&gt;com.ampatspell.maven.plugins&lt;span class=&quot;MetaTag&quot;&gt;&lt;span class=&quot;MetaTag&quot;&gt;&amp;lt;/&lt;/span&gt;&lt;span class=&quot;MetaTag&quot;&gt;groupId&lt;/span&gt;&lt;span class=&quot;MetaTag&quot;&gt;&amp;gt;&lt;/span&gt;&lt;/span&gt;
        &lt;span class=&quot;MetaTag&quot;&gt;&lt;span class=&quot;MetaTag&quot;&gt;&amp;lt;&lt;/span&gt;&lt;span class=&quot;MetaTag&quot;&gt;artifactId&lt;/span&gt;&lt;span class=&quot;MetaTag&quot;&gt;&amp;gt;&lt;/span&gt;&lt;/span&gt;something&lt;span class=&quot;MetaTag&quot;&gt;&lt;span class=&quot;MetaTag&quot;&gt;&amp;lt;/&lt;/span&gt;&lt;span class=&quot;MetaTag&quot;&gt;artifactId&lt;/span&gt;&lt;span class=&quot;MetaTag&quot;&gt;&amp;gt;&lt;/span&gt;&lt;/span&gt;
        &lt;span class=&quot;MetaTag&quot;&gt;&lt;span class=&quot;MetaTag&quot;&gt;&amp;lt;&lt;/span&gt;&lt;span class=&quot;MetaTag&quot;&gt;version&lt;/span&gt;&lt;span class=&quot;MetaTag&quot;&gt;&amp;gt;&lt;/span&gt;&lt;/span&gt;1.0-SNAPSHOT&lt;span class=&quot;MetaTag&quot;&gt;&lt;span class=&quot;MetaTag&quot;&gt;&amp;lt;/&lt;/span&gt;&lt;span class=&quot;MetaTag&quot;&gt;version&lt;/span&gt;&lt;span class=&quot;MetaTag&quot;&gt;&amp;gt;&lt;/span&gt;&lt;/span&gt;
      &lt;span class=&quot;MetaTag&quot;&gt;&lt;span class=&quot;MetaTag&quot;&gt;&amp;lt;/&lt;/span&gt;&lt;span class=&quot;MetaTag&quot;&gt;plugin&lt;/span&gt;&lt;span class=&quot;MetaTag&quot;&gt;&amp;gt;&lt;/span&gt;&lt;/span&gt;
    &lt;span class=&quot;MetaTag&quot;&gt;&lt;span class=&quot;MetaTag&quot;&gt;&amp;lt;/&lt;/span&gt;&lt;span class=&quot;MetaTag&quot;&gt;plugins&lt;/span&gt;&lt;span class=&quot;MetaTag&quot;&gt;&amp;gt;&lt;/span&gt;&lt;/span&gt;
  &lt;span class=&quot;MetaTag&quot;&gt;&lt;span class=&quot;MetaTag&quot;&gt;&amp;lt;/&lt;/span&gt;&lt;span class=&quot;MetaTag&quot;&gt;build&lt;/span&gt;&lt;span class=&quot;MetaTag&quot;&gt;&amp;gt;&lt;/span&gt;&lt;/span&gt;

&lt;span class=&quot;MetaTag&quot;&gt;&lt;span class=&quot;MetaTag&quot;&gt;&amp;lt;/&lt;/span&gt;&lt;span class=&quot;MetaTag&quot;&gt;project&lt;/span&gt;&lt;span class=&quot;MetaTag&quot;&gt;&amp;gt;&lt;/span&gt;&lt;/span&gt;
&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;To create &lt;code&gt;ClassPath&lt;/code&gt; from both dependencies and compiled project classes (what can be filtered out of course):&lt;/p&gt;
&lt;div class=&quot;uv&quot;&gt;&lt;pre class=&quot;lazy&quot;&gt;
&lt;span class=&quot;Comment&quot;&gt;&lt;span class=&quot;Comment&quot;&gt;/**&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;Comment&quot;&gt; * The maven project.&lt;/span&gt;
&lt;span class=&quot;Comment&quot;&gt; *&lt;/span&gt;
&lt;span class=&quot;Comment&quot;&gt; * @parameter expression=&amp;quot;${project}&amp;quot;&lt;/span&gt;
&lt;span class=&quot;Comment&quot;&gt; * @required&lt;/span&gt;
&lt;span class=&quot;Comment&quot;&gt; &lt;span class=&quot;Comment&quot;&gt;*/&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;Keyword&quot;&gt;protected&lt;/span&gt; &lt;span class=&quot;Keyword&quot;&gt;MavenProject&lt;/span&gt; project;

&lt;span class=&quot;Keyword&quot;&gt;protected &lt;/span&gt;&lt;span class=&quot;Keyword&quot;&gt;ClassLoader&lt;/span&gt; &lt;span class=&quot;Entity&quot;&gt;getClassLoader&lt;/span&gt;() &lt;span class=&quot;Keyword&quot;&gt;throws&lt;/span&gt; &lt;span class=&quot;Keyword&quot;&gt;FewNastyExceptions&lt;/span&gt; {
  &lt;span class=&quot;Keyword&quot;&gt;synchronized&lt;/span&gt; (&lt;span class=&quot;Keyword&quot;&gt;SomethingMojo&lt;/span&gt;.&lt;span class=&quot;Keyword&quot;&gt;class&lt;/span&gt;) {
    &lt;span class=&quot;Keyword&quot;&gt;if&lt;/span&gt; (classLoader &lt;span class=&quot;Keyword&quot;&gt;!=&lt;/span&gt; &lt;span class=&quot;Constant&quot;&gt;null&lt;/span&gt;)
      &lt;span class=&quot;Keyword&quot;&gt;return&lt;/span&gt; classLoader;
  }
  &lt;span class=&quot;Keyword&quot;&gt;synchronized&lt;/span&gt; (&lt;span class=&quot;Keyword&quot;&gt;SomethingMojo&lt;/span&gt;.&lt;span class=&quot;Keyword&quot;&gt;class&lt;/span&gt;) {
    &lt;span class=&quot;Support&quot;&gt;List&lt;/span&gt;&lt;span class=&quot;Keyword&quot;&gt;&amp;lt;&lt;/span&gt;&lt;span class=&quot;Constant&quot;&gt;URL&lt;/span&gt;&lt;span class=&quot;Keyword&quot;&gt;&amp;gt;&lt;/span&gt; urls = &lt;span class=&quot;Keyword&quot;&gt;new&lt;/span&gt; &lt;span class=&quot;Support&quot;&gt;ArrayList&lt;/span&gt;&lt;span class=&quot;Keyword&quot;&gt;&amp;lt;&lt;/span&gt;&lt;span class=&quot;Constant&quot;&gt;URL&lt;/span&gt;&lt;span class=&quot;Keyword&quot;&gt;&amp;gt;&lt;/span&gt;();
    &lt;span class=&quot;Keyword&quot;&gt;for&lt;/span&gt; (&lt;span class=&quot;Support&quot;&gt;Object&lt;/span&gt; object : project.getCompileClasspathElements()) {
      &lt;span class=&quot;Support&quot;&gt;String&lt;/span&gt; path = (&lt;span class=&quot;Support&quot;&gt;String&lt;/span&gt;) object;
      urls.add(&lt;span class=&quot;Keyword&quot;&gt;new&lt;/span&gt; &lt;span class=&quot;Support&quot;&gt;File&lt;/span&gt;(path).toURL());
    }
    classLoader = &lt;span class=&quot;Keyword&quot;&gt;new&lt;/span&gt; &lt;span class=&quot;Support&quot;&gt;URLClassLoader&lt;/span&gt;(urls.toArray(&lt;span class=&quot;Keyword&quot;&gt;new&lt;/span&gt; &lt;span class=&quot;Constant&quot;&gt;URL&lt;/span&gt;[] {}) &lt;span class=&quot;Comment&quot;&gt;&lt;span class=&quot;Comment&quot;&gt;/*&lt;/span&gt;, parentClassLoader &lt;span class=&quot;Comment&quot;&gt;*/&lt;/span&gt;&lt;/span&gt;);
    &lt;span class=&quot;Comment&quot;&gt;&lt;span class=&quot;Comment&quot;&gt;//&lt;/span&gt; Thread.currentThread().setContextClassLoader(classLoader); // if needed&lt;/span&gt;
    &lt;span class=&quot;Keyword&quot;&gt;return&lt;/span&gt; classLoader;
  }
}
&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;This created ClassLoader includes:&lt;/p&gt;
&lt;ul&gt;
	&lt;li&gt;target/classes/&lt;/li&gt;
	&lt;li&gt;~/.m2/repository/&lt;em&gt;[..]&lt;/em&gt;/gwt-user-2.0.0-ms2.jar&lt;/li&gt;
	&lt;li&gt;~/.m2/repository/&lt;em&gt;[..]&lt;/em&gt;/gwt-dev-2.0.0-ms2.jar&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;To get class from given ClassLoader:&lt;/p&gt;
&lt;div class=&quot;uv&quot;&gt;&lt;pre class=&quot;lazy&quot;&gt;
&lt;span class=&quot;Keyword&quot;&gt;protected&lt;/span&gt; &lt;span class=&quot;Support&quot;&gt;Class&lt;/span&gt;&lt;span class=&quot;Keyword&quot;&gt;&amp;lt;&lt;/span&gt;?&lt;span class=&quot;Keyword&quot;&gt;&amp;gt;&lt;/span&gt; getClass(&lt;span class=&quot;Support&quot;&gt;String&lt;/span&gt; className) {
  &lt;span class=&quot;Keyword&quot;&gt;return&lt;/span&gt; getClassLoader().loadClass(className);
}
&lt;/pre&gt;&lt;/div&gt;</content>
</entry>


  <entry>
  <title>Publishing Files as Maven Artifacts</title>
  <link href="/articles/2009/11/03/publishing-files-as-maven-artifacts.html" />
  <id>tag:www.amateurinmotion.com,2009-11-03:1257274580</id>
  <updated>2009-11-03T20:56:20+02:00</updated>
  <content type="html">&lt;p&gt;Interwebs are filled with information how to install files in &lt;strong&gt;local&lt;/strong&gt; maven repository&amp;nbsp;&amp;#8212; just type &lt;code&gt;mvn install:install-file&lt;/code&gt;, add few parameters and done. But it took some time for me to find information how to &lt;strong&gt;publish&lt;/strong&gt; (actually to &lt;code&gt;deploy&lt;/code&gt;) file in &lt;a href=&quot;http://www.amateurinmotion.com/repository/&quot;&gt;own repository&lt;/a&gt;. So here it is:&lt;/p&gt;
&lt;h2&gt;Deploy file&lt;/h2&gt;
&lt;div class=&quot;uv&quot;&gt;&lt;pre class=&quot;lazy&quot;&gt;
mvn deploy:deploy-file \
  -Durl=scp://user@server.com/path/to/repository
  -Dfile=gwt-user.jar \
  -DgroupId=com.google.webtoolkit \
  -DartifactId=gwt-user \
  -Dversion=2.0.0-ms2 \
  -Dpackaging=jar \
  -DgeneratePom=true
&lt;/pre&gt;&lt;/div&gt;&lt;h2&gt;Using uploaded artifacts&lt;/h2&gt;
&lt;p&gt;Just add repository in &lt;code&gt;pom.xml&lt;/code&gt;:&lt;/p&gt;
&lt;div class=&quot;uv&quot;&gt;&lt;pre class=&quot;lazy&quot;&gt;
&lt;span class=&quot;MetaTag&quot;&gt;&lt;span class=&quot;MetaTag&quot;&gt;&amp;lt;?&lt;/span&gt;&lt;span class=&quot;MetaTag&quot;&gt;xml&lt;/span&gt;&lt;span class=&quot;MetaTag&quot;&gt; version&lt;/span&gt;=&lt;span class=&quot;String&quot;&gt;&lt;span class=&quot;String&quot;&gt;&amp;quot;&lt;/span&gt;1.0&lt;span class=&quot;String&quot;&gt;&amp;quot;&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;MetaTag&quot;&gt; encoding&lt;/span&gt;=&lt;span class=&quot;String&quot;&gt;&lt;span class=&quot;String&quot;&gt;&amp;quot;&lt;/span&gt;UTF-8&lt;span class=&quot;String&quot;&gt;&amp;quot;&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;MetaTag&quot;&gt;?&amp;gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;MetaTag&quot;&gt;&lt;span class=&quot;MetaTag&quot;&gt;&amp;lt;&lt;/span&gt;&lt;span class=&quot;MetaTag&quot;&gt;project&lt;/span&gt; &lt;span class=&quot;MetaTag&quot;&gt;xmlns&lt;/span&gt;=&lt;span class=&quot;String&quot;&gt;&lt;span class=&quot;String&quot;&gt;&amp;quot;&lt;/span&gt;http://maven.apache.org/POM/4.0.0&lt;span class=&quot;String&quot;&gt;&amp;quot;&lt;/span&gt;&lt;/span&gt; &lt;/span&gt;
&lt;span class=&quot;MetaTag&quot;&gt;  &lt;span class=&quot;MetaTag&quot;&gt;xmlns&lt;/span&gt;&lt;span class=&quot;MetaTag&quot;&gt;&lt;span class=&quot;MetaTag&quot;&gt;:&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;MetaTag&quot;&gt;xsi&lt;/span&gt;=&lt;span class=&quot;String&quot;&gt;&lt;span class=&quot;String&quot;&gt;&amp;quot;&lt;/span&gt;http://www.w3.org/2001/XMLSchema-instance&lt;span class=&quot;String&quot;&gt;&amp;quot;&lt;/span&gt;&lt;/span&gt; &lt;/span&gt;
&lt;span class=&quot;MetaTag&quot;&gt;  &lt;span class=&quot;MetaTag&quot;&gt;xsi&lt;/span&gt;&lt;span class=&quot;MetaTag&quot;&gt;&lt;span class=&quot;MetaTag&quot;&gt;:&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;MetaTag&quot;&gt;schemaLocation&lt;/span&gt;=&lt;span class=&quot;String&quot;&gt;&lt;span class=&quot;String&quot;&gt;&amp;quot;&lt;/span&gt;http://maven.apache.org/POM/4.0.0 &lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;MetaTag&quot;&gt;&lt;span class=&quot;String&quot;&gt;  http://maven.apache.org/maven-v4_0_0.xsd&lt;span class=&quot;String&quot;&gt;&amp;quot;&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;MetaTag&quot;&gt;&amp;gt;&lt;/span&gt;&lt;/span&gt;
  &lt;span class=&quot;MetaTag&quot;&gt;&lt;span class=&quot;MetaTag&quot;&gt;&amp;lt;&lt;/span&gt;&lt;span class=&quot;MetaTag&quot;&gt;modelVersion&lt;/span&gt;&lt;span class=&quot;MetaTag&quot;&gt;&amp;gt;&lt;/span&gt;&lt;/span&gt;4.0.0&lt;span class=&quot;MetaTag&quot;&gt;&lt;span class=&quot;MetaTag&quot;&gt;&amp;lt;/&lt;/span&gt;&lt;span class=&quot;MetaTag&quot;&gt;modelVersion&lt;/span&gt;&lt;span class=&quot;MetaTag&quot;&gt;&amp;gt;&lt;/span&gt;&lt;/span&gt;
  
  &lt;span class=&quot;MetaTag&quot;&gt;&lt;span class=&quot;MetaTag&quot;&gt;&amp;lt;&lt;/span&gt;&lt;span class=&quot;MetaTag&quot;&gt;repositories&lt;/span&gt;&lt;span class=&quot;MetaTag&quot;&gt;&amp;gt;&lt;/span&gt;&lt;/span&gt;
    &lt;span class=&quot;MetaTag&quot;&gt;&lt;span class=&quot;MetaTag&quot;&gt;&amp;lt;&lt;/span&gt;&lt;span class=&quot;MetaTag&quot;&gt;repository&lt;/span&gt;&lt;span class=&quot;MetaTag&quot;&gt;&amp;gt;&lt;/span&gt;&lt;/span&gt;
      &lt;span class=&quot;MetaTag&quot;&gt;&lt;span class=&quot;MetaTag&quot;&gt;&amp;lt;&lt;/span&gt;&lt;span class=&quot;MetaTag&quot;&gt;id&lt;/span&gt;&lt;span class=&quot;MetaTag&quot;&gt;&amp;gt;&lt;/span&gt;&lt;/span&gt;amateurinmotion&lt;span class=&quot;MetaTag&quot;&gt;&lt;span class=&quot;MetaTag&quot;&gt;&amp;lt;/&lt;/span&gt;&lt;span class=&quot;MetaTag&quot;&gt;id&lt;/span&gt;&lt;span class=&quot;MetaTag&quot;&gt;&amp;gt;&lt;/span&gt;&lt;/span&gt;
      &lt;span class=&quot;MetaTag&quot;&gt;&lt;span class=&quot;MetaTag&quot;&gt;&amp;lt;&lt;/span&gt;&lt;span class=&quot;MetaTag&quot;&gt;name&lt;/span&gt;&lt;span class=&quot;MetaTag&quot;&gt;&amp;gt;&lt;/span&gt;&lt;/span&gt;amateurinmotion m2 repository&lt;span class=&quot;MetaTag&quot;&gt;&lt;span class=&quot;MetaTag&quot;&gt;&amp;lt;/&lt;/span&gt;&lt;span class=&quot;MetaTag&quot;&gt;name&lt;/span&gt;&lt;span class=&quot;MetaTag&quot;&gt;&amp;gt;&lt;/span&gt;&lt;/span&gt;
      &lt;span class=&quot;MetaTag&quot;&gt;&lt;span class=&quot;MetaTag&quot;&gt;&amp;lt;&lt;/span&gt;&lt;span class=&quot;MetaTag&quot;&gt;url&lt;/span&gt;&lt;span class=&quot;MetaTag&quot;&gt;&amp;gt;&lt;/span&gt;&lt;/span&gt;http://www.amateurinmotion.com/repository&lt;span class=&quot;MetaTag&quot;&gt;&lt;span class=&quot;MetaTag&quot;&gt;&amp;lt;/&lt;/span&gt;&lt;span class=&quot;MetaTag&quot;&gt;url&lt;/span&gt;&lt;span class=&quot;MetaTag&quot;&gt;&amp;gt;&lt;/span&gt;&lt;/span&gt;
    &lt;span class=&quot;MetaTag&quot;&gt;&lt;span class=&quot;MetaTag&quot;&gt;&amp;lt;/&lt;/span&gt;&lt;span class=&quot;MetaTag&quot;&gt;repository&lt;/span&gt;&lt;span class=&quot;MetaTag&quot;&gt;&amp;gt;&lt;/span&gt;&lt;/span&gt;
  &lt;span class=&quot;MetaTag&quot;&gt;&lt;span class=&quot;MetaTag&quot;&gt;&amp;lt;/&lt;/span&gt;&lt;span class=&quot;MetaTag&quot;&gt;repositories&lt;/span&gt;&lt;span class=&quot;MetaTag&quot;&gt;&amp;gt;&lt;/span&gt;&lt;/span&gt;

&lt;span class=&quot;MetaTag&quot;&gt;&lt;span class=&quot;MetaTag&quot;&gt;&amp;lt;/&lt;/span&gt;&lt;span class=&quot;MetaTag&quot;&gt;project&lt;/span&gt;&lt;span class=&quot;MetaTag&quot;&gt;&amp;gt;&lt;/span&gt;&lt;/span&gt;
&lt;/pre&gt;&lt;/div&gt;&lt;h2&gt;More info&lt;/h2&gt;
&lt;ul&gt;
	&lt;li&gt;&lt;a href=&quot;http://maven.apache.org/plugins/maven-deploy-plugin/deploy-file-mojo.html&quot;&gt;deploy:deploy-file&lt;/a&gt;&lt;/li&gt;
	&lt;li&gt;&lt;a href=&quot;http://maven.apache.org/pom.html#Repositories&quot;&gt;repositories element in pom&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;</content>
</entry>



</feed>

