<?xml version='1.0' encoding='UTF-8'?><?xml-stylesheet href="http://www.blogger.com/styles/atom.css" type="text/css"?><feed xmlns='http://www.w3.org/2005/Atom' xmlns:openSearch='http://a9.com/-/spec/opensearchrss/1.0/' xmlns:blogger='http://schemas.google.com/blogger/2008' xmlns:georss='http://www.georss.org/georss' xmlns:gd="http://schemas.google.com/g/2005" xmlns:thr='http://purl.org/syndication/thread/1.0'><id>tag:blogger.com,1999:blog-260065058526360285</id><updated>2024-10-25T03:24:04.485-07:00</updated><category term=".NET"/><category term="Axis2"/><category term="CFX"/><category term="Clover"/><category term="Code Analysis"/><category term="Code Coverage"/><category term="Eclipse"/><category term="Findbugs"/><category term="JMX"/><category term="Java"/><category term="MBeans"/><category term="PMD"/><category term="Perf Counters"/><category term="Web Service"/><category term="Web Services"/><category term="debug"/><category term="instrumenting"/><category term="log4j"/><category term="monitoring"/><category term="tomcat"/><category term="tracking request"/><title type='text'>A Java perspective for .NET developers</title><subtitle type='html'>Coming to Java from .NET world? Look here to learn some tricks and tips. .NET is great, but Java and open source world have a lot to offer. See how you can ease transition or just compare both worlds.</subtitle><link rel='http://schemas.google.com/g/2005#feed' type='application/atom+xml' href='http://ajavaperspective.blogspot.com/feeds/posts/default'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/260065058526360285/posts/default?redirect=false'/><link rel='alternate' type='text/html' href='http://ajavaperspective.blogspot.com/'/><link rel='hub' href='http://pubsubhubbub.appspot.com/'/><author><name>Yuri</name><uri>http://www.blogger.com/profile/10050240503141428160</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='16' height='16' src='https://img1.blogblog.com/img/b16-rounded.gif'/></author><generator version='7.00' uri='http://www.blogger.com'>Blogger</generator><openSearch:totalResults>9</openSearch:totalResults><openSearch:startIndex>1</openSearch:startIndex><openSearch:itemsPerPage>25</openSearch:itemsPerPage><entry><id>tag:blogger.com,1999:blog-260065058526360285.post-4615891111459170219</id><published>2009-02-09T19:27:00.000-08:00</published><updated>2009-02-09T19:38:05.583-08:00</updated><title type='text'>DBCP Connection pooling – not so  by default</title><content type='html'>Unlike in C#, one has to setup database connection pooling in Java. Not a big deal, as there are several ready-to-use libraries. We picked &lt;a href=&quot;http://commons.apache.org/dbcp/&quot; target=&quot;_blank&quot;&gt;DBCP&lt;/a&gt; from apache commons. While unittests succeeded, stress tests were failing after exhausting all available TCP connections... To make long story short, the constructor we used to setup Object Pool did not pool connections: at first our code looked like this:&lt;br /&gt;&lt;br /&gt;&lt;span style=&quot;font-size:85%;&quot;&gt;&lt;span style=&quot;font-family:courier new;&quot;&gt;ObjectPool connPool = new GenericObjectPool(null, maxActive, GenericObjectPool.WHEN_EXHAUSTED_FAIL);&lt;/span&gt;&lt;br /&gt;&lt;/span&gt;&lt;br /&gt;However, this only limits db connections but doesn’t reuse them. You can confirm this by either looking at the connection ids in my MySQL admin or simply running “netstat –a” and notice the ever-growing number of TCP connections – Windows holds on to TCP connection for a few minutes even after db connection is closed. The fix was rather simple: pass all required parameters:&lt;br /&gt;&lt;br /&gt;&lt;span style=&quot;font-family:courier new;font-size:85%;&quot;&gt;ObjectPool connPool = new GenericObjectPool(null, maxActive,&lt;br /&gt;GenericObjectPool.WHEN_EXHAUSTED_FAIL,&lt;br /&gt;-1, //maxWait,&lt;br /&gt;-1, //maxIdle,&lt;br /&gt;false, //testOnBorrow,&lt;br /&gt;false, // testOnReturn,&lt;br /&gt;-1, //timeBetweenEvictionRunsMillis,&lt;br /&gt;-1, //numTestsPerEvictionRun,&lt;br /&gt;-1, //minEvictableIdleTimeMillis,&lt;br /&gt;false); //testWhileIdle&lt;br /&gt;&lt;/span&gt;&lt;br /&gt;C# wasn’t that bad after all, was it? ;)&lt;div class=&quot;blogger-post-footer&quot;&gt;&lt;script expr:src=&#39;&quot;http://feeds.feedburner.com/~s/AJavaPerspectiveForDotNetDevelopers?i=&quot; + data:post.url&#39; type=&quot;text/javascript&quot; charset=&quot;utf-8&quot;&gt;&lt;/script&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://ajavaperspective.blogspot.com/feeds/4615891111459170219/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment/fullpage/post/260065058526360285/4615891111459170219' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/260065058526360285/posts/default/4615891111459170219'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/260065058526360285/posts/default/4615891111459170219'/><link rel='alternate' type='text/html' href='http://ajavaperspective.blogspot.com/2009/02/dbcp-connection-pooling-not-so-by.html' title='DBCP Connection pooling – not so  by default'/><author><name>Yuri</name><uri>http://www.blogger.com/profile/10050240503141428160</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='16' height='16' src='https://img1.blogblog.com/img/b16-rounded.gif'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-260065058526360285.post-7747242553122247079</id><published>2008-08-04T21:47:00.001-07:00</published><updated>2008-08-05T21:32:47.295-07:00</updated><category scheme="http://www.blogger.com/atom/ns#" term="log4j"/><category scheme="http://www.blogger.com/atom/ns#" term="tracking request"/><title type='text'>Tracking requests in multithreaded environment</title><content type='html'>&lt;p&gt;&lt;font face=&quot;georg&quot;&gt;One &lt;strike&gt;day&lt;/strike&gt; night you&#39;ll have to troubleshoot your application and figure out what requests are causing error logs to fill up.&amp;#160;&amp;#160; You can expedite investigation if you are able to trace every log statement done during processing of the request that resulted in error.&amp;#160; Usually, you can use &lt;/font&gt;&lt;a href=&quot;http://en.wikipedia.org/wiki/Thread_Local_Storage&quot; target=&quot;_blank&quot;&gt;&lt;font face=&quot;georg&quot;&gt;thread local storage&lt;/font&gt;&lt;/a&gt;&lt;font face=&quot;georg&quot;&gt; to stick a a random number at the beginning of processing of every request and print it in the logs.&amp;#160; However, since you&#39;re using &lt;/font&gt;&lt;a href=&quot;http://logging.apache.org/log4j/&quot; target=&quot;_blank&quot;&gt;&lt;font face=&quot;georg&quot;&gt;log4j&lt;/font&gt;&lt;/a&gt;&lt;font face=&quot;georg&quot;&gt; (aren&#39;t you? :-) ), you can take advantage of &lt;/font&gt;&lt;a href=&quot;http://logging.apache.org/log4j/1.2/apidocs/org/apache/log4j/MDC.html&quot; target=&quot;_blank&quot;&gt;&lt;font face=&quot;georg&quot;&gt;log4j.MDC&lt;/font&gt;&lt;/a&gt;&lt;font face=&quot;georg&quot;&gt; object - &amp;quot;an instrument for distinguishing interleaved log output from different sources.&amp;quot; &lt;/font&gt;&lt;/p&gt;  &lt;p&gt;&lt;font face=&quot;georg&quot;&gt;Follow these 3 steps:&lt;/font&gt;&lt;/p&gt;  &lt;ul&gt;   &lt;li&gt;&lt;font face=&quot;georg&quot; color=&quot;#0000ff&quot;&gt;create a log4j decorator object (&lt;strong&gt;MyLogDecorator&lt;/strong&gt;)&lt;/font&gt; &lt;/li&gt; &lt;/ul&gt;  &lt;p&gt;&lt;font face=&quot;georg&quot;&gt;import java.util.Random;      &lt;br /&gt;import org.apache.log4j.MDC; &lt;/font&gt;&lt;/p&gt;  &lt;p&gt;&lt;font face=&quot;georg&quot;&gt;public class MyLogDecorator {&amp;#160; &lt;br /&gt;&lt;/font&gt;&lt;font face=&quot;georg&quot;&gt;&amp;#160; private static Random myrandom = new Random();&amp;#160; &lt;br /&gt;&lt;/font&gt;&lt;font face=&quot;georg&quot;&gt;&amp;#160;&lt;font color=&quot;#008000&quot;&gt; // use enum to ensure compile-time safety&amp;#160; &lt;br /&gt;&lt;/font&gt;&amp;#160; public enum LoggerFields{       &lt;br /&gt;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160; RequestId,       &lt;br /&gt;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160; &lt;font color=&quot;#008000&quot;&gt;//plus other fields relevant to your app&lt;/font&gt;       &lt;br /&gt;&amp;#160;&amp;#160;&amp;#160; } &lt;/font&gt;&lt;/p&gt;  &lt;p&gt;&lt;font face=&quot;georg&quot;&gt;public static void put(LoggerFields key, Object value){      &lt;br /&gt;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160; MDC.put(key.toString(), value.toString());       &lt;br /&gt;}       &lt;br /&gt;public static void remove(LoggerFields key){       &lt;br /&gt;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160; MDC.remove(key.toString());       &lt;br /&gt;}       &lt;br /&gt;&lt;font color=&quot;#008000&quot;&gt;/* make sure that context is empty and add a &lt;/font&gt;&lt;/font&gt;&lt;/p&gt;  &lt;p&gt;&lt;font face=&quot;georg&quot; color=&quot;#008000&quot;&gt; random request id */&lt;/font&gt;&lt;/p&gt;  &lt;p&gt;&lt;font face=&quot;georg&quot;&gt;public static void beginRequest(){      &lt;br /&gt;if (MDC.getContext()!=null &amp;amp;&amp;amp; &lt;/font&gt;&lt;/p&gt;  &lt;p&gt;&lt;font face=&quot;georg&quot;&gt;&amp;#160;&amp;#160;&amp;#160; MDC.getContext().size()&amp;gt;0){      &lt;br /&gt;endRequest();&lt;/font&gt;&lt;/p&gt;  &lt;p&gt;&lt;font face=&quot;georg&quot;&gt;} &lt;/font&gt;&lt;/p&gt;  &lt;p&gt;&lt;font face=&quot;georg&quot;&gt;put(LoggerFields.RequestId, &lt;/font&gt;&lt;/p&gt;  &lt;p&gt;&lt;font face=&quot;georg&quot;&gt;&amp;#160;&amp;#160;&amp;#160; myrandom.nextInt(10000000));      &lt;br /&gt;}       &lt;br /&gt;&lt;/font&gt;&lt;/p&gt;  &lt;p&gt;&lt;font face=&quot;georg&quot;&gt;public static void endRequest()&amp;#160;&amp;#160;&amp;#160; {      &lt;br /&gt;for(LoggerFields key : LoggerFields.values())&amp;#160;&amp;#160;&amp;#160; {       &lt;br /&gt;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160; remove(key);       &lt;br /&gt;}}&lt;/font&gt;&lt;font face=&quot;georg&quot;&gt;}&lt;/font&gt;&lt;/p&gt;  &lt;ul&gt;   &lt;li&gt;&lt;font color=&quot;#0000ff&quot;&gt;call &lt;strong&gt;MyLogDecorator&lt;/strong&gt; inside a Tomcat filter&lt;/font&gt;. &lt;font face=&quot;georg&quot;&gt;Filter code is fairly standard.&amp;#160; Note that MyLogDecorator.beginRequest() call can be made by any application (e.g. multithreaded command-line up).&lt;/font&gt; &lt;/li&gt; &lt;/ul&gt;  &lt;p&gt;&lt;font face=&quot;georg&quot;&gt;public void doFilter(...) {&lt;/font&gt;&lt;/p&gt;  &lt;p&gt;&lt;font face=&quot;georg&quot;&gt;&amp;#160;&amp;#160;&amp;#160; MyLogDecorator.beginRequest();      &lt;br /&gt;&amp;#160;&amp;#160;&amp;#160; chain.doFilter(request, response);       &lt;br /&gt;}&lt;/font&gt;&lt;/p&gt;  &lt;ul&gt;   &lt;li&gt;&lt;font color=&quot;#0000ff&quot;&gt;update pattern layout in log4j.xml to automatically add request id to every log statement:&lt;/font&gt;       &lt;p&gt;&amp;lt;param name=&amp;quot;ConversionPattern&amp;quot; value=&amp;quot;%d{yyyy-MM-dd HH:mm:ss.SSS} -%1X{RequestId} %c - %m%n&amp;quot;/&amp;gt; &lt;/p&gt;   &lt;/li&gt; &lt;/ul&gt;  &lt;div class=&quot;blogger-post-footer&quot;&gt;&lt;script expr:src=&#39;&quot;http://feeds.feedburner.com/~s/AJavaPerspectiveForDotNetDevelopers?i=&quot; + data:post.url&#39; type=&quot;text/javascript&quot; charset=&quot;utf-8&quot;&gt;&lt;/script&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://ajavaperspective.blogspot.com/feeds/7747242553122247079/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment/fullpage/post/260065058526360285/7747242553122247079' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/260065058526360285/posts/default/7747242553122247079'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/260065058526360285/posts/default/7747242553122247079'/><link rel='alternate' type='text/html' href='http://ajavaperspective.blogspot.com/2008/08/tracking-requests-in-multithreaded.html' title='Tracking requests in multithreaded environment'/><author><name>Yuri</name><uri>http://www.blogger.com/profile/10050240503141428160</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='16' height='16' src='https://img1.blogblog.com/img/b16-rounded.gif'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-260065058526360285.post-2798870734230185515</id><published>2008-07-16T22:47:00.001-07:00</published><updated>2008-07-16T23:05:30.358-07:00</updated><title type='text'>The Taming of the JMeter: command-line arguments, tidy, bean shell</title><content type='html'>&lt;p&gt;&lt;br /&gt;&lt;a href=&quot;http://jakarta.apache.org/jmeter/&quot; target=&quot;_blank&quot;&gt;JMeter&lt;/a&gt; is powerful but poorly documented. Here’re few things that everyone could use: &lt;/p&gt;&lt;ul&gt;&lt;li&gt;In order to change User Defined variables from the command line, convert them to properties:&lt;/li&gt;&lt;/ul&gt;&lt;p&gt;&lt;a href=&quot;http://lh5.ggpht.com/yuri.romanenko/SH7dCYWh2iI/AAAAAAAAACI/jAt7i5pOxkc/s1600-h/clip_image002%5B3%5D.jpg&quot;&gt;&lt;img style=&quot;BORDER-RIGHT: 0px; BORDER-TOP: 0px; BORDER-LEFT: 0px; BORDER-BOTTOM: 0px&quot; height=&quot;51&quot; alt=&quot;clip_image002&quot; src=&quot;http://lh3.ggpht.com/yuri.romanenko/SH7dCrCalnI/AAAAAAAAACM/9sKIL8kAIXs/clip_image002_thumb.jpg?imgmax=800&quot; width=&quot;244&quot; border=&quot;0&quot; /&gt;&lt;/a&gt;&lt;/p&gt;&lt;p&gt;&lt;b&gt;&lt;/b&gt;&lt;/p&gt;&lt;p&gt;Now you can store default values in user.properties file and override them by passing &lt;b&gt;-J &lt;/b&gt;parameter on the command line: e.g. &lt;i&gt;-Jthreadcount=1 -JdataFile=data1.xml&lt;/i&gt;&lt;/p&gt;&lt;p&gt;If user.properties file has changed, jmeter must be restared.&lt;/p&gt;&lt;ul&gt;&lt;li&gt;JMeter allows for sophisticated XPath expressions that can be used to parse a random HTML page – just make sure to set “Use Tidy” check-box.&lt;/li&gt;&lt;/ul&gt;&lt;p&gt;&lt;a href=&quot;http://lh6.ggpht.com/yuri.romanenko/SH7dClGZcJI/AAAAAAAAACQ/Dug4YNThwNY/s1600-h/clip_image004%5B3%5D.jpg&quot;&gt;&lt;img style=&quot;BORDER-RIGHT: 0px; BORDER-TOP: 0px; BORDER-LEFT: 0px; BORDER-BOTTOM: 0px&quot; height=&quot;56&quot; alt=&quot;clip_image004&quot; src=&quot;http://lh6.ggpht.com/yuri.romanenko/SH7dC1ioFQI/AAAAAAAAACc/UNshJK7-vOo/clip_image004_thumb.jpg?imgmax=800&quot; width=&quot;244&quot; border=&quot;0&quot; /&gt;&lt;/a&gt;&lt;/p&gt;&lt;p&gt;&lt;b&gt;&lt;/b&gt;&lt;/p&gt;&lt;p&gt;XPath expression can also include JMeter variables, e.g. &lt;/p&gt;&lt;p&gt;/html/body/table/tbody//tr[${__V(server${serverIndex}Section2Header)} + 2]//text()&lt;/p&gt;&lt;p&gt;This is pure goodness… &lt;/p&gt;&lt;ul&gt;&lt;li&gt;What makes JMeter even more powerful is its ability to integrate with &lt;a href=&quot;http://www.beanshell.org/&quot; target=&quot;_blank&quot;&gt;Bean Shell&lt;/a&gt; – you have to copy beanshell’s bsh-2.0b4.jar to jakarta-jmeter-2.3\lib\ext and rename this as bsh.jar – that’s it… Buyer beware: invoking bean shell in a loop is awfully slow. Debugging a bean shell script is nightmare consisting of adding print statements throughout your code. Passing –LDEBUG flag may help with troubleshooting.&lt;br /&gt;&lt;br /&gt;Sometimes I feel it’s just easier to dump data extracted with JMeter script and analyze it with a standalone java program.&lt;/li&gt;&lt;/ul&gt;&lt;p&gt;If JMeter had tighter integration with BeanShell or, even better, allowed for calling user-specified java classes within the same &lt;/p&gt;&lt;p&gt;JVM (to speed things up), it’d rule!&lt;/p&gt;&lt;div class=&quot;wlWriterSmartContent&quot; id=&quot;scid:0767317B-992E-4b12-91E0-4F059A8CECA8:9152a007-9bfb-4cb1-9bbb-8437ecbc633d&quot; style=&quot;PADDING-RIGHT: 0px; DISPLAY: inline; PADDING-LEFT: 0px; PADDING-BOTTOM: 0px; MARGIN: 0px; PADDING-TOP: 0px&quot;&gt;Technorati Tags: &lt;a href=&quot;http://technorati.com/tags/JMeter&quot; rel=&quot;tag&quot; target=&quot;_blank&quot;&gt;JMeter&lt;/a&gt;&lt;/div&gt;&lt;div class=&quot;blogger-post-footer&quot;&gt;&lt;script expr:src=&#39;&quot;http://feeds.feedburner.com/~s/AJavaPerspectiveForDotNetDevelopers?i=&quot; + data:post.url&#39; type=&quot;text/javascript&quot; charset=&quot;utf-8&quot;&gt;&lt;/script&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://ajavaperspective.blogspot.com/feeds/2798870734230185515/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment/fullpage/post/260065058526360285/2798870734230185515' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/260065058526360285/posts/default/2798870734230185515'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/260065058526360285/posts/default/2798870734230185515'/><link rel='alternate' type='text/html' href='http://ajavaperspective.blogspot.com/2008/07/taming-of-jmeter-command-line-arguments.html' title='The Taming of the JMeter: command-line arguments, tidy, bean shell'/><author><name>Yuri</name><uri>http://www.blogger.com/profile/10050240503141428160</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='16' height='16' src='https://img1.blogblog.com/img/b16-rounded.gif'/></author><media:thumbnail xmlns:media="http://search.yahoo.com/mrss/" url="http://lh3.ggpht.com/yuri.romanenko/SH7dCrCalnI/AAAAAAAAACM/9sKIL8kAIXs/s72-c/clip_image002_thumb.jpg?imgmax=800" height="72" width="72"/><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-260065058526360285.post-5861418929131134350</id><published>2008-06-19T07:09:00.000-07:00</published><updated>2008-06-19T08:07:23.595-07:00</updated><title type='text'>Deterministic unittests with ExecutorService</title><content type='html'>Java threadpool (ExecutorService) objects have some differences with .NET Threadpool:&lt;br /&gt;- you can code to the ExecutorService interface&lt;br /&gt;- you can call awaitTermination() to let all threads finish&lt;br /&gt;- and you can use different thread pool objects, for example:&lt;br /&gt;&lt;br /&gt;  · Executors.newCachedThreadPool() is similar to .NET Threadpool where you let JVM manage the number of active threads. However, .NET Threadpool resists creating new threads (and rightfully so), while cached thread pool will create one on demand (according to &lt;a type=&quot;amzn&quot; asin=&quot;0321356683&quot;&gt;Effective Java™, Second Edition&lt;/a&gt;.)&lt;br /&gt;  · Executors.newFixedThreadPool() let you control the number of thread.&lt;br /&gt;&lt;br /&gt;While I usually default to a fixed thread pool, I think one should put code under stress to see which one is better and also allow for switching between two if underlying implementation change – code to the interface!&lt;br /&gt;&lt;br /&gt;&lt;span style=&quot;font-family:courier new;font-size:85%;&quot;&gt;int numberOfThreads = //get from configs&lt;br /&gt;if (numberOfThreads&lt;=0){ &lt;/span&gt;&lt;br /&gt;&lt;span style=&quot;font-family:courier new;font-size:85%;&quot;&gt;executor = Executors.newCachedThreadPool(); &lt;/span&gt;&lt;br /&gt;&lt;span style=&quot;font-family:courier new;font-size:85%;&quot;&gt;} &lt;/span&gt;&lt;br /&gt;&lt;span style=&quot;font-family:courier new;font-size:85%;&quot;&gt;else{ &lt;/span&gt;&lt;br /&gt;&lt;span style=&quot;font-family:courier new;font-size:85%;&quot;&gt;executor = Executors.newFixedThreadPool(numberOfThreads);&lt;/span&gt;&lt;br /&gt;&lt;span style=&quot;font-family:courier new;font-size:85%;&quot;&gt;} &lt;/span&gt;&lt;br /&gt;&lt;br /&gt;I use &lt;a href=&quot;http://www.jmock.org/&quot; target=&quot;_blank&quot;&gt;jmock&lt;/a&gt; a lot for unittests but quickly discovered that it is not threadsafe. I wanted deterministic execution of my unittests, but couldn’t give up on either Jmock or threadpool. I&#39;ve read jmock &lt;a href=&quot;http://www.jmock.org/threads.html&quot; target=&quot;_blank&quot;&gt;faq&lt;/a&gt; on threads and got an idea to mock both threadpool and Future objects:&lt;br /&gt;&lt;br /&gt;&lt;span style=&quot;font-family:courier new;font-size:85%;&quot;&gt;public class MockThreadPoolExecutorFixture implements ExecutorService {&lt;br /&gt;private MockThreadPoolExecutorFixture(){}&lt;br /&gt;&lt;br /&gt;public static ExecutorService getInstance(){&lt;br /&gt;return new MockThreadPoolExecutorFixture();&lt;br /&gt;}&lt;br /&gt;&lt;br /&gt;@Override&lt;br /&gt;public &lt;t&gt;Future&lt;t&gt; submit(Callable&lt;t&gt; mytask){&lt;br /&gt;MockFutureFixture&lt;t&gt; myfuture = new MockFutureFixture&lt;t&gt;(mytask);&lt;br /&gt;return myfuture;&lt;br /&gt;}&lt;br /&gt;/*other API return default values of null or false – they were not used, feel free to override them as well if need be*/&lt;br /&gt;}&lt;br /&gt;&lt;br /&gt;public class MockFutureFixture&lt;v&gt; implements Future&lt;v&gt; {&lt;br /&gt;private Callable&lt;v&gt; mycall;&lt;br /&gt;public MockFutureFixture(Callable&lt;v&gt; arg0) {&lt;br /&gt;mycall = arg0;&lt;br /&gt;}&lt;br /&gt;&lt;br /&gt;@Override&lt;br /&gt;public V get() throws ExecutionException {&lt;br /&gt;try{&lt;br /&gt;return mycall.call();&lt;br /&gt;}&lt;br /&gt;catch (Exception e){&lt;br /&gt;throw new ExecutionException(e);&lt;br /&gt;}&lt;br /&gt;}&lt;br /&gt;/*other API return default values of null or false – they were not used, feel free to override them as well if need be*/&lt;br /&gt;}&lt;br /&gt;&lt;/span&gt;Of course, the next step is to stress the hell out of your code using real threadpool to see if you get thread synchronization problems.&lt;div class=&quot;blogger-post-footer&quot;&gt;&lt;script expr:src=&#39;&quot;http://feeds.feedburner.com/~s/AJavaPerspectiveForDotNetDevelopers?i=&quot; + data:post.url&#39; type=&quot;text/javascript&quot; charset=&quot;utf-8&quot;&gt;&lt;/script&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://ajavaperspective.blogspot.com/feeds/5861418929131134350/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment/fullpage/post/260065058526360285/5861418929131134350' title='2 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/260065058526360285/posts/default/5861418929131134350'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/260065058526360285/posts/default/5861418929131134350'/><link rel='alternate' type='text/html' href='http://ajavaperspective.blogspot.com/2008/06/unittests-for-executorservice.html' title='Deterministic unittests with ExecutorService'/><author><name>Yuri</name><uri>http://www.blogger.com/profile/10050240503141428160</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='16' height='16' src='https://img1.blogblog.com/img/b16-rounded.gif'/></author><thr:total>2</thr:total></entry><entry><id>tag:blogger.com,1999:blog-260065058526360285.post-6240941417005091355</id><published>2008-05-27T21:17:00.000-07:00</published><updated>2008-05-27T21:34:14.579-07:00</updated><category scheme="http://www.blogger.com/atom/ns#" term="debug"/><category scheme="http://www.blogger.com/atom/ns#" term="tomcat"/><title type='text'>Debugging under Tomcat</title><content type='html'>Ever wonder how to debug a webapp running under tomcat? &lt;a href=&quot;http://www.eclipsetotale.com/tomcatPlugin.html&quot; target=&quot;_blank&quot;&gt;This&lt;/a&gt; tomcat plug-in for Eclipse is just about perfect.  Main documentation is in French… so here the trick: after following the installation steps simply configure it in Windows-&gt;Preferences-&gt;Tomcat (see attached screenshot).&lt;br /&gt;&lt;a href=&quot;https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEhzPsTmuyrp3db7ZO1FtizIBhQnr55nXF1_GgyMnPvLiMQoQKceCSFqDHO1hK3ycDMeO58bEeDA_-VK-KRsLhoL83rna6L86qOvzlJaYvujG6mG_zk5jWTcU2S1k_efG-kfaRf3wlVrTaEW/s1600-h/tomcat.jpg&quot;&gt;&lt;img id=&quot;BLOGGER_PHOTO_ID_5205281413147472642&quot; style=&quot;FLOAT: left; MARGIN: 0px 10px 10px 0px; CURSOR: hand&quot; alt=&quot;&quot; src=&quot;https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEhzPsTmuyrp3db7ZO1FtizIBhQnr55nXF1_GgyMnPvLiMQoQKceCSFqDHO1hK3ycDMeO58bEeDA_-VK-KRsLhoL83rna6L86qOvzlJaYvujG6mG_zk5jWTcU2S1k_efG-kfaRf3wlVrTaEW/s320/tomcat.jpg&quot; border=&quot;0&quot; /&gt;&lt;/a&gt;&lt;br /&gt;Now you can start your app from within eclipse and debug away!&lt;div class=&quot;blogger-post-footer&quot;&gt;&lt;script expr:src=&#39;&quot;http://feeds.feedburner.com/~s/AJavaPerspectiveForDotNetDevelopers?i=&quot; + data:post.url&#39; type=&quot;text/javascript&quot; charset=&quot;utf-8&quot;&gt;&lt;/script&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://ajavaperspective.blogspot.com/feeds/6240941417005091355/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment/fullpage/post/260065058526360285/6240941417005091355' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/260065058526360285/posts/default/6240941417005091355'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/260065058526360285/posts/default/6240941417005091355'/><link rel='alternate' type='text/html' href='http://ajavaperspective.blogspot.com/2008/05/debugging-under-tomcat.html' title='Debugging under Tomcat'/><author><name>Yuri</name><uri>http://www.blogger.com/profile/10050240503141428160</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='16' height='16' src='https://img1.blogblog.com/img/b16-rounded.gif'/></author><media:thumbnail xmlns:media="http://search.yahoo.com/mrss/" url="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEhzPsTmuyrp3db7ZO1FtizIBhQnr55nXF1_GgyMnPvLiMQoQKceCSFqDHO1hK3ycDMeO58bEeDA_-VK-KRsLhoL83rna6L86qOvzlJaYvujG6mG_zk5jWTcU2S1k_efG-kfaRf3wlVrTaEW/s72-c/tomcat.jpg" height="72" width="72"/><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-260065058526360285.post-5726566999766531021</id><published>2008-04-17T14:45:00.000-07:00</published><updated>2008-04-17T14:55:35.040-07:00</updated><category scheme="http://www.blogger.com/atom/ns#" term="instrumenting"/><category scheme="http://www.blogger.com/atom/ns#" term="JMX"/><category scheme="http://www.blogger.com/atom/ns#" term="MBeans"/><category scheme="http://www.blogger.com/atom/ns#" term="monitoring"/><category scheme="http://www.blogger.com/atom/ns#" term="Perf Counters"/><title type='text'>Perf Counters using JMX MBeans</title><content type='html'>Performance Counters are part of Windows and are easily available within any .NET app. A bit of kludgy install code and you’re pretty much done. Various monitoring system pick up data, monitor the site and alarm Ops.&lt;br /&gt;&lt;br /&gt;JMX &lt;a href=&quot;http://java.sun.com/j2se/1.5.0/docs/guide/management/overview.html&quot; target=&quot;_blank&quot;&gt;MBeans&lt;/a&gt; is a Java approach for monitoring and management of your application. MBeans not only allow you to instrument the code but also allow your application to notify listeners when something goes wrong. Moreover, they allow for a back-channel to your application to allow for changing behavior on a fly. While the latter feature if nice, I honestly don’t see anyone changing production environment in this manner. Still, it’s a rather slick solution for, say, evaluating various config settings during development or stress testing.&lt;br /&gt;&lt;br /&gt;When tasked with instrumenting my application, start by implementing generic “perf counters”. Check &lt;a href=&quot;http://msdn2.microsoft.com/en-us/library/system.diagnostics.performancecountertype.aspx&quot; target=&quot;_blank&quot;&gt;.net documentation&lt;/a&gt; and implement similar objects in Java. For example, for Average perf counter specify two APIs: &lt;em&gt;add&lt;/em&gt; and &lt;em&gt;get&lt;/em&gt;&lt;br /&gt;&lt;br /&gt;&lt;span style=&quot;font-family:courier new;font-size:85%;&quot;&gt;public void add(int delta)&lt;br /&gt;{&lt;br /&gt;operationscounter.incrementAndGet();&lt;br /&gt;timecounter.addAndGet(delta);&lt;br /&gt;}&lt;br /&gt;&lt;br /&gt;public double get()&lt;br /&gt;{&lt;br /&gt;int currentValue = operationscounter.getAndSet(0);&lt;br /&gt;int accumulatedTime = timecounter.getAndSet(0);&lt;br /&gt;&lt;br /&gt;return accumulatedTime / (double) currentValue;&lt;br /&gt;}&lt;br /&gt;&lt;/span&gt;&lt;br /&gt;While both both operationscounter and timecounter are AtomicIntegers, the above APIs are not thread-safe. I purposely left out synchronized keyword to get better performance. We’re not counting $$ after all, so it’s ok if data is slightly off. The second - &lt;em&gt;get&lt;/em&gt; - api also resets both counters to 0 (ok, check that denominator is not zero; check for overflow – small details).&lt;br /&gt;&lt;br /&gt;Similarly, you can create a rate perf counter:&lt;br /&gt;&lt;span style=&quot;font-family:courier new;&quot;&gt;&lt;span style=&quot;font-size:85%;&quot;&gt;public void increment()&lt;br /&gt;{&lt;br /&gt;mycounter.incrementAndGet();&lt;br /&gt;}&lt;br /&gt;&lt;br /&gt;public double get()&lt;br /&gt;{&lt;br /&gt;long timeNow = System.currentTimeMillis();&lt;br /&gt;final double delta = timeNow – lastPollTime;&lt;br /&gt;lastPollTime = timeNow; //reset time stamp&lt;br /&gt;double result = currentValue/delta * multiplier; &lt;/span&gt;&lt;/span&gt;&lt;br /&gt;&lt;span style=&quot;font-family:courier new;&quot;&gt;&lt;span style=&quot;font-size:85%;&quot;&gt;&lt;/span&gt;&lt;span style=&quot;font-size:85%;&quot;&gt;&lt;em&gt;&lt;span style=&quot;color:#3366ff;&quot;&gt;// multiplier=1000 when returning results in seconds&lt;br /&gt;&lt;/span&gt;&lt;/em&gt;return result;&lt;br /&gt;}&lt;/span&gt;&lt;/span&gt;&lt;span style=&quot;font-size:85%;&quot;&gt;&lt;br /&gt;&lt;/span&gt;&lt;br /&gt;Once perf counters are written, instrument your application and expose data via an MBean. MBean is a regular java class implementing a specially constructed MBean interface: only few rules to follow: your class must have a default constructor; if you class name is MyService, than the MBean interface must be name MyServiceMBean, etc. Amazon has a few JMX-related books; they don’t cover MXBeans which are thoroughly described in &lt;a href=&quot;http://weblogs.java.net/blog/emcmanus/archive/2006/02/what_is_an_mxbe.html&quot; target=&quot;_blank&quot;&gt;this&lt;/a&gt; article.&lt;br /&gt;&lt;br /&gt;e.g. MBean interface:&lt;br /&gt;&lt;span style=&quot;font-size:85%;&quot;&gt;&lt;span style=&quot;font-family:courier new;&quot;&gt;public interface MyServiceMBean&lt;br /&gt;{&lt;br /&gt;public int getRequestsCount();&lt;br /&gt;public int getSystemFailuresCount();&lt;br /&gt;public double getAverageProcessingTime();&lt;br /&gt;public double getRequestRate();&lt;br /&gt;}&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;&lt;span style=&quot;font-family:Courier New;&quot;&gt;public class MyService implements MyServiceMBean&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;&lt;span style=&quot;font-family:Courier New;&quot;&gt;{&lt;/span&gt;&lt;br /&gt;&lt;span style=&quot;font-family:Courier New;&quot;&gt;...&lt;/span&gt;&lt;br /&gt;&lt;span style=&quot;font-family:Courier New;&quot;&gt;}&lt;/span&gt;&lt;br /&gt;&lt;/span&gt;As with Windows perf counters installation, there is a bit of initialization code (5 lines below) and then any JMX-aware monitoring system will be able to see MBeans and poll for data. You can also run &lt;a href=&quot;http://java.sun.com/developer/technicalArticles/J2SE/jconsole.html&quot; target=&quot;_blank&quot;&gt;jconsole&lt;/a&gt; during development phase to verify your JMX MBean implementation.&lt;br /&gt;&lt;br /&gt;Initialization code:&lt;br /&gt;&lt;span style=&quot;font-family:courier new;&quot;&gt;&lt;span style=&quot;font-size:85%;&quot;&gt;MyService instance = new MyService();&lt;br /&gt;String jmxlabel = “MyService:type=MoneyMakerService”;&lt;br /&gt;MBeanServer mbs = ManagementFactory.getPlatformMBeanServer();&lt;br /&gt;ObjectName name = new ObjectName(jmxlabel);&lt;br /&gt;mbs.registerMBean(instance, name);&lt;/span&gt;&lt;br /&gt;&lt;/span&gt;&lt;br /&gt;One caveat: you can’t pack various counter data (request count, rate, etc) into an object or return them as array: otherwise (as of today) data won’t be processed correctly by some management systems. MXBeans appeared to be an answer as the data can be indeed wrapped into a class and shows up nicely on the monitoring side… but, at least with &lt;a href=&quot;http://manageengine.adventnet.com/products/applications_manager/index.html&quot; target=&quot;_blank&quot;&gt;Manage Engine&lt;/a&gt;, the values are treated as strings so you can’t alert on them. You can easily convert to MXBeans later on if need be – but the perf counters classes you build would not have to change!&lt;div class=&quot;blogger-post-footer&quot;&gt;&lt;script expr:src=&#39;&quot;http://feeds.feedburner.com/~s/AJavaPerspectiveForDotNetDevelopers?i=&quot; + data:post.url&#39; type=&quot;text/javascript&quot; charset=&quot;utf-8&quot;&gt;&lt;/script&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://ajavaperspective.blogspot.com/feeds/5726566999766531021/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment/fullpage/post/260065058526360285/5726566999766531021' title='1 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/260065058526360285/posts/default/5726566999766531021'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/260065058526360285/posts/default/5726566999766531021'/><link rel='alternate' type='text/html' href='http://ajavaperspective.blogspot.com/2008/04/perf-counters-using-jmx-mbeans.html' title='Perf Counters using JMX MBeans'/><author><name>Yuri</name><uri>http://www.blogger.com/profile/10050240503141428160</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='16' height='16' src='https://img1.blogblog.com/img/b16-rounded.gif'/></author><thr:total>1</thr:total></entry><entry><id>tag:blogger.com,1999:blog-260065058526360285.post-9153336710465129479</id><published>2008-04-06T12:05:00.000-07:00</published><updated>2008-04-06T12:12:46.411-07:00</updated><category scheme="http://www.blogger.com/atom/ns#" term=".NET"/><category scheme="http://www.blogger.com/atom/ns#" term="Axis2"/><category scheme="http://www.blogger.com/atom/ns#" term="CFX"/><category scheme="http://www.blogger.com/atom/ns#" term="Java"/><category scheme="http://www.blogger.com/atom/ns#" term="Web Service"/><category scheme="http://www.blogger.com/atom/ns#" term="Web Services"/><title type='text'>Web Services</title><content type='html'>&lt;p&gt;It’s all about web services nowadays. It was very simple to create one in .NET – just run dev studio wizard and off you go. Not so fast in Java. First you should pick a library that takes care of SOAP layer. There are a couple big ones, namely &lt;a href=&quot;http://ws.apache.org/axis2/&quot; target=&quot;_blank&quot;&gt;Axis2&lt;/a&gt; and &lt;a href=&quot;http://incubator.apache.org/cxf/&quot; target=&quot;_blank&quot;&gt;XFire/CXF&lt;/a&gt;, both look &lt;a href=&quot;http://www.theserverside.com/tt/articles/article.tss?l=AxisAxis2andCXF&quot; target=&quot;_blank&quot;&gt;robust enough&lt;/a&gt;.&lt;br /&gt;&lt;br /&gt;Axis2 is a complete re-write and in some cases is not compatible with original Axis clients. I still picked Axis2 as it has simple way of wrapping objects into web service calls and doesn’t require tagging them with attributes like CXF. Also, Axis2 allows your object be exposed via &lt;a href=&quot;http://en.wikipedia.org/wiki/Representational_State_Transfer&quot; target=&quot;_blank&quot;&gt;REST&lt;/a&gt;. Basically, you create a &lt;a href=&quot;http://en.wikipedia.org/wiki/Plain_Old_Java_Object&quot; target=&quot;_blank&quot;&gt;POJO&lt;/a&gt; (fancy word for a simple object with setters and getters), update service.xml file to reference this object and you’re done…&lt;br /&gt;Well, there are some caveats:&lt;br /&gt;&lt;/p&gt;&lt;ul&gt;&lt;li&gt;You must have an empty constructor. &lt;/li&gt;&lt;li&gt;Do not overload constructors – it usually works but I’ve ran into scenario where objects were not de-serialized properly and wasted a day chasing down the problem: removing overloaded constructors fixed the issue. &lt;/li&gt;&lt;li&gt;No helper functions other than setters/getters in your object – or they’ll show up in wsdl and mess things up on the client side.&lt;br /&gt;&lt;/li&gt;&lt;/ul&gt;&lt;p&gt;e.g. my entire web service layer now looks like this:&lt;br /&gt;public class MyWS&lt;br /&gt;{&lt;br /&gt;public MyWSResponse SomeRequest(String myarg)&lt;br /&gt;{&lt;br /&gt;MyWSResponse = MyLogicLayer.getInstance().processSomeRequest(myarg);&lt;br /&gt;}&lt;br /&gt;}&lt;br /&gt;&lt;br /&gt;MyWSResponse has only an empty constructor and few setters/getters. Add the following to service.xml and you’re done.&lt;br /&gt;&lt;br /&gt;&amp;lt;service name=&quot;MyWS&quot; scope=&quot;application&quot;&amp;gt;&lt;br /&gt;&amp;lt;description&amp;gt;&lt;br /&gt;My SOAP Service&lt;br /&gt;&amp;lt;/description&amp;gt;&lt;br /&gt;&amp;lt;messageReceivers&amp;gt;&lt;br /&gt;&amp;lt;messageReceiver mep=&quot;http://www.w3.org/2004/08/wsdl/in-out&quot;&lt;br /&gt;class=&quot;org.apache.axis2.rpc.receivers.RPCMessageReceiver&quot;/&amp;gt;&lt;br /&gt;&amp;lt;/messageReceivers&amp;gt;&lt;br /&gt;&amp;lt;parameter name=&quot;ServiceClass&quot;&amp;gt;com.mycompany.MyWS&amp;lt;/parameter&amp;gt;&lt;br /&gt;&amp;lt;/service&amp;gt;&lt;br /&gt;&lt;br /&gt;Entire logic is encapsulated in the MyLogicLayer – makes a very convenient setup for unittests.&lt;br /&gt;&lt;br /&gt;You can run axis2 web service standalone or package it in a war file with other web services or servlets.&lt;br /&gt;&lt;br /&gt;Axis2 comes with many jars – I recommend keeping them in a separate folder and package with your code in build time - this way upgrade to newer Axis2 release will be easy.&lt;br /&gt;&lt;br /&gt;Finally, you can extend Axis’ AbstractHandler to create a module logging every incoming and outgoing message (which was rather painful to do in .NET). The skeleton code is below:&lt;br /&gt;&lt;br /&gt;public InvocationResponse invoke(MessageContext msgContext) throws AxisFault&lt;br /&gt;{&lt;br /&gt;HttpServletRequest request = (HttpServletRequest)msgContext.getProperty(&quot;transport.http.servletRequest&quot;);&lt;br /&gt;//call request.getHeaderNames() and log headers&lt;br /&gt;&lt;br /&gt;//then log message body: msgContext.getEnvelope().toString()&lt;br /&gt;&lt;br /&gt;return InvocationResponse.CONTINUE;&lt;br /&gt;}&lt;br /&gt;&lt;br /&gt;I also removed axis admin servlet from final deployment – I am a bit paranoid of having a GUI-based access to production environment (or I’ll be tempted to make ad-hoc changes to running system at 3am :-).&lt;/p&gt;&lt;div class=&quot;blogger-post-footer&quot;&gt;&lt;script expr:src=&#39;&quot;http://feeds.feedburner.com/~s/AJavaPerspectiveForDotNetDevelopers?i=&quot; + data:post.url&#39; type=&quot;text/javascript&quot; charset=&quot;utf-8&quot;&gt;&lt;/script&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://ajavaperspective.blogspot.com/feeds/9153336710465129479/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment/fullpage/post/260065058526360285/9153336710465129479' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/260065058526360285/posts/default/9153336710465129479'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/260065058526360285/posts/default/9153336710465129479'/><link rel='alternate' type='text/html' href='http://ajavaperspective.blogspot.com/2008/04/web-services.html' title='Web Services'/><author><name>Yuri</name><uri>http://www.blogger.com/profile/10050240503141428160</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='16' height='16' src='https://img1.blogblog.com/img/b16-rounded.gif'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-260065058526360285.post-3358396997856847767</id><published>2008-04-01T20:52:00.000-07:00</published><updated>2008-04-01T21:44:02.051-07:00</updated><category scheme="http://www.blogger.com/atom/ns#" term="Clover"/><category scheme="http://www.blogger.com/atom/ns#" term="Code Analysis"/><category scheme="http://www.blogger.com/atom/ns#" term="Code Coverage"/><category scheme="http://www.blogger.com/atom/ns#" term="Eclipse"/><category scheme="http://www.blogger.com/atom/ns#" term="Findbugs"/><category scheme="http://www.blogger.com/atom/ns#" term="PMD"/><title type='text'>Tools</title><content type='html'>Development environment: use &lt;a href=&quot;http://www.eclipse.org/&quot; target=&quot;_blank&quot;&gt;Eclipse&lt;/a&gt;. Although some people are raving about latest &lt;a href=&quot;http://www.netbeans.org/&quot; target=&quot;_blank&quot;&gt;NetBeans&lt;/a&gt; release. Eclipse has more plugins though.   &lt;em&gt;Ctrl+Shift+L &lt;/em&gt;is your friend -- you&#39;ll see a popup listing all keyboard shortcuts.&lt;br /&gt;&lt;br /&gt;.NET or Java, you have to have continuous builds, unittests, functional tests, code-analysis scans, sane source control practices in additional to design and code reviews, not to mention proper. I am not trying to sound pompous – it just makes sense after you try it.&lt;br /&gt;&lt;br /&gt;Start with good code analysis tools and there are a few descent alternatives to FxCop in Java world. The sooner you set up code checks that easier it’d be to keep it clean.&lt;br /&gt;&lt;br /&gt;&lt;ul&gt;&lt;li&gt;&lt;div align=&quot;left&quot;&gt;PMD is a static analysis tool that examines the source code. I am not crazy about all the rules and lowered “final” keyword priority to 4 but bumped up &lt;a href=&quot;http://en.wikipedia.org/wiki/Cyclomatic_complexity&quot; target=&quot;_blank&quot;&gt;Cyclomatic Complexity&lt;/a&gt; to P1. CPD is part of PMD package and will not let you get away with copy-paste code that so often leads to errors. I don’t recall seeing a warning in FxCop.&lt;br /&gt;&lt;/div&gt;&lt;/li&gt;&lt;li&gt;Findbugs is another good tool that examines compiled code (so don’t run it next to Code Coverage tool, like Clover). I set it up to run it on release builds only. &lt;/li&gt;&lt;/ul&gt;&lt;p&gt;Both PMD and Findbugs have Eclipse plugins but don’t be tempted to suppress warnings or your code will end up being cluttered with comments that make no sense when a new tool comes around. Just fix what you need to fix and lower priority for warnings or remove checks altogether for things that you don’t care for (e.g. “variable names are too long” nags from PMD…).&lt;/p&gt;&lt;ul&gt;&lt;li&gt;Code Coverage - &lt;a href=&quot;http://www.atlassian.com/software/clover/&quot; target=&quot;_blank&quot;&gt;Clover&lt;/a&gt;. &lt;/li&gt;&lt;/ul&gt;&lt;p&gt;Continuous builds is the key (we used &lt;a href=&quot;http://www.atlassian.com/software/bamboo/&quot;&gt;Bamboo&lt;/a&gt; to run our Ant scripts). Continuous builds should run unittests. Unittests without code coverage report don’t count, so setup &lt;a href=&quot;http://www.atlassian.com/software/clover/&quot; target=&quot;_blank&quot;&gt;Clover&lt;/a&gt;. &lt;/p&gt;&lt;p&gt;&lt;a href=&quot;https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEgIVQ_b7zmdhp5qE1TUW1TZsUUobLCDmaFBYchbSfgYFiySVjBREy89OmD1tkST3locBfueBpFgpNse2smo9EneqKIb3vGPfZHv5Of4XM-0_ykvDLDFg47KlGI-G38sd3QkLtZ-unj7A4IM/s1600-h/clover.jpg&quot;&gt;&lt;img id=&quot;BLOGGER_PHOTO_ID_5184493835833171906&quot; style=&quot;FLOAT: left; MARGIN: 0px 10px 10px 0px; CURSOR: hand&quot; alt=&quot;&quot; src=&quot;https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEgIVQ_b7zmdhp5qE1TUW1TZsUUobLCDmaFBYchbSfgYFiySVjBREy89OmD1tkST3locBfueBpFgpNse2smo9EneqKIb3vGPfZHv5Of4XM-0_ykvDLDFg47KlGI-G38sd3QkLtZ-unj7A4IM/s320/clover.jpg&quot; border=&quot;0&quot; /&gt;&lt;/a&gt;It’s cheap, effective, and will keep you honest especially when you start failing the builds when code coverage is below certain limit (we pick 90% in our team). &lt;/p&gt;&lt;p&gt;Clover plugin is very useful as well; just make sure to place instrumented class files in the project output folder (see screenshot). &lt;/p&gt;&lt;br /&gt;&lt;br /&gt;&lt;p&gt;&lt;/p&gt;&lt;p&gt;Another useful hint for clover is to automatically clover off if &lt;em&gt;(log.isDebugEnabled) &lt;/em&gt;and similar statements -- setup a statementContext filter in the Ant script: &lt;/p&gt;&lt;p align=&quot;left&quot;&gt;&lt;span style=&quot;font-size:85%;&quot;&gt;&amp;lt;target name=&quot;with.clover&quot;&amp;gt; &amp;lt;clover-setup&amp;gt;&lt;br /&gt;&amp;lt;statementContext name=&quot;iflog&quot; regexp=&quot;if.?\(log\.is.*&quot;/&amp;gt;&lt;br /&gt;&lt;/span&gt;&lt;span style=&quot;font-size:85%;&quot;&gt;&amp;lt;statementContext name=&quot;iflog_debug&quot; regexp=&quot;if.?\(isDebugEnabled\).*&quot;/&amp;gt;&lt;br /&gt;&lt;/span&gt;&lt;span style=&quot;font-size:85%;&quot;&gt;&amp;lt;statementContext name=&quot;iflog_trace&quot; regexp=&quot;if.?\(isTraceEnabled\).*&quot;/&amp;gt;&lt;br /&gt;&lt;/span&gt;&lt;span style=&quot;font-size:85%;&quot;&gt;…&lt;br /&gt;&lt;/span&gt;&lt;span style=&quot;font-size:85%;&quot;&gt;&amp;lt;/clover-setup&amp;gt;&lt;br /&gt;&lt;/span&gt;&lt;span style=&quot;font-size:85%;&quot;&gt;&amp;lt;/target&amp;gt; &lt;/span&gt;&lt;/p&gt;&lt;p align=&quot;left&quot;&gt;&lt;span style=&quot;font-size:85%;&quot;&gt;&amp;lt;target name=&quot;clover.reports&quot;&amp;gt;&lt;br /&gt;&amp;lt;clover-report&amp;gt;&lt;br /&gt;&amp;lt;current outfile=&quot;${clover.report.html.dir}&quot; title=&quot;MyProject&quot;&amp;gt; &amp;lt;format type=&quot;html&quot; filter=&quot;iflog,iflog_debug,iflog_trace&quot;/&amp;gt;&lt;br /&gt;&amp;lt;/current&amp;gt; &amp;lt;/clover-report&amp;gt;&lt;br /&gt;&amp;lt;clover-check target=&quot;90%&quot; filter=&quot;iflog,iflog_debug,iflog_trace&quot; haltOnFailure=&quot;true&quot;/&amp;gt; &amp;lt;/target&amp;gt;&lt;/span&gt;&lt;/p&gt;&lt;p&gt;Notice &lt;em&gt;clover-check&lt;/em&gt; with &lt;em&gt;haltOnFailure&lt;/em&gt; option in the segment above -- it&#39;ll keep you honest!&lt;br /&gt;Another caveat when using clover: while it recognizes code as test when it that contain JUnit attributes, it tends to treat any helper classes that you may need in unittests as real code (even if they’re in the &lt;em&gt;tests&lt;/em&gt; folder and you marked &lt;em&gt;tests&lt;/em&gt; folder as such in clover-setup).  Not a bid deal – just use &lt;strong&gt;&lt;span style=&quot;font-size:85%;&quot;&gt;///CLOVER:OFF&lt;/span&gt;&lt;/strong&gt; directive and your code coverage will be fixed.&lt;/p&gt;&lt;ul&gt;&lt;li&gt;Code Reviews - &lt;a href=&quot;http://www.atlassian.com/software/crucible&quot;&gt;Crucible&lt;/a&gt;&lt;/li&gt;&lt;/ul&gt;&lt;p&gt;We are starting to use a fantastic code review tool and one day I&#39;ll document the best practices; meanwhile, check out &lt;a href=&quot;http://www.atlassian.com/software/crucible/screencast.jsp&quot;&gt;http://www.atlassian.com/software/crucible/screencast.jsp&lt;/a&gt;&lt;/p&gt;&lt;/target&gt;&lt;div class=&quot;blogger-post-footer&quot;&gt;&lt;script expr:src=&#39;&quot;http://feeds.feedburner.com/~s/AJavaPerspectiveForDotNetDevelopers?i=&quot; + data:post.url&#39; type=&quot;text/javascript&quot; charset=&quot;utf-8&quot;&gt;&lt;/script&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://ajavaperspective.blogspot.com/feeds/3358396997856847767/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment/fullpage/post/260065058526360285/3358396997856847767' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/260065058526360285/posts/default/3358396997856847767'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/260065058526360285/posts/default/3358396997856847767'/><link rel='alternate' type='text/html' href='http://ajavaperspective.blogspot.com/2008/04/tools.html' title='Tools'/><author><name>Yuri</name><uri>http://www.blogger.com/profile/10050240503141428160</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='16' height='16' src='https://img1.blogblog.com/img/b16-rounded.gif'/></author><media:thumbnail xmlns:media="http://search.yahoo.com/mrss/" url="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEgIVQ_b7zmdhp5qE1TUW1TZsUUobLCDmaFBYchbSfgYFiySVjBREy89OmD1tkST3locBfueBpFgpNse2smo9EneqKIb3vGPfZHv5Of4XM-0_ykvDLDFg47KlGI-G38sd3QkLtZ-unj7A4IM/s72-c/clover.jpg" height="72" width="72"/><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-260065058526360285.post-567276669949330699</id><published>2008-03-31T14:00:00.000-07:00</published><updated>2008-04-01T20:57:02.268-07:00</updated><title type='text'>Java … after .NET?</title><content type='html'>I was working on .NET projects for about 7 years when my job was outsourced. Just like that. I transferred to a new team where things were done in Java. They coded using Eclipse and also used MySQL and &lt;a href=&quot;http://www.hibernate.org/&quot; target=&quot;_blank&quot;&gt;Hibernate&lt;/a&gt; and &lt;a href=&quot;http://www.springframework.org/&quot; target=&quot;_blank&quot;&gt;Spring&lt;/a&gt;. I can say I was shocked by how much stuff can be done using free tools; I was surprised at the quality of the products and variety of available packages, libraries, plugins. It took a while to adjust. I jotted down few notes that hopefully should help you in Java world.I love .NET, but at the end of the day it’s the product that matters and if Java and open source can help you develop it faster, cheaper, and you can host it on &lt;a href=&quot;http://aws.amazon.com/ec2&quot; target=&quot;_blank&quot;&gt;EC2&lt;/a&gt; in the matter of hours and just a few bucks a day – so be it!&lt;br /&gt;&lt;div&gt;&lt;/div&gt;&lt;div class=&quot;blogger-post-footer&quot;&gt;&lt;script expr:src=&#39;&quot;http://feeds.feedburner.com/~s/AJavaPerspectiveForDotNetDevelopers?i=&quot; + data:post.url&#39; type=&quot;text/javascript&quot; charset=&quot;utf-8&quot;&gt;&lt;/script&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://ajavaperspective.blogspot.com/feeds/567276669949330699/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment/fullpage/post/260065058526360285/567276669949330699' title='1 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/260065058526360285/posts/default/567276669949330699'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/260065058526360285/posts/default/567276669949330699'/><link rel='alternate' type='text/html' href='http://ajavaperspective.blogspot.com/2008/03/java-after-net.html' title='Java … after .NET?'/><author><name>Yuri</name><uri>http://www.blogger.com/profile/10050240503141428160</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='16' height='16' src='https://img1.blogblog.com/img/b16-rounded.gif'/></author><thr:total>1</thr:total></entry></feed>