tag:blogger.com,1999:blog-44497226172114413502024-03-06T07:20:43.354+01:00TKill's blogRandom notestkillhttp://www.blogger.com/profile/00251805689664856925noreply@blogger.comBlogger4125tag:blogger.com,1999:blog-4449722617211441350.post-58346931811930210012014-08-14T12:13:00.001+02:002014-08-18T09:42:18.983+02:00Using Google Guice in a Netbeans RCP application<div class="tr_bq">
We have been using Tapestry IoC in a Netbeans RCP application for a while. We recently added more NBMs which uses Tapestry, either for IoC or as web framework. We then ran into some dependency issues, and we decided to take the opportunity to replace Tapestry as IoC container with the JSR-330 compliant Google Guice.<br />
<br />
The way the application is configured is pretty similar in Tapestry and Guice, so rewriting the module didn't take long. In addition, we annotated the necessary classes with <span style="font-family: "Courier New",Courier,monospace;">@Inject</span>, some of them residing in different NBMs.<br />
<br />
When launching the application we got six errors with the message:</div>
<br />
<blockquote>
<i>Could not find a suitable constructor in com.example.ClassName. Classes must have either one (and only one) constructor annotated with @Inject or a zero-argument constructor that is not private</i></blockquote>
Googling gave the impression that not that many people have combined Netbeans RCP and Guice. At least, I wasn't able to find any solution.<br />
<br />
Then, I noticed that all the errors were related to classes in NBMs other than the one we were trying to setup IoC in. Netbeans uses different class loaders for each NBM, and the <span style="font-family: "Courier New",Courier,monospace;">@Inject</span>-annotation in the other NBMs was loaded by different class loaders than the one used by Guice. That's why Guice couldn't recognise that the constructors were correctly annotated.<br />
<br />
The solution for us was to create a <a href="http://wiki.netbeans.org/DevFaqWrapperModules">Library Wrapper Module</a> for the jar containing the <span style="font-family: "Courier New",Courier,monospace;">@Inject</span> annotation, namely <i>javax.inject</i>.<br />
<br />
The pom file we used for creating the wrapper, minus release- and deploy-related stuff, looks like this:<br />
<br />
<span style="font-family: "Courier New",Courier,monospace;"><?xml version="1.0" encoding="UTF-8"?><br /><project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"<br /> xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd"><br /> <modelVersion>4.0.0</modelVersion><br /><br /> <groupId>com.example</groupId><br /> <artifactId>javax.inject</artifactId><br /> <version>1</version><br /> <packaging>nbm</packaging><br /><br /> <name>Wrapper for javax.inject</name><br /><br /> <dependencies><br /> <dependency><br /> <groupId>javax.inject</groupId><br /> <artifactId>javax.inject</artifactId><br /> <version>1</version><br /> </dependency><br /> </dependencies><br /><br /> <build><br /> <plugins><br /> <plugin><br /> <groupId>org.codehaus.mojo</groupId><br /> <artifactId>nbm-maven-plugin</artifactId><br /> <version>3.13</version><br /> <extensions>true</extensions><br /> <configuration><br /> <publicPackages><br /> <publicPackage>javax.inject.**</publicPackage><br /> </publicPackages><br /> </configuration><br /> </plugin><br /> <plugin><br /> <groupId>org.apache.maven.plugins</groupId><br /> <artifactId>maven-jar-plugin</artifactId><br /> <version>2.5</version><br /> <configuration><br /> <useDefaultManifestFile>true</useDefaultManifestFile><br /> </configuration><br /> </plugin><br /> </plugins><br /> </build><br /><br /></project></span><br />
<br />tkillhttp://www.blogger.com/profile/00251805689664856925noreply@blogger.com1tag:blogger.com,1999:blog-4449722617211441350.post-7796733295026607372011-05-14T13:58:00.002+02:002011-05-16T08:49:57.434+02:00Analyzing Java memory usageEven when using Java, one might encounter memory issues. In those cases, it is good to know that there are tools to help you out, some of which are bundled with Sun's JDK distribution.<br />
<br />
<span style="font-size: large;">Creating a Java heap dump</span><br />
<span style="font-size: large;"><span style="font-size: small;">The first thing to do is obtaining a heap dump, in which Java writes the current content of its heap to a file. There are many ways to achieve this. This can be done explicitly by issuing commands from a command line, by using Java's JMX, or by instructing the JVM to make a heap dump when an OutOfMemoryError eccurs.</span></span><br />
<br />
<span style="font-size: large;"><span style="font-size: small;">The simplest way to get a heap dump from a running system is by issuing the command <span style="font-family: "Courier New",Courier,monospace;">jmap</span> from a command line, for instance</span></span><br />
<br />
<div style="font-family: "Courier New",Courier,monospace;"><span style="font-size: large;"><span style="font-size: small;">$ jmap -dump:live,format=b,file=heap.bin 6114</span></span></div><br />
<span style="font-size: large;"><span style="font-size: small;">will dump the live objects in the heap of the Java process with process ID 6114 to a file called heap.bin. The process ID can be found by using <span style="font-family: "Courier New",Courier,monospace;">jps</span> or <span style="font-family: "Courier New",Courier,monospace;">ps</span>, if on a Unix system.</span></span><br />
<br />
<span style="font-size: large;"><span style="font-size: small;">But what if one wants a dump of the heap as it is when an OutOfMemoryError occurs? One of the arguments the JVM accepts is: <span style="font-family: "Courier New",Courier,monospace;">-XX:+HeapDumpOnOutOfMemoryError</span></span></span><span style="font-size: large;"><span style="font-size: small;">. As the name of the argument suggests, this</span></span><span style="font-size: large;"><span style="font-size: small;"> tells the JVM to create a dump of the heap when an OutOfMemoryError occurs. If you also supply the argument <span style="font-family: "Courier New",Courier,monospace;">-XX:HeapDumpPath</span>, you can instruct the JVM on where to put the generated dump file (by default it</span></span> is created in the working directory of the VM). For instance:<br />
<br />
<div style="font-family: "Courier New",Courier,monospace;"><span style="font-size: small;">$ java -XX:+HeapDumpOnOutOfMemoryError -XX:HeapDumpPath=/tmp/heap.bin ...</span></div><span style="font-size: small;"> </span> <br />
<span style="font-size: large;">Analyzing the heap dump</span><br />
<span style="font-size: large;"><span style="font-size: small;">The heap dump file obtained by the above is a binary file not suited for manual inspection. However, also in the JDK distribution is a tool called <span style="font-family: "Courier New",Courier,monospace;">jhat</span>.</span></span> This is a tool for analyzing a binary heap dump file (Java Heap Analysis Tool). It parses the heap file and launches a web server, allowing you to navigate the information in the heap in a web browser. The command<br />
<br />
<div style="font-family: "Courier New",Courier,monospace;">$ jhat heap.bin</div><br />
will parse the heap in file heap.bin. When launching a web browser and entering localhost:7000 in the address bar, I am presented with the following:<br />
<br />
<div class="separator" style="clear: both; text-align: center;"><a href="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEjZ0t6_kN1bHvm6lk33R9MWNjEf9k32ZEmQGWdeCg4eFl75nZIghjTl6H10iY1z_Mo-whs1s9vbPJV0ZP8bB1naK2bzQ1anqQ8YpkBrJ8SAIDsaOE0Oaed9wnhrrpkZ84j9FFbB75HbSDtP/s1600/screenshot1.png" imageanchor="1" style="margin-left: 1em; margin-right: 1em;"><img border="0" height="275" src="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEjZ0t6_kN1bHvm6lk33R9MWNjEf9k32ZEmQGWdeCg4eFl75nZIghjTl6H10iY1z_Mo-whs1s9vbPJV0ZP8bB1naK2bzQ1anqQ8YpkBrJ8SAIDsaOE0Oaed9wnhrrpkZ84j9FFbB75HbSDtP/s400/screenshot1.png" width="400" /></a></div><br />
This is simply a listing of all classes loaded. When clicking on one of the class names, a new screen appears with more details on the selected class:<br />
<br />
<div class="separator" style="clear: both; text-align: center;"><a href="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEivMFBMo5PUeny93NfoWt3V7pSIoCRPnHWNbHhrC4r57JQNrntmwitDvroGAVscW-WxZK2gV9BORE33_Cg-51uS_-xCnNDQUWpvzXGtz2T01m31sReHjdKhnmDDV4zj2W9_dHqznLHRRbxk/s1600/screenshot2.png" imageanchor="1" style="margin-left: 1em; margin-right: 1em;"><img border="0" height="287" src="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEivMFBMo5PUeny93NfoWt3V7pSIoCRPnHWNbHhrC4r57JQNrntmwitDvroGAVscW-WxZK2gV9BORE33_Cg-51uS_-xCnNDQUWpvzXGtz2T01m31sReHjdKhnmDDV4zj2W9_dHqznLHRRbxk/s400/screenshot2.png" width="400" /></a></div><br />
It is worth noticing that in the far bottom of the first screen (All classes), there are a number of useful links, for instance the "Heap Histogram", which shows the number of instances and the total size for each class. Another link take you to a new page where you can execute Object Query Language (OQL) queries. One example of a OQL query is:<br />
<span style="font-family: "Courier New",Courier,monospace;">select s from java.lang.String s where s.count >= 100</span><br />
which will show you all Strings of length 100 or more. See the "OQL Help" page for more on OQL.<br />
<br />
Another way of inspecting the obtained heap dump is with the NetBeans IDE. Simply download the simplest version of it, launch it, and import your heap dump with "Load Heap Dump..." under "Profile" on the menu bar. This will give you the same information as the jhat-tool, but in a more user-friendly way.<br />
<br />
<div class="separator" style="clear: both; text-align: center;"><a href="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEg8CB6182AJMRJ1faaTejEZOEw_87u66INisQO2p9D-qh6SPNe5oDJzU4X4CX0FbsRts5yRRya4hOMGUEIi0Y2gEE77LNEXNqbvp9x0Kv3zXCfhxEIR37FReRiFOmg539PJJnn-CLpc8Eyl/s1600/screenshot4.png" imageanchor="1" style="margin-left: 1em; margin-right: 1em;"><img border="0" height="250" src="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEg8CB6182AJMRJ1faaTejEZOEw_87u66INisQO2p9D-qh6SPNe5oDJzU4X4CX0FbsRts5yRRya4hOMGUEIi0Y2gEE77LNEXNqbvp9x0Kv3zXCfhxEIR37FReRiFOmg539PJJnn-CLpc8Eyl/s400/screenshot4.png" width="400" /></a></div>tkillhttp://www.blogger.com/profile/00251805689664856925noreply@blogger.com0tag:blogger.com,1999:blog-4449722617211441350.post-30275162356342553132011-03-16T16:07:00.005+01:002011-05-14T14:05:51.498+02:00Grails - Excluding plugin dependencies from warI started using maven to build my Grails project, and upgraded Grails to version 1.3.7. Running mvn grails:run-app with Tomcat works fine, but when I tried to generate a war file with mvn package, and deploy that to Jetty, it failed:<br />
<br />
Exception in thread "main" java.lang.IllegalAccessError: tried to access field<br />
org.slf4j.impl.StaticLoggerBinder.SINGLETON from class org.slf4j.LoggerFactory<br />
at org.slf4j.LoggerFactory.<clinit>(LoggerFactory.java:60)<br />
<br />
Googling led me to the SLF4J FAQ (http://www.slf4j.org/faq.html) which says that this is caused by slf4j-api <= 1.5.5 being incompatible with an slf4j binding > 1.5.5. My application declares slf4j-api 1.5.8 and slf4j-log4j12 1.5.8 as dependencies. Running mvn dependency:tree didn't reveal any slf4j-api <= 1.5.5, but, indeed, in WEB-INF/lib in the application's war-file there was a slf4j-api-1.5.2.jar. Where did it come from?<br />
<br />
When running mvn package with the log level of Ivy resolver set to "info", it seems that it was pulled in by Hibernate, through its dependencies hibernate-core and hibernate-commons-annotations. Problem solved! Grails has great support for determining which of the plugin's dependencies to exclude. In the Grails Reference Documentation it says:<br />
<br />
<blockquote>If a plugin is using a JAR which conflicts with another plugin, or an application dependency then you can override how a plugin resolves its dependencies inside an application using exclusions. For example:</blockquote><br />
<span style="font-family: "Courier New",Courier,monospace;">plugins {</span><br />
<span style="font-family: "Courier New",Courier,monospace;"> runtime( "org.grails.plugins:hibernate:1.3.0" ) {</span><br />
<span style="font-family: "Courier New",Courier,monospace;"> excludes "javassist"</span><br />
<span style="font-family: "Courier New",Courier,monospace;"> }</span><br />
<span style="font-family: "Courier New",Courier,monospace;">}</span><br />
<br />
This means that all I have to do is include the following in my BuildConfig.groovy:<br />
<br />
<div style="font-family: "Courier New",Courier,monospace;">runtime("org.grails.plugins:hibernate:1.3.7") {</div><div style="font-family: "Courier New",Courier,monospace;"> excludes "slf4j-api" </div><div style="font-family: "Courier New",Courier,monospace;">}</div><br />
No luck. slf4j-api-1.5.2.jar was still there. Googling suggested that there is a bug in Grails that prevents it from excluding transitive dependencies of plugins (<a href="http://jira.codehaus.org/browse/GRAILS-6910">GRAILS-6910</a>). Allright. Let me exclude hibernate-core and hibernate-comons-annotations, then, and include them as dependencies with slf4j-api excluded, ie.<br />
<div style="font-family: "Courier New",Courier,monospace;"><br />
</div><div style="font-family: "Courier New",Courier,monospace;">dependencies {</div><div style="font-family: "Courier New",Courier,monospace;"> compile("org.hibernate:hibernate-commons-annotations:3.1.0.GA") {</div><div style="font-family: "Courier New",Courier,monospace;"> excludes "slf4j-api" </div><div style="font-family: "Courier New",Courier,monospace;"> }</div><div style="font-family: "Courier New",Courier,monospace;"></div><div style="font-family: "Courier New",Courier,monospace;"> compile("org.hibernate:hibernate-core:3.1.0.GA") {</div><div style="font-family: "Courier New",Courier,monospace;"> excludes "slf4j-api" </div><div style="font-family: "Courier New",Courier,monospace;"> } </div><div style="font-family: "Courier New",Courier,monospace;"></div><span style="font-family: "Courier New",Courier,monospace;">}</span><br />
<div style="font-family: "Courier New",Courier,monospace;"><br />
</div><div style="font-family: "Courier New",Courier,monospace;">plugins {</div><div style="font-family: "Courier New",Courier,monospace;"> runtime("org.grails.plugins:hibernate:1.3.7") {</div><div style="font-family: "Courier New",Courier,monospace;"> excludes "hibernate-core", "hibernate-commons-annotations"</div><div style="font-family: "Courier New",Courier,monospace;"> } </div><span style="font-family: "Courier New",Courier,monospace;">}</span><br />
<br />
Still no luck.<br />
<br />
Finally, Google led me to this page: <a href="http://www.anyware.co.uk/2005/2009/01/21/excluding-files-from-a-war-with-grails-the-right-way/">Excluding files from a WAR with Grails – the right way</a>. There, Marc Palmer suggested adding the following to Config.groovy to exclude a certain .jar-file from the war file:<br />
<br />
<br />
<br />
<span style="font-family: "Courier New",Courier,monospace;">grails.war.resources = { stagingDir -></span><span style="font-family: "Courier New",Courier,monospace;"></span><br />
<span style="font-family: "Courier New",Courier,monospace;"> delete(file:"${stagingDir}/WEB-INF/lib/slf4j-api-1.5.2.jar")</span><br />
<span style="font-family: "Courier New",Courier,monospace;"> }</span><br />
<br />
Ran mvn package while I held my breath. Once finished, I checked the generated war file, and, to my disappointment, the slf4j-api-1.5.2.jar was still there.<br />
<br />
However, reading through the mentioned post's comments, some guy suggested that it should be added to BuildConfig.groovy, rather than Config.groovy.<br />
<br />
<br />
Tried that. And finally, no slf4j-api-1.5.2.jar in the generated war file, only my own slf4j-api-1.5.8.jar.<br />
<br />
Deployed the war to Jetty, and it worked like a charm.<br />
<br />
It seems to me that Grails' dependency manipulation methods are rather buggy at the moment. I find this an acceptable workaround.tkillhttp://www.blogger.com/profile/00251805689664856925noreply@blogger.com13tag:blogger.com,1999:blog-4449722617211441350.post-81293162537189178742010-11-28T17:18:00.002+01:002011-05-14T14:00:38.164+02:00Decreasing page load time in a Java web applicationThis post will mention some of the things you can do to decrease the page load time in a Java-based web application with regards to Yahoo!'s list of best practices for speeding up your web site (<a href="http://developer.yahoo.com/performance/rules.html">http://developer.yahoo.com/performance/rules.html</a>).<br />
<br />
<span style="font-size: large;">Minimize HTTP Requests</span><br />
When it comes to external stylesheets and JavaScript files, Web Resource Optimizer for Java (wro4j) can be used to reduce the number of requests required to fetch all content. During development, I find it more maintainable to have stylesheets and JavaScript files split into several files. wro4j merges these files together at runtime, so that one still can have them split into several files, but have only one request for them. How to setup and use wro4j is explained well in <a href="http://code.google.com/p/wro4j/wiki/GettingStarted">http://code.google.com/p/wro4j/wiki/GettingStarted</a>.<br />
<br />
Regarding reducing the number of requests for images, CSS sprites can be used. Use, for instance, SpriteMe (<a href="http://spriteme.org/">http://spriteme.org</a>) or CSS Sprite Generator (<a href="http://spritegen.website-performance.org/">http://spritegen.website-performance.org</a>) to create the sprite. I use CSS Sprite Generator to create a starting point, and then modify and maintain the sprite by hand (<a href="http://www.gimp.org/">GIMP</a>). Be aware of the placement of the images in the sprite so that adjacent images don't show up in the wrong places in your page.<br />
<br />
<span style="font-size: large;">Add an Expires or a Cache-Control Header</span><br />
By default, wro4j sets the Expires-header to be ten years in the future for content served through the wro4j filter. This tells the client browser that the content won't change for ten years, so it shouldn't bother to ask for it again before then. Be aware that the browser won't even bother to ask if the content has changed, so, unless the content is removed from the browser's cache, it will use it's cached version for ten years. This means that if you modify one of the files served by wro4j, but don't change the reference to the group containing the file, the clients won't get the updated file for ten years.<br />
<br />
Since wro4j only handles CSS and JavaScript files, you have to find another way of setting the Expires header on other content, such as images. This can be accomplished by implementing a filter that sets the header on specific content. See <a href="http://juliusdev.blogspot.com/2008/06/tomcat-add-expires-header.html">http://juliusdev.blogspot.com/2008/06/tomcat-add-expires-header.html</a> for an example.<br />
<br />
<span style="font-size: large;">Gzip Components</span><br />
Gzip is a compression method that generally reduces the size of your files about 70%. Once again, wro4j does the job for you. By setting the filter's <span style="font-family: "Courier New",Courier,monospace;">gzipResources</span> init parameter to <span style="font-family: "Courier New",Courier,monospace;">TRUE</span>, wro4j will gzip your CSS and JS resources. Images shouldn't be gzipped because they are compressed already.<br />
<br />
<span style="font-size: large;">Minify JavaScript and CSS</span><br />
<span style="font-size: large;"><span style="font-size: small;">With the danger of repeating myself, wro4j does it for you. Wro4j minimizes both your JavaScript and CSS resources by default. One useful thing to note is that if you have set the filter's <span style="font-family: "Courier New",Courier,monospace;">configuration</span> init parameter to <span style="font-family: "Courier New",Courier,monospace;">DEVELOPMENT</span>, you can add the query parameter </span></span><span style="font-family: "Courier New",Courier,monospace;">minimize=false</span> to the URL of your CSS or JavaScript groups to disable minimization. I, at least, find it difficult trying to find errors in minified content.tkillhttp://www.blogger.com/profile/00251805689664856925noreply@blogger.com1