Friday, October 26, 2007

JavaSpecialists Notes - II

Issue 18: Class names don't identify a class

We can also let these two "A" classes have a common superclass. For example, 
say we have a superclass called Parent.java located in the root directory:

//: Parent.java
public class Parent {
public String toString() {
return "Thanks for caring... but what do you want??? ";
}
}

And our A.java classes are now written as:

//: a1/A.java
public class A extends Parent {
public String toString() {
return super.toString() + "This is the first class";
}
}
//: a2/A.java
public class A extends Parent {
public String toString() {
return super.toString() + "This is the second class";
}
}

We then need to have a common parent ClassLoader which we use to load the
Parent.class file. We have to specify the location to start looking for
Parent.class, and the locations are searched in a hierarchical fasion. Note that the
compile-time Parent class is loaded with a different ClassLoader to the one loaded
with the URLClassLoader called "parent" so they refer to a different class
altogether, which means we cannot type-cast an instance of "A" to a Parent. Also, if
we load the class "Parent" without using the classloader, we will see that it is not
equal to the superclass of "c1".

//: Loader.java
import java.net.*;
public class Loader {
public static void main(String[] args) throws Exception {
ClassLoader parent = new URLClassLoader(
new URL[] {new URL("file:./")}, null);
ClassLoader a1 = new URLClassLoader(
new URL[] {new URL("file:a1/")}, parent);
ClassLoader a2 = new URLClassLoader(
new URL[] {new URL("file:a2/")}, parent);
Class c1 = a1.loadClass("A");
Class c2 = a2.loadClass("A");
System.out.println(c1.newInstance());
System.out.println(c2.newInstance());
System.out.println(
c1.getSuperclass().equals(c2.getSuperclass()));
System.out.println(
Class.forName("Parent").equals(c1.getSuperclass()));
try {
Parent p = (Parent)c1.newInstance();
} catch(ClassCastException ex) {
ex.printStackTrace();
}
System.out.println("We expected to get ClassCastException");
}
}

Thanks for caring... but what do you want??? This is the first class
Thanks for caring... but what do you want??? This is the second class
true
false
java.lang.ClassCastException: A
at Loader.main(Loader.java:18)
We expected to get ClassCastException

Note that the super classes of both "A" classes are equal.

Where is this all this useful? It is very useful when you have an application server
into which you want to deploy business objects written by different people. It is
entirely feasible that you have two developers with different versions of classes
deploying their applications onto the same server. You don't necessarily want to
start a new VM for each deployment, and so with ClassLoaders it is possible to have
lots of classes with the same name running in the same memory space but not
conflicting with one another. They would also share the common JDK classes with one
another, so we would not have to have a java.util.ArrayList class loaded for each of
the ClassLoaders.

Monday, October 22, 2007

JavaSpecialists Notes - I

This is the first part of a series of blogs that I would write in order to keep the crux of all the JavaSpecialists Newsletters at one place for a quick reference. It would include the links and excerpts from the original newsletter.

Issue 1: Deadlocks

In Swing, all GUI components have to be changed from within the Swing thread.
This means that you cannot execute jLabel1.setText("blabla") from within any thread
besides the Swing thread.
If you have change any GUI from another thread you should rather say:
SwingUtilities.invokeLater(new Runnable() {
public void run() {
jLabel1.setText("blabla");
}
}

Issue 2: Anonymous Inner Classes

If you wanted to pass in a Collection instead of an array it would look as follows:

Collection temp_names = new Vector(3);
temp_names.add("Heinz");
temp_names.add("John");
temp_names.add("Anton");
universityRegistration.addNames(temp_names);

The ability to avoid local temporary variables with arrays was always a strong
deciding factor in defining interfaces to my classes because I could get away with
one line of code instead of five, and the less lines of code the better. I would
therefore rather define addNames(String[] names) than addNames(Collection names) even
if it meant I would have to convert backwards and forwards between arrays and
collections. However, with anonymous inner classes we can get the same effect seen
above but with collections:

universityRegistration.addNames(new Vector(3)
{{ add("Heinz"); add("John"); add("Anton"); }});

Issue 8: boolean comparisons

boolean pentiumTMcpu = Utils.isCpuAPentium();
if (pentiumTMcpu == true) {
/* work out incorrect salary using double */
}

This will compile fine in Java, but so will the following, which assigns true to
pentiumTMcpu and will always work out the salary using the Pentium bug (younger
readers would not remember):

boolean pentiumTMcpu = Utils.isCpuAPentium();
if (pentiumTMcpu = true) {
/* this code will always be executed */
}

Instead, it would be a lot safer to write

boolean pentiumTMcpu = Utils.isCpuAPentium();
if (pentiumTMcpu) {
/* work out incorrect salary using double */
}
.........
.........
.........
There is a technique used alot in Microsoft's C++ libraries in which they would have
written the comparison as:

boolean pentiumTMcpu = Utils.isCpuAPentium();
if (true == pentiumTMcpu) {
/* work out incorrect salary using double */
}

More would follow as and when I would read other issues. :)

Java XML binding

A nice article on Java-XML binding using VTD-XML. Especially, I liked the first comment, may be "contrarian" fascination.

Friday, October 19, 2007

String Concatenation

Interesting interview of Heinz Kabutz.

An excerpt speaking about the performance of different ways of String concatenation in Java.

In the early days of Java programming, I sometimes resorted to "clever" coding. For
example, when I was optimizing a system written by a company in Germany, I changed
the String addition to use StringBuffer after we had optimized the architecture and
design of the system and wanted to improve things a bit. Don't read too much into
microbenchmarks. Performance advantages come from good design and an appropriate
architecture.

We start with a basic concatenation based on +=:

public static String concat1(String s1, String s2, String s3,
String s4, String s5, String s6) {
String result = "";
result += s1;
result += s2;
result += s3;
result += s4;
result += s5;
result += s6;
return result;
}



String is immutable, so the compiled code will create many intermediate String
objects, which can strain the garbage collector. A common remedy is to introduce
StringBuffer, causing it to look like this:

public static String concat2(String s1, String s2, String s3,
String s4, String s5, String s6) {
StringBuffer result = new StringBuffer();
result.append(s1);
result.append(s2);
result.append(s3);
result.append(s4);
result.append(s5);
result.append(s6);
return result.toString();
}



But the code is becoming less legible, which is undesirable.

Using JDK 6.0_02 and the server HotSpot compiler, I can execute concat1() a million
times in 2013 milliseconds, but concat2() in 734 milliseconds. At this point, I might
congratulate myself for making the code three times faster. However, the user won't
notice it if 0.1 percent of the program becomes three times faster.

Here's a third approach that I used to make my code run faster, back in the days of
JDK 1.3. Instead of creating an empty StringBuffer, I sized it to the number of
required characters, like so:

public static String concat3(String s1, String s2, String s3,
String s4, String s5, String s6) {
return new StringBuffer(
s1.length() + s2.length() + s3.length() + s4.length() +
s5.length() + s6.length()).append(s1).append(s2).
append(s3).append(s4).append(s5).append(s6).toString();
}



I managed to call that a million times in 604 milliseconds. Even faster than
concat2(). But is this the best way to add the strings? And what is the simplest way?

The approach in concat4() illustrates another way:

public static String concat4(String s1, String s2, String s3,
String s4, String s5, String s6) {
return s1 + s2 + s3 + s4 + s5 + s6;
}



You can hardly make it simpler than that. Interestingly, in Java SE 6, I can call the
code a million times in 578 milliseconds, which is even better than the far more
complicated concat3(). The method is cleaner, easier to understand, and quicker than
our previous best effort.

Sun introduced the StringBuilder class in J2SE 5.0, which is almost the same as
StringBuffer, except it's not thread-safe. Thread safety is usually not necessary
with StringBuffer, since it is seldom shared between threads. When Strings are added
using the + operator, the compiler in J2SE 5.0 and Java SE 6 will automatically use
StringBuilder. If StringBuffer is hard-coded, this optimization will not occur.

When a time-critical method causes a significant bottleneck in your application, it's
possible to speed up string concatenation by doing this:

public static String concat5(String s1, String s2, String s3,
String s4, String s5, String s6) {
return new StringBuilder(
s1.length() + s2.length() + s3.length() + s4.length() +
s5.length() + s6.length()).append(s1).append(s2).
append(s3).append(s4).append(s5).append(s6).toString();
}


However, doing this prevents future versions of the Java platform from automatically
speeding up the system, and again, it makes the code more difficult to read.

Friday, October 12, 2007

target = "_self" problem

I tried writing an HTML today to open a Word document in the same browser window. And as usual found something worth logging.

The file was not opening in the same browser even though target attribute of the anchor tag was set to _self. Then, I tried to use iframe to view the document in a smaller portion/area with in the page but again in vain. The word file was always opening in MS Word.

So, I thought it may be something related to the Windows settings and voila!!! I was right. I needed to change the settings in, Windows Explorer -> Tools -> Folder Options -> File Types for DOC extension. There, for DOC extension I checked the Advanced settings and found that "Browse in same window" option was unchecked. That is what was causing trouble. This setting was making the file to always open in MS Word and so I checked the option and everything was hunky-dory then.

Lesson learnt, don't assume(even because of ignorance) the way a user's machine would be configured while designing a web page.

Wednesday, October 10, 2007

Just Missed!!

Thought I have found a bug in the Oracle JDBC driver. But, to my surprise the bug was actually a feature of Oracle Database.

Question was simple, Why PreparedStatement.setString method works for Number columns, even though the JDBC specification has no reference for such a behavior?

Details here.

File Renaming problem in Java

Ok, so you want to write a code to rename a file in Java. Simple as it may seem, there is a catch in it.

Let us cosider the following code:

File file = new File("toRename.txt");
File newfile = new File("renamed.txt");
file.renameTo(newfile);
System.out.println(file.getName());

What would be the output of the above snippet of code?
Answer seems like "renamed.txt" if the renaming is successful. But, no it is "toRename.txt".

Explanation
The physical file has been renamed to "renamed.txt" but the File object "file" still has the same fileName ("toRename.txt"). So, I tried to find the cause of the behavior, and found this link. One of the users there has mentioned that File is an immutable object. So, I cross-referenced the Java Docs for version 1.4.2 and found the confirmation "Instances of the File class are immutable; that is, once created, the abstract pathname represented by a File object will never change.".

Just one problem, why don't the Sun people make these highlighted in the documentation.

Wednesday, September 26, 2007

Order of Elements in web.xml

Till today I have been thinking that the elements in the deployment descriptor (web.xml) need to be in a specific order.

But on checking the servlet specification I found an interesting point. The DTDs (i.e Servlet version 2.2 and 2.3) define the elements in a sequential fashion. But the Servlet version 2.4 which defines an XSD is more liberal and allows all the root but next elements, i.e, direct child of <web-app> element, to be in any order.

So, now we can have <servlet> anywhere inside <web-app> element.

References: Web.xml XSD, SRV 13.2 in Servlet 2.4 Specification

Tuesday, September 25, 2007

Calling Java servlet from another Servlet/Jsp behind SSO

The issue can be viewed by breaking the problem into two parts.
1) How to make a call to a servlet from another servlet?
2) What if the servlet is SSO protected?

To understand the answer to the first question, we have to be aware that we are trying to call a servlet and not any Java API or a stand-alone class having main method. Ok, there is a way to call another servlet using Request Dispatcher, but what if you don't want to lose the control.

For eg:
1st Scenario: Servlet1 wants the service of Servlet2, and then use the results from Servlet2 for further processing.
2nd Scenario: Servlet1 wants to initialize an asynchronous service exposed as a servlet, Servlet2.

So, to call another servlet we will make use of java.net.* package. The concept is simple, create a new HTTP request in Servlet1 and send this HTTP request to Servlet2. So, to create this HTTP request we can use the java.net.* package.

The other aspect of the problem is how to call the servlet, if it is SSO protected. To bypass the SSO authentication while calling Servlet2 we can extract the authentication information from the Servlet1 request. Since all the authentication information is passed from client-side to the servlets in the form of cookies, we can extract these cookies from the Servlet1 request and include them in the new HTTP request that we are creating for Servlet2.

So, that is all about how and why. Now, check the code below which is calling a servlet from another servlet, without transferring the control and are SSO protected.

String cookieStr = "";
javax.servlet.http.Cookie cookies[] = request.getCookies();
for( int i=0; i<cookies.length; i++) {
javax.servlet.http.Cookie cookie = cookies[i];
String name = cookie.getName();
String value = cookie.getValue();
if(!"JSESSIONID".equals(name)) {
cookieStr += name;
cookieStr += "=";
cookieStr += value;
if(i != cookies.length -1) {
cookieStr += "; ";
}
}
}

StringBuffer mesg = new StringBuffer();
java.net.URL url = new java.net.URL("http://localhost:8080/App1/Servlet2");

java.net.URLConnection urlCon = url.openConnection();
urlCon.setRequestProperty("Cookie", cookieStr);
urlCon.connect();
java.io.InputStream is = urlCon.getInputStream();
int b;
while( (b = is.read() ) != -1) {
out.write(b);
}

Dynamic Table in IE


Problem

Display a dynamic table with in a <div> tag in IE using Javascript.

Non-working Solution

var divElement = document.getElementById("divId");

var tableElement = document.createElement("table");
tableElement.setAttribute("width", "100%");
var tableNode = divElement.appendChild(tableElement);

var trElement = document.createElement("tr");
var tdElement = document.createElement("td");
var trSubGroup = trSubGroup.appendChild(trElement);
var tdFirst = trSubGroup.appendChild(tdElement);
var textNode = document.createTextNode('text');
tdFirst.appendChild(textNode);

This snippet looks all good to display the table, but guess what, it works in Firefox but not in IE.

After a bit of looking around, I found the solution and the cause. IE does not recognize table which does not have <tbody> tag as the child node of <table>. Here, since we are creating dynamic table we have to include the <tbody> tag explicitly. Important to note is that for static tables IE automatically adds the <tbody> tag.

Working Solution

So, the revised code would look like this:

var divElement = document.getElementById("divId");
var tableElement = document.createElement("table");
tableElement.setAttribute("width", "100%");
var tableNode = divElement.appendChild(tableElement);

var tBodyNode = document.createElement("tbody");
var tbody = tableNode.appendChild(tBodyNode);

var trElement = document.createElement("tr");
var tdElement = document.createElement("td");
var trSubGroup = tbody.appendChild(trElement);
var tdFirst = trSubGroup.appendChild(tdElement);
var textNode = document.createTextNode('text');
tdFirst.appendChild(textNode);