Tuesday, May 29, 2007

Myth - Defining loop variables inside the loop is bad for performance

I like to define loop variables inside the loop on the line where the assignment is happening. For example if I was iterating through a String collection I would do it like below

private void test() {
for (Iterator iter = list.iterator(); iter.hasNext();) {
String str = (String) iter.next();
System.out.println(str);
}
}


The other day a colleague of mine was doing a peer review and he said this was bad and I should have defined the String variable str outside the loop. What he suggested was something like below.

private void test() {
String str;
for (Iterator iter = list.iterator(); iter.hasNext();) {
str = (String) iter.next();
System.out.println(str);
}
}

When I questioned the logic behind it he said something like:

If you define str inside the loop it will get initialized in each iteration and that’s bad for performance.

Or something like that… and so the argument started. I mean str is a frigging variable not an object that would get initialized or anything. The compiler wouldn’t go allocating memory to str in each iteration and my belief was that it didn’t matter whether you declare str inside the loop or outside the loop. The compiler wouldn’t care and would generate the same byte code in either case.



I did some googling around and came across this blog which discusses the same thing though his preference was to declare the variable outside the loop. The first example was very similar to what I had in mind but it was with primitives. The second example with StringBuffer is a totally different story from mine.

So I had to do my own test, I wrote another class with the str declared outside the loop and compiled them both. Then using javap utility that comes with the JDK printed the byte code for both implementations (ie. javap –c –private <classname>)


Byte Code genarated when the variable is declared inside the loop:

private void test();
Code:
0: aload_0
1: getfield #15;
4: invokevirtual #22;
7: astore_1
8: goto 28
11: aload_1
12: invokeinterface #26,
17: checkcast #32;
20: astore_2
21: getstatic #34;
24: aload_2
25: invokevirtual #40;
28: aload_1
29: invokeinterface #46,
34: ifne 11
37: return
}


Byte Code genarated when the variable is declared outside the loop:

private void test();
Code:
0: aload_0
1: getfield #15;
4: invokevirtual #22;
7: astore_2
8: goto 28
11: aload_2
12: invokeinterface #26,
17: checkcast #32;
20: astore_1
21: getstatic #34;
24: aload_1
25: invokevirtual #40;
28: aload_2
29: invokeinterface #46,
34: ifne 11
37: return
}

Basically it’s the same byte code except the variable numbers are switched (ie. line 11 aload_1 become aload_2). So it really doesn't make a difference and where you declare the variable is a just a matter of taste.


Don' forget to click the +1 button below if this post was helpful.

Thursday, May 24, 2007

How to notify JavaBlogs.com about blog updates with XML-RPC

Javablogs supports notification of blog updates with a remote API, which enables new blog post to appear on Javablogs immediately (javablogs API). I use blogger and as far as I can tell it doesn't support pinging javablogs.com. So i set out to write my own XML-RPC client to make my posts appear quickly (Yes I'm the impatient type).

Did a search for XML-RPC clients on the web and I found this open source Java library from Redstone. Downloaded the jar file and followed the instructions on Redstone page and the page describing the Weblogs API. I have to say when I started on this I didn't think it would be this easy but after about 10 minutes I had it working :).

Just add the following lines inside a main method and execute:





String weblogName = "Living Tao";
String weblogUrl = "http://livingtao.blogspot.com/";

//create a client pointing to the rpc service on javablogs
XmlRpcClient client = new XmlRpcClient("http://javablogs.com/xmlrpc", true);

//invoke the method to queue the blog for an update
Object token = client.invoke("weblogUpdates.ping", new Object[] { weblogName, weblogUrl} );
System.out.println(token);



The code will out put the following result on successful execution:

{flError=0, message=Success. 1 blogs have been queued for update}



Don' forget to click the +1 button below if this post was helpful.

Wednesday, May 23, 2007

final - Least used keyword in Java development?

I've been writing Java code for a long time and I never thought about making a class or a method final until recently. Actually the only place the final keyword was used was when declaring constants. I still don't think you will gain much on performance by using final but the biggest selling point is the correctness it brings to the code.

So far our development team has not looked at the correct usage of final keyword during peer reviews, but going forward it will be added to the peer review guideline document. Hope I'll see more finals in our code after that [if anyone follows the guideline that is :) ]

Anyway here is a link to a good explanation on final keyword: The Final Word on the final Keyword

Don' forget to click the +1 button below if this post was helpful.

Monday, May 21, 2007

Testing application generated emails with Apache James server

Most of our applications send out emails to customers, different groups of people within the organization etc... Most of these emails were in HTML and had all sorts of fancy formatting in them. It was a pain developing and testing these emails and they took too much developer time.

We needed an easy way to test them locally in developer machines without using an external SMTP server.

The plan was to run a James server in every developer machine which forwarded all the emails it receives to an email account on the same server.

Following were the steps followed to achieve this:


1. Download and Run James Server

Downloaded the latest zip bundle from apache site (ver 2.3.1). Extracted to a folder and executed run.bat in the bin directory to start the server for the first time. This will extract the james.sar file in apps directory to the apps/james directory. Now you will be able to modify the configuration file (config.xml) in apps/james/SAR-INF.


2. Create a local email account.

Open a command window and type telnet localhost 4555. When asked for the user name and password type root for both. Now you will be in the admin console and create a email account by typing adduser test test. This will create an email account named test with the password set to test.


3. Delete remote delivery mailet.

Open up the config.xml and locate the RemoteDelivery mailet section <mailet match="All" class="RemoteDelivery">...</mailet> and remove the tag including all its content.


4. Add a forward mailet to forward all mails

Insert the following mailet in the place where the RemoteDelivery mailet was.
<mailet match="All" class="Forward">
<forwardto>test@localhost</forwardto>
</mailet>


5. Save config.xml and Restart the James Server


Now all emails generated by the application (which is configured to use the SMTP server on localhost) will be handled by the James server running in the local machine and it will forward all emails to the test@localhost email account regardless of recipient addresses in email messages.

You can configure Outlook Express or any other client to read the mails sent to test@localhost.

Don' forget to click the +1 button below if this post was helpful.

Friday, May 18, 2007

When to call isDebugEnabled() before writing debug messages

When using a logging framework like log4j most developers never check whether debug is enabled before writing a debug message or always makes the check. The theory behind it is to prevent unnecessary string concatenations if debug messages are disabled, which is the case most of the times on production environments.

logger.debug("Saved order successfully. Order ID : " + order.getId() +
" items in order " + order.getItems().size())
;

In the above case there is a new string object created by concatenating all the parameters before making the call to debug method. This is done regardless of debug is enabled or not which will be a unnecessary performance overhead if debug is disabled.

if( logger.isDebugEnabled()){
logger.debug("Before saving the order");
}

In the above code section the if condition is not necessary as there is no String concatenations involved and ends up adding two redundant lines of code.

Therefore the rule would be to do a isDebugEnabled check only if there is any String concatenation involved in the call to debug. This seems to be obvious but developers somehow keep getting this wrong.

Don' forget to click the +1 button below if this post was helpful.

Reduce logger initialization code in your Java applications

You might have logger initialization code in most of the classes in an application (e.g. Action, Service and DAO classes). This is actually unnecessary if these types of classes extend from your own base classes.

An application using log4j logging framework will initialize the logger in a class as

private static final Logger logger = Logger.getInstance(TestAction.getClass());

This is done in each and every class which needs to use a logger. Now if we use a base class for lets say all Struts Actions called BaseAction, it can contain the logger initialization code as below.

package com.test.web;

import org.apache.log4j.Logger;
import org.apache.struts.action.Action;

public abstract class BaseAction extends Action{
//initializes the logger object
protected final Logger logger = Logger.getInstance(this.getClass());
}


Now all sub classes that extends from BaseAction (implementation action classes) will have the logger object created on initialization with the proper class name. Even though in theory this creates a new logger object per instance of TestAction class, it wont be an issue since Struts will maintain only a single instance of TestAction to serve all requests mapped to it.

This could be applied to all Service, DAO classes as well if you are using a framework like Spring to manage them, where only one instance per implementation class will be created.

P.S. This post was modified as per comments by fabien...

Don' forget to click the +1 button below if this post was helpful.

Thursday, May 17, 2007

Global Exception Handling for Struts and Tiles Applications

Update: The solution explained in this post has been tested only on Weblogic 8.1 and 9.2. On Tomcat 5.x this will not work and please post a comment with the results if you happen to test this on any other server or find a work around for the Tomcat issue.

I was looking at implementing a global error page for unhandled exceptions in a Struts / Tiles application. Normally this was achieved by adding a section in struts-config.xml with a custom exception handler to log the exceptions and the url to the global error page.

This would forward to the error page if an unhandled exception was thrown from the Struts action but will not do so if the exception occurred in one of the tiles JSPs. An exception in a tile would result in a partly rendered page but this was fine in previous app as there were hardly any logic in JSP files and it was very rare to have an exception at the JSP level in production.

In the new app though this wasn’t the case as there were lot of logic that went in to JSPs in the form of custom tags etc… that could potentially throw all sorts of exceptions at run time and I wanted to handle all these exceptions in a unified manner.


New Solution

I abandoned the global-exceptions approach in struts-config altogether and added a <error-page> section to the web.xml file which instructed the app server to forward the request to the specified URL on all unhandled exceptions.

<error-page>
<exception-type>java.lang.Throwable</exception-type>
<location>/error </location>
</error-page>

Then added a servlet and a servlet mapping to the /error URL

<servlet>
<servlet-name>exceptionHandler</servlet-name>
<servlet-class>com.test.ExceptionHandlerServlet</servlet-class>
<init-param>
<param-name>errorPageURL</param-name>
<param-value>error.html</param-value>
</init-param>
<load-on-startup>3</load-on-startup>
</servlet>


<servlet-mapping>
<servlet-name>exceptionHandler</servlet-name>
<url-pattern>/error</url-pattern>
</servlet-mapping>

The ExceptionHandlerServlet would log the exception and redirect the browser to the URL defined in the servlet configuration (error.html).

ExceptionHandlerServlet Code:





protected void doPost(HttpServletRequest request, HttpServletResponse response)
throws ServletException, IOException {
try {
logger.debug("Handling exception in ErrorHandlerServlet");

Throwable exception = null;

// Check if struts has placed an exception object in request
Object obj = request.getAttribute(Globals.EXCEPTION_KEY);

if (obj == null) {
// Since no struts exception is found,
// check if a JSP exception is available in request.
obj = request.getAttribute("javax.servlet.jsp.jspException");
}

if ((obj != null) && (obj instanceof Throwable)) {
exception = (Throwable) obj;
}


if (logger.isDebugEnabled()) {
logger.debug("Request URI: " + request.getAttribute("javax.servlet.forward.request_uri"));
}

// request uri containing the original URL value will be available
// only on servers implementing servlet 2.4 spec
String requestURI = (String) request.getAttribute("javax.servlet.forward.request_uri");

logger.error("Exception while handling request: " + requestURI, exception);
response.sendRedirect(errorPageURL);
} catch (Exception e) {
// Throwing exceptions from this method can result in request
// going in to an infinite loop forwarding to the error servlet recursively.
e.printStackTrace();
}
}


Now on all unhandled exceptions the servlet will log the exception. Yet on some occasions where the exception was thrown in one of the tile JSPs the browser would display a partially rendered page and would not redirect to the error page.


This was due to tiles flushing content to the response buffer before the whole page was rendered. In such a situation the browser will happily display what it received and the redirect to the error page will have no effect.

In order to prevent or minimize the flushing of response buffer:

1. Set flush attribute to false in all tiles insert tags
2. Increase the response buffer size to minimize auto flushing

This was achieved by modifying the tiles layout jsp page.

<!-- sets the response buffer size to 64kb -->
<%@ page buffer="64kb"%>
<%@ taglib uri="/WEB-INF/struts-tiles.tld" prefix="tiles"%>

<tiles:insert attribute="header" flush="false" />
<tiles:insert attribute="leftnav" flush="false" />
<tiles:insert attribute="body" flush="false" />
<tiles:insert attribute="footer" flush="false" />


In the above code segment all html formatting was removed for clarity. The response buffer was set to 64 kilobytes and this value should be decide based on the average page size of the application and the performance impact of the increased memory usage.


Don' forget to click the +1 button below if this post was helpful.