<?xml version="1.0" encoding="UTF-8"?>
<rss version="2.0"
	xmlns:content="http://purl.org/rss/1.0/modules/content/"
	xmlns:wfw="http://wellformedweb.org/CommentAPI/"
	xmlns:dc="http://purl.org/dc/elements/1.1/"
	xmlns:atom="http://www.w3.org/2005/Atom"
	xmlns:sy="http://purl.org/rss/1.0/modules/syndication/"
	xmlns:slash="http://purl.org/rss/1.0/modules/slash/"
	xmlns:georss="http://www.georss.org/georss" xmlns:geo="http://www.w3.org/2003/01/geo/wgs84_pos#" xmlns:media="http://search.yahoo.com/mrss/"
	>

<channel>
	<title>@TBEE&#039;s</title>
	<atom:link href="http://tbeernot.wordpress.com/feed/" rel="self" type="application/rss+xml" />
	<link>http://tbeernot.wordpress.com</link>
	<description>Ramblings on software development</description>
	<lastBuildDate>Wed, 30 Nov 2011 13:53:15 +0000</lastBuildDate>
	<language>en</language>
	<sy:updatePeriod>hourly</sy:updatePeriod>
	<sy:updateFrequency>1</sy:updateFrequency>
	<generator>http://wordpress.com/</generator>
<cloud domain='tbeernot.wordpress.com' port='80' path='/?rsscloud=notify' registerProcedure='' protocol='http-post' />
<image>
		<url>http://0.gravatar.com/blavatar/af205b5c7be364c43f8cc902db7daef1?s=96&#038;d=http%3A%2F%2Fs2.wp.com%2Fi%2Fbuttonw-com.png</url>
		<title>@TBEE&#039;s</title>
		<link>http://tbeernot.wordpress.com</link>
	</image>
	<atom:link rel="search" type="application/opensearchdescription+xml" href="http://tbeernot.wordpress.com/osd.xml" title="@TBEE&#039;s" />
	<atom:link rel='hub' href='http://tbeernot.wordpress.com/?pushpress=hub'/>
		<item>
		<title>JavaFX 2.0 bubblemark &#8211; part 2</title>
		<link>http://tbeernot.wordpress.com/2011/11/15/javafx-2-0-bubblemark-part-2/</link>
		<comments>http://tbeernot.wordpress.com/2011/11/15/javafx-2-0-bubblemark-part-2/#comments</comments>
		<pubDate>Tue, 15 Nov 2011 10:41:14 +0000</pubDate>
		<dc:creator>tbeernot</dc:creator>
				<category><![CDATA[Java]]></category>
		<category><![CDATA[javafx]]></category>
		<category><![CDATA[UI]]></category>

		<guid isPermaLink="false">http://tbeernot.wordpress.com/?p=207</guid>
		<description><![CDATA[The first post on the JavaFX 2.0 bubblemark created some feedback, most notably an email from the JavaFX engineering team stating in so many words that JavaFX 2.0 has an issue and that is why it per default is not &#8230; <a href="http://tbeernot.wordpress.com/2011/11/15/javafx-2-0-bubblemark-part-2/">Continue reading <span class="meta-nav">&#8594;</span></a><img alt="" border="0" src="http://stats.wordpress.com/b.gif?host=tbeernot.wordpress.com&amp;blog=19658808&amp;post=207&amp;subd=tbeernot&amp;ref=&amp;feed=1" width="1" height="1" />]]></description>
			<content:encoded><![CDATA[<p>The first post on the JavaFX 2.0 bubblemark created some feedback, most notably an email from the JavaFX engineering team stating in so many words that JavaFX 2.0 has an issue and that is why it per default is not running on full speed. But the remedy should be the magical &#8220;-Djavafx.animation.fullspeed=true&#8221; option. So without further due the JavaFX bitmap test was run with that option.</p>
<p>So first here is the total view for all 4 tests (the &#8216;+&#8217; is the fullspeed option):<br />
<a href="http://tbeernot.files.wordpress.com/2011/11/all21.png"><img src="http://tbeernot.files.wordpress.com/2011/11/all21.png?w=640" alt="" title="all+"   class="alignnone size-full wp-image-208" /></a></p>
<p>And the zoomed-in version:<br />
<a href="http://tbeernot.files.wordpress.com/2011/11/all23.png"><img src="http://tbeernot.files.wordpress.com/2011/11/all23.png?w=640" alt="" title="all2+"   class="alignnone size-full wp-image-211" /></a></p>
<p>What stands out first is the fact that JavaFX now has the expected curve, and not only that, but it is uncapped. Swing had a 200 FPS maximum because it used a 5ms timer, with 100 balls JavaFX does 900 fps. Secondly it can be seen that the curve is not impressively offset from swing. On visually inspecting the charts, it seems that JavaFX is on average about 5 fps faster than Swing, with the same amount of balls. That still is not what I would expect.</p>
<p>It is clear that the bubblemark test is a somewhat dual benchmark; it not only measures the graphical part, but also the implementation of the collision code. But never the less it is a comparison, after all all the implementations must move the balls and do collision detection. So therefore some of the other test (Flex, Air, etc) were run as well. Some tests didn&#8217;t have the option to select the number of balls (the air implementation had 16 hardcoded), some had a maximum of 128 balls and I wanted the fps for 512 balls, so I scaled these numbers according to the JavaFX curve. This means the numbers are not 100% accurate, but I believe representative:<br />
<a href="http://tbeernot.files.wordpress.com/2011/11/comparizon.png"><img src="http://tbeernot.files.wordpress.com/2011/11/comparizon.png?w=640" alt="" title="comparizon"   class="alignnone size-full wp-image-213" /></a></p>
<p>It appears Java and its two Oracle UI libraries are the fastest option by far (unfortunately no SWT implementation is available). </p>
<p>Last but not least, let&#8217;s remove the collision detection code from the equation and just keep the ball-moving code, so the graphical part of the test becomes more pronounced. The collision detection has a logarithmic impact on the performance, the moving code only linear. So removing it should make quite a difference:<br />
<a href="http://tbeernot.files.wordpress.com/2011/11/moveonly.png"><img src="http://tbeernot.files.wordpress.com/2011/11/moveonly.png?w=640" alt="" title="moveonly"   class="alignnone size-full wp-image-217" /></a></p>
<p>Again, Swing sticks pretty close to JavaFX. Aside from adding the command line option and commenting out the nested loops in JavaFXTest and BallsTest, the test are identical to the code available in the first blog, so anyone can repeat this easily for himself. The remaining question is: why is there so little difference between Swing and JavaFX? Is it the test? Is JavaFX not very fast?&#8230; Or does the ageing Swing demonstrate that grey hairs are no indication for poor quality or speed?</p>
<p>Feedback is welcome.</p>
<p><strong>Update 2011-1128</strong><br />
The optimized Swing bubblemark code that was the basis for the JavaFX version was originally written by Richard Bair, which co-incidentally is now on the JavaFX team. His reply to an email I send roughly comes down to this: <em>Swing also uses hardware acceleration, so it is only logical that it also is fast. Both should be fast. However, further improvements can be achieved if you start using special graphics algorithms and currently Prism [the engine in JavaFX] does not do much of that, there is a lot of potential there. Work on this is scheduled for JavaFX 2.1, 2.2 and 3.0.</em></p>
<p>In other words; Swing at the moment may be almost as fast as JavaFX, but JavaFX is where growth is possible. One technology is at its peak, the other takes over from there.</p>
<br />  <a rel="nofollow" href="http://feeds.wordpress.com/1.0/gocomments/tbeernot.wordpress.com/207/"><img alt="" border="0" src="http://feeds.wordpress.com/1.0/comments/tbeernot.wordpress.com/207/" /></a> <a rel="nofollow" href="http://feeds.wordpress.com/1.0/godelicious/tbeernot.wordpress.com/207/"><img alt="" border="0" src="http://feeds.wordpress.com/1.0/delicious/tbeernot.wordpress.com/207/" /></a> <a rel="nofollow" href="http://feeds.wordpress.com/1.0/gofacebook/tbeernot.wordpress.com/207/"><img alt="" border="0" src="http://feeds.wordpress.com/1.0/facebook/tbeernot.wordpress.com/207/" /></a> <a rel="nofollow" href="http://feeds.wordpress.com/1.0/gotwitter/tbeernot.wordpress.com/207/"><img alt="" border="0" src="http://feeds.wordpress.com/1.0/twitter/tbeernot.wordpress.com/207/" /></a> <a rel="nofollow" href="http://feeds.wordpress.com/1.0/gostumble/tbeernot.wordpress.com/207/"><img alt="" border="0" src="http://feeds.wordpress.com/1.0/stumble/tbeernot.wordpress.com/207/" /></a> <a rel="nofollow" href="http://feeds.wordpress.com/1.0/godigg/tbeernot.wordpress.com/207/"><img alt="" border="0" src="http://feeds.wordpress.com/1.0/digg/tbeernot.wordpress.com/207/" /></a> <a rel="nofollow" href="http://feeds.wordpress.com/1.0/goreddit/tbeernot.wordpress.com/207/"><img alt="" border="0" src="http://feeds.wordpress.com/1.0/reddit/tbeernot.wordpress.com/207/" /></a> <img alt="" border="0" src="http://stats.wordpress.com/b.gif?host=tbeernot.wordpress.com&amp;blog=19658808&amp;post=207&amp;subd=tbeernot&amp;ref=&amp;feed=1" width="1" height="1" />]]></content:encoded>
			<wfw:commentRss>http://tbeernot.wordpress.com/2011/11/15/javafx-2-0-bubblemark-part-2/feed/</wfw:commentRss>
		<slash:comments>1</slash:comments>
	
		<media:content url="http://0.gravatar.com/avatar/824bd6d211a980b29b2dac9724d4815d?s=96&#38;d=identicon&#38;r=G" medium="image">
			<media:title type="html">tbeernot</media:title>
		</media:content>

		<media:content url="http://tbeernot.files.wordpress.com/2011/11/all21.png" medium="image">
			<media:title type="html">all+</media:title>
		</media:content>

		<media:content url="http://tbeernot.files.wordpress.com/2011/11/all23.png" medium="image">
			<media:title type="html">all2+</media:title>
		</media:content>

		<media:content url="http://tbeernot.files.wordpress.com/2011/11/comparizon.png" medium="image">
			<media:title type="html">comparizon</media:title>
		</media:content>

		<media:content url="http://tbeernot.files.wordpress.com/2011/11/moveonly.png" medium="image">
			<media:title type="html">moveonly</media:title>
		</media:content>
	</item>
		<item>
		<title>JavaFX 2.0 bubblemark</title>
		<link>http://tbeernot.wordpress.com/2011/11/12/javafx-2-0-bubblemark/</link>
		<comments>http://tbeernot.wordpress.com/2011/11/12/javafx-2-0-bubblemark/#comments</comments>
		<pubDate>Sat, 12 Nov 2011 18:06:52 +0000</pubDate>
		<dc:creator>tbeernot</dc:creator>
				<category><![CDATA[Java]]></category>
		<category><![CDATA[javafx]]></category>
		<category><![CDATA[UI]]></category>

		<guid isPermaLink="false">http://tbeernot.wordpress.com/?p=187</guid>
		<description><![CDATA[Oracle has released the revamped JavaFX 2.0 on JavaOne 2011. It&#8217;s an interesting step which immediately invokes many questions. What is the target audience for JavaFX? Which technology segment does it aim at? What are the chances it will actually &#8230; <a href="http://tbeernot.wordpress.com/2011/11/12/javafx-2-0-bubblemark/">Continue reading <span class="meta-nav">&#8594;</span></a><img alt="" border="0" src="http://stats.wordpress.com/b.gif?host=tbeernot.wordpress.com&amp;blog=19658808&amp;post=187&amp;subd=tbeernot&amp;ref=&amp;feed=1" width="1" height="1" />]]></description>
			<content:encoded><![CDATA[<p>Oracle has released the revamped JavaFX 2.0 on JavaOne 2011. It&#8217;s an interesting step which immediately invokes many questions. What is the target audience for JavaFX? Which technology segment does it aim at? What are the chances it will actually claim a piece of that segment? Is it any good at the segment it is aiming at? Only the future will tell the answers to all the questions. But some can be attempted to be answered today.</p>
<p>First of all a short summary of what I believe JavaFX 2.0 is: <em>JavaFX attempts to be a higher performance graphics framework, with a UI layer on top, able to display different types of media</em>.</p>
<ul>
<li>&#8220;Higher&#8221; means that it is not aiming at high end gaming (for example the recently released Battlefield 3 and Call of Duty Modern Warfare 3), but more at the level of platform games like Mario Bros or the fancier and animated user interfaces that some applications have lately.</li>
<li>&#8220;Graphics framework&#8221; indicates that it is not a UI library in its core (like Swing or SWT), but its designed primarily for drawing, manipulating and animating shapes like circles, rectangles and lines.</li>
<li>&#8220;UI layer on top&#8221; to note that it does come with a good set of UI controls, that are drawn using the graphics framework and thus can easily be made &#8220;fancy&#8221;.</li>
<li>&#8220;able to display different types of media&#8221; means that there is support for playing audio or video streams.</li>
</ul>
<p>This kind of framework is commonly known as a RIA, or rich internet application, framework.</p>
<p>Having established the technical intention of JavaFX, the first step would be to see if it is any good at what it&#8217;s trying to be. This means bringing out the tame racing driver, aka a common frame of reference. For benchmarking a RIA the unofficial first thing to do is throw the <a title="bubblemark" href="http://www.bubblemark.com" target="_blank">bubblemark</a> test at it. </p>
<p>Bubblemark contains a lot of different implementations and because I do not like to reinvent the wheel, it seems a good idea to adapt an existing test to JavaFX 2.0. Naturally there is the JavaFX 1.0 implementation, but since that uses JavaFX script, porting it could be, ahm, more work. The other approach would be to adapt the Swing version and because it is implemented in Java, adapting that may be, ahm, less work. Furthermore it is fair to say that JavaFX will initially appeal to Swing developers, so running both side by side also makes for an interesting comparison.</p>
<p>The Swing (optimized version) Bubblemark code seems somewhat illogically structured, but after a closer look it turned out that most logic was put in the Ball class. Extending that with a JavaFXBall implementation was fairly easy. The Swing version uses a bitmap image of a ball, but testing a full vector JavaFX version is relevant, so in fact two classes were made: JavaFXBallBitmap and JavaFXBallVector.</p>
<p>Next the actual test case. The Swing version is implemented as an Applet, to make life not unnecessary complex at this stage, I chose to quickly rewrite that to use a JFrame and write the JavaFX code to use a regular Scene. A browser embedded version can be made later. Furthermore I wanted to put the results in a graph, so I adapted the test cases to calculate the number of frames per second (after a short warm-up period) and then output that on stderr and then automatically increment the number of balls with 100.</p>
<p>The Swing version uses javax.swing.Timer to move the balls, for JavaFX I decided to use javafx.animation.AnimationTimer. And basically that is it: start the timer, count the frames and see how many are done in a second. Below the test case code:</p>
<p><pre class="brush: java; wrap-lines: false;">
package javaballsopt;

import java.net.URL;
import java.util.ArrayList;
import java.util.List;

import javafx.animation.AnimationTimer;
import javafx.application.Application;
import javafx.scene.Group;
import javafx.scene.Scene;
import javafx.scene.image.Image;
import javafx.stage.Stage;

public class JavaFXTest extends Application 
{
	
	public static void main(String[] args) 
	{
		launch(args);	   
	}

	@Override
	public void start(Stage stage) 
	{
		try
		{
			// get the image
			URL url = javaballsopt.JavaBallsApplet.class.getResource(&quot;resources/ball.png&quot;);
			Image lImage = new Image(url.openStream());

			// create the ball object
			final JavaFXBallBitmap lJavaFXBall = new JavaFXBallBitmap(lImage);
			//final JavaFXBallVector lJavaFXBall = new JavaFXBallVector();
			
			// create the JavaFX container to hold the balls and add the first ball
			Group root = new Group();
			root.getChildren().add(lJavaFXBall.img);
			javaFXBalls.add(lJavaFXBall);
			
			// add 99 more balls by cloning it (this is the way the Swing test does it... clone also adds the ball to the group)
			for (int i = 0; i &lt; 99; i++)
			{
				javaFXBalls.add( lJavaFXBall.clone() );
			}
			
			// create scene
			Scene scene = new Scene(root, 500, 300);
			
			// create and show stage
			stage.setTitle(&quot;Bubblemark&quot;);
			stage.setScene(scene);
			stage.show();
			
			// create the incrementing test scenarion
			// let's be bold and time using nanoseconds; expectations are high
			starttimeNano = System.nanoTime();
			new AnimationTimer()
			{
				@Override
				public void handle(long arg0)
				{
					// for all balls
					int s = javaFXBalls.size();
					for (int i = 0; i &lt; s; i++)
					{
						// move the ball
						javaFXBalls.get(i).move();
					}
					
					// for all possible ball interactions
					for (int i = 0; i &lt; s; i++)
					{
						for (int j = i+1; j &lt; s; j++)
						{
							// detect collision and change movement accordingly
							javaFXBalls.get(i).doCollide( javaFXBalls.get(j) );
						}
					}
					
					// count the frame
					frameCnt++;
					
					// check if a second has passed
					long currenttimeNano = System.nanoTime();
					if (currenttimeNano &gt; lasttimeFPS + 1000000000)
					{
						// print out each FPS on stdout
						System.out.println(javaFXBalls.size() + &quot; balls &quot; + frameCnt + &quot; fps&quot;);

						// increase the test counter
						measurementTest++;
						
						// after 5 tests (warm up period) 
						if (measurementTest == 5)
						{
							// print the result on stderr in a Excel readable form
							System.err.println(javaFXBalls.size() + &quot;;&quot; + frameCnt + &quot;;&quot;);
							
							// add 100 balls
							for (int i = 0; i &lt; 100; i++)
							{
								javaFXBalls.add( lJavaFXBall.clone() );
							}
							
							// clear the test counter
							measurementTest = 0;
							
							// stop at 5000 balls
							if (javaFXBalls.size() &gt; 5000) System.exit(0);
						}
						
						// reset frame count and time
						frameCnt = 0;
						lasttimeFPS = currenttimeNano;
					}
				}
			}.start();
		}
		catch (Throwable t) { t.printStackTrace(); }
	}
	List&lt;JavaFXBall&gt; javaFXBalls = new ArrayList&lt;JavaFXBall&gt;();
	int frameCnt = 0;
	long starttimeNano = 0;
	long lasttimeFPS = 0;
	int measurementTest = 0;
}
</pre></p>
<p>Below is the output of the JavaFX run:</p>
<p><pre class="brush: plain; wrap-lines: false;">
100 balls 1 fps
100 balls 56 fps
100 balls 61 fps
100 balls 60 fps
100 balls 61 fps
200 balls 60 fps
200 balls 60 fps
200 balls 61 fps
200 balls 60 fps
200 balls 61 fps
300 balls 60 fps
300 balls 61 fps
300 balls 60 fps
300 balls 60 fps
...
</pre></p>
<p>The first thing that stood out is that AnimationTimer caps the FPS as 60 fps. After an initial confusion this does not seem that bad; we&#8217;re not interested in values greater than 60 fps, those are smooth anyhow, but when it gets below. So with a little help from Excel, there is a nice graph:</p>
<p><a href="http://tbeernot.files.wordpress.com/2011/11/javafx_bitmap.png"><img src="http://tbeernot.files.wordpress.com/2011/11/javafx_bitmap.png?w=640" alt="" title="javafx_bitmap"   class="alignnone size-full wp-image-191" /></a></p>
<p>The result was not what I expected. There seems to be some kind of stepping in the FPS, especially the sudden drop at around 1700 balls; I expected a curve. I reran the test several times, but the results are the same. Naturally I hope people will repeat it on their systems. For reference, I have a 2.4 Ghz quadcore Intel CPU (but the test does not do multi-threading) and a nVidia GTX 560 graphics board (since JavaFX uses hardware acceleration). </p>
<p>So, how about the vector version and the Swing version then? Well, after running and loading them into Excel I got this graph:</p>
<p><a href="http://tbeernot.files.wordpress.com/2011/11/all.png"><img src="http://tbeernot.files.wordpress.com/2011/11/all.png?w=640" alt="" title="all"   class="alignnone size-full wp-image-194" /></a></p>
<p>Again, not what I expected. I would expect JavaFX to be considerably faster than Swing. Zooming into the part where Swing also breaks the 60 fps barrier:</p>
<p><a href="http://tbeernot.files.wordpress.com/2011/11/all2.png"><img src="http://tbeernot.files.wordpress.com/2011/11/all2.png?w=640" alt="" title="all2"   class="alignnone size-full wp-image-196" /></a></p>
<p>Swing has the curve I expected and JavaFX does not. The results as a whole are not what I expected and makes me question the Bubblemark test. If you comment out the collision code, the FPS go up. So the question is: what is the Bubblemark code actually testing? The performance of JavaFX or the implementation of the collision code?</p>
<p>For those interested to run the <a href="http://www.tbee.org/stuff/JavaFXBallsOptimized.zip">code</a> for themselves: the JFrame version of the Swing test is in the JavaBallsApplet class, the JavaFX version is in the JavaFXTest. Alternating between line 32 and 33 will give the bitmap or vector version.</p>
<br />  <a rel="nofollow" href="http://feeds.wordpress.com/1.0/gocomments/tbeernot.wordpress.com/187/"><img alt="" border="0" src="http://feeds.wordpress.com/1.0/comments/tbeernot.wordpress.com/187/" /></a> <a rel="nofollow" href="http://feeds.wordpress.com/1.0/godelicious/tbeernot.wordpress.com/187/"><img alt="" border="0" src="http://feeds.wordpress.com/1.0/delicious/tbeernot.wordpress.com/187/" /></a> <a rel="nofollow" href="http://feeds.wordpress.com/1.0/gofacebook/tbeernot.wordpress.com/187/"><img alt="" border="0" src="http://feeds.wordpress.com/1.0/facebook/tbeernot.wordpress.com/187/" /></a> <a rel="nofollow" href="http://feeds.wordpress.com/1.0/gotwitter/tbeernot.wordpress.com/187/"><img alt="" border="0" src="http://feeds.wordpress.com/1.0/twitter/tbeernot.wordpress.com/187/" /></a> <a rel="nofollow" href="http://feeds.wordpress.com/1.0/gostumble/tbeernot.wordpress.com/187/"><img alt="" border="0" src="http://feeds.wordpress.com/1.0/stumble/tbeernot.wordpress.com/187/" /></a> <a rel="nofollow" href="http://feeds.wordpress.com/1.0/godigg/tbeernot.wordpress.com/187/"><img alt="" border="0" src="http://feeds.wordpress.com/1.0/digg/tbeernot.wordpress.com/187/" /></a> <a rel="nofollow" href="http://feeds.wordpress.com/1.0/goreddit/tbeernot.wordpress.com/187/"><img alt="" border="0" src="http://feeds.wordpress.com/1.0/reddit/tbeernot.wordpress.com/187/" /></a> <img alt="" border="0" src="http://stats.wordpress.com/b.gif?host=tbeernot.wordpress.com&amp;blog=19658808&amp;post=187&amp;subd=tbeernot&amp;ref=&amp;feed=1" width="1" height="1" />]]></content:encoded>
			<wfw:commentRss>http://tbeernot.wordpress.com/2011/11/12/javafx-2-0-bubblemark/feed/</wfw:commentRss>
		<slash:comments>6</slash:comments>
	
		<media:content url="http://0.gravatar.com/avatar/824bd6d211a980b29b2dac9724d4815d?s=96&#38;d=identicon&#38;r=G" medium="image">
			<media:title type="html">tbeernot</media:title>
		</media:content>

		<media:content url="http://tbeernot.files.wordpress.com/2011/11/javafx_bitmap.png" medium="image">
			<media:title type="html">javafx_bitmap</media:title>
		</media:content>

		<media:content url="http://tbeernot.files.wordpress.com/2011/11/all.png" medium="image">
			<media:title type="html">all</media:title>
		</media:content>

		<media:content url="http://tbeernot.files.wordpress.com/2011/11/all2.png" medium="image">
			<media:title type="html">all2</media:title>
		</media:content>
	</item>
		<item>
		<title>Oracle vs Google</title>
		<link>http://tbeernot.wordpress.com/2011/08/09/oracle-vs-google/</link>
		<comments>http://tbeernot.wordpress.com/2011/08/09/oracle-vs-google/#comments</comments>
		<pubDate>Tue, 09 Aug 2011 05:28:00 +0000</pubDate>
		<dc:creator>tbeernot</dc:creator>
				<category><![CDATA[Google]]></category>
		<category><![CDATA[Java]]></category>
		<category><![CDATA[javafx]]></category>
		<category><![CDATA[Oracle]]></category>

		<guid isPermaLink="false">http://tbeernot.wordpress.com/?p=167</guid>
		<description><![CDATA[The latest news about the infringement dance Google and Oracle are doing, indicates that Google may be in serious trouble. These law suites usually are far-from-my-bed things which are taken note of, wondered about, and swapped out for day to &#8230; <a href="http://tbeernot.wordpress.com/2011/08/09/oracle-vs-google/">Continue reading <span class="meta-nav">&#8594;</span></a><img alt="" border="0" src="http://stats.wordpress.com/b.gif?host=tbeernot.wordpress.com&amp;blog=19658808&amp;post=167&amp;subd=tbeernot&amp;ref=&amp;feed=1" width="1" height="1" />]]></description>
			<content:encoded><![CDATA[<p>The latest news about the infringement dance Google and Oracle are doing, indicates that Google may be in serious trouble. These law suites usually are far-from-my-bed things which are taken note of, wondered about, and swapped out for day to day activities. But, for some reason, this morning I woke up early and felt angry. Very angry even. And it was aimed at Oracle.</p>
<p>I&#8217;ve coded Java since version 1.1. The last 10+ years of my professional life have been about Java. I&#8217;ve spent many of my spare time learning, fine tuning, enhancing my Java skills; I&#8217;ve tried to contribute as a compensation for making my work possible; even this week I&#8217;ve spent precious family time on JavaFX (JFXtras). I never believed that Java was dead. No language was able to pull me away; no Jython, Scala, Haskell or Groovy, no C# or mono. Oh, I&#8217;ve examined them all, but they just confirmed that Java is a good and solid choice for the years to come.</p>
<p>But this morning, for the first time, I wondered that if Oracle would use Java to really hurt Google (considering the amount of money they&#8217;re suing for, that is a real possible scenario). If Oracle would abuse their stewardship of Java to really hurt one of the biggest contributors to the Java ecosystem. If this law suite turns out to be more than just a slap on the wrist to make clear who&#8217;s boss. If Oracle loses the benefit of the doubt, if I then still would be willing to invest my private time in a community with such a leader. With such risk of innovation being slammed down by legislation&#8230; Oracle may be able to accomplish what nothing could before; kill my Java community spirit.</p>
<p>I still hope Oracle learned from situations like OpenOffice and Jenkins, and that they will join Google in the mutual interest of further developing Android. The future will tell. Naturally my professional life will still involve a lot of Java in the coming years, Java is too entrenched for that, but what would I do with my spare time if things turn out for the worst?</p>
<br />  <a rel="nofollow" href="http://feeds.wordpress.com/1.0/gocomments/tbeernot.wordpress.com/167/"><img alt="" border="0" src="http://feeds.wordpress.com/1.0/comments/tbeernot.wordpress.com/167/" /></a> <a rel="nofollow" href="http://feeds.wordpress.com/1.0/godelicious/tbeernot.wordpress.com/167/"><img alt="" border="0" src="http://feeds.wordpress.com/1.0/delicious/tbeernot.wordpress.com/167/" /></a> <a rel="nofollow" href="http://feeds.wordpress.com/1.0/gofacebook/tbeernot.wordpress.com/167/"><img alt="" border="0" src="http://feeds.wordpress.com/1.0/facebook/tbeernot.wordpress.com/167/" /></a> <a rel="nofollow" href="http://feeds.wordpress.com/1.0/gotwitter/tbeernot.wordpress.com/167/"><img alt="" border="0" src="http://feeds.wordpress.com/1.0/twitter/tbeernot.wordpress.com/167/" /></a> <a rel="nofollow" href="http://feeds.wordpress.com/1.0/gostumble/tbeernot.wordpress.com/167/"><img alt="" border="0" src="http://feeds.wordpress.com/1.0/stumble/tbeernot.wordpress.com/167/" /></a> <a rel="nofollow" href="http://feeds.wordpress.com/1.0/godigg/tbeernot.wordpress.com/167/"><img alt="" border="0" src="http://feeds.wordpress.com/1.0/digg/tbeernot.wordpress.com/167/" /></a> <a rel="nofollow" href="http://feeds.wordpress.com/1.0/goreddit/tbeernot.wordpress.com/167/"><img alt="" border="0" src="http://feeds.wordpress.com/1.0/reddit/tbeernot.wordpress.com/167/" /></a> <img alt="" border="0" src="http://stats.wordpress.com/b.gif?host=tbeernot.wordpress.com&amp;blog=19658808&amp;post=167&amp;subd=tbeernot&amp;ref=&amp;feed=1" width="1" height="1" />]]></content:encoded>
			<wfw:commentRss>http://tbeernot.wordpress.com/2011/08/09/oracle-vs-google/feed/</wfw:commentRss>
		<slash:comments>0</slash:comments>
	
		<media:content url="http://0.gravatar.com/avatar/824bd6d211a980b29b2dac9724d4815d?s=96&#38;d=identicon&#38;r=G" medium="image">
			<media:title type="html">tbeernot</media:title>
		</media:content>
	</item>
		<item>
		<title>KPCalendarPicker</title>
		<link>http://tbeernot.wordpress.com/2011/05/29/kpcalendarpicker/</link>
		<comments>http://tbeernot.wordpress.com/2011/05/29/kpcalendarpicker/#comments</comments>
		<pubDate>Sun, 29 May 2011 18:48:30 +0000</pubDate>
		<dc:creator>tbeernot</dc:creator>
				<category><![CDATA[Apple]]></category>
		<category><![CDATA[iOS]]></category>
		<category><![CDATA[iPad]]></category>
		<category><![CDATA[Objective-C]]></category>
		<category><![CDATA[UI]]></category>

		<guid isPermaLink="false">http://tbeernot.wordpress.com/?p=142</guid>
		<description><![CDATA[In the previous posts about UIOverlayView and KPMiniPickerView I&#8217;ve already talked about my calendar picker test case that I use to &#8220;hello world&#8221; new UI platforms. So far there is a Java Swing version, a JavaFX 1.3 version, the JavaFX &#8230; <a href="http://tbeernot.wordpress.com/2011/05/29/kpcalendarpicker/">Continue reading <span class="meta-nav">&#8594;</span></a><img alt="" border="0" src="http://stats.wordpress.com/b.gif?host=tbeernot.wordpress.com&amp;blog=19658808&amp;post=142&amp;subd=tbeernot&amp;ref=&amp;feed=1" width="1" height="1" />]]></description>
			<content:encoded><![CDATA[<p>In the previous posts about UIOverlayView and KPMiniPickerView I&#8217;ve already talked about my calendar picker test case that I use to &#8220;hello world&#8221; new UI platforms. So far there is a Java Swing version, a JavaFX 1.3 version, the JavaFX 2.0 version is in the works, and there is a iOS (iPhone / iPad version). </p>
<p>The main excuse I had to write one for iOS is, because I found the normal picker to have a few drawbacks:</p>
<ul>
<li>It is inaccurate; if I want to go back, say, 10 days, I give the thing a swipe and have to hope it stops somewhere around 10 days.</li>
<li>It takes up a big chunk of screen, relatively, for the information being shown.</li>
<li>The styling of the UIPickerView in general is not easily fitted into another look and feel; the rolodex-in-a-box look is very distinctive.</li>
</ul>
<p><a href="http://tbeernot.files.wordpress.com/2011/03/uipickerview.png"><img src="http://tbeernot.files.wordpress.com/2011/03/uipickerview.png?w=640" alt="" title="UIPickerView"   class="alignnone size-full wp-image-71" /></a></p>
<p>It is totally clear what Apple tries to do with the UIPickerView, but I do not believe that UI controls modeled after real world things (like a rolodex) are a good idea. History has shown us that writing computer programs in languages styled after human languages (Cobol) is not working out well either; all though there is something in common, the two worlds are far more different than alike. And the more I see UI&#8217;s made up of thing resembling real world objects, the more I get the feeling that they are not working out very well (the occasional exception excluded naturally).</p>
<p>So therefor the normal style date picker may have some right of existence on the iPad, so I wrote KPCalendarPicker. Calendar is there to suggest it does more than simply selecting a date, but also takes locale settings into account, like first-day-of-week:<br />
<a href="http://tbeernot.files.wordpress.com/2011/03/kpcalendarpickerview.png"><img src="http://tbeernot.files.wordpress.com/2011/03/kpcalendarpickerview.png?w=640" alt="" title="KPCalendarPickerView"   class="alignnone size-full wp-image-66" /></a></p>
<p>The KPCalendarPicker is being used in a hour registration application, but there is a issue with the KPMiniPickerView and losing drag focus which I hope to resolve someday. To see it in action:<br />
<a href="http://tbeernot.files.wordpress.com/2011/05/cv_screenshot_dh2ipad_login.png"><img src="http://tbeernot.files.wordpress.com/2011/05/cv_screenshot_dh2ipad_login.png?w=234&#038;h=300" alt="" title="CV_screenshot_dh2ipad_login" width="234" height="300" class="alignnone size-medium wp-image-145" /></a></p>
<p>BTW, the hour registration also has a applet version, which uses the Swing version of the calendar picker (called JCalendarPicker) as can be seen in the top-left corner here:<br />
<a href="http://tbeernot.files.wordpress.com/2011/05/cv_screenshot_dh2ria.png"><img src="http://tbeernot.files.wordpress.com/2011/05/cv_screenshot_dh2ria.png?w=300&#038;h=206" alt="" title="CV_screenshot_dh2ria" width="300" height="206" class="alignnone size-medium wp-image-148" /></a></p>
<p>Kia Toedler&#8217;s <a href="http://toedter.com/en/jcalendar/index.html" target="_blank">JCalendar</a> component is a great component, but has too many embedded styling elements like the border and background color for my taste. JCalendarPicker simply uses existing controls without much additional styling and therefor easily adopts to new UI themes.</p>
<p>Anyhow, the code for the KPCalendarPickerView, together with all kinds of other iOS classes, is checked into sourceforge. So if you want to give it a spin (and hopefully commit back), you can find it under the project <a href="https://sourceforge.net/projects/kpios/" target="_blank">&#8220;KPiOS&#8221;</a>. Usage is pretty straight forward, although with a twist of Java because I prefer the listeners pattern:</p>
<p><pre class="brush: objc; wrap-lines: false;">
- (void)loadView {
	[super loadView];
	...
	// calendarPicker
	_calendarPicker = [[KPCalendarPicker alloc] initWithFrame:CGRectMake(x,y,w,h)];	
	[_calendarPicker.dateSelectedListeners add:self selector:@selector(dateSelected:)];
	[self.view addSubview:_calendarPicker];	
	...
}

- (void)dateSelected:(NSDate*)date {
	NSLog(@”dateSelected %@”, [KPUtil formatDate:_date]);
	...	
}
</pre></p>
<br />  <a rel="nofollow" href="http://feeds.wordpress.com/1.0/gocomments/tbeernot.wordpress.com/142/"><img alt="" border="0" src="http://feeds.wordpress.com/1.0/comments/tbeernot.wordpress.com/142/" /></a> <a rel="nofollow" href="http://feeds.wordpress.com/1.0/godelicious/tbeernot.wordpress.com/142/"><img alt="" border="0" src="http://feeds.wordpress.com/1.0/delicious/tbeernot.wordpress.com/142/" /></a> <a rel="nofollow" href="http://feeds.wordpress.com/1.0/gofacebook/tbeernot.wordpress.com/142/"><img alt="" border="0" src="http://feeds.wordpress.com/1.0/facebook/tbeernot.wordpress.com/142/" /></a> <a rel="nofollow" href="http://feeds.wordpress.com/1.0/gotwitter/tbeernot.wordpress.com/142/"><img alt="" border="0" src="http://feeds.wordpress.com/1.0/twitter/tbeernot.wordpress.com/142/" /></a> <a rel="nofollow" href="http://feeds.wordpress.com/1.0/gostumble/tbeernot.wordpress.com/142/"><img alt="" border="0" src="http://feeds.wordpress.com/1.0/stumble/tbeernot.wordpress.com/142/" /></a> <a rel="nofollow" href="http://feeds.wordpress.com/1.0/godigg/tbeernot.wordpress.com/142/"><img alt="" border="0" src="http://feeds.wordpress.com/1.0/digg/tbeernot.wordpress.com/142/" /></a> <a rel="nofollow" href="http://feeds.wordpress.com/1.0/goreddit/tbeernot.wordpress.com/142/"><img alt="" border="0" src="http://feeds.wordpress.com/1.0/reddit/tbeernot.wordpress.com/142/" /></a> <img alt="" border="0" src="http://stats.wordpress.com/b.gif?host=tbeernot.wordpress.com&amp;blog=19658808&amp;post=142&amp;subd=tbeernot&amp;ref=&amp;feed=1" width="1" height="1" />]]></content:encoded>
			<wfw:commentRss>http://tbeernot.wordpress.com/2011/05/29/kpcalendarpicker/feed/</wfw:commentRss>
		<slash:comments>2</slash:comments>
	
		<media:content url="http://0.gravatar.com/avatar/824bd6d211a980b29b2dac9724d4815d?s=96&#38;d=identicon&#38;r=G" medium="image">
			<media:title type="html">tbeernot</media:title>
		</media:content>

		<media:content url="http://tbeernot.files.wordpress.com/2011/03/uipickerview.png" medium="image">
			<media:title type="html">UIPickerView</media:title>
		</media:content>

		<media:content url="http://tbeernot.files.wordpress.com/2011/03/kpcalendarpickerview.png" medium="image">
			<media:title type="html">KPCalendarPickerView</media:title>
		</media:content>

		<media:content url="http://tbeernot.files.wordpress.com/2011/05/cv_screenshot_dh2ipad_login.png?w=234" medium="image">
			<media:title type="html">CV_screenshot_dh2ipad_login</media:title>
		</media:content>

		<media:content url="http://tbeernot.files.wordpress.com/2011/05/cv_screenshot_dh2ria.png?w=300" medium="image">
			<media:title type="html">CV_screenshot_dh2ria</media:title>
		</media:content>
	</item>
		<item>
		<title>The road to a fully encapsulated layered business model</title>
		<link>http://tbeernot.wordpress.com/2011/05/22/the-road-to-a-fully-encapsulated-layered-business-model/</link>
		<comments>http://tbeernot.wordpress.com/2011/05/22/the-road-to-a-fully-encapsulated-layered-business-model/#comments</comments>
		<pubDate>Sun, 22 May 2011 14:05:37 +0000</pubDate>
		<dc:creator>tbeernot</dc:creator>
				<category><![CDATA[Uncategorized]]></category>

		<guid isPermaLink="false">http://tbeernot.wordpress.com/?p=119</guid>
		<description><![CDATA[History About 20 years ago, during the time that I was working on my bachelor, I came in contact with a small company selling wall decorations. They had a need for some simple software, so I wrote a MSAccess application &#8230; <a href="http://tbeernot.wordpress.com/2011/05/22/the-road-to-a-fully-encapsulated-layered-business-model/">Continue reading <span class="meta-nav">&#8594;</span></a><img alt="" border="0" src="http://stats.wordpress.com/b.gif?host=tbeernot.wordpress.com&amp;blog=19658808&amp;post=119&amp;subd=tbeernot&amp;ref=&amp;feed=1" width="1" height="1" />]]></description>
			<content:encoded><![CDATA[<p><strong>History</strong><br />
About 20 years ago, during the time that I was working on my bachelor, I came in contact with a small company selling wall decorations. They had a need for some simple software, so I wrote a MSAccess application for them. During the years they grew and so did their software requirements, which resulted in a major overhaul about 10 years later when the whole code base was moved to Java 1.2 on top of an Informix database (back then considered a real competitor of Oracle&#8217;s RDBMS). The best way to access the database was using JDBC, so that was the approach that was chosen. Persistency frameworks were still immature (SDO) or expensive (Oracle&#8217;s Toplink). </p>
<p>The whole JDBC-combined-with-Swing did not work really well, partially because I had not figured Swing out when setting up the application&#8217;s architecture, but also because Swing uses objects and I had resultsets. Jumping forward another 5 years or so and persistency frameworks finally became an affordable foundation, so it was time to slowly migrate the code base over to Toplink (which soon was renamed to Eclipselink). Using Eclipselink made my Swing life that much easier, more than I expected, but also introduced new challenges.</p>
<div id="attachment_132" class="wp-caption alignnone" style="width: 513px"><a href="http://tbeernot.files.wordpress.com/2011/05/2011-05-22-15-36-12-webshop.png"><img src="http://tbeernot.files.wordpress.com/2011/05/2011-05-22-15-36-12-webshop.png?w=640" alt="reinders webshop" title="2011-05-22 15 36 12 reinders webshop"   class="size-full wp-image-132" /></a><p class="wp-caption-text">reinders webshop</p></div>
<p>Up until then, using JDBC in the 10 years old style, business logic was spread throughout the application screens. Initially this was a nuisance, but it could be dealt with. But soon, because of the growth of the company, it became a problem; there were additional interfaces required on top of the database for EDIFACT, website, webshop, email data exchange and support of mobile devices. The whole thing had grown into a full-fledged ERP and all these interfaces needed to make sure business rules were followed; it became clear that another approach was needed. </p>
<p>I was not a fan of EJB2 because of the complex setup, so I wanted to stay close to the basic keep-it-simple architecture of stand alone environments; a fat Swing client and batch Java applications for all the outside communication. That meant that I had to develop the business model (BM) as a simple JAR that could be used in each environment.</p>
<p><strong>Architecture</strong><br />
The first thing that struck me as very odd was the fact that in the domain driven design (or model driven, I&#8217;m not sure where one ends and the other starts) documents I was reading, teaching was that entities basically were nothing more than glorified C-structures, only holding data from the database, decorated with some getters and setters. External controllers then would hold the actual logic&#8230; All very EJB focused with its entity and session beans and automatic transactions. The setup felt so not object-oriented (totally lacking encapsulation) that I refused to adopt this approach; entities were to be objects which could actually do things.</p>
<p>Secondly in DDD the persistency logic is not part of the BM, but somehow bolted onto the side. That also caused some short circuiting in my head; it seemed somewhat like writing a database application without knowing what database it was using. If the BM could only rely on some common API, it would be impossible to take advantage of the strengths of the persistency layer. Don&#8217;t get me wrong, I&#8217;m a big fan of standardisation, but also a fan of achieving my goal, and some choices must be balanced against reality. So I decided that the BM would have full knowledge of, access to and fully use the chosen persistency layer, being Toplink / Eclipselink / JPA.</p>
<p>To summarize; the business model should be a fully encapsulated model (JAR) that could be dropped-in in any type of application.</p>
<p><strong>Implementation</strong><br />
<em>Inheritance</em><br />
Having set the architectural stage, the work on the BM went smoothly. Being lazy by nature, I decided that when I added a field to the database, I was not going to duplicate the work by also adding setters and getters. So after the initial trials a reverse code generator was created, that generated the required Java code from the database. Since that code was generated over and over again, the actual business code needed to go somewhere else.  So a layer was put on top for the business rules and underneath was a common &#8220;bean&#8221; class for handling property change listeners and other Java beany things:</p>
<ul>
<li>@Entity: business logic, generated once never overwritten</li>
<li>@MappedSuperclass: reversed engineered fields, overwritten every time</li>
<li>generic bean logic</li>
</ul>
<p><pre class="brush: java; wrap-lines: false;">
@Entity
@Table(name=&quot;address&quot;)
public class Address extends nl.reinders.bm.generated.Address
implements java.io.Serializable
{ ... }

@MappedSuperclass
abstract public class Address extends nl.reinders.bm.AbstractBean&lt;nl.reinders.bm.Address&gt;
implements java.io.Serializable
         , java.lang.Cloneable
         , Comparable&lt;nl.reinders.bm.Address&gt;
{ ... }
</pre></p>
<p>This was the point where the decision for Eclipselink was made, because Hibernate did not support this setup (at that time?).</p>
<p><em>Relationships</em><br />
Not only does the reverse generator take care of my simple fields, but also the inter-entity relations using the foreign keys; JPA dictates that the BM is responsible for maintaining the two sides of a relationship (scaffolding galore). So for example in a one-to-many relation, JPA does nothing to make sure the single reference on one side and the collection on the other are synced. Luckily the generated code takes care of that. And when some relation is not meant to be maintained (for example with lookup tables, those cause big memory and performance issues if they are fully wired up in the BM), the reverse generator does not generate the collection but replaces it with convenient find-methods. The entity inheritance stack works very well and could fairly easily be adapted to every situation I came across so far. </p>
<p>The generator creates a lot of scaffolding and supporting static variables intended to be used by the applications and thus allowing for compile time checking, but note that you normally never modify or even read this code. I&#8217;ve included one example of a 1-N relation below, but the code one normally writes looks like this:</p>
<p><pre class="brush: java; wrap-lines: false;">
	/**
	 * Must clear the image properties since they depend on the articlenr
	 * @see generated.Article#setArticlenr(java.lang.Integer)
	 */
	@Override
	public void setArticlenr(BigInteger value)
	{
		setImageIcon(null);
		setImageIconThumbnail(null);
		super.setArticlenr(value);
	}
</pre></p>
<p>For illustration purposes a 1-N example of the generated code:</p>
<p><pre class="brush: java; wrap-lines: false;">
class Address { 

	/** Relation */
	public nl.reinders.bm.Relation getRelation() { return iRelation; }
	public void setRelation(nl.reinders.bm.Relation value)
	{
		if (isReadonly() == true) return;
		if (value == iRelation) return; // optimalisation and prevent looping
		nl.reinders.bm.Relation lValue = iRelation; // remember old value for PCE
		if (!nl.knowledgeplaza.util.ObjectUtil.equals(lValue, value)) nl.reinders.bm.BM.failIfNoPermission(Address.class, &quot;relation&quot;);
		if (log4j.isDebugEnabled()) log4j.debug(&quot;setRelation: &quot; + lValue + &quot; -&gt; &quot; + value);
		fireVetoableChange(RELATION_PROPERTY_ID, lValue, value);
		if (lValue != null) lValue.removeAddressesWhereIAmRelation( (nl.reinders.bm.Address)this );
		iRelation = value;
		try {
			if (value != null) value.addAddressesWhereIAmRelation( (nl.reinders.bm.Address)this );
		} catch (RuntimeException e) { iRelation = lValue; throw e; } // restore upon exception 
		if (!nl.knowledgeplaza.util.ObjectUtil.equals(lValue, value)) markAsDirty(true);
		firePropertyChange(RELATION_PROPERTY_ID, lValue, value);
	}
	public nl.reinders.bm.Address withRelation(nl.reinders.bm.Relation value) { setRelation(value); return (nl.reinders.bm.Address)this; } 
	@ManyToOne(fetch = FetchType.LAZY, targetEntity = nl.reinders.bm.Relation.class, cascade = {CascadeType.REFRESH} ) @JoinColumn(name=&quot;relationnr&quot;) 
	volatile protected nl.reinders.bm.Relation iRelation;
	final static public String RELATION_COLUMN_NAME = &quot;relationnr&quot;; // for when building SQL or starting reporting tools 
	final static public String RELATION_FIELD_ID = &quot;iRelation&quot;;
	final static public String RELATION_PROPERTY_ID = &quot;relation&quot;;
	final static public Class&lt;nl.reinders.bm.Relation&gt; RELATION_PROPERTY_CLASS = nl.reinders.bm.Relation.class;
	final static public boolean RELATION_PROPERTY_NULLABLE = true;
	// to make IN queries possible
	@Column(name=&quot;relationnr&quot;, insertable=false, updatable=false)
	volatile protected java.math.BigDecimal iRelationnr = null;
	final static public String RELATIONNR_COLUMN_NAME = &quot;relationnr&quot;; // for when building SQL or starting reporting tools 
}
</pre></p>
<p><pre class="brush: java; wrap-lines: false;">
class Relation { 
	/** AddressesWhereIAmRelation */
	public void addAddressesWhereIAmRelation(nl.reinders.bm.Address value)
	{
		if (isReadonly() == true) return;
		if (value != null &amp;&amp; !iAddressesWhereIAmRelation.contains(value))
		{
			java.util.List&lt;nl.reinders.bm.Address&gt; lValue = new java.util.ArrayList&lt;nl.reinders.bm.Address&gt;();
			lValue.addAll(iAddressesWhereIAmRelation);
			lValue.add(value);
			fireVetoableChange(ADDRESSESWHEREIAMRELATION_PROPERTY_ID, java.util.Collections.unmodifiableList(iAddressesWhereIAmRelation), java.util.Collections.unmodifiableList(lValue));
			boolean lWasAdded = iAddressesWhereIAmRelation.add(value);
			lValue.remove(value);
			firePropertyChange(ADDRESSESWHEREIAMRELATION_PROPERTY_ID, java.util.Collections.unmodifiableList(lValue), java.util.Collections.unmodifiableList(iAddressesWhereIAmRelation));
			try {
				value.setRelation( (nl.reinders.bm.Relation)this);
			} catch (RuntimeException e) { if (lWasAdded) {iAddressesWhereIAmRelation.remove(value);} throw e; } // restore upon exception 
		}
	}
	public void removeAddressesWhereIAmRelation(nl.reinders.bm.Address value)
	{
		if (isReadonly() == true) return;
		if (value != null &amp;&amp; iAddressesWhereIAmRelation.contains(value))
		{
			java.util.List&lt;nl.reinders.bm.Address&gt; lValue = new java.util.ArrayList&lt;nl.reinders.bm.Address&gt;();
			lValue.addAll(iAddressesWhereIAmRelation);
			lValue.remove(value);
			fireVetoableChange(ADDRESSESWHEREIAMRELATION_PROPERTY_ID, java.util.Collections.unmodifiableList(iAddressesWhereIAmRelation), java.util.Collections.unmodifiableList(lValue));
			boolean lWasRemoved = iAddressesWhereIAmRelation.remove(value);
			lValue.add(value);
			firePropertyChange(ADDRESSESWHEREIAMRELATION_PROPERTY_ID, java.util.Collections.unmodifiableList(lValue), java.util.Collections.unmodifiableList(iAddressesWhereIAmRelation));
			try {
				value.setRelation( (nl.reinders.bm.Relation)null );
			} catch (RuntimeException e) { if (lWasRemoved) { iAddressesWhereIAmRelation.add(value); } throw e; } // restore upon exception 
		}
	}
	public void setAddressesWhereIAmRelation(java.util.List&lt;nl.reinders.bm.Address&gt; value)
	{
		// first do a standard setter
		if (isReadonly() == true) return;
		if (value == iAddressesWhereIAmRelation) return; // optimalisation and prevent looping
		java.util.List&lt;nl.reinders.bm.Address&gt; lValue = iAddressesWhereIAmRelation;
		if (log4j.isDebugEnabled()) log4j.debug(&quot;setAddressesWhereIAmRelation: &quot; + lValue + &quot; -&gt; &quot; + value);
		fireVetoableChange(ADDRESSESWHEREIAMRELATION_PROPERTY_ID, java.util.Collections.unmodifiableList(lValue), java.util.Collections.unmodifiableList(value));
		iAddressesWhereIAmRelation = value;
		if (!nl.knowledgeplaza.util.ObjectUtil.equals(lValue, value)) markAsDirty(true);
		firePropertyChange(ADDRESSESWHEREIAMRELATION_PROPERTY_ID, java.util.Collections.unmodifiableList(lValue), java.util.Collections.unmodifiableList(value));

		// then update the other side
		// 1. which entities are no longer in the collection
		if (lValue != null) { // scan the old collection
			for (nl.reinders.bm.Address lOther : lValue) {
				if (value == null || !value.contains(lOther)) { // if the new collection is empty or does not contain this entity
					lOther.setRelation( (nl.reinders.bm.Relation)null ); // unlink
				}
			}
		}
		// 2. which entities are now in the collection
		if (value != null) { // scan the new collection
			for (nl.reinders.bm.Address lOther : value) {
				if (lValue == null || !lValue.contains(lOther))  { // if the old collection is empty or does not contain this entity
					lOther.setRelation( (nl.reinders.bm.Relation)this  ); // link
				}
			}
		}
	}
	public nl.reinders.bm.Relation withAddressesWhereIAmRelation(java.util.List&lt;nl.reinders.bm.Address&gt; value) { setAddressesWhereIAmRelation(value); return (nl.reinders.bm.Relation)this; } 
	/** returns a new list containing a snapshot of the actual list, instead of an returning an unmodifyableList. Either require a new object to be created, but the snapshot allows a.o. sorting without creating another object. Changes to the list are NOT reflected in the BM and vice versa! */ 
	public java.util.List&lt;nl.reinders.bm.Address&gt; getAddressesWhereIAmRelation() { return new java.util.ArrayList&lt;nl.reinders.bm.Address&gt;(iAddressesWhereIAmRelation); }
	final static public String ADDRESSESWHEREIAMRELATION_FIELD_ID = &quot;iAddressesWhereIAmRelation&quot;;
	final static public String ADDRESSESWHEREIAMRELATION_PROPERTY_ID = &quot;addressesWhereIAmRelation&quot;;
	final static public Class&lt;nl.reinders.bm.Address&gt; ADDRESSESWHEREIAMRELATION_PROPERTY_CLASS = nl.reinders.bm.Address.class;
	@OneToMany(mappedBy = &quot;iRelation&quot;, fetch = FetchType.LAZY, targetEntity = nl.reinders.bm.Address.class, cascade = {CascadeType.REFRESH,CascadeType.PERSIST,CascadeType.MERGE,CascadeType.REMOVE} )
	volatile protected java.util.List&lt;nl.reinders.bm.Address&gt; iAddressesWhereIAmRelation = new java.util.ArrayList&lt;nl.reinders.bm.Address&gt;();
</pre></p>
<p><em>Context</em><br />
One other thing turned out to be a big issue; context. Suppose you have a swing application with two screens (JFrames) open. Both screens show the same entity, for example a customer. If you make a change to the entity in one screen, then common usage does not expect the data on the other screen to be affected by that change, at least not until the change is saved to the database. So changes are restricted to the screen they happen on. The initial trials used a global context, and that resulted in a lot of inter-screen conflicts, which were not understood by the actual users. So now entities live within the context of a screen, or in JPA words: a single EntityManager is associated with each screen. This means that the same entity can be loaded into memory more than once, each within its own context.</p>
<div id="attachment_134" class="wp-caption alignnone" style="width: 600px"><a href="http://tbeernot.files.wordpress.com/2011/05/cv_screenshot_reinderserp.png"><img src="http://tbeernot.files.wordpress.com/2011/05/cv_screenshot_reinderserp.png?w=640" alt="Reinders ERP" title="Reinders ERP"   class="size-full wp-image-134" /></a><p class="wp-caption-text">Reinders ERP</p></div>
<p>The BM knows fully what persistency it uses, but is totally unaware of what application it is used in. So if the BM is used in the fat Swing application, context is determined by the screens. However, if the BM is used in a batch process like the EDIFACT interface, there are no screens and there is only one context for the whole application. But if the Swing application decides to spawn a background process, the thread will have a context (EM) on its own. </p>
<p>The context setup is even more complicated by the architectural choice that the BM is to be encapsulated. This meant that the BM should do whatever it needs to in order to get the work done, including adding and removing entities. So if some action on entity A required the creation and persisting of an entity B, the BM needs to be able to get to the EntityManager in order to call &#8220;persist&#8221;. But since it doesn&#8217;t know what application it was running in, the concept of EntityManagerFinder (EMF) was introduced. An EntityManagerFinder has only one static method, being &#8220;find()&#8221; which returns the EntityManager for the context it is called in. </p>
<p>A good example for using the EMF is for searching. Methods for finding entities are available as static methods in the entity classes for example Article.findByEAN(&#8220;1234567890128&#8243;):</p>
<p><pre class="brush: java; wrap-lines: false;">
	/**
	 * @param ean
	 */
	static public java.util.List&lt;nl.reinders.bm.Article&gt; findAllByEAN(String ean)
	{
		EntityManager lEntityManager = nl.knowledgeplaza.util.jpa.EntityManagerFinder.find();
		Query lQuery = lEntityManager.createQuery(&quot;select t from Article t where t.&quot; + EAN_FIELD_ID + &quot;=:ean&quot;);
		lQuery.setParameter(&quot;ean&quot;, ean);
		java.util.List&lt;nl.reinders.bm.Article&gt; lList = lQuery.getResultList();
		return lList;
	}
</pre></p>
<p>There are a number of EMF implementations created:</p>
<ul>
<li>Singleton: one global EM in the whole JVM, used in batch processes</li>
<li>Thread: one EM per thread</li>
<li>Swing: one EM per JFrame,  but extending on the Thread to allow for background processes</li>
</ul>
<p>The thread EMF does not work in Swing applications, because all UI interaction in Swing is done from one thread (the EDT) but may involve different screens.</p>
<p><strong>The catch: persistency events</strong><br />
This setup has served me very well in the last few years, often being totally invisible and just working. Sometimes, when I spawn a background process and use the wrong SwingWorker implementation I get reminded that there is a lot of logic underneath handling the entity&#8217;s universe. There only is one thing that has not been resolved: events.</p>
<p>99% of all business logic is easily implemented overriding setters, or reacting to property change events, but sometime things need to be done upon persistence events. The problem is JPA events are only meant for things happening inside the same entity, like update an age when the birth date is changed. But you should not do anything to other entities, because those actions may or may not be persisted, depending on if the targetted entity already has been visited by the persisting logic. </p>
<p>A good example in this case is the actual allocating of items from the stock the moment the order is persisted. This must be done inside the persisting logic, because the logic uses database locks to prevent other processes from also allocating the same stock amount and that requires running inside a transaction. Also, if the allocation fails because of stock issues, the transaction&#8217;s rollback handles the cleaning up.</p>
<p>I&#8217;ve tried using Eclipselink&#8217;s native events, which are far more fine grained than JPA&#8217;s, but this is something that I was not able to solve. So in the end it comes down to the application layer having to call the appropriate code during the steps of the persistancy. And these calls must be duplicate to other applications which call the same BM logic. Not an ideal situation.</p>
<p><strong>The expert group</strong><br />
So implementing a fully encapsulated business model is almost a success, it&#8217;s just that one thing that is missing. By the time of writing of this blog, the export group has started work on the next version of JPA, and I have submitted the request for an improved event / callback mechanisme which allows modifications to other entities. But if someone has the holy grail of JPA events, and can make my problems go away, please send me a mail!</p>
<br />  <a rel="nofollow" href="http://feeds.wordpress.com/1.0/gocomments/tbeernot.wordpress.com/119/"><img alt="" border="0" src="http://feeds.wordpress.com/1.0/comments/tbeernot.wordpress.com/119/" /></a> <a rel="nofollow" href="http://feeds.wordpress.com/1.0/godelicious/tbeernot.wordpress.com/119/"><img alt="" border="0" src="http://feeds.wordpress.com/1.0/delicious/tbeernot.wordpress.com/119/" /></a> <a rel="nofollow" href="http://feeds.wordpress.com/1.0/gofacebook/tbeernot.wordpress.com/119/"><img alt="" border="0" src="http://feeds.wordpress.com/1.0/facebook/tbeernot.wordpress.com/119/" /></a> <a rel="nofollow" href="http://feeds.wordpress.com/1.0/gotwitter/tbeernot.wordpress.com/119/"><img alt="" border="0" src="http://feeds.wordpress.com/1.0/twitter/tbeernot.wordpress.com/119/" /></a> <a rel="nofollow" href="http://feeds.wordpress.com/1.0/gostumble/tbeernot.wordpress.com/119/"><img alt="" border="0" src="http://feeds.wordpress.com/1.0/stumble/tbeernot.wordpress.com/119/" /></a> <a rel="nofollow" href="http://feeds.wordpress.com/1.0/godigg/tbeernot.wordpress.com/119/"><img alt="" border="0" src="http://feeds.wordpress.com/1.0/digg/tbeernot.wordpress.com/119/" /></a> <a rel="nofollow" href="http://feeds.wordpress.com/1.0/goreddit/tbeernot.wordpress.com/119/"><img alt="" border="0" src="http://feeds.wordpress.com/1.0/reddit/tbeernot.wordpress.com/119/" /></a> <img alt="" border="0" src="http://stats.wordpress.com/b.gif?host=tbeernot.wordpress.com&amp;blog=19658808&amp;post=119&amp;subd=tbeernot&amp;ref=&amp;feed=1" width="1" height="1" />]]></content:encoded>
			<wfw:commentRss>http://tbeernot.wordpress.com/2011/05/22/the-road-to-a-fully-encapsulated-layered-business-model/feed/</wfw:commentRss>
		<slash:comments>0</slash:comments>
	
		<media:content url="http://0.gravatar.com/avatar/824bd6d211a980b29b2dac9724d4815d?s=96&#38;d=identicon&#38;r=G" medium="image">
			<media:title type="html">tbeernot</media:title>
		</media:content>

		<media:content url="http://tbeernot.files.wordpress.com/2011/05/2011-05-22-15-36-12-webshop.png" medium="image">
			<media:title type="html">2011-05-22 15 36 12 reinders webshop</media:title>
		</media:content>

		<media:content url="http://tbeernot.files.wordpress.com/2011/05/cv_screenshot_reinderserp.png" medium="image">
			<media:title type="html">Reinders ERP</media:title>
		</media:content>
	</item>
		<item>
		<title>JavaFX 2.0, Swing 2.0?</title>
		<link>http://tbeernot.wordpress.com/2011/05/01/javafx-2-0-swing-2-0/</link>
		<comments>http://tbeernot.wordpress.com/2011/05/01/javafx-2-0-swing-2-0/#comments</comments>
		<pubDate>Sun, 01 May 2011 19:44:42 +0000</pubDate>
		<dc:creator>tbeernot</dc:creator>
				<category><![CDATA[Java]]></category>
		<category><![CDATA[javafx]]></category>
		<category><![CDATA[UI]]></category>

		<guid isPermaLink="false">http://tbeernot.wordpress.com/?p=111</guid>
		<description><![CDATA[At the beginning of my previous post I mentioned that I was stuck in the implementation of the calendar picker, because I was using one listener for 42 ToggleButtons, and I could not find out which of the 42 ToggleButtons &#8230; <a href="http://tbeernot.wordpress.com/2011/05/01/javafx-2-0-swing-2-0/">Continue reading <span class="meta-nav">&#8594;</span></a><img alt="" border="0" src="http://stats.wordpress.com/b.gif?host=tbeernot.wordpress.com&amp;blog=19658808&amp;post=111&amp;subd=tbeernot&amp;ref=&amp;feed=1" width="1" height="1" />]]></description>
			<content:encoded><![CDATA[<p>At the beginning of my previous post I mentioned that I was stuck in the implementation of the calendar picker, because I was using one listener for 42 ToggleButtons, and I could not find out which of the 42 ToggleButtons was actually clicked. The code I have looks like this:</p>
<p><pre class="brush: java; wrap-lines: false;">
class Skin
{
	/**
	 * create the skin by using other controls
	 */
	private void createNodes()
	{
		for (int i = 0; i &lt; 6 * 7; i++) 
		{
			ToggleButton lToggleButton = new ToggleButton();
			lToggleButton.selectedProperty().addListener( iSelectedListener );
			...
		}
	}

	// one listener for all 42 buttons
	final private InvalidationListener&lt;Boolean&gt; iSelectedListener = new InvalidationListener&lt;Boolean&gt;() 
	{
		@Override public void invalidated(ObservableValue&lt;? extends Boolean&gt; observableValue)
		{
			// selected or deselected
			boolean lSelected = observableValue.getValue();
			
			// TODO: which ToggleButton was pressed?
		}
	}
}
</pre></p>
<p>After having dropped this at the JavaFX people I went into pause, assuming the InvalidationListener API would be extended to include the origin of the event (like Swing events do). After some time Richard Bair came back to me and explained that extending the API with a reference to the bean would mean additional bytes for each property. My initial reaction was; so??? It&#8217;s just a few bytes? But then I realized that JavaFX is not about controls, but about graphics; controls are just a subset in which I&#8217;m very interested, but the real focus of JavaFX is much more basic and raw. There will be applications with thousands of nodes, and then a few bytes per property quickly become megabytes and the rise of the mobile devices suddenly make memory important again. So it became clear that extending the InvalidationListener API is not wise indeed. </p>
<p>It also became clear that a lot of API design decisions are made focused on these thousands of nodes and not focused on controls. This means that people expecting JavaFX to be a perfect replacement for Swing will have some adjusting to do; JavaFX may not have the wealth of information available at your fingertips in the way Swing does. The API&#8217;s are much leaner, cleaner and as a result less informative. In the end the solution to my problem was to bind the one thing that is unique in the listener, the observable, to the button myself using a map.</p>
<p><pre class="brush: java; wrap-lines: false;">
class Skin
{
	/**
	 * create the skin by using other controls
	 */
	private void createNodes()
	{
		for (int i = 0; i &lt; 6 * 7; i++) 
		{
			ToggleButton lToggleButton = new ToggleButton();
			lToggleButton.selectedProperty().addListener( iSelectedListener );

			// remember which bean belongs to this property
			iBooleanPropertyToDayToggleButtonMap.put(lToggleButton.selectedProperty(), lToggleButton);
			...
		}
	}
	final private Map&lt;BooleanProperty, ToggleButton&gt; iBooleanPropertyToDayToggleButtonMap = new HashMap&lt;BooleanProperty, ToggleButton&gt;();

	// one listener for all 42 buttons
	final private InvalidationListener&lt;Boolean&gt; iSelectedListener = new InvalidationListener&lt;Boolean&gt;() 
	{
		@Override public void invalidated(ObservableValue&lt;? extends Boolean&gt; observableValue)
		{
			// this is the actual observable
			BooleanProperty lBooleanProperty = (BooleanProperty)observableValue;
			
			// which ToggleButton was pressed
			ToggleButton lToggleButton = iBooleanPropertyToDayToggleButtonMap.get(lBooleanProperty);
		}
	}
}
</pre></p>
<p>It may turn out that implementing extended listener API&#8217;s for controls (which usually do not run into the thousands) may become desirable in future versions of JavaFX2. </p>
<br />  <a rel="nofollow" href="http://feeds.wordpress.com/1.0/gocomments/tbeernot.wordpress.com/111/"><img alt="" border="0" src="http://feeds.wordpress.com/1.0/comments/tbeernot.wordpress.com/111/" /></a> <a rel="nofollow" href="http://feeds.wordpress.com/1.0/godelicious/tbeernot.wordpress.com/111/"><img alt="" border="0" src="http://feeds.wordpress.com/1.0/delicious/tbeernot.wordpress.com/111/" /></a> <a rel="nofollow" href="http://feeds.wordpress.com/1.0/gofacebook/tbeernot.wordpress.com/111/"><img alt="" border="0" src="http://feeds.wordpress.com/1.0/facebook/tbeernot.wordpress.com/111/" /></a> <a rel="nofollow" href="http://feeds.wordpress.com/1.0/gotwitter/tbeernot.wordpress.com/111/"><img alt="" border="0" src="http://feeds.wordpress.com/1.0/twitter/tbeernot.wordpress.com/111/" /></a> <a rel="nofollow" href="http://feeds.wordpress.com/1.0/gostumble/tbeernot.wordpress.com/111/"><img alt="" border="0" src="http://feeds.wordpress.com/1.0/stumble/tbeernot.wordpress.com/111/" /></a> <a rel="nofollow" href="http://feeds.wordpress.com/1.0/godigg/tbeernot.wordpress.com/111/"><img alt="" border="0" src="http://feeds.wordpress.com/1.0/digg/tbeernot.wordpress.com/111/" /></a> <a rel="nofollow" href="http://feeds.wordpress.com/1.0/goreddit/tbeernot.wordpress.com/111/"><img alt="" border="0" src="http://feeds.wordpress.com/1.0/reddit/tbeernot.wordpress.com/111/" /></a> <img alt="" border="0" src="http://stats.wordpress.com/b.gif?host=tbeernot.wordpress.com&amp;blog=19658808&amp;post=111&amp;subd=tbeernot&amp;ref=&amp;feed=1" width="1" height="1" />]]></content:encoded>
			<wfw:commentRss>http://tbeernot.wordpress.com/2011/05/01/javafx-2-0-swing-2-0/feed/</wfw:commentRss>
		<slash:comments>3</slash:comments>
	
		<media:content url="http://0.gravatar.com/avatar/824bd6d211a980b29b2dac9724d4815d?s=96&#38;d=identicon&#38;r=G" medium="image">
			<media:title type="html">tbeernot</media:title>
		</media:content>
	</item>
		<item>
		<title>JavaFX 2.0 EA binding</title>
		<link>http://tbeernot.wordpress.com/2011/04/02/javafx-2-0-ea-binding/</link>
		<comments>http://tbeernot.wordpress.com/2011/04/02/javafx-2-0-ea-binding/#comments</comments>
		<pubDate>Sat, 02 Apr 2011 08:29:53 +0000</pubDate>
		<dc:creator>tbeernot</dc:creator>
				<category><![CDATA[Java]]></category>
		<category><![CDATA[javafx]]></category>
		<category><![CDATA[UI]]></category>

		<guid isPermaLink="false">http://tbeernot.wordpress.com/?p=93</guid>
		<description><![CDATA[After Swing, JavaFX 1.x and the iPad, now JavaFX 2.0 is candidate for the calendar picker shake down. Using MigLayout I&#8217;ve setup the basic day picking logic, but currently am stuck in build b21, because the events on the selected &#8230; <a href="http://tbeernot.wordpress.com/2011/04/02/javafx-2-0-ea-binding/">Continue reading <span class="meta-nav">&#8594;</span></a><img alt="" border="0" src="http://stats.wordpress.com/b.gif?host=tbeernot.wordpress.com&amp;blog=19658808&amp;post=93&amp;subd=tbeernot&amp;ref=&amp;feed=1" width="1" height="1" />]]></description>
			<content:encoded><![CDATA[<p>After Swing, JavaFX 1.x and the iPad, now JavaFX 2.0 is candidate for the calendar picker shake down. Using MigLayout I&#8217;ve setup the basic day picking logic, but currently am stuck in build b21, because the events on the selected property in ToggleButton do not tell me which togglebutton was actually pressed, which is quite handy if you have 42 of them on screen. So I decided to focus a bit on binding instead.</p>
<p>My binding experience comes from JGoodies used in connecting Swing components to business model bean properties, usually using JGoodies&#8217; BeanAdapter (which takes away the need to rebind every single property when the business model bean is changed underneath a Swing screen). Since I&#8217;m primary focussed on JavaFX&#8217;s controls at the moment, I wanted to see if I could bind my calendar picker to a business model. I&#8217;m also going to assume future 2.0 in which the properties on the business model also are using JavaFX properties. So I constructed a dummy business model with one property:</p>
<p><pre class="brush: java; wrap-lines: false;">
	class BusinessModelBean
	{
		final public ObjectProperty iCalendarObjectProperty= new ObjectProperty();
	}
</pre></p>
<p>This class is then used in a stage:</p>
<p><pre class="brush: java; wrap-lines: false;">
public class XCalendarPickerTest1 extends Application {

    public static void main(String[] args) {
        Launcher.launch(XCalendarPickerTest1.class, args);
    }

	@Override
	public void start(Stage stage) {

        // add a node
        XCalendarPicker lXCalendarPicker = new XCalendarPicker();

        // create scene
        Scene scene = new Scene(lXCalendarPicker, 600, 300);

        // bind Picker to BusinessModelBean
        BusinessModelBean lBusinessModelBean = new BusinessModelBean();
        // binding here...

        // create stage
        stage.setTitle(&quot;XCalendarPicker&quot;);
        stage.setScene(scene);
        stage.setVisible(true);
    }
</pre></p>
<p>Initially I attempted to uses JavaFX&#8217;s binding features and bound the UI property to the BM property:</p>
<p><pre class="brush: java; wrap-lines: false;">
        lXCalendarPicker.calendar().bind( lBusinessModelBean.iCalendarObjectProperty );
</pre></p>
<p>This immediately gave an exception: &#8220;A bound value cannot be set.&#8221;, because JavaFX&#8217;s binding is one way and in this case the picker&#8217;s property is bound to the BM&#8217;s. Clicking on a button in the picker, sets the picker&#8217;s property and this binding doesn&#8217;t allow that. Reversing the binding makes things better:</p>
<p><pre class="brush: java; wrap-lines: false;">
        lBusinessModelBean.iCalendarObjectProperty.bind(lXCalendarPicker.calendar());
</pre></p>
<p>Now clicking in the picker updates the BM&#8217;s property. However, this means that the BM&#8217;s property is blocking any direct changes. I do not know how your business model works, but in my business model it is fairly natural behavior that the BM changes its own properties. For example if a time range was selected by the user, and he changes the duration, then one of the dates at the end would need to change as well and that in fact should update the UI again.</p>
<p>This leads me to the conclusion that business binding requires two way binding and that the binding in JavaFX, being one way, is not well suited for this kind of binding. So this meant the creation of a Binding class which uses the InvalidationListener to bind two properties:</p>
<p><pre class="brush: java; wrap-lines: false;">
public class Binding
{
	/**
	 * Setup two way binding
	 * @param v1
	 * @param v2
	 */
	static public void bind(final ObjectProperty v1, final ObjectProperty v2)
	{
		// listen to changes on the &quot;left&quot; side
		v1.addListener(new InvalidationListener()
		{
			@Override
			public void invalidated(ObservableValue&lt;!--? extends Calendar--&gt; arg0)
			{
				sync(v1, v2);
			}
		});

		// listen to changes on the &quot;right&quot; side
		v2.addListener(new InvalidationListener()
		{
			@Override
			public void invalidated(ObservableValue&lt;!--? extends Calendar--&gt; arg0)
			{
				sync(v2, v1);
			}
		});
	}

	/**
	 * Execute a one way binding, v1 to v2, if required.
	 *
	 * @param v1
	 * @param v2
	 * @return
	 */
	static public boolean sync(final ObjectProperty v1, final ObjectProperty v2)
	{
		// if there is a change
		if ( (v1.getValue() == null &amp;&amp; v2.getValue() != null )
		  || (v1.getValue() != null &amp;&amp; v2.getValue() == null )
		  || (v1.getValue() != null &amp;&amp; v2.getValue() != null &amp;&amp; !v1.getValue().equals(v2.getValue()))
		  )
		{
			// sync v2 with v1
			System.out.println(&quot;Syncing &quot; + quickFormatCalendar(v1.getValue()));
			v2.set(v1.get());
			return true;
		}
		return false;
	}
}
</pre></p>
<p>And this works quite well, setting either side of the binding will update the other side. Great! But as you can see, the code is written specifically for the ObjectProperty type, because the sync logic requires access to three main features to work its magic:</p>
<ul>
<li>get value</li>
<li>set value</li>
<li>register as a listener for value changes</li>
</ul>
<p>It turns out that the actual property classes do not extend any common interface that provides all three. As of now it is not possible to write a method accepting a generic property, and the code above would need to use reflection to access the methods. Not a big problem, but unexpected. I also believe that this will cause more confusing in the future.</p>
<p>Let&#8217;s continue, again I don&#8217;t know how you implement your business model, but mine is supposed to be unaware of whatever is using it. So if you have restrictions on a property; say min should be &lt;= max, or in this test case where I will not allow odd dates to be selected, the BM can only fire an exception telling the other side that what it is trying to do is not alright. Normally, using Java beans, you&#8217;d implement these restrictions in the setter of the property. However, JavaFX&#8217;s properties are accessed directly and the setters are mere compatibility cosmetics, so you need a different way to get between the call and the actual setting of the value. One way would be to use an anonymous inner class:</p>
<p><pre class="brush: java; wrap-lines: false;">
	class BusinessModelBean
	{
		final public ObjectProperty iCalendarObjectProperty = new ObjectProperty()
		{
			@Override
			public void set(Calendar value)
			{
				if (value != null &amp;&amp; value.get(Calendar.DATE) % 2 == 1)
				{
					throw new IllegalArgumentException(&quot;odd date&quot;);
				}
				super.set(value);
			}
		};
        }
</pre></p>
<p>Using this together with my binding code naturally will fail, because the binding logic does not know how to deal with the exception. The idea is that if the setting of a property is not successful, a sync-back is done, resetting the original value. Extending the binding code to do this, is not very hard. In fact, it is wise to always start a sync-back, just in case the setter did something to the value. In 99% of the cases the equals check will make sure no sync is performed.</p>
<p><pre class="brush: java; wrap-lines: false;">
	/**
	 * Setup two way binding
	 * @param v1
	 * @param v2
	 */
	static public void bind(final ObjectProperty v1, final ObjectProperty v2)
	{
		// listen to changes on the &quot;left&quot; side
		v1.addListener(new InvalidationListener()
		{
			@Override
			public void invalidated(ObservableValue&lt;!--? extends Calendar--&gt; arg0)
			{
				try
				{
					// sync left to right
					sync(v1, v2);
				}
				finally
				{
					// always sync back
					sync(v2, v1);
				}
			}
		});

		// listen to changes on the &quot;right&quot; side
		v2.addListener(new InvalidationListener()
		{
			@Override
			public void invalidated(ObservableValue&lt;!--? extends Calendar--&gt; arg0)
			{
				try
				{
					// sync right to left
					sync(v2, v1);
				}
				finally
				{
					// always sync back
					sync(v1, v2);
				}
			}
		});
	}
</pre></p>
<p>This is working fine; the exception is caught and the original value is restored. There is one catch still, JavaFX&#8217;s binding does no go through the set method. So if you&#8217;d bind the BM&#8217;s property using JavaFX&#8217;s binding (which of course is totally legal to do), the restriction is not enforced. Not good. Another approach would be to attempt some kind of vetoable listener:</p>
<p><pre class="brush: java; wrap-lines: false;">
			iCalendarObjectProperty.addListener(new InvalidationListener()
			{
				@Override
				public void invalidated(ObservableValue&lt;!--? extends Calendar--&gt; observableValue)
				{
					Calendar value = observableValue.getValue();
					if (value != null &amp;&amp; value.get(Calendar.DATE) % 2 == 1)
					{
						System.out.println(&quot;odd date&quot;);
						throw new IllegalArgumentException(&quot;odd date&quot;);
					}
				}
			});
</pre></p>
<p>The problem here is that this listener is called after the value is set, so throwing the exception would not have any effect. The same goes for overriding the invalidated method.</p>
<p>There does not seem to be a way to prevent JavaFX&#8217;s binding to set a value. This has to do with the approach JavaFX is taking on binding; Richard Bair explained that they never prevent setting a value on a property. This means that properties can have wrong values (min &gt; max for example) and that the application has to deal with that. Even if I understand why they chose that approach, I personally I do not like it, because it forces the code to deal with all kinds of combinations of situations which actually should not occur.</p>
<p>Summarizing the findings so far:</p>
<ul>
<li>JavaFX&#8217;s binding is one way while business model binding should be two way</li>
<li>JavaFX&#8217;s binding has no formal way to prevent a value to be set</li>
<li>JavaFX&#8217;s properties have no generic superclass or interface</li>
</ul>
<p>This leads me to say that using JavaFX&#8217;s properties <strong>in a business model</strong> with binding is not going to work, JavaFX properties and bindings are intended to work within the UI. Luckily ony minor changes would be required to make it work, so maybe Oracle can be persuaded to make them. </p>
<p>As always I&#8217;d love to be smacked on the head and be proven wrong.</p>
<p>Update 1:<br />
Smacked on the head by Richard himself, gotta love it; JavaFX supports a method &#8220;Bindings.bindWithInverse&#8221; which apparently supports two way binding with honoring exceptions. Naturally I will test this as soon as I have time. This does not solve my second issue of preventing a value to be set.</p>
<p>Update 2: The bindWithReverse indeed allows to way binding, but the issue on when to throw the exception (and actually acting on it) remains. </p>
<br />  <a rel="nofollow" href="http://feeds.wordpress.com/1.0/gocomments/tbeernot.wordpress.com/93/"><img alt="" border="0" src="http://feeds.wordpress.com/1.0/comments/tbeernot.wordpress.com/93/" /></a> <a rel="nofollow" href="http://feeds.wordpress.com/1.0/godelicious/tbeernot.wordpress.com/93/"><img alt="" border="0" src="http://feeds.wordpress.com/1.0/delicious/tbeernot.wordpress.com/93/" /></a> <a rel="nofollow" href="http://feeds.wordpress.com/1.0/gofacebook/tbeernot.wordpress.com/93/"><img alt="" border="0" src="http://feeds.wordpress.com/1.0/facebook/tbeernot.wordpress.com/93/" /></a> <a rel="nofollow" href="http://feeds.wordpress.com/1.0/gotwitter/tbeernot.wordpress.com/93/"><img alt="" border="0" src="http://feeds.wordpress.com/1.0/twitter/tbeernot.wordpress.com/93/" /></a> <a rel="nofollow" href="http://feeds.wordpress.com/1.0/gostumble/tbeernot.wordpress.com/93/"><img alt="" border="0" src="http://feeds.wordpress.com/1.0/stumble/tbeernot.wordpress.com/93/" /></a> <a rel="nofollow" href="http://feeds.wordpress.com/1.0/godigg/tbeernot.wordpress.com/93/"><img alt="" border="0" src="http://feeds.wordpress.com/1.0/digg/tbeernot.wordpress.com/93/" /></a> <a rel="nofollow" href="http://feeds.wordpress.com/1.0/goreddit/tbeernot.wordpress.com/93/"><img alt="" border="0" src="http://feeds.wordpress.com/1.0/reddit/tbeernot.wordpress.com/93/" /></a> <img alt="" border="0" src="http://stats.wordpress.com/b.gif?host=tbeernot.wordpress.com&amp;blog=19658808&amp;post=93&amp;subd=tbeernot&amp;ref=&amp;feed=1" width="1" height="1" />]]></content:encoded>
			<wfw:commentRss>http://tbeernot.wordpress.com/2011/04/02/javafx-2-0-ea-binding/feed/</wfw:commentRss>
		<slash:comments>8</slash:comments>
	
		<media:content url="http://0.gravatar.com/avatar/824bd6d211a980b29b2dac9724d4815d?s=96&#38;d=identicon&#38;r=G" medium="image">
			<media:title type="html">tbeernot</media:title>
		</media:content>
	</item>
		<item>
		<title>Maven is the EJB2 of build tools</title>
		<link>http://tbeernot.wordpress.com/2011/03/25/maven-is-the-ejb2-of-build-tools/</link>
		<comments>http://tbeernot.wordpress.com/2011/03/25/maven-is-the-ejb2-of-build-tools/#comments</comments>
		<pubDate>Fri, 25 Mar 2011 13:41:54 +0000</pubDate>
		<dc:creator>tbeernot</dc:creator>
				<category><![CDATA[Uncategorized]]></category>

		<guid isPermaLink="false">http://tbeernot.wordpress.com/?p=77</guid>
		<description><![CDATA[KnowledgePlaza has a rapid development platform called Cheyenne. Cheyenne is based on Java and produces in the end a WAR file, that can be run inside any servlet 2.5 / jsp 2.1 compatible container (like Tomcat 6). Cheyenne projects are &#8230; <a href="http://tbeernot.wordpress.com/2011/03/25/maven-is-the-ejb2-of-build-tools/">Continue reading <span class="meta-nav">&#8594;</span></a><img alt="" border="0" src="http://stats.wordpress.com/b.gif?host=tbeernot.wordpress.com&amp;blog=19658808&amp;post=77&amp;subd=tbeernot&amp;ref=&amp;feed=1" width="1" height="1" />]]></description>
			<content:encoded><![CDATA[<p>KnowledgePlaza has a rapid development platform called Cheyenne. Cheyenne is based on Java and produces in the end a WAR file, that can be run inside any servlet 2.5 / jsp 2.1 compatible container (like Tomcat 6). Cheyenne projects are build using Maven.</p>
<p>One of the features in the build is that there is the option of overlays; a Cheyenne project can be overlaid with other Cheyenne projects, who provide generic Java classes, JSP files, resources, etc. This feature is very similar to the overlay feature in the default WAR plugin, but Cheyenne has a few tweaks and differences that have forced us to write our own Maven plugin.</p>
<p>Initially the concept of Maven is very straight forward; there is a default build cycle consisting of about 20 steps (phases), and certain actions are bound to the phases based on the packaging type. For example: building JARs require different actions than building WARs. Simple? Simple. So in order to implement our tweaked build for Cheyenne all that needs to be done is write some custom actions and bind them to the build cycle. But there is this huge gap between theory and actually getting it to work.</p>
<p>First step is these custom actions. As it happens we required just some tweaks on the standard WAR plugin, and since the plugins are written in Java it should be simple to extend the existing plugin&#8230; Unfortunately not. Maven plugins use pre-Java5 annotations, which are placed in the comment above variables and methods, similar to the Javadoc annotation. Like this:</p>
<p><pre class="brush: java; wrap-lines: false;">
    /**
     * The maven project.
     *
     * @parameter expression=&quot;${project}&quot;
     * @required
     * @readonly
     */
    private MavenProject project;
</pre></p>
<p>Only these are not Javadoc annotations but real Java wannabe-annotations. When building the plugin, the Maven build process analyses the Java source file and extracts these annotations and uses it for all kinds of things, including dependency injection as the example above shows. This is the way annotations were done before Java supported annotations itself, before Java 1.5. Biggest drawback? The annotations are not part of the class file and that is why extending them will not work. So instead of extending the existing WAR plugin, the actual source code must be included into the project (hurray for open source). Point is; annotations have been around since Java 1.5, since 2004, and Java 1.7 is about to be released (seriously delayed)&#8230;</p>
<p>Then binding the actions to the build process. Normally you would do this using plugins in the pom.xml, like so:<br />
<pre class="brush: xml; wrap-lines: false;">
	&lt;plugins&gt;
		&lt;plugin&gt;
			&lt;groupId&gt;org.apache.maven.plugins&lt;/groupId&gt;
			&lt;artifactId&gt;maven-compiler-plugin&lt;/artifactId&gt;
			&lt;version&gt;2.3.1&lt;/version&gt;
			&lt;configuration&gt;
				&lt;source&gt;1.6&lt;/source&gt;
				&lt;target&gt;1.6&lt;/target&gt;
				&lt;showDeprecation&gt;false&lt;/showDeprecation&gt;
				&lt;warning&gt;false&lt;/warning&gt;
				&lt;fork&gt;false&lt;/fork&gt;
			&lt;/configuration&gt;
		&lt;/plugin&gt;
	&lt;/plugins&gt;
</pre></p>
<p>Loads of XML to configure stuff, very EJB2. I always wondered why this was not written more compact, something like:<br />
<pre class="brush: xml; wrap-lines: false;">
	&lt;plugins&gt;
		&lt;maven-compiler-plugin groupId=&quot;org.apache.maven.plugins&quot; version=&quot;2.3.1&quot; source=&quot;1.6&quot; 
			target=&quot;1.6&quot; showDeprecation=&quot;false&quot; warning=&quot;false&quot; fork=&quot;false&quot;
	&lt;/plugins&gt;
</pre></p>
<p>But this particular plugin also exposes another issue with Maven; bad defaults. The Maven 2 build process  always assumes Java 1.2, Maven 3 per default assumes Java 1.5, but it still is a bad default. Using the currently used javac&#8217;s would be the smarter choice.</p>
<p>Back to the binding. In order to prevent every Cheyenne project to have to include four plugin XML sniplets in their poms (making them hard to maintain), one either lets the project pom inherit from a special Cheyenne superpom, or a custom build cycle is required. Since we do not want to limit the dynamics of the project pom by forcing a packaging-related parent to be inherited, the custom build cycle approach was used. This means that only a single Cheyenne plugin XML sniplet is still required in the project&#8217;s pom, but with one special setting:</p>
<p><pre class="brush: xml; wrap-lines: false;">
	&lt;plugin&gt;
		&lt;groupId&gt;nl.innovationinvestments&lt;/groupId&gt;
		&lt;artifactId&gt;CheyenneMavenPlugin&lt;/artifactId&gt;
		&lt;version&gt;1.11&lt;/version&gt;
		&lt;extensions&gt;true&lt;/extensions&gt;
	&lt;/plugin&gt;
</pre></p>
<p>The extentions tag is the key; it tells Maven that the plugin actually holds a whole new build cycle mapping. This build cycle contains the actual mapping of all the actions to the build cycle phases. Naturally this involves yet another XML configuration:<br />
<pre class="brush: xml; wrap-lines: false;">
&lt;?xml version=&quot;1.0&quot;?&gt;
&lt;component-set&gt;
  &lt;components&gt;
	&lt;!-- this is the custom life cycle binding --&gt;
    &lt;component&gt;
      &lt;role&gt;org.apache.maven.lifecycle.mapping.LifecycleMapping&lt;/role&gt;
      &lt;role-hint&gt;chy&lt;/role-hint&gt;
      &lt;implementation&gt;org.apache.maven.lifecycle.mapping.DefaultLifecycleMapping&lt;/implementation&gt;
      &lt;configuration&gt;
        &lt;lifecycles&gt;
          &lt;lifecycle&gt;
            &lt;id&gt;default&lt;/id&gt;
            &lt;phases&gt;
              &lt;generate-sources&gt;org.appfuse:maven-warpath-plugin:2.0.2:add-classes&lt;/generate-sources&gt; &lt;!-- also include dependencies in war dependencies --&gt;
              &lt;generate-sources&gt;nl.innovationinvestments:CheyenneMavenPlugin:${project.version}:compile&lt;/generate-sources&gt; &lt;!-- call the cheyenne compiler --&gt;
              &lt;process-resources&gt;org.apache.maven.plugins:maven-resources-plugin:resources&lt;/process-resources&gt;
              &lt;compile&gt;org.apache.maven.plugins:maven-compiler-plugin:compile&lt;/compile&gt;
              &lt;process-test-resources&gt;org.apache.maven.plugins:maven-resources-plugin:testResources&lt;/process-test-resources&gt;
              &lt;test-compile&gt;org.apache.maven.plugins:maven-compiler-plugin:testCompile&lt;/test-compile&gt;
              &lt;test&gt;org.apache.maven.plugins:maven-surefire-plugin:test&lt;/test&gt;
              &lt;package&gt;nl.innovationinvestments:CheyenneMavenPlugin:${project.version}:package&lt;/package&gt; &lt;!-- call the cheyenne packager --&gt;
              &lt;install&gt;org.apache.maven.plugins:maven-install-plugin:install&lt;/install&gt;
              &lt;deploy&gt;org.apache.maven.plugins:maven-deploy-plugin:deploy&lt;/deploy&gt;
            &lt;/phases&gt;
          &lt;/lifecycle&gt;
        &lt;/lifecycles&gt;
      &lt;/configuration&gt;
    &lt;/component&gt;
	
	&lt;!-- this makes sure we generate the correct type of artifacts --&gt;
    &lt;component&gt;
      &lt;role&gt;org.apache.maven.artifact.handler.ArtifactHandler&lt;/role&gt;
      &lt;role-hint&gt;chy&lt;/role-hint&gt;
      &lt;implementation&gt;
        org.apache.maven.artifact.handler.DefaultArtifactHandler
      &lt;/implementation&gt;
      &lt;configuration&gt;
        &lt;type&gt;chy&lt;/type&gt;
        &lt;extension&gt;war&lt;/extension&gt;
        &lt;language&gt;java&lt;/language&gt;
        &lt;addedToClasspath&gt;true&lt;/addedToClasspath&gt;
      &lt;/configuration&gt;
    &lt;/component&gt;
	
	&lt;!-- copied from warpath plugin --&gt;
	&lt;component&gt;
      &lt;role&gt;org.apache.maven.artifact.handler.ArtifactHandler&lt;/role&gt;
      &lt;role-hint&gt;warpath&lt;/role-hint&gt;
      &lt;implementation&gt;org.apache.maven.artifact.handler.DefaultArtifactHandler&lt;/implementation&gt;
      &lt;configuration&gt;
        &lt;type&gt;war&lt;/type&gt;
        &lt;includesDependencies&gt;false&lt;/includesDependencies&gt;
        &lt;language&gt;java&lt;/language&gt;
        &lt;addedToClasspath&gt;false&lt;/addedToClasspath&gt;
      &lt;/configuration&gt;
    &lt;/component&gt;
   &lt;component&gt;
    &lt;role&gt;org.apache.maven.artifact.handler.ArtifactHandler&lt;/role&gt;
    &lt;role-hint&gt;classes&lt;/role-hint&gt;
    &lt;implementation&gt;org.apache.maven.artifact.handler.DefaultArtifactHandler&lt;/implementation&gt;
    &lt;configuration&gt;
      &lt;type&gt;war&lt;/type&gt;
      &lt;includesDependencies&gt;true&lt;/includesDependencies&gt;
      &lt;language&gt;java&lt;/language&gt;
      &lt;addedToClasspath&gt;true&lt;/addedToClasspath&gt;
    &lt;/configuration&gt;
  &lt;/component&gt;
  &lt;component&gt;
    &lt;role&gt;org.apache.maven.artifact.handler.ArtifactHandler&lt;/role&gt;
    &lt;role-hint&gt;war&lt;/role-hint&gt;
    &lt;implementation&gt;org.apache.maven.artifact.handler.DefaultArtifactHandler&lt;/implementation&gt;
    &lt;configuration&gt;
      &lt;type&gt;war&lt;/type&gt;
      &lt;includesDependencies&gt;false&lt;/includesDependencies&gt;
      &lt;language&gt;java&lt;/language&gt;
      &lt;addedToClasspath&gt;false&lt;/addedToClasspath&gt;
    &lt;/configuration&gt;
  &lt;/component&gt;
  
  &lt;/components&gt;
&lt;/component-set&gt;
</pre></p>
<p>Using this approach meant that we could no longer use the warpath plugin (which was one of the XML plugins), because it also required the use of &#8220;extention&#8221;, and only one build cycle can be active at any time. That again meant we had to import the binding of the warpath plugin into our own. To be frank, I gave up trying to understand what exactly is being configured here. Too much XML, too much levels, too much EJB2 / struts. It worked and that was enough time spent. </p>
<p>To summarize; the current Maven (3.0) gives me XML blues just like EJB2 and struts did. Don&#8217;t get me wrong, I like Maven. I use it for all my projects, because of its many advantages. And the concept is fine, only the implementation is too complex due to too many layers and configuration files. Coding-by-XML is not the way to go. My wishlist for Maven 3.1 would have it be more like EJB 3, by:<br />
- more compact poms and notation style<br />
- smarter more dynamic defaults<br />
- use Java annotations when developing plugins, thus allowing extending them<br />
- using less XML for plugin development, maybe even no XML at all for 90% of the use cases<br />
- allow plugins to hook into multiple phases which just one entry in the project&#8217;s pom<br />
- allow multiple plugins to do this simultaneously</p>
<p>Afterall it&#8217;s been about 5 years since EJB3 was released and that was the &#8220;corporate slow&#8221; adoption of the keep-it-simple style. If a huge and heavy process like the JCP adopted this style 5 years ago&#8230;</p>
<br />  <a rel="nofollow" href="http://feeds.wordpress.com/1.0/gocomments/tbeernot.wordpress.com/77/"><img alt="" border="0" src="http://feeds.wordpress.com/1.0/comments/tbeernot.wordpress.com/77/" /></a> <a rel="nofollow" href="http://feeds.wordpress.com/1.0/godelicious/tbeernot.wordpress.com/77/"><img alt="" border="0" src="http://feeds.wordpress.com/1.0/delicious/tbeernot.wordpress.com/77/" /></a> <a rel="nofollow" href="http://feeds.wordpress.com/1.0/gofacebook/tbeernot.wordpress.com/77/"><img alt="" border="0" src="http://feeds.wordpress.com/1.0/facebook/tbeernot.wordpress.com/77/" /></a> <a rel="nofollow" href="http://feeds.wordpress.com/1.0/gotwitter/tbeernot.wordpress.com/77/"><img alt="" border="0" src="http://feeds.wordpress.com/1.0/twitter/tbeernot.wordpress.com/77/" /></a> <a rel="nofollow" href="http://feeds.wordpress.com/1.0/gostumble/tbeernot.wordpress.com/77/"><img alt="" border="0" src="http://feeds.wordpress.com/1.0/stumble/tbeernot.wordpress.com/77/" /></a> <a rel="nofollow" href="http://feeds.wordpress.com/1.0/godigg/tbeernot.wordpress.com/77/"><img alt="" border="0" src="http://feeds.wordpress.com/1.0/digg/tbeernot.wordpress.com/77/" /></a> <a rel="nofollow" href="http://feeds.wordpress.com/1.0/goreddit/tbeernot.wordpress.com/77/"><img alt="" border="0" src="http://feeds.wordpress.com/1.0/reddit/tbeernot.wordpress.com/77/" /></a> <img alt="" border="0" src="http://stats.wordpress.com/b.gif?host=tbeernot.wordpress.com&amp;blog=19658808&amp;post=77&amp;subd=tbeernot&amp;ref=&amp;feed=1" width="1" height="1" />]]></content:encoded>
			<wfw:commentRss>http://tbeernot.wordpress.com/2011/03/25/maven-is-the-ejb2-of-build-tools/feed/</wfw:commentRss>
		<slash:comments>0</slash:comments>
	
		<media:content url="http://0.gravatar.com/avatar/824bd6d211a980b29b2dac9724d4815d?s=96&#38;d=identicon&#38;r=G" medium="image">
			<media:title type="html">tbeernot</media:title>
		</media:content>
	</item>
		<item>
		<title>KPMiniPickerView</title>
		<link>http://tbeernot.wordpress.com/2011/03/13/kpminipickerview/</link>
		<comments>http://tbeernot.wordpress.com/2011/03/13/kpminipickerview/#comments</comments>
		<pubDate>Sun, 13 Mar 2011 11:49:44 +0000</pubDate>
		<dc:creator>tbeernot</dc:creator>
				<category><![CDATA[Apple]]></category>
		<category><![CDATA[iOS]]></category>
		<category><![CDATA[iPad]]></category>
		<category><![CDATA[Objective-C]]></category>
		<category><![CDATA[UI]]></category>
		<category><![CDATA[Uncategorized]]></category>

		<guid isPermaLink="false">http://tbeernot.wordpress.com/?p=65</guid>
		<description><![CDATA[In the continuing story of iPad development one of the issues that became obvious was that the UIDatePicker looked really lousy in the overall design of the hour entry application. The UIPickerView component that is used by UIDatePicker has a &#8230; <a href="http://tbeernot.wordpress.com/2011/03/13/kpminipickerview/">Continue reading <span class="meta-nav">&#8594;</span></a><img alt="" border="0" src="http://stats.wordpress.com/b.gif?host=tbeernot.wordpress.com&amp;blog=19658808&amp;post=65&amp;subd=tbeernot&amp;ref=&amp;feed=1" width="1" height="1" />]]></description>
			<content:encoded><![CDATA[<p>In the continuing story of iPad development one of the issues that became obvious was that the UIDatePicker looked really lousy in the overall design of the hour entry application. The UIPickerView component that is used by UIDatePicker has a fixed skin that is hard to fit into another layout. This was mostly caused by the appearence it generates that it is a scroll wheel inside some kind of casing, but the casing has no outside border. So It really did not fit-in well.</p>
<p><a href="http://tbeernot.files.wordpress.com/2011/03/uipickerview.png"><img src="http://tbeernot.files.wordpress.com/2011/03/uipickerview.png?w=640" alt="" title="UIPickerView"   class="alignnone size-full wp-image-71" /></a></p>
<p>Secondly the UIDatePicker takes up quite a bit of space on the screen but you cannot quickly pick another date in the same month; you have to scroll to it, possibly 30 days. I like the &#8220;normal&#8221; date pickers better. So I found the required excuse to write one.</p>
<p><a href="http://tbeernot.files.wordpress.com/2011/03/kpcalendarpickerview.png"><img class="alignnone size-full wp-image-66" title="KPCalendarPickerView" src="http://tbeernot.files.wordpress.com/2011/03/kpcalendarpickerview.png?w=640" alt=""   /></a></p>
<p>Selecting a day somewhere in the month has become much quicker now and the UI is familiar to most user; it takes up a little bit more room than a UIDatePicker, but for that you get quick navigation. The only issue was that there still was a need to pick a year and month. Using the UIPickerView for this was not an option, because of the same problems. So I needed a picker that embedded more easily in a layout and required less space; a mini picker. They are visible at the top of the calendar picker; one for the year, one for the month. I chose a look that was similar to a regular text field, but instead of typing text, you can scroll the contents. The individual views are separated by a vertical divider bar:</p>
<p><a href="http://tbeernot.files.wordpress.com/2011/03/kpminipickerviewmid.png"><img class="alignnone size-full wp-image-68" title="KPMiniPickerViewMid" src="http://tbeernot.files.wordpress.com/2011/03/kpminipickerviewmid.png?w=640" alt=""   /></a></p>
<p>It uses the KPOverlayView that was introduced in a previous blog to paint two small arrows to visually indicate that this is a minipicker, not a textfield. It also mimicks UIPickerView as closely as possible, so it has a delegate that provides the child views with an API that is almost identical to UIPickerView&#8217;s, except naturally that it does not send along a UIPickerView but a KPMiniPickerView. And for now it only supports one component (the UIPickerView can have multiple spinning wheels, aka components, next to each other); I&#8217;m still thinking about how to support multiple components in a mini picker style.</p>
<p>As an example of its uages, below is the code for the KPMonthMiniPickerView that uses the mini picker:</p>
<p><pre class="brush: objc; wrap-lines: false;">
//
//  KPMonthMiniPickerView.m
//  DH2iPad
//
//  Created by Tom Eugelink on 13.02.11.
//  Copyright 2011 KnowledgePlaza. All rights reserved.
//

#import &quot;KPMonthMiniPickerView.h&quot;
#import &quot;KPUtil.h&quot;

@implementation KPMonthMiniPickerView

@synthesize monthSelectedListeners;

- (id)initWithFrame:(CGRect)frame {
    
    self = [super initWithFrame:frame];
    if (self) {
		// listeners
		monthSelectedListeners = [[KPListenerManager alloc] init]; // released in dealloc

        // create a picker
		_kpMiniPickerView = [[KPMiniPickerView alloc] initWithFrame:CGRectMake(0, 0, self.bounds.size.width, self.bounds.size.height)]; // we alloc, and release in dealloc
		_kpMiniPickerView.delegate = self;
		_kpMiniPickerView.backgroundColor = [UIColor clearColor];
		[_kpMiniPickerView selectView:[self pickerView:_kpMiniPickerView numberOfRowsInComponent:1] / 2]; // always start in the middle
		[self addSubview:_kpMiniPickerView];
		_kpMiniPickerView.autoresizingMask = UIViewAutoresizingFlexibleWidth | UIViewAutoresizingFlexibleHeight;
		
		// init
		[self setMonth:1];
    }
    return self;
}

- (void)dealloc {
	[monthSelectedListeners release];
	[_kpMiniPickerView release];
    [super dealloc];
}

// set the selected month
-(void)setMonth:(int)value {
	[_kpMiniPickerView selectView:value - 1];
}

// get the selected month
-(int)getMonth {
	int lMonth =  [_kpMiniPickerView getSelectedViewIdx] + 1;
	return lMonth;
}

// ====================================================================================================================================
// KPMiniPickerViewDelegate 

- (NSInteger) numberOfComponentsInPickerView: (KPMiniPickerView *) pickerView {
	return 1;
}

- (NSInteger) pickerView: (KPMiniPickerView*) pickerView numberOfRowsInComponent: (NSInteger) component {
	return 12;
}

- (UIView *)pickerView:(KPMiniPickerView *)pickerView viewForRow:(NSInteger)row forComponent:(NSInteger)component reusingView:(UIView *)view{
	NSString* lDateString = [NSString stringWithFormat:@&quot;2011-%d-01 00:00:00 +0:00&quot;, (component + 1)];
	NSDate* lDate = [NSDate dateWithString:lDateString];
	NSLocale *lLocale = [[NSLocale alloc] initWithLocaleIdentifier:@&quot;nl_NL&quot;];

	CGRect rect = CGRectMake(0, 0, 120, 80);
	UILabel *label = [[UILabel alloc]initWithFrame:rect];
	label.layer.borderColor = [UIColor grayColor].CGColor; label.layer.borderWidth = 1;
	label.text = [KPUtil formatDate:lDate as:@&quot;MMM&quot; for:lLocale];
	label.textAlignment = UITextAlignmentCenter;
	label.backgroundColor = [UIColor whiteColor];
	label.clipsToBounds = YES;
	
	[lLocale release];
	
	return label ;
}

- (void) pickerView:(KPMiniPickerView*)pickerView didSelectRow:(NSInteger)row inComponent:(NSInteger)component {
	[monthSelectedListeners notify:[NSNumber numberWithInt:[self getMonth]]];
}

@end
</pre></p>
<p>Leaves me to say that personally I&#8217;m very pleased with the result. This does not mean that there is no room for improvement. I want to start recognizing swipes, so you can scroll more easily, but as a basis this works quite nice. If anyone picks up this code and improves it, please send me any enhancements.</p>
<p>The header file:<br />
<pre class="brush: objc; wrap-lines: false;">
//
//  KPMiniPickerViewer.h
//  DH2iPad
//
//  Created by TBEE on 08.02.11.
//  Copyright 2011 KnowledgePlaza. All rights reserved.
//

#import &lt;UIKit/UIKit.h&gt;
#import &quot;KPOverlayView.h&quot; 

@class KPMiniPickerView; // this is required to not have problems with circular references
@protocol KPMiniPickerViewDelegate&lt;NSObject&gt;
	@required
	- (NSInteger) numberOfComponentsInPickerView: (KPMiniPickerView*)pickerView;
	- (NSInteger) pickerView: (KPMiniPickerView*)pickerView numberOfRowsInComponent:(NSInteger)component;
	@optional
	- (UIView *)pickerView:(KPMiniPickerView *)pickerView viewForRow:(NSInteger)row forComponent:(NSInteger)component reusingView:(UIView *)view;
	- (void)pickerView:(KPMiniPickerView *)pickerView didSelectRow:(NSInteger)row inComponent:(NSInteger)component;
	- (CGFloat)pickerView:(KPMiniPickerView *)pickerView rowHeightForComponent:(NSInteger)component; // not used
	- (NSString *)pickerView:(KPMiniPickerView *)pickerView titleForRow:(NSInteger)row forComponent:(NSInteger)component; // not used
	- (CGFloat)pickerView:(KPMiniPickerView *)pickerView widthForComponent:(NSInteger)component; // not used
@end

@interface KPMiniPickerView : UIView {
	int _activeViewIdx;
	int _viewportPos; // assume all child views are stack, then this is the center of the viewport. By changing this value it can be calculated which views are visible how.
	CGPoint _touchStartPos;
	NSMutableDictionary* _indexToViewDictionary;
	KPOverlayView* _kpOverlayView;
	float _lastWidth;
}

@property(nonatomic, assign) id&lt;KPMiniPickerViewDelegate&gt; delegate;

-(void)selectView:(int)index;
-(int)getSelectedViewIdx;

@end
</pre></p>
<p>The actual source file:</p>
<p><pre class="brush: objc; wrap-lines: false;">
//
//  KPMiniPickerViewer.m
//  DH2iPad
//
//  Created by TBEE on 08.02.11.
//  Copyright 2011 KnowledgePlaza. All rights reserved.
//
// This is a alternate implementation for UIPickerView.
// The main issue here is that UIPickerView not only takes up quite an amount of space on screen,
// but also is style explicitly, thus not easy to embed in differently themed apps.
// The minipicker view acts like a viewport on a horizontal string of views, like a ribbon.
//
// This class mimicks the API of UIPickerView, using a similar delegate as the UIPickerViewDelegate.
// But the current version only supports one component.
//
// Usage also is similar to KPPickerView:
//   _kpMiniPickerView = [[KPMiniPickerView alloc] initWithFrame:CGRectMake(...)];
//   _kpMiniPickerView.delegate = self; // self implements KPMiniPickerViewDelegate
//

#import &quot;KPMiniPickerView.h&quot;
#import &lt;QuartzCore/QuartzCore.h&gt;

@interface KPMiniPickerView (hidden)
	-(void)layoutForViewportPos:(int)viewportPos;
	-(UIView*)viewForIndex:(int)index offset:(int)offset;
	-(void)centerOnView:(int)index;
@end

@implementation KPMiniPickerView

@synthesize delegate;

- (id)initWithFrame:(CGRect)frame {
    
    self = [super initWithFrame:frame];
    if (self) {
		// storage 
		_indexToViewDictionary = [[NSMutableDictionary dictionaryWithCapacity:5] retain];
		
		// styling 
		self.backgroundColor = [UIColor whiteColor];
		self.layer.borderColor = [UIColor grayColor].CGColor;
		self.layer.borderWidth = 2;
		self.layer.cornerRadius = 10;
		self.clipsToBounds = YES;
		
		// overlay
		_kpOverlayView = [KPOverlayView overlayWithView:self drawMethod:@selector(drawOverlay:)]; // released when the view is removed from the subviews
		// but since we will be removing it and putting it back on top somehwre below, we need to keep hold of it ourselves
		[_kpOverlayView retain]; // released in dealloc
    }
    return self;
}

- (void)dealloc {
	[_indexToViewDictionary release];
	[_kpOverlayView release];
    [super dealloc];
}

- (void)layoutSubviews {
	// not initialized
	if (_viewportPos == 0) { 
		[self selectView:_activeViewIdx];
		_lastWidth = self.bounds.size.width;
	}
	
	// width changed? (this is for handling rotations)
	if (_lastWidth != self.bounds.size.width) {
		[_indexToViewDictionary removeAllObjects]; // clear the cache
		[self centerOnView:_activeViewIdx]; // recalculate the viewportpos
		_lastWidth = self.bounds.size.width;
	}
	
	// just paint
	[self viewForIndex:_viewportPos offset:0];
}

// return the index of the currently selected view
-(int)getSelectedViewIdx {
	return _activeViewIdx;
}

// make the view at the specified index the active one
-(void)selectView:(int)index {
	int lOldViewIdx = _activeViewIdx;
	_activeViewIdx = index;
	[self centerOnView:_activeViewIdx];
	
	// notify delegate if changed
	if (lOldViewIdx != _activeViewIdx) {
		[delegate pickerView:self didSelectRow:1 inComponent:_activeViewIdx];
	}
}

// set the viewport pos so that it has the specified view index centered
-(void)centerOnView:(int)index {
	_viewportPos = (index * self.bounds.size.width) + (self.bounds.size.width / 2);
	[self layoutForViewportPos:_viewportPos];
}

// calculate which view idx is most visible by the specified pos
-(int)posToView:(int)viewportPos {
	int lViewCnt = [delegate pickerView:self numberOfRowsInComponent:1];
	int lIdx =  (int)(viewportPos / self.bounds.size.width);
	if (lIdx &lt; 0) lIdx = 0;
	if (lIdx &gt;= lViewCnt-1) lIdx = lViewCnt - 1; 
	return lIdx;
}

// return the corresponding via for the specified view index (adding the offset to that index)
-(UIView*)viewForIndex:(int)index offset:(int)offset {
	// cache key
	NSString* lKey = [NSString stringWithFormat:@&quot;%d&quot;, (index + offset)];
	
	// get from cache
	UIView* lView = [_indexToViewDictionary objectForKey:lKey];
	if (lView != nil) return lView;
	
	// create new
	lView = [delegate pickerView:self viewForRow:0 forComponent:(index + offset) reusingView: nil];
	lView.frame = CGRectMake(offset * self.bounds.size.width, 0, self.bounds.size.width, self.bounds.size.height);
	
	// store in cache
	[_indexToViewDictionary setObject:lView forKey:lKey];
	
	// also clear some objects if the cache becomes too full
	int lClearCacheIdx = (index + offset) - 10; // TODO: make 10 configurable?
	lKey = [NSString stringWithFormat:@&quot;%d&quot;, lClearCacheIdx];
	while ([_indexToViewDictionary objectForKey:lKey] != nil) {
		[_indexToViewDictionary removeObjectForKey:lKey];
		lClearCacheIdx--;
		lKey = [NSString stringWithFormat:@&quot;%d&quot;, lClearCacheIdx];
	}
	lClearCacheIdx = (index + offset) + 10; // TODO: make 10 configurable?
	lKey = [NSString stringWithFormat:@&quot;%d&quot;, lClearCacheIdx];
	while ([_indexToViewDictionary objectForKey:lKey] != nil) {
		[_indexToViewDictionary removeObjectForKey:lKey];
		lClearCacheIdx++;
		lKey = [NSString stringWithFormat:@&quot;%d&quot;, lClearCacheIdx];
	}
	
	// done
	return lView;
}

// layout the views of the childeren for the specified viewport pos
-(void)layoutForViewportPos:(int)viewportPos {
	// determine the views that are visible
	int lCenterViewIdx = [self posToView:viewportPos];
	int lCenterViewViewportPos = (lCenterViewIdx * self.bounds.size.width) + (self.bounds.size.width / 2);
	int lDeltaX = lCenterViewViewportPos - viewportPos;
	
	// get visible views
	int lViewCnt = [delegate pickerView:self numberOfRowsInComponent:1];
	UIView* lViewCenter = [self viewForIndex:lCenterViewIdx offset:0];
	UIView* lViewBefore = lCenterViewIdx &lt;= 0 ? nil : [self viewForIndex:lCenterViewIdx offset:-1];
	UIView* lViewAfter = lCenterViewIdx &gt;= (lViewCnt-1) ? nil : [self viewForIndex:lCenterViewIdx offset:+1];
	
	// clear up the childeren so only these three are present
	// this also removes the overlay! We want this so we can add it again and it will be on top
	for (UIView* lView in self.subviews) {
		if (lView != lViewBefore &amp;&amp; lView != lViewCenter &amp;&amp; lView != lViewAfter) {
			[lView removeFromSuperview];
		}
	}	
	
	// add any new subviews
	if (lViewBefore != nil &amp;&amp; [self.subviews containsObject:lViewBefore] == NO) { [self addSubview:lViewBefore]; }
	if (lViewCenter != nil &amp;&amp; [self.subviews containsObject:lViewCenter] == NO) { [self addSubview:lViewCenter]; } 
	if (lViewAfter != nil &amp;&amp; [self.subviews containsObject:lViewAfter] == NO) { [self addSubview:lViewAfter]; }
	// add the overlay again last so it is on top
	[self addSubview:_kpOverlayView]; 
	
	// animate the views to their positions
	CGRect lCGRect = CGRectMake(0, 0, self.bounds.size.width, self.bounds.size.height);
	[UIView beginAnimations:nil context:NULL];
	lCGRect.origin.x = lDeltaX;
	if (lViewCenter != nil) lViewCenter.frame = lCGRect;
	lCGRect.origin.x = lDeltaX - self.bounds.size.width;
	if (lViewBefore != nil) lViewBefore.frame = lCGRect;
	lCGRect.origin.x = lDeltaX + self.bounds.size.width;
	if (lViewAfter != nil) lViewAfter.frame = lCGRect;
	[UIView commitAnimations];	
}

// draw
- (void)drawRect:(CGRect)rect {
	// if there is no child, set it
	if (self.subviews.count == 0) [self selectView:_activeViewIdx];
	
	// do it
	[super drawRect:rect];
}	

// draw the overlay
- (void)drawOverlay:(CGRect)rect {
	int lXMargin = 6;
	int lArrowWidth = 10;
	int lArrowHeight = 10;
	int lYMargin = (self.bounds.size.height - lArrowHeight) / 2;
						
	// get context
	CGContextRef ctx = UIGraphicsGetCurrentContext();
	
	// setup pen 
	CGContextSetRGBStrokeColor(ctx, 0.18, 0.38, 0.86, 0.5);
	CGContextSetLineWidth(ctx,2.0);
	
	// draw left arrow
	CGContextMoveToPoint(ctx, lXMargin + lArrowWidth, lYMargin);
	CGContextAddLineToPoint( ctx, lXMargin, lYMargin + (lArrowHeight / 2) );
	CGContextAddLineToPoint( ctx, lXMargin + lArrowWidth, lYMargin + lArrowHeight);
	
	// draw right arrow
	CGContextMoveToPoint(ctx, self.bounds.size.width - lXMargin - lArrowWidth, lYMargin);
	CGContextAddLineToPoint( ctx, self.bounds.size.width - lXMargin, lYMargin + (lArrowHeight / 2) );
	CGContextAddLineToPoint( ctx, self.bounds.size.width - lXMargin - lArrowWidth, lYMargin + lArrowHeight);
	
	//&quot;stroke&quot; the path
	CGContextStrokePath(ctx);
}	

// Handles the start of a touch
-(void)touchesBegan:(NSSet *)touches withEvent:(UIEvent *)event {
	// Enumerate through all the touch objects.
	for (UITouch* lTouch in touches) {
		_touchStartPos = [lTouch locationInView:self];
	}
}

// Handles the continuation of a touch.
-(void)touchesMoved:(NSSet *)touches withEvent:(UIEvent *)event {
	
	// reposition child
	for (UITouch* lTouch in touches) {
		CGPoint lTouchPos = [lTouch locationInView:self];
		
		// how much did we move horizontally
		CGFloat lDeltaX = lTouchPos.x - _touchStartPos.x;
		
		// determine where we are in the index
		int lNewviewportPos = _viewportPos - lDeltaX;
		
		// also move the view that much horizontally
		[self layoutForViewportPos:lNewviewportPos];
	}
}

// Handles the end of a touch event.
-(void)touchesEnded:(NSSet *)touches withEvent:(UIEvent *)event {
	for (UITouch* lTouch in touches) {
		CGPoint lTouchPos = [lTouch locationInView:self];
		
		// how much did we move horizontally
		CGFloat lDeltaX = lTouchPos.x - _touchStartPos.x;
		
		// determine where we are in the index
		int lNewviewportPos = _viewportPos - lDeltaX;
		
		// determine the view that would be central
		int lCenterViewIdx = [self posToView:lNewviewportPos];

		// center that
		[self selectView:lCenterViewIdx];
	}
}

// if the touch was cancelled, reset to a valid state
-(void)touchesCancelled:(NSSet *)touches withEvent:(UIEvent *)event {
	[self layoutForViewportPos:_viewportPos];
}

@end

</pre></p>
<br />  <a rel="nofollow" href="http://feeds.wordpress.com/1.0/gocomments/tbeernot.wordpress.com/65/"><img alt="" border="0" src="http://feeds.wordpress.com/1.0/comments/tbeernot.wordpress.com/65/" /></a> <a rel="nofollow" href="http://feeds.wordpress.com/1.0/godelicious/tbeernot.wordpress.com/65/"><img alt="" border="0" src="http://feeds.wordpress.com/1.0/delicious/tbeernot.wordpress.com/65/" /></a> <a rel="nofollow" href="http://feeds.wordpress.com/1.0/gofacebook/tbeernot.wordpress.com/65/"><img alt="" border="0" src="http://feeds.wordpress.com/1.0/facebook/tbeernot.wordpress.com/65/" /></a> <a rel="nofollow" href="http://feeds.wordpress.com/1.0/gotwitter/tbeernot.wordpress.com/65/"><img alt="" border="0" src="http://feeds.wordpress.com/1.0/twitter/tbeernot.wordpress.com/65/" /></a> <a rel="nofollow" href="http://feeds.wordpress.com/1.0/gostumble/tbeernot.wordpress.com/65/"><img alt="" border="0" src="http://feeds.wordpress.com/1.0/stumble/tbeernot.wordpress.com/65/" /></a> <a rel="nofollow" href="http://feeds.wordpress.com/1.0/godigg/tbeernot.wordpress.com/65/"><img alt="" border="0" src="http://feeds.wordpress.com/1.0/digg/tbeernot.wordpress.com/65/" /></a> <a rel="nofollow" href="http://feeds.wordpress.com/1.0/goreddit/tbeernot.wordpress.com/65/"><img alt="" border="0" src="http://feeds.wordpress.com/1.0/reddit/tbeernot.wordpress.com/65/" /></a> <img alt="" border="0" src="http://stats.wordpress.com/b.gif?host=tbeernot.wordpress.com&amp;blog=19658808&amp;post=65&amp;subd=tbeernot&amp;ref=&amp;feed=1" width="1" height="1" />]]></content:encoded>
			<wfw:commentRss>http://tbeernot.wordpress.com/2011/03/13/kpminipickerview/feed/</wfw:commentRss>
		<slash:comments>3</slash:comments>
	
		<media:content url="http://0.gravatar.com/avatar/824bd6d211a980b29b2dac9724d4815d?s=96&#38;d=identicon&#38;r=G" medium="image">
			<media:title type="html">tbeernot</media:title>
		</media:content>

		<media:content url="http://tbeernot.files.wordpress.com/2011/03/uipickerview.png" medium="image">
			<media:title type="html">UIPickerView</media:title>
		</media:content>

		<media:content url="http://tbeernot.files.wordpress.com/2011/03/kpcalendarpickerview.png" medium="image">
			<media:title type="html">KPCalendarPickerView</media:title>
		</media:content>

		<media:content url="http://tbeernot.files.wordpress.com/2011/03/kpminipickerviewmid.png" medium="image">
			<media:title type="html">KPMiniPickerViewMid</media:title>
		</media:content>
	</item>
		<item>
		<title>JavaFX 2.0 EA and MigLayout</title>
		<link>http://tbeernot.wordpress.com/2011/03/11/javafx-2-0-ea-and-miglayout/</link>
		<comments>http://tbeernot.wordpress.com/2011/03/11/javafx-2-0-ea-and-miglayout/#comments</comments>
		<pubDate>Fri, 11 Mar 2011 11:28:26 +0000</pubDate>
		<dc:creator>tbeernot</dc:creator>
				<category><![CDATA[Java]]></category>
		<category><![CDATA[javafx]]></category>
		<category><![CDATA[UI]]></category>

		<guid isPermaLink="false">http://tbeernot.wordpress.com/?p=44</guid>
		<description><![CDATA[Oracle rebooted JavaFX and finally positioned it as what I for a long time have been longing for; Swing 2.0. Let&#8217;s not kid ourselves; JavaFX is a new UI library for Java, using the API lessons learned from Swing and &#8230; <a href="http://tbeernot.wordpress.com/2011/03/11/javafx-2-0-ea-and-miglayout/">Continue reading <span class="meta-nav">&#8594;</span></a><img alt="" border="0" src="http://stats.wordpress.com/b.gif?host=tbeernot.wordpress.com&amp;blog=19658808&amp;post=44&amp;subd=tbeernot&amp;ref=&amp;feed=1" width="1" height="1" />]]></description>
			<content:encoded><![CDATA[<p>Oracle rebooted JavaFX and finally positioned it as what I for a long time have been longing for; Swing 2.0. Let&#8217;s not kid ourselves; JavaFX is a new UI library for Java, using the API lessons learned from Swing and taking it to the next level with animations and effects. The concept is powerful enough to even go into the 3rd dimension soon. And more importantly; JavaFX2 finally has a good integration (and therefor migration path) with Swing, so it actually has an existing user base which can easily be persuaded to take a peek. Not to mention the fact that it now uses Java instead of JavaFX script, so the EDI support is great right from the start. (Well done Oracle!) But if this doesn&#8217;t sound like Swing 2.0, I don&#8217;t know what will.</p>
<p>So what is JavaFX2 like? Well&#8230; I like it. The API is clean and intuitive. Since it uses a different approach, making everything from simple lines to complete tables just a node in a tree, it means that I still have to really get my head around that. Fact remains that this approach allows to easily add effects and animation on anything, being it on a square or complete screen (they&#8217;re all just nodes after all). But I know I will initially use JavaFX in existing Swing applications, so my primary interest is in the controls. In order to make my life easier, I decided that porting <a href="http://www.miglayout.com/">MigLayout</a> could be a good idea.</p>
<p>I must say that the initial results in my opinion are not bad at all. Below is an example of a simple test involving a TextBox and Rectangle:</p>
<p><pre class="brush: java; wrap-lines: false;">
public class MigPaneTest1 extends Application {

    public static void main(String[] args) {
        Launcher.launch(MigPane.class, args);
    }

	@Override
	public void start(Stage stage) {

        // root
        MigPane lRoot = new MigPane(new LC(), new AC(), new AC());

        // add nodes
        lRoot.add(new TextBox(10), new CC());
        lRoot.add(new Rectangle(30,30, Color.YELLOW), new CC());

        // create scene
        Scene scene = new Scene(lRoot, 600, 300);

        // create stage
        stage.setTitle(&quot;Test&quot;);
        stage.setScene(scene);
        stage.setVisible(true);
    }
}
</pre></p>
<p>This results in the following layout:</p>
<p><a href="http://tbeernot.files.wordpress.com/2011/03/test12.png"><img class="alignnone size-full wp-image-50" title="JavaFXTest1" src="http://tbeernot.files.wordpress.com/2011/03/test12.png?w=640" alt=""   /></a></p>
<p>What is important to me is the details that MigLayout takes care of that make a UI look good, like the margins and inner gaps. This can been seen when using the debug mode:</p>
<p><a href="http://tbeernot.files.wordpress.com/2011/03/test1d1.png"><img class="alignnone size-full wp-image-49" title="JavaFXTest1Debug" src="http://tbeernot.files.wordpress.com/2011/03/test1d1.png?w=640" alt=""   /></a></p>
<p>Sun told me that they will be phasing out the LayoutInfo class, this means that the approach we took in JFXtras 1.x can no longer work. So now all code resides in a single class.</p>
<p>In JavaFX you add nodes directly to the getChilderen() collection, but that would not allow me to include the MigLayout constraints. So the MigLayout managed nodes are added like GridPane via the add(Node, CC) method. However MigLayout also allows adding unmanaged nodes using the external constraint. The example below adds an additional unmanaged black rectangle to the layout:</p>
<p><pre class="brush: java; wrap-lines: false;">
        // add managed nodes
        lRoot.add(new TextBox(10), new CC());
        lRoot.add(new Rectangle(30,30, Color.YELLOW), new CC());

        // add unmanaged nodes
        lRoot.add(new Rectangle(100, 50, 30, 30), new CC().external());
</pre></p>
<p><a href="http://tbeernot.files.wordpress.com/2011/03/test4.png"><img class="alignnone size-full wp-image-51" title="JavaFXTest4" src="http://tbeernot.files.wordpress.com/2011/03/test4.png?w=640" alt=""   /></a></p>
<p>The code block below creates 10 Buttons, each with a different length of text, and wraps after every third. The second image added growX() to the CC:</p>
<p><pre class="brush: java; wrap-lines: false;">
        // create 10 buttons
        for (int i = 0; i &lt; 10; i++)
        {
	        // add a node
        	Button lButton = new Button(&quot;XXXXXXXXXXXXXXXXXXXXX&quot;.substring(0, i));
	        CC lCC = new CC();
	        if ((i + 1) % 3 == 0)
	        {
	        	lCC = lCC.wrap();
	        }
	        lRoot.add(lButton, lCC);
        }
</pre></p>
<p><a href="http://tbeernot.files.wordpress.com/2011/03/test3.png"><img class="alignnone size-full wp-image-52" title="Test3" src="http://tbeernot.files.wordpress.com/2011/03/test3.png?w=640" alt=""   /></a></p>
<p>MigLayout seems to be doing its job just fine, so layout in JavaFX2 can start at a fairly high level right from the beginning.</p>
<p>It is unclear to me in which project this all will end up. JFXtras seems not to be spooling up yet, so for now I&#8217;ve moved the sources into sourceforge, together with all kinds of other JFX things I&#8217;m fiddling with. The latest version of the source can be found <a href="http://java.net/projects/miglayoutfx2" target="_blank">here</a>.</p>
<p><strong>Update 2011-08-14:</strong> MigLayoutFX2 is renamed to MigPane to better match JavaFX&#8217;s layouts.</p>
<br />  <a rel="nofollow" href="http://feeds.wordpress.com/1.0/gocomments/tbeernot.wordpress.com/44/"><img alt="" border="0" src="http://feeds.wordpress.com/1.0/comments/tbeernot.wordpress.com/44/" /></a> <a rel="nofollow" href="http://feeds.wordpress.com/1.0/godelicious/tbeernot.wordpress.com/44/"><img alt="" border="0" src="http://feeds.wordpress.com/1.0/delicious/tbeernot.wordpress.com/44/" /></a> <a rel="nofollow" href="http://feeds.wordpress.com/1.0/gofacebook/tbeernot.wordpress.com/44/"><img alt="" border="0" src="http://feeds.wordpress.com/1.0/facebook/tbeernot.wordpress.com/44/" /></a> <a rel="nofollow" href="http://feeds.wordpress.com/1.0/gotwitter/tbeernot.wordpress.com/44/"><img alt="" border="0" src="http://feeds.wordpress.com/1.0/twitter/tbeernot.wordpress.com/44/" /></a> <a rel="nofollow" href="http://feeds.wordpress.com/1.0/gostumble/tbeernot.wordpress.com/44/"><img alt="" border="0" src="http://feeds.wordpress.com/1.0/stumble/tbeernot.wordpress.com/44/" /></a> <a rel="nofollow" href="http://feeds.wordpress.com/1.0/godigg/tbeernot.wordpress.com/44/"><img alt="" border="0" src="http://feeds.wordpress.com/1.0/digg/tbeernot.wordpress.com/44/" /></a> <a rel="nofollow" href="http://feeds.wordpress.com/1.0/goreddit/tbeernot.wordpress.com/44/"><img alt="" border="0" src="http://feeds.wordpress.com/1.0/reddit/tbeernot.wordpress.com/44/" /></a> <img alt="" border="0" src="http://stats.wordpress.com/b.gif?host=tbeernot.wordpress.com&amp;blog=19658808&amp;post=44&amp;subd=tbeernot&amp;ref=&amp;feed=1" width="1" height="1" />]]></content:encoded>
			<wfw:commentRss>http://tbeernot.wordpress.com/2011/03/11/javafx-2-0-ea-and-miglayout/feed/</wfw:commentRss>
		<slash:comments>8</slash:comments>
	
		<media:content url="http://0.gravatar.com/avatar/824bd6d211a980b29b2dac9724d4815d?s=96&#38;d=identicon&#38;r=G" medium="image">
			<media:title type="html">tbeernot</media:title>
		</media:content>

		<media:content url="http://tbeernot.files.wordpress.com/2011/03/test12.png" medium="image">
			<media:title type="html">JavaFXTest1</media:title>
		</media:content>

		<media:content url="http://tbeernot.files.wordpress.com/2011/03/test1d1.png" medium="image">
			<media:title type="html">JavaFXTest1Debug</media:title>
		</media:content>

		<media:content url="http://tbeernot.files.wordpress.com/2011/03/test4.png" medium="image">
			<media:title type="html">JavaFXTest4</media:title>
		</media:content>

		<media:content url="http://tbeernot.files.wordpress.com/2011/03/test3.png" medium="image">
			<media:title type="html">Test3</media:title>
		</media:content>
	</item>
	</channel>
</rss>
