<?xml version='1.0' encoding='UTF-8'?><?xml-stylesheet href="http://www.blogger.com/styles/atom.css" type="text/css"?><feed xmlns='http://www.w3.org/2005/Atom' xmlns:openSearch='http://a9.com/-/spec/opensearchrss/1.0/' xmlns:georss='http://www.georss.org/georss' xmlns:gd='http://schemas.google.com/g/2005' xmlns:thr='http://purl.org/syndication/thread/1.0'><id>tag:blogger.com,1999:blog-7836204352369514180</id><updated>2012-02-16T19:41:02.694+01:00</updated><category term='GIS'/><category term='uDig'/><category term='Google Maps'/><category term='m2eclipse'/><category term='JPA'/><category term='Declarative Services'/><category term='Antipatterns'/><category term='Hibernate'/><category term='dnsmasq'/><category term='JTS'/><category term='IPSec'/><category term='Aries'/><category term='OpenStreetMap'/><category term='VPN'/><category term='Babel'/><category term='Geotools'/><category term='reFit'/><category term='Roller'/><category term='Equinox'/><category term='m2e'/><category term='Wicket'/><category term='JAXB'/><category term='Java EE 6'/><category term='Fit'/><category term='JMS'/><category term='CDI'/><category term='Camel'/><category term='Spring'/><category term='JUnit'/><category term='Resin'/><category term='Forms'/><category term='jeeunit'/><category term='EC2'/><category term='DataNucleus'/><category term='JUMP'/><category term='VisualVM'/><category term='I18n'/><category term='JBoss'/><category term='Eclipselink'/><category term='Java3D'/><category term='OSGi'/><category term='MySQL'/><category term='xjc'/><category term='GeoAPI'/><category term='OPS4J'/><category term='Localization'/><category term='ActiveMQ'/><category term='Logging'/><category term='XVisitor'/><category term='XML'/><category term='Anaconda'/><category term='Fun'/><category term='Java'/><category term='slf4j'/><category term='jstatd'/><category term='Mojo'/><category term='JDBC'/><category term='Remoting'/><category term='Interfaces'/><category term='strongswan'/><category term='Tomcat'/><category term='Nexus'/><category term='OpenJPA'/><category term='Firefox'/><category term='Jenkins'/><category term='Lingo'/><category term='Maven'/><category term='NDS'/><category term='Linux'/><category term='Eclipse'/><category term='Integration Tests'/><category term='SLD'/><category term='Dependencies'/><category term='OpenWebBeans'/><category term='Ubuntu'/><category term='Glassfish'/><category term='Metrics'/><category term='Weld'/><category term='SWT'/><category term='Pax Exam'/><title type='text'>Around the World in Java</title><subtitle type='html'></subtitle><link rel='http://schemas.google.com/g/2005#feed' type='application/atom+xml' href='http://hwellmann.blogspot.com/feeds/posts/default'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/7836204352369514180/posts/default?max-results=100'/><link rel='alternate' type='text/html' href='http://hwellmann.blogspot.com/'/><link rel='hub' href='http://pubsubhubbub.appspot.com/'/><author><name>Harald Wellmann</name><uri>http://www.blogger.com/profile/08039976160321882828</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='16' height='16' src='http://img2.blogblog.com/img/b16-rounded.gif'/></author><generator version='7.00' uri='http://www.blogger.com'>Blogger</generator><openSearch:totalResults>69</openSearch:totalResults><openSearch:startIndex>1</openSearch:startIndex><openSearch:itemsPerPage>100</openSearch:itemsPerPage><entry><id>tag:blogger.com,1999:blog-7836204352369514180.post-572182236505560713</id><published>2012-01-25T22:17:00.000+01:00</published><updated>2012-01-25T23:43:57.317+01:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='Pax Exam'/><category scheme='http://www.blogger.com/atom/ns#' term='OSGi'/><category scheme='http://www.blogger.com/atom/ns#' term='OPS4J'/><category scheme='http://www.blogger.com/atom/ns#' term='Resin'/><category scheme='http://www.blogger.com/atom/ns#' term='jeeunit'/><category scheme='http://www.blogger.com/atom/ns#' term='Weld'/><category scheme='http://www.blogger.com/atom/ns#' term='JBoss'/><category scheme='http://www.blogger.com/atom/ns#' term='Spring'/><category scheme='http://www.blogger.com/atom/ns#' term='Glassfish'/><category scheme='http://www.blogger.com/atom/ns#' term='Tomcat'/><category scheme='http://www.blogger.com/atom/ns#' term='CDI'/><category scheme='http://www.blogger.com/atom/ns#' term='Java EE 6'/><title type='text'>Integration Testing for JBoss AS7, Tomcat and Weld SE</title><content type='html'>Initially, the &lt;a href="http://code.google.com/p/jeeunit/"&gt;jeeunit&lt;/a&gt; Integration Testing framework was exclusively focused on Java EE 6, supporting GlassFish 3.x, which was the only Java EE 6 compliant server at that time. Support for Resin 4.x has been added in subsequent releases. &lt;br /&gt;&lt;br /&gt;With the current release 0.9.1, jeeunit supports JBoss AS 7, as well as alternative containers and injection methods beyond the scope of Java EE 6. You can now run jeeunit tests on Tomcat 6 and 7 and Weld SE containers.&lt;br /&gt;&lt;br /&gt;Tomcat can be combined either with Spring 3.1 or with CDI (Weld Servlet) to inject dependencies into jeeunit tests.&lt;br /&gt;&lt;br /&gt;And there's more to come: While jeeunit will continue a life of its own for a while, I'm planning to merge it step by step into &lt;a href="http://team.ops4j.org/wiki/display/paxexam/"&gt;Pax Exam&lt;/a&gt;, the OSGi testing framework of the &lt;a href="http://team.ops4j.org"&gt;OPS4J&lt;/a&gt; community.&lt;br /&gt;&lt;br /&gt;Pax Exam and jeeunit both implement an in-container testing approach - while Pax Exam focuses on OSGi alone, jeeunit now supports various other containers, but no OSGi at all. &lt;br /&gt;&lt;br /&gt;The Pax Exam/jeeunit merger opens interesting perspectives for hybrid applications, i.e. enterprise applications composed of traditional WARs and OSGi bundles. GlassFish 3.x supports this hybrid application model, implementing a subset of the OSGi Enterprise specifications. &lt;br /&gt;&lt;br /&gt;For Pax Exam, the road towards the next major release 3.0.0 will be marked by a sequence of milestone releases, each of which is to incoporate a new container adapted from jeeunit.&lt;br /&gt;&lt;br /&gt;A Pax Exam GlassFish Test Container is the goal of the first proof-of-concept milestone 3.0.0.M1. This is work in progress on a dedicated branch &lt;a href="https://github.com/ops4j/org.ops4j.pax.exam2/tree/exam3-milestones"&gt;exam3-milestones&lt;/a&gt; in the Pax Exam GitHub repository.&lt;br /&gt;&lt;br /&gt;Stay tuned...&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/7836204352369514180-572182236505560713?l=hwellmann.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://hwellmann.blogspot.com/feeds/572182236505560713/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=7836204352369514180&amp;postID=572182236505560713' title='2 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/7836204352369514180/posts/default/572182236505560713'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/7836204352369514180/posts/default/572182236505560713'/><link rel='alternate' type='text/html' href='http://hwellmann.blogspot.com/2012/01/integration-testing-for-jboss-as7.html' title='Integration Testing for JBoss AS7, Tomcat and Weld SE'/><author><name>Harald Wellmann</name><uri>http://www.blogger.com/profile/08039976160321882828</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='16' height='16' src='http://img2.blogblog.com/img/b16-rounded.gif'/></author><thr:total>2</thr:total></entry><entry><id>tag:blogger.com,1999:blog-7836204352369514180.post-1563153977380712980</id><published>2012-01-03T19:21:00.000+01:00</published><updated>2012-01-03T19:24:46.871+01:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='jstatd'/><category scheme='http://www.blogger.com/atom/ns#' term='VisualVM'/><title type='text'>Troubleshooting VisualVM Remote Connections</title><content type='html'>I was trying to use VisualVM to monitor the memory usage of a build job on our build server. According to the &lt;a href="http://docs.oracle.com/javase/6/docs/technotes/guides/visualvm/applications_remote.html"&gt;documentation&lt;/a&gt;, this should require nothing but a &lt;a href="http://docs.oracle.com/javase/6/docs/technotes/tools/share/jstatd.html"&gt;jstatd&lt;/a&gt; daemon running on the remote machine. &lt;br /&gt;&lt;br /&gt;For some reason, I could not see any remote applications in my local VisualVM. It was not a port issue, all the required ports were reachable via telnet.&lt;br /&gt;&lt;br /&gt;Googling around, &lt;a href="http://hillert.blogspot.com/2010/01/remote-profiling-of-jboss-using.html"&gt;this article&lt;/a&gt; finally gave my the important clue: Our network does not have consistent DNS names, so I had to connect to the remote machine via IP address. Setting the &lt;code&gt;java.rmi.server.hostname&lt;/code&gt; property for &lt;code&gt;jstatd&lt;/code&gt; to the IP address solved the problem.&lt;br /&gt;&lt;br /&gt;&lt;h3&gt;Summary&lt;/h3&gt;&lt;br /&gt;&lt;h4&gt;On the remote machine&lt;/h4&gt;&lt;b&gt;Create policy file for jstatd&lt;/b&gt;&lt;br /&gt;&lt;br /&gt;&lt;pre&gt;grant codebase "file:${java.home}/../lib/tools.jar" {&lt;br /&gt;    permission java.security.AllPermission;&lt;br /&gt;};&lt;br /&gt;&lt;/pre&gt;&lt;br /&gt;&lt;b&gt;Start jstatd with this hostname file and the IP address as hostname&lt;/b&gt;&lt;br /&gt;&lt;br /&gt;&lt;pre&gt;jstatd -J-Djava.security.policy=jstatd.all.policy -J-Djava.rmi.server.hostname=192.168.0.123&lt;br /&gt;&lt;/pre&gt;&lt;br /&gt;&lt;h4&gt;On the local machine&lt;/h4&gt;Start &lt;code&gt;jvisualvm&lt;/code&gt; and add a Remote Host with the given IP address. A jstatd connection will be established by default. You should now see your remote applications.&lt;br /&gt;&lt;br /&gt;&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/7836204352369514180-1563153977380712980?l=hwellmann.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://hwellmann.blogspot.com/feeds/1563153977380712980/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=7836204352369514180&amp;postID=1563153977380712980' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/7836204352369514180/posts/default/1563153977380712980'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/7836204352369514180/posts/default/1563153977380712980'/><link rel='alternate' type='text/html' href='http://hwellmann.blogspot.com/2012/01/troubleshooting-visualvm-remote.html' title='Troubleshooting VisualVM Remote Connections'/><author><name>Harald Wellmann</name><uri>http://www.blogger.com/profile/08039976160321882828</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='16' height='16' src='http://img2.blogblog.com/img/b16-rounded.gif'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-7836204352369514180.post-2166042825034768155</id><published>2011-12-21T11:01:00.000+01:00</published><updated>2011-12-21T19:47:06.404+01:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='MySQL'/><category scheme='http://www.blogger.com/atom/ns#' term='Integration Tests'/><category scheme='http://www.blogger.com/atom/ns#' term='Spring'/><category scheme='http://www.blogger.com/atom/ns#' term='JUnit'/><title type='text'>Spring Integration Tests with Real Transactions</title><content type='html'>Spring's Test Context has a &lt;code&gt;@Transactional&lt;/code&gt; annotation for wrapping tests in a transaction started and rolled back by the test container, to keep the tests from modifying the database. This is just what you need for deterministic, repeatable database tests.&lt;br /&gt;&lt;br /&gt;On the other hand, due to this approach, the transaction boundaries in your test system differ from the ones in your production system, which can lead to errors in production which were never noticed in your tests suites.&lt;br /&gt;&lt;br /&gt;I wouldn't go as far as saying that transactional tests should be &lt;a href="http://www.javacodegeeks.com/2011/12/spring-pitfalls-transactional-tests.html"&gt;considered  harmful&lt;/a&gt;, but at least you should be aware of the side effects which may or may not be harmless in your specific use case.&lt;br /&gt;&lt;br /&gt;For tests with real transactions, you need to take care of cleaning up the database yourself.&lt;br /&gt;&lt;br /&gt;&lt;a href="http://kentbeck.github.com/junit/javadoc/latest/org/junit/Rule.html"&gt;JUnit rules&lt;/a&gt; are a neat way of doing this. Here is an example:&lt;br /&gt;&lt;a name='more'&gt;&lt;/a&gt;&lt;br /&gt;&lt;br /&gt;&lt;h3&gt;Using the CleanDatabaseRule&lt;/h3&gt;&lt;br /&gt;&lt;pre class="Java" name="code"&gt;@RunWith(SpringJUnit4ClassRunner.class) &lt;br /&gt;@ContextConfiguration("/META-INF/spring/test-context.xml") &lt;br /&gt;public class RealTransactionTest { &lt;br /&gt;&lt;br /&gt;    @Rule &lt;br /&gt;    @Inject &lt;br /&gt;    public CleanDatabaseRule cleanDatabase; &lt;br /&gt;&lt;br /&gt;    @Inject&lt;br /&gt;    private UserDao userDao;&lt;br /&gt;&lt;br /&gt;    @Test &lt;br /&gt;    public void testFindUsers() { &lt;br /&gt;        userDao.createUsers("wilma", secret); &lt;br /&gt;        assertThat(userDao.findAllUsers().size(), is(1));&lt;br /&gt;    } &lt;br /&gt;} &lt;br /&gt;&lt;/pre&gt;&lt;br /&gt;This test class has the usual &lt;code&gt;@RunWith&lt;/code&gt; and &lt;code&gt;@ContextConfiguration&lt;/code&gt; annotations, to enable the Spring Test Context, but the &lt;code&gt;@Transactional&lt;/code&gt; annotation is missing&lt;br /&gt;&lt;br /&gt;The &lt;code&gt;CleanDatabaseRule&lt;/code&gt; is marked with &lt;code&gt;@Rule&lt;/code&gt;. JUnit requires all rule members to be public. Given that our rule internally works with a persistence unit to be injected by Spring, the rule itself is configured as a singleton Spring bean to be injected into our test class.&lt;br /&gt;&lt;br /&gt;This rule takes care of deleting all database content before and after each test method.&lt;br /&gt;&lt;br /&gt;&lt;h3&gt;CleanDatabaseRule Implementation&lt;/h3&gt;&lt;br /&gt;Our &lt;code&gt;CleanDatabaseRule&lt;/code&gt; extends JUnit's &lt;code&gt;ExternalResourceRule&lt;/code&gt; which has &lt;code&gt;before()&lt;/code&gt; and &lt;code&gt;after()&lt;/code&gt; methods for dealing with a given external resource (the database in our case) before and after running a test method.&lt;br /&gt;&lt;br /&gt;The level of cleanup performed by this rule is up to you: you can drop the database and create a new one, you can restore a given database dump, or simply truncate all tables, which is what I'm doing here.&lt;br /&gt;&lt;br /&gt;The following example uses MySQL syntax to disable all foreign keys before deleting the tables:&lt;br /&gt;&lt;br /&gt;&lt;pre class="Java" name="code"&gt;public class CleanDatabaseRule extends ExternalResource { &lt;br /&gt;&lt;br /&gt;    @PersistenceUnit &lt;br /&gt;    private EntityManagerFactory emf; &lt;br /&gt;&lt;br /&gt;&lt;br /&gt;    @Override &lt;br /&gt;    protected void before() { &lt;br /&gt;        EntityManager em = emf.createEntityManager(); &lt;br /&gt;        em.getTransaction().begin(); &lt;br /&gt;&lt;br /&gt;        // disable foreign keys&lt;br /&gt;        em.createNativeQuery("SET FOREIGN_KEY_CHECKS = 0").executeUpdate(); &lt;br /&gt;        truncateTables(em); &lt;br /&gt;&lt;br /&gt;        // reenable foreign keys &lt;br /&gt;        em.createNativeQuery("SET FOREIGN_KEY_CHECKS = 1").executeUpdate(); &lt;br /&gt;&lt;br /&gt;        em.getTransaction().commit(); &lt;br /&gt;   }&lt;br /&gt;&lt;br /&gt;    @Override &lt;br /&gt;    protected void after() { &lt;br /&gt;        before();&lt;br /&gt;    }&lt;br /&gt;} &lt;br /&gt;&lt;/pre&gt;&lt;br /&gt;Note that we're injecting an &lt;code&gt;EntityManagerFactory&lt;/code&gt; via &lt;code&gt;@PersistenceUnit&lt;/code&gt; instead of the usual &lt;code&gt;EntityManager&lt;/code&gt; This is because the  entity managers injected by Spring do not permit manual transactions. Using an &lt;code&gt;EntityManagerFactory&lt;/code&gt;, we can create our own &lt;code&gt;EntityManager&lt;/code&gt; and control or own transactions. &lt;br /&gt;&lt;br /&gt;In a database schema with lots of foreign key constraints, it is useful to disable them while cleaning up, to avoid the headache of having to delete tables in the correct order.&lt;br /&gt;&lt;br /&gt;The &lt;code&gt;truncateTables()&lt;/code&gt; method is left as an exercise. :-)&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/7836204352369514180-2166042825034768155?l=hwellmann.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://hwellmann.blogspot.com/feeds/2166042825034768155/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=7836204352369514180&amp;postID=2166042825034768155' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/7836204352369514180/posts/default/2166042825034768155'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/7836204352369514180/posts/default/2166042825034768155'/><link rel='alternate' type='text/html' href='http://hwellmann.blogspot.com/2011/12/spring-integration-tests-with-real.html' title='Spring Integration Tests with Real Transactions'/><author><name>Harald Wellmann</name><uri>http://www.blogger.com/profile/08039976160321882828</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='16' height='16' src='http://img2.blogblog.com/img/b16-rounded.gif'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-7836204352369514180.post-7266816295708248602</id><published>2011-12-02T19:23:00.001+01:00</published><updated>2011-12-02T19:42:04.586+01:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='OPS4J'/><category scheme='http://www.blogger.com/atom/ns#' term='JAXB'/><category scheme='http://www.blogger.com/atom/ns#' term='XVisitor'/><category scheme='http://www.blogger.com/atom/ns#' term='xjc'/><title type='text'>XVisitor: Visitor Pattern for JAXB</title><content type='html'>&lt;a href="http://team.ops4j.org/wiki/display/XVISITOR/"&gt;XVisitor&lt;/a&gt; is a plugin for the &lt;a href="http://download.oracle.com/javase/6/docs/technotes/tools/share/xjc.html"&gt;xjc&lt;/a&gt; code generator to enrich the &lt;a href="http://jaxb.java.net/guide/"&gt;JAXB&lt;/a&gt; model generated from an XML schema so that users can work with the Visitor pattern on this model.&lt;br /&gt;&lt;br /&gt;&lt;a name='more'&gt;&lt;/a&gt;Working with large XML documents is a significant part of my job at the moment, and I've found that both JAXB and the Visitor pattern provide useful type-safe abstractions compared to working with DOM and XPath only. This was the motivation for creating XVisitor as an open source project with an Apache License.&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;XVisitor is hosted by the &lt;a href="http://team.ops4j.org/wiki/display/ops4j/"&gt;OPS4J&lt;/a&gt; community, which offers first class infrastructure for Apache-licensed Java projects, including Confluence, GitHub, Hudson, JIRA and Maven Central releases.&lt;br /&gt;&lt;br /&gt;For more details about XVisitor, check out the &lt;a href="http://team.ops4j.org/wiki/display/XVISITOR/"&gt;wiki&lt;/a&gt;.&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/7836204352369514180-7266816295708248602?l=hwellmann.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://hwellmann.blogspot.com/feeds/7266816295708248602/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=7836204352369514180&amp;postID=7266816295708248602' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/7836204352369514180/posts/default/7266816295708248602'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/7836204352369514180/posts/default/7266816295708248602'/><link rel='alternate' type='text/html' href='http://hwellmann.blogspot.com/2011/12/xvisitor-visitor-pattern-for-jaxb.html' title='XVisitor: Visitor Pattern for JAXB'/><author><name>Harald Wellmann</name><uri>http://www.blogger.com/profile/08039976160321882828</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='16' height='16' src='http://img2.blogblog.com/img/b16-rounded.gif'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-7836204352369514180.post-568795938143815047</id><published>2011-11-16T20:51:00.001+01:00</published><updated>2011-11-16T21:08:30.740+01:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='Linux'/><category scheme='http://www.blogger.com/atom/ns#' term='Eclipse'/><category scheme='http://www.blogger.com/atom/ns#' term='Ubuntu'/><title type='text'>Eclipse Performance on KDE and Ubuntu 11.10</title><content type='html'>If you suffer from poor graphics performance when using Eclipse under KDE, especially when scrolling large trees, check your GTK+ Style.&lt;br /&gt;&lt;br /&gt;After changing the style from oxygen-gtk to QtCurve, my Eclipse is now running on steroids.&lt;br /&gt;&lt;br /&gt;I'm using Eclipse Indigo 3.7.1 on Kubuntu 11.10 amd64 with Oracle JDK 1.6.0_26 and an NVIDIA GeForce 8400 GS graphics adapter. I never used to have any issues on Kubuntu 10.04 LTS which is still running smoothly on another partition of my disk.&lt;br /&gt;&lt;br /&gt;I had suspected the NVIDIA drivers, tried different JREs (including 32 bit versions) and Eclipse releases, none of which made a difference.&lt;br /&gt;&lt;br /&gt;Finally, changing various configuration options by trial and error, I found out that &lt;code&gt;oxygen-gtk&lt;/code&gt; seemed to be the cause.&lt;br /&gt;&lt;br /&gt;To optimize your installation, install the &lt;code&gt;qtcurve&lt;/code&gt; package, and select it in &lt;b&gt;K Menu | System Settings | Appearance | GTK+ Appearance | Widget Style&lt;/b&gt;. Then restart Eclipse and enjoy.&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/7836204352369514180-568795938143815047?l=hwellmann.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://hwellmann.blogspot.com/feeds/568795938143815047/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=7836204352369514180&amp;postID=568795938143815047' title='1 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/7836204352369514180/posts/default/568795938143815047'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/7836204352369514180/posts/default/568795938143815047'/><link rel='alternate' type='text/html' href='http://hwellmann.blogspot.com/2011/11/eclipse-performance-on-kde-and-ubuntu.html' title='Eclipse Performance on KDE and Ubuntu 11.10'/><author><name>Harald Wellmann</name><uri>http://www.blogger.com/profile/08039976160321882828</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='16' height='16' src='http://img2.blogblog.com/img/b16-rounded.gif'/></author><thr:total>1</thr:total></entry><entry><id>tag:blogger.com,1999:blog-7836204352369514180.post-8703080186542443951</id><published>2011-10-23T20:49:00.001+02:00</published><updated>2011-10-24T22:34:12.125+02:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='OpenJPA'/><category scheme='http://www.blogger.com/atom/ns#' term='Eclipse'/><category scheme='http://www.blogger.com/atom/ns#' term='JBoss'/><category scheme='http://www.blogger.com/atom/ns#' term='Glassfish'/><category scheme='http://www.blogger.com/atom/ns#' term='Hibernate'/><category scheme='http://www.blogger.com/atom/ns#' term='JPA'/><category scheme='http://www.blogger.com/atom/ns#' term='Java EE 6'/><title type='text'>JBoss AS 7: Catching up with Java EE 6</title><content type='html'>&lt;style type="text/css"&gt;table.content {  border-collapse: collapse;  border-width: thin;  border-style: solid;}table.content td, table.content th {  padding: 5px;  margin: 0px;  border-width: thin;  border-style: solid;}&lt;/style&gt;&lt;br /&gt;&lt;br /&gt;In my &lt;a href="http://hwellmann.blogspot.com/2011/06/java-ee-6-server-comparison.html"&gt;Java EE 6 server comparison&lt;/a&gt; of June 2011, JBoss AS 6.0.0 was not exactly the shining star, both in terms of performance and usability.&lt;br /&gt;&lt;br /&gt;The next major release JBoss AS 7, claiming to be &lt;i&gt;lightning fast&lt;/i&gt;, was published in July 2011, followed by two maintenance updates in August and September.&lt;br /&gt;&lt;br /&gt;Time to take another look at JBoss and check if it now compares more favourably to other servers.&lt;br /&gt;&lt;a name='more'&gt;&lt;/a&gt;&lt;br /&gt;This post is based on JBoss AS 7.0.2 (Full Profile) and the same real-world application which I had ported from Spring to Java EE 6 for the GlassFish/Resin/JBoss AS 6 comparison.&lt;br /&gt;&lt;br /&gt;With some minor modifications, I was able to deploy the same WAR on JBoss AS 7 and to repeat the measurements I did for JBoss AS 6. &lt;br /&gt;&lt;br /&gt;Compared to JBoss AS 6 which did not even offer a Getting Started Guide, the documentation of JBoss AS 7 has improved a lot, but there are still quite a few gaps to be closed. At any rate I found sufficient input for my experiments in the following two documents:&lt;br /&gt;&lt;br /&gt;&lt;ul&gt;&lt;li&gt;&lt;a href="https://docs.jboss.org/author/display/AS7/Getting+Started+Developing+Applications+Guide"&gt;Getting Started Developing Applications Guide&lt;/a&gt;&lt;/li&gt;&lt;li&gt;&lt;a href="https://docs.jboss.org/author/display/AS7/How+do+I+migrate+my+application+from+AS5+or+AS6+to+AS7Getting%20Started%20Developing%20Applications%20Guide"&gt;Migration Guide&lt;/a&gt;&lt;br /&gt;&lt;/li&gt;&lt;/ul&gt;&lt;br /&gt;&lt;h3&gt;Preparing the server&lt;/h3&gt;My application contains a JPA 2.0 persistence unit developed on Hibernate 3.6.x and MySQL 5.1, so first of all I had to configure the data source and the JDBC driver.&lt;br /&gt;&lt;br /&gt;To do so, I added this section to the main configuration file of JBoss AS 7 in &lt;code&gt;standalone/configuration/standalone.xml&lt;/code&gt;:&lt;br /&gt;&lt;br /&gt;&lt;pre class="Xml" name="code"&gt;&amp;lt;datasource jndi-name="jdbc/myapp" pool-name="myapp" enabled="true" jta="true" use-java-context="true" use-ccm="true"&amp;gt;&lt;br /&gt;    &amp;lt;connection-url&amp;gt;&lt;br /&gt;        jdbc:mysql://localhost/myapp&lt;br /&gt;    &amp;lt;/connection-url&amp;gt;&lt;br /&gt;    &amp;lt;driver-class&amp;gt;&lt;br /&gt;        com.mysql.jdbc.Driver&lt;br /&gt;    &amp;lt;/driver-class&amp;gt;&lt;br /&gt;    &amp;lt;driver&amp;gt;&lt;br /&gt;        mysql-connector-java-5.1.13.jar&lt;br /&gt;    &amp;lt;/driver&amp;gt;&lt;br /&gt;    &amp;lt;transaction-isolation&amp;gt;&lt;br /&gt;        TRANSACTION_READ_COMMITTED&lt;br /&gt;    &amp;lt;/transaction-isolation&amp;gt;&lt;br /&gt;    &amp;lt;pool&amp;gt;&lt;br /&gt;        &amp;lt;min-pool-size&amp;gt;&lt;br /&gt;            4&lt;br /&gt;        &amp;lt;/min-pool-size&amp;gt;&lt;br /&gt;        &amp;lt;max-pool-size&amp;gt;&lt;br /&gt;            30&lt;br /&gt;        &amp;lt;/max-pool-size&amp;gt;&lt;br /&gt;        &amp;lt;prefill&amp;gt;&lt;br /&gt;            true&lt;br /&gt;        &amp;lt;/prefill&amp;gt;&lt;br /&gt;        &amp;lt;use-strict-min&amp;gt;&lt;br /&gt;            false&lt;br /&gt;        &amp;lt;/use-strict-min&amp;gt;&lt;br /&gt;        &amp;lt;flush-strategy&amp;gt;&lt;br /&gt;            FailingConnectionOnly&lt;br /&gt;        &amp;lt;/flush-strategy&amp;gt;&lt;br /&gt;    &amp;lt;/pool&amp;gt;&lt;br /&gt;    &amp;lt;security&amp;gt;&lt;br /&gt;        &amp;lt;user-name&amp;gt;&lt;br /&gt;            MYUSER&lt;br /&gt;        &amp;lt;/user-name&amp;gt;&lt;br /&gt;        &amp;lt;password&amp;gt;&lt;br /&gt;            SECRET&lt;br /&gt;        &amp;lt;/password&amp;gt;&lt;br /&gt;    &amp;lt;/security&amp;gt;&lt;br /&gt;&amp;lt;/datasource&amp;gt;&lt;br /&gt;&amp;lt;drivers&amp;gt;&lt;br /&gt;    &amp;lt;driver name="mysql-connector-java-5.1.13.jar" module="com.mysql"/&amp;gt;&lt;br /&gt;&amp;lt;/drivers&amp;gt;&lt;br /&gt;&lt;/pre&gt;&lt;br /&gt;Then I copied both the JDBC driver &lt;code&gt;mysql-connector-java-5.1.13.jar&lt;/code&gt; and my application &lt;code&gt;myapp.war&lt;/code&gt; to &lt;code&gt;standalone/deployments/&lt;/code&gt; and started the server via&lt;br /&gt;&lt;br /&gt;&lt;pre name="code"&gt;bin/standalone.sh&lt;br /&gt;&lt;/pre&gt;&lt;br /&gt;&lt;h3&gt;Troubleshooting&lt;/h3&gt;&lt;br /&gt;Of course, this did not work out of the box. The first exception I had was&lt;br /&gt;&lt;br /&gt;&lt;pre name="code"&gt;java.lang.ClassCastException: org.dom4j.DocumentFactory cannot be cast to org.dom4j.DocumentFactory&lt;br /&gt;&lt;/pre&gt;&lt;br /&gt;This looked like a classloader conflict for dom4j. My WAR has a dom4j.jar in its WEB-INF/lib, but dom4j is also provided by JBoss as an transitive dependency of Hibernate. To resolve the conflict, I rebuilt my WAR without dom4j.&lt;br /&gt;&lt;br /&gt;The next exception was&lt;br /&gt;&lt;br /&gt;&lt;pre name="code"&gt;java.lang.ClassNotFoundException: com.sun.xml.bind.Locatable &lt;br /&gt;&lt;/pre&gt;&lt;br /&gt;My original application included jaxb-impl-2.2.2.jar, which I'd had to remove for JBoss AS 6, so I re-added this dependency to my WAR and redeployed it.&lt;br /&gt;&lt;br /&gt;JBoss AS 7 marks any failed deployment with a &lt;code&gt;foo.war.failed&lt;/code&gt; file in the deployment directory and will not attempt to redeploy the application until the marker file is deleted.&lt;br /&gt;&lt;br /&gt;After restarting the server, the next problem was a &lt;br /&gt;&lt;br /&gt;&lt;pre name="code"&gt;org.jboss.weld.exceptions.DeploymentException: WELD-001408 Unsatisfied dependencies for type [MyType] with qualifiers [@Default] &lt;br /&gt;at injection point [[field] @Inject private MyClient.myType]&lt;br /&gt;&lt;/pre&gt;&lt;br /&gt;This was confusing. I had &lt;code&gt;beans.xml&lt;/code&gt; files in all my application modules, and the same WAR did not cause any CDI exceptions on other servers. So I enabled DEBUG logging for Weld to find out what was going on by adding&lt;br /&gt;&lt;br /&gt;&lt;pre class="Xml" name="code"&gt;&amp;lt;logger category="org.jboss.weld"&amp;gt;&lt;br /&gt;    &amp;lt;level name="DEBUG"/&amp;gt;&lt;br /&gt;&amp;lt;/logger&amp;gt;&lt;br /&gt;&lt;/pre&gt;&lt;br /&gt;to the logging section of &lt;code&gt;standalone.xml&lt;/code&gt;. This did not have the desired effect. I also had to change the &lt;br /&gt;&lt;br /&gt;&lt;pre class="Xml" name="code"&gt;&amp;lt;level name="INFO"/&amp;gt;&lt;br /&gt;&lt;/pre&gt;&lt;br /&gt;child elements of the &lt;code&gt;console-handler&lt;/code&gt; and the &lt;code&gt;periodic-rotating-file-handler&lt;/code&gt; from &lt;code&gt;INFO&lt;/code&gt; to &lt;code&gt;ALL&lt;/code&gt;. (The &lt;a href="https://docs.jboss.org/author/display/AS7/Logging+configuration"&gt;Logging Configuration&lt;/a&gt; documentation does not mention this, but some additional information is hidden in the &lt;a href="https://docs.jboss.org/author/display/AS7/Getting+Started+Guide"&gt;Getting Started Guide&lt;/a&gt;, section &lt;i&gt;Configure Logging in JBoss Application Server 7&lt;/i&gt;.)&lt;br /&gt;&lt;br /&gt;Now the &lt;code&gt;DEBUG&lt;/code&gt; output from Weld revealed the cause of the problem:&lt;br /&gt;&lt;br /&gt;&lt;pre name="code"&gt;17:33:39,799 DEBUG [org.jboss.weld.ClassLoading] (MSC service thread 1-8) WELD-000119 Not generating any bean definitions &lt;br /&gt;from MyType because of underlying class loading error&lt;br /&gt;Caused by: java.lang.NoClassDefFoundError: Lorg/dom4j/Document;&lt;br /&gt;&lt;/pre&gt;&lt;br /&gt;Strange, dom4j had caused a classloader conflict at first, and now it was no longer visible at all? I had a closer look at &lt;a href="https://docs.jboss.org/author/display/AS7/Class+Loading+in+AS7"&gt;Class Loading in AS7&lt;/a&gt; to understand the background of this. &lt;br /&gt;&lt;br /&gt;In short, JBoss AS 7 has a module structure, and server modules are not visible to applications by default, unless they are imported or exported explicitly.&lt;br /&gt;&lt;br /&gt;Both dom4j and jaxb-impl are JBoss modules, so I re-deleted jaxb-impl and jaxb-api from my application and made the JBoss modules globally visible by adding the following to &lt;code&gt;standalone.xml&lt;/code&gt;:&lt;br /&gt;&lt;br /&gt;&lt;pre class="Xml" name="code"&gt;&amp;lt;subsystem xmlns="urn:jboss:domain:ee:1.0"&amp;gt;&lt;br /&gt;    &amp;lt;global-modules&amp;gt;&lt;br /&gt;        &amp;lt;module name="org.dom4j" slot="main"/&amp;gt;&lt;br /&gt;        &amp;lt;module name="com.sun.xml.bind" slot="main"/&amp;gt;&lt;br /&gt;    &amp;lt;/global-modules&amp;gt;&lt;br /&gt;&amp;lt;/subsystem&amp;gt;&lt;br /&gt;&lt;/pre&gt;&lt;br /&gt;(Global visibility is not the best solution, of course, but for this experiment I would rather modify the server configuration than add JBoss-specific manifest headers or deployment descriptors to my application WAR.)&lt;br /&gt;&lt;br /&gt;Finally, I had another ClassNotFoundException for an internal Xerces class from the JDK required by my application. (Yes, such a dependency is bad practice, but as I said above, I'm using a real-world application for these tests...)&lt;br /&gt;&lt;br /&gt;I made this class visible to my application by adding&lt;br /&gt;&lt;br /&gt;&lt;pre class="Xml" name="code"&gt;&amp;lt;path name="com/sun/org/apache/xerces/internal/impl/io"/&amp;gt;&lt;br /&gt;&lt;/pre&gt;&lt;br /&gt;to &lt;code&gt;modules/sun/jdk/main/module.xml&lt;/code&gt; - no idea if you are supposed to do it this way, but it works for me...&lt;br /&gt;&lt;br /&gt;Now at last I was able to deploy and run my application and take some measurements.&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;&lt;h3&gt;Performance measurements&lt;/h3&gt;&lt;br /&gt;The following table compares some performance indicators for JBoss AS 7.0.2, JBoss AS 6.0.0 and GlassFish 3.1.1. For JBoss AS 6, I did not repeat the measurements but simply copied the results of June 2011. For GlassFish, I had been working with a pre-release build at that time, so I've now re-run my tests with the official GlassFish 3.1.1 release.&lt;br /&gt;&lt;br /&gt;&lt;table class="content"&gt;&lt;tbody&gt;&lt;tr&gt;  &lt;th&gt;&lt;/th&gt;  &lt;th&gt;JBoss AS 7.0.2&lt;/th&gt;  &lt;th&gt;JBoss AS 6.0.0&lt;/th&gt;  &lt;th&gt;GlassFish 3.1.1&lt;/th&gt;  &lt;/tr&gt;&lt;tr&gt;  &lt;td&gt;Empty server startup time&lt;/td&gt;  &lt;td&gt;1.9 s&lt;/td&gt;  &lt;td&gt;12 s&lt;/td&gt;  &lt;td&gt;3.2 s&lt;/td&gt;  &lt;/tr&gt;&lt;tr&gt;  &lt;td&gt;Empty server heap memory&lt;/td&gt;  &lt;td&gt;10.5 MB&lt;/td&gt;  &lt;td&gt;100 MB&lt;/td&gt;  &lt;td&gt;26.5 MB&lt;/td&gt;  &lt;/tr&gt;&lt;tr&gt;  &lt;td&gt;Empty server PermGen memory&lt;/td&gt;  &lt;td&gt;36.3 MB&lt;/td&gt;  &lt;td&gt;70 MB&lt;/td&gt;  &lt;td&gt;28.4 MB&lt;/td&gt;  &lt;/tr&gt;&lt;tr&gt;  &lt;td&gt;MyApp deployment time&lt;/td&gt;  &lt;td&gt;5.8 s&lt;/td&gt;  &lt;td&gt;47 s&lt;/td&gt;  &lt;td&gt;13 s&lt;/td&gt;  &lt;/tr&gt;&lt;tr&gt;  &lt;td&gt;Server + MyApp restart time&lt;/td&gt;  &lt;td&gt;8 s&lt;/td&gt;  &lt;td&gt;30 s&lt;/td&gt;  &lt;td&gt;14.5 s&lt;/td&gt;  &lt;/tr&gt;&lt;tr&gt;  &lt;td&gt;Server + MyApp heap memory&lt;/td&gt;  &lt;td&gt;52.8 MB&lt;/td&gt;  &lt;td&gt;236 MB&lt;/td&gt;  &lt;td&gt;55.3 MB&lt;/td&gt;  &lt;/tr&gt;&lt;tr&gt;  &lt;td&gt;Server + MyApp PermGen memory&lt;/td&gt;  &lt;td&gt;80.9 MB&lt;/td&gt;  &lt;td&gt;175 MB&lt;/td&gt;  &lt;td&gt;84.5 MB&lt;/td&gt;  &lt;/tr&gt;&lt;tr&gt;  &lt;td&gt;MyApp redeployment time&lt;/td&gt;  &lt;td&gt;3.5 s&lt;/td&gt;  &lt;td&gt;30 s&lt;/td&gt;  &lt;td&gt;7 s&lt;/td&gt;  &lt;/tr&gt;&lt;/tbody&gt;&lt;/table&gt;&lt;br /&gt;All in all, there is an amazing improvement of performance and memory footprint in JBoss AS 7, compared to JBoss AS 6. JBoss AS 7 is now at a competitive level with Resin and Glassfish and actually outperforms Glassfish in almost all of these tests.&lt;br /&gt;&lt;br /&gt;I don't know if this indeed qualifies as &lt;i&gt;lightning fast&lt;/i&gt;, but it is now safe to say that JBoss AS 6 was blatantly fat and slow, as confirmed by its own successor.&lt;br /&gt;&lt;br /&gt;&lt;h3&gt;Redeployment&lt;/h3&gt;&lt;br /&gt;I tested redeploying my application by simply touching the WAR file in the &lt;code&gt;deployments&lt;/code&gt; directory and watching the memory usage via &lt;i&gt;jvisualvm&lt;/i&gt;.&lt;br /&gt;&lt;br /&gt;I could see the PermGen usage grow at a constant rate, and after a couple of redeployments, there was an OutOfMemoryError, so JBoss AS 7 appears to have a new classloader leak. (The same test did pass successfully on JBoss AS 6.)&lt;br /&gt;&lt;br /&gt;&lt;h3&gt;Eclipse Integration&lt;/h3&gt;&lt;br /&gt;In contrast to the drastic improvements of the server itself, I could find no significant progress with the Eclipse integration. I installed the JBoss AS Tools from &lt;a href="http://download.jboss.org/jbosstools/updates/development/indigo/"&gt;JBoss Tools 3.3.0.M3&lt;/a&gt; into a fresh copy of Eclipse Indigo 3.7.1 with m2e 1.0 and m2e-wtp 0.14.0.&lt;br /&gt;&lt;br /&gt;I was able to deploy my application directly from the workspace, but editing and saving a source file did not redeploy the application. An Incremental Publish did not help either. Only a Full Publish was sufficient to redeploy the application.&lt;br /&gt;&lt;br /&gt;This is a major productivity issue for Eclipse users. Redeploy-on-save works smoothly with the built-in Tomcat integration of Eclipse WTP, so something must be broken in JBoss AS Tools.&lt;br /&gt;&lt;br /&gt;&lt;h3&gt;JPA Providers&lt;/h3&gt;&lt;br /&gt;JBoss AS 7.0.2 comes bundled with Hibernate 4.0.0.CR2. This is a bad smell - an official product release should never contain any release candidates of upstream components, especially not for components originating from the same company. &lt;br /&gt;&lt;br /&gt;The good news is that my application which was developed on Hibernate 3.6.0 works without problems on this Hibernate 4.x release candidate.&lt;br /&gt;&lt;br /&gt;But the real bad news is that JBoss AS 7 does not currently support other persistence providers like Eclipselink, OpenJPA or DataNucleus (according to the &lt;a href="https://docs.jboss.org/author/display/AS7/JPA+Reference+Guide"&gt;JPA Reference Guide&lt;/a&gt;). With GlassFish and Resin, you can simply drop the JARs of your preferred provider and its dependencies in a designated folder of your server installation and edit your &lt;code&gt;persistence.xml&lt;/code&gt; to override the default provider of the server. &lt;br /&gt;&lt;br /&gt;JBoss AS 7 appears to require an adapter per persistence provider, which to me looks like an unfortunate and unnecessary design decision. &lt;br /&gt;&lt;br /&gt;At any rate, this lack of flexibility is a severe restriction. In most of my projects, I had to replace Hibernate by OpenJPA due to a number of bugs related to new JPA 2.0 features.&lt;br /&gt;&lt;br /&gt;&lt;h3&gt;Conclusion&lt;/h3&gt;&lt;br /&gt;Given the drastic performance improvements in JBoss AS 7, which was released only six months and a half after JBoss AS 6, I can only wonder why RedHat and the JBoss community ever spent any resources on an AS 6 release which clearly was not competitive, instead of focusing on AS 7.&lt;br /&gt;&lt;br /&gt;Anybody looking for a production-quality Java EE 6 server in the first half of 2011 was better off with GlassFish 3.1.1 or one of its pre-releases.&lt;br /&gt;&lt;br /&gt;With AS 7, JBoss is now back in the game, it is surprisingly lean and fast, and it even has the potential to take over the lead from GlassFish. &lt;br /&gt;&lt;br /&gt;But performance is not the only factor that counts. The documentation continues to be sketchy and far below the standard of JBoss AS 5.&lt;br /&gt;&lt;br /&gt;Different projects have different needs, but for me, the top-level performance of JBoss AS 7 is more than outweighed by classloader leaks,  productivity issues of the Eclipse integration and lack of support for JPA providers other than Hibernate.&lt;br /&gt;&lt;br /&gt;Each of these is currently a blocker for using JBoss AS 7 in production. GlassFish 3.x has taken more than a year to reach production quality. Let's see if JBoss AS 7.x can do the same &lt;em&gt;lightning fast&lt;/em&gt;.&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/7836204352369514180-8703080186542443951?l=hwellmann.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://hwellmann.blogspot.com/feeds/8703080186542443951/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=7836204352369514180&amp;postID=8703080186542443951' title='10 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/7836204352369514180/posts/default/8703080186542443951'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/7836204352369514180/posts/default/8703080186542443951'/><link rel='alternate' type='text/html' href='http://hwellmann.blogspot.com/2011/10/jboss-as-7-catching-up-with-java-ee-6.html' title='JBoss AS 7: Catching up with Java EE 6'/><author><name>Harald Wellmann</name><uri>http://www.blogger.com/profile/08039976160321882828</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='16' height='16' src='http://img2.blogblog.com/img/b16-rounded.gif'/></author><thr:total>10</thr:total></entry><entry><id>tag:blogger.com,1999:blog-7836204352369514180.post-153540885940890495</id><published>2011-08-29T23:41:00.000+02:00</published><updated>2011-08-29T23:41:12.125+02:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='m2eclipse'/><category scheme='http://www.blogger.com/atom/ns#' term='OpenJPA'/><category scheme='http://www.blogger.com/atom/ns#' term='JAXB'/><category scheme='http://www.blogger.com/atom/ns#' term='Eclipse'/><category scheme='http://www.blogger.com/atom/ns#' term='Maven'/><category scheme='http://www.blogger.com/atom/ns#' term='m2e'/><title type='text'>Eclipse Maven Integration Extensions</title><content type='html'>For me, the most important new feature in Eclipse 3.7.0 (Indigo) is the improved Maven Integration, formerly developed by Sonatype under the name of m2eclipse, now an official Eclipse subproject under the name of m2e.&lt;br /&gt;&lt;br /&gt;m2eclipse and Eclipse sometimes used to have different opinions on what was going on in the workspace, and &lt;em&gt;so we had to go through series of refresh/update  dependencies/update configuration/rebuild voodoo (or "m2eclipse dance"  as some called it) to get projects in a good state.&lt;/em&gt; (Quote from the m2e Wiki).&lt;br /&gt;&lt;br /&gt;m2e has a different approach. First of all, it complains when detecting a Maven plugin in one of your POMs that it cannot handle out of the box. m2e flags your POM with an error marker that will not go away until you tell m2e what do to about the unknown plugin. The easy way out is a Quick Fix to ignore the plugin, which means you'll have to run the corresponding Maven goal manually when you need it.&lt;br /&gt;&lt;br /&gt;However, when the Maven plugin in question generates source code or post-processes byte code, this is usually not sufficient - ideally, Eclipse and m2e should pick up the required build steps from your POM automatically.&lt;br /&gt;&lt;br /&gt;This issue is addressed by &lt;b&gt;m2e extensions&lt;/b&gt;, which provide the missing link between Eclipse project builders and Maven plugins. An m2e extension for a given Maven plugin not only invokes the required mojos but also informs Eclipse about new source or binary folders created by the mojos, so that Eclipse and Maven can stay in sync.&lt;br /&gt;&lt;br /&gt;My projects use a number of Maven plugins that are not supported by m2e out of the box, e.g. for &lt;b&gt;JAXB&lt;/b&gt; and &lt;b&gt;OpenJPA&lt;/b&gt;, so I started creating some custom extensions for these plugins, based on a &lt;a href="https://github.com/hwellmann/m2eclipse-extras/wiki"&gt;GitHub fork&lt;/a&gt; of the official m2e extensions from Sonatype. &lt;br /&gt;&lt;br /&gt;See the&lt;a href="https://github.com/hwellmann/m2eclipse-extras/wiki"&gt; wiki page&lt;/a&gt; at GitHub for more details. The GitHub project also contains an Eclipse &lt;a href="https://github.com/hwellmann/m2eclipse-extras/raw/master/p2/"&gt;update site&lt;/a&gt; (aka p2 repository) for installing the plugins. Time permitting, I'll try to make these extensions available via the Eclipse marketplace.&lt;br /&gt;&lt;br /&gt;For any fixes, additions or new extensions, feel free to send my pull requests.&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/7836204352369514180-153540885940890495?l=hwellmann.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://hwellmann.blogspot.com/feeds/153540885940890495/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=7836204352369514180&amp;postID=153540885940890495' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/7836204352369514180/posts/default/153540885940890495'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/7836204352369514180/posts/default/153540885940890495'/><link rel='alternate' type='text/html' href='http://hwellmann.blogspot.com/2011/08/eclipse-maven-integration-extensions.html' title='Eclipse Maven Integration Extensions'/><author><name>Harald Wellmann</name><uri>http://www.blogger.com/profile/08039976160321882828</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='16' height='16' src='http://img2.blogblog.com/img/b16-rounded.gif'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-7836204352369514180.post-8256602452250137047</id><published>2011-06-25T19:43:00.002+02:00</published><updated>2011-07-10T17:54:39.127+02:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='OSGi'/><category scheme='http://www.blogger.com/atom/ns#' term='Wicket'/><category scheme='http://www.blogger.com/atom/ns#' term='Aries'/><title type='text'>Wicket and OSGi</title><content type='html'>After playing around with the OSGi JPA and JTA components of &lt;a href="http://aries.apache.org/"&gt;Apache Aries&lt;/a&gt; for a while, it was only natural to try and add a web layer to my sample projects. The Aries samples all use plain old servlets and JSPs, so I wondered if &lt;a href="http://wicket.apache.org/"&gt;Wicket&lt;/a&gt; would work in this context.&lt;br /&gt;&lt;br /&gt;So far, I had only ever used Wicket in standard Java EE web applications, but I had noticed the Wicket JARs come with an OSGi manifest, so someone must have tried to use Wicket in OSGi before.&lt;br /&gt;&lt;br /&gt;&lt;a name='more'&gt;&lt;/a&gt;&lt;br /&gt;Then I noticed the ominous&lt;br /&gt;&lt;br /&gt;&lt;pre&gt;DynamicImport-Package: *&lt;br /&gt;&lt;/pre&gt;&lt;br /&gt;manifest header, which is not the best way of interacting with client code, and what's worse, Wicket does not even import its own static dependencies like org.slf4j, but relies on the catch-all dynamic import.&lt;br /&gt;&lt;br /&gt;A &lt;a href="http://apache-wicket.1842946.n4.nabble.com/Wicket-and-OSGi-tp3617698p3617698.html"&gt;discussion&lt;/a&gt; on the Wicket Users mailing list confirmed my suspicion that this had to be related to Wicket's page deserialization requiring to load classes from user bundles.&lt;br /&gt;&lt;br /&gt;Anyway, I had a feeling it shouldn't be too hard to make this work without dynamic imports. In addition, it would be nice to inject OSGi services into Wicket components, just like CDI or Spring beans.&lt;br /&gt;&lt;br /&gt;So I started coding, and by now, there is a first proof-of-concept sample using Wicket on top of Aries, Jetty, OpenJPA, Derby and Equinox. The &lt;a href="http://code.google.com/p/osgi-enterprise/source/browse/#hg/aries-pde"&gt;sample code&lt;/a&gt; is included in my &lt;a href="http://code.google.com/p/osgi-enterprise"&gt;OSGi Enterprise&lt;/a&gt; sandbox project at Google Code. &lt;a href="http://code.google.com/p/osgi-enterprise/wiki/WicketAndOsgi"&gt;More details&lt;/a&gt; can be found in the OSGi Enterprise wiki.&lt;br /&gt;&lt;br /&gt;&lt;b&gt;Update 10 Jul 2011:&lt;/b&gt; After some polishing, my Wicket/OSGi glue code has made it into the &lt;a href="http://wicketstuff.org/"&gt;Wicketstuff&lt;/a&gt; project - see the &lt;a href="https://github.com/wicketstuff/core/wiki/Osgi"&gt;OSGi Integration&lt;/a&gt; wiki page for more details. This subproject targets the Wicket 1.5 release and will automatically be integrated with the next release or release candidate of Wicketstuff.&lt;br /&gt;&lt;br /&gt;Snapshot artifacts are currently available from the &lt;a href="https://oss.sonatype.org/content/repositories/snapshots/org/wicketstuff/wicketstuff-osgi/1.5-SNAPSHOT/"&gt;Sonatype OSS repository&lt;/a&gt;.&lt;br /&gt;&lt;br /&gt;The first shot in the &lt;a href="http://code.google.com/p/osgi-enterprise"&gt;OSGi Enterprise&lt;/a&gt; project works with Wicket 1.4.x. &lt;br /&gt;&lt;br /&gt;wicket-osgi from Wicketstuff cannot be used with Wicket 1.4.x.&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/7836204352369514180-8256602452250137047?l=hwellmann.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://hwellmann.blogspot.com/feeds/8256602452250137047/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=7836204352369514180&amp;postID=8256602452250137047' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/7836204352369514180/posts/default/8256602452250137047'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/7836204352369514180/posts/default/8256602452250137047'/><link rel='alternate' type='text/html' href='http://hwellmann.blogspot.com/2011/06/wicket-and-osgi.html' title='Wicket and OSGi'/><author><name>Harald Wellmann</name><uri>http://www.blogger.com/profile/08039976160321882828</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='16' height='16' src='http://img2.blogblog.com/img/b16-rounded.gif'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-7836204352369514180.post-1309081836238580545</id><published>2011-06-07T18:58:00.001+02:00</published><updated>2011-06-07T19:12:10.045+02:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='Resin'/><category scheme='http://www.blogger.com/atom/ns#' term='Eclipse'/><category scheme='http://www.blogger.com/atom/ns#' term='JBoss'/><category scheme='http://www.blogger.com/atom/ns#' term='Glassfish'/><category scheme='http://www.blogger.com/atom/ns#' term='Java EE 6'/><title type='text'>Java EE 6 Server Comparison: Conclusion</title><content type='html'>&lt;h3&gt;Lessons Learned&lt;/h3&gt;&lt;br /&gt;&lt;b&gt;Portability is not just a Java EE marketing promise.&lt;/b&gt; My application now runs on three different Java EE 6 servers, using the same WAR file, without any compile-time configuration.&lt;br /&gt;&lt;br /&gt;&lt;b&gt;An application is not portable until it has been ported.&lt;/b&gt; Of course, this is true for any specification with different implementations, not just for Java EE. Each of the three servers helped me discovering incorrect API usage in my application that just happened to work on another server.&lt;br /&gt;&lt;br /&gt;&lt;b&gt;Certification is not reliable.&lt;/b&gt; My application hit at least one major specification violation in each of the three Java EE 6 certified servers. Thus, the test coverage in the Java EE TCKs must be insufficient. &lt;br /&gt;&lt;br /&gt;&lt;a name='more'&gt;&lt;/a&gt;&lt;br /&gt;A certification process for an open specification should be open. Implementations of the specification may be closed source, but the test suites (TCKs) should be open source, and the user community should have the chance to contribute new test cases.&lt;br /&gt;&lt;br /&gt;The next version of the Java Community Process is moving in the right direction, but if you read the proposal carefully, you will notice a lot of half-hearted may's and should's, which is not enough. TCKs shall be open, period.&lt;br /&gt;&lt;br /&gt;(Note: Most of the JCP site is currently unavailable, due to restructuring - I read JSR 348 a few days ago. Oracle, did you ever hear about high availability and Cool URLs don't change?)&lt;br /&gt;&lt;br /&gt;&lt;h3&gt;And the winner is...&lt;/h3&gt;&lt;br /&gt;Each of the three servers has its strong points and its weaknesses. &lt;br /&gt;&lt;br /&gt;Only &lt;b&gt;JBoss&lt;/b&gt; has an official release that is able to run my application (with a workaround). On the other hand, its memory footprint is enormous, the deployment speed is inacceptable and the weakest point is the lack of up-to-date documentation. The Eclipse integration is severely limited in not allowing to republish applications.&lt;br /&gt;&lt;br /&gt;&lt;b&gt;Resin&lt;/b&gt; has the smallest footprint by far, clearly in terms of memory, less clearly in terms of deployment speed, where Glassfish is close up and might scale better than Resin for larger applications due to Resin's code generation during deployment. Resin needs a few more releases to mature. Its Eclipse integration is too unstable for serious use.&lt;br /&gt;&lt;br /&gt;&lt;b&gt;Glassfish&lt;/b&gt; is the leader in end-to-end usability. Its ease of use and its excellent documentation are invaluable for promoting the benefits of Java EE 6, keeping the barrier low for newcomers.&lt;br /&gt;&lt;br /&gt;Its speed is excellent (though outrivalled by Resin), its memory footprint needs to be improved, but is still a lot smaller compared to JBoss. Important to note (though without any impact on my experiments) is the fact that Glassfish is the only one of the three certified for the Java EE 6 Full Profile.&lt;br /&gt;&lt;br /&gt;Compared to JBoss and Resin, Glassfish has the best Eclipse integration (but the standard Eclipse WTP Tomcat integration is still better).&lt;br /&gt;&lt;br /&gt;Glassfish needs to shift the balance from new features to stability. There has been no production quality 3.x release so far. Glassfish 3.1.1 is on its way, it has a chance of becoming the first &lt;i&gt;really&lt;/i&gt; stable release, and I'd rather wait for it a little longer to make sure that all major known bugs are fixed.&lt;br /&gt;&lt;br /&gt;Glassfish would benefit from quarterly maintenance releases and more transparency in community communications.&lt;br /&gt;&lt;br /&gt;All in all, if you ask me&lt;br /&gt;&lt;br /&gt;&lt;ul&gt;&lt;li&gt;Which server would you choose for an application to go live next week?&lt;/li&gt;&lt;li&gt;Which server would you choose for developing a new project to go live next year?&lt;/li&gt;&lt;/ul&gt;then my answer is Glassfish for both. And if I couldn't use Glassfish, I would choose JBoss for next week and Resin for next year.&lt;br /&gt;&lt;br /&gt;&lt;h3&gt;Executive Summary&lt;/h3&gt;&lt;br /&gt;&lt;i&gt;Glassfish is Business Class, JBoss is Baroque, Resin is Zen.&lt;/i&gt;&lt;br /&gt;&lt;br /&gt;&lt;h4&gt;Read the whole story&lt;/h4&gt;&lt;br /&gt;&lt;ul&gt;&lt;li&gt;&lt;a href="http://hwellmann.blogspot.com/2011/06/java-ee-6-server-comparison.html"&gt;Part 1: Introduction&lt;/a&gt;&lt;/li&gt;&lt;li&gt;&lt;a href="http://hwellmann.blogspot.com/2011/06/java-ee-6-server-comparison-glassfish.html"&gt;Part 2: Glassfish&lt;/a&gt;&lt;/li&gt;&lt;li&gt;&lt;a href="http://hwellmann.blogspot.com/2011/06/java-ee-6-server-comparison-jboss.html"&gt;Part 3: JBoss&lt;/a&gt;&lt;/li&gt;&lt;li&gt;&lt;a href="http://hwellmann.blogspot.com/2011/06/java-ee-6-server-comparison-resin.html"&gt;Part 4: Resin&lt;/a&gt;&lt;/li&gt;&lt;li&gt;&lt;a href="http://hwellmann.blogspot.com/2011/06/java-ee-6-server-comparison-conclusion.html"&gt;Part 5: Conclusion&lt;/a&gt;&lt;/li&gt;&lt;/ul&gt;&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/7836204352369514180-1309081836238580545?l=hwellmann.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://hwellmann.blogspot.com/feeds/1309081836238580545/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=7836204352369514180&amp;postID=1309081836238580545' title='12 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/7836204352369514180/posts/default/1309081836238580545'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/7836204352369514180/posts/default/1309081836238580545'/><link rel='alternate' type='text/html' href='http://hwellmann.blogspot.com/2011/06/java-ee-6-server-comparison-conclusion.html' title='Java EE 6 Server Comparison: Conclusion'/><author><name>Harald Wellmann</name><uri>http://www.blogger.com/profile/08039976160321882828</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='16' height='16' src='http://img2.blogblog.com/img/b16-rounded.gif'/></author><thr:total>12</thr:total></entry><entry><id>tag:blogger.com,1999:blog-7836204352369514180.post-8263433522060030780</id><published>2011-06-07T18:53:00.001+02:00</published><updated>2011-06-07T19:11:18.426+02:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='Resin'/><category scheme='http://www.blogger.com/atom/ns#' term='Eclipse'/><category scheme='http://www.blogger.com/atom/ns#' term='CDI'/><category scheme='http://www.blogger.com/atom/ns#' term='Java EE 6'/><title type='text'>Java EE 6 Server Comparison: Resin</title><content type='html'>The first time I read about Caucho Resin 4.x was last summer, when I was looking for alternative CDI implementations, i.e. other than Weld. Resin has its own CDI implementation named CanDI, and I was bold enough to give it a try, knowing that Resin 4.x was not yet Java EE 6 certified and probably not stable enough.&lt;br /&gt;&lt;br /&gt;I didn't get very far at that time, CanDI looked ok, but the JPA API was broken and &lt;code&gt;@Singleton @Startup&lt;/code&gt; beans did not work, so I left it at that and made a mental note to check back after the first stable release.&lt;br /&gt;&lt;br /&gt;&lt;a name='more'&gt;&lt;/a&gt;&lt;br /&gt;Now that Resin 4.0.17 passed the Java EE 6 Web Profile certification in May 2011, it's a good time to give it another try. &lt;br /&gt;&lt;br /&gt;Considering that Caucho focuses on the Web Profile and has no intention to support the Full Profile, you'd expect Resin to be more lightweight than Glassfish or JBoss. In fact,  Resin is amazingly small and easy to use, the perfect example to destroy common belief that Java Enterprise servers are heavyweight and slow.&lt;br /&gt;&lt;br /&gt;The Resin download package has 23 MB (compared to 44 MB for Glassfish Web Profile, 78 MB for Glassfish Full Profile, and 173 MB for JBoss).&lt;br /&gt;&lt;br /&gt;Resin has a very small number of third party dependencies. The largest part of Resin is a single &lt;code&gt;resin.jar&lt;/code&gt; of less than 11 MB, the rest is Eclipselink (JPA), Mojarra (JSF), Java Mail and a couple of Java EE API JARs. &lt;br /&gt;&lt;br /&gt;This fact is worth mentioning, not just as an achievement of the Resin development team, but also as a benefit for the application developer: The risk of a version conflict for a library used both by the application and the server is almost zero, given that Resin has little or no external dependencies.&lt;br /&gt;&lt;br /&gt;&lt;h3&gt;Preparing the server&lt;/h3&gt;&lt;br /&gt;To configure my data source, I added the MySQL JDBC driver to Resin's lib directory and then added the following section to &lt;code&gt;conf/resin.xml&lt;/code&gt;:&lt;br /&gt;&lt;br /&gt;&lt;pre class="Xml" name="code"&gt;&amp;lt;database&amp;gt;&lt;br /&gt;    &amp;lt;jndi-name&amp;gt;jdbc/tcm&amp;lt;/jndi-name&amp;gt;&lt;br /&gt;    &amp;lt;driver type="com.mysql.jdbc.jdbc2.optional.MysqlConnectionPoolDataSource"&amp;gt;&lt;br /&gt;      &amp;lt;url&amp;gt;jdbc:mysql://localhost/myapp&amp;lt;/url&amp;gt; &lt;br /&gt;      &amp;lt;user&amp;gt;myuser&amp;lt;/user&amp;gt;&lt;br /&gt;      &amp;lt;password&amp;gt;****&amp;lt;/password&amp;gt;&lt;br /&gt;    &amp;lt;/driver&amp;gt;&lt;br /&gt;    &amp;lt;prepared-statement-cache-size&amp;gt;8&amp;lt;/prepared-statement-cache-size&amp;gt;&lt;br /&gt;    &amp;lt;max-connections&amp;gt;20&amp;lt;/max-connections&amp;gt;&lt;br /&gt;    &amp;lt;max-idle-time&amp;gt;30s&amp;lt;/max-idle-time&amp;gt;&lt;br /&gt;  &amp;lt;/database&amp;gt;&lt;br /&gt;&lt;/pre&gt;&lt;br /&gt;Then I started the server from the command line:&lt;br /&gt;&lt;br /&gt;&lt;pre&gt;bin/resin.sh console&lt;br /&gt;&lt;/pre&gt;&lt;br /&gt;and copied my WAR to the &lt;code&gt;webapps&lt;/code&gt; directory for deployment.&lt;br /&gt;&lt;br /&gt;&lt;h3&gt;Troubleshooting&lt;/h3&gt;&lt;br /&gt;Resin's approach to proxy creation for EJBs and CDI beans is Java code generation and compilation at deployment time. In the current release 4.0.18, the EJB code generator is broken for some use cases with generic methods.&lt;br /&gt;&lt;br /&gt;After I &lt;a href="http://forum.caucho.com/showthread.php?t=27905"&gt;posted my problem&lt;/a&gt; in the Resin forum, the development team advised me to use the current snapshot which solved the problem at least partially, and for the remaining cases, I temporarily removed some generic parameters in a few source files of my application.&lt;br /&gt;&lt;br /&gt;For the rest of my experiments, I used the pre-4.0.19 snaphot version labelled resin-4.0.s110531.&lt;br /&gt;&lt;br /&gt;Besides the generic methods arguments, the code generator complained about a checked exception in a &lt;span style="font-family: &amp;quot;Courier New&amp;quot;,Courier,monospace;"&gt;@PostConstruct&lt;/span&gt; method, but it was right in doing so: the &lt;span style="font-family: &amp;quot;Courier New&amp;quot;,Courier,monospace;"&gt;PostConstruct&lt;/span&gt; Javadoc clearly states that methods with this annotation must not throw checked exceptions, so I wrapped my checked exception in an unchecked exception, and the problem was gone. (Glassfish and JBoss did not complain about the checked exception.)&lt;br /&gt;&lt;br /&gt;The only remaining problem was a version conflict for the SLF4J API. Resin includes &lt;code&gt;slf4j-1.6.1.jar&lt;/code&gt; in &lt;code&gt;webapp-jars&lt;/code&gt; whereas my application requires 1.5.11. I deleted the 1.6.1 version from &lt;code&gt;webapp-jars&lt;/code&gt; and added the Hibernate, Javassist and JAXB JARs I had needed to exclude from my WAR for JBoss.&lt;br /&gt;&lt;br /&gt;Other problems like EL in JSPs not working turned out to be a side effect of a broken Eclipse plugin version.&lt;br /&gt;&lt;br /&gt;&lt;h3&gt;Eclipse Integration&lt;/h3&gt;&lt;br /&gt;In fact, the Eclipse plugin was my biggest source of &lt;a href="http://forum.caucho.com/showthread.php?t=27915"&gt;troubles&lt;/a&gt; with Resin. The current release 4.0.16 from &lt;a href="http://caucho.com/eclipse/"&gt;Caucho's Update Site&lt;/a&gt; did not work at all in the default (i.e. WAR) deployment mode. After enabling directory-based deployment in the Server Runtime dialog, the plugin would deploy my application, but its update behaviour was a complete mystery to me. Sometimes it seemed to deploy out-dated versions of classes, including some classes I had already deleted.&lt;br /&gt;&lt;br /&gt;The WAR deployment has been fixed in the current 4.0.19 snapshot version of the Eclipse plugin which can be installed from the &lt;a href="http://caucho.com/eclipse-snapshot"&gt;Snapshot Update Site&lt;/a&gt;.&lt;br /&gt;&lt;br /&gt;After deleting the 4.0.16 version and installing the 4.0.19 snapshot, the Eclipse plugin finally started to work more or less reliably in the default mode. The directory mode continues to be broken, causing all sorts of mysterious side effects.&lt;br /&gt;&lt;br /&gt;With the default mode, there are still a number of issues:&lt;br /&gt;&lt;br /&gt;&lt;ul&gt;&lt;li&gt;Editing a source file of the top-level module redeploys the application as expected, editing a source of a dependent module does not. &lt;/li&gt;&lt;li&gt;Redeploying the application causes the EJB Proxies and JSPs to be regenerated and recompiled. For some reason, this process is much slower when running under the Eclipse plugin, compared to (re)deploying an application from the command line. Increasing MaxPermSize in the server launcher did not help.&lt;/li&gt;&lt;li&gt;After two or three redeployments from Eclipse, Resin dies with a PermGen size OutOfMemoryError.&lt;/li&gt;&lt;/ul&gt;From the command line, I was able to redeploy my application a couple of times without any apparent memory leaks.&lt;br /&gt;&lt;br /&gt;&lt;h3&gt;Performance Measurements&lt;/h3&gt;&lt;br /&gt;&lt;ul&gt;&lt;li&gt;Empty server startup time: 3.3 s&lt;/li&gt;&lt;li&gt;Empty server memory usage: 22 MB heap, 27 MB PermGen&lt;/li&gt;&lt;li&gt; MyApp deployment time: 8 s&lt;/li&gt;&lt;li&gt;Server + MyApp restart time: 9 s&lt;/li&gt;&lt;li&gt;Server + MyApp memory usage: 44 MB heap, 58 MB PermGen&lt;/li&gt;&lt;li&gt;MyApp redeployment time: 8 s&lt;/li&gt;&lt;li&gt;Server + MyApp startup time from Eclipse: 30 s&lt;/li&gt;&lt;li&gt;Server + MyApp memory usage from Eclipse: 245 MB heap, 124 MB PermGen&lt;/li&gt;&lt;li&gt;MyApp redeployment on Eclipse save: 25 s, heap reduced to 85 MB&lt;/li&gt;&lt;/ul&gt;&lt;br /&gt;It is strange that Resin works rather smoothly from the commandline and has no memory issues at all, while slowing down on code generation, using excessive amounts of memory and throwing PermGen exceptions in combination with the Eclipse plugin.&lt;br /&gt;&lt;br /&gt;&lt;h3&gt;Summary&lt;/h3&gt;&lt;br /&gt;Resin is easy to use and incredibly lightweight. The documentation is rather terse and not always up-to-date, but all in all usable. The Resin Forum was extremely helpful, my questions were answered quickly and some of the bugs I found during this investigation have already been fixed by the Caucho team in the meantime.&lt;br /&gt;&lt;br /&gt;It would be foolish to recommend any server for production use before having worked with it in a real project for at least a couple of months, but it is safe to say that Resin looks extremely promising and is fun to work with.&lt;br /&gt;&lt;br /&gt;The sore point at the moment is the Eclipse integration, which is currently not stable enough for day-to-day development, so this is a real blocker, unless you are happy using command line tools, some other IDE, or maybe some other server for development and Resin for testing and production only.&lt;br /&gt;&lt;br /&gt;Resin 4.0.x releases have been published once a month since February 2010, and if the team can keep up this pulse rate both for the server and the Eclipse plugin, I'm quite confident that Resin will be a first class Java EE 6 Web Profile platform within a few months.&lt;br /&gt;&lt;br /&gt;&lt;h4&gt;Read the whole story&lt;/h4&gt;&lt;br /&gt;&lt;ul&gt;&lt;li&gt;&lt;a href="http://hwellmann.blogspot.com/2011/06/java-ee-6-server-comparison.html"&gt;Part 1: Introduction&lt;/a&gt;&lt;/li&gt;&lt;li&gt;&lt;a href="http://hwellmann.blogspot.com/2011/06/java-ee-6-server-comparison-glassfish.html"&gt;Part 2: Glassfish&lt;/a&gt;&lt;/li&gt;&lt;li&gt;&lt;a href="http://hwellmann.blogspot.com/2011/06/java-ee-6-server-comparison-jboss.html"&gt;Part 3: JBoss&lt;/a&gt;&lt;/li&gt;&lt;li&gt;&lt;a href="http://hwellmann.blogspot.com/2011/06/java-ee-6-server-comparison-resin.html"&gt;Part 4: Resin&lt;/a&gt;&lt;/li&gt;&lt;li&gt;&lt;a href="http://hwellmann.blogspot.com/2011/06/java-ee-6-server-comparison-conclusion.html"&gt;Part 5: Conclusion&lt;/a&gt;&lt;/li&gt;&lt;/ul&gt;&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/7836204352369514180-8263433522060030780?l=hwellmann.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://hwellmann.blogspot.com/feeds/8263433522060030780/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=7836204352369514180&amp;postID=8263433522060030780' title='3 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/7836204352369514180/posts/default/8263433522060030780'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/7836204352369514180/posts/default/8263433522060030780'/><link rel='alternate' type='text/html' href='http://hwellmann.blogspot.com/2011/06/java-ee-6-server-comparison-resin.html' title='Java EE 6 Server Comparison: Resin'/><author><name>Harald Wellmann</name><uri>http://www.blogger.com/profile/08039976160321882828</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='16' height='16' src='http://img2.blogblog.com/img/b16-rounded.gif'/></author><thr:total>3</thr:total></entry><entry><id>tag:blogger.com,1999:blog-7836204352369514180.post-2548639517678926727</id><published>2011-06-07T18:46:00.001+02:00</published><updated>2011-06-07T19:10:26.462+02:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='Eclipse'/><category scheme='http://www.blogger.com/atom/ns#' term='JBoss'/><category scheme='http://www.blogger.com/atom/ns#' term='Java EE 6'/><title type='text'>Java EE 6 Server Comparison: JBoss</title><content type='html'>I never did any serious work with JBoss AS 5 or earlier versions. At the peak of my frustration with Glassfish last summer after the 3.0.1 release when CDI continued to be unusable, I knew that JBoss would be no help as it also included Weld, the main source of trouble. Besides, given the number of problems in released and certified Glassfish, I dreaded an even larger number of problems in an unreleased, uncertified and undocumented JBoss.&lt;br /&gt;&lt;br /&gt;When JBoss AS 6.0.0 was finally released late in December 2010, with surprisingly little marketing noise and community echo, I briefly had a look at the release and was disappointed to find out that it was still largely undocumented.&lt;br /&gt;&lt;br /&gt;&lt;a name='more'&gt;&lt;/a&gt;&lt;br /&gt;Five months later, there has been no maintenance release, and the documentation is not up-to-date, even the Getting Started Guide still refers to JBoss AS 5. &lt;br /&gt;&lt;br /&gt;Anyway, having read &lt;a href="http://blogs.oracle.com/arungupta/entry/which_java_ee_6_app"&gt;Arun Gupta's&lt;/a&gt; and &lt;a href="http://rollerweblogger.org/roller/entry/roller_5_and_jboss_6"&gt;Dave Johnson's&lt;/a&gt; summaries of their first steps with JBoss, I felt should be able to come to grips with it.&lt;br /&gt;&lt;br /&gt;&lt;h3&gt;Preparing the server&lt;/h3&gt;&lt;br /&gt;I copied the MySQL JDBC driver to &lt;span style="font-family: &amp;quot;Courier New&amp;quot;,Courier,monospace;"&gt;server/default/lib&lt;/span&gt;. To configure my datasource, I copied &lt;span style="font-family: &amp;quot;Courier New&amp;quot;,Courier,monospace;"&gt;docs/examples/jca/mysql-xa-ds.xml&lt;/span&gt; to &lt;span style="font-family: &amp;quot;Courier New&amp;quot;,Courier,monospace;"&gt;server/default/deploy&lt;/span&gt; and edited the copy. The most important and non-obvious changes are&lt;br /&gt;&lt;br /&gt;&lt;pre class="Xml" name="code"&gt;&amp;lt;jndi-name&amp;gt;jdbc/myapp&amp;lt;/jndi-name&amp;gt;&lt;br /&gt;&amp;lt;use-java-context&amp;gt;false&amp;lt;/use-java-context&amp;gt;&lt;br /&gt;&lt;/pre&gt;&lt;br /&gt;All the JBoss datasource examples use a simple JNDI name &lt;span style="font-family: &amp;quot;Courier New&amp;quot;,Courier,monospace;"&gt;foo&lt;/span&gt; and then include a reference&lt;br /&gt;&lt;br /&gt;&lt;pre class="Xml" name="code"&gt;&amp;lt;jta-data-source&amp;gt;java:/foo&amp;lt;/jta-data-source&amp;gt;&lt;br /&gt;&lt;/pre&gt;&lt;br /&gt;in &lt;span style="font-family: &amp;quot;Courier New&amp;quot;,Courier,monospace;"&gt;META-INF/persistence.xml&lt;/span&gt;. The problem is how to configure a data source with a cross-platform JNDI name that will work on Glassfish, JBoss and Resin alike.&lt;br /&gt;&lt;br /&gt;I tried using a &lt;span style="font-family: &amp;quot;Courier New&amp;quot;,Courier,monospace;"&gt;resource-ref-name&lt;/span&gt; indirection in my &lt;span style="font-family: &amp;quot;Courier New&amp;quot;,Courier,monospace;"&gt;web.xml&lt;/span&gt; combined with a container specific deployment descriptor, without success. Finally, I found this simple solution with the &lt;span style="font-family: &amp;quot;Courier New&amp;quot;,Courier,monospace;"&gt;use-java-context &lt;/span&gt;tag in &lt;a href="http://rollerweblogger.org/roller/entry/roller_5_and_jboss_6#comment-1296410237000"&gt;this blog comment&lt;/a&gt;.&lt;br /&gt;&lt;br /&gt;&lt;h3&gt;Running the application&lt;/h3&gt;&lt;br /&gt;To run my application on JBoss, I copied my WAR to &lt;span style="font-family: &amp;quot;Courier New&amp;quot;,Courier,monospace;"&gt;server/default/deploy&lt;/span&gt; and then started the server from the command line:&lt;br /&gt;&lt;br /&gt;&lt;pre&gt;bin/run.sh&lt;/pre&gt;&lt;br /&gt;&lt;h3&gt;Troubleshooting&lt;/h3&gt;&lt;br /&gt;At first, I all got was a flood of error messages. which I found hard to interpret.  For every problem I ran into, it was easy to find similar questions in the JBoss forums or on stackoverflow,  but most of the time either without adequate answers, or with solutions  referring to JBoss 4 or 5 that did not seem to apply to JBoss 6.&lt;br /&gt;&lt;br /&gt;The situation was not helped by the extreme verbosity of the console log  messages, and by a sluggish startup. Before starting to deploy my  application, or more likely, while scanning the WAR, JBoss takes a deep thought for about 20 seconds with CPU load &amp;gt; 100 %, printing no  message whatsoever.&lt;br /&gt;&lt;br /&gt;Anyway, most of the problems turned out to be caused by classloader conflicts, which I could solve by excluding a number of libraries from my WAR, but there remained an issue with JNDI lookup exceptions,  caused by a &lt;a href="https://issues.jboss.org/browse/JBAS-8818"&gt;known bug&lt;/a&gt; in JBoss: Injecting EJBs into the web layer with &lt;span style="font-family: &amp;quot;Courier New&amp;quot;,Courier,monospace;"&gt;@Inject&lt;/span&gt;  results in JNDI lookup exceptions, since JBoss starts the web container  before the EJB container by default.&lt;br /&gt;&lt;br /&gt;I could not use the producer method workaround mentioned in the JIRA issue, since my web component uses the CDI-to-Spring bridge and is not itself a CDI bean archive. My solution was to create a &lt;code&gt;ServletContextListener&lt;/code&gt; class which injects all required session beans with an old-school &lt;code&gt;@EJB&lt;/code&gt; annotation. This listener is configured to run before Spring's &lt;code&gt;ContextLoaderListener&lt;/code&gt;.&lt;br /&gt;&lt;br /&gt;JBoss also complained about an invalid XML namespace definition in my &lt;code&gt;web.xml&lt;/code&gt;, and it was right, the namespace was wrong - Glassfish and Resin did not seem to care.&lt;br /&gt;&lt;br /&gt;&lt;h3&gt;Classloader issues&lt;/h3&gt;&lt;br /&gt;Unlike Glassfish and Resin, JBoss adopts the Servlet Specification recommendation and does not use a parent-first strategy for class lookups. As a result, there were lots of &lt;span style="font-family: &amp;quot;Courier New&amp;quot;,Courier,monospace;"&gt;ClassCastExceptions&lt;/span&gt; for &lt;span style="font-family: &amp;quot;Courier New&amp;quot;,Courier,monospace;"&gt;org.hibernate.*&lt;/span&gt; or&lt;span style="font-family: &amp;quot;Courier New&amp;quot;,Courier,monospace;"&gt; javax.*&lt;/span&gt; classes included in my WAR. To get rid of these, I excluded all Hibernate, JAXB and Geronimo Spec libraries from my WAR by changing the scope in the Maven POM to &lt;code&gt;provided&lt;/code&gt;.&lt;br /&gt;&lt;br /&gt;As an alternative, I tried to force JBoss to do a parent-first lookup. The &lt;a href="http://docs.jboss.org/jbossas/docs/Administration_And_Configuration_Guide/5/html_single/index.html"&gt;Administration and Configuration Guide&lt;/a&gt; does not cover the subject, but following the instructions in an &lt;a href="http://phytodata.wordpress.com/2010/10/21/demystifying-the-jboss5-jboss-classloading-xml-file/"&gt;article on JBoss class loading&lt;/a&gt;, I added a configuration file &lt;span style="font-family: &amp;quot;Courier New&amp;quot;,Courier,monospace;"&gt;WEB-INF/jboss-classloading.xml&lt;/span&gt; to my WAR:&lt;br /&gt;&lt;br /&gt;&lt;pre&gt;&amp;lt;classloading xmlns="urn:jboss:classloading:1.0"&lt;br /&gt;       domain="myapp.war"&lt;br /&gt;       parent-first="true"&amp;gt;&lt;br /&gt;&amp;lt;/classloading&amp;gt;&lt;br /&gt;&lt;/pre&gt;&lt;br /&gt;This indeed had an effect on classloading, but only produced a new exception&lt;br /&gt;&lt;br /&gt;&lt;pre&gt;java.lang.NoSuchMethodError: org.objectweb.asm.ClassWriter.&lt;init&gt;(I)V&lt;/init&gt;&lt;br /&gt;&lt;/pre&gt;&lt;br /&gt;caused by an older version of &lt;span style="font-family: &amp;quot;Courier New&amp;quot;,Courier,monospace;"&gt;asm.jar&lt;/span&gt; used by JBoss which is incompatible to the version 3.1 required by my application.&lt;br /&gt;&lt;br /&gt;I did not try to upgrade the &lt;span style="font-family: &amp;quot;Courier New&amp;quot;,Courier,monospace;"&gt;asm.jar&lt;/span&gt; in the JBoss installation for fear of breaking the server, so I ended up excluding the relevant libraries from my WAR, and consequently I had to copy most of these libraries to the appropriate server library directory in Glassfish and Resin to make my WAR portable.&lt;br /&gt;&lt;br /&gt;Later, trying to redeploy my application, simply by running&lt;br /&gt;&lt;br /&gt;&lt;pre&gt;touch server/default/deploy/myapp.war&lt;br /&gt;&lt;/pre&gt;&lt;br /&gt;I ran into &lt;span style="font-family: &amp;quot;Courier New&amp;quot;,Courier,monospace;"&gt;OutOfMemoryErrors&lt;/span&gt;. A heap dump confirmed my suspicion that some classloaders did not get garbage collected. Taking a closer look with the Eclipse Memory Analyzer, I found a class &lt;span style="font-family: &amp;quot;Courier New&amp;quot;,Courier,monospace;"&gt;org.jboss.interceptor.util.InterceptionTypeRegistry&lt;/span&gt; holding an indirect reference to an obsolete class loader.&lt;br /&gt;&lt;br /&gt;Taking another look at my WAR, I noticed a &lt;span style="font-family: &amp;quot;Courier New&amp;quot;,Courier,monospace;"&gt;jboss-interceptor.jar&lt;/span&gt; including the &lt;span style="font-family: &amp;quot;Courier New&amp;quot;,Courier,monospace;"&gt;javax.interceptor &lt;/span&gt;package, a transitive dependency of the CDI-Spring-Bridge. After excluding this library from my WAR, I still had an &lt;span style="font-family: &amp;quot;Courier New&amp;quot;,Courier,monospace;"&gt;OutOfMemoryError&lt;/span&gt; on redeployment, but I could see in &lt;i&gt;jvisualvm&lt;/i&gt; that now at least some classes had been unloaded, so I edited &lt;span style="font-family: &amp;quot;Courier New&amp;quot;,Courier,monospace;"&gt;bin/run.conf&lt;/span&gt; to increase &lt;span style="font-family: &amp;quot;Courier New&amp;quot;,Courier,monospace;"&gt;MaxPermSize&lt;/span&gt; to 384MB and the heap size to 1GB. With this modification, I was able to redeploy my application multiple times in a row without any apparent classloader leaks.&lt;br /&gt;&lt;br /&gt;So while it is certainly not recommended to include another copy of &lt;span style="font-family: &amp;quot;Courier New&amp;quot;,Courier,monospace;"&gt;javax.interceptor&lt;/span&gt; in your WAR, this still leaves the question why JBoss loads classes from this package via the WAR classloader and not via its container classloader.&lt;br /&gt;&lt;br /&gt;&lt;h3&gt;The Web Profile&lt;/h3&gt;&lt;br /&gt;Unlike Glassfish with its two separate distributions for the Full Profile and the Web Profile, JBoss offers a single distribution including different server configurations, which can be selected by a command line option of the startup script.&lt;br /&gt;&lt;br /&gt;JBoss comes with 5 different server configurations. Surprisingly, none of them exactly matches the Web Profile. There is a configuration called &lt;span style="font-family: &amp;quot;Courier New&amp;quot;,Courier,monospace;"&gt;jbossweb-standalone&lt;/span&gt; which launches a web container but does not include CDI support.&lt;br /&gt;&lt;br /&gt;I used the &lt;span style="font-family: &amp;quot;Courier New&amp;quot;,Courier,monospace;"&gt;default&lt;/span&gt; configuration to launch my application. The &lt;span style="font-family: &amp;quot;Courier New&amp;quot;,Courier,monospace;"&gt;default&lt;/span&gt; configuration includes the Web Profile but also other services like JMS which are not part of the Web Profile.&lt;br /&gt;&lt;br /&gt;See &lt;a href="http://community.jboss.org/thread/161662"&gt;this thread&lt;/a&gt; in the JBoss Forum for a more detailed discussion.&lt;br /&gt;&lt;br /&gt;Having the JBoss command line options in mind, I once &lt;a href="http://www.java.net/node/704626?force=507"&gt;suggested in the Glassfish forum&lt;/a&gt; to let users select the desired profile in a similar way. It is now somewhat ironic to find out that JBoss doesn't really let you do that.&lt;br /&gt;&lt;br /&gt;&lt;h3&gt;Eclipse Integration&lt;/h3&gt;&lt;br /&gt;Quite some time ago, I made the mistake of installing the entire JBoss Tools set into what must have been Eclipse Galileo, only to find my workspace cluttered almost beyond recognition by tools and menus I had never intended to use.&lt;br /&gt;&lt;br /&gt;So this time I took care to only install JBoss AS Tools 2.2.0 from the &lt;a href="http://download.jboss.org/jbosstools/updates/stable/helios/"&gt;JBoss Helios Update Site&lt;/a&gt;. I was confused (but no longer surprised) by the feature description "Supports JBoss AS 4.x and 5.x". The plugin does support JBoss AS 6 also, at least to some extent.&lt;br /&gt;&lt;br /&gt;I was able to launch my application from the workspace using &lt;b&gt;Run on Server&lt;/b&gt;. The startup time was between 45-50 s, just the same as from the command line. There was no big difference in the heap size either.&lt;br /&gt;&lt;br /&gt;Editing and saving a source file of my top level project should have triggered a redeploy, but didn't. In the Server view, my application still had the status Synchronized. Clicking the Publish button had no effect. Even cleaning the top-level web project did not cause the application to be redeployed.&lt;br /&gt;&lt;br /&gt;I also tried reloading a page of my application in the browser, hoping that some hot swap magic might have updated my application without redeploying it.&lt;br /&gt;&lt;br /&gt;But no. Stopping and restarting the server seems to be the only way of publishing the current version from Eclipse, so this is at least a critical bug, if not a blocker.&lt;br /&gt;&lt;br /&gt;&lt;h3&gt;Performance Measurements&lt;/h3&gt;&lt;br /&gt;&lt;ul&gt;&lt;li&gt;Empty server startup time: 12 s&lt;/li&gt;&lt;li&gt;Empty server memory usage: 100 MB heap, 70 MB PermGen&lt;/li&gt;&lt;li&gt;MyApp deployment time: 30 s&lt;/li&gt;&lt;li&gt;Server + MyApp restart time: 47 s&lt;/li&gt;&lt;li&gt;Server + MyApp memory usage: 236 MB heap, 175 MB PermGen&lt;/li&gt;&lt;li&gt;MyApp redeployment time: 30 s&lt;/li&gt;&lt;li&gt;Server + MyApp startup time from Eclipse: 47 s&lt;/li&gt;&lt;li&gt;Server + MyApp memory usage from Eclipse: 258 MB heap, 181 MB PermGen&lt;/li&gt;&lt;li&gt;MyApp redeployment on Eclipse save: failed&lt;/li&gt;&lt;/ul&gt;&lt;br /&gt;&lt;h3&gt;Summary&lt;/h3&gt;&lt;br /&gt;JBoss has taken a long time to finally release a Java EE 6 server with JBoss AS 6.0.0, but quality is worth waiting for, and the server itself appears mature and stable.&lt;br /&gt;&lt;br /&gt;This is really the best thing I can say about JBoss. Otherwise, JBoss is too fat, too slow, too verbose, poorly documented and simply not enjoyable to work with. &lt;br /&gt;&lt;br /&gt;While Red Hat have pointed out that their business focus is on JBoss AS 7, whereas JBoss AS 6 is "just" a Community release, I'm still somewhat surprised that the JBoss community do not promote their server more actively.&lt;br /&gt;&lt;br /&gt;Compared to the first class professional documentation of Glassfish and a whole lot of tutorials and videos on almost each and every aspect of Glassfish, Red Hat and/or the JBoss Community do not appear to have a very active interest in widening their audience, or motivating Glassfish users to give JBoss a try.&lt;br /&gt;&lt;br /&gt;For experienced JBoss AS 5 users, upgrading to JBoss AS 6 may be the easiest way to start using Java EE 6 features without losing time on getting familiar with a new server like Glassfish or Resin.&lt;br /&gt;&lt;br /&gt;For Java EE newcomers, starting on JBoss AS 6 is probably the hardest route to take, and frustration with the Java EE 6 server may quickly turn into frustration with Java EE 6 as such and may reinforce common prejudice.&lt;br /&gt;&lt;br /&gt;The JBoss Eclipse integration is currently not usable for day-to-day development, unless you are ready to shutdown and restart the server instead of simply republishing your application. Even if republishing worked as expected, having to wait 40 seconds for a redeployment is no fun.&lt;br /&gt;&lt;br /&gt;All in all, while JBoss may still be &lt;i&gt;the world's number one Java application server&lt;/i&gt; in terms of installed instances, its glory seems to have faded. The boss is still around, but the juniors have taken over the business.&lt;br /&gt;&lt;br /&gt;&lt;h4&gt;Read the whole story&lt;/h4&gt;&lt;br /&gt;&lt;ul&gt;&lt;li&gt;&lt;a href="http://hwellmann.blogspot.com/2011/06/java-ee-6-server-comparison.html"&gt;Part 1: Introduction&lt;/a&gt;&lt;/li&gt;&lt;li&gt;&lt;a href="http://hwellmann.blogspot.com/2011/06/java-ee-6-server-comparison-glassfish.html"&gt;Part 2: Glassfish&lt;/a&gt;&lt;/li&gt;&lt;li&gt;&lt;a href="http://hwellmann.blogspot.com/2011/06/java-ee-6-server-comparison-jboss.html"&gt;Part 3: JBoss&lt;/a&gt;&lt;/li&gt;&lt;li&gt;&lt;a href="http://hwellmann.blogspot.com/2011/06/java-ee-6-server-comparison-resin.html"&gt;Part 4: Resin&lt;/a&gt;&lt;/li&gt;&lt;li&gt;&lt;a href="http://hwellmann.blogspot.com/2011/06/java-ee-6-server-comparison-conclusion.html"&gt;Part 5: Conclusion&lt;/a&gt;&lt;/li&gt;&lt;/ul&gt;&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/7836204352369514180-2548639517678926727?l=hwellmann.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://hwellmann.blogspot.com/feeds/2548639517678926727/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=7836204352369514180&amp;postID=2548639517678926727' title='4 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/7836204352369514180/posts/default/2548639517678926727'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/7836204352369514180/posts/default/2548639517678926727'/><link rel='alternate' type='text/html' href='http://hwellmann.blogspot.com/2011/06/java-ee-6-server-comparison-jboss.html' title='Java EE 6 Server Comparison: JBoss'/><author><name>Harald Wellmann</name><uri>http://www.blogger.com/profile/08039976160321882828</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='16' height='16' src='http://img2.blogblog.com/img/b16-rounded.gif'/></author><thr:total>4</thr:total></entry><entry><id>tag:blogger.com,1999:blog-7836204352369514180.post-4893159921305310440</id><published>2011-06-07T18:37:00.002+02:00</published><updated>2011-06-10T19:49:21.997+02:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='Weld'/><category scheme='http://www.blogger.com/atom/ns#' term='Glassfish'/><category scheme='http://www.blogger.com/atom/ns#' term='Hibernate'/><category scheme='http://www.blogger.com/atom/ns#' term='CDI'/><category scheme='http://www.blogger.com/atom/ns#' term='Java EE 6'/><title type='text'>Java EE 6 Server Comparison: Glassfish</title><content type='html'>In April 2010, I started a Java EE 6 project, and Glassfish 3.0 was the obvious server choice, or rather, the only option at that time. For the next couple of months, I spent a considerable amount of time not working on my application, but analyzing, reporting and working around bugs in the server, mainly in the CDI and JPA areas. This appeared to be the price you had pay for being an early adopter of the new Java Enterprise standard.&lt;br /&gt;&lt;br /&gt;&lt;a name='more'&gt;&lt;/a&gt;&lt;br /&gt;There was an unbearably long gap between the 3.0.1 release in June 2010 and the 3.1 release in February 2011. Glassfish 3.0.1 was still buggy, and the only solution to get my project done on Glassfish 3.0.1 was to stop using CDI completely, reverting to Java EE 5 style @EJB and @Resource injections.&lt;br /&gt;&lt;br /&gt;I was hoping for Glassfish 3.1 to be the first stable release without blocker bugs - but it was not.&lt;br /&gt;&lt;br /&gt;Weld, the CDI reference implementation shared by Glassfish and JBoss, is &lt;a href="http://java.net/jira/browse/GLASSFISH-15721"&gt;still broken in Glassfish 3.1&lt;/a&gt;. The problem can be fixed by replacing &lt;span style="font-family: &amp;quot;Courier New&amp;quot;,Courier,monospace;"&gt;weld-osgi-bundle.jar&lt;/span&gt; with a newer version, or by using a more recent promoted build of Glassfish.&lt;br /&gt;&lt;br /&gt;So this article is based on Glassfish 3.1.1-b06 which includes Weld-1.1.1.Final and to my great relief, this version seems to fix all bugs and memory issues encountered in previous releases.&lt;br /&gt;&lt;br /&gt;Glassfish has an extensive &lt;a href="http://download.oracle.com/docs/cd/E18930_01/index.htm"&gt;documentation set&lt;/a&gt;, and this blog already has a tutorial on &lt;a href="http://hwellmann.blogspot.com/2010/07/building-java-ee-6-web-application-with.html"&gt;setting up Eclipse and Glassfish&lt;/a&gt;, so I'll only briefly touch the basics in this article.&lt;br /&gt;&lt;br /&gt;&lt;h3&gt;Preparing the Server&lt;/h3&gt;&lt;br /&gt;The first thing I do with every Glassfish installation is changing its logging configuration from JUL to SLF4J and Logback, since the default output is pretty unreadable and my application uses SLF4J anyway. Actually, my &lt;a href="http://hwellmann.blogspot.com/2010/12/glassfish-logging-with-slf4j-part-2.html"&gt;posts on this topic&lt;/a&gt; belong to the most popular articles on this blog, so it seems I'm not alone.&lt;br /&gt;&lt;br /&gt;The next thing to do (with any server, not only Glassfish) is to copy the JDBC driver for your database to the appropriate location where the container classloader can pick it up before loading your web application. So I copied the MySQL driver to &lt;span style="font-family: &amp;quot;Courier New&amp;quot;,Courier,monospace;"&gt;domains/domain1/lib&lt;/span&gt;.&lt;br /&gt;&lt;br /&gt;After that I was ready to start Glassfish using&lt;br /&gt;&lt;br /&gt;&lt;pre&gt;bin/asadmin start-domain -v&lt;br /&gt;&lt;/pre&gt;&lt;br /&gt;and to configure my data source using the Admin Console web interface at &lt;span style="font-family: &amp;quot;Courier New&amp;quot;,Courier,monospace;"&gt;http://localhost:4848&lt;/span&gt;.&lt;br /&gt;&lt;br /&gt;Selecting &lt;b&gt;Resources | JDBC | JDBC Connection Pools&lt;/b&gt;, I created a MySQL connection pool and then mapped it to the JNDI name &lt;span style="font-family: &amp;quot;Courier New&amp;quot;,Courier,monospace;"&gt;jdbc/myapp&lt;/span&gt; via &lt;b&gt;Resources | JDBC | JDBC Resources&lt;/b&gt;.&lt;br /&gt;&lt;br /&gt;&lt;h3&gt;Troubleshooting&lt;/h3&gt;&lt;br /&gt;At this point, I was ready to deploy my web app, either by uploading it via the Admin Console, or by copying it to &lt;span style="font-family: &amp;quot;Courier New&amp;quot;,Courier,monospace;"&gt;domains/domain1/autodeploy&lt;/span&gt;, or directly from my Eclipse workspace using &lt;b&gt;Run on Server&lt;/b&gt; (which of course requires installing the latest Glassfish plugin for Eclipse).&lt;br /&gt;&lt;br /&gt;My WAR still included the full set of third-party transitive dependencies from the original Maven build for Tomcat and Spring, some of which are also used by Glassfish itself, with different versions, so I prepared myself for a number of classloader conflicts.&lt;br /&gt;&lt;br /&gt;Actually, there were none. Glassfish uses the standard parent classloader delegation model by default, instead of following the recommendation of the Servlet Specification. (You can override the default by a configuration switch.) So even though my webapp included a whole lot of Java EE API JARs from &lt;span style="font-family: &amp;quot;Courier New&amp;quot;,Courier,monospace;"&gt;org.apache.geronimo.specs&lt;/span&gt; and its own JAXB version, Glassfish would simply ignore the classes included in my WAR and load the ones from its own modules.&lt;br /&gt;&lt;br /&gt;My WAR also included Hibernate and its dependencies. As my &lt;span style="font-family: &amp;quot;Courier New&amp;quot;,Courier,monospace;"&gt;META-INF/persistence.xml&lt;/span&gt; did not explicitly define a persistence provider, Glassfish at first used its built-in provider Eclipselink. This was enough to exhibit a JPQL bug in my application. (Hibernate is known to accept broken JPQL syntax for backward compatibility with its own HQL language, and there is no configuration option to enforce standard compliance.) Eclipselink also complained about a missing &lt;span style="font-family: &amp;quot;Courier New&amp;quot;,Courier,monospace;"&gt;SEQUENCE&lt;/span&gt; table in my database schema, so I left it at that and added&lt;br /&gt;&lt;br /&gt;&lt;pre class="Xml" name="code"&gt;&amp;lt;provider&amp;gt;org.hibernate.ejb.HibernatePersistence&amp;lt;/provider&amp;gt;&lt;br /&gt;&lt;/pre&gt;&lt;br /&gt;to my &lt;span style="font-family: &amp;quot;Courier New&amp;quot;,Courier,monospace;"&gt;persistence.xml&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;After that, I could deploy my web app and open its start page in my browser. Only when undeploying or redeploying the application, there was an error message about an unloaded Hibernate class (which I cannot remember from Glassfish 3.0.1). Anyway, I knew that bundling the JPA provider in the WAR is not the recommended way, so I excluded Hibernate and its dependencies from my WAR and copied the corresponding JARs to &lt;span style="font-family: &amp;quot;Courier New&amp;quot;,Courier,monospace;"&gt;domains/domain1/lib&lt;/span&gt;.&lt;br /&gt;&lt;br /&gt;Finally, I had to solve a runtime issue caused by a version conflict in Woodstox. Glassfish includes Woodstox 3.2.1, whereas my application requires Woodstox 4.1.1 with some new parser options. To get on with my experiments, I simply deleted the missing option from my source code and filed an &lt;a href="http://java.net/jira/browse/GLASSFISH-16748"&gt;enhancement request&lt;/a&gt; for Glassfish to upgrade Woodstox in its 3.1.1 release.&lt;br /&gt;&lt;br /&gt;&lt;h3&gt;Eclipse Integration&lt;/h3&gt;&lt;br /&gt;Complementing the broken 3.1 release, the Glassfish Eclipse plugin was also broken in its default configuration at that time, failing to deploy applications, but this could be worked around by disabling the directory deployment option in the plugin's Server configuration. The current version Oracle Glassfish Server Tools 1.7.1 (released in May 2011) works without problems.&lt;br /&gt;&lt;br /&gt;A point to be improved is the publishing behaviour of the plugin. My application has some 30 Maven modules, represented as individual Eclipse projects. When the application is started via the Eclipse plugin, editing and saving a class from the top-level web project will publish and redeploy the application. Editing a class in any other module does not trigger a redeploy, even after clicking the Publish button. You have to clean the top-level project to force a redeploy.&lt;br /&gt;&lt;br /&gt;Editing a JSP page or a CSS file in the top-level project also causes a redeploy. This could be optimized by simply publishing the changed resource to the running application.&lt;br /&gt;&lt;br /&gt;&lt;h3&gt;Performance Measurements&lt;/h3&gt;&lt;br /&gt;&lt;ul&gt;&lt;li&gt;Empty server startup time: 3.1 s&lt;/li&gt;&lt;li&gt;Empty server memory usage: 37 MB heap, 28 MB PermGen&lt;/li&gt;&lt;li&gt;MyApp deployment time: 13 s&lt;/li&gt;&lt;li&gt;Server + MyApp restart time: 15 s&lt;/li&gt;&lt;li&gt;Server + MyApp memory usage: 156 MB heap, 83 MB PermGen&lt;/li&gt;&lt;li&gt;MyApp redeployment time: 10 s&lt;/li&gt;&lt;li&gt;Server + MyApp startup time from Eclipse: 14 s&lt;/li&gt;&lt;li&gt;Server + MyApp memory usage from Eclipse: 170 MB heap, 89 MB PermGen&lt;/li&gt;&lt;li&gt;MyApp redeployment on Eclipse save: 10.5 s&lt;/li&gt;&lt;/ul&gt;&lt;br /&gt;Glassfish is really fast, but I'm not satisfied with its memory footprint, compared to the original Tomcat/Spring version of my application. This is a &lt;a href="http://java.net/jira/browse/GLASSFISH-16747"&gt;known issue&lt;/a&gt; which can be narrowed down to a single internal metadata cache. The Oracle team is currently working on this, and I'm hoping to see the memory footprint cut drastically in the forthcoming 3.1.1 release.&lt;br /&gt;&lt;br /&gt;&lt;b&gt;[Update 10 Jun 2011:&lt;/b&gt; Tim Quinn from Oracle committed some changes to reduce the memory footprint. I've retested my application with the nightly build &lt;code&gt;glassfish-3.1.1-b07-06_09_2011&lt;/code&gt;, and the heap is now less than 70 MB. Great news!]&lt;br /&gt;&lt;br /&gt;I have redeployed my application 20 times in a row, and there were no classloader or other memory leaks. &lt;br /&gt;&lt;br /&gt;&lt;h3&gt;Summary&lt;/h3&gt;&lt;br /&gt;Glassfish is more than the Java EE 6 Reference Implementation, it is &lt;i&gt;the&lt;/i&gt; reference for Java EE 6 servers. Of course, Glassfish is not perfect and it may be second to one or the other of its competitors in certain areas, but the total package of documentation, community support, first-class technology, and an ever growing number of tutorials, presentations and videos provides a very productive basis for Java Enterprise development.&lt;br /&gt;&lt;br /&gt;Regarding the shared Sun/Oracle background, Glassfish may have some natural bias towards Netbeans, but nevertheless the Glassfish Eclipse plugin is stable and rich enough for professional use.&lt;br /&gt;&lt;br /&gt;Most of the things that could be improved in and about Glassfish are organizational rather than technical aspects.&lt;br /&gt;&lt;br /&gt;The most pressing issue is release management. I cannot help feeling that the 3.0, 3.0.1 and 3.1 releases were more determined by timelines and management requirements than by stability. There was an urgent need for a 3.0.2 maintenance release that never came. Working with 3.1 pre-release promoted builds was a tedious two steps forward, one step back experience.&lt;br /&gt;&lt;br /&gt;From this background, the &lt;a href="http://www.java.net/forum/topic/glassfish/glassfish/where-glassfish-311"&gt;announcement&lt;/a&gt; that the Glassfish 3.1.1 release will be delayed to "include more changes requested by the community" is very good news.&lt;br /&gt;&lt;br /&gt;Since its acquisition of Sun, Oracle has not exactly gained the best of reputations in dealing with Open Source projects. There are plenty of reasons for criticizing Oracle's moves in the Java Community during the last twelve months, but lack of support for Glassfish is definitely not one of them.&lt;br /&gt;&lt;br /&gt;One of the less successful innovations was the migration of the java.net infrastructure, running the Glassfish forums, among others. The forum continues to be a useful information source, but its usability has &lt;a href="http://www.java.net/poll/now-youre-accustomed-it-what-do-you-think-new-javanet#comment-815727"&gt;degraded a lot&lt;/a&gt;.&lt;br /&gt;&lt;br /&gt;Anyway, the Glassfish community is not a one-way road, you do get feedback in the forum, both from users and from Oracle engineers, most of the bugs I reported have been fixed, many of them within a few days, and even though Oracle may be more of a benevolent dictator than a neutral community sponsor, I don't really mind as long as the entire ecosystem is thriving.&lt;br /&gt;&lt;br /&gt;&lt;h4&gt;Read the whole story&lt;/h4&gt;&lt;br /&gt;&lt;ul&gt;&lt;li&gt;&lt;a href="http://hwellmann.blogspot.com/2011/06/java-ee-6-server-comparison.html"&gt;Part 1: Introduction&lt;/a&gt;&lt;/li&gt;&lt;li&gt;&lt;a href="http://hwellmann.blogspot.com/2011/06/java-ee-6-server-comparison-glassfish.html"&gt;Part 2: Glassfish&lt;/a&gt;&lt;/li&gt;&lt;li&gt;&lt;a href="http://hwellmann.blogspot.com/2011/06/java-ee-6-server-comparison-jboss.html"&gt;Part 3: JBoss&lt;/a&gt;&lt;/li&gt;&lt;li&gt;&lt;a href="http://hwellmann.blogspot.com/2011/06/java-ee-6-server-comparison-resin.html"&gt;Part 4: Resin&lt;/a&gt;&lt;/li&gt;&lt;li&gt;&lt;a href="http://hwellmann.blogspot.com/2011/06/java-ee-6-server-comparison-conclusion.html"&gt;Part 5: Conclusion&lt;/a&gt;&lt;/li&gt;&lt;/ul&gt;&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/7836204352369514180-4893159921305310440?l=hwellmann.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://hwellmann.blogspot.com/feeds/4893159921305310440/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=7836204352369514180&amp;postID=4893159921305310440' title='4 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/7836204352369514180/posts/default/4893159921305310440'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/7836204352369514180/posts/default/4893159921305310440'/><link rel='alternate' type='text/html' href='http://hwellmann.blogspot.com/2011/06/java-ee-6-server-comparison-glassfish.html' title='Java EE 6 Server Comparison: Glassfish'/><author><name>Harald Wellmann</name><uri>http://www.blogger.com/profile/08039976160321882828</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='16' height='16' src='http://img2.blogblog.com/img/b16-rounded.gif'/></author><thr:total>4</thr:total></entry><entry><id>tag:blogger.com,1999:blog-7836204352369514180.post-4245820266507651577</id><published>2011-06-07T17:54:00.001+02:00</published><updated>2011-06-07T19:08:20.570+02:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='Resin'/><category scheme='http://www.blogger.com/atom/ns#' term='Eclipse'/><category scheme='http://www.blogger.com/atom/ns#' term='JBoss'/><category scheme='http://www.blogger.com/atom/ns#' term='Spring'/><category scheme='http://www.blogger.com/atom/ns#' term='Glassfish'/><category scheme='http://www.blogger.com/atom/ns#' term='Java EE 6'/><title type='text'>Java EE 6 Server Comparison: Introduction</title><content type='html'>A year and a half after the Java EE 6 specification release, there are now three Open Source servers certified for the Java EE 6 Web Profile: &lt;br /&gt;&lt;ul&gt;&lt;li&gt;Glassfish 3.x&lt;/li&gt;&lt;li&gt;JBoss 6.x&lt;/li&gt;&lt;li&gt;Resin 4.0.x&lt;/li&gt;&lt;/ul&gt;Time to take a look at these three servers in direct comparison and do some experiments, not with a toy or benchmark application developed for this purpose, but with a real-life enterprise application.&lt;br /&gt;&lt;br /&gt;&lt;a name='more'&gt;&lt;/a&gt;&lt;br /&gt;Taking an application developed on server X and porting it to servers Y and Z might cause some bias towards server X, so my scenario is the following:&lt;br /&gt;&lt;ul&gt;&lt;li&gt;MyApp is an enterprise application originally developed on Tomcat 6 and Spring 3, using JPA 2.0 (Hibernate on MySQL), declarative transactions, dependency injection, and Spring MVC in the web layer. In the persistence and service layers, this application has no compile time dependencies on Spring, thanks to the fact that Java EE 6 annotations like &lt;span style="font-family: &amp;quot;Courier New&amp;quot;,Courier,monospace;"&gt;@Inject&lt;/span&gt; or &lt;span style="font-family: &amp;quot;Courier New&amp;quot;,Courier,monospace;"&gt;@TransactionAttribute&lt;/span&gt; are also supported by Spring.&lt;/li&gt;&lt;li&gt;MyApp is built with Maven, my development environment is Eclipse 3.6.2 with m2eclipse.&lt;/li&gt;&lt;/ul&gt;The goals of my experiments:&lt;br /&gt;&lt;ul&gt;&lt;li&gt;Make MyApp run on a Java EE 6 server (using JPA, JTA, EJB, CDI, Servlet, JSP) and restrict the run-time use of Spring to the web layer, using a &lt;a href="http://hwellmann.blogspot.com/2011/06/using-cdi-from-spring.html"&gt;CDI-to-Spring bridge&lt;/a&gt;.&lt;/li&gt;&lt;li&gt;Build a WAR that can be deployed to each of Glassfish, JBoss and Resin.&lt;/li&gt;&lt;li&gt;Work with the Eclipse plugin for each server, compare the edit-save-deploy cycles and developer productivity in general.&lt;/li&gt;&lt;li&gt;Work with the stand-alone servers, and compare startup and deployment times and memory usage.&lt;/li&gt;&lt;/ul&gt;Disclaimer: I started working with Glassfish in March 2010 and I haven't really used either JBoss or Resin before these experiments, so I may be biased towards Glassfish. I'm not in any way affiliated with Oracle, Red Hat or Caucho, and the views expressed in this blog are my own and not my employer's.&lt;br /&gt;&lt;br /&gt;A note on Java EE 6 Profiles and certification: Glassfish is of course certified both for the Full Profile and for the Web Profile. JBoss AS 6.0.0.Final was &lt;a href="http://community.jboss.org/blogs/donnamishelly/2011/01/04/jboss-application-server-6-goes-final"&gt;announced&lt;/a&gt; as a fully certified implementation of the Java EE 6 Web Profile, but for some reason it is not yet listed on the official &lt;a href="http://www.oracle.com/technetwork/java/javaee/overview/compatibility-jsp-136984.html"&gt;Java EE compatibility page&lt;/a&gt;. JBoss also claims to support the Full Profile, but has not taken the pains of undergoing certification for it. Resin is explicitly focused on the Web Profile and has recently been certified. &lt;a href="http://caucho.com/resin-4.0/changes/resin-4.0.17.xtp"&gt;Resin also supports JMS&lt;/a&gt;, which is not part of the Web Profile.&lt;br /&gt;&lt;br /&gt;MyApp only requires the Web Profile. For my experiments, I've used the Full Profile installation of Glassfish, the default server configuration of JBoss, and the Open Source Resin installation (not Resin Pro).&lt;br /&gt;&lt;br /&gt;&lt;h3&gt;Performance Measurement Scenarios&lt;/h3&gt;&lt;br /&gt;For each server, I ran the following tests:&lt;br /&gt;&lt;br /&gt;&lt;ul&gt;&lt;li&gt;Empty server startup time. ("Empty" means without any applications deployed by the user, running the server out of the box, which may include some management applications.)&lt;/li&gt;&lt;li&gt;Empty server total heap and PermGen size. (After starting the server and forcing a garbage collection from jvisualvm.)&lt;/li&gt;&lt;li&gt;MyApp deployment time (copying it to the autodeploy directory of the running server).&lt;/li&gt;&lt;li&gt;Server + MyApp restart time (restarting the server with my deployed application).&lt;/li&gt;&lt;li&gt;Server + MyApp total heap and PermGen size. (After starting the server with the deployed applicaton and forcing a garbage collection from jvisualvm).&lt;/li&gt;&lt;li&gt;MyApp redeployment time (after touching myapp.war in the autodeploy directory).&lt;/li&gt;&lt;li&gt;Server + MyApp startup time from Eclipse. (Using Run on Server on the top-level web project).&lt;/li&gt;&lt;li&gt;Server + MyApp total heap and PermGen size, running from Eclipse (after forcing GC as above).&lt;/li&gt;&lt;li&gt;MyApp redeploy time after changing a source file in Eclipse.&lt;/li&gt;&lt;li&gt;Checking for memory leaks after redeploying.&lt;/li&gt;&lt;/ul&gt;&lt;br /&gt;&lt;h4&gt;Read the whole story&lt;/h4&gt;&lt;br /&gt;&lt;ul&gt;&lt;li&gt;&lt;a href="http://hwellmann.blogspot.com/2011/06/java-ee-6-server-comparison.html"&gt;Part 1: Introduction&lt;/a&gt;&lt;/li&gt;&lt;li&gt;&lt;a href="http://hwellmann.blogspot.com/2011/06/java-ee-6-server-comparison-glassfish.html"&gt;Part 2: Glassfish&lt;/a&gt;&lt;/li&gt;&lt;li&gt;&lt;a href="http://hwellmann.blogspot.com/2011/06/java-ee-6-server-comparison-jboss.html"&gt;Part 3: JBoss&lt;/a&gt;&lt;/li&gt;&lt;li&gt;&lt;a href="http://hwellmann.blogspot.com/2011/06/java-ee-6-server-comparison-resin.html"&gt;Part 4: Resin&lt;/a&gt;&lt;/li&gt;&lt;li&gt;&lt;a href="http://hwellmann.blogspot.com/2011/06/java-ee-6-server-comparison-conclusion.html"&gt;Part 5: Conclusion&lt;/a&gt;&lt;/li&gt;&lt;/ul&gt;&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/7836204352369514180-4245820266507651577?l=hwellmann.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://hwellmann.blogspot.com/feeds/4245820266507651577/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=7836204352369514180&amp;postID=4245820266507651577' title='7 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/7836204352369514180/posts/default/4245820266507651577'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/7836204352369514180/posts/default/4245820266507651577'/><link rel='alternate' type='text/html' href='http://hwellmann.blogspot.com/2011/06/java-ee-6-server-comparison.html' title='Java EE 6 Server Comparison: Introduction'/><author><name>Harald Wellmann</name><uri>http://www.blogger.com/profile/08039976160321882828</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='16' height='16' src='http://img2.blogblog.com/img/b16-rounded.gif'/></author><thr:total>7</thr:total></entry><entry><id>tag:blogger.com,1999:blog-7836204352369514180.post-2496998325279553472</id><published>2011-06-06T12:33:00.000+02:00</published><updated>2011-06-06T12:33:07.127+02:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='Resin'/><category scheme='http://www.blogger.com/atom/ns#' term='jeeunit'/><category scheme='http://www.blogger.com/atom/ns#' term='Glassfish'/><category scheme='http://www.blogger.com/atom/ns#' term='JUnit'/><category scheme='http://www.blogger.com/atom/ns#' term='Java EE 6'/><title type='text'>Java EE 6 Integration Testing on Resin and Glassfish</title><content type='html'>&lt;a href="http://jeeunit.googlecode.com"&gt;jeeunit&lt;/a&gt;, my Java EE 6 Integration Testing project, now supports &lt;a href="http://www.caucho.com/download/"&gt;Caucho Resin 4.0.18&lt;/a&gt; in addition to Glassfish 3.1. &lt;br /&gt;&lt;br /&gt;Another new feature is a &lt;code&gt;@Transactional&lt;/code&gt; annotation which can be used to wrap test methods in an auto-rollback transaction.&lt;br /&gt;&lt;br /&gt;The current release jeeunit 0.8.0 is available from Maven Central and from the &lt;a href="http://jeeunit.googlecode.com"&gt;jeeunit Project Page&lt;/a&gt; on Google Code.&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/7836204352369514180-2496998325279553472?l=hwellmann.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://hwellmann.blogspot.com/feeds/2496998325279553472/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=7836204352369514180&amp;postID=2496998325279553472' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/7836204352369514180/posts/default/2496998325279553472'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/7836204352369514180/posts/default/2496998325279553472'/><link rel='alternate' type='text/html' href='http://hwellmann.blogspot.com/2011/06/java-ee-6-integration-testing-on-resin.html' title='Java EE 6 Integration Testing on Resin and Glassfish'/><author><name>Harald Wellmann</name><uri>http://www.blogger.com/profile/08039976160321882828</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='16' height='16' src='http://img2.blogblog.com/img/b16-rounded.gif'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-7836204352369514180.post-4485102677156875260</id><published>2011-06-01T13:46:00.000+02:00</published><updated>2011-06-01T13:46:44.976+02:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='Wicket'/><category scheme='http://www.blogger.com/atom/ns#' term='Spring'/><category scheme='http://www.blogger.com/atom/ns#' term='Glassfish'/><category scheme='http://www.blogger.com/atom/ns#' term='Tomcat'/><category scheme='http://www.blogger.com/atom/ns#' term='CDI'/><category scheme='http://www.blogger.com/atom/ns#' term='Java EE 6'/><title type='text'>Using CDI from Spring</title><content type='html'>Spring and Java EE are converging in many areas, mainly due to CDI. In fact, by confining yourself to a suitable subset of annotations and other configuration mechanisms, you can design your persistence and service layers to run &lt;a href="http://code.google.com/p/jeeunit/wiki/TestingOnSpring"&gt;either on Java EE 6 or on Spring 3&lt;/a&gt;, simply by selecting the appropriate set of libraries.&lt;br /&gt;&lt;br /&gt;The web layer is a different story: if your web framework is tightly coupled to either Java EE 6 or Spring, it will be hard or even impossible to simply change the container, but even in the web layer, there are solutions like Apache Wicket which work well both with Spring and Java EE, all you need is some glue code to access the dependency injection container.&lt;br /&gt;&lt;br /&gt;I'm currently migrating a web application from Tomcat/Spring to Glassfish, and since this application is based on Spring MVC, I cannot completely replace Spring in this step. The goal of the migration is to drop all Spring dependencies from all components except the web frontend and to somehow make the service beans (stateless session beans and CDI managed beans) visible to the Spring web application context.&lt;br /&gt;&lt;br /&gt;&lt;a name='more'&gt;&lt;/a&gt;&lt;br /&gt;Looking for a solution, I found Rick Hightower's post on &lt;a href="http://rick-hightower.blogspot.com/2011/04/cdi-and-spring-living-in-harmony.html"&gt;CDI and Spring living in harmony&lt;/a&gt; and the related &lt;a href="https://github.com/CDISource/cdisource"&gt;CDISource&lt;/a&gt; project. The basic idea is to use a Spring &lt;code&gt;BeanFactoryPostProcessor&lt;/code&gt; to populate Spring's application context with a factory bean for each CDI bean obtained from the CDI BeanManager, thus making all CDI beans accessible as Spring beans.&lt;br /&gt;&lt;br /&gt;It was very easy to integrate the CDISource Spring Bridge into my project, I just cloned their Git repository, ran the Maven build, added&lt;br /&gt;&lt;br /&gt;&lt;pre class="Xml" name="code"&gt;&lt;br /&gt;    &amp;lt;dependency&amp;gt;&lt;br /&gt;      &amp;lt;groupId&amp;gt;org.cdisource.springbridge&amp;lt;/groupId&amp;gt;&lt;br /&gt;      &amp;lt;artifactId&amp;gt;springbridge&amp;lt;/artifactId&amp;gt;&lt;br /&gt;      &amp;lt;version&amp;gt;1.0-SNAPSHOT&amp;lt;/version&amp;gt;&lt;br /&gt;    &amp;lt;/dependency&amp;gt;&lt;br /&gt;&lt;/pre&gt;&lt;br /&gt;to my own POM and included &lt;br /&gt;&lt;pre&gt;&amp;lt;bean class="org.cdisource.springintegration.CdiBeanFactoryPostProcessor"/&amp;gt;&lt;br /&gt;&lt;/pre&gt;in my Spring configuration.&lt;br /&gt;&lt;br /&gt;This was enough to get going, but I soon found out that some standard but not-so-basic use cases are not yet supported, e.g.&lt;br /&gt;&lt;ul&gt;&lt;li&gt;&lt;code&gt;@Stateless&lt;/code&gt; EJBs &lt;code&gt;@Inject&lt;/code&gt;ed into CDI beans.&lt;/li&gt;&lt;li&gt;Multiple beans of the same type with &lt;code&gt;@Named&lt;/code&gt; or other qualifiers.&lt;/li&gt;&lt;li&gt;Producer methods&lt;/li&gt;&lt;/ul&gt;So I started hacking the &lt;code&gt;CdiBeanFactoryPostProcessor&lt;/code&gt; to make it work for my application. Here is the solution:&lt;br /&gt;&lt;br /&gt;&lt;pre class="Java" name="code"&gt;package org.cdisource.springintegration;&lt;br /&gt;&lt;br /&gt;import java.lang.reflect.Type;&lt;br /&gt;import java.util.Set;&lt;br /&gt;&lt;br /&gt;import javax.enterprise.inject.spi.Bean;&lt;br /&gt;&lt;br /&gt;import org.slf4j.Logger;&lt;br /&gt;import org.slf4j.LoggerFactory;&lt;br /&gt;import org.springframework.beans.BeansException;&lt;br /&gt;import org.springframework.beans.factory.config.BeanFactoryPostProcessor;&lt;br /&gt;import org.springframework.beans.factory.config.ConfigurableListableBeanFactory;&lt;br /&gt;import org.springframework.beans.factory.support.BeanDefinitionBuilder;&lt;br /&gt;import org.springframework.beans.factory.support.DefaultListableBeanFactory;&lt;br /&gt;&lt;br /&gt;public class CdiBeanFactoryPostProcessor implements BeanFactoryPostProcessor {&lt;br /&gt;&lt;br /&gt;    private static Logger logger = LoggerFactory.getLogger(CdiBeanFactoryPostProcessor.class);&lt;br /&gt;&lt;br /&gt;    private boolean useLongName;&lt;br /&gt;&lt;br /&gt;    private BeanManagerLocationUtil beanManagerLocationUtil = new BeanManagerLocationUtil();&lt;br /&gt;&lt;br /&gt;    @Override&lt;br /&gt;    public void postProcessBeanFactory(ConfigurableListableBeanFactory beanFactory)&lt;br /&gt;            throws BeansException {&lt;br /&gt;&lt;br /&gt;        DefaultListableBeanFactory factory = (DefaultListableBeanFactory) beanFactory;&lt;br /&gt;&lt;br /&gt;        Set&amp;lt;Bean&amp;lt;?&gt;&gt; beans = beanManagerLocationUtil.beanManager().getBeans(Object.class);&lt;br /&gt;        for (Bean&amp;lt;?&gt; bean : beans) {&lt;br /&gt;            if (bean instanceof SpringIntegrationExtention.SpringBean) {&lt;br /&gt;                continue;&lt;br /&gt;            }&lt;br /&gt;&lt;br /&gt;            if (bean.getName() != null &amp;&amp; bean.getName().equals("Spring Injection")) {&lt;br /&gt;                continue;&lt;br /&gt;            }&lt;br /&gt;            logger.debug("bean types = {}", bean.getTypes());&lt;br /&gt;            Class&amp;lt;?&gt; beanClass = getBeanClass(bean);&lt;br /&gt;            BeanDefinitionBuilder definition = BeanDefinitionBuilder&lt;br /&gt;                    .rootBeanDefinition(CdiFactoryBean.class)&lt;br /&gt;                    .addPropertyValue("beanClass", beanClass)&lt;br /&gt;                    .addPropertyValue("beanManager", beanManagerLocationUtil.beanManager())&lt;br /&gt;                    .addPropertyValue("qualifiers", bean.getQualifiers()).setLazyInit(true);&lt;br /&gt;            String name = generateName(bean);&lt;br /&gt;            factory.registerBeanDefinition(name, definition.getBeanDefinition());&lt;br /&gt;            logger.debug("bean name = {}, bean class = {}", bean.getName(), beanClass.getName());&lt;br /&gt;        }&lt;br /&gt;    }&lt;br /&gt;&lt;br /&gt;    private Class&amp;lt;?&gt; getBeanClass(Bean&amp;lt;?&gt; bean) {&lt;br /&gt;        Class&amp;lt;?&gt; klass = Object.class;&lt;br /&gt;        for (Type type : bean.getTypes()) {&lt;br /&gt;            if (type instanceof Class) {&lt;br /&gt;                Class&amp;lt;?&gt; currentClass = (Class&amp;lt;?&gt;) type;&lt;br /&gt;                if (klass.isAssignableFrom(currentClass)) {&lt;br /&gt;                    klass = currentClass;&lt;br /&gt;                }&lt;br /&gt;            }&lt;br /&gt;        }&lt;br /&gt;        return klass;&lt;br /&gt;    }&lt;br /&gt;&lt;br /&gt;    private String generateName(Bean&amp;lt;?&gt; bean) {&lt;br /&gt;        String name = bean.getName() != null ? bean.getName() : generateNameBasedOnClassName(bean);&lt;br /&gt;        return name;&lt;br /&gt;    }&lt;br /&gt;&lt;br /&gt;    private String generateNameBasedOnClassName(Bean&amp;lt;?&gt; bean) {&lt;br /&gt;        Class&amp;lt;?&gt; beanClass = getBeanClass(bean);&lt;br /&gt;        return !useLongName ? beanClass.getSimpleName() + "FactoryBean" : beanClass.getName()&lt;br /&gt;                .replace(".", "_") + "FactoryBean";&lt;br /&gt;    }&lt;br /&gt;&lt;br /&gt;    public void setUseLongName(boolean useLongName) {&lt;br /&gt;        this.useLongName = useLongName;&lt;br /&gt;    }&lt;br /&gt;&lt;br /&gt;}&lt;br /&gt;&lt;br /&gt;&lt;/pre&gt;&lt;br /&gt;The main change is in &lt;code&gt;getBeanClass()&lt;/code&gt;: It is important to note that the CDI API &lt;code&gt;Bean.getBeanClass()&lt;/code&gt; does &lt;em&gt;not&lt;/em&gt; return the class of the given bean: the result is the class in which the bean is defined. In particular, for producer methods, the result is the class containing the method and not the method return type.&lt;br /&gt;&lt;br /&gt;&lt;code&gt;Bean.getTypes()&lt;/code&gt; returns all classes and interfaces of potential injection points that the bean will match. This set of types does not always include the bean's implementation class, e.g. for a stateless session bean with a local business interface, the bean types will only be &lt;code&gt;java.lang.Object&lt;/code&gt; and the business interfaces (and any superinterfaces of the business interface).&lt;br /&gt;&lt;br /&gt;&lt;code&gt;getBeanClass()&lt;/code&gt; currently selects the most specialized CDI bean type and uses this type to create the corresponding Spring factory bean.&lt;br /&gt;&lt;br /&gt;The next point to note are qualifiers: I added a &lt;code&gt;qualifiers&lt;/code&gt; property to the &lt;code&gt;CdiFactoryBean&lt;/code&gt; and changed its &lt;code&gt;getObject()&lt;/code&gt; method to use the qualifiers for looking up the bean in the CDI bean container:&lt;br /&gt;&lt;br /&gt;&lt;pre class="Java" name="code"&gt;package org.cdisource.springintegration;&lt;br /&gt;&lt;br /&gt;import java.lang.annotation.Annotation;&lt;br /&gt;import java.util.Set;&lt;br /&gt;&lt;br /&gt;import javax.enterprise.inject.spi.BeanManager;&lt;br /&gt;&lt;br /&gt;import org.cdisource.beancontainer.BeanContainer;&lt;br /&gt;import org.cdisource.beancontainer.BeanContainerImpl;&lt;br /&gt;import org.springframework.beans.factory.FactoryBean;&lt;br /&gt;import org.springframework.beans.factory.InitializingBean;&lt;br /&gt;&lt;br /&gt;public class CdiFactoryBean implements FactoryBean&amp;lt;Object&gt;, InitializingBean {&lt;br /&gt;&lt;br /&gt;    private Class&amp;lt;?&gt; beanClass;&lt;br /&gt;    private boolean singleton = true;&lt;br /&gt;    private BeanContainer beanContainer;&lt;br /&gt;    private BeanManager beanManager;&lt;br /&gt;    private Set&amp;lt;Annotation&gt; qualifiers;&lt;br /&gt;&lt;br /&gt;    @Override&lt;br /&gt;    public void afterPropertiesSet() throws Exception {&lt;br /&gt;        if (beanManager == null)&lt;br /&gt;            throw new IllegalStateException("BeanManager must be set");&lt;br /&gt;        beanContainer = new BeanContainerImpl(beanManager);&lt;br /&gt;    }&lt;br /&gt;&lt;br /&gt;    public void setBeanClass(Class&amp;lt;?&gt; beanClass) {&lt;br /&gt;        this.beanClass = beanClass;&lt;br /&gt;    }&lt;br /&gt;&lt;br /&gt;    @Override&lt;br /&gt;    public Object getObject() throws Exception {&lt;br /&gt;        return beanContainer.getBeanByType(beanClass, qualifiers.toArray(new Annotation[] {}));&lt;br /&gt;    }&lt;br /&gt;&lt;br /&gt;    @Override&lt;br /&gt;    public Class&amp;lt;?&gt; getObjectType() {&lt;br /&gt;        return beanClass;&lt;br /&gt;    }&lt;br /&gt;&lt;br /&gt;    @Override&lt;br /&gt;    public boolean isSingleton() {&lt;br /&gt;        return singleton;&lt;br /&gt;    }&lt;br /&gt;&lt;br /&gt;    public void setSingleton(boolean singleton) {&lt;br /&gt;        this.singleton = singleton;&lt;br /&gt;    }&lt;br /&gt;&lt;br /&gt;    public void setBeanManager(BeanManager beanManager) {&lt;br /&gt;        this.beanManager = beanManager;&lt;br /&gt;    }&lt;br /&gt;&lt;br /&gt;    public void setQualifiers(Set&amp;lt;Annotation&gt; qualifiers) {&lt;br /&gt;        this.qualifiers = qualifiers;&lt;br /&gt;    }&lt;br /&gt;}&lt;br /&gt;&lt;br /&gt;&lt;/pre&gt;&lt;br /&gt;I'm sure this is not the end of the story, both Spring and CDI are complex enough to allow use cases where this bridge is likely to break, but it now works perfectly for me in my real-life application.&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/7836204352369514180-4485102677156875260?l=hwellmann.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://hwellmann.blogspot.com/feeds/4485102677156875260/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=7836204352369514180&amp;postID=4485102677156875260' title='5 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/7836204352369514180/posts/default/4485102677156875260'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/7836204352369514180/posts/default/4485102677156875260'/><link rel='alternate' type='text/html' href='http://hwellmann.blogspot.com/2011/06/using-cdi-from-spring.html' title='Using CDI from Spring'/><author><name>Harald Wellmann</name><uri>http://www.blogger.com/profile/08039976160321882828</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='16' height='16' src='http://img2.blogblog.com/img/b16-rounded.gif'/></author><thr:total>5</thr:total></entry><entry><id>tag:blogger.com,1999:blog-7836204352369514180.post-8900769107398693795</id><published>2011-05-25T17:08:00.002+02:00</published><updated>2011-07-02T14:50:02.769+02:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='SWT'/><category scheme='http://www.blogger.com/atom/ns#' term='Eclipse'/><category scheme='http://www.blogger.com/atom/ns#' term='Ubuntu'/><category scheme='http://www.blogger.com/atom/ns#' term='Firefox'/><title type='text'>Eclipse Helios with Firefox 4 on Ubuntu Natty</title><content type='html'>I've just finished installing Kubuntu 11.04 on a spare partition, and I'm rather pleased with it, there were absolutely no problems with the usual suspects like X driver, sound or fake RAID.&lt;br /&gt;&lt;br /&gt;The only regression I noted is that Eclipse 3.6.2 no longer supports an internal web browser. Ubuntu 11.04 comes with Firefox 4.x, and this is not currently supported by Eclipse SWT.&lt;br /&gt;&lt;br /&gt;&lt;a href="https://bbs.archlinux.org/viewtopic.php?id=115543"&gt;This thread&lt;/a&gt; gave me the hint how to fix it:&lt;br /&gt;&lt;ul&gt;&lt;li&gt;Install package &lt;span style="font-family: &amp;quot;Courier New&amp;quot;,Courier,monospace;"&gt;libwebkitgtk-1.0-0&lt;/span&gt; (do not use the newer version &lt;span style="font-family: &amp;quot;Courier New&amp;quot;,Courier,monospace;"&gt;libwebkitgtk-3.0-0&lt;/span&gt;)&lt;/li&gt;&lt;li&gt;Add the following to &lt;span style="font-family: &amp;quot;Courier New&amp;quot;,Courier,monospace;"&gt;eclipse.ini&lt;/span&gt;: &lt;span style="font-family: &amp;quot;Courier New&amp;quot;,Courier,monospace;"&gt;-Dorg.eclipse.swt.browser.UseWebKitGTK=true&lt;/span&gt;&lt;/li&gt;&lt;li&gt;Create a symlink in &lt;span style="font-family: &amp;quot;Courier New&amp;quot;,Courier,monospace;"&gt;/usr/lib&lt;/span&gt; to satisfy the SWT dependencies: &lt;br /&gt;&lt;span style="font-family: &amp;quot;Courier New&amp;quot;,Courier,monospace;"&gt;ln -sf libwebkitgtk-1.0.so.0.6.0 libwebkit-1.0.so.2&lt;/span&gt;&lt;/li&gt;&lt;/ul&gt;Restart Eclipse and check &lt;b&gt;Window | Preferences | General | Web Browser&lt;/b&gt;. The radio button &lt;b&gt;Use internal web browser&lt;/b&gt; should now be enabled.&lt;br /&gt;&lt;br /&gt;&lt;b&gt;Update 2 Jul 2001:&lt;/b&gt; After upgrading to Eclipse Indigo 3.7.0, the internal browser works out of the box. I did not have to modify &lt;span style="font-family: &amp;quot;Courier New&amp;quot;,Courier,monospace;"&gt;eclipse.ini&lt;/span&gt;. But it seems Eclipse now uses WebKit by default, so you still need to install the WebKit library and create the symlink if you haven't done so before.&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/7836204352369514180-8900769107398693795?l=hwellmann.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://hwellmann.blogspot.com/feeds/8900769107398693795/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=7836204352369514180&amp;postID=8900769107398693795' title='4 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/7836204352369514180/posts/default/8900769107398693795'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/7836204352369514180/posts/default/8900769107398693795'/><link rel='alternate' type='text/html' href='http://hwellmann.blogspot.com/2011/05/eclipse-helios-with-firefox-4-on-ubuntu.html' title='Eclipse Helios with Firefox 4 on Ubuntu Natty'/><author><name>Harald Wellmann</name><uri>http://www.blogger.com/profile/08039976160321882828</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='16' height='16' src='http://img2.blogblog.com/img/b16-rounded.gif'/></author><thr:total>4</thr:total></entry><entry><id>tag:blogger.com,1999:blog-7836204352369514180.post-8769023292298928791</id><published>2011-04-03T23:13:00.000+02:00</published><updated>2011-04-03T23:13:00.914+02:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='reFit'/><category scheme='http://www.blogger.com/atom/ns#' term='Jenkins'/><category scheme='http://www.blogger.com/atom/ns#' term='Fit'/><title type='text'>reFit Plugin for Jenkins</title><content type='html'>After working with Hudson (now &lt;a href="http://jenkins-ci.org/"&gt;Jenkins&lt;/a&gt;) as a user for almost three years, I've now created my first plugin for publishing Fit test reports for Jenkins projects.&lt;br /&gt;&lt;br /&gt;The plugin works with &lt;a href="http://refit.googlecode.com/"&gt;reFit&lt;/a&gt; 1.7.0 or higher. It is published on the Jenkins Community infrastructure, separate from the reFit project on Google Code. You can install the plugin from the Jenkins update centre.&lt;br /&gt;&lt;br /&gt;For more details, see the &lt;a href="http://wiki.jenkins-ci.org/display/JENKINS/reFit+Plugin"&gt;reFit Plugin&lt;/a&gt; page in the Jenkins Wiki.&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/7836204352369514180-8769023292298928791?l=hwellmann.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://hwellmann.blogspot.com/feeds/8769023292298928791/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=7836204352369514180&amp;postID=8769023292298928791' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/7836204352369514180/posts/default/8769023292298928791'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/7836204352369514180/posts/default/8769023292298928791'/><link rel='alternate' type='text/html' href='http://hwellmann.blogspot.com/2011/04/refit-plugin-for-jenkins.html' title='reFit Plugin for Jenkins'/><author><name>Harald Wellmann</name><uri>http://www.blogger.com/profile/08039976160321882828</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='16' height='16' src='http://img2.blogblog.com/img/b16-rounded.gif'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-7836204352369514180.post-7958152484832834483</id><published>2011-03-20T14:04:00.005+01:00</published><updated>2011-03-21T21:33:43.591+01:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='JAXB'/><category scheme='http://www.blogger.com/atom/ns#' term='Maven'/><category scheme='http://www.blogger.com/atom/ns#' term='xjc'/><title type='text'>JAXB Marshalling with Custom Namespace Prefixes</title><content type='html'>&lt;h3&gt;The Problem&lt;/h3&gt;&lt;br /&gt;&lt;ul&gt;&lt;li&gt;You have an XML schema with &lt;b&gt;multiple XML namespaces&lt;/b&gt;.&lt;/li&gt;&lt;li&gt; You generate a &lt;b&gt;JAXB model&lt;/b&gt; with xjc.&lt;/li&gt;&lt;li&gt;You build a JAXB document model and use the &lt;b&gt;JAXB Marshaller&lt;/b&gt; to create XML from the model.&lt;/li&gt;&lt;li&gt;You want to &lt;b&gt;override the default namespace prefixes&lt;/b&gt; &lt;code&gt;ns1, ns2, ...&lt;/code&gt; created by the Marshaller.&lt;/li&gt;&lt;/ul&gt;&lt;br /&gt;&lt;a name='more'&gt;&lt;/a&gt;&lt;br /&gt;&lt;h3&gt;Solution 1&lt;/h3&gt;&lt;br /&gt;You can implement a &lt;code&gt;NamespacePrefixMapper&lt;/code&gt; and pass it to the &lt;code&gt;Marshaller&lt;/code&gt;&lt;br /&gt;&lt;br /&gt;&lt;pre class="Java" name="code"&gt;Marshaller m = context.createMarshaller();&lt;br /&gt;    NamespacePrefixMapper mapper = new MyNamespacePrefixMapper();&lt;br /&gt;    m.setProperty("com.sun.xml.internal.bind.namespacePrefixMapper", mapper);&lt;br /&gt;&lt;/pre&gt;&lt;br /&gt;Drawbacks:&lt;br /&gt;&lt;ul&gt;&lt;li&gt;You need to implement the Mapper.&lt;/li&gt;&lt;li&gt;The Marshaller property is implementation dependent.&lt;/li&gt;&lt;li&gt;When you use a standalone version of the JAXB Reference Implementation and not the one embedded in Oracle's JDK 6, the property name must be replaced by &lt;code&gt;com.sun.xml.bind.namespacePrefixMapper&lt;/code&gt;.&lt;/li&gt;&lt;/ul&gt;&lt;br /&gt;&lt;h3&gt;Solution 2&lt;/h3&gt;&lt;br /&gt;Manually create the &lt;code&gt;package-info.java&lt;/code&gt; source file which is normally generated by xjc:&lt;br /&gt;&lt;br /&gt;&lt;pre class="Java" name="code"&gt;@XmlSchema(namespace = "urn:example.com:foo",&lt;br /&gt;    xmlns = { &lt;br /&gt;        @XmlNs(namespaceURI = "http://example.com/namespaces/bar", prefix = "bar"),&lt;br /&gt;        @XmlNs(namespaceURI = "urn:example.com:foo", prefix = "")&lt;br /&gt;    },&lt;br /&gt;    elementFormDefault = javax.xml.bind.annotation.XmlNsForm.QUALIFIED)&lt;br /&gt;&lt;br /&gt;package com.example.foo.jaxb;&lt;br /&gt;&lt;br /&gt;import javax.xml.bind.annotation.XmlNs;&lt;br /&gt;import javax.xml.bind.annotation.XmlSchema;&lt;br /&gt;&lt;/pre&gt;&lt;br /&gt;&lt;br /&gt;This is enough to make the Marshaller use the prefixes defined in the &lt;code&gt;@XmlNs&lt;/code&gt; annotations.&lt;br /&gt;&lt;br /&gt;Now you only need to make sure that xjc does not overwrite or duplicate the &lt;code&gt;package-info.java&lt;/code&gt; source file by setting the &lt;code&gt;-npa&lt;/code&gt; option.&lt;br /&gt;&lt;br /&gt;Working with Maven and the &lt;code&gt;maven-jaxb2-plugin&lt;/code&gt;, you simply put your customized &lt;code&gt;package-info.java&lt;/code&gt; under &lt;code&gt;src/main/java&lt;/code&gt; and add the &lt;code&gt;-npa&lt;/code&gt; option to the plugin configuration:&lt;br /&gt;&lt;br /&gt;&lt;pre class="Xml" name="code"&gt;&amp;lt;plugin&amp;gt;&lt;br /&gt;        &amp;lt;groupId&amp;gt;org.jvnet.jaxb2.maven2&amp;lt;/groupId&amp;gt;&lt;br /&gt;        &amp;lt;artifactId&amp;gt;maven-jaxb2-plugin&amp;lt;/artifactId&amp;gt;&lt;br /&gt;        &amp;lt;version&amp;gt;0.7.5&amp;lt;/version&amp;gt;&lt;br /&gt;        &amp;lt;executions&amp;gt;&lt;br /&gt;          &amp;lt;execution&amp;gt;&lt;br /&gt;            &amp;lt;goals&amp;gt;&lt;br /&gt;              &amp;lt;goal&amp;gt;generate&amp;lt;/goal&amp;gt;&lt;br /&gt;            &amp;lt;/goals&amp;gt;&lt;br /&gt;          &amp;lt;/execution&amp;gt;&lt;br /&gt;        &amp;lt;/executions&amp;gt;&lt;br /&gt;        &amp;lt;configuration&amp;gt;&lt;br /&gt;          &amp;lt;extension&amp;gt;true&amp;lt;/extension&amp;gt;&lt;br /&gt;          &amp;lt;args&amp;gt;&lt;br /&gt;            &amp;lt;arg&amp;gt;-npa&amp;lt;/arg&amp;gt;&lt;br /&gt;          &amp;lt;/args&amp;gt;&lt;br /&gt;        &amp;lt;/configuration&amp;gt;&lt;br /&gt;      &amp;lt;/plugin&amp;gt;&lt;br /&gt;&lt;/pre&gt;&lt;br /&gt;&lt;b&gt;Update 21 March 2011:&lt;/b&gt; This approach does &lt;i&gt;not&lt;/i&gt; work with the JAXB version contained in Oracle's JDK 1.6.0_24. You have to use a more recent version of the JAXB reference implementation by including the following dependency:&lt;br /&gt;&lt;br /&gt;&lt;pre class="Xml" name="code"&gt;&amp;lt;dependency&gt;&lt;br /&gt;      &amp;lt;groupId&gt;com.sun.xml.bind&amp;lt;/groupId&gt;&lt;br /&gt;      &amp;lt;artifactId&gt;jaxb-impl&amp;lt;/artifactId&gt;&lt;br /&gt;      &amp;lt;version&gt;2.2.2&amp;lt;/version&gt;&lt;br /&gt;    &amp;lt;/dependency&gt;&lt;br /&gt;&lt;/pre&gt;&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/7836204352369514180-7958152484832834483?l=hwellmann.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://hwellmann.blogspot.com/feeds/7958152484832834483/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=7836204352369514180&amp;postID=7958152484832834483' title='6 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/7836204352369514180/posts/default/7958152484832834483'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/7836204352369514180/posts/default/7958152484832834483'/><link rel='alternate' type='text/html' href='http://hwellmann.blogspot.com/2011/03/jaxb-marshalling-with-custom-namespace.html' title='JAXB Marshalling with Custom Namespace Prefixes'/><author><name>Harald Wellmann</name><uri>http://www.blogger.com/profile/08039976160321882828</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='16' height='16' src='http://img2.blogblog.com/img/b16-rounded.gif'/></author><thr:total>6</thr:total></entry><entry><id>tag:blogger.com,1999:blog-7836204352369514180.post-3462105699352642704</id><published>2011-03-13T20:49:00.002+01:00</published><updated>2011-03-20T14:23:28.448+01:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='JMS'/><category scheme='http://www.blogger.com/atom/ns#' term='Camel'/><category scheme='http://www.blogger.com/atom/ns#' term='ActiveMQ'/><category scheme='http://www.blogger.com/atom/ns#' term='Spring'/><category scheme='http://www.blogger.com/atom/ns#' term='Glassfish'/><category scheme='http://www.blogger.com/atom/ns#' term='Java EE 6'/><title type='text'>Transparent Asynchronous Remoting via JMS</title><content type='html'>&lt;h3&gt;The Scenario&lt;/h3&gt;&lt;br /&gt;A client needs to invoke a service interface with the following restrictions:&lt;br /&gt;&lt;ul&gt;&lt;li&gt;The service implementation is running on a &lt;b&gt;remote&lt;/b&gt; machine.&lt;/li&gt;&lt;li&gt;This fact is &lt;b&gt;transparent&lt;/b&gt; to the client, i.e. any service method invocation is just like a local method invocation.&lt;/li&gt;&lt;li&gt;The service methods are executed &lt;b&gt;asychronously&lt;/b&gt; on the server, method invocations on the client return immediately (fire-and-forget).&lt;/li&gt;&lt;li&gt;All service methods have void return types.&lt;/li&gt;&lt;li&gt;The service invocations shall be transported &lt;b&gt;via JMS.&lt;/b&gt; &lt;/li&gt;&lt;/ul&gt;&lt;br /&gt;&lt;a name='more'&gt;&lt;/a&gt;&lt;br /&gt;&lt;h3&gt;Background&lt;/h3&gt;&lt;br /&gt;The post is a sequel to my previous article on &lt;a href="http://hwellmann.blogspot.com/2011/01/transparent-asynchronous-remoting.html"&gt;Transparent Asynchronous Remoting&lt;/a&gt;, the only difference in this scenario is the addition of the JMS requirement.&lt;br /&gt;&lt;br /&gt;This sounds more like an implementation detail than a requirement, but in fact there can be good reasons for mandating the use of JMS, e.g.&lt;br /&gt;&lt;ul&gt;&lt;li&gt;You want to decouple service providers and clients: a client may  invoke a service method even when the service provider is temporarily  not available.&lt;/li&gt;&lt;li&gt;The system's communication infrastructure is based on JMS anyway.&lt;/li&gt;&lt;li&gt;You want to monitor the communication.&lt;/li&gt;&lt;/ul&gt;&lt;h3&gt;The Solution with Apache Camel, Spring and Glassfish MQ&lt;/h3&gt;There is no out-of-the box solution for this scenario either in Java EE 6 or in Spring.&lt;br /&gt;&lt;br /&gt;Java EE 6 has an &lt;span style="font-family: &amp;quot;Courier New&amp;quot;,Courier,monospace;"&gt;@Async&lt;/span&gt; annotation for asynchronous invocations of remote EJBs, but there is no way to use a JMS transport simply by configuration. &lt;br /&gt;&lt;br /&gt;&lt;a href="http://static.springsource.org/spring/docs/3.0.x/spring-framework-reference/html/remoting.html"&gt;Spring Remoting&lt;/a&gt;  provides transparent proxies for remote services using various transports, &lt;a href="http://static.springsource.org/spring/docs/3.0.x/spring-framework-reference/htmlsingle/spring-framework-reference.html#remoting-jms"&gt;including JMS&lt;/a&gt;, but these proxies are  always synchronous. &lt;br /&gt;&lt;br /&gt;I've tried to solve this problem by modifying or extending some of the Spring JMS helper classes, but this turned out to be not quite trivial. The next thing I tried was Spring Integration, but this seems to be lacking the transparent proxy feature and only provides a partial solution for services with single-parameter methods.&lt;br /&gt;&lt;br /&gt;In the end, I turned to &lt;a href="http://camel.apache.org/"&gt;Apache Camel&lt;/a&gt;, which solves the problem rather nicely, once you find the relevant bits of example code and documentation. &lt;a href="http://svn.apache.org/viewvc/camel/tags/camel-2.6.0/examples/camel-example-spring-jms/"&gt;camel-example-spring-jms&lt;/a&gt; was a good starting point. The setup explained in the rest of this post differs from the Camel example in the following points:&lt;br /&gt;&lt;ul&gt;&lt;li&gt;The communication is asynchronous.&lt;/li&gt;&lt;li&gt;The Spring contexts are defined by&amp;nbsp; Java Configuration instead of XML.&lt;/li&gt;&lt;li&gt;The JMS provider is Glassfish MQ, not Active MQ.&lt;/li&gt;&lt;li&gt;Apache Commons Logging is replaced by slf4j and logback.&lt;/li&gt;&lt;li&gt;Dependency injection is based on the JSR-330 &lt;span style="font-family: &amp;quot;Courier New&amp;quot;,Courier,monospace;"&gt;@Inject&lt;/span&gt; annotation.&lt;/li&gt;&lt;/ul&gt;&lt;h4&gt;Overview&lt;/h4&gt;&lt;br /&gt;Apache Camel can be regarded as a giant plumbing framework for message-based communication between endpoints of all sorts. You create &lt;i&gt;endpoints&lt;/i&gt; supporting a given communication protocol, you connect them with &lt;i&gt;routes&lt;/i&gt;, and you may insert &lt;i&gt;filters&lt;/i&gt; to modify the messages on their way.&lt;br /&gt;&lt;br /&gt;Camel directly supports Spring beans as endpoints and uses proxies to adapt method invocations to Camel messages and vice versa. Hence, the setup for our scenario is rather similar to Spring Remoting.&lt;br /&gt;&lt;br /&gt;On the server side, the service implementations are wrapped in proxies which are connected to JMS queues by Camel routes.&lt;br /&gt;&lt;br /&gt;On the client side, you create proxies for the remote services and inject them into your application classes. The proxies are directly connected to JMS service URLs.&lt;br /&gt;&lt;br /&gt;In addition, you need a JMS provider. The original Camel/Spring/JMS example uses an &lt;a href="http://activemq.apache.org/"&gt;ActiveMQ&lt;/a&gt; broker embedded into the server. I'm using a stand-alone Glassfish MQ broker, just to show that Camel also works with other JMS implementations.&lt;br /&gt;&lt;br /&gt;&lt;h4&gt;The API&lt;/h4&gt;&lt;br /&gt;Following the tradition of "Hello World" examples, we create a &lt;code&gt;HelloService&lt;/code&gt; to say hello to a given person, and we add a &lt;code&gt;GoodbyeService&lt;/code&gt;.&lt;br /&gt;&lt;br /&gt;&lt;pre class="Java" name="code"&gt;package com.blogspot.hwellmann.camel.greeter.api;&lt;br /&gt;&lt;br /&gt;@InOnly &lt;br /&gt;public interface HelloService {&lt;br /&gt;    void sayHello(Person person);&lt;br /&gt;}&lt;/pre&gt;&lt;br /&gt;&lt;pre class="Java" name="code"&gt;package com.blogspot.hwellmann.camel.greeter.api;&lt;br /&gt;&lt;br /&gt;@InOnly &lt;br /&gt;public interface GoodbyeService {&lt;br /&gt;    void sayGoodbye(Person person);&lt;br /&gt;}&lt;/pre&gt;&lt;br /&gt;&lt;code&gt;@InOnly&lt;/code&gt; is a Camel annotation indicating that a given method or, in this case, all methods of the given interface, take input parameters only and that the caller shall not wait for any reply. Thanks to this annotation,&amp;nbsp; our scenario is indeed asynchronous.&lt;br /&gt;&lt;br /&gt;By default, Camel uses standard Java  serialization for transporting method parameters, so all parameter  objects need to be &lt;code&gt;Serializable&lt;/code&gt;:&lt;br /&gt;&lt;br /&gt;&lt;pre class="Java" name="code"&gt;package com.blogspot.hwellmann.camel.greeter.api;&lt;br /&gt;&lt;br /&gt;import java.io.Serializable;&lt;br /&gt;&lt;br /&gt;public class Person implements Serializable {&lt;br /&gt;&lt;br /&gt;    private static final long serialVersionUID = 1L;&lt;br /&gt;&lt;br /&gt;    private String firstName;&lt;br /&gt;    private String lastName;&lt;br /&gt;     &lt;br /&gt;    public Person(String firstName, String lastName) {&lt;br /&gt;        this.firstName = firstName;&lt;br /&gt;        this.lastName = lastName;&lt;br /&gt;    }&lt;br /&gt;&lt;br /&gt;    // ...getters and setters...&lt;br /&gt;}&lt;/pre&gt;&lt;br /&gt;&lt;h4&gt;The Server&lt;/h4&gt;&lt;br /&gt;&lt;pre class="Java" name="code"&gt;package com.blogspot.hwellmann.camel.greeter.server;&lt;br /&gt;&lt;br /&gt;public class HelloServiceImpl implements HelloService {&lt;br /&gt;&lt;br /&gt;    public void sayHello(Person person) {&lt;br /&gt;        try {&lt;br /&gt;            Thread.sleep(1000);&lt;br /&gt;            System.out.println(String.format("Hello, %s %s!", &lt;br /&gt;                    person.getFirstName(), person.getLastName()));&lt;br /&gt;        }&lt;br /&gt;        catch (InterruptedException e) {&lt;br /&gt;            e.printStackTrace();&lt;br /&gt;        }&lt;br /&gt;    }&lt;br /&gt;}&lt;/pre&gt;&lt;br /&gt;The &lt;span style="font-family: &amp;quot;Courier New&amp;quot;,Courier,monospace;"&gt;GoodbyeService&lt;/span&gt; is just the same. Now here is the Spring configuration for the server:&lt;br /&gt;&lt;br /&gt;&lt;pre class="Xml" name="code"&gt;&amp;lt;?xml version="1.0" encoding="UTF-8"?&amp;gt;&lt;br /&gt;&amp;lt;beans xmlns="http://www.springframework.org/schema/beans" &lt;br /&gt;  xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"&lt;br /&gt;  xmlns:context="http://www.springframework.org/schema/context" &lt;br /&gt;  xsi:schemaLocation="http://www.springframework.org/schema/beans&lt;br /&gt;         http://www.springframework.org/schema/beans/spring-beans-3.0.xsd&lt;br /&gt;         http://www.springframework.org/schema/context&lt;br /&gt;         http://www.springframework.org/schema/context/spring-context-3.0.xsd"&amp;gt;&lt;br /&gt;&lt;br /&gt;  &amp;lt;context:annotation-config  /&amp;gt;&lt;br /&gt;  &amp;lt;bean class="com.blogspot.hwellmann.camel.greeter.server.GreeterServerSpringConfig"/&amp;gt;&lt;br /&gt;&lt;br /&gt;&amp;lt;/beans&amp;gt;&lt;/pre&gt;&lt;br /&gt;&lt;pre class="Java" name="code"&gt;package com.blogspot.hwellmann.camel.greeter.server;&lt;br /&gt;&lt;br /&gt;@Configuration&lt;br /&gt;public class GreeterServerSpringConfig {&lt;br /&gt;    &lt;br /&gt;    @Inject&lt;br /&gt;    private ApplicationContext applicationContext;&lt;br /&gt;&lt;br /&gt;    @Bean&lt;br /&gt;    public ConnectionFactory cf() throws JMSException {&lt;br /&gt;        com.sun.messaging.ConnectionFactory cf = new com.sun.messaging.ConnectionFactory();&lt;br /&gt;        cf.setProperty(ConnectionConfiguration.imqAddressList, "localhost:7676");&lt;br /&gt;        return cf;&lt;br /&gt;    }&lt;br /&gt;    &lt;br /&gt;    @Bean&lt;br /&gt;    public HelloService helloService() {&lt;br /&gt;        return new HelloServiceImpl();&lt;br /&gt;    }&lt;br /&gt;    &lt;br /&gt;    @Bean&lt;br /&gt;    public GoodbyeService goodbyeService() {&lt;br /&gt;        return new GoodbyeServiceImpl();&lt;br /&gt;    }&lt;br /&gt;    &lt;br /&gt;    @Bean&lt;br /&gt;    public JmsComponent jms() throws JMSException {&lt;br /&gt;        JmsComponent jms = new JmsComponent();&lt;br /&gt;        jms.setConnectionFactory(cf());&lt;br /&gt;        return jms;&lt;br /&gt;    }&lt;br /&gt;    &lt;br /&gt;    @Bean&lt;br /&gt;    public RouteBuilder serverRoutes() {&lt;br /&gt;        return new ServerRoutes();&lt;br /&gt;    }&lt;br /&gt;    &lt;br /&gt;    @Bean&lt;br /&gt;    public CamelContext camelContext() throws Exception {&lt;br /&gt;        CamelContextFactoryBean factory = new CamelContextFactoryBean();&lt;br /&gt;        factory.setApplicationContext(applicationContext);&lt;br /&gt;        factory.setId("jms-server");&lt;br /&gt;        SpringCamelContext context = factory.getContext();&lt;br /&gt;        serverRoutes().addRoutesToCamelContext(context);&lt;br /&gt;        return context;&lt;br /&gt;    }    &lt;br /&gt;}&lt;br /&gt;&lt;br /&gt;&lt;/pre&gt;The &lt;code&gt;ServerRoutes&lt;/code&gt; bean defines two simple Camel routes connecting the JMS queues to our service implementations:&lt;br /&gt;&lt;br /&gt;&lt;pre class="Java" name="code"&gt;package com.blogspot.hwellmann.camel.greeter.server;&lt;br /&gt;&lt;br /&gt;import org.apache.camel.builder.RouteBuilder;&lt;br /&gt;&lt;br /&gt;public class ServerRoutes extends RouteBuilder {&lt;br /&gt;    &lt;br /&gt;    @Override&lt;br /&gt;    public void configure() throws Exception {&lt;br /&gt;        from("jms:queue:hello").to("helloService");&lt;br /&gt;        from("jms:queue:goodbye").to("goodbyeService");&lt;br /&gt;    }&lt;br /&gt;}&lt;br /&gt;&lt;/pre&gt;&lt;br /&gt;Camel has its own &lt;code&gt;org.apache.camel.spring.Main&lt;/code&gt; class which by default creates a Spring application context from all XML files found in &lt;code&gt;META-INF/spring&lt;/code&gt; on the classpath. This is enough to launch the server.&lt;br /&gt;&lt;br /&gt;In addition, you need to launch the Glassfish MQ message broker on the default port 7676. To do so, you can simply start a complete Glassfish instance, which has an embedded MQ broker, or you may use a standalone Glassfish MQ broker by running &lt;code&gt;GLASSFISH_HOME/mq/bin/imqbrokerd&lt;/code&gt;, where &lt;code&gt;GLASSFISH_HOME&lt;/code&gt; refers to your Glassfish installation directory. (Tested with Glassfish 3.1 and Glassfish 3.0.1).&lt;br /&gt;&lt;br /&gt;&lt;h4&gt;The Client&lt;/h4&gt;&lt;br /&gt;This is the client for saying hello and goodbye to three persons:&lt;br /&gt;&lt;br /&gt;&lt;pre class="Java" name="code"&gt;package com.blogspot.hwellmann.camel.greeter.client;&lt;br /&gt;&lt;br /&gt;public class GreeterClient implements Runnable {&lt;br /&gt;    &lt;br /&gt;    private static Logger log = LoggerFactory.getLogger(GreeterClient.class);&lt;br /&gt;&lt;br /&gt;    @Inject&lt;br /&gt;    private HelloService helloProxy;&lt;br /&gt;    &lt;br /&gt;    @Inject&lt;br /&gt;    private GoodbyeService goodbyeProxy;&lt;br /&gt;    &lt;br /&gt;    private Person donald = new Person("Donald", "Duck");&lt;br /&gt;    private Person mickey = new Person("Mickey", "Mouse");&lt;br /&gt;    private Person charlie = new Person("Charlie", "Brown");&lt;br /&gt;&lt;br /&gt;    public void run() {&lt;br /&gt;        log.info("invoking greeter");&lt;br /&gt;        &lt;br /&gt;        helloProxy.sayHello(donald);&lt;br /&gt;        helloProxy.sayHello(mickey);&lt;br /&gt;        helloProxy.sayHello(charlie);&lt;br /&gt;&lt;br /&gt;        goodbyeProxy.sayGoodbye(donald);&lt;br /&gt;        goodbyeProxy.sayGoodbye(mickey);&lt;br /&gt;        goodbyeProxy.sayGoodbye(charlie);&lt;br /&gt;&lt;br /&gt;        log.info("done");&lt;br /&gt;    }&lt;br /&gt;        &lt;br /&gt;    public static void main(String[] args) {&lt;br /&gt;        ApplicationContext context = new AnnotationConfigApplicationContext(GreeterClientSpringConfig.class);&lt;br /&gt;        GreeterClient client = context.getBean(GreeterClient.class);&lt;br /&gt;        client.run();&lt;br /&gt;    }    &lt;br /&gt;}&lt;br /&gt;&lt;br /&gt;&lt;/pre&gt;&lt;br /&gt;Look Mum, no XML! The Spring application context for the client is completely defined in a Java configuration class:&lt;br /&gt;&lt;br /&gt;&lt;pre class="Java" name="code"&gt;package com.blogspot.hwellmann.camel.greeter.client;&lt;br /&gt;&lt;br /&gt;@Configuration&lt;br /&gt;public class GreeterClientSpringConfig {&lt;br /&gt;    &lt;br /&gt;    @Inject&lt;br /&gt;    private ApplicationContext applicationContext;&lt;br /&gt;&lt;br /&gt;    @Bean&lt;br /&gt;    public ConnectionFactory cf() throws JMSException {&lt;br /&gt;        com.sun.messaging.ConnectionFactory cf = new com.sun.messaging.ConnectionFactory();&lt;br /&gt;        cf.setProperty(ConnectionConfiguration.imqAddressList, "localhost:7676");&lt;br /&gt;        return cf;&lt;br /&gt;    }&lt;br /&gt;    &lt;br /&gt;    @Bean&lt;br /&gt;    public GreeterClient greeterClient() {&lt;br /&gt;        return new GreeterClient();&lt;br /&gt;    }&lt;br /&gt;    &lt;br /&gt;    @Bean&lt;br /&gt;    public JmsComponent jms() throws JMSException {&lt;br /&gt;        JmsComponent jms = new JmsComponent();&lt;br /&gt;        jms.setConnectionFactory(cf());&lt;br /&gt;        return jms;&lt;br /&gt;    }&lt;br /&gt;    &lt;br /&gt;    @Bean&lt;br /&gt;    public HelloService helloProxy() throws Exception {&lt;br /&gt;        CamelProxyFactoryBean factory = new CamelProxyFactoryBean();&lt;br /&gt;        factory.setServiceInterface(HelloService.class);&lt;br /&gt;        factory.setServiceUrl("jms:queue:hello");&lt;br /&gt;        factory.setCamelContext(camelContext());&lt;br /&gt;        factory.afterPropertiesSet();&lt;br /&gt;        return (HelloService) factory.getObject();&lt;br /&gt;    }&lt;br /&gt;    &lt;br /&gt;    @Bean&lt;br /&gt;    public GoodbyeService goodbyeProxy() throws Exception {&lt;br /&gt;        CamelProxyFactoryBean factory = new CamelProxyFactoryBean();&lt;br /&gt;        factory.setServiceInterface(GoodbyeService.class);&lt;br /&gt;        factory.setServiceUrl("jms:queue:goodbye");&lt;br /&gt;        factory.setCamelContext(camelContext());&lt;br /&gt;        factory.afterPropertiesSet();&lt;br /&gt;        return (GoodbyeService) factory.getObject();&lt;br /&gt;    }&lt;br /&gt;    &lt;br /&gt;    @Bean&lt;br /&gt;    public CamelContext camelContext() throws Exception {&lt;br /&gt;        CamelContextFactoryBean factory = new CamelContextFactoryBean();&lt;br /&gt;        factory.setApplicationContext(applicationContext);&lt;br /&gt;        factory.setId("jms-client");&lt;br /&gt;        factory.afterPropertiesSet();&lt;br /&gt;        return (CamelContext) factory.getObject();&lt;br /&gt;    }&lt;br /&gt;}&lt;br /&gt;&lt;br /&gt;&lt;/pre&gt;&lt;br /&gt;&lt;h4&gt;The POM&lt;/h4&gt;&lt;br /&gt;&lt;pre class="Xml" name="code"&gt;&amp;lt;project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"&lt;br /&gt;  xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd"&amp;gt;&lt;br /&gt;  &amp;lt;modelVersion&amp;gt;4.0.0&amp;lt;/modelVersion&amp;gt;&lt;br /&gt;  &amp;lt;groupId&amp;gt;com.blogspot.hwellmann&amp;lt;/groupId&amp;gt;&lt;br /&gt;  &amp;lt;artifactId&amp;gt;spring-camel-jms&amp;lt;/artifactId&amp;gt;&lt;br /&gt;  &amp;lt;version&amp;gt;0.0.1&amp;lt;/version&amp;gt;&lt;br /&gt;  &amp;lt;name&amp;gt;Spring Camel JMS Example&amp;lt;/name&amp;gt;&lt;br /&gt;  &amp;lt;properties&amp;gt;&lt;br /&gt;    &amp;lt;camel.version&amp;gt;2.6.0&amp;lt;/camel.version&amp;gt;&lt;br /&gt;    &amp;lt;spring.version&amp;gt;3.0.5.RELEASE&amp;lt;/spring.version&amp;gt;&lt;br /&gt;  &amp;lt;/properties&amp;gt;&lt;br /&gt;  &amp;lt;dependencies&amp;gt;&lt;br /&gt;    &amp;lt;dependency&amp;gt;&lt;br /&gt;      &amp;lt;groupId&amp;gt;org.apache.camel&amp;lt;/groupId&amp;gt;&lt;br /&gt;      &amp;lt;artifactId&amp;gt;camel-core&amp;lt;/artifactId&amp;gt;&lt;br /&gt;      &amp;lt;version&amp;gt;${camel.version}&amp;lt;/version&amp;gt;&lt;br /&gt;      &amp;lt;exclusions&amp;gt;&lt;br /&gt;        &amp;lt;exclusion&amp;gt;&lt;br /&gt;          &amp;lt;groupId&amp;gt;commons-logging&amp;lt;/groupId&amp;gt;&lt;br /&gt;          &amp;lt;artifactId&amp;gt;commons-logging-api&amp;lt;/artifactId&amp;gt;&lt;br /&gt;        &amp;lt;/exclusion&amp;gt;&lt;br /&gt;      &amp;lt;/exclusions&amp;gt;&lt;br /&gt;    &amp;lt;/dependency&amp;gt;&lt;br /&gt;    &amp;lt;dependency&amp;gt;&lt;br /&gt;      &amp;lt;groupId&amp;gt;org.apache.camel&amp;lt;/groupId&amp;gt;&lt;br /&gt;      &amp;lt;artifactId&amp;gt;camel-jms&amp;lt;/artifactId&amp;gt;&lt;br /&gt;      &amp;lt;version&amp;gt;${camel.version}&amp;lt;/version&amp;gt;&lt;br /&gt;    &amp;lt;/dependency&amp;gt;&lt;br /&gt;    &amp;lt;dependency&amp;gt;&lt;br /&gt;      &amp;lt;groupId&amp;gt;org.springframework&amp;lt;/groupId&amp;gt;&lt;br /&gt;      &amp;lt;artifactId&amp;gt;spring-context&amp;lt;/artifactId&amp;gt;&lt;br /&gt;      &amp;lt;version&amp;gt;${spring.version}&amp;lt;/version&amp;gt;&lt;br /&gt;    &amp;lt;/dependency&amp;gt;&lt;br /&gt;    &amp;lt;dependency&amp;gt;&lt;br /&gt;      &amp;lt;groupId&amp;gt;org.springframework&amp;lt;/groupId&amp;gt;&lt;br /&gt;      &amp;lt;artifactId&amp;gt;spring-core&amp;lt;/artifactId&amp;gt;&lt;br /&gt;      &amp;lt;version&amp;gt;${spring.version}&amp;lt;/version&amp;gt;&lt;br /&gt;      &amp;lt;exclusions&amp;gt;&lt;br /&gt;        &amp;lt;exclusion&amp;gt;&lt;br /&gt;          &amp;lt;groupId&amp;gt;commons-logging&amp;lt;/groupId&amp;gt;&lt;br /&gt;          &amp;lt;artifactId&amp;gt;commons-logging&amp;lt;/artifactId&amp;gt;&lt;br /&gt;        &amp;lt;/exclusion&amp;gt;&lt;br /&gt;      &amp;lt;/exclusions&amp;gt;&lt;br /&gt;    &amp;lt;/dependency&amp;gt;&lt;br /&gt;    &amp;lt;dependency&amp;gt;&lt;br /&gt;      &amp;lt;groupId&amp;gt;org.apache.servicemix.bundles&amp;lt;/groupId&amp;gt;&lt;br /&gt;      &amp;lt;artifactId&amp;gt;org.apache.servicemix.bundles.cglib&amp;lt;/artifactId&amp;gt;&lt;br /&gt;      &amp;lt;version&amp;gt;2.2_1&amp;lt;/version&amp;gt;&lt;br /&gt;    &amp;lt;/dependency&amp;gt;    &lt;br /&gt;    &amp;lt;dependency&amp;gt;&lt;br /&gt;      &amp;lt;groupId&amp;gt;org.apache.geronimo.specs&amp;lt;/groupId&amp;gt;&lt;br /&gt;      &amp;lt;artifactId&amp;gt;geronimo-atinject_1.0_spec&amp;lt;/artifactId&amp;gt;&lt;br /&gt;      &amp;lt;version&amp;gt;1.0&amp;lt;/version&amp;gt;&lt;br /&gt;    &amp;lt;/dependency&amp;gt;&lt;br /&gt;    &amp;lt;dependency&amp;gt;&lt;br /&gt;      &amp;lt;groupId&amp;gt;org.slf4j&amp;lt;/groupId&amp;gt;&lt;br /&gt;      &amp;lt;artifactId&amp;gt;slf4j-api&amp;lt;/artifactId&amp;gt;&lt;br /&gt;      &amp;lt;version&amp;gt;1.6.0&amp;lt;/version&amp;gt;&lt;br /&gt;    &amp;lt;/dependency&amp;gt;&lt;br /&gt;    &amp;lt;dependency&amp;gt;&lt;br /&gt;      &amp;lt;groupId&amp;gt;org.slf4j&amp;lt;/groupId&amp;gt;&lt;br /&gt;      &amp;lt;artifactId&amp;gt;jcl-over-slf4j&amp;lt;/artifactId&amp;gt;&lt;br /&gt;      &amp;lt;version&amp;gt;1.6.0&amp;lt;/version&amp;gt;&lt;br /&gt;    &amp;lt;/dependency&amp;gt;&lt;br /&gt;    &amp;lt;dependency&amp;gt;&lt;br /&gt;      &amp;lt;groupId&amp;gt;ch.qos.logback&amp;lt;/groupId&amp;gt;&lt;br /&gt;      &amp;lt;artifactId&amp;gt;logback-core&amp;lt;/artifactId&amp;gt;&lt;br /&gt;      &amp;lt;version&amp;gt;0.9.28&amp;lt;/version&amp;gt;&lt;br /&gt;    &amp;lt;/dependency&amp;gt;&lt;br /&gt;    &amp;lt;dependency&amp;gt;&lt;br /&gt;      &amp;lt;groupId&amp;gt;ch.qos.logback&amp;lt;/groupId&amp;gt;&lt;br /&gt;      &amp;lt;artifactId&amp;gt;logback-classic&amp;lt;/artifactId&amp;gt;&lt;br /&gt;      &amp;lt;version&amp;gt;0.9.28&amp;lt;/version&amp;gt;&lt;br /&gt;    &amp;lt;/dependency&amp;gt;&lt;br /&gt;    &amp;lt;dependency&amp;gt;&lt;br /&gt;      &amp;lt;groupId&amp;gt;com.sun.messaging.mq&amp;lt;/groupId&amp;gt;&lt;br /&gt;      &amp;lt;artifactId&amp;gt;imq&amp;lt;/artifactId&amp;gt;&lt;br /&gt;      &amp;lt;version&amp;gt;4.4.2&amp;lt;/version&amp;gt;&lt;br /&gt;    &amp;lt;/dependency&amp;gt;&lt;br /&gt;  &amp;lt;/dependencies&amp;gt;&lt;br /&gt;  &amp;lt;build&amp;gt;&lt;br /&gt;    &amp;lt;plugins&amp;gt;&lt;br /&gt;      &amp;lt;plugin&amp;gt;&lt;br /&gt;        &amp;lt;groupId&amp;gt;org.apache.maven.plugins&amp;lt;/groupId&amp;gt;&lt;br /&gt;        &amp;lt;artifactId&amp;gt;maven-compiler-plugin&amp;lt;/artifactId&amp;gt;&lt;br /&gt;        &amp;lt;configuration&amp;gt;&lt;br /&gt;          &amp;lt;source&amp;gt;1.6&amp;lt;/source&amp;gt;&lt;br /&gt;          &amp;lt;target&amp;gt;1.6&amp;lt;/target&amp;gt;&lt;br /&gt;        &amp;lt;/configuration&amp;gt;&lt;br /&gt;      &amp;lt;/plugin&amp;gt;&lt;br /&gt;    &amp;lt;/plugins&amp;gt;&lt;br /&gt;  &amp;lt;/build&amp;gt;&lt;br /&gt;&amp;lt;/project&amp;gt;&lt;br /&gt;&lt;/pre&gt;&lt;br /&gt;&lt;h4&gt;Running the example&lt;/h4&gt;&lt;br /&gt;Now if you start the broker, the server and the client in this order, you'll see the following output from the client...&lt;br /&gt;&lt;br /&gt;&lt;pre&gt;20:21:46.789 [main] INFO  c.b.h.c.greeter.client.GreeterClient - invoking greeter&lt;br /&gt;20:21:47.016 [main] INFO  c.b.h.c.greeter.client.GreeterClient - done&lt;br /&gt;&lt;/pre&gt;&lt;br /&gt;...and from the server:&lt;br /&gt;&lt;br /&gt;&lt;pre&gt;20:21:47.976 [DefaultMessageListenerContainer-1] INFO  c.b.h.c.g.server.HelloServiceImpl - Hello, Donald Duck!&lt;br /&gt;20:21:47.995 [DefaultMessageListenerContainer-1] INFO  c.b.h.c.g.server.GoodbyeServiceImpl - Goodbye, Donald Duck!&lt;br /&gt;20:21:48.998 [DefaultMessageListenerContainer-1] INFO  c.b.h.c.g.server.HelloServiceImpl - Hello, Mickey Mouse!&lt;br /&gt;20:21:49.003 [DefaultMessageListenerContainer-1] INFO  c.b.h.c.g.server.GoodbyeServiceImpl - Goodbye, Mickey Mouse!&lt;br /&gt;20:21:50.005 [DefaultMessageListenerContainer-1] INFO  c.b.h.c.g.server.HelloServiceImpl - Hello, Charlie Brown!&lt;br /&gt;20:21:50.009 [DefaultMessageListenerContainer-1] INFO  c.b.h.c.g.server.GoodbyeServiceImpl - Goodbye, Charlie Brown!&lt;br /&gt;&lt;/pre&gt;&lt;br /&gt;The client terminates before the server has even processed the first message. By default, Camel generates a single-threaded consumer for each queue, so the order of the Hellos is preserved, but they get processed in parallel with the Goodbyes.&lt;br /&gt;&lt;br /&gt;&lt;h3&gt;Conclusion&lt;/h3&gt;&lt;br /&gt;Using either Java EE 6 or Spring 3, the standard framework APIs are  not sufficient to implement transparent asynchronous communication via JMS. &lt;br /&gt;&lt;br /&gt;However, with Apache Camel on top of Spring 3, a plug-and-play solution is easy to set up.&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/7836204352369514180-3462105699352642704?l=hwellmann.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://hwellmann.blogspot.com/feeds/3462105699352642704/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=7836204352369514180&amp;postID=3462105699352642704' title='2 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/7836204352369514180/posts/default/3462105699352642704'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/7836204352369514180/posts/default/3462105699352642704'/><link rel='alternate' type='text/html' href='http://hwellmann.blogspot.com/2011/03/transparent-asynchronous-remoting-via.html' title='Transparent Asynchronous Remoting via JMS'/><author><name>Harald Wellmann</name><uri>http://www.blogger.com/profile/08039976160321882828</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='16' height='16' src='http://img2.blogblog.com/img/b16-rounded.gif'/></author><thr:total>2</thr:total></entry><entry><id>tag:blogger.com,1999:blog-7836204352369514180.post-7923275310371367462</id><published>2011-02-20T19:54:00.000+01:00</published><updated>2011-02-20T19:54:36.793+01:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='MySQL'/><category scheme='http://www.blogger.com/atom/ns#' term='Fun'/><title type='text'>Hamburg Elections Powered by MySQL</title><content type='html'>Following a link on Google to the intermediate results of today's elections in Hamburg on the official website of Statistikamt Nord (Hamburg and Schleswig-Holstein Statistics Office), I found this:&lt;br /&gt;&lt;br /&gt;&lt;div class="separator" style="clear: both; text-align: center;"&gt;&lt;a href="http://4.bp.blogspot.com/-7hanHYBBJvw/TWFiizkHF3I/AAAAAAAAADE/niDZ9v6UxXA/s1600/HamburgWahl.png" imageanchor="1" style="margin-left: 1em; margin-right: 1em;"&gt;&lt;img border="0" height="500" src="http://4.bp.blogspot.com/-7hanHYBBJvw/TWFiizkHF3I/AAAAAAAAADE/niDZ9v6UxXA/s640/HamburgWahl.png" width="640" /&gt;&lt;/a&gt;&lt;/div&gt;&lt;br /&gt;Ok, the good news is that our taxes don't get wasted on expensive Oracle licenses...&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/7836204352369514180-7923275310371367462?l=hwellmann.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://hwellmann.blogspot.com/feeds/7923275310371367462/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=7836204352369514180&amp;postID=7923275310371367462' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/7836204352369514180/posts/default/7923275310371367462'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/7836204352369514180/posts/default/7923275310371367462'/><link rel='alternate' type='text/html' href='http://hwellmann.blogspot.com/2011/02/hamburg-elections-powered-by-mysql.html' title='Hamburg Elections Powered by MySQL'/><author><name>Harald Wellmann</name><uri>http://www.blogger.com/profile/08039976160321882828</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='16' height='16' src='http://img2.blogblog.com/img/b16-rounded.gif'/></author><media:thumbnail xmlns:media='http://search.yahoo.com/mrss/' url='http://4.bp.blogspot.com/-7hanHYBBJvw/TWFiizkHF3I/AAAAAAAAADE/niDZ9v6UxXA/s72-c/HamburgWahl.png' height='72' width='72'/><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-7836204352369514180.post-4588680469744817793</id><published>2011-02-20T14:36:00.002+01:00</published><updated>2011-12-20T12:19:07.426+01:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='Wicket'/><category scheme='http://www.blogger.com/atom/ns#' term='Spring'/><category scheme='http://www.blogger.com/atom/ns#' term='JPA'/><category scheme='http://www.blogger.com/atom/ns#' term='Java EE 6'/><title type='text'>Building a Web Application with Wicket, Spring and JPA</title><content type='html'>This is a tutorial on setting up a web application stack with Wicket, Spring and JPA, with a special focus on avoiding Spring XML configuration in favour of Java configuration, and on using the JSR-330 &lt;span style="font-family: &amp;quot;Courier New&amp;quot;,Courier,monospace;"&gt;@Inject&lt;/span&gt; annotation both in the web and service layers.&lt;br /&gt;&lt;br /&gt;Martijn Dashorst's blog on &lt;a href="http://wicketinaction.com/2009/06/wicketspringhibernate-configuration/"&gt;Wicket/Spring/Hibernate configuration&lt;/a&gt;was the starting point for my setup, and as I hate &lt;i&gt;"oodles of XML"&lt;/i&gt;&amp;nbsp; as much as he does, I replaced all the XML bean declarations by a &lt;span style="font-family: &amp;quot;Courier New&amp;quot;,Courier,monospace;"&gt;@Configuration&lt;/span&gt; class, a new feature in Spring 3.0.x.&lt;br /&gt;&lt;br /&gt;&lt;a name='more'&gt;&lt;/a&gt;&lt;br /&gt;Let us start with the &lt;code&gt;web.xml&lt;/code&gt; deployment descriptor, for hooking both Wicket and Spring into our servlet container: &lt;br /&gt;&lt;br /&gt;&lt;pre class="Xml" name="code"&gt;&amp;lt;?xml version="1.0" encoding="UTF-8"?&amp;gt;&lt;br /&gt;&amp;lt;web-app xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"&amp;nbsp;&lt;br /&gt;  xmlns="http://java.sun.com/xml/ns/javaee"&lt;br /&gt;  xmlns:web="http://java.sun.com/xml/ns/javaee/web-app_2_5.xsd" &lt;br /&gt;  xsi:schemaLocation="http://java.sun.com/xml/ns/javaee http://java.sun.com/xml/ns/javaee/web-app_2_5.xsd"&lt;br /&gt;  version="2.5"&amp;gt;&lt;br /&gt;  &lt;br /&gt;  &lt;br /&gt;  &amp;lt;display-name&amp;gt;WicketSpring&amp;lt;/display-name&amp;gt;&lt;br /&gt;&lt;br /&gt;  &amp;lt;context-param&amp;gt;&lt;br /&gt;    &amp;lt;param-name&amp;gt;contextConfigLocation&amp;lt;/param-name&amp;gt;&lt;br /&gt;    &amp;lt;param-value&amp;gt;WEB-INF/app-context.xml&amp;lt;/param-value&amp;gt;&lt;br /&gt;  &amp;lt;/context-param&amp;gt;&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;  &amp;lt;filter&amp;gt;&lt;br /&gt;    &amp;lt;filter-name&amp;gt;WicketSpring&amp;lt;/filter-name&amp;gt;&lt;br /&gt;    &amp;lt;filter-class&amp;gt;org.apache.wicket.protocol.http.WicketFilter&amp;lt;/filter-class&amp;gt;&lt;br /&gt;    &amp;lt;init-param&amp;gt;&lt;br /&gt;      &amp;lt;param-name&amp;gt;applicationFactoryClassName&amp;lt;/param-name&amp;gt;&lt;br /&gt;      &amp;lt;param-value&amp;gt;org.apache.wicket.spring.SpringWebApplicationFactory&amp;lt;/param-value&amp;gt;&lt;br /&gt;    &amp;lt;/init-param&amp;gt;&lt;br /&gt;  &amp;lt;/filter&amp;gt;&lt;br /&gt;&lt;br /&gt;  &amp;lt;filter-mapping&amp;gt;&lt;br /&gt;    &amp;lt;filter-name&amp;gt;WicketSpring&amp;lt;/filter-name&amp;gt;&lt;br /&gt;    &amp;lt;url-pattern&amp;gt;/*&amp;lt;/url-pattern&amp;gt;&lt;br /&gt;  &amp;lt;/filter-mapping&amp;gt;&lt;br /&gt;&lt;br /&gt;  &amp;lt;listener&amp;gt;&lt;br /&gt;    &amp;lt;listener-class&amp;gt;org.springframework.web.context.ContextLoaderListener&amp;lt;/listener-class&amp;gt;&lt;br /&gt;  &amp;lt;/listener&amp;gt;&lt;br /&gt;&lt;br /&gt;&amp;lt;/web-app&amp;gt;&lt;br /&gt;&lt;/pre&gt;&lt;br /&gt;The &lt;span style="font-family: &amp;quot;Courier New&amp;quot;,Courier,monospace;"&gt;ContextLoaderListener&lt;/span&gt; will create the Spring application context as soon as the servlet context is available. The &lt;span style="font-family: &amp;quot;Courier New&amp;quot;,Courier,monospace;"&gt;contextConfigLocation&lt;/span&gt; parameter defines the location of the XML configuration file for the Spring context - unfortunately, we cannot &lt;i&gt;fully&lt;/i&gt; drop XML configuration in Spring 3.0.&lt;br /&gt;&lt;br /&gt;Then we set up the usual &lt;span style="font-family: &amp;quot;Courier New&amp;quot;,Courier,monospace;"&gt;WicketFilter&lt;/span&gt; and map all requests to this filter. Instead of providing the &lt;span style="font-family: &amp;quot;Courier New&amp;quot;,Courier,monospace;"&gt;applicationClassName&lt;/span&gt; as in a vanilla Wicket setup, we configure a &lt;span style="font-family: &amp;quot;Courier New&amp;quot;,Courier,monospace;"&gt;SpringWebApplicationFactory&lt;/span&gt; which will look up a Wicket &lt;span style="font-family: &amp;quot;Courier New&amp;quot;,Courier,monospace;"&gt;WebApplication&lt;/span&gt; bean from the Spring context.&lt;br /&gt;&lt;br /&gt;The Spring application context in &lt;span style="font-family: &amp;quot;Courier New&amp;quot;,Courier,monospace;"&gt;WEB-INF/app-context.xml&lt;/span&gt; is rather short:&lt;br /&gt;&lt;br /&gt;&lt;pre class="Xml" name="code"&gt;&amp;lt;?xml version="1.0" encoding="UTF-8"?&amp;gt;&lt;br /&gt;&amp;lt;beans xmlns="http://www.springframework.org/schema/beans"&lt;br /&gt;     xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"&lt;br /&gt;     xmlns:context="http://www.springframework.org/schema/context"&lt;br /&gt;     xmlns:tx="http://www.springframework.org/schema/tx"&lt;br /&gt;     xsi:schemaLocation="http://www.springframework.org/schema/beans&lt;br /&gt;         http://www.springframework.org/schema/beans/spring-beans-3.0.xsd&lt;br /&gt;         http://www.springframework.org/schema/tx&lt;br /&gt;         http://www.springframework.org/schema/tx/spring-tx-3.0.xsd&lt;br /&gt;         http://www.springframework.org/schema/context&lt;br /&gt;         http://www.springframework.org/schema/context/spring-context-3.0.xsd"&amp;gt;&lt;br /&gt;&lt;br /&gt;  &amp;lt;context:annotation-config/&amp;gt;&lt;br /&gt;  &amp;lt;context:property-placeholder location="file:${wicketspring.config}"/&amp;gt;&lt;br /&gt;  &amp;lt;tx:annotation-driven/&amp;gt;&lt;br /&gt;  &amp;lt;bean class="com.blogspot.hwellmann.wicketspring.beans.WicketSpringConfig"/&amp;gt;      &lt;br /&gt;&amp;lt;/beans&amp;gt;&lt;br /&gt;&lt;/pre&gt;&lt;br /&gt;First, we enable configuration by annotations so we can do the rest of the setup in Java. The &lt;span style="font-family: &amp;quot;Courier New&amp;quot;,Courier,monospace;"&gt;property-placeholder&lt;/span&gt; defines the location of a properties file outside of the WAR which we use to provide the JDBC settings. &lt;span style="font-family: &amp;quot;Courier New&amp;quot;,Courier,monospace;"&gt;tx:annotation-driven&lt;/span&gt; enables declarative transactions by annotations. Finally, we define just one bean &lt;span style="font-family: &amp;quot;Courier New&amp;quot;,Courier,monospace;"&gt;WicketSpringConfig&lt;/span&gt; which does the rest of the work in Java:&lt;br /&gt;&lt;br /&gt;&lt;pre class="Java" name="code"&gt;@Configuration&lt;br /&gt;public class WicketSpringConfig {&lt;br /&gt;    &lt;br /&gt;    @Value("${wicketspring.jdbc.url}")&lt;br /&gt;    private String jdbcUrl;&lt;br /&gt;    &lt;br /&gt;    @Bean&lt;br /&gt;    public WicketSpringApplication wicketSpringApplication() {&lt;br /&gt;        return new WicketSpringApplication();&lt;br /&gt;    }&lt;br /&gt;    &lt;br /&gt;    @Bean&lt;br /&gt;    public BookDao bookDao() {&lt;br /&gt;        return new BookDao();&lt;br /&gt;    }&lt;br /&gt;    &lt;br /&gt;    @Bean&lt;br /&gt;    public DataSource dataSource() {&lt;br /&gt;        return new SimpleDriverDataSource(new org.apache.derby.jdbc.EmbeddedDriver(), jdbcUrl);&lt;br /&gt;    }&lt;br /&gt;&lt;br /&gt;    @Bean&lt;br /&gt;    public PlatformTransactionManager transactionManager() {&lt;br /&gt;      return new JpaTransactionManager(entityManagerFactory());&lt;br /&gt;    }&lt;br /&gt;    &lt;br /&gt;    @Bean&lt;br /&gt;    public EntityManagerFactory entityManagerFactory() {&lt;br /&gt;        LocalContainerEntityManagerFactoryBean bean = new LocalContainerEntityManagerFactoryBean();&lt;br /&gt;        bean.setDataSource(dataSource());&lt;br /&gt;        bean.setPersistenceProvider(new HibernatePersistence());&lt;br /&gt;        bean.afterPropertiesSet();&lt;br /&gt;        return bean.getObject();&lt;br /&gt;    }    &lt;br /&gt;}&lt;br /&gt;&lt;br /&gt;&lt;/pre&gt;&lt;br /&gt;There are some points to note about the &lt;span style="font-family: &amp;quot;Courier New&amp;quot;,Courier,monospace;"&gt;entityManagerFactory&lt;/span&gt; bean: We use a Spring factory bean to construct a JPA &lt;span style="font-family: &amp;quot;Courier New&amp;quot;,Courier,monospace;"&gt;EntityManagerFactory&lt;/span&gt;, so the Spring class should really be called &lt;span style="font-family: &amp;quot;Courier New&amp;quot;,Courier,monospace;"&gt;LocalContainerEntityManagerFactoryFactoryBean&lt;/span&gt; (yuck) or &lt;span style="font-family: &amp;quot;Courier New&amp;quot;,Courier,monospace;"&gt;LocalContainerEmfFactoryBean&lt;/span&gt; for short.&lt;br /&gt;&lt;br /&gt;The Spring Reference Manual does not explain how to use factory beans in Java configurations. For factory beans in XML configurations, &lt;span style="font-family: &amp;quot;Courier New&amp;quot;,Courier,monospace;"&gt;bean.getObject()&lt;/span&gt; is called automatically by the container to produce the real bean from the factory. Apparently, you have to do this explicitly in Java configurations, and &lt;span style="font-family: &amp;quot;Courier New&amp;quot;,Courier,monospace;"&gt;afterPropertiesSet()&lt;/span&gt; is a prerequisite for calling &lt;span style="font-family: &amp;quot;Courier New&amp;quot;,Courier,monospace;"&gt;getObject()&lt;/span&gt;.&lt;br /&gt;&lt;br /&gt;The &lt;span style="font-family: &amp;quot;Courier New&amp;quot;,Courier,monospace;"&gt;@Value&lt;/span&gt; annotation on the &lt;span style="font-family: &amp;quot;Courier New&amp;quot;,Courier,monospace;"&gt;jdbcUrl&lt;/span&gt; field is used to access a value from the properties file referenced in the XML context.&lt;br /&gt;&lt;br /&gt;In our Wicket application class, we define a &lt;span style="font-family: &amp;quot;Courier New&amp;quot;,Courier,monospace;"&gt;SpringComponentInjector&lt;/span&gt; which will inject Spring beans into our Wicket components:&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;&lt;pre class="Java" name="code"&gt;public class WicketSpringApplication extends WebApplication {&lt;br /&gt;    &lt;br /&gt;    @Autowired&lt;br /&gt;    private BookDao bookDao;&lt;br /&gt;    &lt;br /&gt;    @Override&lt;br /&gt;    protected void init() {&lt;br /&gt;        super.init();&lt;br /&gt;        &lt;br /&gt;        addComponentInstantiationListener(new SpringComponentInjector(this));&lt;br /&gt;        bookDao.createBooks();&lt;br /&gt;    }&lt;br /&gt;&lt;br /&gt;    @Override&lt;br /&gt;    public Class getHomePage() {&lt;br /&gt;        return BooksPage.class;&lt;br /&gt;    }&lt;br /&gt;}&lt;br /&gt;&lt;/pre&gt;&lt;br /&gt;&lt;span style="font-family: &amp;quot;Courier New&amp;quot;,Courier,monospace;"&gt;WicketSpringApplication&lt;/span&gt; itself is not a Wicket component, but it is a Spring bean, so the required &lt;span style="font-family: &amp;quot;Courier New&amp;quot;,Courier,monospace;"&gt;bookDao&lt;/span&gt; is injected automatically by the Spring container. The Wicket components like &lt;span style="font-family: &amp;quot;Courier New&amp;quot;,Courier,monospace;"&gt;BooksPage&lt;/span&gt;, on the other hand, are instantiated by Wicket outside of the Spring container, so we need to configure a &lt;span style="font-family: &amp;quot;Courier New&amp;quot;,Courier,monospace;"&gt;ComponentInstantiationListener&lt;/span&gt; to inject Spring beans into our Wicket components.&lt;br /&gt;&lt;br /&gt;The &lt;span style="font-family: &amp;quot;Courier New&amp;quot;,Courier,monospace;"&gt;SpringComponentInjector&lt;/span&gt; is defined in the &lt;span style="font-family: &amp;quot;Courier New&amp;quot;,Courier,monospace;"&gt;wicket-spring&lt;/span&gt; extension library. It will inject all Wicket component fields annotated by &lt;span style="font-family: &amp;quot;Courier New&amp;quot;,Courier,monospace;"&gt;@SpringBean&lt;/span&gt; with beans from the Spring context. This is an example of a Wicket page with an injected Spring DAO:&lt;br /&gt;&lt;br /&gt;&lt;pre class="Java" name="code"&gt;public class BooksPage extends WebPage {&lt;br /&gt;    &lt;br /&gt;    @SpringBean&lt;br /&gt;    private BookDao bookDao;&lt;br /&gt;    &lt;br /&gt;    public BooksPage() {&lt;br /&gt;        &lt;br /&gt;        add(new PropertyListView&amp;lt;Book&amp;gt;("book", bookDao.findBooks()) {&lt;br /&gt;&lt;br /&gt;            @Override&lt;br /&gt;            protected void populateItem(ListItem&amp;lt;Book&amp;gt; item) {&lt;br /&gt;                item.add(new Label("author"));&lt;br /&gt;                item.add(new Label("title"));&lt;br /&gt;            }            &lt;br /&gt;        });        &lt;br /&gt;    }&lt;br /&gt;}&lt;br /&gt;&lt;/pre&gt;&lt;br /&gt;&lt;br /&gt;The DAO itself is nothing special. It has an injected &lt;code&gt;EntityManager&lt;/code&gt; and automatic transactions by means of the &lt;code&gt;@Transactional&lt;/code&gt; annotation:&lt;br /&gt;&lt;br /&gt;&lt;pre class="Java" name="code"&gt;public class BookDao {&lt;br /&gt;    &lt;br /&gt;    @PersistenceContext&lt;br /&gt;    private EntityManager em;&lt;br /&gt;    &lt;br /&gt;    private static String[][] parameters = {&lt;br /&gt;        {"Thomas Mann", "Buddenbrooks"},&lt;br /&gt;        {"Heinrich Mann", "Der Untertan"},&lt;br /&gt;        {"Günter Grass", "Die Blechtrommel"}&lt;br /&gt;    };&lt;br /&gt;    &lt;br /&gt;    @Transactional&lt;br /&gt;    public void createBooks() {&lt;br /&gt;        for (String[] param : parameters) {&lt;br /&gt;            Book book = new Book(param[0], param[1]);&lt;br /&gt;            em.persist(book);&lt;br /&gt;        }        &lt;br /&gt;    }    &lt;br /&gt;    &lt;br /&gt;    public List&amp;lt;Book&amp;gt; findBooks() {&lt;br /&gt;        &lt;br /&gt;        TypedQuery&amp;lt;Book&amp;gt; query = em.createQuery("select b from Book b", Book.class);&lt;br /&gt;        return query.getResultList();&lt;br /&gt;    }    &lt;br /&gt;}&lt;br /&gt;&lt;/pre&gt;&lt;br /&gt;Now we're ready to launch our simple Web applications which will display a list of books from the database. I'm leaving out the &lt;span style="font-family: &amp;quot;Courier New&amp;quot;,Courier,monospace;"&gt;Book&lt;/span&gt; entity and the &lt;span style="font-family: &amp;quot;Courier New&amp;quot;,Courier,monospace;"&gt;BooksPage.html&lt;/span&gt; markup, which are completely trivial.&lt;br /&gt;&lt;br /&gt;This is how the &lt;span style="font-family: &amp;quot;Courier New&amp;quot;,Courier,monospace;"&gt;wicket-spring&lt;/span&gt; integration works out of the box, but I'm not quite satisified with that. There are two different annotations &lt;span style="font-family: &amp;quot;Courier New&amp;quot;,Courier,monospace;"&gt;@Autowired&lt;/span&gt; and &lt;span style="font-family: &amp;quot;Courier New&amp;quot;,Courier,monospace;"&gt;@SpringBean&lt;/span&gt; doing basically the same thing and tying my application classes to Spring. &lt;br /&gt;&lt;br /&gt;However, I would like to preserve the freedom to run my application either on Spring or on Java EE, an approach I explained in &lt;a href="http://hwellmann.blogspot.com/2010/11/java-ee-6-integration-testing-with.html"&gt;another post&lt;/a&gt;.&lt;br /&gt;&lt;br /&gt;More precisely, I would like to replace both &lt;span style="font-family: &amp;quot;Courier New&amp;quot;,Courier,monospace;"&gt;@Autowired&lt;/span&gt; and &lt;span style="font-family: &amp;quot;Courier New&amp;quot;,Courier,monospace;"&gt;@SpringBean&lt;/span&gt; by the standard &lt;span style="font-family: &amp;quot;Courier New&amp;quot;,Courier,monospace;"&gt;@javax.inject.Inject&lt;/span&gt; annotation from JSR-330, and also replace Spring's &lt;span style="font-family: &amp;quot;Courier New&amp;quot;,Courier,monospace;"&gt;@Transactional&lt;/span&gt; by @javax.ejb.TransactionAttribute.&lt;br /&gt;&lt;br /&gt;Spring 3.0 honours the &lt;span style="font-family: &amp;quot;Courier New&amp;quot;,Courier,monospace;"&gt;@Inject&lt;/span&gt; and &lt;span style="font-family: &amp;quot;Courier New&amp;quot;,Courier,monospace;"&gt;@TransactionAttribute&lt;/span&gt; annotations, provided they are on the classpath, so all we need to do is add the corresponding Apache Geronimo Java EE specification JARs to our project.&lt;br /&gt;&lt;br /&gt;Making &lt;span style="font-family: &amp;quot;Courier New&amp;quot;,Courier,monospace;"&gt;wicket-spring&lt;/span&gt; recognize &lt;span style="font-family: &amp;quot;Courier New&amp;quot;,Courier,monospace;"&gt;@Inject&lt;/span&gt; instead of &lt;span style="font-family: &amp;quot;Courier New&amp;quot;,Courier,monospace;"&gt;@SpringBean&lt;/span&gt; requires a few more steps, which I'll just outline: &lt;br /&gt;&lt;ul&gt;&lt;li&gt;Create the classes&lt;span style="font-family: &amp;quot;Courier New&amp;quot;,Courier,monospace;"&gt; Jsr330SpringComponentInjector, Jsr330SpringInjector&lt;/span&gt; and &lt;span style="font-family: &amp;quot;Courier New&amp;quot;,Courier,monospace;"&gt;Jsr330ProxyFieldValueFactory&lt;/span&gt; as copies of &lt;span style="font-family: &amp;quot;Courier New&amp;quot;,Courier,monospace;"&gt;SpringComponentInjector, SpringInjector&lt;/span&gt; and &lt;span style="font-family: &amp;quot;Courier New&amp;quot;,Courier,monospace;"&gt;AnnotProxyFieldValueFactory&lt;/span&gt; in &lt;span style="font-family: &amp;quot;Courier New&amp;quot;,Courier,monospace;"&gt;wicket-spring&lt;/span&gt;.&lt;/li&gt;&lt;li&gt; Replace references to &lt;span style="font-family: &amp;quot;Courier New&amp;quot;,Courier,monospace;"&gt;SpringBean&lt;/span&gt; in &lt;span style="font-family: &amp;quot;Courier New&amp;quot;,Courier,monospace;"&gt;Jsr330ProxyFieldValueFactory&lt;/span&gt; by references to &lt;span style="font-family: &amp;quot;Courier New&amp;quot;,Courier,monospace;"&gt;Inject&lt;/span&gt;.&lt;/li&gt;&lt;li&gt;In our modified copies, reference the modified copies instead of the originals.&lt;/li&gt;&lt;/ul&gt;Not very elegant, but it works. All the copying could easily be avoided by modifying the &lt;span style="font-family: &amp;quot;Courier New&amp;quot;,Courier,monospace;"&gt;wicket-spring&lt;/span&gt; sources, but this is currently out of scope.&lt;br /&gt;&lt;br /&gt;With this approach, I've created a functional example project, using Eclipse, Maven, Tomcat, Hibernate and Derby as further ingredients.&amp;nbsp; Here is my Maven POM:&lt;br /&gt;&lt;br /&gt;&lt;pre class="Xml" name="code"&gt;&amp;lt;project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"&lt;br /&gt;  xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd"&amp;gt;&lt;br /&gt;  &amp;lt;modelVersion&amp;gt;4.0.0&amp;lt;/modelVersion&amp;gt;&lt;br /&gt;  &amp;lt;groupId&amp;gt;com.blogspot.hwellmann.wicketspring&amp;lt;/groupId&amp;gt;&lt;br /&gt;  &amp;lt;artifactId&amp;gt;wicketspring-web&amp;lt;/artifactId&amp;gt;&lt;br /&gt;  &amp;lt;packaging&amp;gt;war&amp;lt;/packaging&amp;gt;&lt;br /&gt;  &amp;lt;version&amp;gt;0.0.1-SNAPSHOT&amp;lt;/version&amp;gt;&lt;br /&gt;  &amp;lt;properties&amp;gt;&lt;br /&gt;    &amp;lt;spring.version&amp;gt;3.0.5.RELEASE&amp;lt;/spring.version&amp;gt;&lt;br /&gt;    &amp;lt;wicket.version&amp;gt;1.4.15&amp;lt;/wicket.version&amp;gt;&lt;br /&gt;  &amp;lt;/properties&amp;gt;&lt;br /&gt;  &amp;lt;dependencies&amp;gt;&lt;br /&gt;    &amp;lt;dependency&amp;gt;&lt;br /&gt;      &amp;lt;groupId&amp;gt;org.apache.wicket&amp;lt;/groupId&amp;gt;&lt;br /&gt;      &amp;lt;artifactId&amp;gt;wicket&amp;lt;/artifactId&amp;gt;&lt;br /&gt;      &amp;lt;version&amp;gt;1.4.15&amp;lt;/version&amp;gt;&lt;br /&gt;    &amp;lt;/dependency&amp;gt;&lt;br /&gt;    &amp;lt;dependency&amp;gt;&lt;br /&gt;      &amp;lt;groupId&amp;gt;org.apache.wicket&amp;lt;/groupId&amp;gt;&lt;br /&gt;      &amp;lt;artifactId&amp;gt;wicket-spring&amp;lt;/artifactId&amp;gt;&lt;br /&gt;      &amp;lt;version&amp;gt;1.4.15&amp;lt;/version&amp;gt;&lt;br /&gt;    &amp;lt;/dependency&amp;gt;&lt;br /&gt;    &amp;lt;dependency&amp;gt;&lt;br /&gt;      &amp;lt;groupId&amp;gt;org.apache.wicket&amp;lt;/groupId&amp;gt;&lt;br /&gt;      &amp;lt;artifactId&amp;gt;wicket-ioc&amp;lt;/artifactId&amp;gt;&lt;br /&gt;      &amp;lt;version&amp;gt;1.4.15&amp;lt;/version&amp;gt;&lt;br /&gt;      &amp;lt;exclusions&amp;gt;&lt;br /&gt;        &amp;lt;exclusion&amp;gt;&lt;br /&gt;          &amp;lt;groupId&amp;gt;cglib&amp;lt;/groupId&amp;gt;&lt;br /&gt;          &amp;lt;artifactId&amp;gt;cglib-nodep&amp;lt;/artifactId&amp;gt;&lt;br /&gt;        &amp;lt;/exclusion&amp;gt;&lt;br /&gt;      &amp;lt;/exclusions&amp;gt;&lt;br /&gt;    &amp;lt;/dependency&amp;gt;&lt;br /&gt;    &amp;lt;dependency&amp;gt;&lt;br /&gt;      &amp;lt;groupId&amp;gt;org.springframework&amp;lt;/groupId&amp;gt;&lt;br /&gt;      &amp;lt;artifactId&amp;gt;spring-context&amp;lt;/artifactId&amp;gt;&lt;br /&gt;      &amp;lt;version&amp;gt;${spring.version}&amp;lt;/version&amp;gt;&lt;br /&gt;      &amp;lt;exclusions&amp;gt;&lt;br /&gt;        &amp;lt;exclusion&amp;gt;&lt;br /&gt;          &amp;lt;groupId&amp;gt;commons-logging&amp;lt;/groupId&amp;gt;&lt;br /&gt;          &amp;lt;artifactId&amp;gt;commons-logging&amp;lt;/artifactId&amp;gt;&lt;br /&gt;        &amp;lt;/exclusion&amp;gt;&lt;br /&gt;      &amp;lt;/exclusions&amp;gt;&lt;br /&gt;    &amp;lt;/dependency&amp;gt;&lt;br /&gt;    &amp;lt;dependency&amp;gt;&lt;br /&gt;      &amp;lt;groupId&amp;gt;org.springframework&amp;lt;/groupId&amp;gt;&lt;br /&gt;      &amp;lt;artifactId&amp;gt;spring-web&amp;lt;/artifactId&amp;gt;&lt;br /&gt;      &amp;lt;version&amp;gt;${spring.version}&amp;lt;/version&amp;gt;&lt;br /&gt;    &amp;lt;/dependency&amp;gt;&lt;br /&gt;    &amp;lt;dependency&amp;gt;&lt;br /&gt;      &amp;lt;groupId&amp;gt;org.springframework&amp;lt;/groupId&amp;gt;&lt;br /&gt;      &amp;lt;artifactId&amp;gt;spring-orm&amp;lt;/artifactId&amp;gt;&lt;br /&gt;      &amp;lt;version&amp;gt;${spring.version}&amp;lt;/version&amp;gt;&lt;br /&gt;    &amp;lt;/dependency&amp;gt;&lt;br /&gt;    &amp;lt;dependency&amp;gt;&lt;br /&gt;      &amp;lt;groupId&amp;gt;org.slf4j&amp;lt;/groupId&amp;gt;&lt;br /&gt;      &amp;lt;artifactId&amp;gt;jcl-over-slf4j&amp;lt;/artifactId&amp;gt;&lt;br /&gt;      &amp;lt;version&amp;gt;1.5.11&amp;lt;/version&amp;gt;&lt;br /&gt;    &amp;lt;/dependency&amp;gt;&lt;br /&gt;    &amp;lt;dependency&amp;gt;&lt;br /&gt;      &amp;lt;groupId&amp;gt;org.slf4j&amp;lt;/groupId&amp;gt;&lt;br /&gt;      &amp;lt;artifactId&amp;gt;slf4j-api&amp;lt;/artifactId&amp;gt;&lt;br /&gt;      &amp;lt;version&amp;gt;1.5.11&amp;lt;/version&amp;gt;&lt;br /&gt;    &amp;lt;/dependency&amp;gt;&lt;br /&gt;    &amp;lt;dependency&amp;gt;&lt;br /&gt;      &amp;lt;groupId&amp;gt;ch.qos.logback&amp;lt;/groupId&amp;gt;&lt;br /&gt;      &amp;lt;artifactId&amp;gt;logback-core&amp;lt;/artifactId&amp;gt;&lt;br /&gt;      &amp;lt;version&amp;gt;0.9.20&amp;lt;/version&amp;gt;&lt;br /&gt;    &amp;lt;/dependency&amp;gt;&lt;br /&gt;    &amp;lt;dependency&amp;gt;&lt;br /&gt;      &amp;lt;groupId&amp;gt;ch.qos.logback&amp;lt;/groupId&amp;gt;&lt;br /&gt;      &amp;lt;artifactId&amp;gt;logback-classic&amp;lt;/artifactId&amp;gt;&lt;br /&gt;      &amp;lt;version&amp;gt;0.9.20&amp;lt;/version&amp;gt;&lt;br /&gt;    &amp;lt;/dependency&amp;gt;&lt;br /&gt;    &amp;lt;dependency&amp;gt;&lt;br /&gt;      &amp;lt;groupId&amp;gt;javax.servlet&amp;lt;/groupId&amp;gt;&lt;br /&gt;      &amp;lt;artifactId&amp;gt;servlet-api&amp;lt;/artifactId&amp;gt;&lt;br /&gt;      &amp;lt;version&amp;gt;2.5&amp;lt;/version&amp;gt;&lt;br /&gt;      &amp;lt;type&amp;gt;jar&amp;lt;/type&amp;gt;&lt;br /&gt;      &amp;lt;scope&amp;gt;provided&amp;lt;/scope&amp;gt;&lt;br /&gt;    &amp;lt;/dependency&amp;gt;&lt;br /&gt;    &amp;lt;dependency&amp;gt;&lt;br /&gt;      &amp;lt;groupId&amp;gt;org.apache.geronimo.specs&amp;lt;/groupId&amp;gt;&lt;br /&gt;      &amp;lt;artifactId&amp;gt;geronimo-atinject_1.0_spec&amp;lt;/artifactId&amp;gt;&lt;br /&gt;      &amp;lt;version&amp;gt;1.0&amp;lt;/version&amp;gt;&lt;br /&gt;    &amp;lt;/dependency&amp;gt;&lt;br /&gt;    &amp;lt;dependency&amp;gt;&lt;br /&gt;      &amp;lt;groupId&amp;gt;org.apache.geronimo.specs&amp;lt;/groupId&amp;gt;&lt;br /&gt;      &amp;lt;artifactId&amp;gt;geronimo-ejb_3.1_spec&amp;lt;/artifactId&amp;gt;&lt;br /&gt;      &amp;lt;version&amp;gt;1.0&amp;lt;/version&amp;gt;&lt;br /&gt;    &amp;lt;/dependency&amp;gt;&lt;br /&gt;    &amp;lt;dependency&amp;gt;&lt;br /&gt;      &amp;lt;groupId&amp;gt;org.apache.derby&amp;lt;/groupId&amp;gt;&lt;br /&gt;      &amp;lt;artifactId&amp;gt;derby&amp;lt;/artifactId&amp;gt;&lt;br /&gt;      &amp;lt;version&amp;gt;10.7.1.1&amp;lt;/version&amp;gt;&lt;br /&gt;    &amp;lt;/dependency&amp;gt;&lt;br /&gt;    &amp;lt;dependency&amp;gt;&lt;br /&gt;      &amp;lt;groupId&amp;gt;org.hibernate&amp;lt;/groupId&amp;gt;&lt;br /&gt;      &amp;lt;artifactId&amp;gt;hibernate-entitymanager&amp;lt;/artifactId&amp;gt;&lt;br /&gt;      &amp;lt;version&amp;gt;3.5.6-Final&amp;lt;/version&amp;gt;&lt;br /&gt;    &amp;lt;/dependency&amp;gt;&lt;br /&gt;  &amp;lt;/dependencies&amp;gt;&lt;br /&gt;&amp;lt;/project&amp;gt;&lt;br /&gt;&lt;/pre&gt;&lt;br /&gt;As my maths books used to say, &lt;i&gt;"the details are left as a trivial exercise to the reader"&lt;/i&gt;, but I hope I've provided enough details to get anyone started...&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/7836204352369514180-4588680469744817793?l=hwellmann.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://hwellmann.blogspot.com/feeds/4588680469744817793/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=7836204352369514180&amp;postID=4588680469744817793' title='6 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/7836204352369514180/posts/default/4588680469744817793'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/7836204352369514180/posts/default/4588680469744817793'/><link rel='alternate' type='text/html' href='http://hwellmann.blogspot.com/2011/02/building-web-applicaton-with-wicket.html' title='Building a Web Application with Wicket, Spring and JPA'/><author><name>Harald Wellmann</name><uri>http://www.blogger.com/profile/08039976160321882828</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='16' height='16' src='http://img2.blogblog.com/img/b16-rounded.gif'/></author><thr:total>6</thr:total></entry><entry><id>tag:blogger.com,1999:blog-7836204352369514180.post-3786408349138498855</id><published>2011-02-07T23:15:00.001+01:00</published><updated>2011-03-20T14:26:26.270+01:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='Nexus'/><category scheme='http://www.blogger.com/atom/ns#' term='Maven'/><title type='text'>Maven Snapshot Repositories with Nexus</title><content type='html'>When you have a Maven build which depends on more than one external repository, it is usually a good idea to work with a repository manager. A repository manager also enables you to share your artifacts with other team members.&lt;br /&gt;&lt;br /&gt;Nexus Open Source is probably the most popular Maven repository manager. Once it's set up correctly, it requires little or no maintenance, at least that's my experience after using it in different projects over the last three years.&lt;br /&gt;&lt;br /&gt;I've just finished setting up Nexus for my current project, but this time, I spent almost a day chasing a problem related to snapshot repositories.&lt;br /&gt;&lt;br /&gt;I had set up the Public Repositories group of Nexus as a mirror for Maven central and configured the Nexus Snapshots repository as an additional snapshot-enabled repository for the snapshots from my own project:&lt;br /&gt;&lt;br /&gt;&lt;a name='more'&gt;&lt;/a&gt;&lt;br /&gt;&lt;br /&gt;&lt;pre class="Xml" name="code"&gt;&amp;lt;mirrors&amp;gt;&lt;br /&gt;    &amp;lt;mirror&amp;gt;&lt;br /&gt;      &amp;lt;id&amp;gt;mynexus&amp;lt;/id&amp;gt;&lt;br /&gt;      &amp;lt;mirrorOf&amp;gt;central&amp;lt;/mirrorOf&amp;gt;&lt;br /&gt;      &amp;lt;name&amp;gt;Nexus&amp;lt;/name&amp;gt;&lt;br /&gt;      &amp;lt;url&amp;gt;http://nexus.example.com/content/groups/public&amp;lt;/url&amp;gt;&lt;br /&gt;    &amp;lt;/mirror&amp;gt;&lt;br /&gt;  &amp;lt;/mirrors&amp;gt;&lt;br /&gt;&lt;br /&gt;  &amp;lt;profile&amp;gt;&lt;br /&gt;    &amp;lt;id&amp;gt;mysnapshots&amp;lt;/id&amp;gt;&lt;br /&gt;    &amp;lt;repositories&amp;gt;&lt;br /&gt;      &amp;lt;repository&amp;gt;&lt;br /&gt;        &amp;lt;id&amp;gt;mysnapshots&amp;lt;/id&amp;gt;&lt;br /&gt;        &amp;lt;url&amp;gt;https://nexus.example.com/content/repositories/snapshots&amp;lt;/url&amp;gt;&lt;br /&gt;        &amp;lt;snapshots&amp;gt;&lt;br /&gt;          &amp;lt;enabled&amp;gt;true&amp;lt;/enabled&amp;gt;&lt;br /&gt;        &amp;lt;/snapshots&amp;gt;        &lt;br /&gt;       &amp;lt;/repository&amp;gt;&lt;br /&gt;     &amp;lt;/repositories&amp;gt;&lt;br /&gt;  &amp;lt;/profile&amp;gt;&lt;br /&gt;&lt;br /&gt;  &amp;lt;activeProfiles&amp;gt;&lt;br /&gt;    &amp;lt;activeProfile&amp;gt;mysnapshots&amp;lt;/activeProfile&amp;gt;&lt;br /&gt;  &amp;lt;/activeProfiles&amp;gt;&lt;br /&gt;&lt;/pre&gt;&lt;br /&gt;I did not enable snapshots for Central as suggested in the &lt;a href="http://www.sonatype.com/books/nexus-book/reference/maven-sect-single-group.html"&gt;Nexus book&lt;/a&gt;, to avoid picking up any snapshots except my own. This setup worked fine in my local workspace and on our build server, but then my off-site co-workers started complaining about build failures.&lt;br /&gt;&lt;br /&gt;They had error messages of the kind&lt;br /&gt;&lt;br /&gt;&lt;pre&gt;Unable to find resource 'com.example.foo:jar:0.0.1-SNAPSHOT' in repository mysnapshots (http://nexus.example.com/content/repositories/snapshots)&lt;br /&gt;&lt;/pre&gt;&lt;br /&gt;even though they could see the required artifact in the given repository via the Nexus interface. Or so we thought...&lt;br /&gt;&lt;br /&gt;It turned out that we'd simply misinterpreted the Maven console messages: &lt;br /&gt;&lt;br /&gt;&lt;pre&gt;Downloading: http://nexus.example.com/content/repositories/snapshots/com/example/foo/0.0.1-SNAPSHOT/foo-0.0.1-SNAPSHOT.pom&lt;br /&gt;&lt;/pre&gt;&lt;br /&gt;should have given us a clue to the root cause, seeing that snapshot resources in remote repositories always have the SNAPSHOT suffix replaced by a timestamp, so the message really should have been something like&lt;br /&gt;&lt;br /&gt;&lt;pre&gt;Downloading: http://nexus.example.com/content/repositories/snapshots/com/example/foo/0.0.1-SNAPSHOT/foo-0.0.1-20110207.090228-284.pom&lt;br /&gt;&lt;/pre&gt;&lt;br /&gt;The problem was the configuration of the Public Repositories group in Nexus which includes the hosted Snapshots repository by default. This appears to have led to the following scenario:&lt;br /&gt;&lt;br /&gt;&lt;ul&gt;&lt;li&gt;Client requests com.example.foo:jar:0.0.1-SNAPSHOT.&lt;/li&gt;&lt;li&gt;Maven tries to locate this artifact in Central.&lt;/li&gt;&lt;li&gt; Central is mirrored to Nexus Public Repositories, which includes Nexus Snapshots, which hosts the requested artifact.&lt;/li&gt;&lt;li&gt;Thus, Maven has found a match in Central and tries to download it from Central.&lt;/li&gt;&lt;li&gt;Now since Snapshots are not enabled for Central, the SNAPSHOT to timestamp conversion does not take place and Maven tries to download a non-existing resource, failing with a somewhat misleading error message.&lt;/li&gt;&lt;/ul&gt;&lt;br /&gt;&lt;h4&gt;Solution:&lt;/h4&gt;&lt;br /&gt;After deleting the Snapshots repository from the Public Repositories group in Nexus, all builds were working fine on all sites.&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/7836204352369514180-3786408349138498855?l=hwellmann.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://hwellmann.blogspot.com/feeds/3786408349138498855/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=7836204352369514180&amp;postID=3786408349138498855' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/7836204352369514180/posts/default/3786408349138498855'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/7836204352369514180/posts/default/3786408349138498855'/><link rel='alternate' type='text/html' href='http://hwellmann.blogspot.com/2011/02/maven-snapshot-repositories-with-nexus.html' title='Maven Snapshot Repositories with Nexus'/><author><name>Harald Wellmann</name><uri>http://www.blogger.com/profile/08039976160321882828</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='16' height='16' src='http://img2.blogblog.com/img/b16-rounded.gif'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-7836204352369514180.post-6132908487373806076</id><published>2011-01-22T20:20:00.001+01:00</published><updated>2011-03-20T14:27:16.518+01:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='Lingo'/><category scheme='http://www.blogger.com/atom/ns#' term='JMS'/><category scheme='http://www.blogger.com/atom/ns#' term='Remoting'/><category scheme='http://www.blogger.com/atom/ns#' term='Camel'/><category scheme='http://www.blogger.com/atom/ns#' term='Spring'/><category scheme='http://www.blogger.com/atom/ns#' term='Java EE 6'/><title type='text'>Transparent Asynchronous Remoting</title><content type='html'>&lt;h3&gt;The Scenario&lt;/h3&gt;&lt;br /&gt;A client needs to invoke a service interface with the following restrictions:&lt;br /&gt;&lt;ul&gt;&lt;li&gt;The service implementation is running on a &lt;b&gt;remote&lt;/b&gt; machine.&lt;/li&gt;&lt;li&gt;This fact is &lt;b&gt;transparent&lt;/b&gt; to the client, i.e. any service method invocation is just like a local method invocation.&lt;/li&gt;&lt;li&gt;The service methods are executed &lt;b&gt;asychronously&lt;/b&gt; on the server, method invocations on the client return immediately (fire-and-forget).&lt;/li&gt;&lt;li&gt;All service methods have void return types.&lt;/li&gt;&lt;/ul&gt;&lt;br /&gt;&lt;h3&gt;The Solution with Java EE 6&lt;/h3&gt;&lt;br /&gt;With Java EE 6, the solution is quite simple, thanks to the &lt;code&gt;@Asynchronous&lt;/code&gt; annotation introduced in EJB 3.1. You simply create a remote session bean and add this annotation to any business method or to the entire class. The container will then execute the given methods asynchronously.&lt;br /&gt;&lt;br /&gt;Patrick Champion has a &lt;a href="http://paddyweblog.blogspot.com/2010/04/ejb-31-asynchronous-session-beans.html"&gt;complete example&lt;/a&gt; in his blog, so there's no need for me to provide any sample code.&lt;br /&gt;&lt;br /&gt;When your client is also a Java EE 6 application, you can simply &lt;code&gt;@Inject&lt;/code&gt; the service interface and use a &lt;code&gt;&lt;a href="http://docs.jboss.org/weld/reference/1.1.0.Final/en-US/html/resources.html"&gt;@Produces&lt;/a&gt;&lt;/code&gt; annotation on an &lt;code&gt;@EJB&lt;/code&gt; reference somewhere else to direct the client to the appropriate implementation.&lt;br /&gt;&lt;br /&gt;In addition, to avoid hardcoding the service URL in your client, you should define a local JNDI alias in your Java EE 6 container for the address of the remote service implementation, so you can move the remote implementation to another host without recompiling your client.&lt;br /&gt;&lt;br /&gt;&lt;h3&gt;The Solution with Spring 3.0&lt;/h3&gt;&lt;br /&gt;Spring does not have an out-of-the box solution for this scenario. &lt;a href="http://static.springsource.org/spring/docs/3.0.x/spring-framework-reference/html/remoting.html"&gt;Spring Remoting&lt;/a&gt; provides transparent proxies for remote services, but these proxies are always synchronous. Since Spring 3.0, there annotation support for &lt;a href="http://static.springsource.org/spring/docs/3.0.x/spring-framework-reference/html/scheduling.html#scheduling-annotation-support-async"&gt;asynchronous execution&lt;/a&gt;, but this only applies to local beans.&lt;br /&gt;&lt;br /&gt;However, it is not hard to combine these two features with some glue code to implement a solution for our scenario.&lt;br /&gt;&lt;br /&gt;&lt;a name='more'&gt;&lt;/a&gt;&lt;br /&gt;&lt;br /&gt;&lt;h4&gt;Overview&lt;/h4&gt;&lt;br /&gt;Spring Remoting requires you to do some plumbing both on the server and client sides. On the server side, you expose your service beans wrapped in a &lt;code&gt;HttpInvokerServiceExporter&lt;/code&gt;. On the client side, you need to configure a local proxy for each remote service using an &lt;code&gt;HttpInvokerProxyFactoryBean&lt;/code&gt;.&lt;br /&gt;&lt;br /&gt;Now this &lt;code&gt;HttpInvokerProxyFactoryBean&lt;/code&gt; lets you provide a custom &lt;code&gt;HttpInvokerRequestExecutor&lt;/code&gt;, so the idea is to build an &lt;code&gt;AsyncHttpRequestExecutor&lt;/code&gt; which delegates the remote invocation to an &lt;code&gt;AsyncHttpRequestWorker&lt;/code&gt; annotated with @Async, so that the remote invocation will indeed be executed asynchronously.&lt;br /&gt;&lt;br /&gt;Here is an example with two remote services - I'm using two services to make clear which of the beans and helper objects need to be constructed per service and which can be shared. The application contexts will use Java configuration to minimize the amount of XML.&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;&lt;h4&gt;The API&lt;/h4&gt;&lt;br /&gt;Following the tradition of "Hello World" examples, we create a &lt;code&gt;HelloService&lt;/code&gt; to say hello to a given person, and we add a &lt;code&gt;GoodbyeService&lt;/code&gt;.&lt;br /&gt;&lt;br /&gt;&lt;pre class="Java" name="code"&gt;package com.blogspot.hwellmann.greeter.api;&lt;br /&gt;&lt;br /&gt;public interface HelloService {&lt;br /&gt;&lt;br /&gt;    void sayHello(Person person);&lt;br /&gt;}&lt;br /&gt;&lt;/pre&gt;&lt;br /&gt;&lt;pre class="Java" name="code"&gt;package com.blogspot.hwellmann.greeter.api;&lt;br /&gt;&lt;br /&gt;public interface GoodbyeService {&lt;br /&gt;&lt;br /&gt;    void sayGoodbye(Person person);&lt;br /&gt;}&lt;br /&gt;&lt;/pre&gt;&lt;br /&gt;Note that Spring Remoting uses standard Java serialization for transporting method parameters, so all parameter objects need to be &lt;code&gt;Serializable&lt;/code&gt;:&lt;br /&gt;&lt;br /&gt;&lt;pre class="Java" name="code"&gt;package com.blogspot.hwellmann.greeter.api;&lt;br /&gt;&lt;br /&gt;import java.io.Serializable;&lt;br /&gt;&lt;br /&gt;public class Person implements Serializable {&lt;br /&gt;&lt;br /&gt;    private static final long serialVersionUID = 1L;&lt;br /&gt;&lt;br /&gt;    private String firstName;&lt;br /&gt;    private String lastName;&lt;br /&gt;     &lt;br /&gt;    public Person(String firstName, String lastName) {&lt;br /&gt;        this.firstName = firstName;&lt;br /&gt;        this.lastName = lastName;&lt;br /&gt;    }&lt;br /&gt;&lt;br /&gt;    // ...getters and setters...&lt;br /&gt;}&lt;br /&gt;&lt;/pre&gt;&lt;br /&gt;&lt;h4&gt;The Server&lt;/h4&gt;&lt;br /&gt;&lt;pre class="Java" name="code"&gt;package com.blogspot.hwellmann.greeter.server;&lt;br /&gt;&lt;br /&gt;import com.blogspot.hwellmann.greeter.api.HelloService;&lt;br /&gt;import com.blogspot.hwellmann.greeter.api.Person;&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;public class HelloServiceImpl implements HelloService {&lt;br /&gt;&lt;br /&gt;    public void sayHello(Person person) {&lt;br /&gt;        try {&lt;br /&gt;            Thread.sleep(1000);&lt;br /&gt;            System.out.println(String.format("Hello, %s %s!", &lt;br /&gt;                    person.getFirstName(), person.getLastName()));&lt;br /&gt;        }&lt;br /&gt;        catch (InterruptedException e) {&lt;br /&gt;            e.printStackTrace();&lt;br /&gt;        }&lt;br /&gt;    }&lt;br /&gt;}&lt;br /&gt;&lt;/pre&gt;&lt;br /&gt;The GoodbyeService is left as an exercise to the reader ;-) Now here is the Spring configuration for the server:&lt;br /&gt;&lt;br /&gt;&lt;pre class="Xml" name="code"&gt;&amp;lt;?xml version="1.0" encoding="UTF-8"?&amp;gt;&lt;br /&gt;&amp;lt;beans xmlns="http://www.springframework.org/schema/beans" &lt;br /&gt;  xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"&lt;br /&gt;  xmlns:context="http://www.springframework.org/schema/context" &lt;br /&gt;  xsi:schemaLocation="http://www.springframework.org/schema/beans&lt;br /&gt;         http://www.springframework.org/schema/beans/spring-beans-3.0.xsd&lt;br /&gt;         http://www.springframework.org/schema/context&lt;br /&gt;         http://www.springframework.org/schema/context/spring-context-3.0.xsd"&amp;gt;&lt;br /&gt;&lt;br /&gt;  &amp;lt;context:annotation-config  /&amp;gt;&lt;br /&gt;  &amp;lt;bean class="com.blogspot.hwellmann.greeter.server.GreeterServerSpringConfig"/&amp;gt;&lt;br /&gt;&lt;br /&gt;&amp;lt;/beans&amp;gt;&lt;br /&gt;&lt;/pre&gt;&lt;br /&gt;&lt;pre class="Java" name="code"&gt;package com.blogspot.hwellmann.greeter.server;&lt;br /&gt;&lt;br /&gt;import java.io.IOException;&lt;br /&gt;&lt;br /&gt;import org.springframework.context.annotation.Bean;&lt;br /&gt;import org.springframework.context.annotation.Configuration;&lt;br /&gt;&lt;br /&gt;import com.blogspot.hwellmann.async.HttpServiceExporterFactoryBean;&lt;br /&gt;import com.blogspot.hwellmann.greeter.api.GoodbyeService;&lt;br /&gt;import com.blogspot.hwellmann.greeter.api.HelloService;&lt;br /&gt;import com.sun.net.httpserver.HttpServer;&lt;br /&gt;&lt;br /&gt;@Configuration&lt;br /&gt;@SuppressWarnings("restriction")&lt;br /&gt;public class GreeterServerSpringConfig {&lt;br /&gt;    &lt;br /&gt;    &lt;br /&gt;    @Bean&lt;br /&gt;    public HelloService helloService() {&lt;br /&gt;        return new HelloServiceImpl();&lt;br /&gt;    }&lt;br /&gt;    &lt;br /&gt;    @Bean&lt;br /&gt;    public GoodbyeService goodbyeService() {&lt;br /&gt;        return new GoodbyeServiceImpl();&lt;br /&gt;    }&lt;br /&gt;    &lt;br /&gt;    @Bean&lt;br /&gt;    public HttpServer httpServer() throws IOException {&lt;br /&gt;        HttpServiceExporterFactoryBean factory = new HttpServiceExporterFactoryBean();&lt;br /&gt;        factory.setPort(9999);&lt;br /&gt;        &lt;br /&gt;        factory.add(HelloService.class, helloService());&lt;br /&gt;        factory.add(GoodbyeService.class, goodbyeService());&lt;br /&gt;&lt;br /&gt;        factory.afterPropertiesSet();&lt;br /&gt;        return factory.getObject();&lt;br /&gt;    }    &lt;br /&gt;}&lt;br /&gt;&lt;/pre&gt;&lt;br /&gt;I'm using a simple standalone HTTP server for this example. The Spring reference manual shows how to configure a dispatcher servlet instead when the services are running in a web container anyway. &lt;br /&gt;&lt;br /&gt;&lt;h4&gt;The Client&lt;/h4&gt;&lt;br /&gt;This is the client for saying hello and goodbye to three persons:&lt;br /&gt;&lt;br /&gt;&lt;pre class="Java" name="code"&gt;package com.blogspot.hwellmann.greeter.client;&lt;br /&gt;&lt;br /&gt;import javax.inject.Inject;&lt;br /&gt;&lt;br /&gt;import org.springframework.context.ApplicationContext;&lt;br /&gt;import org.springframework.context.support.GenericXmlApplicationContext;&lt;br /&gt;&lt;br /&gt;import com.blogspot.hwellmann.greeter.api.GoodbyeService;&lt;br /&gt;import com.blogspot.hwellmann.greeter.api.HelloService;&lt;br /&gt;import com.blogspot.hwellmann.greeter.api.Person;&lt;br /&gt;&lt;br /&gt;public class GreeterClient implements Runnable {&lt;br /&gt;&lt;br /&gt;    @Inject&lt;br /&gt;    private HelloService helloProxy;&lt;br /&gt;&lt;br /&gt;    @Inject&lt;br /&gt;    private GoodbyeService goodbyeProxy;&lt;br /&gt;&lt;br /&gt;    private Person donald = new Person("Donald", "Duck");&lt;br /&gt;    private Person mickey = new Person("Mickey", "Mouse");&lt;br /&gt;    private Person charlie = new Person("Charlie", "Brown");&lt;br /&gt;&lt;br /&gt;    public void run() {&lt;br /&gt;        System.out.println("invoking greeter");&lt;br /&gt;        &lt;br /&gt;        helloProxy.sayHello(donald);&lt;br /&gt;        helloProxy.sayHello(mickey);&lt;br /&gt;        helloProxy.sayHello(charlie);&lt;br /&gt;        &lt;br /&gt;        goodbyeProxy.sayGoodbye(donald);&lt;br /&gt;        goodbyeProxy.sayGoodbye(mickey);&lt;br /&gt;        goodbyeProxy.sayGoodbye(charlie);&lt;br /&gt;&lt;br /&gt;        System.out.println("done");&lt;br /&gt;    }&lt;br /&gt;    &lt;br /&gt;    public static void main(String[] args) throws InterruptedException {&lt;br /&gt;        ApplicationContext context = new GenericXmlApplicationContext("/META-INF/spring/client-context.xml");&lt;br /&gt;        GreeterClient client = context.getBean(GreeterClient.class);&lt;br /&gt;        client.run();&lt;br /&gt;    }    &lt;br /&gt;}&lt;br /&gt;&lt;/pre&gt;&lt;br /&gt;And here is the Spring Configuration:&lt;br /&gt;&lt;br /&gt;&lt;pre class="Xml" name="code"&gt;&amp;lt;?xml version="1.0" encoding="UTF-8"?&amp;gt;&lt;br /&gt;&amp;lt;beans xmlns="http://www.springframework.org/schema/beans" &lt;br /&gt;  xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"&lt;br /&gt;  xmlns:context="http://www.springframework.org/schema/context" &lt;br /&gt;  xmlns:task="http://www.springframework.org/schema/task"&lt;br /&gt;  xsi:schemaLocation="http://www.springframework.org/schema/beans&lt;br /&gt;         http://www.springframework.org/schema/beans/spring-beans-3.0.xsd&lt;br /&gt;         http://www.springframework.org/schema/task&lt;br /&gt;         http://www.springframework.org/schema/task/spring-task-3.0.xsd&lt;br /&gt;         http://www.springframework.org/schema/context&lt;br /&gt;         http://www.springframework.org/schema/context/spring-context-3.0.xsd"&amp;gt;&lt;br /&gt;&lt;br /&gt;  &amp;lt;context:annotation-config  /&amp;gt;&lt;br /&gt;  &amp;lt;task:annotation-driven proxy-target-class="true"/&amp;gt;&lt;br /&gt;  &amp;lt;bean class="com.blogspot.hwellmann.greeter.client.GreeterClientSpringConfig"/&amp;gt;&lt;br /&gt;&lt;br /&gt;&amp;lt;/beans&amp;gt;&lt;br /&gt;&lt;/pre&gt;&lt;br /&gt;Note the &lt;code&gt;&amp;lt;task:annotation-driven&amp;gt;&lt;/code&gt; element which is required to enable the &lt;code&gt;@Async&lt;/code&gt; annotation.&lt;br /&gt;&lt;br /&gt;&lt;pre class="Java" name="code"&gt;package com.blogspot.hwellmann.greeter.client;&lt;br /&gt;&lt;br /&gt;import org.springframework.context.annotation.Bean;&lt;br /&gt;import org.springframework.context.annotation.Configuration;&lt;br /&gt;import org.springframework.remoting.httpinvoker.HttpInvokerProxyFactoryBean;&lt;br /&gt;import org.springframework.remoting.httpinvoker.SimpleHttpInvokerRequestExecutor;&lt;br /&gt;&lt;br /&gt;import com.blogspot.hwellmann.async.AsyncHttpRequestExecutor;&lt;br /&gt;import com.blogspot.hwellmann.async.AsyncHttpRequestWorker;&lt;br /&gt;import com.blogspot.hwellmann.greeter.api.GoodbyeService;&lt;br /&gt;import com.blogspot.hwellmann.greeter.api.HelloService;&lt;br /&gt;&lt;br /&gt;@Configuration&lt;br /&gt;public class GreeterClientSpringConfig {&lt;br /&gt;    &lt;br /&gt;    private &amp;lt;T&amp;gt; T createHttpInvokerProxy(Class&amp;lt;T&amp;gt; service, String url) {&lt;br /&gt;        HttpInvokerProxyFactoryBean factory = new HttpInvokerProxyFactoryBean();&lt;br /&gt;        factory.setServiceInterface(service);&lt;br /&gt;        factory.setServiceUrl(url);&lt;br /&gt;        factory.setHttpInvokerRequestExecutor(asyncHttpRequestExecutor());&lt;br /&gt;        factory.afterPropertiesSet();&lt;br /&gt;        return service.cast(factory.getObject());        &lt;br /&gt;    }&lt;br /&gt;    &lt;br /&gt;    private &amp;lt;T&amp;gt; T createHttpInvokerProxy(Class&amp;lt;T&amp;gt; service) {&lt;br /&gt;        String url = "http://remotehost:9999/remoting/" + service.getName();&lt;br /&gt;        return createHttpInvokerProxy(service, url);&lt;br /&gt;    }&lt;br /&gt;    &lt;br /&gt;    @Bean&lt;br /&gt;    public HelloService helloProxy() {&lt;br /&gt;        return createHttpInvokerProxy(HelloService.class);&lt;br /&gt;    }&lt;br /&gt;    &lt;br /&gt;    @Bean&lt;br /&gt;    public GoodbyeService goodbyeProxy() {&lt;br /&gt;        return createHttpInvokerProxy(GoodbyeService.class);&lt;br /&gt;    }&lt;br /&gt;    &lt;br /&gt;    @Bean&lt;br /&gt;    public SimpleHttpInvokerRequestExecutor asyncHttpRequestExecutor() {&lt;br /&gt;        return new AsyncHttpRequestExecutor();&lt;br /&gt;    }&lt;br /&gt;    &lt;br /&gt;    @Bean&lt;br /&gt;    public AsyncHttpRequestWorker asyncWorker() {&lt;br /&gt;        return new AsyncHttpRequestWorker();&lt;br /&gt;    }&lt;br /&gt;&lt;br /&gt;    @Bean&lt;br /&gt;    public GreeterClient greeterClient() {&lt;br /&gt;        return new GreeterClient();&lt;br /&gt;    }    &lt;br /&gt;}&lt;br /&gt;&lt;/pre&gt;&lt;br /&gt;You'll probably want to use a &lt;code&gt;PropertyPlaceholderConfigurer&lt;/code&gt; to inject the remote host name from a properties file.&lt;br /&gt;&lt;br /&gt;&lt;h4&gt;The Glue&lt;/h4&gt;&lt;br /&gt;Here is a helper class reducing the amount of boilerplate code for exporting your services on the server:&lt;br /&gt;&lt;br /&gt;&lt;pre class="Java" name="code"&gt;package com.blogspot.hwellmann.async;&lt;br /&gt;&lt;br /&gt;import java.io.IOException;&lt;br /&gt;import java.util.HashMap;&lt;br /&gt;import java.util.Map;&lt;br /&gt;&lt;br /&gt;import org.springframework.remoting.httpinvoker.SimpleHttpInvokerServiceExporter;&lt;br /&gt;import org.springframework.remoting.support.SimpleHttpServerFactoryBean;&lt;br /&gt;&lt;br /&gt;import com.sun.net.httpserver.HttpHandler;&lt;br /&gt;&lt;br /&gt;@SuppressWarnings("restriction")&lt;br /&gt;public class HttpServiceExporterFactoryBean extends SimpleHttpServerFactoryBean {&lt;br /&gt;&lt;br /&gt;    public static final String DEFAULT_CONTEXT_ROOT = "/remoting/";&lt;br /&gt;    &lt;br /&gt;    private Map&amp;lt;String, HttpHandler&amp;gt; contexts = new HashMap&amp;lt;String, HttpHandler&amp;gt;();&lt;br /&gt;    &lt;br /&gt;    private String contextRoot = DEFAULT_CONTEXT_ROOT;&lt;br /&gt;&lt;br /&gt;    &lt;br /&gt;    public &amp;lt;T&amp;gt; void add(Class&amp;lt;T&amp;gt; klass, T service) {&lt;br /&gt;&lt;br /&gt;        SimpleHttpInvokerServiceExporter exporter = new SimpleHttpInvokerServiceExporter();&lt;br /&gt;        exporter.setService(service);&lt;br /&gt;        exporter.setServiceInterface(klass);&lt;br /&gt;        exporter.afterPropertiesSet();&lt;br /&gt;&lt;br /&gt;        contexts.put(contextRoot + klass.getName(), exporter);&lt;br /&gt;    }&lt;br /&gt;    &lt;br /&gt;    @Override&lt;br /&gt;    public void afterPropertiesSet() throws IOException {&lt;br /&gt;        setContexts(contexts);&lt;br /&gt;        super.afterPropertiesSet();&lt;br /&gt;    }&lt;br /&gt;    &lt;br /&gt;    public void setContextRoot(String contextRoot) {&lt;br /&gt;        this.contextRoot = contextRoot;&lt;br /&gt;        if (! contextRoot.endsWith("/")) {&lt;br /&gt;            this.contextRoot += "/";&lt;br /&gt;        }&lt;br /&gt;    }&lt;br /&gt;}&lt;br /&gt;&lt;br /&gt;&lt;/pre&gt;&lt;br /&gt;This is the &lt;code&gt;AsyncHttpRequestExecutor&lt;/code&gt;:&lt;br /&gt;&lt;br /&gt;&lt;pre class="Java" name="code"&gt;package com.blogspot.hwellmann.async;&lt;br /&gt;&lt;br /&gt;import java.io.ByteArrayOutputStream;&lt;br /&gt;import java.io.IOException;&lt;br /&gt;&lt;br /&gt;import javax.inject.Inject;&lt;br /&gt;&lt;br /&gt;import org.springframework.remoting.httpinvoker.HttpInvokerClientConfiguration;&lt;br /&gt;import org.springframework.remoting.httpinvoker.SimpleHttpInvokerRequestExecutor;&lt;br /&gt;import org.springframework.remoting.support.RemoteInvocationResult;&lt;br /&gt;&lt;br /&gt;public class AsyncHttpRequestExecutor extends SimpleHttpInvokerRequestExecutor {&lt;br /&gt;&lt;br /&gt;    @Inject&lt;br /&gt;    private AsyncHttpRequestWorker worker;&lt;br /&gt;    &lt;br /&gt;    @Override&lt;br /&gt;    public RemoteInvocationResult doExecuteRequest(HttpInvokerClientConfiguration config,&lt;br /&gt;            ByteArrayOutputStream baos) throws IOException, ClassNotFoundException {&lt;br /&gt;        worker.executeAsyncRequest(config, baos);&lt;br /&gt;        return new RemoteInvocationResult(null);&lt;br /&gt;    }    &lt;br /&gt;}&lt;br /&gt;&lt;/pre&gt;&lt;br /&gt;And this is the worker which gets proxied by Spring to run asynchronously:&lt;br /&gt;&lt;pre class="Java" name="code"&gt;package com.blogspot.hwellmann.async;&lt;br /&gt;&lt;br /&gt;import java.io.ByteArrayOutputStream;&lt;br /&gt;import java.io.IOException;&lt;br /&gt;&lt;br /&gt;import org.springframework.remoting.httpinvoker.HttpInvokerClientConfiguration;&lt;br /&gt;import org.springframework.remoting.httpinvoker.SimpleHttpInvokerRequestExecutor;&lt;br /&gt;import org.springframework.scheduling.annotation.Async;&lt;br /&gt;&lt;br /&gt;public class AsyncHttpRequestWorker extends SimpleHttpInvokerRequestExecutor {&lt;br /&gt;&lt;br /&gt;    @Async&lt;br /&gt;    public void executeAsyncRequest(HttpInvokerClientConfiguration config,&lt;br /&gt;            ByteArrayOutputStream baos) {&lt;br /&gt;        try {&lt;br /&gt;            super.doExecuteRequest(config, baos);&lt;br /&gt;        }&lt;br /&gt;        catch (IOException exc) {&lt;br /&gt;            exc.printStackTrace();&lt;br /&gt;        }&lt;br /&gt;        catch (ClassNotFoundException exc) {&lt;br /&gt;            exc.printStackTrace();&lt;br /&gt;        }&lt;br /&gt;    }&lt;br /&gt;}&lt;br /&gt;&lt;/pre&gt;&lt;br /&gt;That's all. Starting the server and then the client, you'll see the following output from the client...&lt;br /&gt;&lt;br /&gt;&lt;pre&gt;invoking greeter&lt;br /&gt;done&lt;br /&gt;&lt;/pre&gt;&lt;br /&gt;...and from the server:&lt;br /&gt;&lt;br /&gt;&lt;pre&gt;Hello, Mickey Mouse!&lt;br /&gt;Bye, Charlie Brown!&lt;br /&gt;Bye, Mickey Mouse!&lt;br /&gt;Hello, Donald Duck!&lt;br /&gt;Hello, Charlie Brown!&lt;br /&gt;Bye, Donald Duck!&lt;br /&gt;&lt;/pre&gt;&lt;br /&gt;The execution order on the server is indeterminate.&lt;br /&gt;&lt;br /&gt;&lt;h3&gt;Traditional Approaches&lt;/h3&gt;&lt;br /&gt;In existing software systems, it is not uncommon to see a similar scenario implemented by means of a JMS message queue. &lt;br /&gt;&lt;br /&gt;Now there's nothing wrong with JMS, but I think it's simply overkill for our simple remoting scenario, where persistence or multiple subscribers are not required. Besides, JMS does not address transparency, you have to marshall your method parameters into messages and vice versa.&lt;br /&gt;&lt;br /&gt;The &lt;a href="http://lingo.codehaus.org/"&gt;Lingo&lt;/a&gt; project used to provide transparent proxies on top of JMS, but I would not recommend it. Lingo has not been maintained since 2006, the Maven artifacts are unusable due to a broken POM referencing snapshot artifacts, and it has dependencies on outdated Spring versions, so if your own system uses any recent Spring version, you'll have to patch Lingo due to some API changes in Spring.&lt;br /&gt;&lt;br /&gt;&lt;a href="http://camel.apache.org/"&gt;Apache Camel&lt;/a&gt; is sometimes perceived as an up-to-date alternative to Lingo, but in fact it &lt;a href="http://www.mail-archive.com/users@camel.apache.org/msg00732.html"&gt;does not provide transparent proxies&lt;/a&gt;.&lt;br /&gt;&lt;br /&gt;As a sidenote, Javalobby has an interesting discussion thread on &lt;a href="http://www.javalobby.org/java/forums/t62690.html"&gt;Why are Java developers ignorant of JMS and messaging in general?&lt;/a&gt;, which is five years old but still worth reading.&lt;br /&gt;&lt;br /&gt;&lt;h3&gt;Conclusion&lt;/h3&gt;&lt;br /&gt;Using either Java EE 6 or Spring 3, the standard framework APIs are sufficient to implement  transparent asynchronous communication with a remote system. Third-party frameworks or additional systems like a JMS server are not required.&lt;br /&gt;&lt;br /&gt;While Java EE 6 has a standard solution for this scenario, there is no direct equivalent in Spring 3. Anybody still claiming that Spring is &lt;i&gt;"simpler than Java EE"&lt;/i&gt;?&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/7836204352369514180-6132908487373806076?l=hwellmann.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://hwellmann.blogspot.com/feeds/6132908487373806076/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=7836204352369514180&amp;postID=6132908487373806076' title='2 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/7836204352369514180/posts/default/6132908487373806076'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/7836204352369514180/posts/default/6132908487373806076'/><link rel='alternate' type='text/html' href='http://hwellmann.blogspot.com/2011/01/transparent-asynchronous-remoting.html' title='Transparent Asynchronous Remoting'/><author><name>Harald Wellmann</name><uri>http://www.blogger.com/profile/08039976160321882828</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='16' height='16' src='http://img2.blogblog.com/img/b16-rounded.gif'/></author><thr:total>2</thr:total></entry><entry><id>tag:blogger.com,1999:blog-7836204352369514180.post-8222051433160640490</id><published>2011-01-18T22:07:00.000+01:00</published><updated>2011-01-18T22:07:05.422+01:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='reFit'/><category scheme='http://www.blogger.com/atom/ns#' term='OSGi'/><category scheme='http://www.blogger.com/atom/ns#' term='Fit'/><category scheme='http://www.blogger.com/atom/ns#' term='Declarative Services'/><category scheme='http://www.blogger.com/atom/ns#' term='jeeunit'/><category scheme='http://www.blogger.com/atom/ns#' term='Spring'/><category scheme='http://www.blogger.com/atom/ns#' term='Glassfish'/><category scheme='http://www.blogger.com/atom/ns#' term='JUnit'/><category scheme='http://www.blogger.com/atom/ns#' term='Java EE 6'/><title type='text'>reFit: Acceptance Testing for Java EE 6, Spring and OSGi</title><content type='html'>Even if you don't practice test-driven development, you are certainly familiar with the JUnit family of testing frameworks (including ports to other languages like cppunit, NUnit, or independent but similar approaches like TestNG).&lt;br /&gt;&lt;br /&gt;This post is about the &lt;a href="http://fit.c2.com/"&gt;Fit&lt;/a&gt; framework family, which has a somewhat different focus and is not just another JUnit clone. In a nutshell, Fit represents expected and actual test results in tables, and you do not have to be a programmer to read or write them.&lt;br /&gt;&lt;br /&gt;The following table has one column of inputs and two columns of outputs:&lt;br /&gt;&lt;br /&gt;&lt;div class="separator" style="clear: both; text-align: center;"&gt;&lt;a href="http://wiki.refit.googlecode.com/hg/img/BeforeCityFixture.png" imageanchor="1" style="margin-left: 1em; margin-right: 1em;"&gt;&lt;img border="0" height="117" src="http://wiki.refit.googlecode.com/hg/img/BeforeCityFixture.png" width="320" /&gt;&lt;/a&gt;&lt;/div&gt;Each row of this table can be regarded as an acceptance test case. You can feed this table to a given system and compare the outputs:&lt;br /&gt;&lt;br /&gt;&lt;div class="separator" style="clear: both; text-align: center;"&gt;&lt;a href="http://wiki.refit.googlecode.com/hg/img/CityFixture.png" imageanchor="1" style="margin-left: 1em; margin-right: 1em;"&gt;&lt;img border="0" height="177" src="http://wiki.refit.googlecode.com/hg/img/CityFixture.png" width="320" /&gt;&lt;/a&gt;&lt;/div&gt;It's only a couple of weeks ago I was introduced to Fit in my current project, and I must admit my first thought was "Why don't you just write a &lt;span style="font-family: &amp;quot;Courier New&amp;quot;,Courier,monospace;"&gt;@Parameterized&lt;/span&gt; JUnit test?"&lt;br /&gt;&lt;br /&gt;The answer is, JUnit is for developers, and developers only; Fit is for customers &lt;i&gt;and&lt;/i&gt; developers.&lt;br /&gt;&lt;br /&gt;You still need a developer to implement the skeleton logic of a test (called fixture in Fit), but anyone can write new test cases by adding rows or columns to a given Fit table.&lt;br /&gt;&lt;br /&gt;The Fit method and the original Java implementation were created by Ward Cunningham in or around 2002, the project is hosted on &lt;a href="http://sourceforge.net/projects/fit"&gt;Sourceforge&lt;/a&gt; and has been inactive since 2008.&lt;br /&gt;&lt;br /&gt;The &lt;a href="http://fitnesse.org/"&gt;Fitnesse&lt;/a&gt; project integrates Fit with a Wiki, it includes a modified version of the original Fit implementation and is under active development. However, Fit and Fitnesse are incompatible, Fit lets you write your test tables in plain old HTML, whereas Fitnesse supports its own Wiki syntax only.&lt;br /&gt;&lt;br /&gt;Our project has a fair amount of plain old HTML Fit tests, and our production code uses Spring, so it was a fairly natural idea to inject Spring beans from the system under test into our Fit test code.&lt;br /&gt;&lt;br /&gt;Spring is just one (and not really my favourite) framework for dependency injection (and lots of others things). so I inevitably started thinking about how to use Fit together with Java EE or OSGi.&lt;br /&gt;&lt;br /&gt;Thinking was followed by coding (yeah, it can be the other way round sometimes...), and this led to a project called &lt;a href="http://refit.googlecode.com/"&gt;reFit&lt;/a&gt; hosted on Google Code.&lt;br /&gt;&lt;br /&gt;reFit is based on the latest Fit sources from SourceForge, it provides up-to-date Maven artifacts on Maven Central and integrations with Java EE 6, Spring and OSGi Declarative Services. The Java EE integration reuses parts of my &lt;a href="http://jeeunit.googlecode.com/"&gt;jeeunit&lt;/a&gt; project.&lt;br /&gt;&lt;br /&gt;In addition, reFit lets you run Fit tests under a JUnit wrapper or from a Maven plugin, both with or without Spring integration. reFit includes ready-to-run example code for Glassfish 3.1, Spring 3, Equinox and Weld SE. &lt;br /&gt;&lt;br /&gt;There's more to come, I'm currently experimenting with a Web frontend and a WYSIWYG HTML editor.&lt;br /&gt;&lt;br /&gt;For more details, check out the &lt;a href="http://code.google.com/p/refit/wiki/FitInANutshell"&gt;reFit Wiki&lt;/a&gt;.&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/7836204352369514180-8222051433160640490?l=hwellmann.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://hwellmann.blogspot.com/feeds/8222051433160640490/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=7836204352369514180&amp;postID=8222051433160640490' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/7836204352369514180/posts/default/8222051433160640490'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/7836204352369514180/posts/default/8222051433160640490'/><link rel='alternate' type='text/html' href='http://hwellmann.blogspot.com/2011/01/refit-acceptance-testing-for-java-ee-6.html' title='reFit: Acceptance Testing for Java EE 6, Spring and OSGi'/><author><name>Harald Wellmann</name><uri>http://www.blogger.com/profile/08039976160321882828</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='16' height='16' src='http://img2.blogblog.com/img/b16-rounded.gif'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-7836204352369514180.post-222265875166699392</id><published>2011-01-04T23:08:00.000+01:00</published><updated>2011-01-04T23:08:01.994+01:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='Eclipse'/><title type='text'>Eclipse Meta-Error</title><content type='html'>&lt;div class="separator" style="clear: both; text-align: center;"&gt;&lt;a href="http://3.bp.blogspot.com/_BJAmlQZb_Bs/TSOYnnMqRJI/AAAAAAAAAC8/PmYb7PfFzjU/s1600/EclipseInternalError.png" imageanchor="1" style="margin-left: 1em; margin-right: 1em;"&gt;&lt;img border="0" src="http://3.bp.blogspot.com/_BJAmlQZb_Bs/TSOYnnMqRJI/AAAAAAAAAC8/PmYb7PfFzjU/s1600/EclipseInternalError.png" /&gt;&lt;/a&gt;&lt;/div&gt;&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/7836204352369514180-222265875166699392?l=hwellmann.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://hwellmann.blogspot.com/feeds/222265875166699392/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=7836204352369514180&amp;postID=222265875166699392' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/7836204352369514180/posts/default/222265875166699392'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/7836204352369514180/posts/default/222265875166699392'/><link rel='alternate' type='text/html' href='http://hwellmann.blogspot.com/2011/01/eclipse-meta-error.html' title='Eclipse Meta-Error'/><author><name>Harald Wellmann</name><uri>http://www.blogger.com/profile/08039976160321882828</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='16' height='16' src='http://img2.blogblog.com/img/b16-rounded.gif'/></author><media:thumbnail xmlns:media='http://search.yahoo.com/mrss/' url='http://3.bp.blogspot.com/_BJAmlQZb_Bs/TSOYnnMqRJI/AAAAAAAAAC8/PmYb7PfFzjU/s72-c/EclipseInternalError.png' height='72' width='72'/><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-7836204352369514180.post-7742382880691425021</id><published>2011-01-01T22:00:00.000+01:00</published><updated>2011-01-01T22:00:52.569+01:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='Mojo'/><category scheme='http://www.blogger.com/atom/ns#' term='OPS4J'/><category scheme='http://www.blogger.com/atom/ns#' term='Maven'/><title type='text'>Maven Plugin Inheritance</title><content type='html'>&lt;a href="http://www.sonatype.com/books/mvnref-book/reference/writing-plugins.html"&gt;Writing Plugins&lt;/a&gt; for Maven is not hard, and &lt;a href="http://www.sonatype.com/books/mvnref-book/"&gt;Maven: The Complete Reference&lt;/a&gt; has an entire chapter on this subject. Of course, nothing is ever complete in real life or in software development, and one of the topics not covered in the book is plugin inheritance.&lt;br /&gt;&lt;br /&gt;The scenario:&lt;br /&gt;&lt;ul&gt;&lt;li&gt;There is a (fictitious) &lt;span style="font-family: &amp;quot;Courier New&amp;quot;,Courier,monospace;"&gt;maven-tea-plugin&lt;/span&gt; which takes a number of configuration parameters and has a &lt;span style="font-family: &amp;quot;Courier New&amp;quot;,Courier,monospace;"&gt;tea&lt;/span&gt; goal. It is implemented by a &lt;span style="font-family: &amp;quot;Courier New&amp;quot;,Courier,monospace;"&gt;TeaMojo&lt;/span&gt;.&lt;/li&gt;&lt;li&gt;You are writing a &lt;span style="font-family: &amp;quot;Courier New&amp;quot;,Courier,monospace;"&gt;maven-greentea-plugin&lt;/span&gt; which has almost but not quite the same behaviour as the &lt;span style="font-family: &amp;quot;Courier New&amp;quot;,Courier,monospace;"&gt;maven-tea-plugin&lt;/span&gt;. It takes the same parameters and has the same goals.&lt;/li&gt;&lt;li&gt;The natural idea is to derive a &lt;span style="font-family: &amp;quot;Courier New&amp;quot;,Courier,monospace;"&gt;GreenTeaMojo&lt;/span&gt; from the &lt;span style="font-family: &amp;quot;Courier New&amp;quot;,Courier,monospace;"&gt;TeaMojo&lt;/span&gt; and to override one or two methods of the base class, reusing all the parameters.&lt;/li&gt;&lt;/ul&gt;Unfortunately, this does not work, at least not out of the box. The problem is:&lt;br /&gt;&lt;ul&gt;&lt;li&gt;Maven uses poor man's Javadoc annotations to inject configuration parameters into Mojo classes.&lt;/li&gt;&lt;li&gt;This is &lt;a href="http://www.sonatype.com/people/2010/11/whats-in-maven-3-0-for-plugin-authors/"&gt;still true&lt;/a&gt; in Maven 3.0, even though the traditional Plexus container has now been replaced by Guice.&lt;/li&gt;&lt;li&gt;The &lt;span style="font-family: &amp;quot;Courier New&amp;quot;,Courier,monospace;"&gt;maven-plugin-plugin&lt;/span&gt; (i.e. the plugin responsible for plugin building) needs to scan the Mojo sources for Javadoc annotations, but the &lt;span style="font-family: &amp;quot;Courier New&amp;quot;,Courier,monospace;"&gt;maven-tea-plugin&lt;/span&gt; sources are not visible during the build of the &lt;span style="font-family: &amp;quot;Courier New&amp;quot;,Courier,monospace;"&gt;maven-greentea-plugin&lt;/span&gt;.&lt;/li&gt;&lt;/ul&gt;Now the &lt;a href="http://www.ops4j.org/projects/pax/construct/maven-inherit-plugin/"&gt;&lt;span style="font-family: &amp;quot;Courier New&amp;quot;,Courier,monospace;"&gt;maven-inherit-plugin&lt;/span&gt;&lt;/a&gt; from OPS4J fills the gap by looking up the plugin descriptor from the &lt;span style="font-family: &amp;quot;Courier New&amp;quot;,Courier,monospace;"&gt;maven-tea-plugin&lt;/span&gt; and merging it with any additional parameters defined in the &lt;span style="font-family: &amp;quot;Courier New&amp;quot;,Courier,monospace;"&gt;maven-greentea-plugin&lt;/span&gt;. To use it, just follow the documentation.&lt;br /&gt;&lt;br /&gt;There is just one point to note: You have to add an &lt;span style="font-family: &amp;quot;Courier New&amp;quot;,Courier,monospace;"&gt;@extendsPlugin&lt;/span&gt; annotation to your &lt;span style="font-family: &amp;quot;Courier New&amp;quot;,Courier,monospace;"&gt;GreenTeaMojo&lt;/span&gt; to indicate the plugin you want to extend, but the value of this annotation is not quite obvious. It has to be either the plugin artifact id, or the plugin short name, &lt;span style="font-family: &amp;quot;Courier New&amp;quot;,Courier,monospace;"&gt;tea&lt;/span&gt; in our case, but this requires the artifact id to be &lt;span style="font-family: &amp;quot;Courier New&amp;quot;,Courier,monospace;"&gt;maven-tea-plugin&lt;/span&gt; or &lt;span style="font-family: &amp;quot;Courier New&amp;quot;,Courier,monospace;"&gt;tea-maven-plugin&lt;/span&gt;.&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/7836204352369514180-7742382880691425021?l=hwellmann.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://hwellmann.blogspot.com/feeds/7742382880691425021/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=7836204352369514180&amp;postID=7742382880691425021' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/7836204352369514180/posts/default/7742382880691425021'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/7836204352369514180/posts/default/7742382880691425021'/><link rel='alternate' type='text/html' href='http://hwellmann.blogspot.com/2011/01/maven-plugin-inheritance.html' title='Maven Plugin Inheritance'/><author><name>Harald Wellmann</name><uri>http://www.blogger.com/profile/08039976160321882828</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='16' height='16' src='http://img2.blogblog.com/img/b16-rounded.gif'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-7836204352369514180.post-9065975668663576040</id><published>2010-12-28T21:18:00.000+01:00</published><updated>2010-12-28T21:18:24.442+01:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='Eclipse'/><category scheme='http://www.blogger.com/atom/ns#' term='jeeunit'/><category scheme='http://www.blogger.com/atom/ns#' term='Glassfish'/><category scheme='http://www.blogger.com/atom/ns#' term='JUnit'/><category scheme='http://www.blogger.com/atom/ns#' term='Java EE 6'/><title type='text'>Java EE 6 Integration Testing Easier Than Ever</title><content type='html'>With &lt;a href="http://code.google.com/p/jeeunit/"&gt;jeeunit&lt;/a&gt; 0.6.0, you can write and run JUnit integration tests for Java EE 6 components as easy as this:&lt;br /&gt;&lt;br /&gt;&lt;pre&gt;&lt;b&gt;@RunWith(JeeunitRunner.class)&lt;/b&gt;&lt;br /&gt;class MySessionBeanTest {&lt;br /&gt;    &lt;br /&gt;    @Inject&lt;br /&gt;    private MySessionBean mySessionBean;&lt;br /&gt;&lt;br /&gt;    @Test&lt;br /&gt;    public void aSimpleTest() {&lt;br /&gt;        boolean result = mySessionBean.doSomething();&lt;br /&gt;        assertTrue(result);&lt;br /&gt;    }&lt;br /&gt;}&lt;br /&gt;&lt;/pre&gt;&lt;br /&gt;The &lt;span style="font-family: &amp;quot;Courier New&amp;quot;,Courier,monospace;"&gt;JeeunitRunner&lt;/span&gt; builds a WAR on the fly, launches an embedded container, deploys the WAR and delegates all test methods to a proxy runner within the container.&lt;br /&gt;&lt;br /&gt;With this approach, you can run your test class (or even a package with multiple test classes) from Eclipse via the context menu. The container is only launched once for all classes.&lt;br /&gt;&lt;br /&gt;jeeunit currently supports Glassfish 3.1-b33 or higher. It uses the new &lt;a href="http://embedded-glassfish.java.net/nonav/apidocs/index.html"&gt;Embedded Glassfish API &lt;/a&gt;introduced in b33.&lt;br /&gt;&lt;br /&gt;Compared to earlier jeeunit versions, it is no longer required to build a test WAR manually or to provide a test suite for running multiple test classes.&lt;br /&gt;&lt;br /&gt;Thanks to the excellent service provided by &lt;a href="https://docs.sonatype.org/display/Repository/Sonatype+OSS+Maven+Repository+Usage+Guide"&gt;Sonatype OSS Repository Hosting&lt;/a&gt;, jeeunit is now available from Maven Central.&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/7836204352369514180-9065975668663576040?l=hwellmann.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://hwellmann.blogspot.com/feeds/9065975668663576040/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=7836204352369514180&amp;postID=9065975668663576040' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/7836204352369514180/posts/default/9065975668663576040'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/7836204352369514180/posts/default/9065975668663576040'/><link rel='alternate' type='text/html' href='http://hwellmann.blogspot.com/2010/12/java-ee-6-integration-testing-easier.html' title='Java EE 6 Integration Testing Easier Than Ever'/><author><name>Harald Wellmann</name><uri>http://www.blogger.com/profile/08039976160321882828</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='16' height='16' src='http://img2.blogblog.com/img/b16-rounded.gif'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-7836204352369514180.post-5294750562014015512</id><published>2010-12-18T20:50:00.001+01:00</published><updated>2011-07-26T20:41:44.049+02:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='slf4j'/><category scheme='http://www.blogger.com/atom/ns#' term='Logging'/><category scheme='http://www.blogger.com/atom/ns#' term='Glassfish'/><title type='text'>Glassfish Logging with slf4j (Part 2)</title><content type='html'>My &lt;a href="http://hwellmann.blogspot.com/2010/05/glassfish-logging-with-slf4j.html"&gt;previous post&lt;/a&gt; on the same subject is one of the most popular articles in this blog, and since Glassfish still does not officially support slf4j, this update may be helpful to anyone hitting my blog via Google trying to improve their logging experience with Glassfish.&lt;br /&gt;&lt;br /&gt;To redirect (almost) all log messages from Glassfish and your applications to the same log file and/or console, follow this recipe:&lt;br /&gt;&lt;ul&gt;&lt;li&gt; Copy these JARs to&lt;span style="font-family: &amp;quot;Courier New&amp;quot;,Courier,monospace;"&gt; [install-root]/lib/endorsed&lt;/span&gt;:&lt;/li&gt;&lt;ul&gt;&lt;li&gt;jul-to-slf4j.jar&lt;/li&gt;&lt;li&gt;slf4j-api.jar&lt;/li&gt;&lt;li&gt;logback-classic.jar&lt;/li&gt;&lt;li&gt;logback-core.jar&lt;/li&gt;&lt;/ul&gt;&lt;li&gt;Build a JAR containing your &lt;span style="font-family: &amp;quot;Courier New&amp;quot;,Courier,monospace;"&gt;logback.xml&lt;/span&gt; configuration at root level and put it in the same place. [&lt;b&gt;Update 26 Jul 2011:&lt;/b&gt; Actually, this is no longer required: Simply create a logback configuration file somewhere in your local file system and add the system property &lt;code&gt;-Dlogback.configurationFile=file:/path/to/my/logback.xml&lt;/code&gt; to your Glassfish configuration.]&lt;/li&gt;&lt;li&gt;Define a new system property in the &lt;span style="font-family: &amp;quot;Courier New&amp;quot;,Courier,monospace;"&gt;jvm-options&lt;/span&gt; section of your &lt;span style="font-family: &amp;quot;Courier New&amp;quot;,Courier,monospace;"&gt;domain.xml&lt;/span&gt;: &lt;br /&gt;&lt;code&gt;-Djava.util.logging.config.file=${com.sun.aas.instanceRoot}/config/my_logging.properties&lt;/code&gt;&lt;/li&gt;&lt;li&gt;Create the corresponding file &lt;span style="font-family: &amp;quot;Courier New&amp;quot;,Courier,monospace;"&gt;my_logging.properties&lt;/span&gt; with the following contents: &lt;/li&gt;&lt;pre&gt;handlers = org.slf4j.bridge.SLF4JBridgeHandler&lt;br /&gt;com.sun.enterprise.server.logging.GFFileHandler.flushFrequency=1&lt;br /&gt;com.sun.enterprise.server.logging.GFFileHandler.file=${com.sun.aas.instanceRoot}/logs/server.log&lt;br /&gt;com.sun.enterprise.server.logging.GFFileHandler.rotationTimelimitInMinutes=0&lt;br /&gt;com.sun.enterprise.server.logging.GFFileHandler.logtoConsole=false&lt;br /&gt;com.sun.enterprise.server.logging.GFFileHandler.rotationLimitInBytes=2000000&lt;br /&gt;com.sun.enterprise.server.logging.GFFileHandler.alarms=false&lt;br /&gt;com.sun.enterprise.server.logging.GFFileHandler.formatter=com.sun.enterprise.server.logging.UniformLogFormatter&lt;br /&gt;com.sun.enterprise.server.logging.GFFileHandler.retainErrorsStasticsForHours=0&lt;br /&gt;&lt;/pre&gt;&lt;/ul&gt;When you restart Glassfish, you should only see two log messages in the old &lt;span style="font-family: &amp;quot;Courier New&amp;quot;,Courier,monospace;"&gt;java.util.logging&lt;/span&gt; format, all the rest goes via slf4j and logback to the appenders configured in your &lt;span style="font-family: &amp;quot;Courier New&amp;quot;,Courier,monospace;"&gt;logback.xml&lt;/span&gt;. The two remaining log messages are issued before Glassfish reads the &lt;span style="font-family: &amp;quot;Courier New&amp;quot;,Courier,monospace;"&gt;domain.xml&lt;/span&gt; configuration with the adapted configuration, so there is no easy way of avoiding them.&lt;br /&gt;&lt;br /&gt;I have been using this approach on various Glassfish versions from 3.0.1 to 3.1-b33. It is rather ugly, but nonetheless effective. &lt;br /&gt;&lt;br /&gt;All this may sound rather mysterious, so I'd better add some explanations:&lt;br /&gt;&lt;br /&gt;&lt;span style="font-family: &amp;quot;Courier New&amp;quot;,Courier,monospace;"&gt;jul-to-slf4j.jar&lt;/span&gt; is a bridge for redirecting &lt;span style="font-family: &amp;quot;Courier New&amp;quot;,Courier,monospace;"&gt;java.util.logging&lt;/span&gt; via the slf4j API to any logging backend of your choice (logback in this case). To make the redirection work, the bridge has to be visible to the classloader evaluating the logging configuration. Since Glassfish starts logging very early in its bootstrapping phase, the &lt;span style="font-family: &amp;quot;Courier New&amp;quot;,Courier,monospace;"&gt;lib/endorsed&lt;/span&gt; folder is the only place where the bridge has the desired effect.&lt;br /&gt;&lt;br /&gt;Unfortunately, class file folders seem to be unsupported for endorsed  libraries. Of course, it would be easier to simply put the &lt;span style="font-family: &amp;quot;Courier New&amp;quot;,Courier,monospace;"&gt;logback.xml&lt;/span&gt;  file in &lt;span style="font-family: &amp;quot;Courier New&amp;quot;,Courier,monospace;"&gt;lib/endorsed/classes&lt;/span&gt; where you can directly edit it. But for a  quick change to your logging configuration, you can always use an editor  which supports editing ZIP/JAR file contents in place. &lt;br /&gt;&lt;br /&gt;I created the contents of &lt;span style="font-family: &amp;quot;Courier New&amp;quot;,Courier,monospace;"&gt;my_logging.properties&lt;/span&gt; by trial and error, starting with a one-liner containing only the handler. This caused a couple of exceptions as Glassfish seemed to be missing the &lt;span style="font-family: &amp;quot;Courier New&amp;quot;,Courier,monospace;"&gt;GFFileHandler&lt;/span&gt; settings, so I copied them over from the original &lt;span style="font-family: &amp;quot;Courier New&amp;quot;,Courier,monospace;"&gt;logging.properties&lt;/span&gt;.&lt;br /&gt;&lt;br /&gt;The same procedure should also work for other slf4j backends, so you could replace the logback JARs by a &lt;span style="font-family: &amp;quot;Courier New&amp;quot;,Courier,monospace;"&gt;log4j.jar&lt;/span&gt;.&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/7836204352369514180-5294750562014015512?l=hwellmann.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://hwellmann.blogspot.com/feeds/5294750562014015512/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=7836204352369514180&amp;postID=5294750562014015512' title='11 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/7836204352369514180/posts/default/5294750562014015512'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/7836204352369514180/posts/default/5294750562014015512'/><link rel='alternate' type='text/html' href='http://hwellmann.blogspot.com/2010/12/glassfish-logging-with-slf4j-part-2.html' title='Glassfish Logging with slf4j (Part 2)'/><author><name>Harald Wellmann</name><uri>http://www.blogger.com/profile/08039976160321882828</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='16' height='16' src='http://img2.blogblog.com/img/b16-rounded.gif'/></author><thr:total>11</thr:total></entry><entry><id>tag:blogger.com,1999:blog-7836204352369514180.post-1439346675548754816</id><published>2010-12-18T18:47:00.000+01:00</published><updated>2010-12-18T18:47:43.440+01:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='Weld'/><category scheme='http://www.blogger.com/atom/ns#' term='Glassfish'/><category scheme='http://www.blogger.com/atom/ns#' term='CDI'/><category scheme='http://www.blogger.com/atom/ns#' term='Java EE 6'/><title type='text'>An Update on Memory Issues in Glassfish and Weld</title><content type='html'>Using the most recent Glassfish milestone build 3.1-b33, I took another look at the memory issues that had &lt;a href="http://hwellmann.blogspot.com/2010/11/cdi-major-risk-factor-in-java-ee-6.html"&gt;plagued my project on Glassfish 3.0.1&lt;/a&gt;. The last build I tried was b30, which &lt;a href="http://hwellmann.blogspot.com/2010/12/glassfish-and-weld-new-builds-new-bugs.html"&gt;did not even let me deploy&lt;/a&gt; my application.&lt;br /&gt;&lt;br /&gt;Just in time for Christmas, there are Good Tidings - Weld has improved a lot, and I can no longer see any suspicious memory usage related to Weld. I took my Wicket+EJB+OpenJPA+PostgreSQL application packaged in a single WAR and deployed it to several different Glassfish versions from the command line. Then I used the &lt;a href="http://www.java-forum-stuttgart.de/jfs/2008/folien/F3.pdf"&gt;Eclipse Memory Analyzer&lt;/a&gt; to a create a heap dump of the running Glassfish instance.&lt;br /&gt;&lt;br /&gt;The Total Heap column in the following table is the total size of the heap as reported by the Memory Analyzer. The Shallow, Retained, and Percentage Columns refer to the amount of heap memory consumed by instances of &lt;code&gt;org.jboss.weld.introspector.weld.jlr.WeldClassImpl&lt;/code&gt;&lt;br /&gt;&lt;br /&gt;&lt;table style="padding:5px"&gt;&lt;tr&gt;  &lt;td style="padding:5px"&gt;Glassfish Version&lt;/td&gt;  &lt;td style="padding:5px"&gt;Total Heap&lt;/td&gt;  &lt;td style="padding:5px"&gt;Shallow&lt;/td&gt;  &lt;td style="padding:5px"&gt;Retained&lt;/td&gt;  &lt;td style="padding:5px"&gt;Percentage&lt;/td&gt;&lt;/tr&gt;&lt;tr&gt;  &lt;td style="padding:5px"&gt;3.0.1&lt;/td&gt;  &lt;td style="padding:5px"&gt;412.1 MB&lt;/td&gt;  &lt;td style="padding:5px"&gt;84.680&lt;/td&gt;  &lt;td style="padding:5px"&gt;378.215.056&lt;/td&gt;  &lt;td style="padding:5px"&gt;87.52 %&lt;/td&gt;&lt;/tr&gt;&lt;tr&gt;  &lt;td style="padding:5px"&gt;3.1-b26&lt;/td&gt;  &lt;td style="padding:5px"&gt;335.3 MB&lt;/td&gt;  &lt;td style="padding:5px"&gt;85.144&lt;/td&gt;  &lt;td style="padding:5px"&gt;205.527.048&lt;/td&gt;  &lt;td style="padding:5px"&gt;58.38 %&lt;/td&gt;&lt;/tr&gt;&lt;tr&gt;  &lt;td style="padding:5px"&gt;3.1-b33&lt;/td&gt;  &lt;td style="padding:5px"&gt;149.6 MB&lt;/td&gt;  &lt;td style="padding:5px"&gt;84.216&lt;/td&gt;  &lt;td style="padding:5px"&gt;7.041.704&lt;/td&gt;  &lt;td style="padding:5px"&gt;4.49 %&lt;/td&gt;&lt;/tr&gt;&lt;/table&gt;&lt;br /&gt;The retained heap of an object is the set of objects that will be garbage collected when the given parent object is garbage collected.&lt;br /&gt;&lt;br /&gt;So in b33, Weld still holds 5 % of the total heap - whether or not this is still too much or just reasonable is surely debatable. But I'm really happy to see that Weld has improved a lot, so I would no longer consider it as a no-go.&lt;br /&gt;&lt;br /&gt;The version of my application I used for these measurements is the last one that actually used Weld, before I decided in August to stop using CDI to get rid of most memory issues.&lt;br /&gt;&lt;br /&gt;I took some more measurements with the successor version in which CDI was eliminated essentially just by replacing @Inject by @EJB throughout the sources. This is really the only difference between the two versions, and here are the total heap sizes:&lt;br /&gt;&lt;br /&gt;&lt;table&gt;&lt;tr&gt;  &lt;td style="padding:5px"&gt;Glassfish Version&lt;/td&gt;  &lt;td style="padding:5px"&gt;with @Inject&lt;/td&gt;  &lt;td style="padding:5px"&gt;with @EJB&lt;/td&gt;&lt;/tr&gt;&lt;tr&gt;  &lt;td style="padding:5px"&gt;3.0.1&lt;/td&gt;  &lt;td style="padding:5px"&gt;412.1 MB&lt;/td&gt;  &lt;td style="padding:5px"&gt;44.4 MB&lt;/td&gt;&lt;/tr&gt;&lt;tr&gt;  &lt;td style="padding:5px"&gt;3.1-b33&lt;/td&gt;  &lt;td style="padding:5px"&gt;149.6 MB&lt;/td&gt;  &lt;td style="padding:5px"&gt;138.3 MB&lt;/td&gt;&lt;/tr&gt;&lt;/table&gt;&lt;br /&gt;The illustrates, as claimed in my previous post, that I was able to save 90 % of heap memory by not using CDI on Glassfish 3.0.1. Doing the same on Glassfish 3.1-b33, I can still save about 9 %.&lt;br /&gt;&lt;br /&gt;But I was really surprised to see the heap usage of my application increase by a factor of 3 between Glassfish 3.0.1 and 3.1-b33.&lt;br /&gt;&lt;br /&gt;The Memory Analyzer reveals the culprit to be &lt;code&gt;org.glassfish.hk2.classmodel.reflect.impl.TypesCtr&lt;/code&gt; with a retained heap of about 80 MB.&lt;br /&gt;&lt;br /&gt;I have no clue what this class is doing, but it smells like another case of an oversized reflective model of the application, which was just the problem with earlier Weld versions.&lt;br /&gt;&lt;br /&gt;&lt;a href="http://java.net/jira/browse/GLASSFISH-15266"&gt;GLASSFISH-15266&lt;/a&gt; is the related issue in Glassfish JIRA.&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/7836204352369514180-1439346675548754816?l=hwellmann.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://hwellmann.blogspot.com/feeds/1439346675548754816/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=7836204352369514180&amp;postID=1439346675548754816' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/7836204352369514180/posts/default/1439346675548754816'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/7836204352369514180/posts/default/1439346675548754816'/><link rel='alternate' type='text/html' href='http://hwellmann.blogspot.com/2010/12/update-on-memory-issues-in-glassfish.html' title='An Update on Memory Issues in Glassfish and Weld'/><author><name>Harald Wellmann</name><uri>http://www.blogger.com/profile/08039976160321882828</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='16' height='16' src='http://img2.blogblog.com/img/b16-rounded.gif'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-7836204352369514180.post-4125536807424090814</id><published>2010-12-10T22:18:00.000+01:00</published><updated>2010-12-10T22:18:05.406+01:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='OSGi'/><category scheme='http://www.blogger.com/atom/ns#' term='Antipatterns'/><category scheme='http://www.blogger.com/atom/ns#' term='Interfaces'/><category scheme='http://www.blogger.com/atom/ns#' term='Declarative Services'/><category scheme='http://www.blogger.com/atom/ns#' term='Spring'/><category scheme='http://www.blogger.com/atom/ns#' term='Java EE 6'/><title type='text'>The Interface Antipattern</title><content type='html'>Keeping interfaces and implementations separate is a useful design pattern for building modular systems. If your clients only depend on a service interface, you can switch service implementations without your clients even noticing.&lt;br /&gt;&lt;br /&gt;Now there can be too much of a good thing, and the quality of a software system is certainly not measured by the ratio of interfaces to classes.&lt;br /&gt;&lt;br /&gt;When you are planning to implement a &lt;span style="font-family: &amp;quot;Courier New&amp;quot;,Courier,monospace;"&gt;FrobnicatorService&lt;/span&gt;, think twice before creating an &lt;span style="font-family: &amp;quot;Courier New&amp;quot;,Courier,monospace;"&gt;IFrobnicatorService&lt;/span&gt; interface and a &lt;span style="font-family: &amp;quot;Courier New&amp;quot;,Courier,monospace;"&gt;FrobnicatorServiceImpl&lt;/span&gt;. How many different &lt;span style="font-family: &amp;quot;Courier New&amp;quot;,Courier,monospace;"&gt;Frobnicator&lt;/span&gt; implementations are there going to be? If you do need at least two implementations with distinct behaviour, then go ahead and create the interface. If there's only one implementation, then don't bother with the interface.&lt;br /&gt;&lt;br /&gt;Resist the temptation of speculative generalization: "Oh, there might be a performance bottleneck, and in that case an alternative &lt;span style="font-family: &amp;quot;Courier New&amp;quot;,Courier,monospace;"&gt;CacheingFrobnicatorServiceImpl&lt;/span&gt; might help, so I really should start with a service interface now." Think twice: you ain't gonna need it.&lt;br /&gt;&lt;br /&gt;And if you do need the interface, you can still pull it out &lt;i&gt;when&lt;/i&gt; you need it. Most IDEs have an automatic refactoring &lt;i&gt;Extract Interface&lt;/i&gt;. (Unfortunately, none of the major Java IDEs seems to have the opposite refactoring &lt;i&gt;Merge Interface and Implementation&lt;/i&gt;.)&lt;br /&gt;&lt;br /&gt;Even in Java EE, the times of interface inflation are gone with EJB 3.1, thanks to the no-interface local view. For a stateless session bean, it is enough to implement&lt;br /&gt;&lt;br /&gt;&lt;pre&gt;@Stateless&lt;br /&gt;public class FrobnicatorService {&lt;br /&gt;    &lt;br /&gt;    public void frobnicate() {&lt;br /&gt;        ...&lt;br /&gt;    }&lt;br /&gt;}&lt;br /&gt;&lt;/pre&gt;&lt;br /&gt;Every public method of this class will be part of the implicit local business interface.&lt;br /&gt;&lt;br /&gt;In OSGi, a service does not need to have a separate interface, you can register any class as a service. Even when using Declarative Services, don't get fooled by the XML syntax of the Service Component Descriptor:&lt;br /&gt;&lt;br /&gt;&lt;pre&gt;&amp;lt;service&amp;gt;&lt;br /&gt;  &amp;lt;provide interface="com.example.FrobnicatorService"/&amp;gt;&lt;br /&gt;&amp;lt;/service&amp;gt;&lt;br /&gt;&lt;br /&gt;&lt;/pre&gt;&lt;br /&gt;The &lt;span style="font-family: &amp;quot;Courier New&amp;quot;,Courier,monospace;"&gt;provide&lt;/span&gt; element has an &lt;span style="font-family: &amp;quot;Courier New&amp;quot;,Courier,monospace;"&gt;interface&lt;/span&gt; attribute, but the attribute value can be any old class.&lt;br /&gt;&lt;br /&gt;The same is true in Spring: There is no rule forcing you to inject Spring beans only via their interface. Any old class will do, even when working with automatic transaction proxies (just make sure that CGLIB is on your classpath).&lt;br /&gt;&lt;br /&gt;So remember the KISS principle and kill some of the interfaces you don't really need!&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/7836204352369514180-4125536807424090814?l=hwellmann.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://hwellmann.blogspot.com/feeds/4125536807424090814/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=7836204352369514180&amp;postID=4125536807424090814' title='1 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/7836204352369514180/posts/default/4125536807424090814'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/7836204352369514180/posts/default/4125536807424090814'/><link rel='alternate' type='text/html' href='http://hwellmann.blogspot.com/2010/12/interface-antipattern.html' title='The Interface Antipattern'/><author><name>Harald Wellmann</name><uri>http://www.blogger.com/profile/08039976160321882828</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='16' height='16' src='http://img2.blogblog.com/img/b16-rounded.gif'/></author><thr:total>1</thr:total></entry><entry><id>tag:blogger.com,1999:blog-7836204352369514180.post-1651511893144960732</id><published>2010-12-01T09:54:00.000+01:00</published><updated>2010-12-01T09:54:14.659+01:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='Weld'/><category scheme='http://www.blogger.com/atom/ns#' term='Glassfish'/><category scheme='http://www.blogger.com/atom/ns#' term='CDI'/><title type='text'>Glassfish and Weld: New builds, new bugs</title><content type='html'>My article about &lt;a href="http://hwellmann.blogspot.com/2010/11/cdi-major-risk-factor-in-java-ee-6.html"&gt;memory issues with CDI/Weld&lt;/a&gt; seems to have caused rather a wave. Someone (not me) posted a link on DZone, which triggered an unprecedented amount of traffic on this blog, there were discussions both in the Glassfish and Weld communities, and I was very happy to see that Weld appears to have made &lt;a href="http://lists.jboss.org/pipermail/weld-dev/2010-November/002746.html"&gt;significant progress&lt;/a&gt; in terms of resource usage.&lt;br /&gt;&lt;br /&gt;So the good news is: First, things are moving in the right direction with Weld, and second, blogging helps - at least in this case, it seems to have been a lot more effective than my previous bug reports and forum messages.&lt;br /&gt;&lt;br /&gt;Unfortunately, there is also some bad news. Several users have already reported regressions with Glassfish 3.1-b29 and b30 related to Weld. My application fails to deploy on b30 with a stack trace which looks like a case of&amp;nbsp;&lt;a href="http://java.net/jira/browse/GLASSFISH-13131"&gt;GLASSFISH-13131&lt;/a&gt;. So I'd better wait and try again with Glassfish 3.1 milestone 8.&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/7836204352369514180-1651511893144960732?l=hwellmann.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://hwellmann.blogspot.com/feeds/1651511893144960732/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=7836204352369514180&amp;postID=1651511893144960732' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/7836204352369514180/posts/default/1651511893144960732'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/7836204352369514180/posts/default/1651511893144960732'/><link rel='alternate' type='text/html' href='http://hwellmann.blogspot.com/2010/12/glassfish-and-weld-new-builds-new-bugs.html' title='Glassfish and Weld: New builds, new bugs'/><author><name>Harald Wellmann</name><uri>http://www.blogger.com/profile/08039976160321882828</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='16' height='16' src='http://img2.blogblog.com/img/b16-rounded.gif'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-7836204352369514180.post-6393163518198111996</id><published>2010-11-29T22:24:00.000+01:00</published><updated>2010-11-29T22:24:02.570+01:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='OSGi'/><category scheme='http://www.blogger.com/atom/ns#' term='Spring'/><category scheme='http://www.blogger.com/atom/ns#' term='Java EE 6'/><title type='text'>Java EE and Spring: Why I couldn't care less</title><content type='html'>&amp;nbsp;Java EE or Spring - for an independent software architect, the question is just as relevant as &lt;i&gt;Catholic or Protestant&lt;/i&gt; to an atheist. The question has recently been discussed in a number of articles mostly taking one side or the other:&lt;br /&gt;&lt;ul&gt;&lt;li&gt;&lt;a href="http://www.theserverside.com/discussions/thread.tss?thread_id=61023"&gt;Moving from Spring to Java EE 6: The Age of Frameworks is Over&lt;/a&gt;&lt;/li&gt;&lt;li&gt;&lt;a href="http://jandiandme.blogspot.com/2010/10/spring-vs-java-ee-and-why-i-dont-care.html"&gt;Spring vs. Java EE and Why I Don't Care&lt;/a&gt;&lt;/li&gt;&lt;li&gt;&lt;a href="http://techscouting.wordpress.com/2010/10/22/java-ee-spring-and-why-i-care/"&gt;Java EE, Spring, and why I care&lt;/a&gt;&lt;/li&gt;&lt;li&gt;&lt;a href="http://it-republik.de/jaxenter/news/Java-EE-6-und-das-Ende-von-Spring-057299.html"&gt;Java EE 6 und das Ende von Spring&lt;/a&gt;&lt;/li&gt;&lt;/ul&gt;&lt;br /&gt;In this post, I'll try to point out why I'm not fully happy with either of the two.&lt;br /&gt;&lt;br /&gt;If there's one thing that matters to me, it's modularity. To put my cards on the table, I'm a strong OSGi supporter, but I'm not even religious about that - in fact, &lt;i&gt;Living without OSGi&lt;/i&gt; (which is what I've been doing for nine months now) would be a nice headline for one of my next posts.&lt;br /&gt;&lt;br /&gt;Seen from outside, Spring and Java EE share a number of shortcomings:&lt;br /&gt;&lt;br /&gt;&lt;h3&gt;Preaching to the Converted&lt;/h3&gt;When did you last visit the official homepages of &lt;a href="http://www.oracle.com/technetwork/java/javaee/overview/index.html"&gt;Java EE&lt;/a&gt; or &lt;a href="http://www.springframework.org/"&gt;Spring&lt;/a&gt;? Take a moment to click on the links and imagine you've never heard about either. After visiting the homepages, you are none the wiser, all you get is the usual marketing blurb and a couple of newsbites completely meaningless to the uninitiated.&lt;br /&gt;&lt;br /&gt;&lt;h3&gt;Lack of focus&lt;/h3&gt;Java EE and Spring both are animals of the rare species &lt;i&gt;Sus ovipara lactifera velluta &lt;/i&gt;unknown in English speaking countries which we call &lt;a href="http://translate.google.de/translate?js=n&amp;amp;prev=_t&amp;amp;hl=de&amp;amp;ie=UTF-8&amp;amp;layout=2&amp;amp;eotf=1&amp;amp;sl=de&amp;amp;tl=en&amp;amp;u=http%3A%2F%2Fde.wikipedia.org%2Fwiki%2FEierlegende_Wollmilchsau"&gt;&lt;i&gt;eierlegende Wollmilchsau&lt;/i&gt;&lt;/a&gt; in German. In plain English, they both try to be everything to everyone and end up doing nothing in particular.&lt;br /&gt;&lt;br /&gt;In contrast, &lt;a href="http://www.osgi.org/"&gt;OSGi&lt;/a&gt; has a clear mission statement &lt;i&gt;The Dynamic Module System for Java &lt;/i&gt;and provides a link to its key benefits right on its homepage.&lt;br /&gt;&lt;br /&gt;&lt;h3&gt;Bloat&lt;/h3&gt;Ever heard about lean development? Let's have a look at the official Javadocs:&lt;br /&gt;&lt;ul&gt;&lt;li&gt;Java EE 6: 1597 classes&lt;/li&gt;&lt;li&gt;Spring 3.0.5: 2312 classes&lt;/li&gt;&lt;/ul&gt;&lt;br /&gt;&lt;h3&gt;Legacy&lt;/h3&gt;Backward compatibility is a good thing for veteran users of a framework. Users don't want to change all of their application code just for upgrading to a new framework version.&lt;br /&gt;&lt;br /&gt;On the other hand, backward compatibility can be extremely confusing to new users: There's two or three solutions for the same kind of problem, the legacy one is not marked as legacy or deprecated clearly enough, tutorials and example code still use the old style, and you can only resort to your favourite search engine or to trial and error to make things work consistently.&lt;br /&gt;&lt;br /&gt;&lt;h3&gt;Love Thy User&lt;/h3&gt;Don't just list what you can do for your users, ask them what they want you to do for them. Looking at the Java EE and Spring reference documentation, I can see that both frameworks solve lots of problems I've never had in my life.&lt;br /&gt;&lt;br /&gt;On the other hand, looking for a solution for some specific standard kind of problem, it is often surprisingly hard to find a comprehensive code example.&lt;br /&gt;&lt;br /&gt;User documentation should be structured by user stories, not by technology.&lt;br /&gt;&lt;br /&gt;&lt;h3&gt;Enough Rope&lt;/h3&gt;Both Spring and Java EE give you enough rope to hang yourself. It's easy to write messy and ugly code on top of both frameworks, and I've seen enough of that.&lt;br /&gt;&lt;br /&gt;You &lt;i&gt;can&lt;/i&gt; write loosely coupled and elegant applications on top of either, but it takes a good architect to set up guidelines and restrict the number of choices.&lt;br /&gt;&lt;br /&gt;&lt;h3&gt;Development Process Integration&lt;/h3&gt;As an application developer, you don't just write code to run on a given framework. You want to run integration tests on your applications, you want to deploy and debug them directly in your favourite IDE, and you want your batch build and continuous integration to be able to deploy your applications.&lt;br /&gt;&lt;br /&gt;When choosing a framework, always consider the entire process chain - some lack of tooling for your favourite framework may be reason enough to pick the second best instead.&lt;br /&gt;&lt;br /&gt;&lt;h3&gt;Modularity&lt;/h3&gt;My ideal framework/container/app server - pick any name you like - would allow me to write truly modular applications, enforcing modularity at design time, at compile time, and at run time. The framework itself would be modular, allowing me to pick out those and only those modules actually required by my application.&lt;br /&gt;&lt;br /&gt;It would actively support OSGi as the most mature module system for Java, and maybe a few others on top.&lt;br /&gt;&lt;br /&gt;I expect some further degree of convergence between Java EE, Spring and OSGi within the next two years or so. There has been a lot slideware and a number of proof-of-concept or early adopter projects, but my feeling is that none of this has reached production quality yet.&lt;br /&gt;&lt;br /&gt;To sum up, frameworks in general are alive and kicking, but the age of &lt;i&gt;monolithic all-in-one frameworks&lt;/i&gt; is definitely over.&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/7836204352369514180-6393163518198111996?l=hwellmann.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://hwellmann.blogspot.com/feeds/6393163518198111996/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=7836204352369514180&amp;postID=6393163518198111996' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/7836204352369514180/posts/default/6393163518198111996'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/7836204352369514180/posts/default/6393163518198111996'/><link rel='alternate' type='text/html' href='http://hwellmann.blogspot.com/2010/11/java-ee-and-spring-why-i-couldnt-care.html' title='Java EE and Spring: Why I couldn&apos;t care less'/><author><name>Harald Wellmann</name><uri>http://www.blogger.com/profile/08039976160321882828</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='16' height='16' src='http://img2.blogblog.com/img/b16-rounded.gif'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-7836204352369514180.post-3955125291867026827</id><published>2010-11-28T20:03:00.000+01:00</published><updated>2010-11-28T20:03:31.444+01:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='Eclipse'/><category scheme='http://www.blogger.com/atom/ns#' term='jeeunit'/><category scheme='http://www.blogger.com/atom/ns#' term='Spring'/><category scheme='http://www.blogger.com/atom/ns#' term='JUnit'/><category scheme='http://www.blogger.com/atom/ns#' term='Java EE 6'/><title type='text'>Java EE 6 Integration Testing with Spring</title><content type='html'>Half a year ago, I created and published the jeeunit project to fill in some gaps for running integration tests on Java EE 6 components in an embedded EJB container, mainly targeted at Embedded Glassfish 3.x. One of the alternatives I considered and dismissed before writing my own solution was the &lt;a href="http://static.springsource.org/spring/docs/3.0.x/spring-framework-reference/html/testing.html#testcontext-framework"&gt;Spring Test Context&lt;/a&gt;.&lt;br /&gt;&lt;br /&gt;At the time, I was left with the impression you had to pollute your Java EE components with Spring annotations like &lt;span style="font-family: &amp;quot;Courier New&amp;quot;,Courier,monospace;"&gt;@Transactional&lt;/span&gt; to make declarative transactions work in the Spring container, and I did not (and still do not) like the idea of writing XML just to create a couple of Java beans and wire them up.&lt;br /&gt;&lt;br /&gt;After taking a closer look at Spring 3.0.x these days, I realized a number of facts which are not quite obvious from the Spring reference manual:&lt;br /&gt;&lt;ul&gt;&lt;li&gt;You can do most of your Spring configuration (but sadly not all of it!) in Java instead of XML, which makes your application context type-safe and easier to read, and gives you refactoring support from your IDE.&lt;/li&gt;&lt;li&gt; Spring supports some (but not all) of the Java EE 6 annotations as alternatives to its own flavours.&lt;/li&gt;&lt;li&gt;You can run Stateless Session Beans and JPA entities in a Spring container with declarative transactions &lt;i&gt;without introducing dependencies on Spring APIs or annotations&lt;/i&gt;.&lt;/li&gt;&lt;/ul&gt;jeeunit now includes an example project &lt;a href="http://code.google.com/p/jeeunit/source/browse/#hg/jeeunit-example/jeeunit-example-test-spring"&gt;jeeunit-example-test-spring&lt;/a&gt; demonstrating this approach. The details are documented in the jeeunit Wiki page &lt;a href="http://code.google.com/p/jeeunit/wiki/TestingOnSpring"&gt;Testing on Spring&lt;/a&gt;.&lt;br /&gt;&lt;br /&gt;This solution is not intended to replace the original in-container-testing approach of jeeunit, because transactional Spring beans and EJBs have different run-time semantics. However, for many integration tests, these differences are irrelevant.&lt;br /&gt;&lt;br /&gt;Using the Spring Test Context instead of Embedded Glassfish and jeeunit has two main advantages:&lt;br /&gt;&lt;ul&gt;&lt;li&gt;Spring starts noticeably faster than Embedded Glassfish.&lt;/li&gt;&lt;li&gt;Launching a single test from your suite is much easier than with jeeunit. E.g. in Eclipse, you can simply use &lt;i&gt;Run as JUnit Test&lt;/i&gt; just as with plain old unit tests.&lt;/li&gt;&lt;/ul&gt;&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/7836204352369514180-3955125291867026827?l=hwellmann.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://hwellmann.blogspot.com/feeds/3955125291867026827/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=7836204352369514180&amp;postID=3955125291867026827' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/7836204352369514180/posts/default/3955125291867026827'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/7836204352369514180/posts/default/3955125291867026827'/><link rel='alternate' type='text/html' href='http://hwellmann.blogspot.com/2010/11/java-ee-6-integration-testing-with.html' title='Java EE 6 Integration Testing with Spring'/><author><name>Harald Wellmann</name><uri>http://www.blogger.com/profile/08039976160321882828</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='16' height='16' src='http://img2.blogblog.com/img/b16-rounded.gif'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-7836204352369514180.post-7326424327879968772</id><published>2010-11-04T15:40:00.002+01:00</published><updated>2010-12-18T18:53:01.536+01:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='Resin'/><category scheme='http://www.blogger.com/atom/ns#' term='Weld'/><category scheme='http://www.blogger.com/atom/ns#' term='OpenWebBeans'/><category scheme='http://www.blogger.com/atom/ns#' term='JBoss'/><category scheme='http://www.blogger.com/atom/ns#' term='Glassfish'/><category scheme='http://www.blogger.com/atom/ns#' term='CDI'/><category scheme='http://www.blogger.com/atom/ns#' term='Java EE 6'/><title type='text'>CDI - A Major Risk Factor in Java EE 6</title><content type='html'>&lt;i&gt;&lt;b&gt;Update 18 Dec 2010:&lt;/b&gt; This post mainly relates to Glassfish 3.0.1. As of 3.1-b33, the situation &lt;a href="http://hwellmann.blogspot.com/2010/12/update-on-memory-issues-in-glassfish.html"&gt;has improved a lot&lt;/a&gt;.&lt;/i&gt;&lt;br /&gt;&lt;br /&gt;Evaluating platforms and architectures for a new enterprise web application earlier this year, around March/April, scheduled to be released in 2011, I was bold enough to settle on Java EE 6.&lt;br /&gt;&lt;br /&gt;In retrospective, I do not regret this decision, but I had to spend a significant amount of time analyzing and debugging platform problems. Based on this experience with Java EE 6, which may not be representative of course, the only advice I can give is: When Java EE 7 is released, wait a year or two before using it for production, unless you have the time and resources to act as beta tester.&lt;br /&gt;&lt;br /&gt;The Java EE 6 specifications were released in December 2009, together with Glassfish v3, the first "production-quality release" of a Java EE 6 server. "Marketing release" would have been more appropriate, since going by the number of bugs in Glassfish 3.0, the main driving factor for the release date was quite obviously not a quality benchmark, but simply the need for Sun as the Java EE champion to release a working server simultaneously with the specifications.&lt;br /&gt;&lt;br /&gt;&lt;h3&gt;The Problem&lt;/h3&gt;&lt;br /&gt;Java EE 6 was advertised as the lightest Java Enterprise Edition ever, with Contexts and Dependency Injection (CDI, JSR-299) as one of the most prominent innovations. However, for my project, CDI in the guise of Weld, its reference implementation, turned out to be the largest single source of problems. In addition to a number of functional bugs where injection would not work in certain scenarios, there are at least two severe memory issues:&lt;br /&gt;&lt;ol&gt;&lt;li&gt;Weld causes &lt;a href="https://glassfish.dev.java.net/issues/show_bug.cgi?id=12368"&gt;memory leaks&lt;/a&gt; on application redeployment.&lt;/li&gt;&lt;li&gt;Even in the first deployment of an application, Weld uses enormous amounts of memory.&lt;/li&gt;&lt;/ol&gt;The first issue had plagued us for months, and my team had grown accustomed to kill all Glassfish and Eclipse processes after three or four redeployments and to re-initialize their entire workspace, which was rather a pain.&lt;br /&gt;Investigating the memory leaks using the Eclipse Memory Analyzer, I realized that Weld claimed almost 90 % of the heap memory of my application. Most of this was due to instances of &lt;span style="font-family: &amp;quot;Courier New&amp;quot;,Courier,monospace;"&gt;org.jboss.weld.introspector.weld.jlr.WeldClassImpl&lt;/span&gt;, which appears to be a reflective model of a class inspected by the CDI &lt;span style="font-family: &amp;quot;Courier New&amp;quot;,Courier,monospace;"&gt;BeanManager&lt;/span&gt;. Some instances of this class were as large as 1 MB.&lt;br /&gt;&lt;br /&gt;I should add that our application uses Wicket for the web front end, injecting EJBs into custom Wicket components. Custom components inherit from Wicket base classes with a fairly deep inheritance hierarchy and a large number of methods. This accounts for the size of the reflective models.&lt;br /&gt;&lt;br /&gt;Our usage of CDI was fairly basic, so it was just an hour's work to replace all &lt;span style="font-family: &amp;quot;Courier New&amp;quot;,Courier,monospace;"&gt;@Inject&lt;/span&gt; annotations by Java EE 5 style &lt;span style="font-family: &amp;quot;Courier New&amp;quot;,Courier,monospace;"&gt;@EJB&lt;/span&gt; annotations. After that, the heap usage of our application was reduced by 90 %, we no longer had any memory leaks, and we finally had a hassle-free edit-save-debug cycle in our development environment.&lt;br /&gt;&lt;br /&gt;The figure of 90 % heap usage by Weld was observed on Glassfish 3.0.1, running on a 32-bit JVM on Windows XP.&lt;br /&gt;&lt;br /&gt;This week, I retested the same application with Glassfish 3.1-b26 (using a newer version of Weld), running on a 64-bit JVM on Ubuntu 10.04. The result was not as drastic as before, but still about 50 % of my heap memory was consumed by Weld.&lt;br /&gt;&lt;br /&gt;&lt;h3&gt;Alternatives&lt;/h3&gt;&lt;br /&gt;This article is mainly about problems with the CDI reference implementation Weld, not about CDI as such. But these implementation details have a ripple effect:&lt;br /&gt;&lt;ul&gt;&lt;li&gt;Glassfish 3.x still is the only certified Open Source Java EE 6 server. It uses a newer version of Weld in the current 3.1 promoted builds, but I can see no indication of the Weld issues being solved in time for the 3.1 release.&lt;/li&gt;&lt;li&gt;JBoss AS 6 is likely to be the next in line for full Java EE 6 compliance. However, JBoss also includes Weld, so you're bound to run into the same kind of problems on JBoss.&lt;/li&gt;&lt;li&gt;There are alternative CDI implementations, CanDI from Caucho and OpenWebBeans from Apache. Unfortunately, unlike JPA, there is no pluggable CDI provider interface that would allow you to simply replace Weld by some other CDI implementation on Glassfish or any other server.&lt;/li&gt;&lt;li&gt;I tried running my application on Resin 4.0.8 to see if CanDI was any better than Weld. However, Resin had bugs in the JPA and EJB areas and I was unable to deploy my application, let alone run and monitor it. (Resin only aims at supporting the Java EE 6 Web Profile, but that would have been sufficient for my case.)&lt;/li&gt;&lt;/ul&gt;&lt;br /&gt;&lt;h3&gt;Conclusion&lt;/h3&gt;&lt;br /&gt;All in all, if you want to work with Java EE 6, there is currently no way around Weld. And until Weld reaches production quality, the only way to build production quality applications on Java EE 6 is to avoid using CDI.&lt;br /&gt;&lt;br /&gt;Free and Open Source Software is all about choice - so I would really love to see a pluggable CDI provider interface that would allow users to work with Glassfish and some CDI implementation other than Weld.&lt;br /&gt;&lt;br /&gt;The second best solution might be to join forces from different CDI project to make Weld stable enough for production usage.&lt;br /&gt;&lt;br /&gt;The third option would be another fully Java EE 6 compliant Open Source server (maybe Geronimo?) not including Weld.&lt;br /&gt;&lt;br /&gt;No idea if any of these options is realistic, but this is on my wishlist for 2011.&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/7836204352369514180-7326424327879968772?l=hwellmann.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://hwellmann.blogspot.com/feeds/7326424327879968772/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=7836204352369514180&amp;postID=7326424327879968772' title='11 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/7836204352369514180/posts/default/7326424327879968772'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/7836204352369514180/posts/default/7326424327879968772'/><link rel='alternate' type='text/html' href='http://hwellmann.blogspot.com/2010/11/cdi-major-risk-factor-in-java-ee-6.html' title='CDI - A Major Risk Factor in Java EE 6'/><author><name>Harald Wellmann</name><uri>http://www.blogger.com/profile/08039976160321882828</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='16' height='16' src='http://img2.blogblog.com/img/b16-rounded.gif'/></author><thr:total>11</thr:total></entry><entry><id>tag:blogger.com,1999:blog-7836204352369514180.post-1247650056350340556</id><published>2010-09-19T16:47:00.004+02:00</published><updated>2010-09-26T11:13:27.781+02:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='OpenJPA'/><category scheme='http://www.blogger.com/atom/ns#' term='OSGi'/><category scheme='http://www.blogger.com/atom/ns#' term='Aries'/><category scheme='http://www.blogger.com/atom/ns#' term='JPA'/><title type='text'>OpenJPA and OSGi</title><content type='html'>In my &lt;a href="http://hwellmann.blogspot.com/2010/09/osgi-support-in-jpa-20-persistence.html"&gt;previous review&lt;/a&gt; of OSGi support in JPA 2.0 persistence providers, I promised to explain my setup for using &lt;a href="http://openjpa.apache.org/"&gt;OpenJPA&lt;/a&gt; in an OSGi environment.&lt;br /&gt;&lt;br /&gt;The solution I'm going to outline is by no means final, and in the meantime, my first shot has been greatly simplified using some valuable input from the Apache Aries User mailing list.&lt;br /&gt;&lt;br /&gt;In the past, brute force solutions like &lt;span style="font-family: &amp;quot;Courier New&amp;quot;,Courier,monospace;"&gt;DynamicImport-Package&lt;/span&gt; were more or less the only way to let a JPA provider bundle access all the required classes for a persistence unit from application bundles. Since Release 4.2, the &lt;a href="http://www.osgi.org/Download/File?url=/download/r4v42/r4.enterprise.pdf"&gt;OSGi Enterprise Specification&lt;/a&gt; standardizes a whole lot of OSGi service wrappers for well-known Java EE APIs, including JPA, JDBC, JTA and JNDI, so this should be the preferred way of integrating&amp;nbsp; JPA providers into an OSGi environment.&lt;br /&gt;&lt;br /&gt;The &lt;a href="http://incubator.apache.org/aries"&gt;Apache Aries&lt;/a&gt; project provides (partial) implementations for some of the OSGi enterprise services and a whole lot of other things beyond the scope of this article. Fortunately, all their service implementations are nicely modular, so it is quite easy to use just the JPA and JNDI Services from Aries to make OpenJPA work on OSGi, following the OSGi Enterprise spec rather closely (though not fully).&lt;br /&gt;&lt;br /&gt;Here is an overview of the required steps:&lt;br /&gt;&lt;ul&gt;&lt;li&gt;Get OSGi bundles for OpenJPA and all its dependencies, plus the required Aries bundles.&lt;/li&gt;&lt;li&gt;Publish the datasource to be used by your persistence unit as an OSGi service. &lt;/li&gt;&lt;li&gt;Make sure that your persistence.xml satisfies a number of restrictions. &lt;/li&gt;&lt;li&gt;Run the OpenJPA enhancer and package all classes and metadata of your persistence unit into a bundle with a special manifest header.&lt;/li&gt;&lt;li&gt;Start your OSGi framework. The JPA Service will publish an EntityManagerFactory service for each persistence unit.&lt;/li&gt;&lt;li&gt;In your client bundles, import your persistence bundle, OpenJPA and &lt;span style="font-family: &amp;quot;Courier New&amp;quot;,Courier,monospace;"&gt;javax.persistence&lt;/span&gt;, get the appropriate &lt;span style="font-family: &amp;quot;Courier New&amp;quot;,Courier,monospace;"&gt;EntityManagerFactory&lt;/span&gt; from the service registry and use it just like in an unmanaged Java SE environment.&lt;/li&gt;&lt;/ul&gt;Each step is explained in more detail in the following sections. I'm using Java 1.6.0, Maven 2.2.1 for collecting the dependencies, Eclipse 3.5.2 for doing most of the work, and the corresponding Equinox version as OSGi runtime.&lt;br /&gt;&lt;br /&gt;&lt;h3&gt;Get the dependencies&lt;/h3&gt;&lt;br /&gt;The main JAR in the OpenJPA binary distribution is an OSGi bundle, but most of the included dependencies are plain old JARs, so you need to go shopping for osgified versions of all required libraries. All the required bundles for this example can be found in the SpringSource Enterprise Bundle Repository.&lt;br /&gt;&lt;br /&gt;The following is the best part of a Maven POM for copying all the dependencies to a local directory &lt;span style="font-family: &amp;quot;Courier New&amp;quot;,Courier,monospace;"&gt;target/platform/plugins&lt;/span&gt;.&lt;br /&gt;&lt;br /&gt;You need to add the OSGi framework, &lt;span style="font-family: &amp;quot;Courier New&amp;quot;,Courier,monospace;"&gt;javax.persistence&lt;/span&gt; (I copied both of them from Eclipse 3.5.2) and a JDBC driver bundle for your database. Then copy the whole lot to a new directory to be used as target platform for your Eclipse workspace.&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;&lt;pre&gt;&amp;lt;project&amp;gt;&lt;br /&gt;  &amp;lt;properties&amp;gt;&lt;br /&gt;    &amp;lt;aries.version&amp;gt;0.2-incubating&amp;lt;/aries.version&amp;gt;&lt;br /&gt;    &amp;lt;output.dir&amp;gt;${project.build.directory}/platform/plugins&amp;lt;/output.dir&amp;gt;&lt;br /&gt;  &amp;lt;/properties&amp;gt;&lt;br /&gt;  &amp;lt;dependencies&amp;gt;&lt;br /&gt;    &amp;lt;dependency&amp;gt;  &lt;br /&gt;      &amp;lt;groupId&amp;gt;javax.transaction&amp;lt;/groupId&amp;gt;  &lt;br /&gt;      &amp;lt;artifactId&amp;gt;com.springsource.javax.transaction&amp;lt;/artifactId&amp;gt;  &lt;br /&gt;      &amp;lt;version&amp;gt;1.1.0&amp;lt;/version&amp;gt; &lt;br /&gt;    &amp;lt;/dependency&amp;gt;    &lt;br /&gt;    &amp;lt;dependency&amp;gt;&lt;br /&gt;      &amp;lt;groupId&amp;gt;net.sourceforge.serp&amp;lt;/groupId&amp;gt;&lt;br /&gt;      &amp;lt;artifactId&amp;gt;com.springsource.serp&amp;lt;/artifactId&amp;gt;&lt;br /&gt;      &amp;lt;version&amp;gt;1.13.1&amp;lt;/version&amp;gt;&lt;br /&gt;    &amp;lt;/dependency&amp;gt;&lt;br /&gt;    &amp;lt;dependency&amp;gt;&lt;br /&gt;      &amp;lt;groupId&amp;gt;org.apache.aries&amp;lt;/groupId&amp;gt;&lt;br /&gt;      &amp;lt;artifactId&amp;gt;org.apache.aries.util&amp;lt;/artifactId&amp;gt;&lt;br /&gt;      &amp;lt;version&amp;gt;${aries.version}&amp;lt;/version&amp;gt;&lt;br /&gt;    &amp;lt;/dependency&amp;gt;&lt;br /&gt;    &amp;lt;dependency&amp;gt;&lt;br /&gt;      &amp;lt;groupId&amp;gt;org.apache.aries.jndi&amp;lt;/groupId&amp;gt;&lt;br /&gt;      &amp;lt;artifactId&amp;gt;org.apache.aries.jndi.api&amp;lt;/artifactId&amp;gt;&lt;br /&gt;      &amp;lt;version&amp;gt;${aries.version}&amp;lt;/version&amp;gt;&lt;br /&gt;    &amp;lt;/dependency&amp;gt;&lt;br /&gt;    &amp;lt;dependency&amp;gt;&lt;br /&gt;      &amp;lt;groupId&amp;gt;org.apache.aries.jndi&amp;lt;/groupId&amp;gt;&lt;br /&gt;      &amp;lt;artifactId&amp;gt;org.apache.aries.jndi.core&amp;lt;/artifactId&amp;gt;&lt;br /&gt;      &amp;lt;version&amp;gt;${aries.version}&amp;lt;/version&amp;gt;&lt;br /&gt;    &amp;lt;/dependency&amp;gt;&lt;br /&gt;    &amp;lt;dependency&amp;gt;&lt;br /&gt;      &amp;lt;groupId&amp;gt;org.apache.aries.jndi&amp;lt;/groupId&amp;gt;&lt;br /&gt;      &amp;lt;artifactId&amp;gt;org.apache.aries.jndi.url&amp;lt;/artifactId&amp;gt;&lt;br /&gt;      &amp;lt;version&amp;gt;${aries.version}&amp;lt;/version&amp;gt;&lt;br /&gt;    &amp;lt;/dependency&amp;gt;&lt;br /&gt;    &amp;lt;dependency&amp;gt;&lt;br /&gt;      &amp;lt;groupId&amp;gt;org.apache.aries.jpa&amp;lt;/groupId&amp;gt;&lt;br /&gt;      &amp;lt;artifactId&amp;gt;org.apache.aries.jpa.api&amp;lt;/artifactId&amp;gt;&lt;br /&gt;      &amp;lt;version&amp;gt;${aries.version}&amp;lt;/version&amp;gt;&lt;br /&gt;    &amp;lt;/dependency&amp;gt;&lt;br /&gt;    &amp;lt;dependency&amp;gt;&lt;br /&gt;      &amp;lt;groupId&amp;gt;org.apache.aries.jpa&amp;lt;/groupId&amp;gt;&lt;br /&gt;      &amp;lt;artifactId&amp;gt;org.apache.aries.jpa.container&amp;lt;/artifactId&amp;gt;&lt;br /&gt;      &amp;lt;version&amp;gt;${aries.version}&amp;lt;/version&amp;gt;&lt;br /&gt;    &amp;lt;/dependency&amp;gt;&lt;br /&gt;    &amp;lt;dependency&amp;gt;&lt;br /&gt;      &amp;lt;groupId&amp;gt;org.apache.commons&amp;lt;/groupId&amp;gt;&lt;br /&gt;      &amp;lt;artifactId&amp;gt;com.springsource.org.apache.commons.collections&amp;lt;/artifactId&amp;gt;&lt;br /&gt;      &amp;lt;version&amp;gt;3.2.1&amp;lt;/version&amp;gt;&lt;br /&gt;    &amp;lt;/dependency&amp;gt;&lt;br /&gt;    &amp;lt;dependency&amp;gt;&lt;br /&gt;      &amp;lt;groupId&amp;gt;org.apache.commons&amp;lt;/groupId&amp;gt;&lt;br /&gt;      &amp;lt;artifactId&amp;gt;com.springsource.org.apache.commons.lang&amp;lt;/artifactId&amp;gt;&lt;br /&gt;      &amp;lt;version&amp;gt;2.2.0&amp;lt;/version&amp;gt;&lt;br /&gt;    &amp;lt;/dependency&amp;gt;&lt;br /&gt;    &amp;lt;dependency&amp;gt;&lt;br /&gt;      &amp;lt;groupId&amp;gt;org.apache.commons&amp;lt;/groupId&amp;gt;&lt;br /&gt;      &amp;lt;artifactId&amp;gt;com.springsource.org.apache.commons.pool&amp;lt;/artifactId&amp;gt;&lt;br /&gt;      &amp;lt;version&amp;gt;1.5.3&amp;lt;/version&amp;gt;&lt;br /&gt;    &amp;lt;/dependency&amp;gt;&lt;br /&gt;   &amp;lt;dependency&amp;gt;&lt;br /&gt;      &amp;lt;groupId&amp;gt;org.apache.openjpa&amp;lt;/groupId&amp;gt;&lt;br /&gt;      &amp;lt;artifactId&amp;gt;openjpa-all&amp;lt;/artifactId&amp;gt;&lt;br /&gt;      &amp;lt;version&amp;gt;2.0.1&amp;lt;/version&amp;gt;&lt;br /&gt;    &amp;lt;/dependency&amp;gt;&lt;br /&gt;    &amp;lt;dependency&amp;gt;&lt;br /&gt;      &amp;lt;groupId&amp;gt;org.slf4j&amp;lt;/groupId&amp;gt;&lt;br /&gt;      &amp;lt;artifactId&amp;gt;com.springsource.slf4j.api&amp;lt;/artifactId&amp;gt;&lt;br /&gt;      &amp;lt;version&amp;gt;1.5.0&amp;lt;/version&amp;gt;&lt;br /&gt;    &amp;lt;/dependency&amp;gt;&lt;br /&gt;    &amp;lt;dependency&amp;gt;&lt;br /&gt;      &amp;lt;groupId&amp;gt;org.slf4j&amp;lt;/groupId&amp;gt;&lt;br /&gt;      &amp;lt;artifactId&amp;gt;com.springsource.slf4j.log4j&amp;lt;/artifactId&amp;gt;&lt;br /&gt;      &amp;lt;version&amp;gt;1.5.0&amp;lt;/version&amp;gt;&lt;br /&gt;    &amp;lt;/dependency&amp;gt;&lt;br /&gt;    &amp;lt;dependency&amp;gt;&lt;br /&gt;      &amp;lt;groupId&amp;gt;org.apache.log4j&amp;lt;/groupId&amp;gt;&lt;br /&gt;      &amp;lt;artifactId&amp;gt;com.springsource.org.apache.log4j&amp;lt;/artifactId&amp;gt;&lt;br /&gt;      &amp;lt;version&amp;gt;1.2.15&amp;lt;/version&amp;gt;&lt;br /&gt;    &amp;lt;/dependency&amp;gt;&lt;br /&gt;  &amp;lt;/dependencies&amp;gt;&lt;br /&gt;  &amp;lt;build&amp;gt;&lt;br /&gt;    &amp;lt;plugins&amp;gt;&lt;br /&gt;      &amp;lt;plugin&amp;gt;&lt;br /&gt;        &amp;lt;artifactId&amp;gt;maven-dependency-plugin&amp;lt;/artifactId&amp;gt;&lt;br /&gt;        &amp;lt;executions&amp;gt;&lt;br /&gt;          &amp;lt;execution&amp;gt;&lt;br /&gt;            &amp;lt;id&amp;gt;copy-bundles&amp;lt;/id&amp;gt;&lt;br /&gt;            &amp;lt;phase&amp;gt;package&amp;lt;/phase&amp;gt;&lt;br /&gt;            &amp;lt;goals&amp;gt;&lt;br /&gt;              &amp;lt;goal&amp;gt;copy-dependencies&amp;lt;/goal&amp;gt;&lt;br /&gt;            &amp;lt;/goals&amp;gt;&lt;br /&gt;            &amp;lt;configuration&amp;gt;&lt;br /&gt;              &amp;lt;outputDirectory&amp;gt;${output.dir}&amp;lt;/outputDirectory&amp;gt;&lt;br /&gt;            &amp;lt;/configuration&amp;gt;&lt;br /&gt;          &amp;lt;/execution&amp;gt;&lt;br /&gt;        &amp;lt;/executions&amp;gt;&lt;br /&gt;      &amp;lt;/plugin&amp;gt;&lt;br /&gt;    &amp;lt;/plugins&amp;gt;&lt;br /&gt;  &amp;lt;/build&amp;gt;&lt;br /&gt;  &amp;lt;repositories&amp;gt;&lt;br /&gt;    &amp;lt;repository&amp;gt;&lt;br /&gt;      &amp;lt;id&amp;gt;com.springsource.repository.bundles.external&amp;lt;/id&amp;gt;&lt;br /&gt;      &amp;lt;name&amp;gt;SpringSource Enterprise Bundle Repository - External Bundle Releases&amp;lt;/name&amp;gt;&lt;br /&gt;      &amp;lt;url&amp;gt;http://repository.springsource.com/maven/bundles/external&amp;lt;/url&amp;gt;&lt;br /&gt;    &amp;lt;/repository&amp;gt;&lt;br /&gt;  &amp;lt;/repositories&amp;gt;&lt;br /&gt;&lt;br /&gt;&amp;lt;/project&amp;gt;&lt;br /&gt;&lt;br /&gt;&lt;/pre&gt;&lt;br /&gt;&lt;br /&gt;&lt;h3&gt;Register a data source service&lt;/h3&gt;&lt;br /&gt;A persistence unit requires a data source, either from a &lt;span style="font-family: &amp;quot;Courier New&amp;quot;,Courier,monospace;"&gt;javax.sql.DataSource&lt;/span&gt; or from a JDBC driver URL. This may be a matter of taste - in this article, I'm focusing on the &lt;span style="font-family: &amp;quot;Courier New&amp;quot;,Courier,monospace;"&gt;DataSource&lt;/span&gt;. &lt;br /&gt;&lt;br /&gt;Create a &lt;span style="font-family: &amp;quot;Courier New&amp;quot;,Courier,monospace;"&gt;DataSource&lt;/span&gt; for your database using any suitable driver and register it as an OSGi service with the &lt;span style="font-family: &amp;quot;Courier New&amp;quot;,Courier,monospace;"&gt;javax.sql.DataSource&lt;/span&gt; interface and optionally some additional identifying properties of your choice, e.g. &lt;span style="font-family: &amp;quot;Courier New&amp;quot;,Courier,monospace;"&gt;name=myds&lt;/span&gt;, in case you have more than one &lt;span style="font-family: &amp;quot;Courier New&amp;quot;,Courier,monospace;"&gt;DataSource&lt;/span&gt; in your system.&lt;br /&gt;&lt;br /&gt;It is useful to do this from a separate bundle, so that this bundle will be the only one in your system with a direct dependency on the JDBC driver.&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;&lt;h3&gt;Adapt your persistence.xml&lt;/h3&gt;&lt;br /&gt;If you have a persistence.xml which works on Java SE oder Java EE, you will probably have to modify it&amp;nbsp; to make it work with OSGi and Aries. Here is an example:&lt;br /&gt;&lt;br /&gt;&lt;pre&gt;&amp;lt;?xml version="1.0" encoding="UTF-8"?&amp;gt;&lt;br /&gt;&amp;lt;persistence version="2.0" xmlns="http://java.sun.com/xml/ns/persistence"&lt;br /&gt;  xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"&lt;br /&gt;  xsi:schemaLocation="http://java.sun.com/xml/ns/persistence http://java.sun.com/xml/ns/persistence/persistence_2_0.xsd"&amp;gt;&lt;br /&gt;  &amp;lt;persistence-unit name="myapp" &lt;b&gt;transaction-type="RESOURCE_LOCAL"&lt;/b&gt;&amp;gt;&lt;br /&gt;  &amp;lt;non-jta-data-source&amp;gt;&lt;b&gt;osgi:service/javax.sql.DataSource&lt;/b&gt;&amp;lt;/non-jta-data-source&amp;gt;   &lt;br /&gt;    &amp;lt;mapping-file&amp;gt;META-INF/orm.xml&amp;lt;/mapping-file&amp;gt;&lt;br /&gt;    &lt;b&gt;&amp;lt;exclude-unlisted-classes&amp;gt;true&amp;lt;/exclude-unlisted-classes&amp;gt;&lt;/b&gt;&lt;br /&gt;  &amp;lt;/persistence-unit&amp;gt;&lt;br /&gt;&amp;lt;/persistence&amp;gt;&lt;br /&gt;&lt;br /&gt;&lt;/pre&gt;&lt;br /&gt;First, you need to specify the &lt;span style="font-family: &amp;quot;Courier New&amp;quot;,Courier,monospace;"&gt;RESOURCE_LOCAL&lt;/span&gt; transaction type explicitly, or else OpenJPA will complain about a missing transaction manager. This is because Aries creates a container &lt;span style="font-family: &amp;quot;Courier New&amp;quot;,Courier,monospace;"&gt;EntityManagerFactory&lt;/span&gt; and not a stand-alone one.&lt;br /&gt;&lt;br /&gt;Second, your data source has to be a &lt;span style="font-family: &amp;quot;Courier New&amp;quot;,Courier,monospace;"&gt;non-jta-data-source&lt;/span&gt;. Note the special syntax for accessing your data source as an OSGi service via JNDI. To make this work, you need to include the &lt;a href="http://incubator.apache.org/aries/jndiproject.html"&gt;Aries JNDI Service&lt;/a&gt; bundles. To select a specific data source by properties, you can append an LDAP filter to the JNDI URL, e.g. &lt;code&gt;osgi:service/javax.sql.DataSource/(name=myds)&lt;/code&gt;.&lt;br /&gt;&lt;br /&gt;Third, you need to prevent the persistence provider from scanning your persistence unit for entity classes, since this may lead to classloader problems. To do so, either list all your classes explicitly if you use JPA annotations, or include all mapping files if you use XML metadata and set &lt;span style="font-family: &amp;quot;Courier New&amp;quot;,Courier,monospace;"&gt;exclude-unlisted-classes&lt;/span&gt; to &lt;span style="font-family: &amp;quot;Courier New&amp;quot;,Courier,monospace;"&gt;true&lt;/span&gt; to prevent the provider from scanning your bundle.&lt;br /&gt;&lt;br /&gt;If you get funny exceptions like&lt;br /&gt;&lt;br /&gt;&lt;pre&gt;org.apache.openjpa.persistence.PersistenceException: Error extracting class information from "bundleresource://23.fwk1421571929/".&lt;br /&gt;Caused by: java.io.FileNotFoundException: /myapp/plugins/test.openjpa/bin (Is a directory)&lt;br /&gt;&lt;/pre&gt;&lt;br /&gt;then check if you have set this option. (This problem may be specific to Eclipse, but I'm not sure about that.)&lt;br /&gt;&lt;br /&gt;&lt;h3&gt;Package your persistence unit bundle&lt;/h3&gt;&lt;br /&gt;To turn your persistence unit into a persistence bundle, make sure you have all mapping data resources and all entity classes included. In addition to the usual OSGi headers, insert the following one into your manifest:&lt;br /&gt;&lt;br /&gt;&lt;pre&gt;Meta-Persistence: META-INF/persistence.xml&lt;br /&gt;&lt;/pre&gt;&lt;br /&gt;This is the hook for Aries to discover your persistence bundle using the &lt;i&gt;extender pattern&lt;/i&gt;. If all goes well, an &lt;span style="font-family: &amp;quot;Courier New&amp;quot;,Courier,monospace;"&gt;EntityManagerFactory&lt;/span&gt; will be registered as an OSGi service.&lt;br /&gt;&lt;br /&gt;In theory, your persistence bundle should only depend on&lt;span style="font-family: &amp;quot;Courier New&amp;quot;,Courier,monospace;"&gt; javax.persistence&lt;/span&gt; and not on &lt;span style="font-family: &amp;quot;Courier New&amp;quot;,Courier,monospace;"&gt;org.apache.openjpa&lt;/span&gt;. In practice, you currently need to include this unwanted import, or else you will get exceptions of the following kind:&lt;br /&gt;&lt;br /&gt;&lt;pre&gt;java.lang.NoClassDefFoundError: org/apache/openjpa/enhance/PersistenceCapable&lt;br /&gt;&lt;/pre&gt;&lt;br /&gt;Apparently, OpenJPA tries to load one of its own classes via your persistence bundle class loader, which is incorrect.&lt;br /&gt;&lt;br /&gt;&lt;h3&gt;Use the EntityManagerFactory service in your clients&lt;/h3&gt;&lt;br /&gt;Finally, to work with your persistence unit from client bundles, just get hold of the appropriate &lt;span style="font-family: &amp;quot;Courier New&amp;quot;,Courier,monospace;"&gt;EntityManagerFactory&lt;/span&gt; service any way you like, using the filter &lt;code&gt;(osgi.unit.name=myapp)&lt;/code&gt;.&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;&lt;b&gt;Update 26 Sep 2010:&lt;/b&gt; I have submitted some sample code for inclusion into the OpenJPA test suite. The sample is attached to &lt;a href="https://issues.apache.org/jira/browse/OPENJPA-1815"&gt;OPENJPA-1815&lt;/a&gt;.&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/7836204352369514180-1247650056350340556?l=hwellmann.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://hwellmann.blogspot.com/feeds/1247650056350340556/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=7836204352369514180&amp;postID=1247650056350340556' title='2 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/7836204352369514180/posts/default/1247650056350340556'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/7836204352369514180/posts/default/1247650056350340556'/><link rel='alternate' type='text/html' href='http://hwellmann.blogspot.com/2010/09/openjpa-and-osgi.html' title='OpenJPA and OSGi'/><author><name>Harald Wellmann</name><uri>http://www.blogger.com/profile/08039976160321882828</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='16' height='16' src='http://img2.blogblog.com/img/b16-rounded.gif'/></author><thr:total>2</thr:total></entry><entry><id>tag:blogger.com,1999:blog-7836204352369514180.post-4124635204176047962</id><published>2010-09-15T23:25:00.000+02:00</published><updated>2010-09-15T23:25:37.009+02:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='OpenJPA'/><category scheme='http://www.blogger.com/atom/ns#' term='OSGi'/><category scheme='http://www.blogger.com/atom/ns#' term='Eclipselink'/><category scheme='http://www.blogger.com/atom/ns#' term='Hibernate'/><category scheme='http://www.blogger.com/atom/ns#' term='JPA'/><title type='text'>OSGi Support in JPA 2.0 Persistence Providers</title><content type='html'>About three years ago, I started working with Hibernate in an OSGi environment, and at that time, I had to roll &lt;a href="http://hwellmann.blogspot.com/2008/11/hibernate-and-osgi-elaborate-solution.html"&gt;my own solution&lt;/a&gt; for resolving all sorts of classloader issues. &lt;br /&gt;&lt;br /&gt;Since then, with OSGi 4.2 and JPA 2.0, there have been major specification releases, followed by implementations; OSGi is growing ever more popular, and the current release of the JPA standard has integrated a lot of functionality which used to be available in proprietary API extensions only.&lt;br /&gt;&lt;br /&gt;The OSGi 4.2 Enterprise Specification includes JPA, JTA and JDBC services, so in theory, using JPA in an OSGi environment should stop being an issue, as soon as this specification is supported by all OSGi and JPA implementations.&lt;br /&gt;&lt;br /&gt;In practice, the specifications are not yet fully covered by the available implementations, and the degree of OSGi support varies a lot.&lt;br /&gt;&lt;br /&gt;In the past few months, I have worked with the current versions of the three certified JPA 2.0 persistence providers, and in my opinion, the ranking for OSGi support is quite clear:&lt;br /&gt;&lt;ol&gt;&lt;li&gt;Eclipselink&lt;/li&gt;&lt;li&gt;OpenJPA&lt;/li&gt;&lt;li&gt;Hibernate&lt;/li&gt;&lt;/ol&gt;Some more details on each provider:&lt;br /&gt;&lt;br /&gt;&lt;h3&gt;Eclipselink&lt;/h3&gt;&lt;br /&gt;Eclipselink has a fully osgified distribution containing OSGi bundles of Eclipselink itself and all dependencies. To make your entity classes visible to Eclipselink, all you need to do is add a &lt;span style="font-family: &amp;quot;Courier New&amp;quot;,Courier,monospace;"&gt;JPA-PersistenceUnits&lt;/span&gt; manifest header to each bundle containing one or more persistence units. This is enough for Eclipselink to load all your XML metadata and entity classes.&lt;br /&gt;&lt;br /&gt;No ugly hacks, no buddy policies or fragments, it just works out of the box.&lt;br /&gt;&lt;br /&gt;So for a quick start with JPA under OSGi, Eclipslink is definitely the best choice, even though the OSGi 4.2 JPA Service Specification is not yet fully supported (for instance, the &lt;span style="font-family: &amp;quot;Courier New&amp;quot;,Courier,monospace;"&gt;Meta-Persistence&lt;/span&gt; header does not work), but this will be of little or no concern to most users.&lt;br /&gt;&lt;br /&gt;Leaving OSGi aside, I have been bitten by a number of bugs in Eclipselink, discussed in &lt;a href="http://hwellmann.blogspot.com/search/label/Eclipselink"&gt;earlier articles&lt;/a&gt;. If you do not use any of these features, you may be very happy with Eclipselink. For me, this set of bugs is currently a no-go, so I have migrated my OSGi applications from Eclipselink to OpenJPA.&lt;br /&gt;&lt;br /&gt;&lt;h3&gt;OpenJPA&lt;/h3&gt;&lt;br /&gt;The silver medal goes to OpenJPA: OSGi does not appear to be on the top of the agenda of the OpenJPA core developers, but since OpenJPA is used under OSGi by &lt;a href="http://incubator.apache.org/aries/"&gt;Aries&lt;/a&gt;, another Apache project, there is at least a certain level of OSGi support.&lt;br /&gt;&lt;br /&gt;In the binary distribution, the OpenJPA aggregate JAR is an OSGi bundle, but most of the dependencies are plain old JARs, so you need to find osgified versions of the dependencies on your own. The same goes for the Maven artifacts.&lt;br /&gt;&lt;br /&gt;Once you have downloaded the appropriate OSGi bundles, you still have to do some extra work to ensure that OpenJPA finds your persistence units and your entity classes, and there are a couple of minor issues with the enhancer and with user-defined value handlers.&lt;br /&gt;&lt;br /&gt;I will explain the details of my setup and some of the problems that should be addressed in OpenJPA in my next post.&lt;br /&gt;&lt;br /&gt;&lt;h3&gt;Hibernate&lt;/h3&gt;&lt;br /&gt;Sadly, regarding OSGi support, Hibernate 3.5.x is not much different from the 3.2.x release I discussed in my earlier articles. The distribution contains plain old JARs, no OSGi bundles. The latest osgified version available from the &lt;a href="http://www.springsource.com/repository"&gt;SpringSource Enterprise Bundle Repository&lt;/a&gt; is 3.4.0, and the SpringSource versions never used to work for me, so I expect that the steps described in &lt;a href="http://hwellmann.blogspot.com/2008/11/hibernate-and-osgi-elaborate-solution.html"&gt;my 2008 article&lt;/a&gt; are still required to make Hibernate work on OSGi.&lt;br /&gt;&lt;br /&gt;&lt;i&gt;Disclaimer:&lt;/i&gt; I did not try to make Hibernate 3.5 work on OSGi, due to its lack of support of a number of JPA 2.0 features used heavily by my applications. For this reason, I have stopped using Hibernate, both on OSGi and on Java EE.&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/7836204352369514180-4124635204176047962?l=hwellmann.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://hwellmann.blogspot.com/feeds/4124635204176047962/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=7836204352369514180&amp;postID=4124635204176047962' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/7836204352369514180/posts/default/4124635204176047962'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/7836204352369514180/posts/default/4124635204176047962'/><link rel='alternate' type='text/html' href='http://hwellmann.blogspot.com/2010/09/osgi-support-in-jpa-20-persistence.html' title='OSGi Support in JPA 2.0 Persistence Providers'/><author><name>Harald Wellmann</name><uri>http://www.blogger.com/profile/08039976160321882828</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='16' height='16' src='http://img2.blogblog.com/img/b16-rounded.gif'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-7836204352369514180.post-5019877178889637428</id><published>2010-09-12T17:23:00.000+02:00</published><updated>2010-09-12T17:23:35.063+02:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='OpenJPA'/><category scheme='http://www.blogger.com/atom/ns#' term='Eclipselink'/><category scheme='http://www.blogger.com/atom/ns#' term='OpenStreetMap'/><category scheme='http://www.blogger.com/atom/ns#' term='Hibernate'/><category scheme='http://www.blogger.com/atom/ns#' term='JPA'/><title type='text'>JPA 2.0: Ordered Collections</title><content type='html'>In &lt;a href="http://hwellmann.blogspot.com/2010/07/jpa-20-mapping-map.html"&gt;earlier posts&lt;/a&gt;, I wrote about problems with persistent maps, a new feature introduced in &lt;a href="http://jcp.org/aboutJava/communityprocess/final/jsr317/index.html"&gt;JPA 2.0&lt;/a&gt;. Ordered collections with explicit order columns are another JPA 2.0 feature which, again, is not yet fully robust in all JPA 2.0 compliant and TCK tested implementations.&lt;br /&gt;&lt;br /&gt;I'm currently working with a simple JPA model for &lt;a href="http://www.openstreetmap.org/"&gt;OpenStreetMap&lt;/a&gt; (OSM). There are &lt;i&gt;ways&lt;/i&gt; and &lt;i&gt;nodes&lt;/i&gt;, and each way has a sequence of nodes. Of course the order of the nodes is important, and a node may be used more than once for a given way.&lt;br /&gt;&lt;br /&gt;Thus, the nodes collection has to be a &lt;span style="font-family: &amp;quot;Courier New&amp;quot;,Courier,monospace;"&gt;List&lt;/span&gt;, not a &lt;span style="font-family: &amp;quot;Courier New&amp;quot;,Courier,monospace;"&gt;Set&lt;/span&gt;, and we need an explicit order column specifying the sequence number of the nodes along the way. Sorting the nodes by ID would not make any sense, obviously.&lt;br /&gt;&lt;br /&gt;Here is a snippet from the model:&lt;br /&gt;&lt;br /&gt;&lt;pre&gt;@Entity&lt;br /&gt;@Table(name = "ways")&lt;br /&gt;public class OsmWay&lt;br /&gt;{&lt;br /&gt;    @Id&lt;br /&gt;    private long id;&lt;br /&gt;    &lt;br /&gt;    @ManyToMany(cascade = CascadeType.ALL)&lt;br /&gt;    @OrderColumn(name = "sequence_id")&lt;br /&gt;    @JoinTable(name = "way_nodes", &lt;br /&gt;               joinColumns = @JoinColumn(name = "id"), &lt;br /&gt;               inverseJoinColumns = @JoinColumn(name = "node_id"))&lt;br /&gt;    private List&amp;lt;OsmNode&amp;gt; nodes = new ArrayList&amp;lt;OsmNode&amp;gt;();&lt;br /&gt;}    &lt;br /&gt;&lt;/pre&gt;&lt;br /&gt;This entity is represented by two tables:&lt;br /&gt;&lt;br /&gt;&lt;pre&gt;CREATE TABLE ways&lt;br /&gt;(&lt;br /&gt;  id bigint NOT NULL&lt;br /&gt;);&lt;br /&gt;&lt;br /&gt;CREATE TABLE way_nodes&lt;br /&gt;(&lt;br /&gt;  id bigint NOT NULL,&lt;br /&gt;  node_id bigint NOT NULL,&lt;br /&gt;  sequence_id integer,&lt;br /&gt;);&lt;br /&gt;&lt;/pre&gt;&lt;br /&gt;I've tested this scenario on Hibernate 3.5.3, Eclipselink 2.1.1 and OpenJPA 2.0.1: Hibernate and OpenJPA pass, &lt;b&gt;Eclipselink fails&lt;/b&gt; with 2 issues.&lt;br /&gt;&lt;br /&gt;First, the generated DDL is incorrect: There is a &lt;span style="font-family: &amp;quot;Courier New&amp;quot;,Courier,monospace;"&gt;PRIMARY KEY (id, node_id)&lt;/span&gt; for &lt;span style="font-family: &amp;quot;Courier New&amp;quot;,Courier,monospace;"&gt;way_nodes&lt;/span&gt;. This should be &lt;span style="font-family: &amp;quot;Courier New&amp;quot;,Courier,monospace;"&gt;(id, sequence_id)&lt;/span&gt;.&lt;br /&gt;&lt;br /&gt;Second, the order of the list items is not maintained in all contexts. It is ok when the collection is lazily loaded, e.g.&lt;br /&gt;&lt;br /&gt;&lt;pre&gt;OsmWay way = em.find(OsmWay.class, wayId);&lt;br /&gt;List&amp;lt;OsmNode&amp;gt; nodes = way.getNodes();&lt;br /&gt;&lt;/pre&gt;&lt;br /&gt;but it is broken when using a fetch join:&lt;br /&gt;&lt;br /&gt;&lt;pre&gt;String jpql = "select distinct w from OsmWay w join fetch w.nodes";&lt;br /&gt;TypedQuery&amp;lt;OsmWay&amp;gt; query = em.createQuery(jpql, OsmWay.class);&lt;br /&gt;List&amp;lt;OsmWay&amp;gt; ways = query.getResultList();&lt;br /&gt;OsmWay way = ways.get(0);&lt;br /&gt;List&amp;lt;OsmNode&amp;gt; nodes = way.getNodes();&lt;br /&gt;&lt;/pre&gt;&lt;br /&gt;The funny thing is, the nodes are neither ordered by &lt;span style="font-family: &amp;quot;Courier New&amp;quot;,Courier,monospace;"&gt;sequence_id&lt;/span&gt; nor by &lt;span style="font-family: &amp;quot;Courier New&amp;quot;,Courier,monospace;"&gt;node_id&lt;/span&gt;. In my test case, the way has 5 nodes, one of which appears twice in different positions.&lt;br /&gt;&lt;br /&gt;So here is some more evidence for my claim that the JPA 2.0 TCK is insufficient.&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/7836204352369514180-5019877178889637428?l=hwellmann.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://hwellmann.blogspot.com/feeds/5019877178889637428/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=7836204352369514180&amp;postID=5019877178889637428' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/7836204352369514180/posts/default/5019877178889637428'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/7836204352369514180/posts/default/5019877178889637428'/><link rel='alternate' type='text/html' href='http://hwellmann.blogspot.com/2010/09/jpa-20-ordered-collections.html' title='JPA 2.0: Ordered Collections'/><author><name>Harald Wellmann</name><uri>http://www.blogger.com/profile/08039976160321882828</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='16' height='16' src='http://img2.blogblog.com/img/b16-rounded.gif'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-7836204352369514180.post-8029920647962759537</id><published>2010-08-08T17:48:00.000+02:00</published><updated>2010-08-08T17:48:29.903+02:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='VPN'/><category scheme='http://www.blogger.com/atom/ns#' term='IPSec'/><category scheme='http://www.blogger.com/atom/ns#' term='Linux'/><category scheme='http://www.blogger.com/atom/ns#' term='strongswan'/><category scheme='http://www.blogger.com/atom/ns#' term='Ubuntu'/><category scheme='http://www.blogger.com/atom/ns#' term='dnsmasq'/><title type='text'>Ubuntu VPN Client Setup</title><content type='html'>Not a Java topic this time: Setting up an IPSec VPN client on my Linux box was a complete nightmare. The final solution is rather easy, but I wasted hours and hours trying different clients with different configurations which simply did not work...&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;This is the environment:&lt;br /&gt;&lt;ul&gt;&lt;li&gt;Linux client machine running Kubuntu 10.04.&lt;/li&gt;&lt;li&gt;Network interface eth0 on client configured via DHCP from a Netgear Router.&lt;/li&gt;&lt;li&gt;The router acts as DNS server.&lt;/li&gt;&lt;li&gt;The home network is 192.168.0.0/24.&lt;/li&gt;&lt;li&gt;The company network has a FortiGate firewall with an IPSec VPN.&lt;/li&gt;&lt;li&gt;The IPSec tunnel uses a pre-shared key and XAUTH username/password authentication.&lt;/li&gt;&lt;li&gt;The company network is 172.16.0.0/16, VPN clients get a virtual IP adress from 172.19.0.0/24 via DHCP-over-IPSec.&lt;/li&gt;&lt;/ul&gt;The problem:&lt;br /&gt;&lt;ul&gt;&lt;li&gt;There is no official Linux VPN client for FortiGate. (This is rather ironic, given that Fortinet products include GPLed Linux code, which became public after a &lt;a href="http://gpl-violations.org/news/20050414-fortinet-injunction.html"&gt;GPL violation injunction&lt;/a&gt; in 2005.)&lt;/li&gt;&lt;li&gt;Ubuntu has just too many too buggy VPN clients and too little readable documentation on VPN setup. (I tried KNetworkManager, kvpnc, ike and openswan, mostly getting only error messages I could not make sense of. ike did work ocasionally, but most of the time, the incoming packets from the tunnel would not reach my client port.)&lt;/li&gt;&lt;/ul&gt;My solution:&lt;br /&gt;&lt;ul&gt;&lt;li&gt;strongswan for the IPSec tunnel&lt;/li&gt;&lt;li&gt;dnsmasq for merging the public and private DNS zones&lt;/li&gt;&lt;li&gt;&lt;span style="font-family: &amp;quot;Courier New&amp;quot;,Courier,monospace;"&gt;eth0&lt;/span&gt; now uses manual configuration instead of DHCP&lt;/li&gt;&lt;/ul&gt;Now for the details: The XAUTH credentials and the pre-shared key are stored in &lt;span style="font-family: &amp;quot;Courier New&amp;quot;,Courier,monospace;"&gt;/etc/ipsec.secrets&lt;/span&gt;:&lt;br /&gt;&lt;br /&gt;&lt;pre&gt;: XAUTH myusername "MyPassword"&lt;br /&gt;: PSK "MyPreSharedKey"&lt;br /&gt;&lt;/pre&gt;&lt;br /&gt;The general and connection specific settings for IPSec are in &lt;span style="font-family: &amp;quot;Courier New&amp;quot;,Courier,monospace;"&gt;/etc/ipsec.conf&lt;/span&gt;:&lt;br /&gt;&lt;br /&gt;&lt;pre&gt;config setup&lt;br /&gt;     nat_traversal=yes&lt;br /&gt;                                                             &lt;br /&gt;conn office&lt;br /&gt;     left=%defaultroute&lt;br /&gt;     leftsourceip=172.19.0.99&lt;br /&gt;     right=firewall.example.com&lt;br /&gt;     rightsubnet=172.16.0.0/16&lt;br /&gt;     auto=add&lt;br /&gt;     authby=xauthpsk&lt;br /&gt;&lt;br /&gt;&lt;/pre&gt;&lt;br /&gt;The only flaw is the explicit virtual IP address: I tried using &lt;span style="font-family: &amp;quot;Courier New&amp;quot;,Courier,monospace;"&gt;leftsourceip=%config&lt;/span&gt; to let the client use an address assigned by the server, but this did not work as FortiGate does not support the &lt;span style="font-family: &amp;quot;Courier New&amp;quot;,Courier,monospace;"&gt;ModeCfg&lt;/span&gt; protocol (at least not in the firmware version we are currently using), and I could not find out how to set up DHCP-over-IPSec with strongswan, so I ended up using an explicit address not part of the DHCP pool.&lt;br /&gt;&lt;br /&gt;After editing these files and starting the tunnel via&lt;br /&gt;&lt;br /&gt;&lt;pre&gt;ipsec restart&lt;br /&gt;ipsec up office&lt;br /&gt;&lt;/pre&gt;&lt;br /&gt;I could successfully ping addresses from the office network.&lt;br /&gt;&lt;br /&gt;In contrast both to the Windows FortiClient and the Shrew VPN Client (&lt;span style="font-family: &amp;quot;Courier New&amp;quot;,Courier,monospace;"&gt;ikea&lt;/span&gt;), strongswan does not require a virtual network device and does not change the routing table. You can see the IPSec tunnel and the corresponding policies using the commands&lt;br /&gt;&lt;br /&gt;&lt;pre&gt;ip xfrm state&lt;br /&gt;ip xfrm policy&lt;br /&gt;&lt;/pre&gt;&lt;br /&gt;The log output from the &lt;span style="font-family: &amp;quot;Courier New&amp;quot;,Courier,monospace;"&gt;strongswan&lt;/span&gt; IKEv1 daemon named &lt;span style="font-family: &amp;quot;Courier New&amp;quot;,Courier,monospace;"&gt;pluto&lt;/span&gt; can be found in &lt;span style="font-family: &amp;quot;Courier New&amp;quot;,Courier,monospace;"&gt;/etc/auth.log&lt;/span&gt;.&lt;br /&gt;&lt;br /&gt;Now for DNS: Of course I don't want all my DNS requests for things like &lt;span style="font-family: &amp;quot;Courier New&amp;quot;,Courier,monospace;"&gt;schweinebildchen.com&lt;/span&gt; to hit the office DNS server while the tunnel is up, so I'm using &lt;span style="font-family: &amp;quot;Courier New&amp;quot;,Courier,monospace;"&gt;dnsmasq&lt;/span&gt; as a simple DNS proxy which redirects all DNS requests from my local machine either to my home router or to the office DNS server via the tunnel, depending on the domain.&lt;br /&gt;&lt;br /&gt;The &lt;span style="font-family: &amp;quot;Courier New&amp;quot;,Courier,monospace;"&gt;dnsmasq&lt;/span&gt; configuration in &lt;span style="font-family: &amp;quot;Courier New&amp;quot;,Courier,monospace;"&gt;/etc/dnsmasq.conf&lt;/span&gt; is as simple as this:&lt;br /&gt;&lt;br /&gt;&lt;pre&gt;server=/example.com/172.16.0.2&lt;br /&gt;server=192.168.0.1&lt;br /&gt;&lt;/pre&gt;&lt;br /&gt;&lt;br /&gt;Finally, I changed the configuration of my network interface &lt;span style="font-family: &amp;quot;Courier New&amp;quot;,Courier,monospace;"&gt;eth0&lt;/span&gt; from auto to manual, using the IP address &lt;span style="font-family: &amp;quot;Courier New&amp;quot;,Courier,monospace;"&gt;192.168.0.5&lt;/span&gt; and set this as nameserver in &lt;span style="font-family: &amp;quot;Courier New&amp;quot;,Courier,monospace;"&gt;/etc/resolv.conf&lt;/span&gt;.&lt;br /&gt;&lt;br /&gt;This means that all DNS requests are first handled by dnsmasq on my local machine, requests for &lt;span style="font-family: &amp;quot;Courier New&amp;quot;,Courier,monospace;"&gt;example.com&lt;/span&gt;  get forwarded to the office DNS server (via the IPSec tunnel), and  everything else gets routed to my Netgear router (and from there to my  ISP).&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/7836204352369514180-8029920647962759537?l=hwellmann.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://hwellmann.blogspot.com/feeds/8029920647962759537/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=7836204352369514180&amp;postID=8029920647962759537' title='1 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/7836204352369514180/posts/default/8029920647962759537'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/7836204352369514180/posts/default/8029920647962759537'/><link rel='alternate' type='text/html' href='http://hwellmann.blogspot.com/2010/08/ubuntu-vpn-client-setup.html' title='Ubuntu VPN Client Setup'/><author><name>Harald Wellmann</name><uri>http://www.blogger.com/profile/08039976160321882828</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='16' height='16' src='http://img2.blogblog.com/img/b16-rounded.gif'/></author><thr:total>1</thr:total></entry><entry><id>tag:blogger.com,1999:blog-7836204352369514180.post-1662951656936700608</id><published>2010-07-27T21:16:00.000+02:00</published><updated>2010-07-27T21:16:59.180+02:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='Glassfish'/><category scheme='http://www.blogger.com/atom/ns#' term='Ubuntu'/><category scheme='http://www.blogger.com/atom/ns#' term='EC2'/><title type='text'>A Fish in the Clouds</title><content type='html'>How long does it take to find a hosting company and get an enterprise web application up and running from scratch? Could be weeks if there are enough lawyers and pointy-haired bosses involved. And even if you can directly talk to the providers, it usually takes a couple of days to request quotes and compare them.&lt;br /&gt;&lt;br /&gt;That's the way we started for our current project, but now we've decided to have a go at cloud computing. (So at last this adds another buzzword to my CV...)&lt;br /&gt;&lt;br /&gt;I vaguely remembered Arun Gupta's blog about &lt;a href="http://blogs.sun.com/arungupta/entry/totd_141_running_glassfish_3"&gt;Glassfish on Amazon EC2&lt;/a&gt;, and using that together with the &lt;a href="https://help.ubuntu.com/community/EC2StartersGuide"&gt;Ubuntu EC2 Starter's Guide&lt;/a&gt;, it just took me about half an hour to set up a virtual machine in the &lt;a href="http://aws.amazon.com/ec2/"&gt;Amazon Cloud&lt;/a&gt; with Ubuntu Server 10.04, JDK 1.6.0_20 and Glassfish 3.0.1, start the Glassfish domain and access the admin console from my local web browser. &lt;br /&gt;&lt;br /&gt;And downloading the 78 M Glassfish zip file on the EC2 instance from Oracle's server took less than 2 seconds...&lt;br /&gt;&lt;br /&gt;Not bad for a start. I would have expected to spend about a day to get as far as that.&lt;br /&gt;&lt;br /&gt;I was also using Ubuntu 10.04 on my local machine, working with the command line interface from the&lt;br /&gt;&lt;span style="font-family: &amp;quot;Courier New&amp;quot;,Courier,monospace;"&gt;ec2-api-tools&lt;/span&gt; Ubuntu package most of the time. &lt;br /&gt;&lt;br /&gt;Of course it will take some more time to set up the database server, deploy our web app and to secure the system. And it's too early to tell if we really require all the elasticity of EC2, which is likely to be more expensive in the long run than a conventional dedicated server cluster.&lt;br /&gt;&lt;br /&gt;At any rate, installing a site in virtually no time and running it for less than 10 cents per hour is rather impressive. Thumbs up for Amazon Web Services!&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/7836204352369514180-1662951656936700608?l=hwellmann.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://hwellmann.blogspot.com/feeds/1662951656936700608/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=7836204352369514180&amp;postID=1662951656936700608' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/7836204352369514180/posts/default/1662951656936700608'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/7836204352369514180/posts/default/1662951656936700608'/><link rel='alternate' type='text/html' href='http://hwellmann.blogspot.com/2010/07/fish-in-clouds.html' title='A Fish in the Clouds'/><author><name>Harald Wellmann</name><uri>http://www.blogger.com/profile/08039976160321882828</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='16' height='16' src='http://img2.blogblog.com/img/b16-rounded.gif'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-7836204352369514180.post-2611664083377986783</id><published>2010-07-26T23:25:00.000+02:00</published><updated>2010-07-26T23:25:12.683+02:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='Wicket'/><category scheme='http://www.blogger.com/atom/ns#' term='Eclipse'/><category scheme='http://www.blogger.com/atom/ns#' term='Maven'/><category scheme='http://www.blogger.com/atom/ns#' term='Glassfish'/><category scheme='http://www.blogger.com/atom/ns#' term='Java EE 6'/><category scheme='http://www.blogger.com/atom/ns#' term='Google Maps'/><title type='text'>Building a Java EE 6 Web Application with Eclipse Helios, Maven and Glassfish</title><content type='html'>This is a short tutorial showing how to use Eclipse 3.6 (Helios) with Glassfish and Maven for building and running a Java EE 6 web application from a multi-module source tree.&lt;br /&gt;&lt;br /&gt;We are going to import and run the Wicket &lt;span style="font-family: &amp;quot;Courier New&amp;quot;,Courier,monospace;"&gt;gmap2-examples&lt;/span&gt;, demonstrating the use of Google Maps via Apache Wicket, but this is purely incidental - even if you prefer mainstream JSF or another web framework to Wicket, you may find this tutorial useful. There are absolutely no Wicket specifics involved; gmap2 was just a handy small but non-trivial example.&lt;br /&gt;&lt;br /&gt;If you haven't worked with Maven before, you will get an idea how Maven can save you a lot of work managing the third-party dependencies of your project automatically.&lt;br /&gt;&lt;br /&gt;This is what you'll see in the end: &lt;br /&gt;&lt;br /&gt;&lt;div class="separator" style="clear: both; text-align: center;"&gt;&lt;a href="http://1.bp.blogspot.com/_BJAmlQZb_Bs/TE38T5hyPdI/AAAAAAAAACY/mPoYQB4SWuc/s1600/gmap2.png" imageanchor="1" style="margin-left: 1em; margin-right: 1em;"&gt;&lt;img border="0" height="331" src="http://1.bp.blogspot.com/_BJAmlQZb_Bs/TE38T5hyPdI/AAAAAAAAACY/mPoYQB4SWuc/s400/gmap2.png" width="400" /&gt;&lt;/a&gt;&lt;/div&gt;&lt;br /&gt;There's quite a few things on your shopping list before you can start. If you are reading this, you probably already have the following on your disk:&lt;br /&gt;&lt;ul&gt;&lt;li&gt;&lt;a href="http://www.eclipse.org/downloads/packages/eclipse-ide-java-ee-developers/heliosr"&gt;Eclipse 3.6 for Java EE Developers&lt;/a&gt;&lt;/li&gt;&lt;li&gt; &lt;a href="https://glassfish.dev.java.net/downloads/3.0.1-final.html"&gt;Glassfish 3.0.1&lt;/a&gt;&lt;/li&gt;&lt;/ul&gt;You'll need to install these features into Eclipse:&lt;br /&gt;&lt;ul&gt;&lt;li&gt;Maven Integration for Eclipse (also known as m2eclipse)&lt;/li&gt;&lt;li&gt; Maven Integration for Eclipse (Extras)&lt;/li&gt;&lt;li&gt;Glassfish Java EE Application Server Plugin for Eclipse&lt;/li&gt;&lt;/ul&gt;Eclipse 3.6 has a new way of installing plugins via &lt;b&gt;Help | Eclipse Marketplace&lt;/b&gt;. This is an integrated web client which lets you search for plugins by free text, so you no longer have to copy and paste update site URLs into the Update Manager - but you can still do so if you prefer.&lt;br /&gt;&lt;br /&gt;The &lt;a href="http://www.sonatype.com/books/m2eclipse-book/reference/"&gt;m2eclipse book&lt;/a&gt; has step-by-step instructions and screenshots explaining the installation process: &lt;a href="http://www.sonatype.com/books/m2eclipse-book/reference/install-sect-marketplace.html#d0e359"&gt;start here&lt;/a&gt; with the m2eclipse installation. When you get to the Extras, the only ones required for the rest of this tutorial are &lt;i&gt;Maven Integration for WTP&lt;/i&gt; and &lt;i&gt;Maven SCM Integration&lt;/i&gt;. The WTP integration will let Eclipse recognize your Maven projects with &lt;span style="font-family: &amp;quot;Courier New&amp;quot;,Courier,monospace;"&gt;war&lt;/span&gt; packaging as Dynamic Web Projects.&lt;br /&gt;&lt;br /&gt;The Maven SCM Integration lets you fetch Maven projects directly from source code repositories like Subversion, Mercurial or others. Note that this integration simply invokes the corresponding command line clients like &lt;span style="font-family: &amp;quot;Courier New&amp;quot;,Courier,monospace;"&gt;/usr/bin/svn&lt;/span&gt;.&lt;br /&gt;&lt;br /&gt;Having installed m2clipse via the Eclipse Marketplace, use the same procedure to install the Glassfish Plugin.&lt;br /&gt;&lt;br /&gt;After restarting Eclipse, set your Glassfish preferences via &lt;b&gt;Window | Preferences | Glassfish Preferences&lt;/b&gt;. For this tutorial, you should check &lt;i&gt;Start the Glassfish Enterprise Server in verbose mode &lt;/i&gt;and uncheck the other items.&lt;br /&gt;&lt;br /&gt;Next, define a server runtime environment via &lt;b&gt;Window | Preferences | Server | Runtime Environment | Add...&lt;/b&gt; Select the server type &lt;b&gt;Glassfish | Glassfish Server Open Source Edition 3 (Java EE 6)&lt;/b&gt;, check &lt;i&gt;Create a new local server&lt;/i&gt; and click &lt;b&gt;Next&lt;/b&gt;. Select your Glassfish installation directory - this is required to be the parent of the &lt;span style="font-family: &amp;quot;Courier New&amp;quot;,Courier,monospace;"&gt;modules&lt;/span&gt; and &lt;span style="font-family: &amp;quot;Courier New&amp;quot;,Courier,monospace;"&gt;domains&lt;/span&gt; directories, e.g. &lt;span style="font-family: &amp;quot;Courier New&amp;quot;,Courier,monospace;"&gt;/home/hwellmann/glassfish-3.0.1/glassfishv3/glassfish&lt;/span&gt;. Click &lt;b&gt;Next&lt;/b&gt; and fill in the domain name and the administrator credentials. If you did not change the Glassfish defaults, you can probably just click on &lt;b&gt;Finish&lt;/b&gt;.&lt;br /&gt;&lt;br /&gt;The &lt;b&gt;Servers&lt;/b&gt; view has opened automatically. You can select your server and click on the &lt;b&gt;Run&lt;/b&gt; button to&amp;nbsp; launch Glassfish from Eclipse. The Eclipse plugin launches Glassfish indirectly via an &lt;span style="font-family: &amp;quot;Courier New&amp;quot;,Courier,monospace;"&gt;asadmin&lt;/span&gt; subprocess.&lt;br /&gt;&lt;br /&gt;You will see some Glassfish log messages in the console. To stop Glassfish, &lt;i&gt;do not&lt;/i&gt; hit the stop button in the Console view. This will just kill the &lt;span style="font-family: &amp;quot;Courier New&amp;quot;,Courier,monospace;"&gt;asadmin&lt;/span&gt; process, but not Glassfish itself, and Eclipse and Glassfish will get terribly out of sync. Make sure to select the &lt;b&gt;Servers&lt;/b&gt; view and hit the stop button there to avoid trouble.&lt;br /&gt;&lt;br /&gt;Now for the interesting part: Let us import and build the &lt;span style="font-family: &amp;quot;Courier New&amp;quot;,Courier,monospace;"&gt;gmap2&lt;/span&gt; example project.&lt;br /&gt;&lt;br /&gt;This project has a parent project with two subprojects, or modules in Maven terms. Maven requires you to store the module subprojects of a parent project in subdirectories of the parent directory. Eclipse normally cannot handle overlapping or nested directory structures for projects in the same workspace. Fortunately, m2eclipse works some magic to flatten the project structure, making Eclipse happy.&lt;br /&gt;&lt;br /&gt;To import the example sources directly from the Subversion repository, select &lt;b&gt;File | Import... | Maven | Check out Maven Projects from SCM&lt;/b&gt; and click &lt;b&gt;Next&lt;/b&gt;. Fill in the SCM URL&lt;br /&gt;&lt;br /&gt;&lt;div style="font-family: &amp;quot;Courier New&amp;quot;,Courier,monospace;"&gt;&lt;span class="term"&gt;https://wicket-stuff.svn.sourceforge.net/svnroot/wicket-stuff/tags/wicketstuff-core-1.4.9.2/gmap2-parent&lt;/span&gt;&lt;/div&gt;&lt;br /&gt;and select the SCM provider &lt;span style="font-family: &amp;quot;Courier New&amp;quot;,Courier,monospace;"&gt;svn&lt;/span&gt;, then click &lt;b&gt;Next&lt;/b&gt; and &lt;b&gt;Finish&lt;/b&gt;.&lt;br /&gt;&lt;br /&gt;After a while, you will see three projects in your workspace:&lt;br /&gt;&lt;ul&gt;&lt;li style="font-family: &amp;quot;Courier New&amp;quot;,Courier,monospace;"&gt;&lt;span class="term"&gt;gmap2&lt;/span&gt;&lt;/li&gt;&lt;li style="font-family: &amp;quot;Courier New&amp;quot;,Courier,monospace;"&gt;&lt;span class="term"&gt;gmap2-examples&lt;/span&gt;&lt;/li&gt;&lt;li style="font-family: &amp;quot;Courier New&amp;quot;,Courier,monospace;"&gt;&lt;span class="term"&gt;gmap2-parent&lt;/span&gt;&lt;/li&gt;&lt;/ul&gt;&lt;br /&gt;The parent project &lt;span style="font-family: &amp;quot;Courier New&amp;quot;,Courier,monospace;"&gt;gmap2-parent&lt;/span&gt; has two subfolders &lt;span style="font-family: &amp;quot;Courier New&amp;quot;,Courier,monospace;"&gt;gmap2&lt;/span&gt; and &lt;span style="font-family: &amp;quot;Courier New&amp;quot;,Courier,monospace;"&gt;gmap2-examples&lt;/span&gt; which are also represented as top-level Eclipse projects - this is a special feature of the m2eclipse integration.&lt;br /&gt;&lt;br /&gt;The &lt;span style="font-family: &amp;quot;Courier New&amp;quot;,Courier,monospace;"&gt;gmap2-examples&lt;/span&gt; subproject is a web application, as indicated by the Maven packaging type &lt;span style="font-family: &amp;quot;Courier New&amp;quot;,Courier,monospace;"&gt;war&lt;/span&gt;. Using this and other information specified in the Maven POM, m2eclipse was able to turn this Eclipse project into a Dynamic Web Modules project - have a look at the Project Facets in the project properties to convince yourself.&lt;br /&gt;&lt;br /&gt;Opening the project, you will notice two classpath containers &lt;b&gt;Maven Dependencies&lt;/b&gt; and &lt;b&gt;Web App Libraries&lt;/b&gt;. The latter contains just one item &lt;span style="font-family: &amp;quot;Courier New&amp;quot;,Courier,monospace;"&gt;gmap2&lt;/span&gt; with an open folder icon, indicating a reference to another subproject in our workspace that will go into &lt;span style="font-family: &amp;quot;Courier New&amp;quot;,Courier,monospace;"&gt;WEB-INF/lib&lt;/span&gt;. The Maven Dependencies container displays all JARs required by our project, e.g. &lt;span style="font-family: &amp;quot;Courier New&amp;quot;,Courier,monospace;"&gt;wicket-1.4.9.jar&lt;/span&gt; and &lt;span style="font-family: &amp;quot;Courier New&amp;quot;,Courier,monospace;"&gt;slf4j-api-1.5.8.jar&lt;/span&gt;. All these were downloaded automatically by Maven into your local Maven repository on your hard drive, and m2eclipse makes Eclipse reference them from that location.&lt;br /&gt;&lt;br /&gt;We are now ready to launch the web app: Select the &lt;span style="font-family: &amp;quot;Courier New&amp;quot;,Courier,monospace;"&gt;gmap2-examples&lt;/span&gt; project folder and then &lt;b&gt;Run As... | Run on Server&lt;/b&gt; from the context menu. Select the existing Glassfish server you created before and click &lt;b&gt;Finish&lt;/b&gt;. After a while, you see the &lt;span style="font-family: &amp;quot;Courier New&amp;quot;,Courier,monospace;"&gt;gmap2-examples&lt;/span&gt; welcome page in a web browser window.&lt;br /&gt;&lt;br /&gt;Click on one of the links, e.g. &lt;b&gt;marker listener&lt;/b&gt;, to see Google Maps in Firefox in Eclipse via Wicket on Glassfish on Java on Linux. (OK, maybe it's not Firefox or Linux on your machine...)&lt;br /&gt;&lt;br /&gt;Note that the Java compilation and the WAR assembly and deployment were done by Eclipse, not by Maven.&lt;br /&gt;&lt;br /&gt;However, you can also run a Maven build from Eclipse. To build our entire project hierarchy, select &lt;span style="font-family: &amp;quot;Courier New&amp;quot;,Courier,monospace;"&gt;gmap2-parent&lt;/span&gt; and open &lt;b&gt;Run As | Maven build...&lt;/b&gt; from the context menu. Enter the goals &lt;span style="font-family: &amp;quot;Courier New&amp;quot;,Courier,monospace;"&gt;clean install&lt;/span&gt; and click &lt;b&gt;Run&lt;/b&gt;. You will see the Maven messages in the console window. When Maven has finished, click &lt;b&gt;Refresh (F5)&lt;/b&gt; on &lt;span style="font-family: &amp;quot;Courier New&amp;quot;,Courier,monospace;"&gt;gmap2-parent&lt;/span&gt;, and open &lt;span style="font-family: &amp;quot;Courier New&amp;quot;,Courier,monospace;"&gt;gmap2-examples/target&lt;/span&gt; to see the WAR file compiled by Maven.&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/7836204352369514180-2611664083377986783?l=hwellmann.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://hwellmann.blogspot.com/feeds/2611664083377986783/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=7836204352369514180&amp;postID=2611664083377986783' title='1 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/7836204352369514180/posts/default/2611664083377986783'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/7836204352369514180/posts/default/2611664083377986783'/><link rel='alternate' type='text/html' href='http://hwellmann.blogspot.com/2010/07/building-java-ee-6-web-application-with.html' title='Building a Java EE 6 Web Application with Eclipse Helios, Maven and Glassfish'/><author><name>Harald Wellmann</name><uri>http://www.blogger.com/profile/08039976160321882828</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='16' height='16' src='http://img2.blogblog.com/img/b16-rounded.gif'/></author><media:thumbnail xmlns:media='http://search.yahoo.com/mrss/' url='http://1.bp.blogspot.com/_BJAmlQZb_Bs/TE38T5hyPdI/AAAAAAAAACY/mPoYQB4SWuc/s72-c/gmap2.png' height='72' width='72'/><thr:total>1</thr:total></entry><entry><id>tag:blogger.com,1999:blog-7836204352369514180.post-6330123515006800909</id><published>2010-07-20T21:40:00.000+02:00</published><updated>2010-07-20T21:40:58.285+02:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='OpenJPA'/><category scheme='http://www.blogger.com/atom/ns#' term='DataNucleus'/><category scheme='http://www.blogger.com/atom/ns#' term='Eclipselink'/><category scheme='http://www.blogger.com/atom/ns#' term='Hibernate'/><category scheme='http://www.blogger.com/atom/ns#' term='JPA'/><title type='text'>JPA 2.0: Querying a Map</title><content type='html'>Welcome back to more merriment with Maps in JPA 2.0!&lt;br /&gt;&lt;br /&gt;After watching 3 out of 4 persistence providers choke on a model with a map in the previous post, let us now continue our experiments and see how our guinea pigs can handle JPQL queries for maps.&lt;br /&gt;&lt;br /&gt;Recall that the JPQL query language has three special operators for building map queries: &lt;span style="font-family: &amp;quot;Courier New&amp;quot;,Courier,monospace;"&gt;KEY()&lt;/span&gt;, &lt;span style="font-family: &amp;quot;Courier New&amp;quot;,Courier,monospace;"&gt;VALUE()&lt;/span&gt; and &lt;span style="font-family: &amp;quot;Courier New&amp;quot;,Courier,monospace;"&gt;ENTRY()&lt;/span&gt;.&lt;br /&gt;&lt;br /&gt;Now let us try and run the following query on a slightly modified model, compared to the previous post.&lt;br /&gt;&lt;br /&gt;&lt;pre&gt;select m.text from MultilingualString s join s.map m where KEY(m) = 'de'&lt;br /&gt;&lt;/pre&gt;&lt;br /&gt;The corresponding model is:&lt;br /&gt;&lt;br /&gt;&lt;pre&gt;@Embeddable&lt;br /&gt;public class LocalizedString {&lt;br /&gt;&lt;br /&gt;    private String language;&lt;br /&gt;&lt;br /&gt;    private String text;&lt;br /&gt;&lt;br /&gt;}&amp;nbsp;&lt;/pre&gt;&lt;pre&gt;&amp;nbsp;&lt;/pre&gt;&lt;pre&gt;@Entity&lt;br /&gt;@Table(schema = "jpa", name = "multilingual_string")&lt;br /&gt;public class MultilingualString {&lt;br /&gt;&lt;br /&gt;    @Id&lt;br /&gt;    @GeneratedValue(strategy = GenerationType.SEQUENCE)&lt;br /&gt;    @Column(name = "string_id")&lt;br /&gt;    private long id;&lt;br /&gt;&lt;br /&gt;    @ElementCollection(fetch=FetchType.EAGER)&lt;br /&gt;    @MapKeyColumn(name = "language_key")&lt;br /&gt;    @CollectionTable(schema = "jpa", name = "multilingual_string_map", &lt;br /&gt;                     joinColumns = @JoinColumn(name = "string_id"))&lt;br /&gt;    private Map&amp;lt;String, LocalizedString&amp;gt; map = new HashMap&amp;lt;String, LocalizedString&amp;gt;();&lt;br /&gt;}&lt;br /&gt;&lt;/pre&gt;&lt;br /&gt;This time I've changed the model so that the map key is stored in its own column, which gives Hibernate and Eclipselink at least a chance to digest the model and proceed to the query. OpenJPA is fine with either version of the model.&lt;br /&gt;&lt;br /&gt;DataNucleus is out of the game by now. I even tried replacing the &lt;span style="font-family: &amp;quot;Courier New&amp;quot;,Courier,monospace;"&gt;@Embeddable&lt;/span&gt; by an &lt;span style="font-family: &amp;quot;Courier New&amp;quot;,Courier,monospace;"&gt;@Entity&lt;/span&gt; and a few other things to cheat it into accepting my model, but in the end I gave up.&lt;br /&gt;&lt;br /&gt;Now, Ladies and Gentleman, the winner and sole survivor is: &lt;b&gt;OpenJPA again!&lt;/b&gt;&lt;br /&gt;&lt;br /&gt;Both Hibernate and Eclipselink fail, merrily throwing exceptions. Hibernate only seems to have stubbed out the &lt;span style="font-family: &amp;quot;Courier New&amp;quot;,Courier,monospace;"&gt;KEY()&lt;/span&gt; and &lt;span style="font-family: &amp;quot;Courier New&amp;quot;,Courier,monospace;"&gt;VALUE()&lt;/span&gt; operators in their parser code (see &lt;a href="http://opensource.atlassian.com/projects/hibernate/browse/HHH-5396"&gt;HHH-5396&lt;/a&gt; for the gory details and elaborate stack traces).&lt;br /&gt;&lt;br /&gt;And Eclipselink's famous last words are:&lt;br /&gt;&lt;br /&gt;&lt;pre&gt;Error compiling the query [select m.text from MultilingualString s join s.map m where KEY(m) = 'de'], &lt;br /&gt;line 1, column 9: unknown state or association field [text] of class [LocalizedString].&amp;nbsp;&lt;/pre&gt;&lt;pre&gt;&amp;nbsp;&lt;/pre&gt;&lt;br /&gt;Not sure what the poor soul is trying to tell me.&lt;br /&gt;&lt;br /&gt;To sum up: Should you ever consider working with persistent maps à la JPA 2.0, beware! Here be dragons...&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/7836204352369514180-6330123515006800909?l=hwellmann.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://hwellmann.blogspot.com/feeds/6330123515006800909/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=7836204352369514180&amp;postID=6330123515006800909' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/7836204352369514180/posts/default/6330123515006800909'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/7836204352369514180/posts/default/6330123515006800909'/><link rel='alternate' type='text/html' href='http://hwellmann.blogspot.com/2010/07/jpa-20-querying-map.html' title='JPA 2.0: Querying a Map'/><author><name>Harald Wellmann</name><uri>http://www.blogger.com/profile/08039976160321882828</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='16' height='16' src='http://img2.blogblog.com/img/b16-rounded.gif'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-7836204352369514180.post-1960854305330573912</id><published>2010-07-17T15:24:00.001+02:00</published><updated>2010-07-20T20:39:21.190+02:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='OpenJPA'/><category scheme='http://www.blogger.com/atom/ns#' term='DataNucleus'/><category scheme='http://www.blogger.com/atom/ns#' term='Eclipselink'/><category scheme='http://www.blogger.com/atom/ns#' term='Hibernate'/><category scheme='http://www.blogger.com/atom/ns#' term='JPA'/><title type='text'>JPA 2.0: Mapping a Map</title><content type='html'>JPA 2.0 has added support for persistent maps where keys and values may be any combination of basic types, embeddables or entities.&lt;br /&gt;&lt;br /&gt;Let's start with a use case:&lt;br /&gt;&lt;br /&gt;&lt;h3&gt;The Use Case&lt;/h3&gt;&lt;br /&gt;In an internationalized application, working with plain old &lt;span style="font-family: inherit;"&gt;&lt;span style="font-family: &amp;quot;Courier New&amp;quot;,Courier,monospace;"&gt;String&lt;/span&gt;s&lt;/span&gt; is not enough, sometimes you also need to know the language of a string, and given a string in English, you may need to find an equivalent string in German.&lt;br /&gt;&lt;br /&gt;So you come up with a &lt;span style="font-family: &amp;quot;Courier New&amp;quot;,Courier,monospace;"&gt;LocalizedString&lt;/span&gt;, which is nothing but a plain old &lt;span style="font-family: &amp;quot;Courier New&amp;quot;,Courier,monospace;"&gt;String&lt;/span&gt; together with a language code, and then you build a &lt;span style="font-family: &amp;quot;Courier New&amp;quot;,Courier,monospace;"&gt;MultilingualString&lt;/span&gt; as a map of language codes to &lt;span style="font-family: &amp;quot;Courier New&amp;quot;,Courier,monospace;"&gt;LocalizedString&lt;/span&gt;s. Since you want to reuse &lt;span style="font-family: &amp;quot;Courier New&amp;quot;,Courier,monospace;"&gt;LocalizedString&lt;/span&gt;s in other contexts, and you don't need to address them individually, you model them as an embeddable class, not as an entity.&lt;br /&gt;&lt;br /&gt;The special thing about this map is that the keys are part of the value. The map contents look like&lt;br /&gt;&lt;br /&gt;&lt;pre&gt;'de' -&amp;gt; ('de', 'Hallo')&lt;br /&gt;'en' -&amp;gt; ('en', 'Hello')&lt;br /&gt;&lt;/pre&gt;&lt;br /&gt;&lt;h3&gt;The Model&lt;/h3&gt;&lt;br /&gt;This is the resulting model:&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;&lt;i&gt;[&lt;b&gt;Update 20 July 2010:&lt;/b&gt; There is a slight misconception in my model as pointed out by Mike Keith in his first comment on this post. Editing the post in-place would turn the comments meaningless, so I think I'd better leave the original text unchanged and insert a few Editor's Notes. The @MapKey annotation below should be replaced by @MapKeyColumn(name = "language", insertable = false, updatable = false) to make the model JPA 2.0 compliant.] &lt;/i&gt;&lt;br /&gt;&lt;br /&gt;&lt;pre&gt;@Embeddable&lt;br /&gt;public class LocalizedString {&lt;br /&gt;&lt;br /&gt;    private String language;&lt;br /&gt;&lt;br /&gt;    private String text;&lt;br /&gt;&lt;br /&gt;    public LocalizedString() {}&lt;br /&gt;&lt;br /&gt;    public LocalizedString(String language, String text) {&lt;br /&gt;        this.language = language;&lt;br /&gt;        this.text = text;&lt;br /&gt;    }&lt;br /&gt;    &lt;br /&gt;    // autogenerated getters and setters, hashCode(), equals()&lt;br /&gt;}&amp;nbsp;&lt;/pre&gt;&lt;pre&gt;&amp;nbsp;&lt;/pre&gt;&lt;pre&gt;@Entity&lt;br /&gt;@Table(schema = "jpa", name = "multilingual_string")&lt;br /&gt;public class MultilingualString {&lt;br /&gt;&lt;br /&gt;    @Id&lt;br /&gt;    @GeneratedValue(strategy = GenerationType.SEQUENCE)&lt;br /&gt;    @Column(name = "string_id")&lt;br /&gt;    private long id;&lt;br /&gt;&lt;br /&gt;    @ElementCollection(fetch=FetchType.EAGER)&lt;br /&gt;    @MapKey(name = "language")&lt;br /&gt;    @CollectionTable(schema = "jpa", name = "multilingual_string_map", &lt;br /&gt;                     joinColumns = @JoinColumn(name = "string_id"))&lt;br /&gt;    private Map&amp;lt;String, LocalizedString&amp;gt; map = new HashMap&amp;lt;String, LocalizedString&amp;gt;();&lt;br /&gt;&lt;br /&gt;    public MultilingualString() {}&lt;br /&gt;    &lt;br /&gt;    public MultilingualString(String lang, String text) {&lt;br /&gt;        addText(lang, text);&lt;br /&gt;    }&lt;br /&gt;    &lt;br /&gt;    public void addText(String lang, String text) {&lt;br /&gt;        map.put(lang, new LocalizedString(lang, text));&lt;br /&gt;    }&lt;br /&gt;&lt;br /&gt;    public String getText(String lang) {&lt;br /&gt;        if (map.containsKey(lang)) {&lt;br /&gt;            return map.get(lang).getText();&lt;br /&gt;        }&lt;br /&gt;        return null;&lt;br /&gt;    }&lt;br /&gt;    &lt;br /&gt;    // autogenerated getters and setters, hashCode(), equals()&lt;br /&gt;}&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;&lt;/pre&gt;&lt;br /&gt;The SQL statements for creating the corresponding tables:&lt;br /&gt;&lt;br /&gt;&lt;pre&gt;CREATE TABLE jpa.multilingual_string&lt;br /&gt;(&lt;br /&gt;  string_id bigint NOT NULL,&lt;br /&gt;  CONSTRAINT multilingual_string_pkey PRIMARY KEY (string_id)&lt;br /&gt;)&lt;br /&gt;&lt;br /&gt;CREATE TABLE jpa.multilingual_string_map&lt;br /&gt;(&lt;br /&gt;  string_id bigint,&lt;br /&gt;  language character varying(255) NOT NULL,&lt;br /&gt;  text character varying(255)&lt;br /&gt;)&lt;br /&gt;&lt;/pre&gt;&lt;br /&gt;&lt;h3&gt;The Specification&lt;/h3&gt;&lt;br /&gt;The most important and most difficult annotation in this example is &lt;span style="font-family: &amp;quot;Courier New&amp;quot;,Courier,monospace;"&gt;@MapKey&lt;/span&gt;. According to JSR-317, section 2.1.7 Map Keys:&lt;br /&gt;&lt;br /&gt;&lt;blockquote&gt;If the map key type is a basic type, the &lt;span style="font-family: &amp;quot;Courier New&amp;quot;,Courier,monospace;"&gt;MapKeyColumn&lt;/span&gt; annotation can be used to specify the column mapping for the map key. [...]&lt;br /&gt;The &lt;span style="font-family: &amp;quot;Courier New&amp;quot;,Courier,monospace;"&gt;MapKey&lt;/span&gt; annotation is used to specify the special case where the map key is itself the primary key or a persistent field or property of the entity that is the value of the map.&lt;/blockquote&gt;&lt;br /&gt;Unfortunately, in our case it is not quite clear whether we should use &lt;span style="font-family: &amp;quot;Courier New&amp;quot;,Courier,monospace;"&gt;@MapKey&lt;/span&gt; or &lt;span style="font-family: &amp;quot;Courier New&amp;quot;,Courier,monospace;"&gt;@MapKeyColumn&lt;/span&gt; to define the table column for our map key. Our map key is a basic type and our map value is not an entity, so this seems to imply we should use &lt;span style="font-family: &amp;quot;Courier New&amp;quot;,Courier,monospace;"&gt;@MapKeyColumn&lt;/span&gt;.&lt;br /&gt;&lt;br /&gt;On the other hand, our key is a persistent field of the map value, and I think the whole point of the &lt;span style="font-family: &amp;quot;Courier New&amp;quot;,Courier,monospace;"&gt;@MapKey&lt;/span&gt; annotation is to indicate the fact that we simply reuse a property of the map value as the map key, so we do not need to provide an extra table column, as the given property is already mapped to a column.&lt;br /&gt;&lt;br /&gt;The way I see it, replacing &lt;span style="font-family: &amp;quot;Courier New&amp;quot;,Courier,monospace;"&gt;@MapKey&lt;/span&gt; by &lt;span style="font-family: &amp;quot;Courier New&amp;quot;,Courier,monospace;"&gt;@MapKeyColumn(name = "language_key")&lt;/span&gt; - note the&lt;span style="font-family: &amp;quot;Courier New&amp;quot;,Courier,monospace;"&gt; _key&lt;/span&gt; suffix! - is also legal, but then we get a different table model and different semantics: The table &lt;span style="font-family: &amp;quot;Courier New&amp;quot;,Courier,monospace;"&gt;jpa.multilingual_string_map&lt;/span&gt; would have a fourth column &lt;span style="font-family: &amp;quot;Courier New&amp;quot;,Courier,monospace;"&gt;language_key&lt;/span&gt;, this &lt;span style="font-family: &amp;quot;Courier New&amp;quot;,Courier,monospace;"&gt;language_key&lt;/span&gt; would not necessarily have to be equal to the language of the map value.&lt;br /&gt;&lt;br /&gt;Another open question: Is it legal to write &lt;span style="font-family: &amp;quot;Courier New&amp;quot;,Courier,monospace;"&gt;@MapKeyColumn(name = "language")&lt;/span&gt;? If so, this should indicate that the language column is to be used as the map key, so this would be equivalent to the &lt;span style="font-family: &amp;quot;Courier New&amp;quot;,Courier,monospace;"&gt;@MapKey&lt;/span&gt; annotation. On the other hand, you might say that this annotation indicates that the application is free to use map keys that are independent of the map values, so this contract would be violated if the column name indicated by the annotation is already mapped.&lt;br /&gt;&lt;br /&gt;&lt;h3&gt;The Persistence Providers&lt;/h3&gt;&lt;br /&gt;I've tried implementing this example with the current versions of Hibernate, Eclipselink, OpenJPA and DataNucleus.&lt;i&gt; &lt;/i&gt;&lt;b&gt;I did not succeed with any of them.&lt;/b&gt; Only OpenJPA provided a workable solution using &lt;span style="font-family: &amp;quot;Courier New&amp;quot;,Courier,monospace;"&gt;@MapKeyColumn&lt;/span&gt;, but as I said, I'm not sure if this usage is really intended by the specification.&lt;br /&gt;&lt;br /&gt;&lt;i&gt;[&lt;b&gt;Update 20 July 2010:&lt;/b&gt; With the corrected model, the updated verdict is: &lt;b&gt;Only OpenJPA passes the test&lt;/b&gt;, the other three bail out for various reasons.] &lt;/i&gt;&lt;br /&gt;&lt;br /&gt;Let's look at the contestants in turn:&lt;br /&gt;&lt;br /&gt;&lt;h4&gt;Hibernate&lt;/h4&gt;&lt;br /&gt;Using the mapping defined above, Hibernate 3.5.3-Final complains:&lt;br /&gt;&lt;br /&gt;&lt;pre&gt;org.hibernate.AnnotationException: Associated class not found: LocalizedString&lt;br /&gt;&lt;/pre&gt;&lt;br /&gt;Apparently Hibernate is expecting the map value to be an entity not an embeddable.&lt;br /&gt;&lt;br /&gt;Using &lt;span style="font-family: &amp;quot;Courier New&amp;quot;,Courier,monospace;"&gt;@MapKeyColumn(name = "language")&lt;/span&gt;, the exception is&lt;br /&gt;&lt;br /&gt;&lt;pre&gt;org.hibernate.MappingException: Repeated column in mapping for collection: MultilingualString.map column: language&lt;br /&gt;&lt;/pre&gt;&lt;br /&gt;Finally, with &lt;span style="font-family: &amp;quot;Courier New&amp;quot;,Courier,monospace;"&gt;@MapKeyColumn(name = "language_key")&lt;/span&gt;, Hibernate no longer complains about duplicate columns, but I end up with a redundant table column in my database which I was trying to avoid.&lt;br /&gt;&lt;br /&gt;Another problem with Hibernate is different behaviour when working with XML mapping data instead of annotations (which is what I prefer for various reasons, but that's a topic for another post).&lt;br /&gt;&lt;br /&gt;Using XML metadata for this example, Hibernate happily ignores the table names from the metadata and simply uses the default names. I filed a bug report in April 2010 (&lt;a href="http://opensource.atlassian.com/projects/hibernate/browse/HHH-5136"&gt;HHH-5136&lt;/a&gt;), with no reaction ever since. &lt;br /&gt;&lt;br /&gt;&lt;br /&gt;&lt;h4&gt;Eclipselink&lt;/h4&gt;&lt;br /&gt;Using Eclipselink 2.1.0, I simply get a rather cryptic exception&lt;br /&gt;&lt;br /&gt;&lt;pre&gt;java.lang.NullPointerException&lt;br /&gt; at org.eclipse.persistence.internal.queries.MapContainerPolicy.compareKeys(MapContainerPolicy.java:234)&lt;br /&gt;&lt;/pre&gt;&lt;br /&gt;With &lt;span style="font-family: &amp;quot;Courier New&amp;quot;,Courier,monospace;"&gt;@MapKeyColumn=(name = "language")&lt;/span&gt;, Eclipselink also complains about a duplicate column, and changing the name to &lt;span style="font-family: &amp;quot;Courier New&amp;quot;,Courier,monospace;"&gt;language_key&lt;/span&gt;, my test finally passes, at the expense of a redundant column, as with Hibernate.&lt;br /&gt;&lt;br /&gt;&lt;h4&gt;OpenJPA&lt;/h4&gt;&lt;br /&gt;With OpenJPA 2.0.0, the message is &lt;br /&gt;&lt;br /&gt;&lt;pre&gt;org.apache.openjpa.persistence.ArgumentException: Map field "MultilingualString.map" is attempting to use a map table, &lt;br /&gt;but its key is mapped by another field.  Use an inverse key or join table mapping.&lt;br /&gt;&lt;/pre&gt;&lt;br /&gt;which I can't make sense of. Switching to &lt;span style="font-family: &amp;quot;Courier New&amp;quot;,Courier,monospace;"&gt;@MapKeyColumn=(name = "language")&lt;/span&gt;, the new message is&lt;br /&gt;&lt;br /&gt;&lt;pre&gt;org.apache.openjpa.persistence.ArgumentException: &lt;br /&gt;"LocalizedString.text" declares a column that is not compatible with the expected type "varchar".  &lt;br /&gt;&lt;/pre&gt;&lt;br /&gt;Its seems OpenJPA is confused by the column name &lt;span style="font-family: &amp;quot;Courier New&amp;quot;,Courier,monospace;"&gt;text&lt;/span&gt; which sounds like a column data type. After adding &lt;span style="font-family: &amp;quot;Courier New&amp;quot;,Courier,monospace;"&gt;@Column(name = "_text")&lt;/span&gt; to &lt;span style="font-family: &amp;quot;Courier New&amp;quot;,Courier,monospace;"&gt;LocalizedString.text&lt;/span&gt;, my test case works and my database table only has three columns.&lt;br /&gt;&lt;h4&gt;DataNucleus&lt;/h4&gt;&lt;br /&gt;DataNucleus 2.1.1 complains&lt;br /&gt;&lt;br /&gt;&lt;pre&gt;javax.persistence.PersistenceException: Persistent class "LocalizedString" has no table in the database, &lt;br /&gt;but the operation requires it. Please check the specification of the MetaData for this class.&lt;br /&gt;&lt;/pre&gt;&lt;br /&gt;I'm getting the same message with all three variants of the annotation, so it appears that DataNucleus simply cannot handle embeddable map value and expects them to be entities.&lt;br /&gt;&lt;br /&gt;&lt;h3&gt;Conclusion&lt;/h3&gt;&lt;br /&gt;Mapping maps with JPA is much harder than you would think, both for the user and for the implementor. Hibernate, Eclipselink and OpenJPA have all passed the JPA TCK. DataNucleus would have liked to do so, but they have not yet been granted access to the TCK.&lt;br /&gt;&lt;br /&gt;All four implementors failed this simple map example to various degrees, which implies that there are features in the JPA 2.0 specification which are not sufficiently covered by the TCK.&lt;br /&gt;&lt;br /&gt;An Open Source TCK for JPA would help in detecting and eliminating such gaps instead of leaving that to the initiative of individuals.&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/7836204352369514180-1960854305330573912?l=hwellmann.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://hwellmann.blogspot.com/feeds/1960854305330573912/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=7836204352369514180&amp;postID=1960854305330573912' title='16 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/7836204352369514180/posts/default/1960854305330573912'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/7836204352369514180/posts/default/1960854305330573912'/><link rel='alternate' type='text/html' href='http://hwellmann.blogspot.com/2010/07/jpa-20-mapping-map.html' title='JPA 2.0: Mapping a Map'/><author><name>Harald Wellmann</name><uri>http://www.blogger.com/profile/08039976160321882828</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='16' height='16' src='http://img2.blogblog.com/img/b16-rounded.gif'/></author><thr:total>16</thr:total></entry><entry><id>tag:blogger.com,1999:blog-7836204352369514180.post-866193637080589787</id><published>2010-07-16T22:34:00.000+02:00</published><updated>2010-07-16T22:34:41.790+02:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='JPA'/><category scheme='http://www.blogger.com/atom/ns#' term='Java EE 6'/><title type='text'>JPA 2.0 Frustration</title><content type='html'>JPA 2.0 is one of the areas where Java EE 6 can make your life a lot easier compared to Java EE 5 - at least if your life is somehow connected to Java software development. &lt;br /&gt;&lt;br /&gt;So much for the marketing blurb. In practice, working with JPA 2.0 means&lt;br /&gt;&lt;ul&gt;&lt;li&gt;trying to understand a specification (&lt;a href="http://jcp.org/aboutJava/communityprocess/final/jsr317/index.html"&gt;JSR 317&lt;/a&gt;) which may be quite challenging to read for the average developer and occasionally somewhat too vague even for experts&lt;/li&gt;&lt;li&gt;making sense of obscure stack traces from the JPA provider of your choice&lt;/li&gt;&lt;li&gt;discovering numerous bugs and omissions in implementations claiming to be JPA 2.0 compliant.&lt;/li&gt;&lt;/ul&gt;If you think this sounds fun, then read on...&lt;br /&gt;&lt;br /&gt;Actually, this post is just an introductory note to a series of articles on specific use cases that seem to be particularly hard to get right.&lt;br /&gt;&lt;br /&gt;I'm not unhappy about the spec as such - Object Relational Mapping (ORM) is a challenging topic and not exactly the stuff you expect first year computer science students to understand. JPA 2.0 narrows the gap between the JPA standard and vendor-specific extensions or native ORM features.&lt;br /&gt;&lt;br /&gt;Still, there are some areas not covered by the standard where you have to fall back to vendor extensions or even write your own code: for instance, I would really like to see more flexible support for enum types, a standard for user-defined column types and an addition for spatial objects and queries, based on &lt;a href="http://www.opengeospatial.org/"&gt;OGC&lt;/a&gt; standards.&lt;br /&gt;&lt;br /&gt;The main source of frustration with JPA 2.0 is simply the lack of specification compliance of the available implementations. Implementing any but the most trivial persistence mappings and queries at application level can require hours of trial and error to get the expected results. Yes, most of the time the problem may be in your application code. But with JPA 2.0, chances are really high that your persistence provider has a bug.&lt;br /&gt;&lt;br /&gt;The situation is not helped by the policy of Sun/Oracle/the JCP (I'm not really sure who's in charge of that) to keep the JPA TCK (Technology Compliance Kit) under a non-disclosure agreement - see &lt;a href="http://datanucleus.blogspot.com/2010/04/jpa-and-role-of-compliance.html"&gt;this blog post&lt;/a&gt; from DataNucleus, which was linked in a related thread in the Glassfish forums recently. (&lt;a href="http://www.datanucleus.org/"&gt;DataNucleus&lt;/a&gt; is a JPA implementor not beloging to the inner circle of the JCP.)&lt;br /&gt;&lt;br /&gt;So far, I've looked at&lt;br /&gt;&lt;ul&gt;&lt;li&gt;Hibernate&lt;/li&gt;&lt;li&gt;Eclipselink&lt;/li&gt;&lt;li&gt;OpenJPA&lt;/li&gt;&lt;li&gt;DataNucleus,&lt;/li&gt;&lt;/ul&gt;and sadly, I've had problems with all of them. I'm going to provide specific examples in the following posts.&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/7836204352369514180-866193637080589787?l=hwellmann.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://hwellmann.blogspot.com/feeds/866193637080589787/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=7836204352369514180&amp;postID=866193637080589787' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/7836204352369514180/posts/default/866193637080589787'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/7836204352369514180/posts/default/866193637080589787'/><link rel='alternate' type='text/html' href='http://hwellmann.blogspot.com/2010/07/jpa-20-frustration.html' title='JPA 2.0 Frustration'/><author><name>Harald Wellmann</name><uri>http://www.blogger.com/profile/08039976160321882828</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='16' height='16' src='http://img2.blogblog.com/img/b16-rounded.gif'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-7836204352369514180.post-973974490225299805</id><published>2010-06-26T22:55:00.000+02:00</published><updated>2010-06-26T22:55:49.559+02:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='Java'/><title type='text'>Early Adopter</title><content type='html'>My mum keeps telling me I used to be gifted child. Of course I don't remember everything I did at the age of three, but I seem to have signed up for the &lt;a href="http://forums.java.net/"&gt;java.net forums&lt;/a&gt; at that time. Quite impressive!&lt;br /&gt;&lt;br /&gt;&lt;div class="separator" style="clear: both; text-align: center;"&gt;&lt;a href="http://1.bp.blogspot.com/_BJAmlQZb_Bs/TCZo2lKuVcI/AAAAAAAAABs/aurKER6PUeE/s1600/gf1969red.png" imageanchor="1" style="margin-left: 1em; margin-right: 1em;"&gt;&lt;img border="0" height="338" src="http://1.bp.blogspot.com/_BJAmlQZb_Bs/TCZo2lKuVcI/AAAAAAAAABs/aurKER6PUeE/s400/gf1969red.png" width="400" /&gt;&lt;/a&gt;&lt;/div&gt;&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/7836204352369514180-973974490225299805?l=hwellmann.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://hwellmann.blogspot.com/feeds/973974490225299805/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=7836204352369514180&amp;postID=973974490225299805' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/7836204352369514180/posts/default/973974490225299805'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/7836204352369514180/posts/default/973974490225299805'/><link rel='alternate' type='text/html' href='http://hwellmann.blogspot.com/2010/06/early-adopter.html' title='Early Adopter'/><author><name>Harald Wellmann</name><uri>http://www.blogger.com/profile/08039976160321882828</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='16' height='16' src='http://img2.blogblog.com/img/b16-rounded.gif'/></author><media:thumbnail xmlns:media='http://search.yahoo.com/mrss/' url='http://1.bp.blogspot.com/_BJAmlQZb_Bs/TCZo2lKuVcI/AAAAAAAAABs/aurKER6PUeE/s72-c/gf1969red.png' height='72' width='72'/><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-7836204352369514180.post-7620005092659552328</id><published>2010-05-14T19:44:00.000+02:00</published><updated>2010-05-14T19:44:14.014+02:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='Java'/><category scheme='http://www.blogger.com/atom/ns#' term='JAXB'/><category scheme='http://www.blogger.com/atom/ns#' term='XML'/><category scheme='http://www.blogger.com/atom/ns#' term='xjc'/><title type='text'>Java XML Binding with Property Change Support</title><content type='html'>In an earlier post, I was talking about generating Java classes with xjc with property change support which is not enabled by default. This post explains the details, an in fact the Maven build explained below is a lot a easier than my original approch with Ant which required some downloads to set things up.&lt;br /&gt;&lt;br /&gt;The general idea is same as &lt;a href="http://weblogs.java.net/blog/2007/01/30/using-maven-jaxb2-plugin-compile-dtd"&gt;described by Kohsuke Kawaguchi&lt;/a&gt; in a post of 2007, but his POM is broken with the current stage of the Maven repositories. In addition, there is a tweak with the &lt;span style="font-family: &amp;quot;Courier New&amp;quot;,Courier,monospace;"&gt;PropertyListener&lt;/span&gt; customization.&lt;br /&gt;&lt;br /&gt;So here is a little example schema:&lt;br /&gt;&lt;br /&gt;&lt;pre&gt;&amp;lt;?xml version="1.0" encoding="UTF-8"?&amp;gt;&lt;br /&gt;&amp;lt;schema xmlns="http://www.w3.org/2001/XMLSchema" xmlns:tns="http://www.example.org/person/" targetNamespace="http://www.example.org/person/"&amp;gt;&lt;br /&gt;    &amp;lt;complexType name="Person"&amp;gt;&lt;br /&gt;      &amp;lt;sequence&amp;gt;&lt;br /&gt;        &amp;lt;element name="firstName" type="string"&amp;gt;&amp;lt;/element&amp;gt;&lt;br /&gt;        &amp;lt;element name="lastName" type="string"&amp;gt;&amp;lt;/element&amp;gt;&lt;br /&gt;        &amp;lt;element name="address" type="tns:Address"&amp;gt;&amp;lt;/element&amp;gt;&lt;br /&gt;      &amp;lt;/sequence&amp;gt;&lt;br /&gt;    &amp;lt;/complexType&amp;gt;&lt;br /&gt;&lt;br /&gt;    &amp;lt;complexType name="Address"&amp;gt;&lt;br /&gt;      &amp;lt;sequence&amp;gt;&lt;br /&gt;        &amp;lt;element name="street" type="string"&amp;gt;&amp;lt;/element&amp;gt;&lt;br /&gt;        &amp;lt;element name="houseNumber" type="string"&amp;gt;&amp;lt;/element&amp;gt;&lt;br /&gt;        &amp;lt;element name="city" type="string"&amp;gt;&amp;lt;/element&amp;gt;&lt;br /&gt;        &amp;lt;element name="postalCode" type="string"&amp;gt;&amp;lt;/element&amp;gt;&lt;br /&gt;        &amp;lt;element name="country" type="string"&amp;gt;&amp;lt;/element&amp;gt;&lt;br /&gt;      &amp;lt;/sequence&amp;gt;&lt;br /&gt;    &amp;lt;/complexType&amp;gt;&lt;br /&gt;&amp;lt;/schema&amp;gt;&lt;br /&gt;&lt;/pre&gt;&lt;br /&gt;We use the following file &lt;span style="font-family: &amp;quot;Courier New&amp;quot;,Courier,monospace;"&gt;bindings.xjb&lt;/span&gt; to customize the Java classes generated by xjc. We make all classes serializable and include support for &lt;span style="font-family: &amp;quot;Courier New&amp;quot;,Courier,monospace;"&gt;PropertyChangeListeners&lt;/span&gt;.&lt;br /&gt;&lt;br /&gt;&lt;pre&gt;&amp;lt;?xml version="1.0" encoding ="UTF-8"?&amp;gt;&lt;br /&gt;&amp;lt;jaxb:bindings&lt;br /&gt;    schemaLocation="person.xsd"&lt;br /&gt;    version="2.1"&lt;br /&gt;    xmlns:li="http://jaxb.dev.java.net/plugin/listener-injector"&lt;br /&gt;    xmlns:jaxb="http://java.sun.com/xml/ns/jaxb"&lt;br /&gt;    xmlns:xs="http://www.w3.org/2001/XMLSchema"&amp;gt;&lt;br /&gt;&lt;br /&gt;  &amp;lt;jaxb:bindings node="/xs:schema"&amp;gt;&lt;br /&gt;    &amp;lt;jaxb:globalBindings&amp;gt;&lt;br /&gt;      &amp;lt;jaxb:serializable uid="1" /&amp;gt;&lt;br /&gt;    &amp;lt;/jaxb:globalBindings&amp;gt;&lt;br /&gt;    &amp;lt;li:listener&amp;gt;java.beans.PropertyChangeListener&amp;lt;/li:listener&amp;gt;    &lt;br /&gt;  &amp;lt;/jaxb:bindings&amp;gt;&lt;br /&gt;&amp;lt;/jaxb:bindings&amp;gt;&lt;br /&gt;&lt;br /&gt;&lt;/pre&gt;&lt;br /&gt;The following POM takes care of the code generation:&lt;br /&gt;&lt;br /&gt;&lt;pre&gt;&amp;lt;project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"&lt;br /&gt;  xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/maven-v4_0_0.xsd"&amp;gt;&lt;br /&gt;  &amp;lt;modelVersion&amp;gt;4.0.0&amp;lt;/modelVersion&amp;gt;&lt;br /&gt;  &amp;lt;groupId&amp;gt;jaxb-properties&amp;lt;/groupId&amp;gt;&lt;br /&gt;  &amp;lt;artifactId&amp;gt;jaxb-properties&amp;lt;/artifactId&amp;gt;&lt;br /&gt;  &amp;lt;version&amp;gt;0.0.1-SNAPSHOT&amp;lt;/version&amp;gt;&lt;br /&gt;  &amp;lt;name&amp;gt;JAXB PropertyListener Demo&amp;lt;/name&amp;gt;&lt;br /&gt;&lt;br /&gt;  &amp;lt;build&amp;gt;&lt;br /&gt;    &amp;lt;plugins&amp;gt;&lt;br /&gt;      &amp;lt;plugin&amp;gt;&lt;br /&gt;        &amp;lt;groupId&amp;gt;org.apache.maven.plugins&amp;lt;/groupId&amp;gt;&lt;br /&gt;        &amp;lt;artifactId&amp;gt;maven-compiler-plugin&amp;lt;/artifactId&amp;gt;&lt;br /&gt;        &amp;lt;version&amp;gt;2.3&amp;lt;/version&amp;gt;&lt;br /&gt;        &amp;lt;configuration&amp;gt;&lt;br /&gt;          &amp;lt;source&amp;gt;1.6&amp;lt;/source&amp;gt;&lt;br /&gt;          &amp;lt;target&amp;gt;1.6&amp;lt;/target&amp;gt;&lt;br /&gt;        &amp;lt;/configuration&amp;gt;&lt;br /&gt;      &amp;lt;/plugin&amp;gt;&lt;br /&gt;      &amp;lt;plugin&amp;gt;&lt;br /&gt;        &amp;lt;groupId&amp;gt;org.jvnet.jaxb2.maven2&amp;lt;/groupId&amp;gt;&lt;br /&gt;        &amp;lt;artifactId&amp;gt;maven-jaxb2-plugin&amp;lt;/artifactId&amp;gt;&lt;br /&gt;        &amp;lt;version&amp;gt;0.7.3&amp;lt;/version&amp;gt;&lt;br /&gt;        &amp;lt;executions&amp;gt;&lt;br /&gt;          &amp;lt;execution&amp;gt;&lt;br /&gt;            &amp;lt;goals&amp;gt;&lt;br /&gt;              &amp;lt;goal&amp;gt;generate&amp;lt;/goal&amp;gt;&lt;br /&gt;            &amp;lt;/goals&amp;gt;&lt;br /&gt;          &amp;lt;/execution&amp;gt;&lt;br /&gt;        &amp;lt;/executions&amp;gt;&lt;br /&gt;        &amp;lt;configuration&amp;gt;&lt;br /&gt;          &amp;lt;extension&amp;gt;true&amp;lt;/extension&amp;gt;&lt;br /&gt;          &amp;lt;generatePackage&amp;gt;com.example.jaxb&amp;lt;/generatePackage&amp;gt;&lt;br /&gt;          &amp;lt;schemaIncludes&amp;gt;&lt;br /&gt;            &amp;lt;schemaInclude&amp;gt;person.xsd&amp;lt;/schemaInclude&amp;gt;&lt;br /&gt;          &amp;lt;/schemaIncludes&amp;gt;&lt;br /&gt;          &amp;lt;bindingIncludes&amp;gt;&lt;br /&gt;            &amp;lt;bindingInclude&amp;gt;bindings.xjb&amp;lt;/bindingInclude&amp;gt;&lt;br /&gt;          &amp;lt;/bindingIncludes&amp;gt;&lt;br /&gt;          &amp;lt;args&amp;gt;&lt;br /&gt;            &amp;lt;arg&amp;gt;-Xinject-listener-code&amp;lt;/arg&amp;gt;&lt;br /&gt;          &amp;lt;/args&amp;gt;&lt;br /&gt;        &amp;lt;/configuration&amp;gt;&lt;br /&gt;        &amp;lt;dependencies&amp;gt;&lt;br /&gt;          &amp;lt;dependency&amp;gt;&lt;br /&gt;            &amp;lt;groupId&amp;gt;com.sun.xml.bind&amp;lt;/groupId&amp;gt;&lt;br /&gt;            &amp;lt;artifactId&amp;gt;jaxb-xjc&amp;lt;/artifactId&amp;gt;&lt;br /&gt;            &amp;lt;version&amp;gt;2.1.13&amp;lt;/version&amp;gt;&lt;br /&gt;          &amp;lt;/dependency&amp;gt;&lt;br /&gt;          &amp;lt;dependency&amp;gt;&lt;br /&gt;            &amp;lt;groupId&amp;gt;org.jvnet.jaxb2-commons&amp;lt;/groupId&amp;gt;&lt;br /&gt;            &amp;lt;artifactId&amp;gt;property-listener-injector&amp;lt;/artifactId&amp;gt;&lt;br /&gt;            &amp;lt;version&amp;gt;1.1-SNAPSHOT&amp;lt;/version&amp;gt;&lt;br /&gt;            &amp;lt;exclusions&amp;gt;&lt;br /&gt;              &amp;lt;exclusion&amp;gt;&lt;br /&gt;                &amp;lt;groupId&amp;gt;com.sun.xml.bind&amp;lt;/groupId&amp;gt;&lt;br /&gt;                &amp;lt;artifactId&amp;gt;jaxb-xjc&amp;lt;/artifactId&amp;gt;&lt;br /&gt;              &amp;lt;/exclusion&amp;gt;&lt;br /&gt;            &amp;lt;/exclusions&amp;gt;&lt;br /&gt;          &amp;lt;/dependency&amp;gt;&lt;br /&gt;        &amp;lt;/dependencies&amp;gt;&lt;br /&gt;      &amp;lt;/plugin&amp;gt;&lt;br /&gt;&lt;br /&gt;    &amp;lt;/plugins&amp;gt;&lt;br /&gt;  &amp;lt;/build&amp;gt;&lt;br /&gt;&amp;lt;/project&amp;gt;&lt;br /&gt;&lt;br /&gt;&lt;/pre&gt;&lt;br /&gt;You do need to use the 1.1-SNAPSHOT version of the &lt;span style="font-family: &amp;quot;Courier New&amp;quot;,Courier,monospace;"&gt;property-listener-injector&lt;/span&gt;, as the 1.0 release only supports &lt;span style="font-family: &amp;quot;Courier New&amp;quot;,Courier,monospace;"&gt;VetoableChangeListeners&lt;/span&gt; and not the &lt;span style="font-family: &amp;quot;Courier New&amp;quot;,Courier,monospace;"&gt;PropertyChangeListeners&lt;/span&gt; we want to use. The &lt;span style="font-family: &amp;quot;Courier New&amp;quot;,Courier,monospace;"&gt;&amp;lt;li:listener&amp;gt;&lt;/span&gt; element in the bindings file is used to define the listener class.&lt;br /&gt;&lt;br /&gt;It is important to exclude the &lt;span style="font-family: &amp;quot;Courier New&amp;quot;,Courier,monospace;"&gt;jaxb-xjc&lt;/span&gt; dependency from the &lt;span style="font-family: &amp;quot;Courier New&amp;quot;,Courier,monospace;"&gt;property-listener-injector&lt;/span&gt;, or else it will try to download an non-existing snapshot version. Looks like something is broken in the java.net repository, but then again, working with snapshot releases is always dangerous....&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/7836204352369514180-7620005092659552328?l=hwellmann.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://hwellmann.blogspot.com/feeds/7620005092659552328/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=7836204352369514180&amp;postID=7620005092659552328' title='3 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/7836204352369514180/posts/default/7620005092659552328'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/7836204352369514180/posts/default/7620005092659552328'/><link rel='alternate' type='text/html' href='http://hwellmann.blogspot.com/2010/05/java-xml-binding-with-property-change.html' title='Java XML Binding with Property Change Support'/><author><name>Harald Wellmann</name><uri>http://www.blogger.com/profile/08039976160321882828</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='16' height='16' src='http://img2.blogblog.com/img/b16-rounded.gif'/></author><thr:total>3</thr:total></entry><entry><id>tag:blogger.com,1999:blog-7836204352369514180.post-3913303520383317287</id><published>2010-05-13T18:38:00.002+02:00</published><updated>2010-12-18T20:53:16.645+01:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='slf4j'/><category scheme='http://www.blogger.com/atom/ns#' term='Logging'/><category scheme='http://www.blogger.com/atom/ns#' term='Glassfish'/><title type='text'>Glassfish Logging with slf4j</title><content type='html'>&lt;i&gt;&lt;b&gt;Update 18 Dec 2010:&lt;/b&gt; There is an &lt;a href="http://hwellmann.blogspot.com/2010/12/glassfish-logging-with-slf4j-part-2.html"&gt;extended version&lt;/a&gt; of this article.&lt;/i&gt; &lt;br /&gt;&lt;br /&gt;It can be annoying to have each third-party library or framework in your application logging to a different logfile. &lt;a href="http://www.slf4j.org/"&gt;slf4j&lt;/a&gt; with its various adapters enables you to collect logging events from various APIs (org.slf4j.api, java.util.logging, org.apache.commons.logging) and redirect them to a logging backend of your choice.&lt;br /&gt;&lt;br /&gt;I've always preferred log4j or, more recently, logback over java.util.logging, so after working with Glassfish v3 for a while, I tried to tweak it to use logback over slf4j and the jul-to-slf4j bridge.&lt;br /&gt;&lt;br /&gt;To redirect java.util.logging used by Glassfish v3, you put the following libs on your classpath:&lt;br /&gt;&lt;ul&gt;&lt;li&gt;jul-to-slf4j.jar&lt;/li&gt;&lt;li&gt;slf4j-api.jar&lt;/li&gt;&lt;li&gt;logback-classic.jar&lt;/li&gt;&lt;li&gt;logback-core.jar&lt;/li&gt;&lt;/ul&gt;(You can replace the logback libs by any other supported backend like log4j, see the slf4j docs for more details.)&lt;br /&gt;The problem with Glassfish is:&lt;br /&gt;&lt;ul&gt;&lt;li&gt;You need to take care of its class loader hierarchy and make sure that the logging jars get picked up early enough.&lt;/li&gt;&lt;li&gt;Glassfish does some &lt;a href="http://simplericity.com/2009/01/02/1230894176938.html"&gt;all-too-clever logger manipulation&lt;/a&gt; in its &lt;a href="http://fisheye5.cenqua.com/browse/glassfish/appserv-core/src/java/com/sun/enterprise/v3/services/impl/LogManagerService.java#r1.2"&gt;LogManagerService&lt;/a&gt; which will get in your way if you don't like the Glassfish defaults: It redirects all System.out messages to a logger.&lt;/li&gt;&lt;/ul&gt;I did not manage to fully supersede Glassfish logging by slf4j and logback, but at least I can copy all Glassfish log events to my logback application log like this:&lt;br /&gt;&lt;ul&gt;&lt;li&gt;Put the logging libs in [install-root]/lib/endorsed.&lt;/li&gt;&lt;li&gt;Build a JAR containing your logback.xml configuration and put it in the same place.&lt;/li&gt;&lt;li&gt;Edit an entry in [instance-root]/config/logging.properties, setting&lt;br /&gt;handlers = org.slf4j.bridge.SLF4JBridgeHandler&lt;/li&gt;&lt;/ul&gt;Now if you omit a ConsoleAppender from your logging configuration, the Glassfish server.log will no longer contain any log output from your application. It will still contain the log messages from Glassfish itself, but they will also be included in your own logback logfile.&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/7836204352369514180-3913303520383317287?l=hwellmann.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://hwellmann.blogspot.com/feeds/3913303520383317287/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=7836204352369514180&amp;postID=3913303520383317287' title='8 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/7836204352369514180/posts/default/3913303520383317287'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/7836204352369514180/posts/default/3913303520383317287'/><link rel='alternate' type='text/html' href='http://hwellmann.blogspot.com/2010/05/glassfish-logging-with-slf4j.html' title='Glassfish Logging with slf4j'/><author><name>Harald Wellmann</name><uri>http://www.blogger.com/profile/08039976160321882828</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='16' height='16' src='http://img2.blogblog.com/img/b16-rounded.gif'/></author><thr:total>8</thr:total></entry><entry><id>tag:blogger.com,1999:blog-7836204352369514180.post-8857903923356805164</id><published>2010-05-09T22:05:00.002+02:00</published><updated>2010-11-28T19:06:53.369+01:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='jeeunit'/><category scheme='http://www.blogger.com/atom/ns#' term='Maven'/><category scheme='http://www.blogger.com/atom/ns#' term='Glassfish'/><category scheme='http://www.blogger.com/atom/ns#' term='JUnit'/><category scheme='http://www.blogger.com/atom/ns#' term='Java EE 6'/><title type='text'>jeeunit: In-Container Integration Testing for Java EE 6</title><content type='html'>Recently, I've started working with Java EE 6 in general and Glassfish v3 in particular. Some software engineering best practices do not really depend on the framework or even the language you work with, so I was looking for a convenient way of doing automatic integration tests.&lt;br /&gt;&lt;br /&gt;I've been in the habit of using &lt;a href="http://www.junit.org/"&gt;JUnit&lt;/a&gt; not just for unit tests, but also for integration or system tests, so this was a natural starting point.&lt;br /&gt;&lt;br /&gt;Traditionally, Java EE containers were heavy-weight machinery so that people preferred writing their tests to run out-of-container, paying the price of emulating or mocking some of the container functionality.&lt;br /&gt;&lt;br /&gt;Maybe I've been looking in the wrong places, but most of the out-of-container testing approaches like ejb3unit seem to carry more baggage than the container itself, at least when it comes to working with Glassfish v3.&lt;br /&gt;&lt;br /&gt;Anyway, as I could not find a ready-to-go solution, I wrote a little JUnit extension called jeeunit together with an example project showing how to set things up with Glassfish v3 and Maven.&lt;br /&gt;&lt;br /&gt;The &lt;a href="http://code.google.com/p/jeeunit/"&gt;jeeunit&lt;/a&gt; project is available from Google Code under an Apache License.&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/7836204352369514180-8857903923356805164?l=hwellmann.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://hwellmann.blogspot.com/feeds/8857903923356805164/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=7836204352369514180&amp;postID=8857903923356805164' title='6 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/7836204352369514180/posts/default/8857903923356805164'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/7836204352369514180/posts/default/8857903923356805164'/><link rel='alternate' type='text/html' href='http://hwellmann.blogspot.com/2010/05/jeeunit-in-container-integration.html' title='jeeunit: In-Container Integration Testing for Java EE 6'/><author><name>Harald Wellmann</name><uri>http://www.blogger.com/profile/08039976160321882828</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='16' height='16' src='http://img2.blogblog.com/img/b16-rounded.gif'/></author><thr:total>6</thr:total></entry><entry><id>tag:blogger.com,1999:blog-7836204352369514180.post-4724711541016708747</id><published>2010-03-03T19:30:00.000+01:00</published><updated>2010-03-03T19:30:19.271+01:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='Metrics'/><title type='text'>The Ultimate Software Metric</title><content type='html'>&lt;div class="separator" style="clear: both; text-align: center;"&gt;&lt;a href="http://www.osnews.com/images/comics/wtfm.jpg" imageanchor="1" style="margin-left: 1em; margin-right: 1em;"&gt;&lt;img border="0" height="301" src="http://www.osnews.com/images/comics/wtfm.jpg" width="320" /&gt;&lt;/a&gt;&lt;/div&gt;&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/7836204352369514180-4724711541016708747?l=hwellmann.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://hwellmann.blogspot.com/feeds/4724711541016708747/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=7836204352369514180&amp;postID=4724711541016708747' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/7836204352369514180/posts/default/4724711541016708747'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/7836204352369514180/posts/default/4724711541016708747'/><link rel='alternate' type='text/html' href='http://hwellmann.blogspot.com/2010/03/ultimate-software-metric.html' title='The Ultimate Software Metric'/><author><name>Harald Wellmann</name><uri>http://www.blogger.com/profile/08039976160321882828</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='16' height='16' src='http://img2.blogblog.com/img/b16-rounded.gif'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-7836204352369514180.post-832602017666320057</id><published>2010-02-28T20:19:00.001+01:00</published><updated>2010-02-28T20:22:43.498+01:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='Java'/><category scheme='http://www.blogger.com/atom/ns#' term='I18n'/><title type='text'>Misconceptions about Java Internationalization</title><content type='html'>Let me start with a joke:&lt;br /&gt;&lt;blockquote&gt;What do you call someone who speaks three languages?&lt;br /&gt;Trilingual.&lt;br /&gt;What do you call someone who speaks two languages?&lt;br /&gt;Bilingual.&lt;br /&gt;What do you call someone who speaks one language?&lt;br /&gt;American.&lt;/blockquote&gt;To be fair on Americans, even most of us multilingual Europeans tend to be biased when it comes to internationalization, tacitly assuming that text is written left-to-right and can be sorted from A to Z. &lt;br /&gt;&lt;br /&gt;Most Java developers are familiar with resource bundles backed by properties files. The basics can be found in the &lt;a href="http://java.sun.com/docs/books/tutorial/i18n"&gt;Internationalization Trail&lt;/a&gt; of the Java Tutorial. Multilingual Java applications often come with a set of properties files, e.g.&lt;br /&gt;&lt;ul&gt;&lt;li&gt;MyApp_de_AT.properties&lt;/li&gt;&lt;li&gt;MyApp_de.properties&lt;/li&gt;&lt;li&gt;MyApp_es.properties&lt;/li&gt;&lt;li&gt;MyApp.properties&lt;/li&gt;&lt;/ul&gt;where &lt;span style="font-family: &amp;quot;Courier New&amp;quot;,Courier,monospace;"&gt;MyApp.properties&lt;/span&gt; contains the "default" message resources in English, &lt;span style="font-family: &amp;quot;Courier New&amp;quot;,Courier,monospace;"&gt;MyApp_de.properties&lt;/span&gt; and &lt;span style="font-family: &amp;quot;Courier New&amp;quot;,Courier,monospace;"&gt;MyApp_es.properties&lt;/span&gt; contain the German and Spanish resources, respectively, and &lt;span style="font-family: &amp;quot;Courier New&amp;quot;,Courier,monospace;"&gt;MyApp_de_AT.properties&lt;/span&gt; contains some country specific variants for the Austrian flavour of German. Usually, files for country specific variants are sparsely populated, containing only those properties that actually differ from the mainstream language version, like &lt;i&gt;Jänner&lt;/i&gt; (de_AT) vs.&lt;i&gt; Januar&lt;/i&gt; (de) vs. &lt;i&gt;January&lt;/i&gt; (en). &lt;br /&gt;&lt;br /&gt;However, you may be surprised in this case to end up with a German string even when you requested a resource for an English locale.&lt;br /&gt;&lt;br /&gt;&lt;i&gt;Assume nothing&lt;/i&gt; is a sound principle for robust software development, and you should not assume that English is the default or fallback language. In fact, the fallback for resources from an unsupported locale is the system default locale, which is based on the host environment. &lt;br /&gt;&lt;br /&gt;See the documentation for &lt;a href="http://java.sun.com/javase/6/docs/api/java/util/ResourceBundle.html#getBundle%28java.lang.String,%20java.util.Locale,%20java.lang.ClassLoader%29"&gt;&lt;span style="font-family: &amp;quot;Courier New&amp;quot;,Courier,monospace;"&gt;ResourceBundle.getBundle()&lt;/span&gt;&lt;/a&gt; and &lt;a href="http://java.sun.com/javase/6/docs/api/java/util/Locale.html#getDefault%28%29" style="font-family: &amp;quot;Courier New&amp;quot;,Courier,monospace;"&gt;Locale.getDefault()&lt;/a&gt; for more details.&lt;br /&gt;&lt;br /&gt;So when the default locale of your system is &lt;span style="font-family: &amp;quot;Courier New&amp;quot;,Courier,monospace;"&gt;de_DE&lt;/span&gt; and you request a resource for locale &lt;span style="font-family: &amp;quot;Courier New&amp;quot;,Courier,monospace;"&gt;en_US&lt;/span&gt;, the lookup order for the properties files is&lt;br /&gt;&lt;ol&gt;&lt;li&gt;MyApp_en_US.properties&lt;/li&gt;&lt;li&gt;MyApp_en.properties&lt;/li&gt;&lt;li&gt;MyApp_de_DE.properties&lt;/li&gt;&lt;li&gt;MyApp_de.properties&lt;/li&gt;&lt;li&gt;MyApp.properties&lt;/li&gt;&lt;/ol&gt;Hence, &lt;span style="font-family: &amp;quot;Courier New&amp;quot;,Courier,monospace;"&gt;ResourceBundle.getString()&lt;/span&gt; will return a German string from &lt;span style="font-family: &amp;quot;Courier New&amp;quot;,Courier,monospace;"&gt;MyApp_de.properties&lt;/span&gt;, since the first three files do not exist and the English resources are preceded by the German ones in this sequence.&lt;br /&gt;&lt;br /&gt;There are two solutions:&lt;br /&gt;&lt;ol&gt;&lt;li&gt;As a user, set your default locale to &lt;span style="font-family: &amp;quot;Courier New&amp;quot;,Courier,monospace;"&gt;en&lt;/span&gt; when launching the application.&lt;/li&gt;&lt;li&gt;As a developer, make sure to provide a properties file for locale &lt;span style="font-family: &amp;quot;Courier New&amp;quot;,Courier,monospace;"&gt;en&lt;/span&gt; (which may be empty).&lt;/li&gt;&lt;/ol&gt;The method for changing the default locale depends on your Java VM and your operating system. Setting the system property &lt;span style="font-family: &amp;quot;Courier New&amp;quot;,Courier,monospace;"&gt;user.language&lt;/span&gt; may work on some platforms, but not with the Sun JDK 1.6.0 under Linux. Instead, you need to set the environment variable &lt;span style="font-family: &amp;quot;Courier New&amp;quot;,Courier,monospace;"&gt;LANG&lt;/span&gt; before launching the Java VM.&lt;br /&gt;&lt;br /&gt;The preferred solution is the second one, of course. Even when &lt;span style="font-family: &amp;quot;Courier New&amp;quot;,Courier,monospace;"&gt;MyApp_en.properties&lt;/span&gt; is empty, it will be picked up as entry point for resource lookup. If a given key cannot be found in this file, the parent file &lt;span style="font-family: &amp;quot;Courier New&amp;quot;,Courier,monospace;"&gt;MyApp.properties&lt;/span&gt; will be used as fallback, which is just the desired behaviour.&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/7836204352369514180-832602017666320057?l=hwellmann.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://hwellmann.blogspot.com/feeds/832602017666320057/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=7836204352369514180&amp;postID=832602017666320057' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/7836204352369514180/posts/default/832602017666320057'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/7836204352369514180/posts/default/832602017666320057'/><link rel='alternate' type='text/html' href='http://hwellmann.blogspot.com/2010/02/misconceptions-about-java.html' title='Misconceptions about Java Internationalization'/><author><name>Harald Wellmann</name><uri>http://www.blogger.com/profile/08039976160321882828</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='16' height='16' src='http://img2.blogblog.com/img/b16-rounded.gif'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-7836204352369514180.post-9189400133267041067</id><published>2010-02-24T22:18:00.003+01:00</published><updated>2010-02-26T12:13:24.028+01:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='Localization'/><category scheme='http://www.blogger.com/atom/ns#' term='Eclipse'/><category scheme='http://www.blogger.com/atom/ns#' term='Babel'/><category scheme='http://www.blogger.com/atom/ns#' term='Roller'/><title type='text'>Editing Resource Bundles in Eclipse</title><content type='html'>Playing around with the &lt;a href="http://roller.apache.org/"&gt;Apache Roller&lt;/a&gt; blog engine, I noticed that some of the localized German text messages were missing or broken. Roller uses plain old Java resource bundles instead of the NLS mechanisms offered by Eclipse. Editing resource bundles for multiple languages in parallel is rather a pain with a plain text editor, so I was looking for an Eclipse plugin to do this job.&lt;br /&gt;&lt;br /&gt;(Just to avoid any confusion, even though I've been writing a lot about OSGi bundles, the term &lt;i&gt;bundle &lt;/i&gt;is only used in the sense of a resource bundle, or properties file, in this article.) &lt;br /&gt;&lt;br /&gt;I found two solutions, both of which have minor bugs and lack some documentation but are very helpful nevertheless. And it turned out that the second solution uses code from the first one:&lt;br /&gt;&lt;ul&gt;&lt;li&gt;&lt;a href="http://sourceforge.net/projects/eclipse-rbe/"&gt;Resource Bundle Editor&lt;/a&gt; from Sourceforge&lt;/li&gt;&lt;li&gt; &lt;a href="http://wiki.eclipse.org/Babel_/_Message_Bundle_Editor"&gt;Messages Editor&lt;/a&gt; from the &lt;a href="http://www.eclipse.org/babel"&gt;Eclipse Babel&lt;/a&gt; project&lt;/li&gt;&lt;/ul&gt;At first, I tried the Resource Bundle Editor. The latest version is from 2007, and some people have reported conflicts with newer Eclipse versions. I installed the Bundle in my Eclipse 3.5.1, and did not notice any version conflicts at all.&lt;br /&gt;&lt;br /&gt;However, the Resource Bundle Editor does not parse the properties files correctly. It does not recognize exclamation marks as comment signs. For comment lines of the form&lt;br /&gt;&lt;pre&gt;!some.key = some value&lt;br /&gt;&lt;/pre&gt;the editor will display a bogus key &lt;code&gt;!some.key&lt;/code&gt;.&lt;br /&gt;&lt;br /&gt;Looking at the sources, I found the the PropertiesParser class only recognizes a subset of the valid properties file syntax.&lt;br /&gt;&lt;br /&gt;After that, I had a look at the Eclipse Babel editor. Unfortunately, the Babel project does not yet provide binary downloads, so you have to build the two plugins from source.&lt;br /&gt;&lt;br /&gt;As it turned out, parts of the Babel sources are derived from the Resource Bundle Editor sources, and the same incomplete parser code is also used in the Eclipse project in class &lt;code&gt;PropertiesDeserializer&lt;/code&gt;.&lt;br /&gt;&lt;br /&gt;I &lt;a href="https://bugs.eclipse.org/bugs/show_bug.cgi?id=303906"&gt;changed &lt;/a&gt;a regular expression in the source to fix the "!"-problem. You can get the binary plugins including my patch from here:&lt;br /&gt;&lt;br /&gt;&lt;ul&gt;&lt;li&gt;&lt;a href="http://www.sendspace.com/file/6edwhp"&gt;org.eclipse.babel.core_0.8.0.201002251355.jar&lt;/a&gt;&lt;/li&gt;&lt;li&gt;&lt;a href="http://www.sendspace.com/file/zfdhon"&gt;org.eclipse.babel.editor_0.8.0.201002251355.jar&lt;/a&gt;&lt;/li&gt;&lt;/ul&gt;After installing the plugins, go to &lt;b&gt;Window | Preferences | Messages Editor&lt;/b&gt; and deselect the option &lt;b&gt;Setup validation builder on Java projects automatically&lt;/b&gt;, or else you may get lots of error markers on other properties files which are not used as message bundles at all. I also set the &lt;b&gt;Reports &lt;/b&gt;severities to &lt;b&gt;Ignore &lt;/b&gt;and the &lt;b&gt;Displayed Locales&lt;/b&gt; to &lt;span style="font-family: &amp;quot;Courier New&amp;quot;,Courier,monospace;"&gt;de&lt;/span&gt; to narrow the Editor display to the language I'm actually working on.&lt;br /&gt;&lt;br /&gt;To edit a resource bundle, select the properties file in the Package Explorer and open it with the Messages Editor via the context menu.&lt;br /&gt;&lt;br /&gt;Here is a screenshot of the Messages Editor in action:&lt;br /&gt;&lt;br /&gt;&lt;div class="separator" style="clear: both; text-align: center;"&gt;&lt;a href="http://4.bp.blogspot.com/_BJAmlQZb_Bs/S4cQqABqj2I/AAAAAAAAABk/GSwQXkw2KhA/s1600-h/Babel.png" imageanchor="1" style="margin-left: 1em; margin-right: 1em;"&gt;&lt;img border="0" src="http://4.bp.blogspot.com/_BJAmlQZb_Bs/S4cQqABqj2I/AAAAAAAAABk/GSwQXkw2KhA/s320/Babel.png" /&gt;&lt;/a&gt;&lt;/div&gt;With the additional toolbar buttons, you can limit the view to missing or unused translations.&lt;br /&gt;&lt;ul&gt;&lt;/ul&gt;&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/7836204352369514180-9189400133267041067?l=hwellmann.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://hwellmann.blogspot.com/feeds/9189400133267041067/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=7836204352369514180&amp;postID=9189400133267041067' title='3 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/7836204352369514180/posts/default/9189400133267041067'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/7836204352369514180/posts/default/9189400133267041067'/><link rel='alternate' type='text/html' href='http://hwellmann.blogspot.com/2010/02/editing-resource-bundles-in-eclipse.html' title='Editing Resource Bundles in Eclipse'/><author><name>Harald Wellmann</name><uri>http://www.blogger.com/profile/08039976160321882828</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='16' height='16' src='http://img2.blogblog.com/img/b16-rounded.gif'/></author><media:thumbnail xmlns:media='http://search.yahoo.com/mrss/' url='http://4.bp.blogspot.com/_BJAmlQZb_Bs/S4cQqABqj2I/AAAAAAAAABk/GSwQXkw2KhA/s72-c/Babel.png' height='72' width='72'/><thr:total>3</thr:total></entry><entry><id>tag:blogger.com,1999:blog-7836204352369514180.post-5361269582783590506</id><published>2010-02-23T19:38:00.003+01:00</published><updated>2010-02-23T19:41:59.945+01:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='m2eclipse'/><category scheme='http://www.blogger.com/atom/ns#' term='Eclipse'/><category scheme='http://www.blogger.com/atom/ns#' term='Roller'/><category scheme='http://www.blogger.com/atom/ns#' term='Maven'/><category scheme='http://www.blogger.com/atom/ns#' term='Tomcat'/><title type='text'>Setting up Eclipse for Roller</title><content type='html'>There is an Eclipse plug-in for almost any task, and most of them do their job rather nicely. On the other hand, even some of the more or less official ones may give you a hard time if you try to use them in combination.&lt;br /&gt;&lt;br /&gt;Recently, I've been playing around with &lt;a href="http://roller.apache.org/"&gt;Apache Roller&lt;/a&gt;, a Java blog engine, much like Blogger or Wordpress. This project is currently in beta for the next major release 5.0, so I checked out the sources from trunk, ran the Maven build, created a PostgreSQL database and got my own blog engine up and running within minutes.&lt;br /&gt;&lt;br /&gt;Some minor things did not quite work as expected, so I thought I'd just create an Eclipse workspace for Roller and build and run it from there. As it turned out, the combination of Maven, Subversion, and a Web Application was a rather fatal mix, and it took me a day to figure out what was going wrong.&lt;br /&gt;&lt;br /&gt;Most of this was not a Roller issue at all: Eclipse Web application tooling (WTP) and Maven Integration (m2eclipse) just make too many implicit and conflicting assumptions which make it hard to set things up correctly, so this article is really about working with a mavenized web application in Eclipse, and Roller is just an example.&lt;br /&gt;&lt;br /&gt;There are a couple of threads on the Roller developer mailing list dealing with Eclipse setups, but none of them really provides a working solution, so maybe this post can fill gap.&lt;br /&gt;&lt;br /&gt;&lt;h4&gt;Step 1: Get Eclipse and all required plug-ins&lt;/h4&gt;&lt;br /&gt;To avoid any conflicts with other plug-ins or features not required for this project, I used a separate Eclipse installation consisting of&lt;br /&gt;&lt;ul&gt;&lt;li&gt;Eclipse for Java EE Developers 3.5.1&lt;/li&gt;&lt;li&gt;Subversive SVN Team Provider 0.7.8&lt;/li&gt;&lt;li&gt;Subversive SVN Connectors 2.2.1&lt;/li&gt;&lt;li&gt;Maven Integration for Eclipse 0.10.0&lt;/li&gt;&lt;li&gt;Maven Integration for WTP 0.10.0 &lt;/li&gt;&lt;/ul&gt;Even if you do not intend to commit any changes from Eclipse, you will need the Subversion integration to deploy your web application from a Subversion working copy, otherwise Eclipse will try to pack the hidden .svn directories into the JARs and WARs and complain about duplicate paths.&lt;br /&gt;&lt;h4&gt;Step 2: Set up m2eclipse&lt;br /&gt;&lt;/h4&gt;m2eclipse has a built-in pre-release version of Maven 3.0.0 which is not compatible with most existing projects based on Maven 2.x. Get a local installation of Maven 2.1.0 and define it as default for m2eclipse in &lt;b&gt;Window | Preferences | Maven | Installations&lt;/b&gt;.&lt;br /&gt;&lt;h4&gt;Step 3: Set up Tomcat&lt;br /&gt;&lt;/h4&gt;Download and install Tomcat 6.0.24 to a local directory. Create a Tomcat server instance for Eclipse via &lt;b&gt;Window | Preferences | Server | Runtime Environments&lt;/b&gt; pointing to your Tomcat installation directory.&lt;br /&gt;&lt;br /&gt;Install the additional prerequisites of Roller in the Tomcat lib directory:&lt;br /&gt;&lt;ul&gt;&lt;li&gt;mail.jar&lt;/li&gt;&lt;li&gt;activation.jar&lt;/li&gt;&lt;li&gt;your JDBC driver&lt;/li&gt;&lt;/ul&gt;&lt;h4&gt;Step 4: Get Roller into your Eclipse workspace&lt;/h4&gt;Create a new empty workspace and switch to the SVN Repository Exploring perspective. There is supposed to be an integration of m2eclipse and Subversive, which I never managed to get to work, so this is why I use the following somewhat clumsy procedure to populate my workspace:&lt;br /&gt;&lt;ul&gt;&lt;li&gt;Switch to the SVN Repository Exploring perspective and define a new repository location for https://svn.apache.org/repos/asf.&lt;/li&gt;&lt;li&gt;Check out Roller from roller/trunk. This will create a new project roller-project in your workspace.&lt;/li&gt;&lt;li&gt;Unfortunately, the Maven modules of this project do not yet appear as separate Eclipse projects. To change this, delete the project from your workspace and use &lt;b&gt;File | Import | Maven | Existing Maven Projects&lt;/b&gt;. Select the workspace folder from your initial checkout.&lt;/li&gt;&lt;li&gt;After this, you should have six Maven projects in your workspace, all shared via Subversive.&lt;/li&gt;&lt;/ul&gt;&lt;h4&gt;Step 5: Apply some fixes in the workspace &lt;/h4&gt;&lt;ul&gt;&lt;li&gt;Go to roller-weblogger-business and delete src/test/resources/org/apache/roller/weblogger/business/package.html, since this file would cause a clash with another copy from src/main/resources.&lt;/li&gt;&lt;li&gt;Open /roller-weblogger-web/src/main/webapp/WEB-INF/security.xml and replace spring-security-2.0.1-openidfix.xsd by spring-security-2.0.4.xsd.&lt;/li&gt;&lt;li&gt;Copy your roller-custom.properties to /roller-weblogger-web/src/main/resources.&lt;/li&gt;&lt;/ul&gt;&lt;h4&gt;Step 6: Configure your web application&lt;/h4&gt;&lt;ul&gt;&lt;li&gt;Open the project properties of roller-weblogger-web.&lt;/li&gt;&lt;li&gt;Select the Java EE Module Dependencies and activate roller-planet-business, roller-core and roller-weblogger-business.&lt;/li&gt;&lt;li&gt;Make sure that the resources from all dependent projects will get copied into the web application by modifying the build path settings of roller-planet-business, roller-weblogger-business and roller-weblogger-web. Select &lt;b&gt;Java Build Path&lt;/b&gt; from the project properties and remove the Excluded: ** entry from src/main/resources for each of these projects.&lt;/li&gt;&lt;/ul&gt;&lt;h4&gt;Step 7: Run a Maven build&lt;/h4&gt;&lt;ul&gt;&lt;li&gt;Select roller-project/pom.xml. From the context menu, select &lt;b&gt;Run As | Maven build...&lt;/b&gt;&lt;/li&gt;&lt;li&gt;In the launcher dialog, fill in the goals clean install and (optionally) check Skip Tests to save some time during each build.&lt;/li&gt;&lt;li&gt;When the build has completed, select all projects and press F5 so that Eclipse will see all the resources created by Maven.&lt;/li&gt;&lt;li&gt;This step is required, since the Maven build generates some additional resources and runs the OpenJPA Enhancer. These two steps would not be handled by the Eclipse automatic build.&lt;/li&gt;&lt;/ul&gt;&lt;h4&gt;Step 8: Make sure that Eclipse picks up the generated resources&lt;/h4&gt;&lt;ul&gt;&lt;li&gt;Create a folder /roller-weblogger-web/src/main/sql and turn it into a source folder.&lt;/li&gt;&lt;li&gt;Copy /roller-weblogger-business/target/dbscripts into this folder.&lt;/li&gt;&lt;/ul&gt;&lt;h4&gt;Step 9: Get Rolling!&lt;/h4&gt;&lt;ul&gt;&lt;li&gt;Select roller-weblogger-web and invoke &lt;b&gt;Run As | Run on Server&lt;/b&gt; from the context menu.&lt;/li&gt;&lt;li&gt;Select the Tomcat instance created in Step 3 and activate it as default if you like and click &lt;b&gt;Finish&lt;/b&gt;.&lt;/li&gt;&lt;/ul&gt;&lt;h4&gt;Troubleshooting&lt;/h4&gt;&lt;ul&gt;&lt;li&gt;If you get stuck, clean the Tomcat instance. Open the Servers view and select Tomcat. From the context menu, invoke Clean...&lt;/li&gt;&lt;li&gt;To check the web application assembled by Eclipse, have a look into &amp;lt;Eclipse workspace&amp;gt;/.metadata/.plugins/org.eclipse.wst.server.core/tmp0/wtpwebapps/roller-weblogger-web/&lt;/li&gt;&lt;/ul&gt;All of this should have been a lot easier. m2eclipse will have to mature, and Eclipse should be more flexible about resource locations... &lt;br /&gt;&lt;ul&gt;&lt;/ul&gt;&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/7836204352369514180-5361269582783590506?l=hwellmann.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://hwellmann.blogspot.com/feeds/5361269582783590506/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=7836204352369514180&amp;postID=5361269582783590506' title='6 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/7836204352369514180/posts/default/5361269582783590506'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/7836204352369514180/posts/default/5361269582783590506'/><link rel='alternate' type='text/html' href='http://hwellmann.blogspot.com/2010/02/setting-up-eclipse-for-roller.html' title='Setting up Eclipse for Roller'/><author><name>Harald Wellmann</name><uri>http://www.blogger.com/profile/08039976160321882828</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='16' height='16' src='http://img2.blogblog.com/img/b16-rounded.gif'/></author><thr:total>6</thr:total></entry><entry><id>tag:blogger.com,1999:blog-7836204352369514180.post-7957250794972021081</id><published>2009-12-17T21:42:00.000+01:00</published><updated>2009-12-17T23:43:32.559+01:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='Anaconda'/><category scheme='http://www.blogger.com/atom/ns#' term='JUnit'/><title type='text'>Running parameterized JUnit tests in parallel</title><content type='html'>We use JUnit 4 for &lt;b&gt;Anaconda&lt;/b&gt;, not just for unit tests, but also for integration or system tests. Typically, we iterate over all features of a given class in a database and validate each feature.&lt;br /&gt;&lt;br /&gt;&lt;b&gt;Note:&lt;/b&gt; I'm using the term &lt;i&gt;feature&lt;/i&gt; in the sense of map feature, not in the sense of application feature or implemented requirement.&lt;br /&gt;&lt;br /&gt;A simple pattern for such tests is&lt;br /&gt;&lt;br /&gt;&lt;pre&gt;public class FeatureTest&lt;br /&gt;{ &lt;br /&gt;    @Test&lt;br /&gt;    public void testAllFeatures()&lt;br /&gt;    {&lt;br /&gt;        for (Feature feature : findAllFeatures())&lt;br /&gt;        {&lt;br /&gt;            testOneFeature(feature);&lt;br /&gt;        }&lt;br /&gt;    }&lt;br /&gt;&lt;br /&gt;    private void testOneFeature(Feature feature)&lt;br /&gt;    {&lt;br /&gt;        // some logic with one or more JUnit assertions&lt;br /&gt;    }&lt;br /&gt;}&lt;br /&gt;&lt;/pre&gt;&lt;br /&gt;Obviously, this naive approach has the following drawbacks:&lt;br /&gt;&lt;ul&gt;&lt;li&gt;The test fails and terminates on the first incorrect feature. The remaining features will not be tested.&lt;/li&gt;&lt;li&gt;All features get tested sequentially. This may take awfully long for a large database.&lt;/li&gt;&lt;/ul&gt;JUnit 4 has a specialized runner &lt;span style="font-family: &amp;quot;Courier New&amp;quot;,Courier,monospace;"&gt;Parameterized&lt;/span&gt; for running all tests in a given class with different parameters from a given list of parameter sets. An instance of the test class is created for each parameter set, and the parameters are passed to the constructor via reflection:&lt;br /&gt;&lt;br /&gt;&lt;pre&gt;@RunWith(Parameterized.class)&lt;br /&gt;public class FeatureTest&lt;br /&gt;{&lt;br /&gt;    // This is the parameter for each instance of the test.&lt;br /&gt;    private Feature feature;&lt;br /&gt;&lt;br /&gt;    public FeatureTest(Feature feature)&lt;br /&gt;    {&lt;br /&gt;         this.feature = feature;&lt;br /&gt;    }&lt;br /&gt;&lt;br /&gt;    @Parameters&lt;br /&gt;    public static Collection&amp;lt;Object[]&amp;gt; getParameters()     &lt;br /&gt;    {         &lt;br /&gt;        List&amp;lt;Feature&amp;gt; features = findAllFeatures();&lt;br /&gt;        List&amp;lt;Object&amp;gt; parameters = new ArrayList&amp;lt;Object[]&amp;gt;(features.size());&lt;br /&gt;        for (Feature feature : features)         &lt;br /&gt;        {&lt;br /&gt;             parameters.add(new Object[] { feature };&lt;br /&gt;        }&lt;br /&gt;        return parameters;&lt;br /&gt;    }&lt;br /&gt; &lt;br /&gt;    @Test&lt;br /&gt;    public void testOneFeature()     &lt;br /&gt;    {&lt;br /&gt;        // assertions acting on the feature member&lt;br /&gt;    }&lt;br /&gt;} &lt;br /&gt;&lt;/pre&gt;&lt;br /&gt;This solves the first problem: Each feature gets tested in its own test instance. Now if there is a large number of features or if each individual test is very expensive, we would like to run the test instances in parallel, using a thread pool, or maybe even a grid of multiple computers.&lt;br /&gt;&lt;br /&gt;Browsing through the JUnit sources, I found a surprisingly easy way of parallelizing the tests with a thread pool, simply by using a custom runner:&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;&lt;pre&gt;@RunWith(Parallelized.class)&lt;br /&gt;public class FeatureTest&lt;br /&gt;{&lt;br /&gt;   // same class body as above&lt;br /&gt;}&lt;br /&gt;&lt;/pre&gt;&lt;br /&gt;&lt;br /&gt;All you need is a simple extension of the Parameterized runner:&lt;br /&gt;&lt;br /&gt;&lt;pre&gt;public class Parallelized extends Parameterized&lt;br /&gt;{&lt;br /&gt;    &lt;br /&gt;    private static class ThreadPoolScheduler implements RunnerScheduler&lt;br /&gt;    {&lt;br /&gt;        private ExecutorService executor; &lt;br /&gt;        &lt;br /&gt;        public ThreadPoolScheduler()&lt;br /&gt;        {&lt;br /&gt;            String threads = System.getProperty("junit.parallel.threads", "16");&lt;br /&gt;            int numThreads = Integer.parseInt(threads);&lt;br /&gt;            executor = Executors.newFixedThreadPool(numThreads);&lt;br /&gt;        }&lt;br /&gt;        &lt;br /&gt;        @Override&lt;br /&gt;        public void finished()&lt;br /&gt;        {&lt;br /&gt;            executor.shutdown();&lt;br /&gt;            try&lt;br /&gt;            {&lt;br /&gt;                executor.awaitTermination(10, TimeUnit.MINUTES);&lt;br /&gt;            }&lt;br /&gt;            catch (InterruptedException exc)&lt;br /&gt;            {&lt;br /&gt;                throw new RuntimeException(exc);&lt;br /&gt;            }&lt;br /&gt;        }&lt;br /&gt;&lt;br /&gt;        @Override&lt;br /&gt;        public void schedule(Runnable childStatement)&lt;br /&gt;        {&lt;br /&gt;            executor.submit(childStatement);&lt;br /&gt;        }&lt;br /&gt;    }&lt;br /&gt;&lt;br /&gt;    public Parallelized(Class klass) throws Throwable&lt;br /&gt;    {&lt;br /&gt;        super(klass);&lt;br /&gt;        setScheduler(new ThreadPoolScheduler());&lt;br /&gt;    }&lt;br /&gt;}&lt;br /&gt;&lt;br /&gt;&lt;/pre&gt;&lt;br /&gt;The &lt;code&gt;RunnerScheduler&lt;/code&gt; interface is fairly new in JUnit and marked as experimental. I discovered it in the current version JUnit 4.8.1 and found it missing in JUnit 4.4.0 which we have been using so far. &lt;code&gt;RunnerScheduler&lt;/code&gt; is also available in JUnit 4.7.0, but I did not check if this is the earliest version.&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/7836204352369514180-7957250794972021081?l=hwellmann.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://hwellmann.blogspot.com/feeds/7957250794972021081/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=7836204352369514180&amp;postID=7957250794972021081' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/7836204352369514180/posts/default/7957250794972021081'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/7836204352369514180/posts/default/7957250794972021081'/><link rel='alternate' type='text/html' href='http://hwellmann.blogspot.com/2009/12/running-parameterized-junit-tests-in.html' title='Running parameterized JUnit tests in parallel'/><author><name>Harald Wellmann</name><uri>http://www.blogger.com/profile/08039976160321882828</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='16' height='16' src='http://img2.blogblog.com/img/b16-rounded.gif'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-7836204352369514180.post-329023463610591607</id><published>2009-10-04T20:50:00.000+02:00</published><updated>2009-10-04T20:50:13.449+02:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='Forms'/><category scheme='http://www.blogger.com/atom/ns#' term='Eclipse'/><title type='text'>Eclipse Forms and Data Binding</title><content type='html'>Our map compiler &lt;span style="font-weight: bold;"&gt;Anaconda &lt;/span&gt;reads all parameters and settings from a configuration file, which over time has evolved from a simple Java properties file to a not-so-simple XML file which is validated by an XML schema.&lt;br /&gt;&lt;br /&gt;To access the configuration at runtime, we use Java XML Bindings generated from our schema by xjc in a straightforward manner, without any fancy customizations.&lt;br /&gt;&lt;br /&gt;Using the XML editing support in Eclipse, it is very easy to edit and validate a configuration file, at least from a developer perspective. However, our customers will not be too happy about editing large XML files by hand, so the idea is to develop a form-based configuration editor for our RCP application &lt;span style="font-weight: bold;"&gt;Anaconda Workbench&lt;/span&gt;, similar to the manifest editor of Eclipse PDE or the POM editor of m2eclipse.&lt;br /&gt;&lt;br /&gt;These editors are based on Eclipse UI forms, another layer on top of SWT and JFace, which is obviously powerful enough for complex tasks, as demonstrated by the above examples. Less obviously, it is rather poorly documented. The Eclipse online help has just 10 brief pages about UI Forms and the Javadocs which, as usual, are not very useful for getting started.&lt;br /&gt;&lt;br /&gt;The Eclipe Rich Client Platform book also has not more than one page on UI Forms and a link to an &lt;a href="http://dev.eclipse.org/viewcvs/index.cgi/pde-ui-home/working/EclipseForms/EclipseForms.html?view=co"&gt;online article&lt;/a&gt; from 2004. On the Eclipse site, there are two more recent articles&lt;br /&gt;&lt;ul&gt;&lt;li&gt;&lt;a href="http://www.eclipse.org/articles/Article-Forms/article.html"&gt;Eclipse Forms: Rich UI for the Rich Client&lt;/a&gt;&lt;/li&gt;&lt;li&gt;&lt;a href="http://www.eclipse.org/articles/article.php?file=Article-Forms33/index.html"&gt;Eclipse Forms: New in 3.3&lt;/a&gt;&lt;/li&gt;&lt;/ul&gt;Looking for futher tutorials, I came across Marco van Meegen's critical review &lt;a href="http://it-republik.de/jaxenter/artikel/Eclipse-Forms-im-Haertetest-1816.html"&gt;Eclipse Forms im Härtetest&lt;/a&gt;. I decided to make up my own mind, but after implementing a few examples with Eclipse Forms, I largely agree to his criticism: the API forces you to write lots of repetitive code and it is not easy to figure out how to wire up the different classes to do your job.&lt;br /&gt;&lt;br /&gt;To alleviate the shortcomings of Eclipse Forms, Marco created yet another layer called &lt;a href="http://rcpforms.wiki.sourceforge.net/"&gt;RCPForms&lt;/a&gt;. So I gave it a try, and I found it a lot easier to use than working with UI Forms directly. I had to use the sources from the Subversion trunk at Sourceforge, the older tagged or released versions do not seem to work with Eclipse 3.5.&lt;br /&gt;&lt;br /&gt;Eclipse forms are usually wrapped by a ManagedForm which manages the state of the form parts and the underlying data models.&lt;br /&gt;&lt;br /&gt;The form parts and the models can vary independently, and one model can be shared by multiple form parts.&lt;br /&gt;&lt;br /&gt;A managed form is dirty, when one of its parts is more recent than the underlying model. Conversely, it is stale, when a change in the underlying model is not yet reflected on the UI.&lt;br /&gt;&lt;br /&gt;To handle this form lifecycle, RCPForms expects the model to support PropertyChangeListeners, which again requires you to add some boilerplate code to your model beans. For my example with a JAXB model, I managed to tweak xjc to generate the required listeners, which is to be discussed in detail in a separate article.&lt;br /&gt;&lt;br /&gt;Here is a screenshot of a simple example:&lt;br /&gt;&lt;div class="separator" style="clear: both; text-align: center;"&gt;&lt;a href="http://1.bp.blogspot.com/_BJAmlQZb_Bs/SsjuAMSWH7I/AAAAAAAAABc/gTAyDKrIEOA/s1600-h/RcpForms1.png" imageanchor="1" style="margin-left: 1em; margin-right: 1em;"&gt;&lt;img border="0" src="http://1.bp.blogspot.com/_BJAmlQZb_Bs/SsjuAMSWH7I/AAAAAAAAABc/gTAyDKrIEOA/s400/RcpForms1.png" /&gt;&lt;/a&gt;&lt;br /&gt;&lt;/div&gt;&lt;br /&gt;The warnings result from validators on missing mandatory fields.&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/7836204352369514180-329023463610591607?l=hwellmann.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://hwellmann.blogspot.com/feeds/329023463610591607/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=7836204352369514180&amp;postID=329023463610591607' title='8 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/7836204352369514180/posts/default/329023463610591607'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/7836204352369514180/posts/default/329023463610591607'/><link rel='alternate' type='text/html' href='http://hwellmann.blogspot.com/2009/10/eclipse-forms-and-data-binding.html' title='Eclipse Forms and Data Binding'/><author><name>Harald Wellmann</name><uri>http://www.blogger.com/profile/08039976160321882828</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='16' height='16' src='http://img2.blogblog.com/img/b16-rounded.gif'/></author><media:thumbnail xmlns:media='http://search.yahoo.com/mrss/' url='http://1.bp.blogspot.com/_BJAmlQZb_Bs/SsjuAMSWH7I/AAAAAAAAABc/gTAyDKrIEOA/s72-c/RcpForms1.png' height='72' width='72'/><thr:total>8</thr:total></entry><entry><id>tag:blogger.com,1999:blog-7836204352369514180.post-3421518749509928348</id><published>2009-09-13T21:35:00.018+02:00</published><updated>2009-09-14T21:27:00.919+02:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='Eclipse'/><title type='text'>Eclipse RCP Application Branding</title><content type='html'>A while ago, I figured out how to use the branding features in Eclipse to make the About dialog in my &lt;span style="font-weight: bold;"&gt;Anaconda Workbench&lt;/span&gt; show all the included features with the appropriate icons and other information. This was based on Eclipse 3.4, and here is a screenshot of the results:&lt;br /&gt;&lt;br /&gt;&lt;a onblur="try {parent.deselectBloggerImageGracefully();} catch(e) {}" href="http://1.bp.blogspot.com/_BJAmlQZb_Bs/Sq1KkgS_jbI/AAAAAAAAAA0/V2CNvUSrWi0/s1600-h/AboutWorkbench.png"&gt;&lt;img style="margin: 0px auto 10px; display: block; text-align: center; cursor: pointer; width: 400px; height: 202px;" src="http://1.bp.blogspot.com/_BJAmlQZb_Bs/Sq1KkgS_jbI/AAAAAAAAAA0/V2CNvUSrWi0/s400/AboutWorkbench.png" alt="" id="BLOGGER_PHOTO_ID_5381039120782953906" border="0" /&gt;&lt;/a&gt;&lt;br /&gt;&lt;br /&gt;Clicking on Feature Details, you get a list of all branded features included in the product:&lt;br /&gt;&lt;br /&gt;&lt;a onblur="try {parent.deselectBloggerImageGracefully();} catch(e) {}" href="http://2.bp.blogspot.com/_BJAmlQZb_Bs/Sq1LFZHpMdI/AAAAAAAAAA8/7eQ1QtKr0gQ/s1600-h/FeatureDetails.png"&gt;&lt;img style="margin: 0px auto 10px; display: block; text-align: center; cursor: pointer; width: 400px; height: 320px;" src="http://2.bp.blogspot.com/_BJAmlQZb_Bs/Sq1LFZHpMdI/AAAAAAAAAA8/7eQ1QtKr0gQ/s400/FeatureDetails.png" alt="" id="BLOGGER_PHOTO_ID_5381039685791986130" border="0" /&gt;&lt;/a&gt;&lt;br /&gt;Not every feature is branded by default. You have to associate a branding plug-in to a given feature and  include an &lt;code&gt;about.ini&lt;/code&gt; file and an optional icon in the branding plug-in. I won't go into details for this Eclipse 3.4 example, seeing that things have changed for Eclipse 3.5, and the rest of this post relates to Eclipse 3.5.&lt;br /&gt;&lt;br /&gt;&lt;h4&gt;What's new in 3.5&lt;/h4&gt;&lt;br /&gt;&lt;a onblur="try {parent.deselectBloggerImageGracefully();} catch(e) {}" href="http://4.bp.blogspot.com/_BJAmlQZb_Bs/Sq1Rfoc6kjI/AAAAAAAAABM/1-GqETbOyUw/s1600-h/AboutWorkbench3.5.png"&gt;&lt;img style="margin: 0px auto 10px; display: block; text-align: center; cursor: pointer; width: 400px; height: 188px;" src="http://4.bp.blogspot.com/_BJAmlQZb_Bs/Sq1Rfoc6kjI/AAAAAAAAABM/1-GqETbOyUw/s400/AboutWorkbench3.5.png" alt="" id="BLOGGER_PHOTO_ID_5381046733654102578" border="0" /&gt;&lt;/a&gt;&lt;br /&gt;&lt;br /&gt;The Feature, Plug-ins and Configuration Details buttons have gone, now there is just a single Installation Details button. To see the installed features, click on one of the feature icons to open a dialog listing all features branded with the same icon.&lt;br /&gt;&lt;br /&gt;&lt;a onblur="try {parent.deselectBloggerImageGracefully();} catch(e) {}" href="http://2.bp.blogspot.com/_BJAmlQZb_Bs/Sq1RpCNS90I/AAAAAAAAABU/x90uiW2XW0E/s1600-h/FeatureDetails3.5.png"&gt;&lt;img style="margin: 0px auto 10px; display: block; text-align: center; cursor: pointer; width: 400px; height: 380px;" src="http://2.bp.blogspot.com/_BJAmlQZb_Bs/Sq1RpCNS90I/AAAAAAAAABU/x90uiW2XW0E/s400/FeatureDetails3.5.png" alt="" id="BLOGGER_PHOTO_ID_5381046895186736962" border="0" /&gt;&lt;/a&gt;&lt;br /&gt;&lt;br /&gt;(Actually, I'm not quite sure whether or not the icon name is the grouping criterion, but I guess so from my experiments.)&lt;br /&gt;&lt;br /&gt;Selecting a feature from the list and clicking on Plug-in Details, you can display all plug-ins contained in the feature.&lt;br /&gt;&lt;br /&gt;&lt;h4&gt;Things to note&lt;/h4&gt;&lt;br /&gt;Eclipse Help has just two rather brief topics on &lt;a href="http://help.eclipse.org/galileo/index.jsp?topic=/org.eclipse.pde.doc.user/guide/tools/editors/product_editor/branding.htm"&gt;Product Branding&lt;/a&gt; and &lt;a href="http://help.eclipse.org/galileo/index.jsp?topic=/org.eclipse.platform.doc.isv/guide/product_configproduct.htm"&gt;Customizing a product&lt;/a&gt;. Branding a product is straightforward if you use the Product Configuration Editor as explained in the first topic. Things get more complicated when your product contains multiple features or even third-party products.&lt;br /&gt;&lt;br /&gt;For each feature to branded, you need a branding plug-in containing the following resources:&lt;br /&gt;&lt;br /&gt;&lt;ul&gt;&lt;li&gt;about.ini&lt;/li&gt;&lt;li&gt;about.properties (optional)&lt;br /&gt;&lt;/li&gt;&lt;li&gt;a 32*32 icon&lt;/li&gt;&lt;/ul&gt;Make sure to include these resources in you build.properties so they will be exported to your plug-in JAR.&lt;br /&gt;&lt;br /&gt;In &lt;code&gt;about.ini&lt;/code&gt;, set the following two properties:&lt;br /&gt;&lt;pre&gt;&lt;br /&gt;aboutText=Anaconda Workbench for Car Navigation Databases&lt;br /&gt;featureImage=icons/anaconda32.png&lt;br /&gt;&lt;/pre&gt;&lt;br /&gt;You can use the optional &lt;code&gt;about.properties&lt;/code&gt; to work with language dependent variables in &lt;code&gt;about.ini&lt;/code&gt;. Set &lt;code&gt;featureImage&lt;/code&gt; to the relative path of your icon resource.&lt;br /&gt;&lt;br /&gt;By default, Eclipse assumes that the branding plugin for a feature &lt;code&gt;com.acme.foo&lt;/code&gt; is also named &lt;code&gt;com.acme.foo&lt;/code&gt;. If you want to assign a different name, you have to explicitly declare the branding plug-in in the feature editor.&lt;br /&gt;&lt;br /&gt;I ran into a conflict between feature branding and product branding: My top-level product Anaconda Workbench contains another product udigLite, which in turn contains Geotools, Eclipse EMF and Eclipse RCP.&lt;br /&gt;&lt;br /&gt;udigLite is a modified subset of uDig. uDig has a top-level feature named &lt;code&gt;net.refractions.udig&lt;/code&gt; which a contains a branding plug-in of the same name with a product definition.&lt;br /&gt;&lt;br /&gt;udigLite originally had a top-level feature &lt;code&gt;net.refractions.udig.lite&lt;/code&gt; containing just a subset of the uDig plug-ins, including the &lt;code&gt;net.refractions.udig&lt;/code&gt; plug-in which cannot be left out as it contains more than just branding information.&lt;br /&gt;&lt;br /&gt;With this configuration, I ended up with two uDig features in the feature list: &lt;code&gt;net.refractions.udig.lite&lt;/code&gt; as expected, and &lt;code&gt;net.refractions.udig&lt;/code&gt;, although no such feature exists in my product.&lt;br /&gt;&lt;br /&gt;It seems that a branding plug-in containing a product definition is automatically treated as a feature of the same name. I wonder if that's a bug or a feature (pun intended).&lt;br /&gt;&lt;br /&gt;Anyway, to remove this duplicate, I dropped my &lt;code&gt;net.refractions.udig.lite&lt;/code&gt; feature and changed the original &lt;code&gt;net.refractions.udig&lt;/code&gt; feature to include just the required subset of plug-ins.&lt;br /&gt;&lt;br /&gt;Another problem I ran into is &lt;a href="https://bugs.eclipse.org/bugs/show_bug.cgi?id=280186"&gt;bug 280186&lt;/a&gt; or &lt;a href="https://bugs.eclipse.org/bugs/show_bug.cgi?id=289300"&gt;bug 289300&lt;/a&gt;, causing each feature to be listed twice in the exported product. To supress that, you can drop the &lt;code&gt;org.eclipse.equinox.ds&lt;/code&gt; plug-in from your product, provided your application does not depend on Declarative Services.&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/7836204352369514180-3421518749509928348?l=hwellmann.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://hwellmann.blogspot.com/feeds/3421518749509928348/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=7836204352369514180&amp;postID=3421518749509928348' title='2 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/7836204352369514180/posts/default/3421518749509928348'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/7836204352369514180/posts/default/3421518749509928348'/><link rel='alternate' type='text/html' href='http://hwellmann.blogspot.com/2009/09/eclipse-rcp-application-branding.html' title='Eclipse RCP Application Branding'/><author><name>Harald Wellmann</name><uri>http://www.blogger.com/profile/08039976160321882828</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='16' height='16' src='http://img2.blogblog.com/img/b16-rounded.gif'/></author><media:thumbnail xmlns:media='http://search.yahoo.com/mrss/' url='http://1.bp.blogspot.com/_BJAmlQZb_Bs/Sq1KkgS_jbI/AAAAAAAAAA0/V2CNvUSrWi0/s72-c/AboutWorkbench.png' height='72' width='72'/><thr:total>2</thr:total></entry><entry><id>tag:blogger.com,1999:blog-7836204352369514180.post-4273013290987561308</id><published>2009-04-07T16:09:00.004+02:00</published><updated>2010-02-19T12:07:13.207+01:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='uDig'/><category scheme='http://www.blogger.com/atom/ns#' term='SLD'/><category scheme='http://www.blogger.com/atom/ns#' term='Anaconda'/><title type='text'>Arrows with Styled Layer Descriptor</title><content type='html'>In our &lt;a href="http://udig.refractions.net/"&gt;uDig &lt;/a&gt;plug-ins for the &lt;span style="font-weight: bold;"&gt;Anaconda Workbench&lt;/span&gt;, we use &lt;a href="http://www.opengeospatial.org/standards/sld"&gt;Styled Layer Descriptors&lt;/a&gt; (SLD) for the map styles.&lt;br /&gt;&lt;br /&gt;One of the features we are currently working on is the direction attributes for one-way streets. Of course you want to visualize them on the map, but SLD does not directly support arrow decorations for lines.&lt;br /&gt;&lt;br /&gt;I asked for advice on the uDig mailing list and got the answer in no time. You can either use an arrow character from a suitable font in a Text Symbolizer, or a clever combination of Line Symbolizers with different styles of dashed lines to emulate arrows.&lt;br /&gt;&lt;br /&gt;Using an &lt;a href="http://blog.geoserver.org/2009/04/02/follow-the-arrows/"&gt;SLD snippet from the Geoserver blog&lt;/a&gt;, I got the following result:&lt;br /&gt;&lt;br /&gt;&lt;small&gt;[Sorry, screenshot deleted to avoid potential licence issues.]&lt;/small&gt;&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/7836204352369514180-4273013290987561308?l=hwellmann.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://hwellmann.blogspot.com/feeds/4273013290987561308/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=7836204352369514180&amp;postID=4273013290987561308' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/7836204352369514180/posts/default/4273013290987561308'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/7836204352369514180/posts/default/4273013290987561308'/><link rel='alternate' type='text/html' href='http://hwellmann.blogspot.com/2009/04/arrows-with-styled-layer-descriptor.html' title='Arrows with Styled Layer Descriptor'/><author><name>Harald Wellmann</name><uri>http://www.blogger.com/profile/08039976160321882828</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='16' height='16' src='http://img2.blogblog.com/img/b16-rounded.gif'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-7836204352369514180.post-1439418686442330584</id><published>2009-04-02T10:10:00.002+02:00</published><updated>2009-04-03T10:39:12.213+02:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='OSGi'/><category scheme='http://www.blogger.com/atom/ns#' term='Equinox'/><category scheme='http://www.blogger.com/atom/ns#' term='Eclipse'/><category scheme='http://www.blogger.com/atom/ns#' term='Declarative Services'/><title type='text'>Getting Started with OSGi Declarative Services</title><content type='html'>OSGi Declarative Services have been on my mental agenda for a while, and now I've started using them. I'm not going to write yet another tutorial on the subject, but there are some bits and pieces I could not find anywhere else that may be worth mentioning.&lt;br /&gt;&lt;br /&gt;To get an overview of Declarative Services, have a look at Neil Bartlett's &lt;a href="http://www.eclipsezone.com/eclipse/forums/t96740.html"&gt;tutorial on EclipseZone&lt;/a&gt;, or at his more recent &lt;a href="http://neilbartlett.name/blog/2009/03/25/component-models-tutorial/"&gt;EclipseCon presentation&lt;/a&gt;. The former is based on Eclipse 3.2.2, the latter on the latest Eclipse 3.5 milestones, so there are some differences to the current release Eclipse 3.4.2. In particular, Eclipse 3.5 supports a newer version of the Declarative Services Specification (1.1 vs. 1.0 in Eclipse 3.4).&lt;br /&gt;&lt;br /&gt;All of the following refers to Eclipse 3.4.2. For using Declarative Services with Equinox, you need the following bundles:&lt;br /&gt;&lt;ul&gt;&lt;li&gt;org.eclipse.osgi&lt;/li&gt;&lt;li&gt;org.eclipse.osgi.services&lt;/li&gt;&lt;li&gt;org.eclipse.equinox.ds&lt;/li&gt;&lt;li&gt;org.eclipse.equinox.util&lt;/li&gt;&lt;/ul&gt;The last two are not included in standard Eclipse distributions. Download them from the &lt;a href="http://download.eclipse.org/equinox/"&gt;Equinox download area&lt;/a&gt;, or use the Eclipse update manager to install &lt;span style="font-style: italic;"&gt;Equinox Bundles&lt;/span&gt;.&lt;br /&gt;&lt;br /&gt;Follow the tutorials to implement a simple example. If you cannot figure out why your component does not start, enable console logging for the Service Component Runtime in your OSGi launcher by setting the following system properties.&lt;br /&gt;&lt;ul&gt;&lt;li&gt;equinox.ds.debug=true&lt;/li&gt;&lt;li&gt;equinox.ds.print=true&lt;/li&gt;&lt;/ul&gt;Make sure to include the OSGI-INF folder with your component descriptors into the binary build on the Build tab of the Eclipe manifest editor. This amounts to adding the folder to the bin.includes property in the build.properties.&lt;br /&gt;&lt;br /&gt;Add a header &lt;code&gt;Service-Component: OSGI-INF/components.xml&lt;/code&gt; to your manifest. (Choose any other filename if you like.)&lt;br /&gt;&lt;br /&gt;Do not forget to specify the correct XML namespace &lt;code&gt;http://www.osgi.org/xmlns/scr/v1.0.0&lt;/code&gt; in your XML documents, or else your component definitions will not be recognized.&lt;br /&gt;&lt;br /&gt;Seeing that Eclipse 3.4 has no graphical editors for the component descriptors, it is useful to install the Eclipse XML editor features and to work with XML validation on the component descriptors.&lt;br /&gt;&lt;br /&gt;If your bundle contains more than one component, you can have one XML document per component and list them all in the manifest header, or you can have a single XML document containing all component descriptions, which is what I prefer.&lt;br /&gt;&lt;br /&gt;To enable XML validation on a multi-component descriptor, write your own XML schema where the root element contains a sequence of 1..n component descriptors.&lt;br /&gt;&lt;br /&gt;Here is an XML schema for this purpose:&lt;br /&gt;&lt;br /&gt;&lt;pre name="code" class="Xml"&gt;&lt;br /&gt;&amp;lt;?xml version="1.0" encoding="UTF-8"?&gt;&lt;br /&gt;&amp;lt;schema xmlns="http://www.w3.org/2001/XMLSchema"&lt;br /&gt;        xmlns:scr="http://www.osgi.org/xmlns/scr/v1.0.0" &lt;br /&gt;        targetNamespace="http://www.harmanbecker.com/anaconda/components" &lt;br /&gt;        xmlns:tns="http://www.example.org/components" &lt;br /&gt;        elementFormDefault="qualified"&gt;&lt;br /&gt;&lt;br /&gt;   &amp;lt;import namespace="http://www.osgi.org/xmlns/scr/v1.0.0"/&gt;&lt;br /&gt;&lt;br /&gt;    &amp;lt;element name="components"&gt;&lt;br /&gt;      &amp;lt;complexType&gt;&lt;br /&gt;        &amp;lt;sequence&gt;        &lt;br /&gt;          &amp;lt;element ref="scr:component" maxOccurs="unbounded"/&gt;&lt;br /&gt;        &amp;lt;/sequence&gt;&lt;br /&gt;      &amp;lt;/complexType&gt;&lt;br /&gt;    &amp;lt;/element&gt;&lt;br /&gt;&amp;lt;/schema&gt;&lt;br /&gt;&lt;br /&gt;&lt;/pre&gt;&lt;br /&gt;Using this schema, a component descriptor for two components might look like this:&lt;br /&gt;&lt;pre name="code" class="Xml"&gt;&lt;br /&gt;&amp;lt;?xml version="1.0" encoding="UTF-8"?&gt;&lt;br /&gt;&amp;lt;c:components xmlns:scr="http://www.osgi.org/xmlns/scr/v1.0.0"&lt;br /&gt;      xmlns:c="http://www.harmanbecker.com/anaconda/components"&gt;&lt;br /&gt;&lt;br /&gt;&lt;br /&gt; &amp;lt;scr:component name="foo"&gt;              &lt;br /&gt;   &amp;lt;implementation class="com.acme.foo.FooImpl"/&gt;&lt;br /&gt;   &amp;lt;service&gt;&lt;br /&gt;     &amp;lt;provide interface="com.acme.foo.Foo"/&gt;&lt;br /&gt;   &amp;lt;/service&gt;&lt;br /&gt; &amp;lt;/scr:component&gt;&lt;br /&gt;&lt;br /&gt; &amp;lt;scr:component name="bar"&gt;              &lt;br /&gt;   &amp;lt;implementation class="com.acme.foo.BarImpl"/&gt;&lt;br /&gt;   &amp;lt;service&gt;&lt;br /&gt;     &amp;lt;provide interface="com.acme.bar.Bar"/&gt;&lt;br /&gt;   &amp;lt;/service&gt;&lt;br /&gt; &amp;lt;/scr:component&gt;&lt;br /&gt;&lt;br /&gt;&amp;lt;/c:components&gt;&lt;br /&gt;&lt;br /&gt;&lt;/pre&gt;&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/7836204352369514180-1439418686442330584?l=hwellmann.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://hwellmann.blogspot.com/feeds/1439418686442330584/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=7836204352369514180&amp;postID=1439418686442330584' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/7836204352369514180/posts/default/1439418686442330584'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/7836204352369514180/posts/default/1439418686442330584'/><link rel='alternate' type='text/html' href='http://hwellmann.blogspot.com/2009/04/getting-started-with-osgi-declarative.html' title='Getting Started with OSGi Declarative Services'/><author><name>Harald Wellmann</name><uri>http://www.blogger.com/profile/08039976160321882828</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='16' height='16' src='http://img2.blogblog.com/img/b16-rounded.gif'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-7836204352369514180.post-3767111364511144104</id><published>2009-04-01T16:50:00.005+02:00</published><updated>2009-04-02T18:50:26.109+02:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='OSGi'/><category scheme='http://www.blogger.com/atom/ns#' term='JDBC'/><title type='text'>JDBC Drivers in OSGi</title><content type='html'>How do you create a JDBC connection for a given JDBC URL in an OSGi application? In particular, how do you avoid an explicit dependency of your application code on a given driver?&lt;br /&gt;&lt;br /&gt;In a plain old classpath context, you would invoke &lt;code&gt;DriverManager.getConnection()&lt;/code&gt;, maybe after loading the driver class using &lt;code&gt;Class.forName()&lt;/code&gt;, if your driver does not support the Service Provider mechanism which is mandatory for JDBC 4.0.&lt;br /&gt;&lt;br /&gt;The trouble is, even if your driver does provide the &lt;code&gt;META-INF/services&lt;/code&gt; metadata, this does not work in OSGi, since DriverManager creates a number of class loader problems by using &lt;code&gt;Class.forName()&lt;/code&gt; internally.&lt;br /&gt;&lt;br /&gt;I'm working with a variant of the &lt;a href="http://www.zentus.com/sqlitejdbc/"&gt;Zentus driver&lt;/a&gt; for &lt;a href="http://www.blogger.com/www.sqlite.org"&gt;SQLite&lt;/a&gt;, which I've modified slightly to build an OSGi bundle under Java 1.6. I added the service metadata, and indeed my application code now works without loading the driver via &lt;code&gt;Class.forName()&lt;/code&gt; - as long as the code is running outside of OSGi.&lt;br /&gt;&lt;br /&gt;There are the following issues:&lt;br /&gt;&lt;ol&gt;&lt;li&gt;The context class loader of the current thread is used to scan for &lt;code&gt;META-INF/services&lt;/code&gt; resources and to load the referenced classes. This happens during initialization of DriverManager, so it will not catch resources from bundles which are not visible to the current context.&lt;br /&gt;&lt;/li&gt;&lt;br /&gt;&lt;li&gt;Additional drivers can register with DriverManager, they should do so in static initalization code, so that the driver gets registered when someone calls &lt;code&gt;Class.forName("my.own.Driver")&lt;/code&gt;.&lt;/li&gt;&lt;br /&gt;&lt;li&gt;&lt;code&gt;DriverManager.getConnection()&lt;/code&gt; iterates over the registered drivers until it finds one that can process the given URL. Unfortunately, it does a fatal double check to see if the class of that driver is the same that would be obtained by the caller. This amounts to calling &lt;code&gt;Class.forName("some.matching.Driver", ccl)&lt;/code&gt; where ccl is the caller's class loader.&lt;/li&gt;&lt;/ol&gt;(To get some information on what is happening, it is useful to call &lt;code&gt;DriverManager.setLogStream(System.out)&lt;/code&gt;.)&lt;br /&gt;&lt;br /&gt;The third point means that &lt;code&gt;DriverManager.getConnection()&lt;/code&gt; will always fail if the driver class is not visible to your bundle, so there really is no way to avoid a dependency.&lt;br /&gt;&lt;br /&gt;Here is an outline of a partial solution:&lt;br /&gt;&lt;ul&gt;&lt;li&gt;Create an OSGi bundle for each JDBC driver you want to use. Add a bundle activator that calls &lt;code&gt;Class.forName("some.jdbc.Driver")&lt;/code&gt;. This will register the driver with DriverManager when the bundle is started.&lt;/li&gt;&lt;li&gt;For each bundle that needs to create connections using &lt;code&gt;DriverManager.getConnection()&lt;/code&gt;, add optional dependencies on the JDBC drivers packages for all drivers that you are planning to use.&lt;/li&gt;&lt;/ul&gt;This is rather ugly, because you need to edit your client bundle manifest whenever you want to add support for an additional driver. But at least you can deploy your system with any subset of the defined drivers, maybe with just a single driver.&lt;br /&gt;&lt;br /&gt;If you do not need to support legacy code, do not bother using DriverManager and the Service Provider mechanism. After all, this is just a poor man's service registry, and you are much better off using the OSGi Service Registry.&lt;br /&gt;&lt;br /&gt;I'll give an example in one of my next posts.&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/7836204352369514180-3767111364511144104?l=hwellmann.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://hwellmann.blogspot.com/feeds/3767111364511144104/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=7836204352369514180&amp;postID=3767111364511144104' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/7836204352369514180/posts/default/3767111364511144104'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/7836204352369514180/posts/default/3767111364511144104'/><link rel='alternate' type='text/html' href='http://hwellmann.blogspot.com/2009/04/jdbc-drivers-in-osgi.html' title='JDBC Drivers in OSGi'/><author><name>Harald Wellmann</name><uri>http://www.blogger.com/profile/08039976160321882828</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='16' height='16' src='http://img2.blogblog.com/img/b16-rounded.gif'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-7836204352369514180.post-6485635702962031857</id><published>2009-03-29T19:46:00.007+02:00</published><updated>2009-03-29T20:11:03.835+02:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='Eclipse'/><category scheme='http://www.blogger.com/atom/ns#' term='Maven'/><title type='text'>Maven Plugin for Eclipse Source Bundles</title><content type='html'>The &lt;a href="http://maven.apache.org/plugins/maven-source-plugin/"&gt;Maven Source Plugin&lt;/a&gt; creates a JAR containing the sources of a project and attaches it to the main artifact of the project.&lt;br /&gt;&lt;br /&gt;It would be nice if you could directly use this JAR as source attachment for a bundle in your Eclipse target platform, but Eclipse 3.4 expects a special &lt;a href="http://help.eclipse.org/ganymede/index.jsp?topic=/org.eclipse.pde.doc.user/tasks/pde_individual_source.htm"&gt;Source Bundle&lt;/a&gt; format with specific headers in the manifest. There is a &lt;a href="http://jira.codehaus.org/browse/MSOURCES-41"&gt;feature request&lt;/a&gt; to support this directly in the Maven Source Plugin.&lt;br /&gt;&lt;br /&gt;To fill this gap, I had a look at the sources of the Maven Source and Archiver plugins and wrote my own &lt;a href="https://svn.berlios.de/svnroot/repos/datascript/trunk/maven-sourcebundle-plugin/"&gt;maven-sourcebundle-plugin&lt;/a&gt;. This plugin is available for public use as a subproject of the &lt;a href="http://developer.berlios.de/projects/datascript"&gt;DataScript&lt;/a&gt; project hosted at &lt;a href="http://developer.berlios.de/"&gt;BerliOS&lt;/a&gt;.&lt;br /&gt;&lt;br /&gt;There is no public Maven repository for this project yet, but it is contained in the latest binary release &lt;a href="http://prdownload.berlios.de/datascript/rds-bin-0.30.zip"&gt;rds-bin-0.30&lt;/a&gt;, or you can get the sources from Subversion.&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/7836204352369514180-6485635702962031857?l=hwellmann.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://hwellmann.blogspot.com/feeds/6485635702962031857/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=7836204352369514180&amp;postID=6485635702962031857' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/7836204352369514180/posts/default/6485635702962031857'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/7836204352369514180/posts/default/6485635702962031857'/><link rel='alternate' type='text/html' href='http://hwellmann.blogspot.com/2009/03/maven-plugin-for-eclipse-source-bundles.html' title='Maven Plugin for Eclipse Source Bundles'/><author><name>Harald Wellmann</name><uri>http://www.blogger.com/profile/08039976160321882828</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='16' height='16' src='http://img2.blogblog.com/img/b16-rounded.gif'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-7836204352369514180.post-7079142228564701970</id><published>2009-03-29T17:22:00.003+02:00</published><updated>2009-03-29T17:25:54.694+02:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='uDig'/><category scheme='http://www.blogger.com/atom/ns#' term='Java3D'/><title type='text'>3D Rendering in uDig</title><content type='html'>I've started experimenting with Java3D rendering in uDig. The goal is to use Java3D as a rendering engine first for plain old 2D data, and then for real 3D data in the next step.&lt;br /&gt;&lt;br /&gt;&lt;a href="http://udig.refractions.net/confluence/display/HACK/Java3D+Renderer"&gt;More details&lt;/a&gt; can be found in the uDig wiki.&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/7836204352369514180-7079142228564701970?l=hwellmann.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://hwellmann.blogspot.com/feeds/7079142228564701970/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=7836204352369514180&amp;postID=7079142228564701970' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/7836204352369514180/posts/default/7079142228564701970'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/7836204352369514180/posts/default/7079142228564701970'/><link rel='alternate' type='text/html' href='http://hwellmann.blogspot.com/2009/03/3d-rendering-in-udig.html' title='3D Rendering in uDig'/><author><name>Harald Wellmann</name><uri>http://www.blogger.com/profile/08039976160321882828</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='16' height='16' src='http://img2.blogblog.com/img/b16-rounded.gif'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-7836204352369514180.post-6279636315192496707</id><published>2009-03-25T20:49:00.006+01:00</published><updated>2009-03-25T21:48:38.606+01:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='Java3D'/><category scheme='http://www.blogger.com/atom/ns#' term='Eclipse'/><title type='text'>Java3D and Eclipse</title><content type='html'>The world is not flat, and 3D maps is one of the latest hypes in navigation systems. (Is anybody using them for real, I wonder....)&lt;br /&gt;&lt;br /&gt;So there is a need for me to deal with 3D city and terrain models in my applications, and of course the first thing you want is a 3D viewer. I started experimenting with Java3D a few months ago, and it felt such a relief compared to OpenGL programming in C. The only thing that gave me a hard time is the lack of documentation in some areas, but in the end I could answer most of my questions by studying the source code or by trial and error.&lt;br /&gt;&lt;br /&gt;At first, I wrote a couple of stand-alone viewers with a Canvas3D embedded in an AWT Frame, but what I really need is Java3D embedded in an Eclipse view or editor.&lt;br /&gt;&lt;br /&gt;I found a couple of postings on Java3D with SWT which sounded rather discouraging, but in the end it was rather straightforward. The &lt;a href="http://java3d-eclipse.sourceforge.net/"&gt;java3d-eclipse&lt;/a&gt; project on Sourceforge gave me some useful hints, but I cannot recommend using it, since the way that it re-bundles the Java3D JARs is definitely not OSGi-compliant.&lt;br /&gt;&lt;br /&gt;Now here is my own recipe:&lt;br /&gt;&lt;ul&gt;&lt;li&gt;Get the sources for Java3D 1.5.2 from &lt;a href="https://java3d.dev.java.net/"&gt;https://java3d.dev.java.net&lt;/a&gt;. There is no source package, you have to use CVS. You need three subprojects: j3d-core, j3d-core-utils and vecmath.&lt;br /&gt;&lt;/li&gt;&lt;li&gt;Compile vecmath into a stand-alone OSGi bundle.&lt;/li&gt;&lt;li&gt;Follow the Java3D build instructions to build j3d-core and j3d-utils in one go, including some native library compilation and Java code generation.&lt;/li&gt;&lt;li&gt;j3d-core and j3d-core-utils mutually depend on each other and cannot be compiled separately, so I really don't understand why Sun created two libraries instead of one. Anyway, to be friendly to Maven and OSGi, I copied the original sources, the generated sources and the native library binaries to just one Maven project, created a POM and built my Java3D OSGi bundle using the &lt;a href="http://felix.apache.org/site/apache-felix-maven-bundle-plugin-bnd.html"&gt;maven-bundle-plugin&lt;/a&gt;.&lt;/li&gt;&lt;li&gt;I did this both for Windows and Linux and managed to launch the HelloUniverse demo from Equinox.&lt;/li&gt;&lt;li&gt;For cross-platform use,  move the platform specific code (both the native libs and a handful of Java classes) to separate projects and build OSGi fragments for these, similar to SWT.&lt;/li&gt;&lt;/ul&gt;After these preparations, embedding a Canvas3D into an Eclipse view or editor is as easy as this:&lt;br /&gt;&lt;pre&gt;&lt;br /&gt;public void createPartControl(Composite parent)&lt;br /&gt;{&lt;br /&gt;   awtContainer = new Composite(parent, SWT.EMBEDDED);&lt;br /&gt;&lt;br /&gt;   Frame frame = SWT_AWT.new_Frame(awtContainer);&lt;br /&gt;   frame.setLayout(new BorderLayout());&lt;br /&gt;&lt;br /&gt;   GraphicsConfiguration config = SimpleUniverse&lt;br /&gt;       .getPreferredConfiguration();&lt;br /&gt;&lt;br /&gt;   Canvas3D canvas = new Canvas3D(config);&lt;br /&gt;&lt;br /&gt;   createUniverse(canvas);&lt;br /&gt;   frame.add(canvas, BorderLayout.CENTER);&lt;br /&gt;}&lt;br /&gt;&lt;br /&gt;&lt;/pre&gt;&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/7836204352369514180-6279636315192496707?l=hwellmann.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://hwellmann.blogspot.com/feeds/6279636315192496707/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=7836204352369514180&amp;postID=6279636315192496707' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/7836204352369514180/posts/default/6279636315192496707'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/7836204352369514180/posts/default/6279636315192496707'/><link rel='alternate' type='text/html' href='http://hwellmann.blogspot.com/2009/03/java3d-and-eclipse.html' title='Java3D and Eclipse'/><author><name>Harald Wellmann</name><uri>http://www.blogger.com/profile/08039976160321882828</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='16' height='16' src='http://img2.blogblog.com/img/b16-rounded.gif'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-7836204352369514180.post-8989396480274896638</id><published>2009-03-19T19:57:00.002+01:00</published><updated>2009-03-19T20:10:07.851+01:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='OSGi'/><category scheme='http://www.blogger.com/atom/ns#' term='Anaconda'/><category scheme='http://www.blogger.com/atom/ns#' term='Eclipse'/><title type='text'>Anaconda: A New Architecture for Compiling Navigation Databases</title><content type='html'>In my previous post, I presented the &lt;span style="font-weight: bold;"&gt;Anaconda Workbench&lt;/span&gt;, without explaining about &lt;span style="font-weight: bold;"&gt;Anaconda&lt;/span&gt;. This is the code name for my current project, a Map Compiler for processing map data into a compact binary database for car navigation systems of &lt;a href="http://www.harmanbecker.com"&gt;Harman/Becker&lt;/a&gt;.&lt;br /&gt;&lt;br /&gt;I gave a talk about Anaconda at the &lt;a href="http://wiki.eclipse.org/Eclipse_DemoCamps_November_2008/Hamburg"&gt;Eclipse Demo Camp&lt;/a&gt; in Hamburg in November last year. The &lt;a href="http://wiki.eclipse.org/images/f/fd/EuropeOnADisk.pdf"&gt;slides&lt;/a&gt; of this talk explain the purpose of a Map Compiler and our usage of OSGi and Eclipse and lots of other fabulous Open Source components.&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/7836204352369514180-8989396480274896638?l=hwellmann.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://hwellmann.blogspot.com/feeds/8989396480274896638/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=7836204352369514180&amp;postID=8989396480274896638' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/7836204352369514180/posts/default/8989396480274896638'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/7836204352369514180/posts/default/8989396480274896638'/><link rel='alternate' type='text/html' href='http://hwellmann.blogspot.com/2009/03/anaconda-new-architecture-for-compiling.html' title='Anaconda: A New Architecture for Compiling Navigation Databases'/><author><name>Harald Wellmann</name><uri>http://www.blogger.com/profile/08039976160321882828</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='16' height='16' src='http://img2.blogblog.com/img/b16-rounded.gif'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-7836204352369514180.post-3214718995572986338</id><published>2009-03-18T11:01:00.010+01:00</published><updated>2010-02-19T12:15:20.679+01:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='uDig'/><category scheme='http://www.blogger.com/atom/ns#' term='NDS'/><category scheme='http://www.blogger.com/atom/ns#' term='Anaconda'/><category scheme='http://www.blogger.com/atom/ns#' term='Geotools'/><title type='text'>Anaconda Workbench: A uDig Application</title><content type='html'>Now here is a glimpse at what we are using &lt;a href="http://udig.refractions.net/"&gt;uDig &lt;/a&gt;for. I think all the digging in the internals of several Open Source projects is now beginning to pay off.&lt;br /&gt;&lt;br /&gt;The &lt;span style="font-weight: bold;"&gt;Anaconda Workbench&lt;/span&gt; is an application for viewing and testing car navigation databases in the forthcoming &lt;a href="http://www.psf-initiative.com/"&gt;Navigation Data Standard&lt;/a&gt; format (NDS). (This is a closed source project of &lt;a href="http://www.harmanbecker.com/"&gt;Harman/Becker&lt;/a&gt;, so I cannot offer more than some general information here.)&lt;br /&gt;&lt;br /&gt;We implemented a Geotools extension for the NDS format, and a corresponding uDig catalog plug-in. This was enough to build an NDS map viewer. The map has multiple levels of detail in separate layers. We use SLD for styling the layers and for activating the appropriate layer depending on the current map scale.&lt;br /&gt;&lt;br /&gt;On top of the map viewer functionality, there is a name browser which allows you to select road names and display the road on the map or use it as a start or destination for a route.&lt;br /&gt;&lt;br /&gt;There is also a route calculator plug-in which finds the shortest route between two points and highlights the route in a separate layer.&lt;br /&gt;&lt;br /&gt;More functionality will be added step by step. In the end, the Anaconda Workbench shall become a front-end for our map compilation process and not just a viewer for the compiled map databases.&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/7836204352369514180-3214718995572986338?l=hwellmann.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://hwellmann.blogspot.com/feeds/3214718995572986338/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=7836204352369514180&amp;postID=3214718995572986338' title='4 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/7836204352369514180/posts/default/3214718995572986338'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/7836204352369514180/posts/default/3214718995572986338'/><link rel='alternate' type='text/html' href='http://hwellmann.blogspot.com/2009/03/anaconda-workbench-udig-application.html' title='Anaconda Workbench: A uDig Application'/><author><name>Harald Wellmann</name><uri>http://www.blogger.com/profile/08039976160321882828</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='16' height='16' src='http://img2.blogblog.com/img/b16-rounded.gif'/></author><thr:total>4</thr:total></entry><entry><id>tag:blogger.com,1999:blog-7836204352369514180.post-8341291190872930613</id><published>2009-03-18T10:49:00.006+01:00</published><updated>2009-03-29T21:38:27.730+02:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='uDig'/><category scheme='http://www.blogger.com/atom/ns#' term='GeoAPI'/><category scheme='http://www.blogger.com/atom/ns#' term='Geotools'/><title type='text'>udigLite: An OSGi-friendly subset of uDig</title><content type='html'>At long last, my team and I have succeeded in creating a subset of &lt;a href="http://udig.refractions.net/"&gt;uDig &lt;/a&gt;which suits our environment. The baby is called udigLite, and the first &lt;a href="http://developer.berlios.de/projects/udig-osgi/"&gt;binary releases&lt;/a&gt; can be downloaded from BerliOS, the site also hosting our Mercurial clones of the original Subversion source repositories.&lt;br /&gt;&lt;br /&gt;Read the &lt;a href="http://udig.refractions.net/confluence/display/HACK/udigLite+-+An+OSGi-friendly+subset"&gt;whole story&lt;/a&gt; in the uDig wiki.&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/7836204352369514180-8341291190872930613?l=hwellmann.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://hwellmann.blogspot.com/feeds/8341291190872930613/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=7836204352369514180&amp;postID=8341291190872930613' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/7836204352369514180/posts/default/8341291190872930613'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/7836204352369514180/posts/default/8341291190872930613'/><link rel='alternate' type='text/html' href='http://hwellmann.blogspot.com/2009/03/udiglite-osgi-friendly-subset-of-udig.html' title='udigLite: An OSGi-friendly subset of uDig'/><author><name>Harald Wellmann</name><uri>http://www.blogger.com/profile/08039976160321882828</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='16' height='16' src='http://img2.blogblog.com/img/b16-rounded.gif'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-7836204352369514180.post-2322882952690209015</id><published>2008-11-08T11:55:00.003+01:00</published><updated>2008-11-08T18:15:36.883+01:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='uDig'/><category scheme='http://www.blogger.com/atom/ns#' term='Java'/><category scheme='http://www.blogger.com/atom/ns#' term='GIS'/><category scheme='http://www.blogger.com/atom/ns#' term='JUMP'/><category scheme='http://www.blogger.com/atom/ns#' term='JTS'/><category scheme='http://www.blogger.com/atom/ns#' term='Eclipse'/><category scheme='http://www.blogger.com/atom/ns#' term='GeoAPI'/><category scheme='http://www.blogger.com/atom/ns#' term='Geotools'/><title type='text'>The Digital World</title><content type='html'>Digital maps and geographical databases have come to be a commonplace commodity. To locate a friend's address, you simple open &lt;a href="http://maps.google.com/"&gt;Google Maps&lt;/a&gt;, when you go to their place by car, your nav system will guide you, and if you feel challenged by the patent folding of your Falk city map, you can download a map on your mobile phone to cover the last mile to your friend's home.&lt;br /&gt;&lt;br /&gt;The raw geographical data for such services are supplied by companies like &lt;a href="http://www.navteq.com/"&gt;NAVTEQ&lt;/a&gt; and &lt;a href="http://www.teleatlas.com/"&gt;Tele Atlas&lt;/a&gt;, but it takes a lot of additional data processing to build user-friendly services based on these data.&lt;br /&gt;&lt;br /&gt;My daytime work is dedicated to the design and development of a map compiler for &lt;a href="http://www.harmanbecker.com/"&gt;Harman/Becker&lt;/a&gt;, which will produce the map databases for the next generation of car navigation systems to hit the market within a few years from now.&lt;br /&gt;&lt;br /&gt;Doing this job in Java does not sound natural to everyone, but for us, the choice of Java has been the key to building our work on top of a whole lot of ready-to-use components and libraries, both for general purpose and domain specific tasks. So it is really Java and all these excellent open source components that help us getting &lt;span style="font-style: italic;"&gt;around the world&lt;/span&gt;.&lt;br /&gt;&lt;br /&gt;Let me just mention some of the Java libraries or applications that are useful for dealing with geographical data. I will cover some of them in more detail in future posts.&lt;br /&gt;&lt;br /&gt;The best thing about geo data is that you can have a look at them - if you have some viewer tool that renders a map for you. A couple of years ago, I was searching for a Java-based alternative to the home-grown tools we use at work, and I came across &lt;a href="http://www.jump-project.org/"&gt;JUMP&lt;/a&gt;. This gave me a jump start into geo data processing in Java...&lt;br /&gt;&lt;br /&gt;JUMP is a map viewer and editor for a number of open standard data formats, and it has "plug-in" interfaces for supporting alternative data formats, which was a key requirement for me.  I put the word "plug-in" in quotes, because JUMP has absolutely nothing to do with Eclipse plug-ins or extension points or OSGi bundles. JUMP does its own bit of class loader magic to use extension classes from JAR files you drop into a given folder.&lt;br /&gt;&lt;br /&gt;I found JUMP easy to use and fairly easy to extend. Some people complained to me about its bland and somewhat out-dated GUI, but that has never really bothered me. JUMP is a solid and mature piece of work, and the major downside I see is the fact that it is no longer under active development. There are now more flexible extension mechanisms, and some of the features I would like to extend or modify are simply not laid open, so I would have to modify the sources.&lt;br /&gt;&lt;br /&gt;Actually, Mama JUMP may have retired, but her offspring is alive and kicking: There is a whole family of &lt;a href="http://openjump.org/wiki/show/OpenJUMPs+Family"&gt;JUMP spin-off projects&lt;/a&gt;.&lt;br /&gt;&lt;br /&gt;JUMP introduced me to the &lt;a href="http://tsusiatsoftware.net/jts/main.html"&gt;JTS Topology Suite&lt;/a&gt; which it uses for all operations on two-dimensional geometrical shapes. I found JTS to be extremely useful and well-designed, it is based on solid mathematical background and suceeds in hiding the most of the maths from the average user who just needs to get his job done, and it has a rather interesting &lt;a href="http://tsusiatsoftware.net/jts/jts-history.html"&gt;history&lt;/a&gt;.&lt;br /&gt;&lt;br /&gt;JTS has an LPGL license, whereas JUMP is under GPL. This may be too restrictive for some commercial applications, and when I wrote to &lt;span style="text-decoration: underline;"&gt;&lt;/span&gt;&lt;a href="http://www.vividsolutions.com/"&gt;Vivid Solutions&lt;/a&gt;, the company behind both JUMP and JTS, about this licensing issue, they pointed me to &lt;a href="http://udig.refractions.net/"&gt;uDig&lt;/a&gt; as an LGPLed alternative.&lt;br /&gt;&lt;br /&gt;That must have been some time in 2005. My first encounter with uDig was not very successful: I did see the power of its architecture, built on top of &lt;a href="http://wiki.eclipse.org/Rich_Client_Platform"&gt;Eclipse RCP&lt;/a&gt;, but at that time, I was simply overwhelmed by all the prerequisites you had to understand to implement as much as a Hello World plug-in in uDig. And back then, I knew little or nothing about Eclipse plug-in development, so I concluded that uDig was not (yet) for me, but I kept watching its progress.&lt;br /&gt;&lt;br /&gt;In the meantime, uDig has grown a lot in terms of functionality, stability and documentation, whereas my own knowledge of OSGi and Eclipse technologies has increased. Getting started with uDig extensions is still rather a challenge,  but my efforts have started paying off. With support from the developer mailing list, my uDig plug-ins have grown to a level of functionality almost equivalent to my JUMP extensions, so I am planning to stop working with JUMP and use uDig as a more flexible, powerful and (hopefully) future-proof platform.&lt;br /&gt;&lt;br /&gt;The abstractions of cartographic features and datastores used by uDig are based on &lt;a href="http://geotools.codehaus.org/"&gt;Geotools&lt;/a&gt;, another open source project providing a set of Java libraries for processing a vast number of geospatial data formats, including plain files, databases or web services.  Both Geotools and uDig use JTS for geometrical operations.&lt;br /&gt;&lt;br /&gt;All these projects directly or indirectly rely on &lt;a href="http://www.opengeospatial.org/"&gt;OpenGIS &lt;/a&gt;standards and specifications, in particular, the Simple Features Specification. Geotools provides implementations of the OpenGIS Java interfaces published by the &lt;a href="http://geoapi.sourceforge.net/"&gt;GeoAPI&lt;/a&gt; project.&lt;br /&gt;&lt;br /&gt;To sum up, for geospatial data processing, there is a wealth of open source Java libraries based on open standards. For any Java-based development in this area, one of these projects may save you some work.&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/7836204352369514180-2322882952690209015?l=hwellmann.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://hwellmann.blogspot.com/feeds/2322882952690209015/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=7836204352369514180&amp;postID=2322882952690209015' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/7836204352369514180/posts/default/2322882952690209015'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/7836204352369514180/posts/default/2322882952690209015'/><link rel='alternate' type='text/html' href='http://hwellmann.blogspot.com/2008/11/digital-world.html' title='The Digital World'/><author><name>Harald Wellmann</name><uri>http://www.blogger.com/profile/08039976160321882828</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='16' height='16' src='http://img2.blogblog.com/img/b16-rounded.gif'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-7836204352369514180.post-2511610459176822431</id><published>2008-11-06T22:10:00.004+01:00</published><updated>2008-11-06T22:34:45.528+01:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='OSGi'/><category scheme='http://www.blogger.com/atom/ns#' term='Hibernate'/><title type='text'>Hibernate and OSGi: An elaborate solution</title><content type='html'>A much cleaner and flexible way of osgifying a plain old JAR with lots of dependencies is adding the required OSGi headers to each JAR, so you will replace the megabundle with a bunch of small bundles, one per JAR, which you can reuse in other contexts.&lt;br /&gt;&lt;br /&gt;In an ideal OSGi world, every JAR would be an OSGi bundle, so you would have nothing to worry about. Unfortunately, most Java libraries still come as plain old JARs and you have to add the headers on your own.&lt;br /&gt;&lt;br /&gt;If you are lucky, someone has done the job for you already. There are a number of third-party repositories offering osgified versions of popular Java libraries, e.g. the &lt;a href="http://www.osgi.org/Repository/HomePage"&gt;OSGi bundle repository&lt;/a&gt; or the &lt;a href="http://www.osgi.org/Repository/HomePage"&gt;SpringSource Enterprise Bundle Repository&lt;/a&gt;.&lt;br /&gt;&lt;br /&gt;SpringSource even has an OSGi bundle of Hibernate itself. However, their version does not work, at any rate not in my setup, so I had to build my own Hibernate bundle.&lt;br /&gt;&lt;br /&gt;At least, I was able to use the SpringSource OSGi version for each dependency of Hibernate.&lt;br /&gt;&lt;br /&gt;These are the problems I had with the SpringSource version of Hibernate (3.2.6.ga):&lt;br /&gt;&lt;br /&gt;&lt;ul&gt;&lt;li&gt;The &lt;span style="font-family:courier new;"&gt;javax.transaction&lt;/span&gt; package does not resolve. It is imported with a specific version range. However, in Java 1.6.0, this package is contained in the JRE and comes from there without a version. I had to drop the version directive to make Hibernate use the &lt;span style="font-family:courier new;"&gt;javax.transaction&lt;/span&gt; package from the JRE.&lt;/li&gt;&lt;li&gt;I got an exception on running a HQL query, since ANTLR could not load the Hibernate token class.&lt;/li&gt;&lt;li&gt;I had a very mysterious &lt;span style="font-family:courier new;"&gt;ClassNotFoundException &lt;/span&gt;when accessing some of my model classes. As it turned out, the reason was my usage of lazy loading, where Hibernate injects CGLIB proxy classes into my model classes. The exception was due to the fact that my model bundle did not have access to the CGLIB classes. Rather than declaring a dependency on CGLIB for each of my model bundles, I added the following header to my Hibernate manifest:&lt;/li&gt;&lt;/ul&gt;&lt;br /&gt;&lt;span style="font-family:courier new;"&gt;Require-Bundle: com.springsource.net.sf.cglib;visibility:=reexport&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;This means that every bundle with a dependency on Hibernate automatically inherits the dependency on CGLIB. Even St. Peter the Evangelist who usually preaches about using &lt;span style="font-family:courier new;"&gt;Import-Package&lt;/span&gt; instead of &lt;span style="font-family:courier new;"&gt;Require-Bundle&lt;/span&gt; &lt;a href="http://www.osgi.org/blog/2007/07/to-declare-or-not-to-declare.html"&gt;admits this to be one of the rare cases&lt;/a&gt; where the latter has its merits.&lt;br /&gt;&lt;br /&gt;So far, with this approach, we have not used any Equinox buddy policies, but we still need to deal with the application model classes and resources.&lt;br /&gt;&lt;br /&gt;For a while, I thought a fragment bundle would be the definitive solution, which would work not only on Equinox.&lt;br /&gt;&lt;br /&gt;I created a bundle &lt;span style="font-family:courier new;"&gt;com.acme.myapp.hibernate.fragment&lt;/span&gt;, containing no Java classes, but only a manifest and some resources, i.e. the Hibernate configuration file and all my Hibernate mapping files. I added all model packages and all relevant JDBC driver packages to the &lt;span style="font-family:courier new;"&gt;Import-Package&lt;/span&gt; header (using &lt;span style="font-family:courier new;"&gt;resolution:= optional&lt;/span&gt; for the JDBC packages.) The host for this fragment is the &lt;span style="font-family:courier new;"&gt;org.hibernate.osgi&lt;/span&gt; bundle, of course.&lt;br /&gt;&lt;br /&gt;This worked perfectly when launching my application from within the Eclipse IDE. However, I had an unpleasant surprise when running our batch builds which are based on the Eclipse PDE Ant runner.&lt;br /&gt;&lt;br /&gt;PDE kept complaining about cyclic dependencies in my bundles. And not even in my own bundles, also between some of the third-party libraries used by Hibernate, in particular between jaxen and dom4j.&lt;br /&gt;&lt;br /&gt;(I had a look at the sources of these two libraries to understand what was going on here: each of them contains some helper classes for the other one, and each must have been compiled against an older version of its friend - really scary...)&lt;br /&gt;&lt;br /&gt;I had already spent half a day in working around this problem by repackaging each cycle of libraries in one bundle, and I was going to file an Eclipse bug report. When searching for similar issues, I found &lt;a href="https://bugs.eclipse.org/bugs/show_bug.cgi?id=208011"&gt;bug 208011&lt;/a&gt; which not only describes the problem, but also offers a partial solution:&lt;br /&gt;&lt;br /&gt;&lt;span style="font-family:courier new;"&gt;allowBinaryCycles = true&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;is a property you can set in your top-level &lt;span style="font-family:courier new;"&gt;build.properties&lt;/span&gt; file as of Eclipse 3.4. (Not a word about this in the Eclipse Online Help, and not even in the comments of the batch build template files!)&lt;br /&gt;&lt;br /&gt;&lt;a href="http://code9.com/2008/10/28/tip-pde-build-and-binary-cycles/"&gt;According to Chris Aniszczyk&lt;/a&gt;, this option will be accessible from the IDE UI in Eclipse 3.5M3.&lt;br /&gt;&lt;br /&gt;&lt;span style="font-family:courier new;"&gt;allowBinaryCycles &lt;/span&gt;did suppress the error message regarding the dom4j-jaxen cycle.&lt;br /&gt;&lt;br /&gt;But alas, now I had another error complaining about a cycle between Hibernate, my hibernate fragment and my model bundles. Apparently, Eclipse regards the fragment as part of its host (which is ok), and since the fragment depends on an application bundle, and the application bundle depends on Hibernate, so the PDE batch build now complains about a cycle between Hibernate and my application bundle.&lt;br /&gt;&lt;br /&gt;So for now, I left all the resources and the JDBC dependencies in the Hibernate fragment, but reverted to using buddy declarations in Hibernate and my model bundles to break the dependency cycle.&lt;br /&gt;&lt;br /&gt;I also created a fragment &lt;span style="font-family:courier new;"&gt;com.acme.myapp.antlr.fragment&lt;/span&gt; which imports &lt;span style="font-family:courier new;"&gt;org.hibernate.hql.ast.HqlToken&lt;/span&gt; and thus make the custom token class of Hibernate visible to ANTLR. (See the &lt;a href="https://issuetracker.springsource.com/browse/BRITS-167"&gt;SpringSource bug report&lt;/a&gt;.)&lt;br /&gt;&lt;br /&gt;All in all, this looks 95 % clean to me, so I think I'm going to leave it at that for a while...&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/7836204352369514180-2511610459176822431?l=hwellmann.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://hwellmann.blogspot.com/feeds/2511610459176822431/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=7836204352369514180&amp;postID=2511610459176822431' title='1 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/7836204352369514180/posts/default/2511610459176822431'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/7836204352369514180/posts/default/2511610459176822431'/><link rel='alternate' type='text/html' href='http://hwellmann.blogspot.com/2008/11/hibernate-and-osgi-elaborate-solution.html' title='Hibernate and OSGi: An elaborate solution'/><author><name>Harald Wellmann</name><uri>http://www.blogger.com/profile/08039976160321882828</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='16' height='16' src='http://img2.blogblog.com/img/b16-rounded.gif'/></author><thr:total>1</thr:total></entry><entry><id>tag:blogger.com,1999:blog-7836204352369514180.post-4291662126316096813</id><published>2008-11-06T21:59:00.005+01:00</published><updated>2008-11-06T22:34:13.285+01:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='OSGi'/><category scheme='http://www.blogger.com/atom/ns#' term='Hibernate'/><title type='text'>Hibernate and OSGi: A pragmatic solution</title><content type='html'>The simplest thing you can do to turn a plain old JAR with a number of external dependencies into an OSGi bundle is wrapping this JAR and all its dependencies in another JAR and adding an OSGi manifest with all dependencies on the bundle classpath.&lt;br /&gt;&lt;br /&gt;For example:&lt;br /&gt;&lt;pre&gt;Bundle-SymbolicName: org.hibernate.osgi&lt;br /&gt;Bundle-ClassPath: hibernate3.jar,&lt;br /&gt;lib/antlr.jar,&lt;br /&gt;lib/cglib.jar,&lt;br /&gt;lib/commons-logging.jar,&lt;br /&gt;...&lt;br /&gt;Export-Package: org.hibernate,&lt;br /&gt;org.hibernate.configuration,&lt;br /&gt;...&lt;br /&gt;&lt;/pre&gt;With this megabundle, you can trivially solve all classpath or visibility issues between Hibernate and its dependencies.&lt;br /&gt;&lt;br /&gt;You still have to do something to make the model classes of your application and the mapping files accessible to Hibernate.&lt;br /&gt;&lt;br /&gt;Eclipse Equinox has an extension of the OSGi standard called buddy policies, which enables you to define some kind of classloader callback.&lt;br /&gt;&lt;br /&gt;Your application depends on Hibernate, but you do not want Hibernate to depend on your application. Even if you wrap your own Hibernate bundle, you want to be able to use it in more than one of your applications.&lt;br /&gt;&lt;br /&gt;There are several flavours of buddy policies, I will just mention one of them: Adding the header&lt;br /&gt;&lt;pre&gt;Eclipse-BuddyPolicy: registered&lt;br /&gt;&lt;/pre&gt;to your Hibernate bundle manifest will tell Hibernate to ask all its buddies for classes it cannot load using its own classloader.&lt;br /&gt;&lt;br /&gt;In each bundle of your application containing some Hibernate model classes, you then add a dependency on Hibernate and a header telling Hibernate that your bundle is a buddy:&lt;br /&gt;&lt;pre&gt;Eclipse-RegisterBuddy: org.hibernate.osgi&lt;br /&gt;Require-Bundle: org.hibernate.osgi&lt;br /&gt;&lt;/pre&gt;(The buddy thing does not work unless there is an actual dependency by &lt;span style="font-family:courier new;"&gt;Require-Bundle&lt;/span&gt; or &lt;span style="font-family:courier new;"&gt;Import-Package&lt;/span&gt;.) This will enable Hibernate to load classes and resources from your bundle, so it will also be able to locate your Hibernate mapping files if you put them into your bundle next to the model classes. Make sure to define your mappings in terms of resources, not files.&lt;br /&gt;&lt;br /&gt;You can use the same approach for your JDBC drivers. More likely than not, your JDBC JAR does not come with an OSGi manifest, so you have to wrap it in a bundle anyway. Add a dependency on Hibernate and make your JDBC bundle a buddy of Hibernate. Logically, this is upside-down, but it has the advantage that you can exchange your JDBC drivers without changing the Hibernate bundle.&lt;br /&gt;&lt;br /&gt;Alternatively, you can add optional dependencies to the Hibernate manifest on any JDBC driver you are planning to use, e.g.&lt;br /&gt;&lt;pre&gt;Require-Bundle: com.microsoft.sqljdbc;resolution:=optional,&lt;br /&gt;org.postgresql;resolution:=optional&lt;br /&gt;&lt;/pre&gt;Of course, this solution is a nightmare to any OSGi purist, but it does work and it is easy to set up.&lt;br /&gt;&lt;br /&gt;There are the following major drawbacks:&lt;br /&gt;&lt;ul&gt;&lt;li&gt;You are bound to Equinox. Other OSGi implementations do not have a buddy policy equivalent. To my best knowledge, you would have to resort to &lt;span style="font-family:courier new;"&gt;DynamicImport-Package&lt;/span&gt; which opens the gates much wider.&lt;/li&gt;&lt;li&gt;The megabundle approach does not scale. It will be okay if Hibernate is the only component in your system you treat this way. If you have three or four of such heavyweight components you will end up wrapping general purpose JARs like &lt;span style="font-family:courier new;"&gt;commons-logging.jar&lt;/span&gt; over and over again.&lt;/li&gt;&lt;li&gt;And you will be in real trouble if some of the wrapped third-party dependencies occur in more than one megabundle and are used on the API of your components. With multiple copies of the same JAR in different bundles, and each bundle having its own classloader, you will end up with class cast or assignment exceptions, because classes loaded via different class loaders are always incompatible, even if they have the same fully qualified name.&lt;/li&gt;&lt;/ul&gt;&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/7836204352369514180-4291662126316096813?l=hwellmann.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://hwellmann.blogspot.com/feeds/4291662126316096813/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=7836204352369514180&amp;postID=4291662126316096813' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/7836204352369514180/posts/default/4291662126316096813'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/7836204352369514180/posts/default/4291662126316096813'/><link rel='alternate' type='text/html' href='http://hwellmann.blogspot.com/2008/11/hibernate-and-osgi-pragmatic-solution.html' title='Hibernate and OSGi: A pragmatic solution'/><author><name>Harald Wellmann</name><uri>http://www.blogger.com/profile/08039976160321882828</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='16' height='16' src='http://img2.blogblog.com/img/b16-rounded.gif'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-7836204352369514180.post-8899803651838780886</id><published>2008-11-05T20:40:00.005+01:00</published><updated>2008-11-06T22:33:32.586+01:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='OSGi'/><category scheme='http://www.blogger.com/atom/ns#' term='Hibernate'/><title type='text'>Hibernate and OSGi: The problem</title><content type='html'>Making Hibernate work in an OSGi environment is not trivial. Over the last couple of months, I have been experimenting with various approaches, and I'm not yet fully satisfied with the solutions I have found.&lt;br /&gt;&lt;br /&gt;The funny thing is, there must be a whole bunch of people facing the same problem, and you do find a couple of postings or example code with the help of your favourite search engine, however, none of the articles or examples seem to match my environment or my requirements.&lt;br /&gt;&lt;br /&gt;Now here is an outline of my approaches, which may or may not work for you. Take a look and give me some feedback.&lt;br /&gt;&lt;br /&gt;Before talking about the solutions, we all know the answer is 42, but we haven't really worked out the question yet, so let me first list the issues you have to deal with:&lt;br /&gt;&lt;ul&gt;&lt;li&gt;Hibernate has a lot of third-party dependencies.&lt;/li&gt;&lt;li&gt;When you use an XML configuration file for your session factory, Hibernate must be able to load ist.&lt;/li&gt;&lt;li&gt;Hibernate needs to load your JDBC driver classes.&lt;br /&gt;&lt;/li&gt;&lt;li&gt;When using Hibernate mapping files for your entity classes, Hibernate needs to be able to load them as resources.&lt;/li&gt;&lt;li&gt;While processing the mapping files, Hibernate reads the names of your entity classes and loads them using &lt;span style="font-family:courier new;"&gt;Class.forName()&lt;/span&gt;.&lt;/li&gt;&lt;li&gt;Hibernate internally uses ANTLR to parse HQL queries, and it passes a custom token class to ANTLR. Unfortunately, ANTLR requires you to specify this class by name and uses Class.forName() load the custom token class.&lt;/li&gt;&lt;li&gt;When using lazy loading with the CGLIB proxy generator, Hibernate injects a dependency on CGLIB into your model classes. Thus, any bundle using you model classes may have to load CGLIB classes.&lt;/li&gt;&lt;/ul&gt;There may be more issues, depending on the way you work with Hibernate. In my project environment, some issues mentioned by other people simply do not occur, while others lead to new problems.&lt;br /&gt;&lt;ul&gt;&lt;li&gt;We do not use Hibernate annotations.&lt;/li&gt;&lt;li&gt;Our OSGi configuration is static. All bundles are installed and started during the framework startup phase, registering all services. We do not have to worry about adding new classes to the session factory when a bundle gets installed at run-time. (For this reason, the &lt;a href="http://www.osgi.org/blog/2007/06/osgi-and-hibernate.html"&gt;extender pattern&lt;/a&gt; approach is a bit too heavyweight for my taste.)&lt;/li&gt;&lt;li&gt;We do not use a web container, or Spring, or anything else, just naked OSGi - well, Eclipse Equinox, in fact.&lt;/li&gt;&lt;li&gt;Our IDE is Eclipse and we want to be able to launch our OSGi application including Hibernate from Eclipse.&lt;/li&gt;&lt;li&gt;We also use Eclipse PDE batch builds.&lt;br /&gt;&lt;/li&gt;&lt;/ul&gt;Having described to problem in some detail,  I will explain a pragmatic and a more elaborate solution in separate articles.&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/7836204352369514180-8899803651838780886?l=hwellmann.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://hwellmann.blogspot.com/feeds/8899803651838780886/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=7836204352369514180&amp;postID=8899803651838780886' title='1 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/7836204352369514180/posts/default/8899803651838780886'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/7836204352369514180/posts/default/8899803651838780886'/><link rel='alternate' type='text/html' href='http://hwellmann.blogspot.com/2008/11/hibernate-and-osgi-problem.html' title='Hibernate and OSGi: The problem'/><author><name>Harald Wellmann</name><uri>http://www.blogger.com/profile/08039976160321882828</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='16' height='16' src='http://img2.blogblog.com/img/b16-rounded.gif'/></author><thr:total>1</thr:total></entry><entry><id>tag:blogger.com,1999:blog-7836204352369514180.post-4907138811919492405</id><published>2008-11-03T22:00:00.003+01:00</published><updated>2008-11-03T22:56:23.181+01:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='OSGi'/><category scheme='http://www.blogger.com/atom/ns#' term='Java'/><category scheme='http://www.blogger.com/atom/ns#' term='Eclipse'/><category scheme='http://www.blogger.com/atom/ns#' term='Dependencies'/><title type='text'>Why I use OSGi</title><content type='html'>I want &lt;span style="font-weight: bold;"&gt;modules &lt;/span&gt;and &lt;span style="font-weight: bold;"&gt;controlled dependencies&lt;/span&gt; in my Java applications. OSGi gives me both, that's why I use it.&lt;br /&gt;&lt;br /&gt;It's as simple as that. Really.&lt;br /&gt;&lt;br /&gt;Yes, OSGi gives you a lot more into the bargain, most notably &lt;span style="font-weight: bold;"&gt;services&lt;/span&gt;, which I also use, but the unique selling point for me is modules.&lt;br /&gt;&lt;br /&gt;When you look at the sources and binaries of any software system  (not only in Java), preferably one you haven't written yourself, you see a lot of files in a directory structure. Usually, the directory structure reflects the system architecture, subdirectories corresponding to subsystems or components.&lt;br /&gt;&lt;br /&gt;Some of these directories correspond to binary artifacts (JARs, DLLs, whatever) which you may want to reuse independently or in another system.&lt;br /&gt;&lt;br /&gt;Now when you start pulling out this library, you have to satisfy all its runtime dependencies. So you need to take a bunch of other libraries for this library to work. Identifying the dependencies may be a tedious trial-and-error process.&lt;br /&gt;&lt;br /&gt;There may be additional compile-time dependencies you cannot recognize by looking at the binaries only. In C/C++, there is often some &lt;span style="font-family:courier new;"&gt;global.h&lt;/span&gt; directly or indirectly included by every source file in your system.&lt;br /&gt;&lt;br /&gt;Even if there was some clever architect who designed the system in terms of components and allowed dependencies, there is usually no guarantee that this architecture will be adhered to, because nothing ever prevents a developer from including or importing something they are not supposed to use.&lt;br /&gt;&lt;br /&gt;Java has packages and classes with visibility levels, but classes and even packages are rather too fine-grained from an architect's perspective.  I want my modules to be larger than packages, and I want to use them as &lt;span style="font-weight: bold;"&gt;configuration units&lt;/span&gt;. The modules should be in one-to-one correspondence to libraries or JARs.&lt;br /&gt;&lt;br /&gt;This is just what OSGi provides. A plain old JAR is turned into an OSGi bundle (that's what modules are called in OSGi-land) simply by adding a couple of special headers to its manifest.&lt;br /&gt;&lt;br /&gt;The manifest headers declare the &lt;span style="font-weight: bold;"&gt;import &lt;/span&gt;and &lt;span style="font-weight: bold;"&gt;export &lt;/span&gt;relations between modules. A bundle B may have a package with public classes, but at runtime, no other bundle C can use these classes unless bundle B exports them.&lt;br /&gt;&lt;br /&gt;When working with Eclipse, its Plugin Development Environment (PDE) already controls bundle imports and exports at compile time. You get a warning when you import a class that was not exported.&lt;br /&gt;&lt;br /&gt;Of course this does not prevent you from adding import or export directives to your bundle manifests, thus diluting the original architecture. But Eclipse offers tools for the architect (or yourself) to inspect the bundle hierarchy and to easily detect any unintentional dependencies.&lt;br /&gt;&lt;br /&gt;This is just &lt;span style="font-style: italic;"&gt;one &lt;/span&gt;aspect of OSGi, but it's the one I find most valuable.&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/7836204352369514180-4907138811919492405?l=hwellmann.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://hwellmann.blogspot.com/feeds/4907138811919492405/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=7836204352369514180&amp;postID=4907138811919492405' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/7836204352369514180/posts/default/4907138811919492405'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/7836204352369514180/posts/default/4907138811919492405'/><link rel='alternate' type='text/html' href='http://hwellmann.blogspot.com/2008/11/why-i-use-osgi.html' title='Why I use OSGi'/><author><name>Harald Wellmann</name><uri>http://www.blogger.com/profile/08039976160321882828</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='16' height='16' src='http://img2.blogblog.com/img/b16-rounded.gif'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-7836204352369514180.post-2247105329938265178</id><published>2008-11-02T22:45:00.002+01:00</published><updated>2008-11-02T23:07:11.630+01:00</updated><title type='text'>Joining the Blogosphere</title><content type='html'>To blog, or not to blog - that never used to be the question, but now it somehow makes sense to start.&lt;br /&gt;&lt;br /&gt;Blogo ergo sum?&lt;br /&gt;&lt;br /&gt;Well, recently I found myself reading a growing number of blog postings from other people working on related topics, which gave me some help on problems I was dealing with or showed me some new tools or technologies I found useful, so I think it's time to reciprocate.&lt;br /&gt;&lt;br /&gt;Topics that are likely to show up here include Software Development in general, with a special focus on Java, Eclipse, OSGi and all sorts of tools and tricks that help you solve problems you never had without them.&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/7836204352369514180-2247105329938265178?l=hwellmann.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://hwellmann.blogspot.com/feeds/2247105329938265178/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=7836204352369514180&amp;postID=2247105329938265178' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/7836204352369514180/posts/default/2247105329938265178'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/7836204352369514180/posts/default/2247105329938265178'/><link rel='alternate' type='text/html' href='http://hwellmann.blogspot.com/2008/11/joining-blogosphere.html' title='Joining the Blogosphere'/><author><name>Harald Wellmann</name><uri>http://www.blogger.com/profile/08039976160321882828</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='16' height='16' src='http://img2.blogblog.com/img/b16-rounded.gif'/></author><thr:total>0</thr:total></entry></feed>
