Main

Java Archives

December 27, 2002

Architecture war of the decade ...

With the preliminary injunction ordering Microsoft to include Sun's version of Java with Windows (actually, any product that includes .NET), the battle lines are clearly drawn for the architectural war of the decade.

The injunction order provides a nice overview of how Microsoft has done everythin possible, some legal and some not so, to fragment Java, destroy its channel of distribution, and finally, may use the Windows monopoly to tip the market in favor of its .NET as the winner for the general purpose, Internet enabled distributed computing platform market.

As someone who has been working on Java platform for past few years, and has some degree of vested interest in seeing it continue as a dominant platform, I have been watching this war with great interest -- be it performance, functionality, ease of use, sleek marketing, legal battles -- whatever. Besides that, it is fun to watch and understand how one of the most successful corporation of its time defends its turf and prepares to gain new grounds.

With this brief introduction, allow me to analyze, from my perspective, why is this war and its outcome is important to the players (including myself) and what would be the role of this preliminary injunction. I have organized my thoughts around these points:


  • Microsoft has a lot to lose if the market tips in favor of Java. A lot of enterprise applications are getting written for Java, which can run on any platform (mostly different flavor of Unices) and this has somewhat slowed the penetration of Windows in the enterprise market. Ofcourse, the injunction order will perhaps have little impact on this market. On the client side, Java has been less successful. The reason, in my opinion, is its technical inferiority (Swing applications hog memory, are slow and have inferior look & feel) than universality of Java runtime on Windows machines. However, if SWT (of eclipse) finds its way to J2SE through JCP and J2SE runtime is made universally available on Windows, it could cause some problems to Microsoft even on the client side.

  • Sun may not be able to translate the dominance of Java into additional revenues and profits but has a lot to lose in terms of its leadership of Java community. This leadership did accrue a lot of revenue to Sun during the Internet boom days. However, it is not clear how it will earn money for Sun in future. May be Sun hopes that its Java based SunOne will bring money and be reason for sale of its hardware in a world dominated by Java. Or atleast enable Unix platform to continue to be a competition to Windows in the enterprise and Sun can have a slice of it.

  • I personally like the Java approach of separating standards from the implementation, community driven evolution and having building block components with commandline interface for basic functionality and visual tools for more complex repititive functions. Have not looked at .NET seriously, so can't say how it compares with Java. But the hype around VS.NET seems to imply that you better use VS for .NET development.

  • One of the beneficiaries of Java's dominance is likely to be Linux. One of the oft-cited reasons for not adopting Linux has been lack of applications. But Java applications can run anywhere, including Linux. This may erode the profit margins of some of the backers of Java (Sun, IBM, ...). Interestingly, Linux community is hedging its bet by supporting both Java and .NET (through MONO).

  • The must carry provision ordered by the court may only have a minor role to play, impacting the decision of only those developers who develop applets to be delivered to the browser via the Internet. As this group is quite a minority, it may not matter much.

  • Finally, a close competition with .NET is likely to cause more innovation within Java, benefitting developers and consumers.

Irrespective of the outcome, the battles and the war are going to be worth watching. The most likely outcome, in my opinion is that it would be a heterogenous market with .NET and Java being strong in their own constituencies.

June 6, 2003

In search of a CMS/CP

The book is almost complete and will soon be gone to production.

It would be good idea to setup a website complementing the book. In fact, I have already got a fitting domain name and parked it on a friend's box. Have a Linux box up and ready on my HOME network, waiting to go live (Thanks to LinkSys router -- it would take me less than a minute to configure it for open access from the Internet). However, I am stuck at this point.

I am not able to decide what CMS (Content Management System) or CP (Collaborative portal) should I use to setup this site. I would like it to be open source software, preferrably based on Java/J2EE. Here is what I would like to be able to do:

1. Allow download of the sample examples and tools.
2. Maintain a live FAQ.
3. Allow reader registrations.
4. Answer reader questions.
5. Post product evaluation reports.
6. Allow reader comments and ratings.
7. Publish a monthly/quaterly news letter.
8. Aggregate content related to book topics.
9. Post articles/writeups on related topics.
10. Provide search.

This list may change as I work on this site but the basic idea is to have some more dyanmic than my static home page or even somewhat dynamic weblog.

After a brief session with Google, I short-listed following software for evaluation:

I installed CoFax and played around a bit. Not too happy with it.

Read the details about OpenSymphony but looks like it provides low level components and expects signficant plumbing. java.blogs, which uses OS components, is impressive but I do not have the time or energy to learn a bunch of APIs even before I get started.

Am yet to look at others. Are there folks out there who are running such systems and would be able to recommend me something.

July 10, 2003

Exploring Java Code Made Easy ...

Navigating a huge number of source files, especially opensource software written by others, has always been problematic to me. I typically resort to "find . -name *.java -exec grep ... {}\;" on Unix machines and "Search" button on Windows machines to locate specific files that use particular classes or methods. However, these approaches are quite crude and do not go very far.

So when I ran into Java2HTML, my first reaction was cautious. But as looked at some of the HTML generated by it here and here, my excitement grew. This is exactly what I needed. As you can see, Java2HTML converts Java source files rooted at a directory in a familiar javadoc style -- with top-left frame having the package names, bottom-left frame having the classnames and the right frame having the hyper-linked, colorized source files. This makes source files navigation really easy.

Not only this, it is also possible to link external packages and classes within a source file to their javadoc documentation over the Web. For example, all uses of JDK classes could be hyperlinked with the corresponding JavaDoc kept at Sun's site. I found this really cool.

The goodness doesn't stop here: Java2HTML has an Apache Ant task for the conversion. As I was looking for the ability to publish Java code on the Web for my own project and be able to generate it as part of my build process, this came really handy.

As I started using Java2HTML more and more, I started expecting more capabilities. Often, I download only binary distribution and getting the sources (when I can) only adds extra overhead. What if it could decompile a class file (or better, or class files of a jar file) and genrate the easily navigable HTML files! I have used DJ Java Decompiler on some occassions and have found it quite useful. Of course, the source output is not so nice as the one from Java2HTML.

I knew that DJ Java Decompiler uses Jad as the engine to convert class files into java files and adds the capability to work with jar files and provides a graphical user interface.

Wouldn't it be cool to combine Jad and Jav2HTML to generate HTML from source files, class files or jar files! Given that jar can unjar a jar file, Jad can decompile class files and Java2HTML can convert class files into HTML, it certainly seemed possible.

After a couple of hours of experimentation, I was ready with an Ant build.xml file that made it possible. I call it "Java Code to HTML Converter" or just jc2h. Feel free to download and use it. As you will see fronm the file header, I am releasing this file with GPL Version 2.

Unfortunately, you would need to download Java2HTML and Jad from their respective sites. I was thinking of packagin them all together but their licenses do not allow repackaging. Also, Jad is distributed in binary form and you must get the appropriate binary for your platform.

To use jc2h, you should have Apache Ant, Java2HTML and Jad. Have the bin directory of Apache Ant and the directory having the Jad executable in PATH. Also, include c2h.jar (part of Java2HTML download) in the CLASSPATH. Once this setup is done, issue the following command from the same directory that has jc2h build.xml file to generate HTML of source files in src directory:

ant -Dsrcdir=src

For a jar file name code.jar, issue the command:

ant jar2html -Djarfile=code.jar

Play with jc2h and let me know if you find it useful.

September 16, 2003

A book, a website, free sample chapter and open source software

This particular welog entry is culmination of my hardwork of more than a year!

Last week, my (one and only) book, J2EE Security for Servlets, EJBs and Web Services, went on sale at Amazon. This was sooner than my expectation. In fact, when I returned back from India a couple of weeks ago, I had no idea that the book has already been published. My first reaction was that of panic -- how am I going to create the companion web site http://www.j2ee-security.net in a jiffy!

Well, scared at the dreadful thought of turning off paying buyers, I devoted few late night sessions to populate the website with atleast the static content. And I got most of it ready: book highlights, table of contents, preface, sample chapter, viewable sources and the downloadable source distribution.

The website is not just a promotional tool but an integral part of the book. The book relies heavily on the example programs and utility tools but the printed code includes only the most essential portions of the code necessary to understand the concepts and APIs. If you want to play with the code then you would need to get the electronic version and the only way is to download it from the book's website.

I would not attempt covering the book software (which, BTW, is open source and is available and OSL v2.0) in this post. It deserves its own separate posts. Similarly, the free sample chapter also merits its own post.

Watch out this space!

Free Sample Chapter: Web Services Security

Among all the chapters for J2EE Security book, the one on Web Services Security was most difficult to write. More so because I wanted the intended audience for the book, and hence this chapter, to be developers.

Writing about SSL based transport security was straight-forward. In fact, I had done some work in this direction long ago.

Most of the literature I came across talked about yet-to-come security standards. Even these standards were for securing XML and SOAP messages. I am talking specifically of WS Security. Even now, after the book is out in the market, the Oasis TC developing this specification has not completed its work. The Java API standards or even proprietary implementations were even harder to find.

So I ended up doing some heavy lifting and doing my own implementation based on VeriSign TSIK library that provides a WS Security implementation based on the initial WS-Security specification. I basically wrote JAX-RPC compliant handlers which made use of TSIK library to apply WS-Security based protection on SOAP messages and tested these on Apache Axis.

During this implementation, I did run into an interesting problem. The TSIK library worked on a W3C DOM document or Node, but what you got in a JAX-RPC handler was a SAAJ SOAPMessage object. Converting this into a W3C Document esentially mean't serialing the memory object and reading it back into a W3C DOM document. Once the WS Security related processing is over, this needs to be converted back into SOAPMessage. This is prohibitively expensive. (Note: SAAJ 1.2 has fixed this problem by requiring SOAPMessage to extend from org.w3c.dom.Node).

The good news is that you can read the complete chapter online as it happens to be the free sample chapter. The code is also available with an Open Source License.

October 10, 2003

Great Review of "J2EE Security ..."

JavaRanch Book Review team has this nice review of J2EE Security for Servlets, EJBs and Web Services.

Here are excerpts:

"Security is like spinach - it's good for you but not too many people like it. Most security books bore me to tears with page after page of description accompanying three lines of code. This book is different."

"The explanations throughout the book are clear and easy to follow with plenty of code samples to demonstrate how to use the various APIs associated with security in Java programs. The best part of the book is the many code samples provided and the detailed descriptions accompanying these code samples."

October 28, 2003

SunJCE is broken in J2SDK1.4.2

The handling of JCEKS keystores is broken in J2SDK1.4.2.

The first signs of the problem appeared in form of this error report. Instinctively, I suspected my own program, not the JDK. However, I couldn't reproduce the error with JDK1.4.1_05 but could easily do that with JDK1.4.2_02. And although the report mentioned only one instance of the problem, many of the JSTK utilities and programs that relied on a JCEKS keystore, failed. In fact, simple operations on JCEKS keystore using keytool, such as -genkey followed by -export, failed. In fact, the problem is acknowledged in a Java forum discussion as well.

As a workaround to this problem, I am making a maintenance release of JSTK, JSTK-1.0.1. This release allows a user to specify the keystore type as either JCEKS or JKS. Though the default remains JCEKS.

January 26, 2004

Startup time improvement in J2SE 1.5

Today I received an e-mail notification by JDC (Java Developer Connection) regarding closure of a bug I had voted for [free reg. required].

As per the resolution description, different Java programs (JVMs) running on the same machine will be able to share a large number of system classes using a technology termed as Class Data Sharing (CDS), thus signficantly reducing memory requirements and startup time.

This is indeed a great news! The only caveat is that this may not be available on Windows platform in the beginning (my favorite development platform).

February 1, 2004

Accessing Windows Certificates from Java

MS-Windows stores certificates and private keys in a registry-based certificate store which are accessed by applications such as IE, Outlook Express, MS-Outlook and so on. MS CryptoAPI lets any WIndows application to access these certificates.

Java programs, on the other hand, must maintain their own certificate store in different file -- one for trusted CAs and one for personal certificates.

Wouldn't it be nice if Java programs running on Windows could access the default certificate store and save the poor user from the trouble of maintaining multiple stores and allow him/her to work with much nicer Windows CertMgr Wizards than the crappy keytool.

Well, this is now possible, at least in theory, through Assembla JCE Provider, a JCE provider that exposes a number of MS CryptoAPI capabilities. The provider itself is a thin wrapper over the MS CryptoAPI.

I played with it a little bit. Comes with a good Windows based installer. However, I had to manually copy the jar file in J2SDK_HOME\jre\lib\ext and modify the java.security file. Nice to see that the provider jar class is signed by JCE Code Signing CA.

Once installed, using this from my very own JSTK was straight-forward.

But before you rush to download, install and use Assembla JCE provider let me warn you that


  • Although Assembla is free to use, it is not open source.

  • The MS CryptoAPI doesn't lend itself very well to JCE API and it shows. Read the Assembla Javadocs for more details.

  • It is not possible to extract the private key from a key entry.

  • JSSE cannot use (at least in the version 1.21 that I played with ) the KeyStore created by this provider.

February 22, 2004

Comparing SSL performance: J2SE1.4 vs. J2SE1.5b1

The SSL support in J2SE (through JSSE) has changed a lot from J2SE1.4 to J2SE1.5. So, when I got a chance this weekend, I ran my favourite ssltool (part of JSTK) to collect some performance numbers.

Now, I know the pitfalls of microbenchmarks -- but they do have some utility in some scenarios. And I consider this parituclar scenario simulated by ssltool to be one of those: a client program establishes connection with the server, sends a fixed no. of bytes and the server echoes back the same data. The client does send and receive in a loop for a fixed no. of times and reports the duration of the loop.

For the numbers given below, I executed both client and server programs on the same Athlon 900MHz machine running W2K. The buffer size was fixed at 8KB and the loopcount was 2048. Also, I measured the elapsed time for two different cipher suites: SSL_RSA_WITH_RC4_128_MD5 and SSL_RSA_WITH_3DES_EDE_CBC_SHA, as shown in the following table:





J2SDK1.4.1_02J2SDK1.5.0b1
SSL_RSA_WITH_RC4_128_MD58.6 secs.6.5 secs.
SSL_RSA_WITH_3DES_EDE_CBC_SHA45 secs.64 secs.

Now, this is really interesting!? The new JDK is better for SSL_RSA_WITH_RC4_128_MD5 but worse for SSL_RSA_WITH_3DES_EDE_CBC_SHA. How is this explained? Well, only the Sun engineers, who have the source code, can answer. I can only guess that the performance difference is because of the change in how JSSE performs cryptographic operations: JSSE now uses the default JCE provider, whereas earlier it had its own code for doing these operations.

Whatever be the reason , I only hope that Sun addresses this before their final release, for the cipher suite SSL_RSA_WITH_3DES_EDE_CBC_SHA is stronger and more widely used

March 21, 2004

Why is developing JCE Providers so hard?

Don't take me wrong -- I don't mean to say that the JCE API is complex or the logic of providers is difficult to get right. The JCE framework itself is quite simple, in fact same as the JCA. The algorithms implemented by a JCE provider could be complicated, but that is not the point. One could develop a JCE provider by just writing a wrapper over some existing library (like OpenSSL or MS CAPI on Windows).

What makes writing JCE providers is the requirement that it must be signed by a certificate issued by, directly or indirectly, a certification authority with distinguished name of CN=JCE Code Signing CA, OU=Java Software Code Signing, O=Sun Microsystems Inc, L=Palo Alto, ST=CA, C=US. This is checked by the JCE engine that come with J2SE -- it simply refuses to load JCE provider jars that are not signed by an appropriate code signing authority.

As per the JCE documentation, if you are writing a JCE provider then you should make a request to Sun for a code signing certificate. This in itself is not bad. But the caveat is that you must be a vendor to actually get the code signing certificate. This will actually get verified -- making the whole process quite beurocratic and beyond the reach of individual developers. For example, I am interested in trying out my little wrapper over MS-CAPI, but I am not a vendor, and so cannot test my little program!

This was just a little annoyance with J2SE1.4.x, for I had figured out that I could simply remove the jce.jar from jre\lib, and place the opensource Cryptix implementation of JCE engine. This worked fine for all my experimentation. However, with J2SE1.5, the Cryptix JCE jar doesn't work. As I don't see much activity with Cryptix (actually, most of the time the website is down!), not much hope that I will have an updated opensource JCE engine.

And this is happening exactly when it has become somewhat interesting to plug-in my JCE provider to speed-up SSL processing in J2SE1.5 by simple configuration change (JSSE of J2SE1.4 didn't support pluggable crypto providers; JSSE of J2SE1.5 does.). How does Sun expect programmers like me to try out this new exciting feature!

I don't know the rationale of requiring signed JCE providers, but even if we assume that this is needed for some arcane reasons, it is possible to promote experimentation by allowing download of a JCE engine that doesn't require signed JCE provider for testing purposes. This will continue to allow Sun to have the same control over people or organization who distribute their providers, for the users of the JCE provider would still need signed jars.

April 11, 2004

Client side single sign-on

Ovidiu Predescu, an old friend and now a Google employee, has written an excellent writeup on using ssh-agent on Windows XP for single authentication for all ssh-based logins. I got to follow his instructions and setup my Windows machines to use this!

A recent San Jose Mercury News article talked about some of the technologies/products for client-side solution to authentication at multiple websites: Windows password manager, roboform, iKey and so on.

Ofcourse, ssh-agent and these web sign-on products address different target markets, but attempt to solve the same problem.

Recently, I came across a variant of this problem -- we have a Java based client program that interacts with a number of different and independent Web Services. These Web Services could assign different usernames and passwords to the client, requiring the client to use something like a password manager.

April 12, 2004

J2EE Management in J2EE1.4 RI

J2EE Management (a.k.a JSR-77) defines an alternate mechanim (the conventional one being through an MBean Server) to access J2EE Management Objects: through a Management EJB called MEJB. However, the information to access MEJB in a client Java program is quite scarce.

With some digging around and trial-and-error, I was able to get a Java client within an Application Client Container to access EJB. However, what I am really interested is to access MEJB from a standalone Java client through RMI-IIOP. This is currently not working.

I am posting the client code for those who may be interested:

package client;
import java.util.*;
import javax.naming.Context;
import javax.naming.InitialContext;
import javax.rmi.PortableRemoteObject;
import javax.management.*;
import javax.management.j2ee.*;
public class MEJBClient {
public static void main(String[] args) {
String url = null;
String jndiname = null;
boolean acc = true;
try {
if (args.length == 1 ) {
url = args[0];
acc = false;
System.out.println("url = " + url);
}
Context initial;
Object objref;
if (acc) {
initial = new InitialContext();
objref = initial.lookup("ejb/mgmt/MEJB");
System.out.println("objref obtained within ACC...");
} else {
Properties env = new Properties();
env.put("java.naming.factory.initial",
"com.sun.jndi.cosnaming.CNCtxFactory");
env.put("java.naming.provider.url", url);
env.put("java.naming.security.authentication", "simple");
env.put("java.naming.security.principal", "admin");
env.put("java.naming.security.credentials", "weblogic");
initial = new InitialContext(env);
objref = initial.lookup("ejb/mgmt/MEJB");
System.out.println("objref obtained through RMI-IIOP...");
}
System.out.println("objref = " + objref);
ManagementHome mhome = (ManagementHome)PortableRemoteObject.narrow(objref,
ManagementHome.class);
Management mejb = mhome.create();
ObjectName sp = new ObjectName("*:*");
Set mos = mejb.queryNames(null, null);
System.out.println("Found " + mos.size() + " Managed Objects.");
System.exit(0);
} catch (Exception ex) {
//ResourceBundle rb = ResourceBundle.getBundle("LocalStrings", Locale.getDefault());
//System.err.println(rb.getString("caught_exception")+"!");
ex.printStackTrace();
}
}
}

June 5, 2004

ArrayList versus LinkedList: Aren't they same?

Minor editing and update at 3:30pm, June 05:
The trade-offs in using java.util.ArrayList and java.util.LinkedList should be straight-forward, shouldn't it? At least this is what I used to think till today. But then most of my thinking around these datastructures were formed during college days, when C was the hottest language and Java and its Collection classes just didn't exist.

Not surprisingly, it is natural for me to think of arrays as fixed size containers, where elements can be accessed at random location through O(1) operation (ie; in constant time) and insertion/deletion in the middle are O(N) operations (ie; could take time proportional to the size of the array) and hence, are better avoided. In contrast, a linked list can grow in size, access of its head or tail and insertion/deletion in the middle are all O(1) operations (assuming that you have pointer to an adjacent element).

It is possible get around the fixed size limitation of arrays by writing a wrapper which will allocate a new array, copy the elements of the old array into the new one and then discard the old one (BTW, this is what ArrayList does). Still, the basic arrays remain a datastructure for collections of fixed size. In contrast, a linked list consists of nodes with 'pointers' to the next and previous node in the list. So, adding or removing a node is simply a matter of reassigning the pointers. Of course, this implies linear time for traversing upto an indexed node, starting from beginning or end. This simple model is very handy in deciding when to use an array and when to use a linked list.

In Java, the ArrayList and LinkedList classes provide a uniform interface to both these datastructures and hence, destroy this simple conceptual model, so necessary to make judicious implementation decisions, in impressionable young minds of many Java programmers. Let me further elaborate this with my recent own experience.

Today, while going over a graph traversal code, I was somewhat alarmed by the generous use of ArrayLists. This code was written by someone who perhaps had learnt programming with Java. As hinted earlier, both ArrayList and LinkedList implement List interface and support similar operations. An ArrayList can grow dynamically and allows insertion/deletion of elements. A LinkedList also allows access of elements through an index, exactly the same way as an ArrayList. This is all fine. However, the problem is that the apparent similarity in the API hides the widely different memory and time costs of these datastructures for different kinds of operations, luring the unwary to use them in dangerous ways:

  1. An empty ArrayList takes two to three times more memory than an empty LinkedList (because ArrayList would typically preallocate memory). This becomes important if you plan to keep an adjacency list of nodes for each node in the graph and you know beforehand that the nodes will have at most one or two adjacent nodes and the total number of nodes in the graph can be quite large.
  2. The following straight-forward loop to iterate over all elements of a list


      for (int i = 0; i < list.size(); i++)
        doSomething(list.get(i));


    works great for an ArrayList but will cause serious performance problems for a LinkedList. Can you guess why? The right way to iterate over a LinkedList is:


      ListIterator li = list.listIterator(0);
      while (li.hasNext())
        doSomething(li.next());


  3. Although both ArrayList and LinkedList allow insertion/deletion in the middle through similar operations (ie; by invoking add(int index) or remove(index)), these operations do not offer you the advantage of O(1) insertion/deletion for a LinkedList. For that, you must work through a ListIterator.

While researching on this topic, I did find a couple of good articles on the Web:


  • JDC Tech Tip article on Using ArrayList/LinkedList. Good coverage of the topic. Worth reading if you want to know more about performance tradeoffs.

  • joustlog entry titled LinkedList vs. ArrayList performance tests and subsequent clarification. This entry is more focussed in scope, pointing out the fact that addition as the end is faster for ArrayList than for LinkedList. The only thing I would like to add is that addition at the end of a LinkedList is always O(1) whereas addition at the end of an ArrayList is amortized O(1), meaning if you do M at-the-end additions then the total cost will be proportional to M. This is due to the fact that the underlying array may have to be grown (a new one to be allocated, old one to be copied and discarded) when the capacity is reached. However, I can understand that a normal at-the-end addition (ie; not involving resizing of the underlying array) will be faster for ArrayList (compared to LinkedList).

I am not advocating either ArrayList or LinkedList, though it can be justifiably argued that the use of ArrayList is better suited in many more programming scenarios, and I have no contention with that. The point I am making is that the sameness of the API makes it easy for programmers to assume that these can be used interchangeably. Nothing can be farther from truth. They are distinct datastructures, each optimized for certain kinds of operations and domain of applicability. And a good programmer should be aware of the distinction. The API exposed by the above mentioned Java classes blur this distinction. In my opinion, this is one of those areas where implementation hiding behind a common, easy-to-use interface (think of List interface that both ArrayList and LinkedList implement) may not be in the best interest of the primary user of these classes.

June 27, 2004

Who (or What) is slowing down my Java App Startup?

Few weeks ago I got an email message from my colleague Craig Bryant asking about potential fix for an annoying pause during startup of his Java program that did some crypto during initialization. He also attached his code, pin-pointing the problem to the first invocation of the call Cipher.getInstance("DES/CBC/PKCS5Padding"), which took more than 5 seconds to execute on an HPUX box with JDK1.4.1. Agreed that 5 seconds delay at startup is not a big deal, but is still unacceptable in most development and production systems.

I compiled and executed the program on my old and rusty W2K desktop (a Pentium 350MHz box), and confirmed the delay. I also found that the delay was cut by almost half by just switching from J2SDK1.4.1 to J2SDK1.4.2. Not surprising given the impressive optimizations reported in J2SE 1.4.2. Running the program on a more modern machine (say, a 2.0GHz box) further reduced the delay to a more acceptable sub-second range. I attributed this to slow-but-necessary security intialization overhead and forgot about it.

Craig later reported that he profiled the code and found that most of the delay was due to signature verification. This made sense. Invocation of Cipher.getInstance("DES/CBC/PKCS5Padding")would require execution of classes in a JCE provider and the JCE engine requires the provider to be signed by a certificate issued JavaSoft. It appears silly, at least for a standalone Java program running on a trusted machine, to verify the JCE provider jar every time the program starts.

Lateron, after reading the recommendation to run the server JVM for better performance (which made sense anyway, as the original program was to run as a server program), I tried the same program with java -server, only to find that startup delay was worse than without -server option, with a factor of 3.5! (a 0.9 sec. delay became a 3.2 sec. delay). Again, an explanation is not hard to come by: -server option causes the JVM to compile all the code used in verifying the signed jar to native code, even if the verification takes place only once. And because of this, the performance gain of running native machine instructions do not offset the time spent in doing the byte code to native code translation.

Although the previous story is in the context of crypto operations, the general observation that signed jar files introduce human perceptible startup delays, applies to many more situations. This delay is proportional to the size of the signed jar and not the size of classes that get used from this jar file. For example, the following HelloWorld.java program:


//File: HelloWorld.java
import lib.HelloWorldLib;
public class HelloWorld {
public static void main(String[] args) throws Exception {
HelloWorldLib.helloWorld();
}
}
------------------------------------------------------
// File: lib\HelloWorldLib.java
package lib;
public class HelloWorldLib {
public static void helloWorld() throws Exception {
System.out.println("Hello, World!");
}
}

takes around 280 milli seconds to execute when class lib.HelloWorldLib is packaged within a jar file. However, the execution time jumps to 700 milli seconds when this jar file is signed. Adding this class to a large existing jar file such as rt.jar (which is a 25MB monster!) and signing the resulting jar makes the execution time to be more than 7 seconds. Note: All measurements reported in this paragraph were made on a AMD Athlon 900MHz box running W2K, J2SE 1.4.2 and server JVM. The measurements of first few executions were discarded to allow for OS and filesystem cache warmup.

This is something to keep mind if you plan to deliver signed jar files!

August 10, 2004

J2SDK 1.5.0 (sorry... 5.0) does not like XML processing

Seduced by JConsole of J2SDK 1.5.0 and the curiosity to see the GC, memeory utilization and threads in action, tried to run a couple of my application (one an Eclipse RCP and another one a WebLogic Server application) with 1.5.0 beta2 JVM. Both failed with NullPointerException in XML processing code ...

October 4, 2004

Beware of Apache Ant Tar task

I was almost fooled by the happy

[tar] Nothing to do: filename.tar is up to date.

message, but then better sense prevailed and I reran my build script after deleting the filename.tar file. The tar file created on the second run was bigger (and hence, different) than the former one.

But why did I suspect the Ant message at the first instance? Because, the previous run had failed with the following message:

BUILD FAILED
build.xml:51: Problem creating TAR: No space left on device

However, after freeing up disk space, I had expected Ant to remove the half-built tar file and recreate it.

October 5, 2004

Disappointed in J2SE5.0

Putting behind an earlier mishap with J2SE5.0 beta, I ventured to try out the final release of J2SE5.0 with the same set of programs: an Apache Axis based server program running within BEA Weblogic Server and an Eclipse RCP based client. I should point out that in the last attempt both programs had failed with NullPointerException within XML processing.

Thankfully, XML processing problems seems to have been resolved, at least for some cases. But still a long way to go. This time, the server program failed with the following message:


*******
[java] The WebLogic Server did not start up properly.
[java] java.io.InvalidClassException: javax.management.MBeanAttributeInfo;local class incompatible: stream classdesc serialVersionUID = 7043855487133450673, local class serialVersionUID = 8644704819898565848
[java] at java.io.ObjectStreamClass.initNonProxy(ObjectStreamClass.java
:519)
[java] at java.io.ObjectInputStream.readNonProxyDesc(ObjectInputStream.java:1546)
... other stuff omitted ...

I didn't spend much time trying to figure out what is going, but from first glance it appears that J2SE5.0 JVM doesn't like the classes created by earlier versions!!

The client program also failed, again in XML processing:


Error invoking '{http://schemas.hp.com/wsmf/2003/03/Foundation}ManagedObjectDiscoveryPT GetSpecificRelationships' operation.
java.lang.NullPointerException
at java.util.Hashtable.put(Hashtable.java:396)
at com.sun.org.apache.xerces.internal.jaxp.SAXParserImpl.setProperty(SAXParserImpl.java:385)
... other stuff omitted ...

I should mention that both these programs run flawlessly under J2SE1.4.x.

Such poor backward compatibility is indeed cause of concern and disappointment.

November 1, 2004

Evolving JMX: on the cover of WebSevices Journal

I was pleasantly surpised to find the Evolving JMX article as the Web Services Journal cover story. (Note: the cover link will probably work only for a month but I don't know how to get the permanent URL).

The full article can be accessed either as a collection of HTML pages or within the PDF version of the WSJ November Issue. I personally prefer the PDF version as it has less clutter and better flow.

This article, co-authored with Chris Peltz, was a direct result of our work on WSMF and OpenView Smart Plug-In for Web Logic Integration, though the article itself doesn't mention these.

Unlike some of my earlier work, this article is not a "HOW-TO" guide on making a known technology work -- it is more about combining existing technologies (JMX and WSDM) in interesting ways and evolving ideas on how to make them work together in even better way (than currently possible). This is the kind of work I always wanted to do.

I am excited to say that thi WSJ article is not a one-off thing. I and Chris have further evolved our ideas and are currently working on another article titled "Five Best Practices for JMX Development: Making Java Applications Good Citizens of SOA". This article builds upon the main concepts of the WSJ article and provide guidelines on how to design JMX MBeans for better manageability in general, and through WSDM in particular. Stay tuned.

November 2, 2004

A little script to disassemble jar files

My favorite Java decompiler Jad was having trouble decompiling J2SE5.0 class files, forcing me to use the bundled disassembler javap. The Java assembly code it generates is no match for source code generated by Jad, but is not too bad if your goal is just to understand some observed behavior and the supplied documentation is not sufficient (which is not exactly a rarity!). What I did find irritating about javap is its inability to handle directory tree and propensity to dump the disassembled code on standard output (so if I tried to disassemble multiple class files in one command and redirected the output to a file, all I get is one single big fat file with idsassemble code for all the classes).

These limitations motivated me to write jarp.pl, a little perl script, to disassemble all classes of a jar file and produce a directory tree of appropriately named files with disassembled code (to get this script, download jarp.txt and rename it to jarp.pl). It worked quite well on a number of jar files (including rt.jar of J2SE5.0) on my Windows box.

It takes the filename of the jar file as an argument, unjars it in a subdirectory named classes (provided this subdirectory doesn't exist), and then invokes javap for each of the .class files, saving the output in the corresponding .jasm file under jasm subdirectory. Goes without saying that you should have Perl installed in your machine (you can Perl for Windows from ActiveState).

A sample session with jarp.pl is shown below:

C:\myhome>set java_home=c:\j2se\j2sdk5.0 C:\myhome>dir Volume in drive C has no label. Volume Serial Number is 14A6-C5D4
Directory of C:\myhome
11/02/2004 07:10p <DIR> . 11/02/2004 07:10p <DIR> .. 11/02/2004 06:35a 1,762 jarp.pl 1 File(s) 1,762 bytes 2 Dir(s) 53,062,135,808 bytes free
C:\myhome>perl jarp.pl %java_home%\jre\lib\jce.jar Unjarring C:\j2se\j2sdk5.0\jre\lib\jce.jar in directory classes ... ... done. Making list of classes ... ... done. jasm/javax jasm/javax/crypto jasm/javax/crypto/interfaces jasm/javax/crypto/spec jasm/META-INF [0] Disassembled: jasm/javax/crypto/BadPaddingException.jasm [1] Disassembled: jasm/javax/crypto/Cipher.jasm ... Output Skipped ... [60] Disassembled: jasm/javax/crypto/spec/RC5ParameterSpec.jasm [61] Disassembled: jasm/javax/crypto/spec/SecretKeySpec.jasm
C:\myhome>dir Volume in drive C has no label. Volume Serial Number is 14A6-C5D4
Directory of C:\myhome
11/02/2004 07:12p <DIR> . 11/02/2004 07:12p <DIR> .. 11/02/2004 07:12p <DIR> classes 11/02/2004 06:35a 1,762 jarp.pl 11/02/2004 07:12p <DIR> jasm 1 File(s) 1,762 bytes 4 Dir(s) 53,057,335,296 bytes free
C:\myhome>

I have found it to be a very useful tool. Hope it helps you as well!

November 11, 2004

Upgrading JMX: JMX1.2 --> JMX2.0

Came across this JSR titled Java Management Extensions (JMX) Specification, version 2.0, promising easier to use JMX API.

As outlined in my Evolving JMX paper, I see a number of areas where JMX needs to be improved:

  1. Better support for management models: Although one could use JMX MBeans as proxy for real managed resources, the JMX specification doesn't mandate this or even provide relevant guidelines. As a result, I see a lot of MBeans which are just support classes made available to Admin. console applications. It would help to have guidelines on what should be made as MBeans so that a generic management application can construct a management model just by discovering the MBeans.
  2. Better support for management specific mechanisms: Specifically, JMX should have built-in support for State and Metrics. The current support for relationships through Relationship MBeans and Relationship service, although very flexible, is very difficult to use and hasn't got much traction.
  3. Supporting non-Java clients: Open MBeans allow use of data types that can be used by non-Java clients but they are difficult to use. Platform MXBeans, introduced in J2SE5.0, are a much better alternative. I would like to see user defined MXBeans to be part of JMX specification.

December 18, 2004

XInclude Processing with J2SE5.0

While working with long XML documents, I always felt it was better to break them into smaller documents and have a master document that could simply include the smaller documents. In fact, I always found it amazing that the base XML specification didn't include such a capability. This changed with XML Inclusion spec. becoming a W3C Proposed Recommendation.

Recently, while looking for a processor that allowed me to create a single XML document, starting with a document that included others, I was pleasantly surprized to find XML Inclusion support in J2SE5.0. You could simply mark a SAXParserFactory or DocumentBuilderFactory to be XIncludeAware and it will do the processing. To test this feature, I wrote this simple Java program that treads a XMl document with XInclude tags from standard input and writes the consolidated XML document to the standard output.


// --------------------------------------------------------
// File: XMLProcessor.java
// Description: An XML Processor to do XInclude Processing
// Author: Pankaj Kumar
// Copyright 2004 Pankaj Kumar. All Rights Reserved.
// License: This software is available under GPL.
// ---------------------------------------------------------
import javax.xml.parsers.SAXParserFactory;
import org.xml.sax.XMLReader;
import org.xml.sax.InputSource;
import javax.xml.transform.TransformerFactory;
import javax.xml.transform.Transformer;
import javax.xml.transform.OutputKeys;
import javax.xml.transform.stream.StreamResult;
import javax.xml.transform.sax.SAXSource;
public class XMLProcessor {
public static void main(String[] args) throws Exception{
InputSource is = new InputSource(System.in);
SAXParserFactory spf = SAXParserFactory.newInstance();
spf.setNamespaceAware(true);
spf.setXIncludeAware(true);
XMLReader xr = spf.newSAXParser().getXMLReader();
SAXSource source = new SAXSource(xr, is);
StreamResult result = new StreamResult(System.out);
Transformer xf = TransformerFactory.newInstance().newTransformer();
xf.setOutputProperty(OutputKeys.INDENT, "yes");
xf.setOutputProperty(OutputKeys.METHOD, "xml");
xf.transform(source, result);
}
}

As You can see, I have used an identity transformation from SAXSource to StreamResult for serializing the XML document. This technique has the additional advantage of applying any XSLT transformation specified in the source document, justifying the XMLProcessor name of the program.

January 31, 2005

(Really Crappy) JavaOne 2005 Paper Submission Website

Every once in a while I get so much pissed by a software interface that I have to find an outlet for my frustration. This time, it is the JavaOne 2005 paper submission website.

The first nuisance was the welcome greeting with this dialogue box:

stack-overflow.jpg

Next was the following HTML page after a SUCCESSFUL login:

successful-login.jpg

Note that this message has all sorts of information but no indication that the login actually succeeded. The only way I could figure that out was to infer from the fact that Log In text had changed into log Out (not captured in the above image).

The final thing, and the most irksome, was the screen asking for contact details. It kept asking "Complete YOUR contact details below ..." on every Submit,

submit-contact.jpg

giving the impression that the Submit didn't succeed. After adjusting the value in some fields a number of times, I gave up and logged out. Logged in again just to check if the contact information was saved. And sure enough, it was there!

July 23, 2005

Published by Slashdot

My review of Ant - The Definitive Guide got published by Slashdot with minor editorial changes.

As usual, the comments on the Slashdot book review provide interesting insight into what the developer community, not just a specific segment closely associated with the technology covered by the book, thinks about it. After reviewing these comments, I noted following points:


  1. Ant not good for build systems requiring both dependency driven and procedural (involving looping and conditional) actions. Need a build framework invocable from general purpose scripting language. More gripes on lack of conditionals.
  2. Is XML syntax good or bad for Ant? You decide after reading this, this and this.
  3. Ant versus make. Ant is no make, but includes those capabilities. Scons is an alternative for Python fans. BTW, there are people who like Ant over Make.
  4. Ant and Maven.
  5. Need a GUI for Ant. Personally, I am perfectly happy without GUI.


Well, not much discussion on the book review or the book itself, though.

August 5, 2005

JBoss shutdown doesn't play nice with JDK Logger class

I spent better part of today fighting with a JBoss-4.0.2 idiosyncracy with regard to its handling of Logger class during shutdown.
Here is a brief explanation of the problem, the diagnosis and how I fixed it.

The Problem

I have a JBoass XMBean compliant MBean (meaning it extends JBoss class ServiceMBeanSupport) that initialized a Logger object with a special FileHandler, Formatter and other configured values for log file, level etc. This object worked as expected in most cases, but not all. Specifically, all log invocations, directly or indirectly, from the stopService() of the MBean did not produce any output when the JBoss was shutdown with "$JBOSS_HOME/bin/shutdown.sh -S" command. Interestingly, these invocations worked just fine when stopService() was invoked either directly or through the the JBoss's JMX Console.

The Diagnosis

My first diagnosis was that the shutdown command was not calling the stopService() method. But I had to reject this diagnosis after seeing System.out.println() output from this method. Then I got suspicious about the identity of the Logger object. However, a println of the Logger object address confirmed that it was the same object in both startService() and stopService(). The next step was to print various attributes of the logger object -- level, handlers etc. This helped in pin-pointing the problem. The getLevel() method was returning null (it should have been Level.INFO).

So, JBoss is traversing the tree of Loggers and resetting them before calling stopService() method of deployed MBeans!

The Fix

The only fix I could think of was to keep my Logger object away from the Logger hierarchy manitained by JDK logging library and hence the JBoss. But how to do that?

That is when I stumbled upon getAnonymousLogger() method. Replacing the call Logger.getLogger("mylogger") with Logger.getAnonymousLogger() did the trick and allowed my cleanup code to be run with proper log messages.

August 7, 2005

Who should fear AJAX?

A recent slashdot post links to this Wired story and asks the following oft-asked question: Will AJAX Threaten Windows Desktop? BTW, there is nothing new in this, as it has been opined before in a copule of well cited writings: How Microsoft Lost the API War by Joel Spolsky and The Location Field is The New Command Line by John Gruber.

Continue reading "Who should fear AJAX?" »

August 8, 2005

Ant1.7 for Build, SmartFrog for Deployment

Steve Loughran recently posted Meeting new challenges with Ant1.7 [PDF], a presentation he made at ApacheCon Europe 2005. In this he talks about existing features in Ant1.6.x being refined and new features being introduced in Ant1.7. An intresting observation is about (in)suitablity of Ant for deployment and mention of a little known opensource software SmartFrog.

Here is a brief summary for the impatient (but you must go through the presentation to make sense of any of this):

Continue reading "Ant1.7 for Build, SmartFrog for Deployment" »

August 10, 2005

Ant Tip: Checking for environment variable

Recently I had a defect report that the default value of a configurable parameter was nonsensical to the user, something like "${env.TEST_HOME}".

Of course, this is not nonsensical at all to someone familiar with Ant, though bit embarassing as it reveals an implementation detail: An Ant script is responsible for assigning the default value, taking the value from an environment varaible. When this varaible is not set then the default is set to the string "${env.TEST_HOME}".

So, how to fix this?

Continue reading "Ant Tip: Checking for environment variable" »

November 29, 2006

How hard is test for equality in Java -- the answer will surprise you

A post at THE DAILY WTF includes a function with a compound if statement consisting of eight lines of code to set a flag when the Boolean argument is not equal to a Boolean member, suggesting that the code is correct but overly complex and verbose.

/** Set the value of the isRecordLocked attribute. @param newValue is the new isRecordLocked value. */ public void setIsRecordLocked(Boolean newValue) { // Update state if required. if (isRecordLocked != null) { if (newValue == null || !isRecordLocked.equals(newValue)) { context.setDirty(true); } } else if (newValue != null) { context.setDirty(true); } // Change the value. isRecordLocked = newValue; }

The post also includes a suggestion that the compound if statement can be replaced entirely by a much more understandable one-liner, but doesn't really include the one-liner (perhaps obvious to the submitter).

I struggled for few minutes to figure out the obvious one liner, but couldn't come up with anything signficantly better. The problem is that a simple (A != B) doesn't work for Java Objects (and Boolean is an Object), for either A or B could be null and invoking equals method on null would result in a NullPointerException.

I clicked to see the comments, hoping to find the elusive one-liner in the copious comments (137, when I checked). No luck there. Though some people pointed out that there was nothing wrong with the code, most attempts to better the code resulted in buggy code.

Update (4:40PM, Nov. 30): Got a comment via email(My comments link is disabled due to heavy comment spam and I haven't gotten around to upgrade my blogging software to include an effective filter)

Hi,

I posted this comment to your blog about the thedailywtf code - your
blog software allowed me to preview, and post, then said something
along the lines of "this blog is not accepting comments"..

Cheers.

Ricky.

Because context.setDirty should only be invoked conditionally, and the
guess is that it's a void method, the ternary operator is of no use.
The best I can come up with is:


if (isRecordLocked==newValue || (isRecordLocked != null &&
isRecordLocked.equals(newValue))
context.setDirty(true);
isRecordLocked=newValue;

It might be possible to sandwich the last line into the if statement
somewhere, but I can't see how to do that while guaranteeing its
execution, and preserving the if statement's results.

If invoking context.setDirty(false) when the condition failed was
acceptable (unlikely), then this would work, still 2 lines though:


context.setDirty(isRecordLocked==newValue || (isRecordLocked != null
&& isRecordLocked.equals(newValue));
isRecordLocked=newValue;

Actually, this replacement is problematic (read, buggy!): it attempts to call context.setDirty(true) when both the member (isRecordLocked) and the argument (newValue)are equal, whereas the original code did it the other way round. Notice the emphasis on attempts -- the attempt fails when isRecordLocked is null and newValue is not ( both isRecordLocked==newValue and isRecordLocked != null &&
isRecordLocked.equals(newValue)
will evaluate to false).

Besides, I don't think the replacement is any better in terms of overall readability!

In any case, it just proves my original point -- test of equality, or rather inequality, of two objects is pretty hard in Java.

Update (9:50PM, Dec. 1): Got the following comment, again via email, from the previous commenter Ricky:

You're right, my code was naive. I should probably have written a test that passed with the 'WTF' code, and written my implementation against that. I most likely would have done if it wasn't just for a blog. ;)

"In any case, it just proves my original point -- test of equality, or
rather inequality, of two objects is pretty hard in Java."

Actually, no. Testing equality of objects when all you have are two
references that *may* point at objects is the problem. If you
systematically disallow null (that doesn't necessarily mean testing
for it everywhere), then you're really comparing objects, not just
references, and then you've got this into a 3 liner.


if (!a.equals(b))
{
setDirty(true);
a=b;
}


Yes, the problem does become much simpler if you can ensure non-null values for both the member field and the argument for all invocations of the method. This is easy to do for a private method or when it is used by only code that you or your team writes. But not if the class goes out as part of a library to be used by other developers.

Btw, I did come across a somewhat cleaner solution at behrangsa's page.

January 30, 2007

"Effective Java" or "Heads First Java"

Which one will you buy if you had to make a choice? Which one is selling more copies? This comparison graph using Charteous widget to plot Amazon Sales Rank over time has the answer: As you can see from their respective pages, with Time Average Sales Rank of 1232, Head First Java is significantly ahead of Effective Java, which has Time Average Sales Rank of 6878. Both the ranks are valid at the time of post only and may vary a little bit over time. Note that the sales volume or no. of copies sold by Amazon has an exponential inverse relationship with Sales Rank. This article does a good job of explaining this relationship. Btw, if you didn't notice, the Charteous widget is "live" -- the chart update itself to include the latest rank if you come back tomorrow or day after or any other time in future.

About Java

This page contains an archive of all entries posted to Pankaj Kumar's Weblog in the Java category. They are listed from oldest to newest.

India is the previous category.

Linux is the next category.

Many more can be found on the main index page or by looking through the archives.

Powered by
Movable Type 3.33