tag:blogger.com,1999:blog-26645286358224065432024-03-14T12:13:32.138+11:00IMHOMy thoughts on software technologies and development...Alex Weihttp://www.blogger.com/profile/16196507572911120081noreply@blogger.comBlogger29125tag:blogger.com,1999:blog-2664528635822406543.post-1050331370946904832009-01-22T22:35:00.002+11:002009-01-24T00:32:55.159+11:00Simplest way to override hashCode(), equals(Object) and toString()We all know that these three methods belongs to <tt>java.lang.Object</tt>, the parent of all other Java classes, and they are intended to be overridden by subclasses wherever appropriate.<br /><br />Both <tt>hashCode</tt> and <tt>equals(Object)</tt> should be overridden for entity objects that have a database identity and value objects that are used to pass parameters and return result, especially if they are used in a <tt>Set</tt> or a <tt>Map</tt>.<br /><br />An often overlooked benefit of overriding these two methods for value objects is that it makes assertion and verification of invocation on mock objects much easier and more resilient to changes.<br /><br />As for stateless objects, such as web actions, service objects, entity managers, repositories and data access objects, there is little to gain by overriding these methods.<br /><br />With regards to <tt>toString</tt>, it would make our life debugging or reading log file a lot easier if it is overridden even though business may not mandate this.<br /><br />In "<a href="http://www.amazon.com/Effective-Java-2nd-Joshua-Bloch/dp/0321356683/" rel="nofollow">Effective Java</a>", Joshua Bloch provides the following guidance on when it is appropriate to override these methods:<br /><ul><li>Override <tt>equals(Object)</tt> unless:<ul><li>Each instance of the class is inherently unique.</li><li>You don't care whether the class provides a "logical equality" test.</li><li>A superclass has already overridden <tt>equals</tt>, and the superclass behaviour is appropriate for this class.</li><li>The class is private or package-private, and you are certain that its <tt>equals</tt> method will never be invoked.</li></ul></li><li>(Item 9) Always override <tt>hashCode</tt> when you override <tt>equals</tt></li><li>(Item 10) Always override <tt>toString</tt></li></ul><br />But, why are we not overriding these methods as often as we should? I can think of the following reasons:<br /><ul><li>When we write a new class, our focus is on the implementation of the core responsibility of the class. Overriding these methods are often a result of after thoughts.</li><li>We can "cheat" in unit testing by substituting "logical equality" test with a "uniqueness" test, especially if the value object is immutable so that the class under test does not need to defensively copy an incoming value object to preserve invariants.</li><li>As there is a fair bit of code in overriding <tt>equals(Object)</tt>, it requires unit testing the correctness of the overriding, which can be several times longer than the overriding method itself, depending on how thorough your tests are.</li><li>These methods are considered "affordable debt" in order to meet a project deadline.</li></ul><br />Is there a way to override these methods with least effort?<br /><br />Yes. We'll go through several ways of overriding these methods to find the simplest way.<br /><br /><b><u><font size="+1">DIY</font></u></b><br />When hand-crafting <tt>equals</tt> method, make sure you follow the high-quality <tt>equals</tt> method recipe from "<a href="http://www.amazon.com/Effective-Java-2nd-Joshua-Bloch/dp/0321356683/" rel="nofollow">Effective Java</a>":<br /><ol><li>Use the <tt>==</tt> operator to check if the argument is a reference to this object.</li><li>Use the <tt>instanceof</tt> operator to check if the argument has the correct type.</li><li>Cast the argument to the correct type.</li><li>For each "significant" field in the class, check if that field of the argument matches the corresponding field of this object.<ul><li>Avoid the possibility of a <tt>NullPointerException</tt> if some instance fields are nullable.</li></ul></li><li>When you are finished writing your <tt>equals</tt> method, ask yourself three questions: Is it symmetric? Is it transitive? Is it consistent?</li></ol><br />Some additional suggestions:<br /><ul><li>If the superclass also overrides <tt>equals</tt> method, invoke <tt>super.equals(obj)</tt> as well, provided that the superclass's overriding method does not use a <tt>getClass</tt> test in place of the <tt>instanceof</tt> test.</li><li>Unit test symmetry, transitivity and consistency.</li></ul><br /><b>Pros</b><ul><li>No third-party dependencies</li></ul><br /><b>Cons</b><ul><li>Humans are error-prone, so it definitely requires unit-testing</li><li>Can be time-consuming</li><li>Requires "maintenance" when adding new instance fields</li><li><tt>equals(Object</tt> and <tt>hashCode()</tt> can get out-of-sync when introducing new instance fields</li></ul><br /><b><u><font size="+1">Code generation by IDE</font></u></b><br />In IDEA, select "Code" -> "Generate..." and select "equals() and hashCode()".<br/><br />In Eclipse, select "Source" -> "Generate equals() and hashCode()...".<br/><br />Both IDEs let you choose whether to use <tt>instanceof</tt> test or not, and which instance fields are used in these methods.<br /><br /><b>Pros</b><ul><li>No third-party dependencies</li></ul><br /><b>Cons</b><ul><li>Requires re-generation when adding new instance fields</li><li>Unit testing may be needed if the generated code is significantly "enhanced by hand"</li><li><tt>equals(Object</tt> and <tt>hashCode()</tt> can get out-of-sync when introducing new instance fields without regenerating the code</li></ul><br /><b><u><font size="+1">Typical Use of Apache Commons Lang's Builders</font></u></b><br />The "typical use" of <tt>EqualsBuilder</tt>, as documented, is as follows:<br /><pre name="code" class="Java"><br />public boolean equals(Object obj) {<br /> if (this == obj) {<br /> return true;<br /> }<br /> if (obj instanceof MyClass == false) {<br /> return false;<br /> }<br /> MyClass rhs = (MyClass) obj;<br /> return new EqualsBuilder()<br /> .appendSuper(super.equals(obj))<br /> .append(field1, rhs.field1)<br /> .append(field2, rhs.field2)<br /> .append(field3, rhs.field3)<br /> .isEquals();<br />}<br /></pre><br /><br /><b>Pros</b><ul><li>Flexible</li></ul><br /><b>Cons</b><ul><li>Lengthy</li><li>May require some degree of unit testing, usually the reflexive test, null test and type test.</li><li>Requires "maintenance" when adding new instance fields</li><li><tt>equals(Object</tt> and <tt>hashCode()</tt> can get out-of-sync when introducing new instance fields</li><li>Third-party library dependency (this should not be an issue as Apache Commons Lang in ubiquitous...)</li></ul><br /><b><u><font size="+1">The Simplest Way to Override these methods</font></u></b><br />The possibly simplest way is to use the reflection-based methods of the Apache Commons Lang's Builders, as shown below:<br /><pre name="code" class="Java"><br />@Override<br />public int hashCode()<br />{<br /> return HashCodeBuilder.reflectionHashCode(this);<br /> // or<br /> // return HashCodeBuilder.reflectionHashCode(23, 13, this);<br />}<br /><br />@Override<br />public boolean equals(Object obj)<br />{<br /> return EqualsBuilder.reflectionEquals(this, obj);<br /> // or, if transient fields are tested while some other fields should be excluded, and the reflection should be done<br /> // up to a certain class (there are many overloading versions, so choose the right one)<br /> // return EqualsBuilder.reflectionEquals(this, obj, true, Parent.class, new String[]{"excludedField1", "excludedField2"});<br />}<br /><br />@Override<br />public String toString()<br />{<br /> return ToStringBuilder.reflectionToString(this);<br /> // or, if you'd like to choose a different style<br /> // return ToStringBuilder.reflectionToString(this, ToStringStyle.SHORT_PREFIX_STYLE);<br />}<br /></pre><br /><br /><b>Pros:</b><ul><li>No "maintenance" when adding new instance fields.</li><li>Won't accidentally make <tt>hashCode()</tt> and <tt>equals(Object)</tt> out-of-sync when introducing new instance fields</li><li>No need to write unit tests for these methods because they are <em>too simple to break</em>.</li></ul><br /><b>Cons:</b><ul><li>The overhead of reflection. But you shouldn't avoid these methods simply because of the overhead:<ul><li>Unless your class is used in big <tt>Collection</tt>s and as key in big <tt>Map</tt>s, the overhead should be insignificant.</li><li>Don't <em>prematurely optimize</em>. Wait until you identify this is where the bottleneck is using a profiler before you try a different implementation. In that case, don't forget to add unit tests first.</li></ul></li><li>Does not apply to entity objects directly. For these objects with a database identity, the equality test should be based only on database key, preferrably unique natural key.</li></ul><br />So, if you think this is good, then why don't you put it in the code templates?<br /><br /><b><u><font size="+1">Embed in Code Templates</font></u></b><br /><br />If you use IDEA, go to "Settings" -> "File Templates", select "Templates" tab and edit the content of "Class" to the following:<br /><pre name="code" class="Java"><br />#if (${PACKAGE_NAME} != "")package ${PACKAGE_NAME};#end<br /><br />import org.apache.commons.lang.builder.EqualsBuilder;<br />import org.apache.commons.lang.builder.HashCodeBuilder;<br />import org.apache.commons.lang.builder.ToStringBuilder;<br />import org.apache.commons.lang.builder.ToStringStyle;<br />import org.apache.commons.logging.Log;<br />import org.apache.commons.logging.LogFactory;<br /><br />#parse("File Header.java")<br /><br />public class ${NAME}<br />{<br /><br /> @SuppressWarnings("unused")<br /> private static final Log log = LogFactory.getLog(${NAME}.class);<br /> <br /> @Override<br /> public int hashCode()<br /> {<br /> return HashCodeBuilder.reflectionHashCode(this);<br /> }<br /> <br /> @Override<br /> public boolean equals(Object obj)<br /> {<br /> return EqualsBuilder.reflectionEquals(this, obj);<br /> }<br /> <br /> @Override<br /> public String toString()<br /> {<br /> return ToStringBuilder.reflectionToString(this, ToStringStyle.SHORT_PREFIX_STYLE);<br /> }<br /><br />}<br /></pre><br /><br />If you use Eclipse, select "Preferences", under "Java" -> "Code Style" -> "Code Templates", expand "Code".<br/><br />Edit "New Java files" to something like the following:<br /><pre name="code" class="Java"><br />${filecomment}<br />${package_declaration}<br /><br />import org.apache.commons.lang.builder.EqualsBuilder;<br /><br />import org.apache.commons.lang.builder.HashCodeBuilder;<br />import org.apache.commons.lang.builder.ToStringBuilder;<br />import org.apache.commons.lang.builder.ToStringStyle;<br />import org.apache.commons.logging.Log;<br />import org.apache.commons.logging.LogFactory;<br /><br />${typecomment}<br />${type_declaration}<br /></pre><br /><br />Then edit "Class body" and change to the following:<br /><pre name="code" class="Java"><br /><br />@SuppressWarnings("unused")<br />private static final Log log = LogFactory.getLog(${type_name}.class);<br /><br />@Override<br />public int hashCode()<br />{<br /> return HashCodeBuilder.reflectionHashCode(this);<br />}<br /><br />@Override<br />public boolean equals(Object obj)<br />{<br /> return EqualsBuilder.reflectionEquals(this, obj);<br />}<br /><br />@Override<br />public String toString()<br />{<br /> return ToStringBuilder.reflectionToString(this, ToStringStyle.SHORT_PREFIX_STYLE);<br />}<br /></pre><br /><br />Finally, if you use JAXB 2.x to generate Java classes from XML Schema, make sure you use <a href="https://jaxb2-commons.dev.java.net/" rel="nofollow">jaxb2-commons</a>'s <a href="https://jaxb2-commons.dev.java.net/commons-lang-plugin/" rel="nofollow">jakarta-commons-lang plugin</a> to generate these methods. I have painful memory of working with plain JAB2-generated classes in unit testing before I discovered this precious plugin, which inspired me to write this post entry to share the simplest way to override <tt>hasCode()</tt>, <tt>equals(Object)</tt> and <tt>toString()</tt> methods with you....Alex Weihttp://www.blogger.com/profile/16196507572911120081noreply@blogger.com1tag:blogger.com,1999:blog-2664528635822406543.post-8422915938971016262008-12-29T22:15:00.002+11:002009-01-24T00:35:44.255+11:00Preventing NullPointerExceptionWhen a NullPointerException (NPE) is thrown, it can be hard to trace back to the bug that causes it, especially if it comes from an instance variable of a mutable class, where the execution of buggy code may have finished long before the NPE is thrown. With the wide adoption of the best practice of immutability and IoC container, it is not seen as frequently as before and most of the time it is easy to locate the bug, such as a missing setter injection in the Spring application context. Probably as a result, recently some developers seem to have relaxed on null checking as I have seem some codes in an open soure project that completely lacks both null checking and documentation of the preconditions on methods.<br /><br />This week, I have seen two good practices (IMHO) of null checking and related documentation:<br /><br />The first is a static method named <font color="blue"><tt>T checkNotNull(T reference, String referenceName)</tt></font> in class <font color="blue"><tt>Preconditions</tt></font> I found in the Activity Stream project. This class is modelled after <a href="http://google-collections.googlecode.com/svn/trunk/javadoc/com/google/common/base/Preconditions.html" rel="nofollow">a similar class from Google Collections API</a>. Note that it does not share any of its source code.<br /><br />This reminds me of the static methods <font color="blue"><tt>void notNull(Object object)</tt></font> and <font color="blue"><tt>void notNull(Object object, String message)</tt></font> from <font color="blue"><tt><a href="http://commons.apache.org/lang/api-release/org/apache/commons/lang/Validate.html" rel="nofollow">Validate</a></tt></font> class in Apache Commons Lang that are used a lot in my previous job for null checking:<br /><pre name="code" class="Java"><br />import static org.apache.commons.lang.Validate.notNull;<br />...<br />public class Foo<br />{<br /> private final Bar bar;<br /><br /> public Foo(Bar bar)<br /> {<br /> notNull(bar, "Bar must not be null.");<br /> this.bar = bar;<br /> ...<br /> }<br /> ...<br />}<br /></pre><br />The <font color="blue"><tt>T checkNotNull(T reference, String referenceName)</tt></font> has the advantage of returning the parameter, thus it can be assigned right after the null checking:<br /><pre name="code" class="Java"><br />import static com.atlassian.streams.util.Preconditions.checkNotNull;<br />...<br />public class Foo<br />{<br /> private final Bar bar;<br /><br /> public Foo(Bar bar)<br /> {<br /> this.bar = checkNotNull(bar, "Bar");<br /> ...<br /> }<br /> ...<br />}<br /></pre><br />Similar to null checking, quite often there is also a need to guard against empty <font color="blue"><tt>String</tt></font>, blank <font color="blue"><tt>String</tt></font> (containing only whitespaces, see <font color="blue"><tt><a href="http://commons.apache.org/lang/api-release/org/apache/commons/lang/StringUtils.html" rel="nofollow">StringUtils</a></tt></font>), empty <font color="blue"><tt>Collection</tt></font>, null-containing <font color="blue"><tt>Collection</tt></font> (containing a null element), empty <font color="blue"><tt>Array</tt></font>, null-containing <font color="blue"><tt>Array</tt></font> and empty <font color="blue"><tt>Map</tt></font>, etc.<br /><br />Luckily, <font color="blue"><tt>Validate</tt></font> provides most of these checks:<ul><li><font color="blue"><tt>void notEmpty(Collection collection, String referenceName)</tt></font></li><li><font color="blue"><tt>void noNullElements(Collection collection, String referenceName)</tt></font></li><li><font color="blue"><tt>void notEmpty(String string, String referenceName)</tt></font></li><li><font color="blue"><tt>void notEmpty(Object[] array, String referenceName)</tt></font></li><li><font color="blue"><tt>void noNullElements(Object[] array, String referenceName)</tt></font></li><li><font color="blue"><tt>void notEmpty(Map map, String referenceName)</tt></font></li></ul><br />Unfortunately, they all return <tt>void</tt> and cannot be chained, and it can force you to write your own little static method to do all the checks, or use it before the proper check:<br /><pre name="code" class="Java"><br />import static org.apache.commons.lang.Validate.*;<br />...<br />public class Foo extends Bar<br />{<br /> public Foo(List list)<br /> {<br /> super(notEmptyNoNullElements(list));<br /> }<br /><br /> private static notEmptyNoNullElements(Collection collection)<br /> {<br /> notEmpty(collection);<br /> noNullElements(collection);<br /> }<br /> ...<br />}<br /></pre><br />So I have added the following methods to <font color="blue"><tt>Preconditions</tt></font>:<ul><li><font color="blue"><tt><T, C extends Collection<T>> C notEmpty(C collection, String name)</tt></font></li><li><font color="blue"><tt><T, C extends Collection<T>> C noNullElements(C collection, String name)</tt></font></li><li><font color="blue"><tt><T, C extends Collection<T>> C notEmptyNoNullElements(C collection, String name)</tt></font></li><li><font color="blue"><tt><T> T[] notEmpty(T[] array, String name)</tt></font></li><li><font color="blue"><tt><T> T[] noNullElements(T[] array, String name)</tt></font></li><li><font color="blue"><tt><T> T[] notEmptyNoNullElements(T[] array, String name)</tt></font></li><li><font color="blue"><tt><K, V> Map<K, V> notEmpty(Map<K, V> map, String name)</tt></font></li><li><font color="blue"><tt>String notBlank(String text, String name)</tt></font></li></ul><br />The other example is actually in the Google Gadgets API. All the optional parameters are prefixed with "<tt>opt_</tt>", making it very obvious. So instead of just documenting in javadoc, we can also given a more intention-revealing name to parameters, such as:<br /><pre name="code" class="Java"><br />/**<br /> * Do something.<br /> * @param bar Used to do something. Cannot be <code>null</code>. Mandatory... <br /> * @param baz Used to do something. Can be <code>null</code>. Optional... <br /> */<br />public void foo(Bar bar, Baz optBaz)<br />{<br /> ...<br />}<br /></pre><br />Finally, <font color="blue"><tt>Preconditions</tt></font> probably should not sit in <tt>streams-core</tt>. It would be more useful if it is moved to some core projects, such as <tt>atlassian-core</tt>, so that different teams do not have to reinvent the wheel.Alex Weihttp://www.blogger.com/profile/16196507572911120081noreply@blogger.com0tag:blogger.com,1999:blog-2664528635822406543.post-77935495507212472802008-07-23T22:53:00.002+10:002008-07-23T23:23:29.096+10:00Unable to install equinox p2 plugins for Eclipse GanymedeI have been trying to install "build utility feature for equinox p2 plugins", on which Spring IDE Eclipse plugin and M2Eclipse plugin have a dependency. But I'm constantly getting an "Invalid zip file format" error:<br /><br /><span style="font-size:85%;"><span style="font-family: courier new;">An error occurred while collecting items to be installed</span><br /><span style="font-family: courier new;"> Error closing the output stream for master-equinox-p2/org.eclipse.update.feature/1.0.0.v20080506-4--8Mc44yANsYbyiqu-z-uDo0 on repository file:/C:/eclipse-3.4-ganymede/. </span><br /><span style="font-family: courier new;"> Error unzipping C:\DOCUME~1\Alex\LOCALS~1\Temp\master-equinox-p2_1.0.0.v20080506-4--8Mc44yANsYbyiqu-z-uDo044914.jar: Invalid zip file format</span></span><br /><br />It seems to be unable to download a good copy of master-equinox-p2 JAR file. I have cleaned up all the temporary internet files and tried to install on a different machine but still no luck. I suspect that the mirror site is corrupted, probably with a bad signature or something. But it doesn't seem to allow me to choose mirror site in Ganymede any more. Urrghh!Alex Weihttp://www.blogger.com/profile/16196507572911120081noreply@blogger.com7tag:blogger.com,1999:blog-2664528635822406543.post-58033491645362931072008-06-14T00:40:00.002+10:002008-06-14T01:04:45.749+10:00Which is the hottest Java web framework that people want to learn?A recent post on <a href="http://www.breakitdownblog.com/">The "Break it Down" Blog</a>, <a href="http://www.breakitdownblog.com/which-is-the-hottest-java-web-framework-or-maybe-not-java/">Which is the Hottest Java Web Framework? Or Maybe Not Java?</a> has attracted lots of attention, including <a href="http://raibledesigns.com/rd/entry/re_which_is_the_hottest">that</a> of Java Web Frameworks Guru Matt Raible.<br /><br />The author excluded <span style="color: rgb(51, 204, 0);">Tapestry</span> and <span style="color: rgb(51, 204, 0);">Stripes </span>because of the high noise from the common usage of these terms.<br /><br />Some readers, including myself, commented that the high search rate may reflect that some frameworks, like <span style="color: rgb(51, 204, 0);">JSF</span>, especially <span style="color: rgb(51, 204, 0);">JSF 1.1</span>, are so bad that people encounter problems all the time and have to rely on Google to search for solutions.<br /><br />In order to find out how people really like to learn about those frameworks mentioned in the post, I tweaked the search terms a bit by adding the word "tutorial", as I reckon anyone who wants to learn a web technology is likely to search for a tutorial on that technology, only if they speak English...<br /><br />And here are the result.<br /><br />Comparing <span style="color: rgb(51, 204, 0);">JSF</span>, <span style="color: rgb(51, 204, 0);">Struts 2</span>, <span style="color: rgb(51, 204, 0);">Spring MVC</span> / <span style="color: rgb(51, 204, 0);">Spring Webflow</span>, <span style="color: rgb(51, 204, 0);">JBoss Seam</span> and <span style="color: rgb(51, 204, 0);">Apache Wicket</span>:<br /><a href="http://www.google.com/trends?q=%28jsf+tutorial%29+%7C+%28javaserver+faces+tutorial%29+%7C+%28java+server+faces+tutorial%29%2C+%28wicket+tutorial%29%2C+%28seam+tutorial%29%2C+%28spring+mvc+tutorial%29+%7C+%28spring+webflow+tutorial%29+%7C+%28spring+web+flow+tutorial%29%2C+%28%22struts+2%22+tutorial%29+%7C+%28struts2+tutorial%29%2C+%28tapestry+tutorial%29&ctab=0&geo=all&date=all&sort=1"><img id="BLOGGER_PHOTO_ID_5211368674726646722" style="margin: 0px auto 10px; display: block; text-align: center;" alt="" src="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEgZF0IeOzy14SG1sZWNAaFH6jUqKcaBT9-Mr83oJreWkLsBbXQ9nd5rdpQQGUs6XMIXrHWE49Xt2kqg9QV2kfldV8t3-jZDhhYYvcp-ymWPyHEfjiC2HmKWyOvVwLy_C2o1ANIGB3M962My/s400/jsf-wicket-seam-springmvc-struts2.PNG" border="0" /></a><br />As we can see, <span style="color: rgb(51, 204, 0);">JSF</span> is much more popular than all other Java web frameworks and is very popular in India, Hong Kong, Czech, Singapore and the Philippines. <span style="color: rgb(51, 204, 0);">Struts 2</span> ranked second, slightly better than <span style="color: rgb(51, 204, 0);">Spring MVC</span> and <span style="color: rgb(51, 204, 0);">Seam</span>. And <span style="color: rgb(51, 204, 0);">Wicket</span> didn't even have enough search volume to rank.<br /><br />Then I compared <span style="color: rgb(51, 204, 0);">Struts 2</span>, <span style="color: rgb(51, 204, 0);">Spring MVC</span> / <span style="color: rgb(51, 204, 0);">Spring Webflow</span>, <span style="color: rgb(51, 204, 0);">JBoss Seam</span>, <span style="color: rgb(51, 204, 0);">Tapestry</span> and <span style="color: rgb(51, 204, 0);">Grails</span>:<br /><p><a href="http://www.google.com/trends?q=%28grails+tutorial%29%2C+%28seam+tutorial%29%2C+%28spring+mvc+tutorial%29+%7C+%28spring+webflow+tutorial%29+%7C+%28spring+web+flow+tutorial%29%2C+%28%22struts+2%22+tutorial%29+%7C+%28struts2+tutorial%29%2C+%28tapestry+tutorial%29&ctab=0&geo=all&date=all&sort=1"><img id="BLOGGER_PHOTO_ID_5211368679609317426" style="margin: 0px auto 10px; display: block; text-align: center;" alt="" src="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEjO9OHz9zI7jwAz2NwRmtcFHG1F_DxO72YdT19bl44aYCw_1dmzKzonBdp8Sf85MGX64oTtyOQHge0yan8RkfAMNCFKcaiL2ThTQaYpcrKmv36a7GyydeZ_fedRmzzrkrQQyL_T8UIfXUQT/s400/grails-seam-springmvc-struts2-tapestry.PNG" border="0" /></a></p><p>Basically, there is little search volume for tutorials on <span style="color: rgb(51, 204, 0);">Grails</span>, <span style="color: rgb(51, 204, 0);">Tapestry</span> and <span style="color: rgb(51, 204, 0);">Stripes</span> (not shown in this image). This is probably an indication that the official website for these frameworks have good documentation and tutorials, where JSF is only a specification and you have to find tutorials elsewhere.</p><p>Here the interesting observation is: Struts 2 is very popular in India and Brazil; Seam is far more popular in Austria, Spring MVC is especially popular in London and Grails has been taken up quite well in Germany. And surprsingly, even Australia has more search volumes for these frameworks than the United States.</p><p> </p><p>Finally, I compared <span style="color: rgb(51, 204, 0);">Ruby on Rails</span>, <span style="color: rgb(51, 204, 0);">Adobe Flex</span>, <span style="color: rgb(51, 204, 0);">JSF</span>, <span style="color: rgb(51, 204, 0);">Struts 2</span> and <span style="color: rgb(51, 204, 0);">Spring MVC</span> / <span style="color: rgb(51, 204, 0);">Spring Webflow</span>: </p><a href="http://www.google.com/trends?q=%28rails+tutorial%29%2C+%28flex+tutorial%29%2C+%28jsf+tutorial%29+%7C+%28javaserver+faces+tutorial%29+%7C+%28java+server+faces+tutorial%29%2C+%28spring+mvc+tutorial%29+%7C+%28spring+webflow+tutorial%29+%7C+%28spring+web+flow+tutorial%29%2C+%28%22struts+2%22+tutorial%29+%7C+%28struts2+tutorial%29&ctab=0&geo=all&date=all&sort=1"><img id="BLOGGER_PHOTO_ID_5211368678796338994" style="margin: 0px auto 10px; display: block; text-align: center;" alt="" src="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEhRee29a97b3wDX4m7hy9W44uzvwswtAZ1KI3neZIWJe6pt-KjpaeJuUpIxcTURArcuExcQ1PwAIf6k5gv5eeXNpzYPm-stHfFlw4bAfxSLc0V3xogxTEvJ18aBWmlvlLP3QQBvsu-M48AI/s400/rails-flex-jsf-springmvc-struts2.PNG" border="0" /></a><br /><br />Hmmm, <span style="color: rgb(51, 204, 0);">Ruby on Rails</span>, <span style="color: rgb(51, 204, 0);">Adobe Flex</span> and <span style="color: rgb(51, 204, 0);">JSF</span> are popular to the same level. However, the popularity of <span style="color: rgb(51, 204, 0);">JSF</span> has been on a plateau for the past few years and has begun to decline. <span style="color: rgb(51, 204, 0);">Ruby on Rails</span> also starts to show signs of decline, while <span style="color: rgb(51, 204, 0);">Flex</span> is rising sharply.<br /><br />And <span style="color: rgb(51, 204, 0);">Ruby on Rails</span> are very popular in San Francisco and San Jose, CA, the Philippines and Sweden. And <span style="color: rgb(51, 204, 0);">Flex</span> is rather popular in Brazil and Europe.Alex Weihttp://www.blogger.com/profile/16196507572911120081noreply@blogger.com20tag:blogger.com,1999:blog-2664528635822406543.post-91241033633434702342008-03-08T00:18:00.003+11:002008-12-25T00:04:50.155+11:00More on How to make Acegi work on Sun Application Server 8.x?Applying the solution mentioned in my previous post <a href="http://ozgwei.blogspot.com/2008/01/how-to-make-acegi-work-on-sun.html">IMHO: How to make Acegi work on Sun Application Server 8.x?</a> has been proved working quite well. Well, until I encountered the same <tt>ClassCastException</tt> again. This time it was because the access was denied. Looking into the stack trace, I found that it was because Acegi's <tt>AccessDeniedHandlerImpl</tt> forwards the <tt>SecurityContextHolderAwareRequestWrapper</tt> to show the error page.<br /><br />Similar to the solution in the previous post, I creates a <tt>NullPrincipalAccessDeniedHandlerImpl</tt>, which extends Acegi's <tt>AccessDeniedHandlerImpl</tt> but wrap the <tt>HttpServletRequest</tt> with the <tt>NullPrincipalHttpServletRequestWrapper</tt>.<br /><br />Following is the source code of <tt>NullPrincipalAccessDeniedHandlerImpl</tt>:<br /><br /><pre name='code' class='Java'>package au.net.ozgwei.util.spring.security;<br /><br />import java.io.IOException;<br /><br />import javax.servlet.ServletException;<br />import javax.servlet.ServletRequest;<br />import javax.servlet.ServletResponse;<br />import javax.servlet.http.HttpServletRequest;<br /><br />import org.acegisecurity.AccessDeniedException;<br />import org.acegisecurity.ui.AccessDeniedHandlerImpl;<br /><br />import org.apache.commons.logging.Log;<br />import org.apache.commons.logging.LogFactory;<br /><br />import au.net.ozgwei.util.httpservlet.NullPrincipalHttpServletRequestWrapper;<br /><br />/**<br /> * An Acegi AccessDeniedHandler implementation designed specific to get around<br /> * the bug in Sun Application Server 8.x where a custom security framework's<br /> * implementation of Principal is casted to Sun Application Server's own<br /> * implementation.<br /> *<br /> * @author Alex<br /> * @version 1.0<br /> */<br />public class NullPrincipalAccessDeniedHandlerImpl extends<br /> AccessDeniedHandlerImpl {<br /><br /> @SuppressWarnings("unused")<br /> private static final Log log =<br /> LogFactory.getTrace(<br /> NullPrincipalAccessDeniedHandlerImpl.class);<br /><br /> /**<br /> * Default no-arg constructor.<br /> */<br /> public NullPrincipalAccessDeniedHandlerImpl() {<br /> super();<br /> }<br /><br /> @Override<br /> public void handle(ServletRequest aRequest, ServletResponse aResponse,<br /> AccessDeniedException aAccessDeniedException) throws IOException,<br /> ServletException {<br /><br /> super.handle(new NullPrincipalHttpServletRequestWrapper(<br /> (HttpServletRequest)aRequest), aResponse, aAccessDeniedException);<br /> }<br /><br />}<br /></pre><br />Of course, the Spring application context must be changed to replace the original AccessDeniedHandler implementation with this in the definition of the <tt>exceptionTranslationFilter</tt> bean:<br /><pre name="code" class="Xml"><bean id="exceptionTranslationFilter"<br /> class="org.acegisecurity.ui.ExceptionTranslationFilter"><br /> <property name="authenticationEntryPoint"><br /> <ref local="authenticationProcessingFilterEntryPoint"/><br /> </property><br /> <br /> <property name="accessDeniedHandler"><br /> <bean class="au.com.cardlink.common.util.spring.security.NullPrincipalAccessDeniedHandlerImpl"><br /> <property name="errorPage" value="/faces/ForbiddenAccess.jsp"/><br /> </bean><br /> </property><br /><br /></bean><br /></pre><br />Now it works even if user's access to a protected URL is denied by Acegi.Alex Weihttp://www.blogger.com/profile/16196507572911120081noreply@blogger.com0tag:blogger.com,1999:blog-2664528635822406543.post-51007823299232457612008-02-22T22:38:00.003+11:002008-02-22T22:45:06.452+11:0012 Technologies I Would Like to Grasp in 2008<ol><li>Grails</li><li>Groovy</li><li>OSGi</li><li>Spring Batch</li><li>Spring Security 2.0</li><li>Spring Web Services</li><li>AspectJ</li><li>JBoss Seam</li><li>RichFaces</li><li>Mule</li><li>JavaFX</li><li>Selenium</li></ol>Alex Weihttp://www.blogger.com/profile/16196507572911120081noreply@blogger.com1tag:blogger.com,1999:blog-2664528635822406543.post-4372408050660297042008-02-06T23:05:00.001+11:002008-04-05T23:25:50.851+11:00Grails 1.0 is Out!<a href="http://grails.org/">Grails</a> 1.0 was finally released yesterday!<br />To quote from the official website: "The Search Is Over!"<br />After a long and exciting wait, Grails, the response to Ruby on Rails (RoR) from the Java land, has reached maturity.<br />It adopts "Convention over Configuration" (CoC), which has been made popular by RoR.<br />It's built on top of solid frameworks, such as <a href="http://www.blogger.com/www.springframework.org">Spring</a>, <a href="http://hibernate.org/">Hibernate</a> & <a href="http://www.opensymphony.com/sitemesh/">Sitemesh</a>, allowing developers to quickly develop web application with a focus on CRUD operations on database.<br />It also has a healthy plugin system to allow contributors to develope plugins, such as <a href="http://www.acegisecurity.org/">Acegi</a> plugin.<br />When developing with Grails, you program in Groovy, a powerful scripting language that runs seamlessly on the JVM. It has all the powers that Ruby has and maybe more.<br />Enjoy the journey to Grails! I'm sure I will.Alex Weihttp://www.blogger.com/profile/16196507572911120081noreply@blogger.com0tag:blogger.com,1999:blog-2664528635822406543.post-27114713088384579202008-01-21T17:56:00.002+11:002008-12-25T00:03:33.676+11:00How to make Acegi work on Sun Application Server 8.x?We are currently developing an application that employs <a href="http://www.acegisecurity.org/">Acegi</a> and runs on Sun Application Server 8 (Sun AS 8.x).<br /><br />Being a mature and widely adopted security solution, we did not have many problems until we encountered the following puzzling exception:<br /><pre class="alt2" dir="ltr" style="border: 1px inset ; margin: 0px; padding: 6px; overflow: auto; font-size: 12px; width: 540px; height: 180px; text-align: left;">[#|2008-01-18T16:58:28.984+1100|SEVERE|sun-appserver-pe8.2|javax.enterprise.system.container.web|_ThreadID=22;|ApplicationDispatcher[/express_portal] Servlet.service() for servlet jsp threw exception<br />java.lang.ClassCastException: org.acegisecurity.providers.UsernamePasswordAuthenticationToken<br />at com.sun.web.server.J2EEInstanceListener.handleBeforeEvent(J2EEInstanceListener.java:130)<br />at com.sun.web.server.J2EEInstanceListener.instanceEvent(J2EEInstanceListener.java:68)<br />at org.apache.catalina.util.InstanceSupport.fireInstanceEvent(InstanceSupport.java:300)<br />at org.apache.catalina.core.ApplicationDispatcher.invoke(ApplicationDispatcher.java:712)<br />at org.apache.catalina.core.ApplicationDispatcher.processRequest(ApplicationDispatcher.java:482)<br />at org.apache.catalina.core.ApplicationDispatcher.doForward(ApplicationDispatcher.java:417)<br />at org.apache.catalina.core.ApplicationDispatcher.access$000(ApplicationDispatcher.java:80)<br />at org.apache.catalina.core.ApplicationDispatcher$PrivilegedForward.run(ApplicationDispatcher.java:95)<br />at java.security.AccessController.doPrivileged(Native Method)<br />at org.apache.catalina.core.ApplicationDispatcher.forward(ApplicationDispatcher.java:313)<br />at org.acegisecurity.ui.AccessDeniedHandlerImpl.handle(AccessDeniedHandlerImpl.java:65)<br />at org.acegisecurity.ui.ExceptionTranslationFilter.handleException(ExceptionTranslationFilter.java:166)<br />at org.acegisecurity.ui.ExceptionTranslationFilter.doFilter(ExceptionTranslationFilter.java:118)<br />at org.acegisecurity.util.FilterChainProxy$VirtualFilterChain.doFilter(FilterChainProxy.java:274)<br />at org.acegisecurity.providers.anonymous.AnonymousProcessingFilter.doFilter(AnonymousProcessingFilter.java:125)<br />at org.acegisecurity.util.FilterChainProxy$VirtualFilterChain.doFilter(FilterChainProxy.java:274)<br />at org.acegisecurity.wrapper.SecurityContextHolderAwareRequestFilter.doFilter(SecurityContextHolderAwareRequestFilter.java:81)<br />at org.acegisecurity.util.FilterChainProxy$VirtualFilterChain.doFilter(FilterChainProxy.java:274)<br />at org.acegisecurity.ui.AbstractProcessingFilter.doFilter(AbstractProcessingFilter.java:217)<br />at org.acegisecurity.util.FilterChainProxy$VirtualFilterChain.doFilter(FilterChainProxy.java:274)<br />at org.acegisecurity.ui.logout.LogoutFilter.doFilter(LogoutFilter.java:106)<br />at org.acegisecurity.util.FilterChainProxy$VirtualFilterChain.doFilter(FilterChainProxy.java:274)<br />at org.acegisecurity.context.HttpSessionContextIntegrationFilter.doFilter(HttpSessionContextIntegrationFilter.java:229)<br />at org.acegisecurity.util.FilterChainProxy$VirtualFilterChain.doFilter(FilterChainProxy.java:274)<br />at org.acegisecurity.concurrent.ConcurrentSessionFilter.doFilter(ConcurrentSessionFilter.java:95)<br />at org.acegisecurity.util.FilterChainProxy$VirtualFilterChain.doFilter(FilterChainProxy.java:274)<br />at org.acegisecurity.util.FilterChainProxy.doFilter(FilterChainProxy.java:148)<br />at org.acegisecurity.util.FilterToBeanProxy.doFilter(FilterToBeanProxy.java:98)<br />at org.apache.catalina.core.ApplicationFilterChain.internalDoFilter(ApplicationFilterChain.java:210)<br />at org.apache.catalina.core.ApplicationFilterChain.access$000(ApplicationFilterChain.java:55)<br />at org.apache.catalina.core.ApplicationFilterChain$1.run(ApplicationFilterChain.java:161)<br />at java.security.AccessController.doPrivileged(Native Method)<br />at org.apache.catalina.core.ApplicationFilterChain.doFilter(ApplicationFilterChain.java:157)<br />at org.apache.catalina.core.StandardWrapperValve.invoke(StandardWrapperValve.java:263)<br />at org.apache.catalina.core.StandardPipeline.invoke(StandardPipeline.java:551)<br />at org.apache.catalina.core.StandardContextValve.invokeInternal(StandardContextValve.java:225)<br />at org.apache.catalina.core.StandardContextValve.invoke(StandardContextValve.java:173)<br />at org.apache.catalina.core.StandardPipeline.invoke(StandardPipeline.java:551)<br />at org.apache.catalina.core.StandardHostValve.invoke(StandardHostValve.java:170)<br />at org.apache.catalina.core.StandardPipeline.invoke(StandardPipeline.java:551)<br />at org.apache.catalina.core.StandardEngineValve.invoke(StandardEngineValve.java:132)<br />at org.apache.catalina.core.StandardPipeline.invoke(StandardPipeline.java:551)<br />at org.apache.catalina.core.ContainerBase.invoke(ContainerBase.java:933)<br />at org.apache.coyote.tomcat5.CoyoteAdapter.service(CoyoteAdapter.java:189)<br />at com.sun.enterprise.web.connector.grizzly.ProcessorTask.doProcess(ProcessorTask.java:604)<br />at com.sun.enterprise.web.connector.grizzly.ProcessorTask.process(ProcessorTask.java:475)<br />at com.sun.enterprise.web.connector.grizzly.ReadTask.executeProcessorTask(ReadTask.java:371)<br />at com.sun.enterprise.web.connector.grizzly.ReadTask.doTask(ReadTask.java:264)<br />at com.sun.enterprise.web.connector.grizzly.TaskBase.run(TaskBase.java:281)<br />at com.sun.enterprise.web.connector.grizzly.WorkerThread.run(WorkerThread.java:83)<br />|#]</pre><br /><br />We traced the application server and found that it was likely caused by the Sun AS 8.x trying to cast the Acegi-implemented <tt>Principal</tt> to an internal Sun AS implementation.<br /><br />We did some googling and found that <a href="http://www.jroller.com/agrebnev/entry/acegi_does_not_work_at">Andrey Grebnev blogged about this</a> two years ago, and he suggested a workaround by overriding the <tt>getUserPrincipal()</tt> method (of <tt>SecurityContextHolderAwareRequestWrapper</tt>) by always returning a <tt>null</tt>.<br /><br />Because <tt>SecurityContextHolderAwareRequestWrapper</tt> and its subclasses are used internally by Acegi, his workaround implied changing the source code of Acegi, which we are reluctant to do.<br /><br />Realizing that the it was only unsafe for the <tt>HttpServletRequest</tt> to return the Acegi-implemented <tt>Principal</tt> when the servlet filter chain has been executed and the control is handed over to the AS and the running application, we came up with a <tt>NullPrincipalFilter</tt> that wraps the incoming <tt>HttpServletRequest</tt> with a <tt>NullPrincipalHttpServletRequestWrapper</tt>, which returns <tt>null</tt> for <tt>getUserPrincipal()</tt>, and hands the control over to the AS. This filter should always be placed at the end of the filter proxy chain in Acegi. And of course, the application must not use <tt>HttpServletRequest</tt>'s <tt>getUserPrincipal()</tt> method to retrieve the user principal, which is very easy to do, as it can invoke <tt>SecurityContextHolder.getContext().getAuthentication()</tt> to achieve the same goal, without coupling to the Servlet API.<br /><br />The following is the source code of <tt>NullPrincipalFilter</tt>:<br /><br /><pre name="code" class="Java">package au.net.ozgwei.util.httpservlet;<br /><br />import java.io.IOException;<br /><br />import javax.servlet.Filter;<br />import javax.servlet.FilterChain;<br />import javax.servlet.FilterConfig;<br />import javax.servlet.ServletException;<br />import javax.servlet.ServletRequest;<br />import javax.servlet.ServletResponse;<br />import javax.servlet.http.HttpServletRequest;<br />import javax.servlet.http.HttpServletRequestWrapper;<br /><br />import org.apache.commons.logging.Log;<br />import org.apache.commons.logging.LogFactory;<br /><br />/**<br /> * A filter designed specific to get around the bug in Sun Application Server<br /> * 8.x where a custom security framework's implementation of Principal is<br /> * casted to Sun Application Server's own implementation.<br /> *<br /> * @author Alex<br /> * @version 1.0<br /> */<br />public class NullPrincipalFilter implements Filter {<br /><br /> @SuppressWarnings("unused")<br /> private static final Log log = LogFactory.getLog(NullPrincipalFilter.class);<br /><br /> /* (non-Javadoc)<br /> * @see javax.servlet.Filter#destroy()<br /> */<br /> public void destroy() {<br /> }<br /><br /> /* (non-Javadoc)<br /> * @see javax.servlet.Filter#doFilter(javax.servlet.ServletRequest, javax.servlet.ServletResponse, javax.servlet.FilterChain)<br /> */<br /> public void doFilter(ServletRequest aRequest, ServletResponse aResponse, FilterChain aFileterChain) throws IOException, ServletException {<br /> aFileterChain.doFilter(<br /> new NullPrincipalHttpServletRequestWrapper(<br /> (HttpServletRequest) aRequest), aResponse);<br /> }<br /><br /> /* (non-Javadoc)<br /> * @see javax.servlet.Filter#init(javax.servlet.FilterConfig)<br /> */<br /> public void init(FilterConfig aArg0) throws ServletException {<br /> }<br /><br />}</pre><br /><br />And the source code of <tt>NullPrincipalHttpServletRequestWrapper</tt>:<br /><br /><pre name="code" class="Java">package au.net.ozgwei.util.httpservlet;<br /><br />import java.security.Principal;<br /><br />import javax.servlet.http.HttpServletRequest;<br />import javax.servlet.http.HttpServletRequestWrapper;<br /><br />import org.apache.commons.logging.Log;<br />import org.apache.commons.logging.LogFactory;<br /><br />/**<br /> * A HttpServletRequestWrapper that always return null for Principal.<br /> *<br /> * @author Alex<br /> * @version 1.0<br /> */<br />public class NullPrincipalHttpServletRequestWrapper extends HttpServletRequestWrapper {<br /><br /> @SuppressWarnings("unused")<br /> private static final Log log = LogFactory.getLog(<br /> NullPrincipalHttpServletRequestWrapper.class);<br /><br /> public NullPrincipalHttpServletRequestWrapper(HttpServletRequest aReq) {<br /> super(aReq);<br /> }<br /><br /> @Override<br /> public Principal getUserPrincipal() {<br /> return null;<br /> }<br /><br />}</pre><br /><br />And a <tt>nullPrincipalFilter</tt> bean should be defined in the Spring application context and added to the end of the <tt>filterChainProxy</tt>, as following:<br /><pre name="code" class="Xml"><bean class="org.acegisecurity.util.FilterChainProxy" id="filterChainProxy"><br /> <property name="filterInvocationDefinitionSource"><br /> <value><br /> CONVERT_URL_TO_LOWERCASE_BEFORE_COMPARISON<br /> PATTERN_TYPE_APACHE_ANT<br /> /**=concurrentSessionFilter,httpSessionContextIntegrationFilter,logoutFilter,authenticationProcessingFilter,securityContextHolderAwareRequestFilter,anonymousProcessingFilter,exceptionTranslationFilter,filterInvocationInterceptor,nullPrincipalFilter<br /> </value><br /> </property><br /></bean><br /><br /><bean class="au.net.ozgwei.util.httpservlet.NullPrincipalFilter" id="nullPrincipalFilter"></pre><br /><br />Finally, this bug has been fixed in GlassFish eventually.Alex Weihttp://www.blogger.com/profile/16196507572911120081noreply@blogger.com0tag:blogger.com,1999:blog-2664528635822406543.post-7113669350614687652008-01-16T23:15:00.001+11:002008-02-22T22:47:33.082+11:00Gavin King: first impression (contrasting Spring guys)Today I attended Red Hat's "Gavin King" event. While I have attended many Spring events in Sydney, this is my first time attending a Hibernate/<span class="blsp-spelling-error" id="SPELLING_ERROR_0">JBoss</span>/Red Hat event. And the impressions are quite different...<br /><br /><ul><li>First impression - clothes:</li><ul><li>The Spring guys are always well-suited and businessmen-like. They are often the centre of the crowd.</li><li>Gavin's clothes were the most casual in the room. Before his presentation, I thought that fitted T-shirt wearing guy in trendy jeans was some skateboarding Ruby programmer who happened to want to know something in the Java world...</li></ul><li>Presentation style:</li><ul><li>The presentations by the Spring guys are always very professional, with the right level in technology details according to the nature of the event, the structure well organised, and seemingly well rehearsed.</li><li>Gavin's presentation is, again, more casual, just like a technology chat. I don't know how much the other people in the audience know about Web Beans and Seam, but Gavin lost me a few times because I haven't been following what's happening in the <span class="blsp-spelling-error" id="SPELLING_ERROR_1">JBoss</span> world...</li></ul><li>Technology inclination:</li><ul><li>The Spring guys can be very pedantic (in a good way), always emphasising best practices, such as programming to interfaces, abstraction levels, separation of concerns, etc.</li><li>Gavin is more pragmatic. Interfaces did not even make it to his slides. His Web Beans <span class="blsp-spelling-error" id="SPELLING_ERROR_2">JSR</span> recommends to make business interface optional for <span class="blsp-spelling-error" id="SPELLING_ERROR_3">EJB</span> 3.1 in Java <span class="blsp-spelling-error" id="SPELLING_ERROR_4">EE</span> 6. He reckons <span class="blsp-spelling-error" id="SPELLING_ERROR_5">AOP</span> is too complex for ordinary Java developers, there are only a handful of cross-cutting concerns, and <span class="blsp-spelling-error" id="SPELLING_ERROR_6">EJB</span> interceptors are enough to get the job done.</li><li>Spring framework focuses on enterprise applications that are typically developed by financial institutions and usually involves lots of web services and enterprise application integration, and some of these enterprise applications may not even have a web tier.</li><li>Web Beans <span class="blsp-spelling-error" id="SPELLING_ERROR_7">JSR</span>, <span class="blsp-spelling-error" id="SPELLING_ERROR_8">JBoss</span> Seam and Rich Faces, promoted by Gavin, are all mostly relevant to web-focused projects. Web Beans and <span class="blsp-spelling-error" id="SPELLING_ERROR_9">JBoss</span> Seam are particularly designed to ease development burden on entity management website with lots of CRUD operations, which make them competitors of (J)Ruby on Rails and Grails. I'll try to compare these frameworks in a later post. Enterprise applications seem off the target.</li><li>The apparent weakness in the Spring framework are: no type-safety check in the application context until <span class="blsp-spelling-error" id="SPELLING_ERROR_10">runtime</span>, verbose XML configuration, no bean id (or name) <span class="blsp-spelling-error" id="SPELLING_ERROR_11">namespaces</span> and the statelessness of Spring-managed beans. However, the first two have been addressed by <span class="blsp-spelling-error" id="SPELLING_ERROR_12">JavaConfig</span> and XML <span class="blsp-spelling-error" id="SPELLING_ERROR_13">namespace</span>. Noticeably, <span class="blsp-spelling-error" id="SPELLING_ERROR_14">JavaConfig</span> also uses annotations, but only in the <span class="blsp-spelling-error" id="SPELLING_ERROR_15">config</span> class without polluting the service bean or the service client. The stateless singleton issue has also been tackled with 'scopes' and domain object dependency injection, which is enabled by Spring <span class="blsp-spelling-error" id="SPELLING_ERROR_16">AOP</span>.</li><li>Gavin loves type-safety check in Java, so he hates the lack of type-safety check in Spring XML configuration, and he embraces annotation wholeheartedly. So he prefers Google <span class="blsp-spelling-error" id="SPELLING_ERROR_17">Guice</span> to Spring for dependency injection. In contrast to <span class="blsp-spelling-error" id="SPELLING_ERROR_18">Spring's</span> <span class="blsp-spelling-error" id="SPELLING_ERROR_19">JavaConfig</span>, Google <span class="blsp-spelling-error" id="SPELLING_ERROR_20">Guice's</span> annotations are used everywhere, in the service bean, in the service client or both. <span class="blsp-spelling-error" id="SPELLING_ERROR_21">JBoss</span> Seam introduces lots of annotations, and Web Beans <span class="blsp-spelling-error" id="SPELLING_ERROR_22">JSR</span> is to make many of these annotations into Java <span class="blsp-spelling-error" id="SPELLING_ERROR_23">EE</span> standard. I don't remember how many times Gavin showed the definition of an annotation in his slides today. Probably a dozen! And he still relies on XML configuration to override annotations. He classifies services beans according to deployment, such as one for production, one for stubbing in testing. So what will you do if you have two classes with the same service <span class="blsp-spelling-error" id="SPELLING_ERROR_24">API</span>, both used in production environment? My guess is you need to write a new annotation to differentiate them... Seems overuse of annotations, doesn't it?</li></ul><li>Hostility:</li><ul><li>Spring guys rarely publicly show their hostility towards <span class="blsp-spelling-error" id="SPELLING_ERROR_25">JBoss</span>, though in after session chats, they describe <span class="blsp-spelling-error" id="SPELLING_ERROR_26">JBoss</span> Seam as a "big hack", "annotation hell", "technologically inferior" and "would have been just another web <span class="blsp-spelling-corrected" id="SPELLING_ERROR_27">framework</span> were it not for Gavin King's fame".</li><li>Gavin is more straight forward, rubbished Spring guys as "<span class="blsp-spelling-error" id="SPELLING_ERROR_28">AOP</span> nerds" during the session, and I wouldn't be surprised if he called Spring "XML hell". He deliberately omitted Spring when he enumerated the open source frameworks that have influenced Java <span class="blsp-spelling-error" id="SPELLING_ERROR_29">EE</span>.</li></ul><li>The audience:</li><ul><li>Spring events usually draw a huge audience. Many times, some people who came late had to stand in the back of the room for the whole session. They are almost always held in the evening.</li><li>Today's Hibernate event was held in the morning with only a few dozen people attending. One-third of the seats were empty.</li></ul></ul><p>Anyway, I was pretty impressed by Gavin's demo of fast web project development with <span class="blsp-spelling-error" id="SPELLING_ERROR_30">JBoss</span> AS, <span class="blsp-spelling-error" id="SPELLING_ERROR_31">JBoss</span> Seam, Rich Faces and <span class="blsp-spelling-error" id="SPELLING_ERROR_32">JBoss</span> Tools. I'll definitely give it a try when I have the time...</p>Alex Weihttp://www.blogger.com/profile/16196507572911120081noreply@blogger.com3tag:blogger.com,1999:blog-2664528635822406543.post-65442496258319937792007-12-31T23:56:00.001+11:002008-12-25T00:07:17.419+11:00Hibernate: how to map a collection of embedded components keyed by one of the component's properties?<div>Quite often, during application development, I encounter the issue of mapping a collection of embedded components using Hibernate.</div><br /><div>An embedded component is, in Hibernate, a user-defined value-typed class. It has no individual identity, hence the persistent component class requires no identifier property or identifier mapping; its lifespan is bounded by the lifespan of the owning entity instance.</div><br /><div>When mapping a collection of embedded components, it is very important to override the <code>equals()</code> and <code>hashCode()</code> methods and compare all properties, because they are used by Hibernate to detect modifications to these components.</div><br /><div>Very often, this collection of components also has a unique key property, that is, the collection should normally be implemented as a map indexed by the value of the key property.</div><br /><div>The book "Java Persistence with Hibernate" and <a href="http://www.hibernate.org/hib_docs/reference/en/html/components.html">Hibernate's documentation</a> illustrate 3 ways to map a collection of embedded components.</div><br /><div>The first and highly recommended (by Hibernate) option is to map the collection to a <code>set</code>. This method requires all database columns mapped to the component class must be declared with <code>not-null="true"</code>. It does not address the key property issue, either. I myself often find it unwieldy when dealing with the key property because it becomes my responsibility to enforce the map semantics. For example, when adding a new element, I need to iterate the set and find the existing element having the same key property value with the new element. If the existing element is found, depending on the business rule, I may throw an exception, or remove the existing element from the set and add the new element in. When you have several entity classes that have component map, you have to duplicate the same set iteration logic in many places...</div><br /><div>The second option is to map the collection to an <code>idbag</code>. Again, it is the responsibility of my application to ensure the map semantics.</div><br /><div>The third option is to map it to a <code>map</code>. Unfortunately, this option requires the removal of the key property from the component class. The following is the example extracted from the above-mentioned book to demonstrate the mapping of the images belonging to an item in the Caveate Emptor sample application, where the image name must be unique.</div><br /><pre name="code" class="Xml"><map name="images"<br /> table="ITEM_IMAGE"<br /> order-by="IMAGENAME asc"><br /><br /> <key column="ITEM_ID"/><br /> <map-key type="string" column="IMAGENAME"/><br /> <composite-element class="Image"><br /> <property name="filename" column="FILENAME" not-null="true"/><br /> <property name="sizeX" column="SIZEX"/><br /> <property name="sizeY" column="SIZEY"/><br /> </composite-element><br /></map></pre><br /><div>As can be seen from the mapping file snippet above, the "Image" component class no longer has a "name" property. This removal can be quite problematic. The key property is usually the most important property of a component class; removing this property from the component class and handle it merely as a map key not only potentially violates object oriented technology principles theoretically, but also can have significant consequences in practice. For example, the public interface of the entity class may need to be overhauled. Instead of an <code>addImage(Image image)</code> method, you need to provide an <code>addImage(String imageName, Image image)</code> method. Or, you have to create another value-type class just in order to wrap the name-deprived Image and the image name together.</div><br /><div>Luckily, Hibernate 3.x provides a very powerful new feature called <strong>formula</strong>. This can easily solve our dilemma. It can map the component map to a <code>map</code>, but it does not require the removal of the key property from the component class. With <code>formula</code>, the above mapping can be modified to:</div><br /><pre name="code" class="Xml"><map name="images"<br /> table="ITEM_IMAGE"<br /> order-by="IMAGENAME asc"><br /><br /> <key column="ITEM_ID"/><br /> <map-key type="string" column="IMAGENAME"/><br /> <composite-element class="Image"><br /> <property name="name" type="string" formula="IMAGENAME"/><br /> <property name="filename" column="FILENAME" not-null="true"/><br /> <property name="sizeX" column="SIZEX"/><br /> <property name="sizeY" column="SIZEY"/><br /> </composite-element><br /></map></pre><br /><div>In short, it allows the "IMAGENAME" column to be mapped to both the map key and the key property of the "Image" class when loading from database. When persisting, only the map key is used to update the "IMAGENAME" column.</div><br /><div>Now we can map a map of embedded components to a map without sacrificing the key property or writing messy codes to enforce map semantics...</div>Alex Weihttp://www.blogger.com/profile/16196507572911120081noreply@blogger.com4tag:blogger.com,1999:blog-2664528635822406543.post-69858839824208096102007-11-02T22:55:00.000+11:002007-11-07T01:39:20.669+11:00classpath*:BeanRefFactory.xml not found when instantiating a singleton Spring application context inside EJB2.x running on Sun application server 8.2For the project I'm currently working on, we use Spring's EJB support. In order to share application context among all EJB instances, <span style="font-family:courier new;">SingletonBeanFactoryLocator</span> is used to locate or load the shared application context. And we used the default "classpath*:beanRefFactory.xml" selector key.<br /><br />However, when the EJB is deployed and invoked, a FatalBeanException is thrown stating <blockquote>Unable to find resource for specified definition. Group resource name<br />[classpath*:beanRefFactory.xml], factory key [...]</blockquote><br /><br />Looking into the implementation of <span style="font-family:courier new;">SingletonBeanFactoryLocator</span>, we found that it delegates to <span style="font-family:courier new;">PathMatchingResourcePatternResolver</span> to load the XML file. If the resource starts with "classpath*:" prefix, it uses <span style="font-family:courier new;">ClassLoader</span>'s <span style="font-family:courier new;">getResources(String)</span> method to load the resource; otherwise, a <span style="font-family:courier new;">ClasspathResource</span> is returned, which eventually uses <span style="font-family:courier new;">ClassLoader</span>'s <span style="font-family:courier new;">getResource(String)</span> method to load the resource. Pay attention to the plural form of the method name.<br /><br />In the base <span style="font-family:courier new;">java.lang.ClassLoader</span>, both <span style="font-family:courier new;">getResource(String)</span> and <span style="font-family:courier new;">getResources(String)</span> delegate to its parent first. If the resource is not found by the parent, it invokes <span style="font-family:courier new;">findResource(String)</span> and <span style="font-family:courier new;">findResources(String)</span> methods, both of which simply return null. The Javadoc of <span style="font-family:courier new;">ClassLoader</span> recommends that, for both finder methods: <blockquote>Class loader implementations should override this method to specify where to<br />load resources from.</blockquote><br /><br />However, when tracing the execution in debug mode, we found that the <span style="font-family:courier new;">EJBClassLoader</span> used by Sun Application Server 8.2 only overrides <span style="font-family:courier new;">findResource(String)</span> method and searches for the resource in the expanded directory of the EJB Jar file; it does not override <span style="font-family:courier new;">findResources(String)</span>, which remains returning null, against their own advice.<br /><br />Now it's obvious, this is due to a defect in Sun Application Server 8.2. The simplest solution is to specify the selector key as "classpath:beanRefFactory.xml" instead of the default value.Alex Weihttp://www.blogger.com/profile/16196507572911120081noreply@blogger.com1tag:blogger.com,1999:blog-2664528635822406543.post-83348356378757622672007-10-27T20:08:00.001+10:002008-12-25T00:09:19.417+11:00Integrating Spring, Hibernate and EJB 2.xHow to configure Hibernate Session Factory in a Spring application context used in an EJB 2.x stateless session bean?<br /><br />Most of the examples found on the internet about Hibernate and Spring integration are targeted at web applications. How to configure Hibernate and Spring inside an EJB 2.x stateless session bean is rarely mentioned, and it is not as simple and straightforward as many assume.<br /><br />The most important issue of the integration is around the management of JDBC connections:<br />In EJB 2.x, JDBC connections are managed by the data source registered with JNDI on the application server:<ul><br /><li>Applications are not expected to hold on JDBC connections after each use, that is, applications should aggressively release JDBC connections, preferrably after each statement.</li><br /><li>Applications can acquire JDBC connections multiple times during the execution of one EJB invocation. The application server may return the same JDBC connection, or it may return different JDBC connections, but it assures that all JDBC connections returned are registered within the same Container Managed Transaction.</li></ul><br /><br />When database is accessed outside EJB 2.x, such as in a web application running in Tomcat, the application itself is responsible for transaction demarcation. When using a local database transaction, the application code must ensure that the same JDBC connection be used in all database access within the same transaction. Because database access occurs in multiple classes that collaborate to complete a transaction, it is very unwieldy for applications to pass around the JDBC connection in order to re-use the same JDBC connection.<br /><br />Enter Spring and Hibernate.<br /><br />Spring guarantees the same JDBC connection is reused, provided the same Spring-managed data source is re-used. The magic happens when a JDBC connection is retrieved for the first time from a Spring-managed data source, Spring binds the JDBC connection to the current execution thread. When another JDBC connection is requested within the same transaction from the Spring-managed data source, Spring returns the thread-bound JDBC connection. When the transaction ends, Spring invokes the commit() or rollback() method of the thread-bound JDBC connection and then unbinds it from the thread.<br /><br />Hibernate 3.x employs similar technique. By default, a Hibernate session is bound to the thread and returned whenever SessionFactory.getCurrentSession() is invoked within the same transaction. The same JDBC connection is used for all JDBC operations initiated by the same Hibernate session. It is possible to specify other current session context class other than the default thread local context since Hibernate 3.1.<br /><br />As can be seen from the above discussion, Spring and Hibernate by default re-use the same thread-bound JDBC connection. This setting does not go well with the aggressive connection release mode expected by EJB 2.x. Therefore, non-default settings must be configured for both Spring and Hibernate for Spring and Hibernate combination to be integrated within EJB 2.x.<br /><br />Below is the recommended configuration. The reasons behind this configuration are explained following the configuration. <br /><br /><pre name="code" class="Xml"><jee:jndi-lookup id="dataSource"<br /> jndi-name="jdbc/datasource" resource-ref="true"/><br /><br /><bean id="transactionManager"<br /> class="org.springframework.transaction.jta.JtaTransactionManager"/><br /><br /><bean class="org.springframework.dao.annotation.PersistenceExceptionTranslationPostProcessor"/><br /><br /><bean id="sessionFactory"<br /> class="org.springframework.orm.hibernate3.LocalSessionFactoryBean"><br /> <property name="dataSource" ref="dataSource"/><br /><!-- default value is "false"<br /> <property name="useTransactionAwareDataSource" value="false"/><br />--><br /> <property name="exposeTransactionAwareSessionFactory" value="false"/><br /> <property name="hibernateProperties"><br /> <props><br /> <prop key="hibernate.dialect">org.hibernate.dialect.SomeDialect</prop><br /><!--<br /> WARNING! 'hibernate.connection.release_mode' must not be set to<br /> 'after_statement'. Otherwise, it will be overriden with 'after_transaction'<br /> by Hibernate because Spring's LocalConnectionProvider does not support<br /> aggressive connection release.<br />--> <br /> <prop key="hibernate.connection.release_mode">auto</prop><br /> <prop key="hibernate.current_session_context_class">jta</prop><br /> <prop key="hibernate.transaction.manager_lookup_class">org.hibernate.transaction.SunONETransactionManagerLookup</prop><br /> <prop key="hibernate.transaction.factory_class">org.hibernate.transaction.CMTTransactionFactory</prop><br /> <prop key="hibernate.transaction.flush_before_completion">true</prop><br /> <prop key="hibernate.transaction.auto_close_session">true</prop><br /> </props><br /> </property><br /> <property name="mappingResources"><br /> <list>...</list><br /> </property><br /></bean><br /></pre><br /><br />The reasons behind this configuration are explained below. It is recommended to have your IDE opened and source code of Spring and Hibernate 3.1 or above ready.<br /><br />Spring uses LocalSessionFactoryBean, which is a subclass of AbstractSessionFactoryBean, to configure a Hibernate session factory.<br /><br />There are lots of javadoc to read for each bean property that can be set for a LocalSessionFactoryBean. It's better off to read the buildSessionFactory() method to understand what each property value does in the build time.<br /><br />Note that the above configuration has two parts for LocalSessionFactoryBean, the 'normal' Spring bean properties, such as 'dataSource', and the 'hibernateProperties' that takes a java.util.Properties value. The 'normal' properties are used to configure the default settings, which can be overriden by the 'hibernateProperties'.<br /><br />As a side note, we don't set the 'jtaTransactionManager' property. Note that the class for this property is javax.transaction.TransactionManager, not the JtaTransactionManager that implements Spring's PlatformTransactionManager. In order to set this property, we need to know the JNDI name that the target application server binds its JTA transaction manager. The benefit of setting this property would be that we don't need to configure Hibernate's 'hibernate.transaction.manager_lookup_class' and 'hibernate.transaction.factory_class' properties. We concluded that this benefit could not justify explicitly specifying the application server specific JNDI name for transaction manager. We would rather set those two properties in Hibernate configuration.<br /><br />If 'jtaTransactionManager' property is not set, Spring automatically set the 'hibernate.connection.release_mode' property to 'on_close'. Because we are running Hibernate inside an EJB 2.x, we must set this property to other value in the overriding 'hibernateProperties'.<br /><br />The 'exposeTransactionAwareSessionFactory' property has a default value of true. If set to true, Spring will set the 'hibernate.current_session_context_class' property to Spring's own thread-bound implementation, which must be overriden by a value of 'jta' in the 'hibernateProperties'.<br /><br />The 'useTransactionAwareDataSource' property must be left to the default 'false' value. Otherwise, Spring will wrap the data source with a TransactionAwareDataSourceProxy, which will effectively re-use the same JDBC transaction within the same transaction, even if Hibernate aggressively releases connections.<br /><br />It must be pointed out that when 'useTransactionAwareDataSource' is set to false, Spring will supply LocalDataSourceConnectionProvider as the implementation of Hibernate's ConnectionProvider. LocalDataSourceConnectionProvider informs Hibernate that it does not support aggressive release of connection. However, in Hibernate's SettingsFactory, if the ConnectionProvider does not support aggressive release of connections and connection release mode is set to 'after_statement', the connection release mode will be automatically rectified to 'after_transaction', which effectively re-uses the same JDBC transaction for the whole transaction. A warning message "Overriding release mode as connection provider does not support 'after_statement'" is logged. Therefore, the connection release mode in the 'hibernateProperties' must be set to 'auto' instead of 'after_statement'. When the transaction factory is set to 'CMTTransactionFactory', the default connection release mode is 'after_statement', which is precisely what we want.<br /><br />The other property settings are self-explanatory:<ul><br /><li> 'hibernate.current_session_context_class' should be set to 'jta'.</li><br /><li> 'hibernate.transaction.manager_lookup_class' should be set the a class mapped to the target application server.</li><br /><li> 'hibernate.transaction.factory_class' should be set to 'org.hibernate.transaction.CMTTransactionFactory'.</li></ul><br /><br />I hope this post will help anyone who has encountered mysterious connection problems when integrating Spring, Hibernate and EJB 2.xAlex Weihttp://www.blogger.com/profile/16196507572911120081noreply@blogger.com7tag:blogger.com,1999:blog-2664528635822406543.post-3936675018644900142007-10-25T19:35:00.000+10:002007-10-30T00:50:19.218+11:00Cryptic JTS5031 and JTS5068 errors on Sun Application Server 8.1 and 8.2We encountered the following exceptions when testing our EJB 2.1 + Spring + Hibernate + Osworkflow (also using Hibernate) application.<br /><br />When running on Sun Application Server 8.1 EE, the stack trace is listed below:<br /><pre class="alt2" dir="ltr" style="BORDER-RIGHT: 1px inset; PADDING-RIGHT: 6px; BORDER-TOP: 1px inset; PADDING-LEFT: 6px; PADDING-BOTTOM: 6px; MARGIN: 0px; OVERFLOW: auto; BORDER-LEFT: 1px inset; WIDTH: 580px; PADDING-TOP: 6px; BORDER-BOTTOM: 1px inset; HEIGHT: 480px; TEXT-ALIGN: left">[#2007-10-25T10:50:34.347+1000FINEsun-appserver-ee8.1_02javax.enterprise.resource.jta_ThreadID=13;TM: enlistComponentResources#]<br />[#2007-10-25T10:50:34.400+1000FINEsun-appserver-ee8.1_02javax.enterprise.resource.jta_ThreadID=13;--Created new J2EETransaction, txId = 25#]<br />[#2007-10-25T10:50:34.400+1000FINEsun-appserver-ee8.1_02javax.enterprise.resource.jta_ThreadID=13;TM: enlistComponentResources#]<br />[#2007-10-25T10:50:34.401+1000FINEsun-appserver-ee8.1_02javax.enterprise.resource.jta_ThreadID=13;<br />In J2EETransactionManagerOpt.enlistResource, h=5 h.xares=com.sun.gjc.spi.XAResourceImpl@c21e52 h.alloc=com.sun.enterprise.resource.ConnectorAllocator@54d24d tx=J2EETransaction: txId=25 nonXAResource=null jtsTx=null localTxStatus=0 syncs=[]#]<br />[#2007-10-25T10:50:34.401+1000FINEsun-appserver-ee8.1_02javax.enterprise.resource.jta_ThreadID=13;TM: begin#]<br />[#2007-10-25T10:50:34.402+1000FINEsun-appserver-ee8.1_02javax.enterprise.system.core.transaction_ThreadID=13;Control object :com.sun.jts.CosTransactions.ControlImpl@162aeda corresponding to this transaction has been createdGTID is : 19000000BBF79CD4616476627661707030312C5033373030#]<br />[#2007-10-25T10:50:34.402+1000FINEsun-appserver-ee8.1_02javax.enterprise.resource.jta_ThreadID=13;TM: enlistResource#]<br />[#2007-10-25T10:50:34.402+1000FINEsun-appserver-ee8.1_02javax.enterprise.resource.jta_ThreadID=13;--In J2EETransaction.enlistResource, jtsTx=com.sun.jts.jta.TransactionImpl@ffe966e9 nonXAResource=null#]<br />[#2007-10-25T10:50:34.404+1000FINEsun-appserver-ee8.1_02javax.enterprise.resource.jta_ThreadID=13;--In J2EETransaction.registerSynchronization, jtsTx=com.sun.jts.jta.TransactionImpl@ffe966e9 nonXAResource=null#]<br />[#2007-10-25T10:50:34.405+1000FINEsun-appserver-ee8.1_02javax.enterprise.resource.jta_ThreadID=13;--In J2EETransaction.registerSynchronization, jtsTx=com.sun.jts.jta.TransactionImpl@ffe966e9 nonXAResource=null#]<br />[#2007-10-25T10:50:34.406+1000FINEsun-appserver-ee8.1_02javax.enterprise.resource.jta_ThreadID=13;TM: delistResource#]<br />[#2007-10-25T10:50:34.406+1000FINEsun-appserver-ee8.1_02javax.enterprise.resource.jta_ThreadID=13; ejbDestroyed: AccountProcessServiceBean; id: [B@7219a#]<br />[#2007-10-25T10:50:34.406+1000FINEsun-appserver-ee8.1_02javax.enterprise.resource.jta_ThreadID=13;TM: rollback#]<br />[#2007-10-25T10:50:34.406+1000FINEsun-appserver-ee8.1_02javax.enterprise.system.core.transaction_ThreadID=13;Within TopCoordinator.rollback() :GTID is : 19000000BBF79CD4616476627661707030312C5033373030#]<br />[#2007-10-25T10:50:34.409+1000SEVEREsun-appserver-ee8.1_02javax.enterprise.system.core.transaction_ThreadID=13;JTS5031: Exception [org.omg.CORBA.INTERNAL: vmcid: 0x0 minor code: 0 completed: Maybe] on Resource [rollback] operation.#]<br />[#2007-10-25T10:50:34.410+1000FINEsun-appserver-ee8.1_02javax.enterprise.system.container.ejb_ThreadID=13;context with empty container in ContainerSynchronization.afterCompletion#]<br />[#2007-10-25T10:50:34.410+1000FINEsun-appserver-ee8.1_02javax.enterprise.system.core.transaction_ThreadID=13;Within TopCoordinator.rollback() :GTID is : 19000000BBF79CD4616476627661707030312C5033373030#]<br />[#2007-10-25T10:50:34.411+1000FINEsun-appserver-ee8.1_02javax.enterprise.system.container.ejb_ThreadID=13;EJB5092:Exception occurred in postInvokeTx : [{0}]<br />javax.transaction.SystemException: org.omg.CORBA.INTERNAL: JTS5031: Exception [org.omg.CORBA.INTERNAL: vmcid: 0x0 minor code: 0 completed: Maybe] on Resource [rollback] operation. vmcid: 0x0 minor code: 0 completed: No<br /> at com.sun.jts.jta.TransactionManagerImpl.rollback(TransactionManagerImpl.java:295)<br /> at com.sun.enterprise.distributedtx.J2EETransactionManagerImpl.rollback(J2EETransactionManagerImpl.java:1054)<br /> at com.sun.enterprise.distributedtx.J2EETransactionManagerOpt.rollback(J2EETransactionManagerOpt.java:391)<br /> at com.sun.ejb.containers.BaseContainer.completeNewTx(BaseContainer.java:2711)<br /> at com.sun.ejb.containers.BaseContainer.postInvokeTx(BaseContainer.java:2521)<br /> at com.sun.ejb.containers.BaseContainer.postInvoke(BaseContainer.java:819)<br /> at com.sun.ejb.containers.EJBLocalObjectInvocationHandler.invoke(EJBLocalObjectInvocationHandler.java:137)<br /> at $Proxy22.processUser(Unknown Source)<br /> at au.net.ozgwei.services.userprocess.UserProcessServiceDelegate.processUser(UserProcessServiceDelegate.java:96)<br />...<br />[#2007-10-25T10:50:34.414+1000INFOsun-appserver-ee8.1_02javax.enterprise.system.container.ejb_ThreadID=13;EJB5018: An exception was thrown during an ejb invocation on [UserProcessServiceBean]#]<br /></pre><br /><br />When running on Sun Application Server 8.2 PE, the stack trace is listed below:<br /><pre class="alt2" dir="ltr" style="BORDER-RIGHT: 1px inset; PADDING-RIGHT: 6px; BORDER-TOP: 1px inset; PADDING-LEFT: 6px; PADDING-BOTTOM: 6px; MARGIN: 0px; OVERFLOW: auto; BORDER-LEFT: 1px inset; WIDTH: 580px; PADDING-TOP: 6px; BORDER-BOTTOM: 1px inset; HEIGHT: 480px; TEXT-ALIGN: left">[#2007-10-25T17:52:04.079+1000INFOsun-appserver-pe8.2javax.enterprise.system.stream.out_ThreadID=14;454609 [httpWorkerThread-2189-4] INFO org.hibernate.impl.SessionFactoryObjectFactory - Not binding factory to JNDI, no JNDI name configured<br />#]<br />[#2007-10-25T17:52:04.079+1000INFOsun-appserver-pe8.2javax.enterprise.system.stream.out_ThreadID=14;454609 [httpWorkerThread-2189-4] INFO org.hibernate.util.NamingHelper - JNDI InitialContext properties:{}<br />#]<br />[#2007-10-25T17:52:04.079+1000INFOsun-appserver-pe8.2javax.enterprise.system.stream.out_ThreadID=14;454609 [httpWorkerThread-2189-4] INFO org.springframework.context.support.ClassPathXmlApplicationContext - Bean 'siteManagerSessionFactory' is not eligible for getting processed by all BeanPostProcessors (for example: not eligible for auto-proxying)<br />#]<br />[#2007-10-25T17:52:04.110+1000INFOsun-appserver-pe8.2javax.enterprise.system.stream.out_ThreadID=14;454640 [httpWorkerThread-2189-4] INFO org.springframework.context.support.ClassPathXmlApplicationContext - Bean 'org.springframework.dao.annotation.PersistenceExceptionTranslationPostProcessor' is not eligible for getting processed by all BeanPostProcessors (for example: not eligible for auto-proxying)<br />#]<br />[#2007-10-25T17:52:04.110+1000INFOsun-appserver-pe8.2javax.enterprise.system.stream.out_ThreadID=14;454640 [httpWorkerThread-2189-4] INFO org.springframework.beans.factory.support.DefaultListableBeanFactory - Pre-instantiating singletons in org.springframework.beans.factory.support.DefaultListableBeanFactory@1956ba5: defining beans [siteManager,siteRepository,siteAssembler,org.springframework.dao.annotation.PersistenceExceptionTranslationPostProcessor,dataSource,transactionManager,siteManagerSessionFactory,eventLogService]; root of factory hierarchy<br />#]<br />[#2007-10-25T17:52:05.207+1000INFOsun-appserver-pe8.2javax.enterprise.system.stream.out_ThreadID=14;455737 [httpWorkerThread-2189-4] INFO org.springframework.transaction.jta.JtaTransactionManager - Using JTA UserTransaction: com.sun.enterprise.distributedtx.UserTransactionImpl@ad9064<br />#]<br />[#2007-10-25T17:52:05.207+1000INFOsun-appserver-pe8.2javax.enterprise.system.stream.out_ThreadID=14;455737 [httpWorkerThread-2189-4] INFO org.springframework.transaction.jta.JtaTransactionManager - Using JTA TransactionManager: com.sun.ejb.containers.PMTransactionManagerImpl@1eafdce<br />#]<br />[#2007-10-25T17:52:26.027+1000WARNINGsun-appserver-pe8.2javax.enterprise.system.core.transaction_ThreadID=15;JTS5068: Unexpected error occurred in rollback<br />java.lang.NullPointerException<br /> at com.sun.gjc.spi.ManagedConnection.transactionCompleted(ManagedConnection.java:429)<br /> at com.sun.gjc.spi.XAResourceImpl.rollback(XAResourceImpl.java:140)<br /> at com.sun.jts.jta.TransactionState.rollback(TransactionState.java:168)<br /> at com.sun.jts.jtsxa.OTSResourceImpl.rollback(OTSResourceImpl.java:271)<br /> at com.sun.jts.CosTransactions.RegisteredResources.distributeRollback(RegisteredResources.java:971)<br /> at com.sun.jts.CosTransactions.TopCoordinator.rollback(TopCoordinator.java:2240)<br /> at com.sun.jts.CosTransactions.CoordinatorTerm.rollback(CoordinatorTerm.java:504)<br /> at com.sun.jts.CosTransactions.TerminatorImpl.rollback(TerminatorImpl.java:266)<br /> at com.sun.jts.CosTransactions.CurrentImpl.rollback(CurrentImpl.java:728)<br /> at com.sun.jts.jta.TransactionManagerImpl.rollback(TransactionManagerImpl.java:308)<br /> at com.sun.enterprise.distributedtx.J2EETransactionManagerImpl.rollback(J2EETransactionManagerImpl.java:1058)<br /> at com.sun.enterprise.distributedtx.J2EETransactionManagerOpt.rollback(J2EETransactionManagerOpt.java:391)<br /> at com.sun.ejb.containers.BaseContainer.completeNewTx(BaseContainer.java:2711)<br /> at com.sun.ejb.containers.BaseContainer.postInvokeTx(BaseContainer.java:2521)<br /> at com.sun.ejb.containers.BaseContainer.postInvoke(BaseContainer.java:819)<br /> at com.sun.ejb.containers.EJBLocalObjectInvocationHandler.invoke(EJBLocalObjectInvocationHandler.java:137)<br /> at $Proxy22.processUser(Unknown Source)<br /> at au.net.ozgwei.services.userprocess.UserProcessServiceDelegate.processUser(UserProcessServiceDelegate.java:96)<br /></pre><br /><p>These exceptions were really frustrating as they appeared to occur only at transaction commit time that somehow the commit failed and the EJB container was trying to roll back and then encountered an unexpected CORBA or null pointer error.</p><p>That led us to think that our configuration for Spring and Hibernate to work with EJB 2.1 was not set up properly.</p><p>Well, all that was just red herring. With debugging turned on, it was clear to us that a minor and seemingly innocent change in the web tier resulted in invoking the EJB with illegal arguments and that the POJO implementation wrapped by the EJB threw an <span style="font-family:courier new;">IllegalArgumentException</span>, which was swallowed by Sun's EJB container and triggered the transaction to be rolled back.</p><p>Once we fixed the bug at the web tier, the issue went away immediately.</p><p>So, the problem is with Sun's EJB container: when it catches a runtime exception, it should have printed the stack trace of the root cause of the exception instead of swallowing it. It wasted us several hours to figure out what went wrong.</p><p>It also taught us a few lessons:</p><ol><li>Debug early on may save you many hours of code reading and googling for a problem that was hidden/eclipse by a seemingly complex problem.</li><li>Write more test cases for web tier codes, preferably with EasyMock 2 or jMock 2. If we had written the test cases for the UI, this problem would probably occur in the first place.</li></ol><p>So, if you see similar JTS5031 or JTS5068 errors on Sun Application Server 8.x, make sure you do some debugging to verify that it was not caused by a runtime exception thrown by your application code...</p><p> </p>Alex Weihttp://www.blogger.com/profile/16196507572911120081noreply@blogger.com0tag:blogger.com,1999:blog-2664528635822406543.post-29894597916606368512007-09-28T20:28:00.001+10:002008-12-25T00:10:44.642+11:00Spring 2.0 schemas not found? And the solution is...We've experienced a mysterious problem that the Spring 2.0 schemas could not be found when the application context is being created inside an EJB 2.1, using Spring's AbstractStatelessSessionBean.<br /><br />The problem manifests itself with the following exception:<br /><pre class="alt2" dir="ltr" style="border: 1px inset ; margin: 0px; padding: 6px; overflow: auto; width: 540px; height: 80px; text-align: left;">org.springframework.beans.factory.xml.XmlBeanDefinitionStoreException: Line 18 in XML document from class path resource [springContext.xml] is invalid; nested exception is org.xml.sax.SAXParseException: cvc-elt.1: Cannot find the declaration of element 'beans'.<br />Caused by:<br />org.xml.sax.SAXParseException: cvc-elt.1: Cannot find the declaration of element 'beans'.<br /> at org.apache.xerces.util.ErrorHandlerWrapper.createSAXParseException(Unknown Source)<br /> at org.apache.xerces.util.ErrorHandlerWrapper.error(Unknown Source)</pre><br /><br />Normally this is caused by the incorrect XML namespace or schema location declaration at the head of the application context. However, in our case, the declaration was correct:<br /><pre name="code" class="Xml"><?xml version="1.0" encoding="UTF-8"?><br /><beans xmlns="http://www.springframework.org/schema/beans"<br /> xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"<br /> xmlns:aop="http://www.springframework.org/schema/aop"<br /> xmlns:jee="http://www.springframework.org/schema/jee"<br /> xmlns:tx="http://www.springframework.org/schema/tx"<br /> xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans-2.0.xsd<br /> http://www.springframework.org/schema/aop http://www.springframework.org/schema/aop/spring-aop-2.0.xsd<br /> http://www.springframework.org/schema/jee http://www.springframework.org/schema/jee/spring-jee-2.0.xsd<br /> http://www.springframework.org/schema/tx http://www.springframework.org/schema/tx/spring-tx-2.0.xsd"><br />...<br /></bean><br /></pre><br /><br />After some research, we found that <a href="http://forum.springframework.org/showthread.php?t=39979&highlight=spring.schemas+beans#6738101512460349867">other</a> <a href="http://www.jroller.com/hugolima/entry/schema_n%C3%A3o_encontrado_no_spring">people</a> <a href="http://www.blogjava.net/SimonLei/">have also experienced this problem</a>.<br /><br />The cause is that somehow the "META-INF/spring.schemas" and "META-INF/spring.handlers" files packaged in spring.jar could not be found.<br /><br />What are these two files?<ul><li>"spring.schemas" specifies the classpaths of all Spring schemas within the spring.jar. The content of this file is listed below:</li></ul><br /><pre class="alt2" dir="ltr" style="border: 1px inset ; margin: 0px; padding: 6px; overflow: auto; width: 540px; height: 160px; text-align: left;">http\://www.springframework.org/schema/beans/spring-beans-2.0.xsd=org/springframework/beans/factory/xml/spring-beans-2.0.xsd<br />http\://www.springframework.org/schema/tool/spring-tool-2.0.xsd=org/springframework/beans/factory/xml/spring-tool-2.0.xsd<br />http\://www.springframework.org/schema/util/spring-util-2.0.xsd=org/springframework/beans/factory/xml/spring-util-2.0.xsd<br />http\://www.springframework.org/schema/aop/spring-aop-2.0.xsd=org/springframework/aop/config/spring-aop-2.0.xsd<br />http\://www.springframework.org/schema/lang/spring-lang-2.0.xsd=org/springframework/scripting/config/spring-lang-2.0.xsd<br />http\://www.springframework.org/schema/tx/spring-tx-2.0.xsd=org/springframework/transaction/config/spring-tx-2.0.xsd<br />http\://www.springframework.org/schema/jee/spring-jee-2.0.xsd=org/springframework/ejb/config/spring-jee-2.0.xsd<br /><br />http\://www.springframework.org/schema/beans/spring-beans.xsd=org/springframework/beans/factory/xml/spring-beans-2.0.xsd<br />http\://www.springframework.org/schema/tool/spring-tool.xsd=org/springframework/beans/factory/xml/spring-tool-2.0.xsd<br />http\://www.springframework.org/schema/util/spring-util.xsd=org/springframework/beans/factory/xml/spring-util-2.0.xsd<br />http\://www.springframework.org/schema/aop/spring-aop.xsd=org/springframework/aop/config/spring-aop-2.0.xsd<br />http\://www.springframework.org/schema/lang/spring-lang.xsd=org/springframework/scripting/config/spring-lang-2.0.xsd<br />http\://www.springframework.org/schema/tx/spring-tx.xsd=org/springframework/transaction/config/spring-tx-2.0.xsd<br />http\://www.springframework.org/schema/jee/spring-jee.xsd=org/springframework/ejb/config/spring-jee-2.0.xsd</pre><br /><ul><li>"spring.handlers" specifies the handler class that implements the NamespaceHandler interface for each namespace. The content of this file is listed below:<br /></li></ul><br /><pre class="alt2" dir="ltr" style="border: 1px inset ; margin: 0px; padding: 6px; overflow: auto; width: 540px; height: 80px; text-align: left;">http\://www.springframework.org/schema/util=org.springframework.beans.factory.xml.UtilNamespaceHandler<br />http\://www.springframework.org/schema/aop=org.springframework.aop.config.AopNamespaceHandler<br />http\://www.springframework.org/schema/lang=org.springframework.scripting.config.LangNamespaceHandler<br />http\://www.springframework.org/schema/tx=org.springframework.transaction.config.TxNamespaceHandler<br />http\://www.springframework.org/schema/jee=org.springframework.ejb.config.JeeNamespaceHandler<br />http\://www.springframework.org/schema/p=org.springframework.beans.factory.xml.SimplePropertyNamespaceHandler<br /></pre><br />One raised the <a href="http://forum.springframework.org/showthread.php?t=39979&highlight=spring.schemas+beans#6738101512460349867">topic</a> in Spring's support forum that it was because of no internet access for the application server to access the schemas over the internet. Another post even provided a <a href="http://www.jroller.com/hugolima/entry/schema_n%C3%A3o_encontrado_no_spring">solution</a> to reference the schemas using classpath prefix directly in the application context configuration files.<br /><br />However, that's not the root cause and a good solution, because even if the application server can access the schemas over the internet or via classpath prefix, the bootstrap code still cannot access the "spring.handlers" file and would not know how to handle various namespaces other than the default "beans".<br /><br />In fact, the root cause is that the META-INF directory of a can be blocked when referenced inside an EJB jar.<br /><br />I tried a few ways to get around this problem, and the final solution I adopted is to extract these two files and put them in the META-INF directory of a JAR file that contains only this directory, and place this JAR file in the lib/ext directory of the application server domain where the application is deployed.<br /><br />I hope this would help others who may face this problem.Alex Weihttp://www.blogger.com/profile/16196507572911120081noreply@blogger.com11tag:blogger.com,1999:blog-2664528635822406543.post-42770791963621216162007-09-25T00:41:00.000+10:002007-09-25T00:53:15.745+10:00Nice improvements in NetBeans 6.0<a href="http://www.netbeans.org/community/releases/60/index.html">NetBeans 6.0 Beta 1</a> has been released since last week.<br /><br />There are a few nice improvements that I have been waiting for:<br /><br />1) Different font style for different scoped variables.<br />In NetBeans 5.5.1 and earlier versions, all variables have the default black colour, unlike Eclipse, which displays instance variables in blue and static variables in italic.<br />NetBeans 6.0 has finally caught up. Now the instance variables are in green and static variables/methods are also italic.<br /><br />2) Visual JSF page editing now supports message resource bundles.<br />Previously, when using visual editing of a JSF page, if you need to display a label with text from a resource bundle, you have to manually edit the JSP pages. The resulting components are not displayed on the canvas.<br />This has been improved. Now these components are displayed on the canvas with the text from the default base.<br /><br />Nice, isn't it? I may consider switching from MyEclipse to NetBeans 6.0 when it's finally out.Alex Weihttp://www.blogger.com/profile/16196507572911120081noreply@blogger.com0tag:blogger.com,1999:blog-2664528635822406543.post-47756677423372882942007-09-19T23:57:00.000+10:002007-09-27T01:52:33.040+10:00Won an IntelliJ IDEA 6.0 licence!Tonight I went to the Sydney Java User Group's Lightning Talks Night hosted by Atlassian, and won the random audience draw. Among three rewards: a Sun umbrella, a "Java Concurrency in Practice" book and an IntelliJ IDEA licence, I chose IntelliJ IDEA, since: 1) who needs an umbrella in Sydney? 2) I have already got that book, though I haven't started reading...<br /><br />I used IntelliJ at work previously. But we switched to <a href="http://www.myeclipseide.com">MyEclipse</a>, mainly because it's easier to find developers with <a href="http://www.eclipse.org">Eclipse</a> experience on the market, and also because the licence is much cheaper.<br /><br />IntelliJ IDEA is actually a pretty cool IDE. One of the plugins I'd like to try out is the <a href="http://grails.org">Grails</a> plugin...<br /><br />I'm also playing with <a href="http://www.netbeans.org">NetBeans</a> 6.0. The beta 1 has just been released.<br /><br />If I have time, I will try to blog about my experience with these IDEs: Eclipse (and MyEclipse), IDEA and NetBeans...Alex Weihttp://www.blogger.com/profile/16196507572911120081noreply@blogger.com0tag:blogger.com,1999:blog-2664528635822406543.post-64923005842683699402007-08-28T20:18:00.002+10:002008-12-25T00:34:44.383+11:00Developer-friendly JAXB code generation with JAXB Commons and binding fileIn my previous post "<a href="http://ozgwei.blogspot.com/2007/08/defining-servicecomponent-interfaces-in.html">Defining service/component interfaces in WSDLs</a>", I mentioned that "Not only are no-argument constructors and all public getter and setter methods generated for complex types, but also other useful methods, such as valued constructors, builder methods, hashCode, equals and toString methods can be implemented using XJC extensions." This post is about how to do this.<br /><br />Our project uses <a href="http://xfire.codehaus.org/Client+and+Server+Stub+Generation+from+WSDL">XFire's WsGenTask</a> Ant task to generate service interfaces, DTO classes and exceptions from WSDL file and the referenced XSD files. WsGenTask delegates the generation of DTO classes to <a href="http://java.sun.com/webservices/docs/2.0/jaxb/xjc.html">JAXB's XJC</a> compiler. However, these DTO classes generated by JAXB XJC's default are not particularly developer-friendly, in the following aspects:<br /><ol><li>They have only one default constructor. This is quite inconvenient when you need to instantiate a DTO to hold some values:</li><br /><ul><li>You need to declare a local variable, which may otherwise be unnecessary.</li><br /><li>You need to call the constructor to instantiate a new instance, then you need to invoke the setter methods for each property value you would like to it to hold.</li><br /><li>To re-use the code and get rid of the local variable declaration, you need to create a factory class with one or more overloading create methods for each DTO class, which essentially are value-taking constructors moved to a factory class.</li></ul><br /><li>They do not override the hashCode(), equals(Object) and toString() methods of the Object class. DTOs are value objects and no identity. Two instances holding exactly the same data should be considered interchangeable. Thus, overriding hashCode() and equals(Object) is essential for DTO classes. Moreover, not overriding toString() implementation makes it inconvenient in unit testing:</li><br /><ul><li>You cannot invoke assertEquals(Object, Object) directly. You have to rely on a static method to determine whether two objects are equal in values. And if the assertion fails, you need to invoke another static method to have a useful string representation of both the expected and actual objects.</li></ul><br /><li>Default values are not honoured in the generated classes, that means you have to set the value explicitly even if you are using a default value in most cases.</li><br /><li>If you are not the owner of the schemas being used, the class and property names generated may not be following the Java's camel-case conventions.</li><li>There is no setter method for collections. You need to invoke the getter method to retrieve the collection and invoke the addAll(Collection) method to add all elements of the prepared collection.</li><br /><li>If an element has a maxOccurs attribute value greater than one, the getter method generated is not using plural by default.</li><br /><li>Date, time and dateTime are generated as XMLGregorianCalendar, which requires constant conversion to and from the java.util.Date and java.util.Calendar values you use in your domain models.</li></ol><br />Fortunately, XJC has an extension option that allows third-party extensions. A whole bunch of XJC plugins have been developed to iron out most of these isses in the open source community, and many of them are under the <a href="https://jaxb2-commons.dev.java.net/">JAXB 2.0 Commons</a> project hosted by java.net.<br /><br />Many of the these plugins are very useful:<br /><ol><li>The <a href="https://jaxb2-commons.dev.java.net/default-value/">Value Constructor plugin</a> generates a constructor that takes values for all properties besides the default no-argument constructor.</li><br /><li>If you have many properties in a DTO class, or some of the properties are optional, you can use the <a href="https://jaxb2-commons.dev.java.net/fluent-api/">Fluent API plugin</a>, which generates builder-styled methods, which essentially provides named-parameter constructor, which is not provided by Java.</li><br /><li>The <a href="https://jaxb2-commons.dev.java.net/commons-lang-plugin/">jakarta-commons-lang plugin</a> generates overriding hashCode(), equals(Object) and toString() methods using jakarta commons lang's HashCodeBuilder, EqualsBuilder and ToStringBuilder classes, which in turn uses reflection.</li><br /><li>The <a href="https://jaxb2-commons.dev.java.net/default-value/">Default Value plugin</a> honours the default values specified in the schemas.</li><br /><li>The <a href="https://jaxb2-commons.dev.java.net/camelcase-always/">CamelCase Always plugin</a> generates class and property names following the camel-case convention.</li><br /><li>The <a href="https://jaxb2-commons.dev.java.net/collection-setter-injector/">Collection Setter Injection plugin</a> generates setter methods for collections.</li></ol><br /><br />Unfortunately, at the time of this writing, XFire's WsGen does not pass parameters to JAXB's XJC, as tracked by this <a href="http://jira.codehaus.org/browse/XFIRE-1038">XFIRE-1038</a> JIRA. The way to get around it is to call the XJCTask Ant task after the WsGenTask call and overwrite all DTOs generated by WsGenTask.<br /><br />Note that some of the plugins required JAXB 2.1 to work. If you intend to use JAXB 2.0 in runtime environment, it is fine: you can generate the classes using JAXB 2.1 with the target specified as "2.0" to avoid generating annotations introduced in JAXB 2.1.<br /><br />To generate a plural form for collections, use a simple JAXB binding file with XJCTask.<br /><br />If you would like to work with java.util.Date or java.util.Calendar instead of XMLGregorianCalendar, you can provide your own parseMethod and printMethod and specify them in your JAXB binding file used by XJCTask, as detailed by Sun's engineer <a href="http://weblogs.java.net/blog/kohsuke/archive/2006/03/how_do_i_map_xs.html">Kohsuke's blog entry</a>.<br /><br />Follwing are extracted from the ant build file to illustrate how to generate developer-friendly DTO classes using JAXB:<br /><blockquote><pre name="code" class="Xml"><br /> <!-- This task will autogenerate the code from the XSD specification --><br /> <taskdef name="xjc" classname="com.sun.tools.xjc.XJCTask" ><br /> <classpath><br /> <pathelement path="${jaxb1-impl-2.1.3.jar}:${jaxb-api-2.1.3.jar}:${jaxb-impl-2.1.3.jar}:${jaxb-xjc-2.1.3.jar}" /><br /> <pathelement path="${jaxb2-commons-commons-lang-plugin.jar}"/><br /> <pathelement path="${jaxb2-commons-value-constructor.jar}"/><br /> <pathelement path="${jaxb2-commons-fluent-api.jar}"/><br /> <pathelement path="${jaxb2-commons-default-value-plugin.jar}"/><br /> <pathelement path="${jaxb2-commons-collection-setter-injector.jar}"/><br /> <pathelement path="${component.classpath}" /><br /> </classpath><br /> </taskdef><br /><br /> <!-- This task will autogenerate the code from the WSDL specification --><br /> <taskdef name="wsgen" classname="org.codehaus.xfire.gen.WsGenTask" ><br /> <classpath><br /> <pathelement path="${component.classpath}" /><br /> </classpath><br /> </taskdef><br /><br /> <!-- Auto generate classes based on the XSD definitions using JAXB bindings --><br /> <target name="xjc_gen"><br /> <mkdir dir="${component.autogen_src}"/><br /> <delete><br /> <fileset dir="${component.autogen_src}"<br /> excludes="**/service/**/*.java"/><br /> </delete><br /> <xjc destdir="${component.autogen_src}" target="2.0" extension="true"><br /> <arg value="-Xcommons-lang"/><br /> <arg value="-Xvalue-constructor"/><br /> <arg value="-Xfluent-api"/><br /> <arg value="-Xcollection-setter-injector"/><br /> <arg value="-Xdefault-value"/><br /> <schema dir="${component.home}/src/conf/wsdl" includes="*.xsd"/><br /> <binding file="${component.home}/src/conf/wsdl/simple.xjb"/><br /> </xjc><br /> </target><br /><br /> <!-- Auto generate interfaces and classes based on the WSDL definitions using JAXB bindings --><br /> <target name="wsdl_gen"><br /> <mkdir dir="${component.autogen_src}"/><br /> <wsgen outputDirectory="${component.autogen_src}"<br /> wsdl="${component.home}/src/conf/wsdl/service-foo.wsdl"<br /> package="com.blogspot.ozgwei.service.foo"<br /> overwrite="true"<br /> binding="jaxb"<br /> externalBindings="${component.home}/src/conf/wsdl/simple.xjb"<br /> /><br /> <wsgen outputDirectory="${component.autogen_src}"<br /> wsdl="${component.home}/src/conf/wsdl/service-bar.wsdl"<br /> package="com.blogspot.ozgwei.service.bar"<br /> overwrite="true"<br /> binding="jaxb"<br /> externalBindings="${component.home}/src/conf/wsdl/simple.xjb"<br /> /><br /> </target><br /> <br /> <!-- Build all user, autogenerated and test code --><br /> <target name="compile" depends="wsdl_gen, xjc_gen"><br /> ...<br /> </target><br /></pre></blockquote><br /><br />The next is the content of the simple.xjb file for JAXB Binding, which use java.util.Calendar:<br /><blockquote><pre name="code" class="Xml"><br /><!--<br /> This enables the simple binding mode in JAXB.<br /> See http://weblogs.java.net/blog/kohsuke/archive/2006/03/simple_and_bett.html<br />--><br /><jaxb:bindings jaxb:version="2.0" jaxb:extensionBindingPrefixes="xjc"<br /> xmlns:jaxb="http://java.sun.com/xml/ns/jaxb"<br /> xmlns:xjc="http://java.sun.com/xml/ns/jaxb/xjc"<br /> xmlns:xs="http://www.w3.org/2001/XMLSchema"><br /> <jaxb:globalBindings><br /> <xjc:simple/><br /> <jaxb:javaType name="java.util.Calendar" xmlType="xs:date"<br /> parseMethod="javax.xml.bind.DatatypeConverter.parseDate"<br /> printMethod="javax.xml.bind.DatatypeConverter.printDate"/><br /> <jaxb:javaType name="java.util.Calendar" xmlType="xs:time"<br /> parseMethod="javax.xml.bind.DatatypeConverter.parseTime"<br /> printMethod="javax.xml.bind.DatatypeConverter.printTime"/><br /> <jaxb:javaType name="java.util.Calendar" xmlType="xs:dateTime"<br /> parseMethod="javax.xml.bind.DatatypeConverter.parseDateTime"<br /> printMethod="javax.xml.bind.DatatypeConverter.printDateTime"/><br /> </jaxb:globalBindings><br /></jaxb:bindings><br /></pre></blockquote><br /><br />If you prefer to use java.util.Date instead of java.util.Calendar, define the following class and change the binding file accordingly:<br /><blockquote><pre name="code" class="Java"><br />package com.blogspot.ozgwei.jaxb<br /><br />import java.util.Date;<br />import javax.xml.bind.DatatypeConverter;<br /><br />public class DateConverter {<br /><br /> public static Date parseDate(String s) {<br /> return DatatypeConverter.parseDate(s).getTime();<br /> }<br /><br /> public static Date parseTime(String s) {<br /> return DatatypeConverter.parseTime(s).getTime();<br /> }<br /><br /> public static Date parseDateTime(String s) {<br /> return DatatypeConverter.parseDateTime(s).getTime();<br /> }<br /><br /> public static String printDate(Date dt) {<br /> Calendar cal = new GregorianCalendar();<br /> cal.setTime(dt);<br /> return DatatypeConverter.printDate(cal);<br /> }<br /><br /> public static String printTime(Date dt) {<br /> Calendar cal = new GregorianCalendar();<br /> cal.setTime(dt);<br /> return DatatypeConverter.printTime(cal);<br /> }<br /><br /> public static String printDateTime(Date dt) {<br /> Calendar cal = new GregorianCalendar();<br /> cal.setTime(dt);<br /> return DatatypeConverter.printDateTime(cal);<br /> }<br /><br />}<br /></pre></blockquote><br /><br />The simple.xjb will be changed to:<br /><blockquote><pre name="code" class="Xml"><br /><jaxb:bindings jaxb:version="2.0" jaxb:extensionBindingPrefixes="xjc"<br /> xmlns:jaxb="http://java.sun.com/xml/ns/jaxb"<br /> xmlns:xjc="http://java.sun.com/xml/ns/jaxb/xjc"<br /> xmlns:xs="http://www.w3.org/2001/XMLSchema"><br /> <jaxb:globalBindings><br /> <xjc:simple/><br /> <jaxb:javaType name="java.util.Date" xmlType="xs:date"<br /> parseMethod="com.blogspot.ozgwei.jaxb.DateConverter.parseDate"<br /> printMethod="com.blogspot.ozgwei.jaxb.DateConverter.printDate"/><br /> <jaxb:javaType name="java.util.Date" xmlType="xs:time"<br /> parseMethod="com.blogspot.ozgwei.jaxb.DateConverter.parseTime"<br /> printMethod="com.blogspot.ozgwei.jaxb.DateConverter.printTime"/><br /> <jaxb:javaType name="java.util.Date" xmlType="xs:dateTime"<br /> parseMethod="com.blogspot.ozgwei.jaxb.DateConverter.parseDateTime"<br /> printMethod="com.blogspot.ozgwei.jaxb.DateConverter.printDateTime"/><br /> </jaxb:globalBindings><br /></jaxb:bindings><br /></pre></blockquote>Alex Weihttp://www.blogger.com/profile/16196507572911120081noreply@blogger.com9tag:blogger.com,1999:blog-2664528635822406543.post-25916866805166773392007-08-21T05:38:00.000+10:002007-09-01T22:23:31.562+10:00Defining service/component interfaces in WSDLsWe have just completed an iteration of the project we have been working on for the past few months. Now it's a good time to summarise the experiences we have gained so far.<br /><br />Probably the most significant one is defining all service/component interfaces in WSDLs.<br /><br />The project started with the interfaces of a few services being defined in WSDLs because they are invoked by the web tier as web services call. Since the JAXB-generated Java classes of some complex types defined in the XML schema are reused in some other service interfaces that are not originally intended to be invoked via web services, we finally decided to define all service interfaces in WSDLs, regardless whether they are intended to be invoked as web services or not. And this brought us unexpected benefits and productivity.<br /><br />So what are the benefits of defining all service interfaces in WSDLs?<br /><br />First of all, it takes away most of the tedious work of implementing Data Transfer Objects (DTOs), resulting in higher productivity. If you wonder why DTOs are still in use when domain model objects persisted by Hibernate and JPA can be passed back to service clients directly, please read my previoug blog entry: <a href="http://ozgwei.blogspot.com/2007/08/dtos-are-necessary-devil-in-building.html">DTOs are a necessary devil in building SOA enterprise applications</a>.<br /><br />So, how does defining service interfaces in WSDLs take away the boring implementation of DTOs? In a WSDL file, each operation has input messages, output messages and/or fault messages, which in turn are defined as elements in an external or embedded XML schema. And each element is declared in an XML type. The XJC compiler from JAXB can be used to generate corresponding Java classes of any complex types and some restricted simple types. These classes are data holders with absolutely no behaviours; in other words, they are DTOs. Code generation of DTOs has other benefits: no behaviours can be added to the DTOs without subclassing and defining new operations; and these DTOs won't accidentally reference any domain model objects, which is always a concern for hand-coded DTOs.<br /><br />XML schema allows very rich type definitions, such as abstract types and type inheritance, which has corresponding concepts in object-oriented languages, such as Java, making it a perfect choice to generate Java classes from XML data types.<br /><br />Not only are no-argument constructors and all public getter and setter methods generated for complex types, but also other useful methods, such as valued constructors, builder methods, hashCode, equals and toString methods can be implemented using XJC extensions. These are to be blogged in a follow-up post.<br /><br />Moreover, defining service/component interfaces in WSDLs can partially enforce the "contract" using schema validation, promoting the best practice of "Design by Contract" (DBC).<br /><br />Java, by itself, does not provide native support to DBC. Any acceptable input values, return values and exceptions are only documented using javadoc in the interfaces. The implementation classes have to do all the hard work to validate input values, such as making sure a mandatory parameter is not null, an amount is greater than zero and less than a preset limit, etc.<br /><br />Meanwhile, XML schema provides a rich basic data types, such as positive integers. It can also specify whether an element is mandatory or not using the "minOccur" attribute. Furthermore, it allows you to add restrictions to simple types, such as the maximum length of a string and regular expression patterns that must be matched by a string. Thus, XML schema validation can catch many simple field validation errors. More complex validations, such as cross-field validations and business rule validations cannot be done by schema validation. However, they can still be documented using annotations, which are generated as Java comments in the generated Java classes.<br /><br />Another benefit of defining service/component interfaces in WSDLs is that it promotes the best practice of "contract-first" web service design. Because the service interface is defined in a WSDL file, the service is web service ready, even if it is not intended to be used as a web service at this stage. The opposite of "contract-first" is "code-first". When adopting a "code-first" practice, the service interfaces are defined in Java, potentially without using DTOs. When the service needs to be accessed via web services or remotely, it is not as easy as just exposing the service as a web service by, say, wiring up the Spring application context. A proper service interface using DTOs has to be defined and implemented by delegate calls to the original interface and doing all the transformation between DTOs and domain models. Even if DTOs are used in the original Java interface, exposing the service as a web service is not as simple as adding the JSR-181 annotations to the interface and all DTOs: some common Java types do not have a counterpart in XML, such as java.util.Map. Moreover, the methods defined in your original DTOs may not be suitable for JAXB use. You may not have defined a no-argument constructor; you may not have defined a setter method for each property... So, why go the hard way when defining the interfaces in WSDLs can save you the tedious work of implementing DTOs and, at the same time, provide an elegant way to expose it as a web service when the time calls?Alex Weihttp://www.blogger.com/profile/16196507572911120081noreply@blogger.com1tag:blogger.com,1999:blog-2664528635822406543.post-72657467907820478292007-08-18T20:18:00.000+10:002007-09-01T22:17:17.441+10:00DTOs are a necessary devil in building SOA enterprise applicationsBringing up the topic of Data Transfer Objects (DTOs), many people's first thought would probably be that it was a reminiscence of the old Enterprise Java Bean (EJB) 2.0.<br /><br />Hibernate, JDO and JPA have made it possible to eliminate DTOs from web applications. However, DTOs are a necessary devil when building an enterprise application, especially in a Service-Oriented Architecture (SOA).<br /><br />For each service or component, the underneath domain model that provides the service should be encapsulated and not leaked beyond the boundary of the service's interfaces.<br /><br />It is often said that the interfaces are the contracts between the client and the provider of the services. However, many new Java developers think that only the interface classes and their method names are the contract without realising that any objects passed in and out of these operations are also part of the contract, such as method parameters, return values and thrown exceptions. And the contractual binding is transitive by reachability, that is, all classes directly or indirectly referenced by these parameters, return values and exceptions are all part of the contract. Therefore, if domain models are passed in and out of any operation defined in the service interfaces, they are leaked, making service clients susceptible to any changes in the domain models, which are the implementation details that are supposed to be encapsulated.<br /><br />For a web application, this is probably not a big deal, as the presentation tier is typically closely coupled to the service and persistence tiers. However, for any enterprise applications in a Service-Oriented Architecture, the change of interfaces can have a ripple effect.<br /><br />In order to achieve the encapsulation, DTOs are used as the parameters, returned values and exceptions in operations defined in the interfaces to isolate domain models from the outside world. For this reason, it is not hard to imagine that DTOs are ubiquitous in a SOA world.Alex Weihttp://www.blogger.com/profile/16196507572911120081noreply@blogger.com0tag:blogger.com,1999:blog-2664528635822406543.post-55318947890058967272007-08-09T00:58:00.001+10:002008-12-25T00:24:08.412+11:00EasyMock Class Extension 2.2 Gotcha<a href="http://easymock.org/">EasyMock</a> mocks interfaces, and the Class Extension mocks classes.<br /><br />When using the class extension, the <span style="font-family: courier new;color:blue">EasyMock</span> from the <span style="font-family: courier new;color:blue">org.easymock.classextension</span> package should be used instead of the same-named class from the original <tt style="color:blue">org.easymock package</tt>.<br /><br />When working with more than one mocks with Java 5, we can invoke the replay and verify methods using varargs, such as:<br /><blockquote><pre style="color:blue">import static org.easymock.classextension.EasyMock.*;<br />...<br />replay(mockCustomerRepository, mockCustomer);<br />...<br />verify(mockCustomerRepository, mockCustomer);</pre></blockquote>However, if one of the mocks is mocking a class instead of an interface, I got an <span style="font-family: courier new;color:red">IllegalArgumentException: not a proxy instance</span>.<br /><br />Looking into the stack trace, I can see the <span style="font-family: courier new;color:blue">EasyMock.replay/verify</span> from the original <span style="font-family: courier new;color:blue">org.easymock package</span> is used instead of the one from <span style="font-family: courier new;color:blue">org.easymock.classextension</span> package, as stated in the import statement.<br /><br />What happened is: <span style="font-family: courier new;color:blue">org.easymock.classextension.EasyMock</span> extends the <span style="font-family: courier new;color:blue">org.easymock.EasyMock</span> without providing a vararg version of <span style="font-family: courier new;color:blue">replay(Object...)</span> and<span style="font-family: courier new;color:blue"> verify(Object...)</span> method. Thus, when the vararg versions are invoked, the control is passed to the vararg version of its super class, which only mocks interfaces using standard Java Proxy.<br /><br />To get around this, you invoke the single parameter version, such as:<br /><blockquote><pre style="color:blue">import static org.easymock.classextension.EasyMock.*;<br />...<br />replay(mockCustomerRepository);<br />replay(mockCustomer);<br />...<br />verify(mockCustomerRepository);<br />verify(mockCustomer);<br /></pre></blockquote>Of course, this gotcha only exists in EasyMock class extension 2.2. The latest 2.2.2 version provides vararg version for these two methods. So a better solution is to upgrade to this latest version.Alex Weihttp://www.blogger.com/profile/16196507572911120081noreply@blogger.com10tag:blogger.com,1999:blog-2664528635822406543.post-65926178934896589112007-07-31T23:52:00.001+10:002008-12-25T00:19:36.057+11:00EasyMock2 quirk...When using EasyMock 2 for testing, typically we need to set up expectations before replay, like this:<br /><blockquote><pre style="color:blue">expect(mockEmployeeRepository<br /> .findByFirstNameAndLastName("John", "Doe"))<br /> .andReturn(employees);<br /></pre></blockquote>Sometimes, you don't know exactly what parameter will be used for the expected call, you can instead specify the class of the parameter, such as:<br /><blockquote><pre style="color:blue">expect(mockEmployeeRepository<br /> .findBySpecification(isA(EmployeeSearchSpecification.class))<br /> .andReturn(employees);</pre></blockquote>What if you know the exact value of some but not all parameters? I tried the following:<br /><blockquote><pre style="color:blue">expect(mockEmployeeRepository<br /> .findByDepartmentAndSpecification("HR",<br /> isA(EmployeeSearchSpecification.class))<br /> .andReturn(emplooyees);<br /></pre></blockquote>Unfortunately, running this test will get the following exception thrown by EasyMock:<br /><blockquote><pre style="color:red">java.lang.IllegalStateException: 2 matchers expected, 1 recorded.</pre></blockquote>The correct way is to wrap the known parameter with an "eq" matcher:<br /><blockquote><pre style="color:blue">expect(mockEmployeeRepository<br /> .findByDepartmentAndSpecification(eq("HR"),<br /> isA(EmployeeSearchSpecification.class))<br /> .andReturn(employees);</pre></blockquote>This is a small quirk when using EasyMock 2.2...Alex Weihttp://www.blogger.com/profile/16196507572911120081noreply@blogger.com18tag:blogger.com,1999:blog-2664528635822406543.post-83316861276991399822007-07-31T00:41:00.001+10:002008-12-25T00:17:48.035+11:00Handling referential integrity when doing persistence testing using DbUnit<a href="http://dbunit.sourceforge.net/">DbUnit</a> is a great tool when testing database persistence codes.<br /><br />There are many ways to using DbUnit. Anyhow, my preferred way is to delete all records from the database tables and re-populate with test data before each test. For unit testing, I test against a memory database, such as <a href="http://hsqldb.org/">Hypersonic</a>; for integration testing, I test against a database that mirrors the one in production.<br /><br />However, this approach sometimes will get you into the trouble of referential integrity violation.<br /><br />For example, I had some integration tests against the PRODUCT table, and later I developd some integration tests against the ORDER table, which has a foreign key dependency on the PRODUCT table.<br /><br />After checking in the latest changes, the continuous integration test failed because of data integrity violation. The cause was that the PRODUCT integration tests saved some records in both PRODUCT and ORDER table, with some orders referencing some products. When DbUnit tried to delete all records from the PRODUCT table, the database detected the violation.<br /><br />How to solve this? It's pretty easy, just add an empty ORDER record to the test data XML file that is used to populate the database. Following is a sample of a FlatXmlDataSet file:<blockquote><pre style="color:blue"><br /><?xml version='1.0' encoding='UTF-8'?><br /><dataset><br /> <product id="1" desc="abc" price="1.23"/><br /> <order/><br /></dataset></pre></blockquote>The trick is that in a FlatXmlDataSet file, the order of the tables defined must follow the dependency, that is, a later defined table can have a dependency on an earlier defined table. When DbUnit deletes records, it will delete records from the last defined table first.Alex Weihttp://www.blogger.com/profile/16196507572911120081noreply@blogger.com2tag:blogger.com,1999:blog-2664528635822406543.post-25922511381156247852007-07-29T13:45:00.000+10:002007-07-29T21:41:24.420+10:00Springify a "Singleton"-infested applicationThe singleton pattern has been avidly <a href="http://tech.puredanger.com/2007/07/03/pattern-hate-singleton/">avoided</a> by most developers since the introduction of Spring, which solved the problem in an elegant way.<br /><br />However, there have been many applications that were developed before and were infested with the "evil" singleton pattern. Quite often, these singletons are not really singletons; the singleton pattern was just misapplied to a problem that may be more suitable to use <a href="http://www.martinfowler.com/eaaCatalog/registry.html">Registry</a> to solve.<br /><br />Every now and then, developers are asked to add Spring to such applications with minimal code changes and refactoring because these applications typically do not have any automated unit tests or do not have a good enough test coverage.<br /><br />Adding Spring to such applications is rather simple if there is no dependency between the existing codes and the Spring-managed beans.<br /><br />If Spring-managed beans have a dependency on a "singleton" that is not managed by Spring. We can define the "singleton" as a Spring-managed bean using a "factory-method", such as "getInstance()", to retrieve the "singleton" instance and inject it into other beans.<br /><br />Things get more complex when you want to use Spring to configure these "singletons".<br /><br />For example, one of the application that I need to springify used a "singleton" to look up data source from JNDI. In order to add tests that can be run out of container, we need to inject a Spring-configured data source, whether it is registered with JNDI or not, to that "singleton" instance, instead of letting the "singleton" to look up JNDI.<br /><br />What we did was that we added a new static factory method "createInstance(DataSource)" accepting a pre-configured data source and returning the singleton instance. Then we configure Spring to invoke this new factory method to create a bean, which is stored in the original static variable and returned to caller of the static "getInstance()" method.<br /><br />I have read on the internet that some call this a "Singleton with a back door" pattern. To me, it is pretty clear that the singleton pattern is misused here. What the original developer really needed was a "Registry" pattern that allows other objects to "find common objects and services" using "a well-known object". Spring creates and configures the common object or service, which is registered so that other objects in the same application can locate it.<br /><br />In fact, Spring itself uses "Registry" pattern in many places. Some of the significant places include transaction management and JDBC connection management. Spring uses a thread-local scoped registry to hold JDBC connection so that all JDBC operations within the same transaction use the same JDBC connection...<br /><br />One thing to note when using Spring to configure such "singletons" is that there are typically many implicit dependencies between these "singletons". If Spring instantiates these "singletons" in a wrong order, the application cannot run properly, usually with failure in constructing application context. The solution to this is to use the "depends-on" attribute in bean definition to explicitly specify the dependencies between these "singletons".Alex Weihttp://www.blogger.com/profile/16196507572911120081noreply@blogger.com1tag:blogger.com,1999:blog-2664528635822406543.post-76325690046327670882007-06-29T01:07:00.000+10:002007-06-29T01:48:28.496+10:00Workflow engine integration, where does it go?In one of the projects I have worked on, <a href="http://www.opensymphony.com/osworkflow/">OSWorkflow</a> is used to manage workflows. It is integrated to the service layer instead of to the domain objects.<br /><br />The design feels unnatural somehow:<br /><br /><ul><li>The workflow id is stored in the domain object, passed as a parameter in constructor. However, it is not used by the domain object itself. The domain class provides a getter method so that the service layer can retrieve the workflow id and load the workflow instance from OSWorkflow.</li></ul><ul><li>After loading the domain object and then the workflow instance, the service layer needs to pass to the workflow engine some properties from the domain object and some properties from the DTO that carries the input of the user for the current request, so that the workflow engine can work out what is the next status for the domain object.<br /></li></ul><ul><li>The domain class also expose a method to allow arbitrary update of the 'status' field so that the service layer can update the domain object with the status that is come up with by the workflow engine. The domain model loses encapsulation.<br /></li></ul><ul><li>The service layer becomes thick while the domain model becomes <a href="http://www.martinfowler.com/bliki/AnemicDomainModel.html">anaemic</a>...</li></ul><br />IMHO, this design smells.<br /><br />The change of state in a domain object should be managed by the domain itself. Any application requirements, such as sending email notifications, can be implemented as state change event listeners.<br /><br />If the workflow logic gets too complicated, workflow engines like OSWorkflow come to rescue. But even if the workflow logic is delegated or outsourced to a workflow engine, it is still domain logic; thus, the workflow engine should be integrated directly into the domain objects instead of to the service layer.<br /><br />In order for domain objects to work with a workflow engine, domain objects need to have a reference to the workflow engine, which used to be an issue.<br /><br />With domain object dependency injection feature introduced in Spring 2, this problem is solved. Even if you are using Spring 1.2 or other IoC Containers that do not support domain object dependency injection, or if you are not using an IoC container at all, you can still use <a href="http://www.martinfowler.com/eaaCatalog/registry.html">Registry pattern</a> where a domain object can look up a dependency.<br /><br />In conclusion, state change is part of the domain logic, and even if it is outsourced to a workflow engine, the workflow engine integration should still happen in the domain object, without leaking the implementation details to other layers. And technically, there is no more barrier that prevents injecting the workflow engine into domain objects.Alex Weihttp://www.blogger.com/profile/16196507572911120081noreply@blogger.com0tag:blogger.com,1999:blog-2664528635822406543.post-87591856407089315322007-06-24T10:45:00.000+10:002007-06-25T00:23:57.499+10:00Is using domain entities in presentation layer encouraged?There is an interesting discussion going on in the Spring support forum about <a href="http://forum.springframework.org/showthread.php?p=127724#post127724">using Hibernate entities in web layer</a>.<br /><br />In his reply, Debasish said:<br /><blockquote>I am all for using domain entities in the presentation layer. If you read the Expert Spring MVC book or the Hibernate book, both of them encourage using smart domain models and reusing domain objects in the presentation layer. The Spring MVC book recommends using domain objects as command objects and the Hibernate book recommends doing away with the behaviorless JSF backing beans in favor of smart POJOs in SEAM.</blockquote>I have plenty of respects for Debasish. However, I have to disagree on this.<br /><br />One thing that I have kept in mind is that Spring MVC and Hibernate's development started in the dark age of EJB 2.0, which forced developers to build enterprise applications with anaemic domain models using transaction scripts. At that time, many people equalled Java Beans to POJOs and domain classes. Unfortunately that was misleading... In a rich domain model, typically entity classes are NOT Java beans, because providing setter methods can easily break invariants of a domain class. Since then, Domain Driven Design has gained wider adoption and recognition.<br /><br />In a recent presentation "Are We There Yet?", Rod Johnson, the founder of Spring, asked the attendees a question: when working with Hibernate, who use property access and who use field access? Those who use property access are persisting DTOs, or, using an anaemic domain model. I cannot recall the exact words, but that's basically what he said and meant.<br /><br />I would like to add: that those who use domain classes as command objects in the web layer are working with an anaemic domain model.<br /><br />For example, in one of the projects I have worked on, there is a Fraud class, which has three fields: fraudPaymentDate, fraudPaymentAmount, amountRecovered and dateRecovered. The invariants regarding these three fields are:<br />1) amountRecovered must not exceed fraudPaymentAmount.<br />2) When amountRecovered is $0.00, dateRecovered must be null.<br />3) When amount Recovered is greater than $0.00, dateRecovered must be present, in the past and must not predate fraudPaymentDate.<br /><br />If this class provides setter methods for all these fields and is directly used as a command object, there is no way not to break invariants in the binding phase of Spring MVC:<br />If setAmountRecovered() is invoked with a non-zero amount before setDateRecovered(), then invariant no. 3 is broken.<br />If setDateRecovered() is invoked before setAmountRecovered(), then invariant no. 2 is broken.<br /><br />Therefore, a command object typically does not maintain data integrity. Usually a validate() method is provided to the client to ensure data integrity AFTER the binding.<br /><br />There is one big drawback with using validate() method: the domain object relies on its client to call its validate() method to check data integrity or on a trigger from an event such as save(). However, when using Hibernate, domain objects can be persisted transparently without the domain object being persisted beware of the fact that it's being persisted. Thus, a corrupted domain object can easily be persisted to database.<br /><br />When using a rich domain model with DTO, this problem is solved:<br />The DTO can be used as a command object in the web layer and passed to the service tier. The UpdateService can construct two value objects fraudPaymentInfo, which contains both fraudPaymentDate and fraudPaymentAmount, and recoveryInfo, which contains both amountRecovered and dateRecovered, according to the data in the DTO and invoke the Fraud object's updatePaymentInfo() and updateRecoveryInfo(). Invariants are always maintained in the process.Alex Weihttp://www.blogger.com/profile/16196507572911120081noreply@blogger.com2