Letters to the Editor

Humphrey Sheil defends EJB performance, and Jeff Friesen talks more trash

Java Design Patterns

"Decorate your Java code"

David Geary

LETTER_HEAD: Decorator pattern compares to composition/delegation

David,

Decorators are a form of a dynamic inheritance system, but with normal object-oriented inheritance, no matter where a method is implemented in a hierarchy, this always refers to the same object. With normal Decorators, however, once a call is passed on, the wrapped object doesn't know about the original object. It's as if the super method call forgot who this was.

There's an almost convenient mechanism to solve this problem: have two versions of each method, one with an extra parameter representing the effective this, which I call the target. The short form of each method just calls the expanded form with the current this as the target. Automatic design patterns via proxies can be made to look for expanded methods and pass in the proper target object.

Tom

AUTHOR_REPLY: Tom,

That's a good point. Instead of comparing Decorators to inheritance, it's more appropriate to compare the more general techniques of composition or delegation, which you describe, to inheritance.

Decorators use object composition by forwarding method calls to an enclosed object. It's called composition because the enclosed object does not have access to its enclosing object -- that is, to the this reference you discuss.

Delegation resembles composition, except in that the enclosing object passes a reference to itself to the enclosed instance. There are a number of ways for the enclosing object to make itself known to the enclosed object; you describe one of them.

For the Decorator pattern, composition is used instead of delegation, because delegation requires the enclosed object to be aware of its enclosing object. One of the Decorator pattern's main attractions is that enclosed objects (and the objects that use the Decorators) are oblivious to Decorators. For example, in one of the examples discussed in my article, table models are unaware of the sorters that decorate them, so any table model can be sorted.

David Geary END_REPLY

"To EJB, or not to EJB"

Humphrey Sheil

LETTER_HEAD: Aren't EJBs slower than servlets and JSPs? Humphrey,

One disadvantage of EJBs (Enterprise JavaBeans) that you didn't mention is that EJBs are much slower than straight servlets or JSPs (JavaServer Pages). Sure, EJBs run great on a 50-processor Solaris box, but what about on a quad Intel? Everyone who I have spoken to that has implemented EJBs says they are extremely slow.

Ryan Ackley AUTHOR_REPLY:

Ryan,

To be blunt, you need to perform your own investigation. You are falling prey to the standard "EJBs are slow" fallacy. EJBs are not slower than alternative approaches, given the added benefits they bring, which I list in the article.

You say that EJBs are "much slower than straight servlets or JSPs." You aren't comparing like to like here. JSPs are designed for presentation logic; a creative designer should be able to work with JSPs as if they were straight HTML. Ideally, a JSP should have no Java code; it should be hidden inside taglibs.

Servlets, which were the precursors of JSP technology, are more suited for control/navigation tasks (see the Model 2 architecture for more details).

When you boil it all right down, applications with low/middle complexity and requirements can usually be architected successfully using a JSP/servlet paradigm, not with EJBs.

I'm willing to bet that you will be pleasantly surprised by the performance achievable with Orion, JBoss, and others on a quad-Intel box if you invest a small amount of time building a meaningful, correctly designed prototype of your target application -- assuming you need to use EJBs at all.

Humphrey Sheil END_REPLY

LETTER_HEAD: How will JDO affect EJBs? Humphrey,

What about JDO (Java Data Objects)? Will JDO mean additional alternative approaches? Will plain JDO be EJB friendly?

Sometimes you have the same piece of business logic in a single-user application, which uses a local database, and in a workgroup or enterprise application. How do you implement this business logic as reusable code? I call that a personal edition problem. Are there solutions that are better than plain JDBC (Java Database Connectivity) or custom framework?

A typical single-user application is an editor of some document -- a business plan, say. An enterprise application can manage the same document type. If one department needs only a single-user application and another department needs an enterprise application, you might force both departments to use the enterprise application. But if a customer needs just a single-user application, you shouldn't force him to build an enterprise solution.

Nebojsa Vasiljevic

AUTHOR_REPLY: Nebojsa,

From my limited knowledge of JDO, I would say that if JDO becomes part of the J2EE platform, it would affect container developers more than it would application developers. From a JDO FAQ:

How will JDO affect the EJB technology?

JDO is a suitable implementation (1) for persistent helper classes for Session Beans, (2) as delegate classes for Bean Managed Persistence Entity Beans, and (3) for delegate classes for Container Managed Persistence Entity Beans.

Regarding the personal edition problem: Judicious use of design patterns would help; perhaps you could use a Factory, for example, that creates different types of wrappers for workers depending on the environment. The Factory can then delegate to a common business logic implementation for both the personal and enterprise editions.

Humphrey Sheil END_REPLY

Java 101

"Trash talk, Part 1"

Jeff Friesen

LETTER_HEAD: When do you run System.gc()? Jeff,

You cautioned against running System.gc() right after System.runFinalization(). Well, when I ran your example (FinalizeDemo3), I didn't see System.runFinalization() do anything at all. If you comment it out and just run System.gc(), the method works fine. On the other hand, if you comment out System.gc() and run System.runFinalization() by itself, it doesn't do anything -- at least on my Java HotSpot Client VM (build 1.3.1_01, mixed mode). It appears that runFinalization() never calls an object's finalize method! Any ideas?

Bill

AUTHOR_REPLY:

Bill,

While writing "Trash Talk, Part 1," I performed quite a few experiments with FinalizeDemo3. Basically, I experimented with just System.gc() at the end of the main() method; with just System.runFinalization() at the end of main(); and with combinations of those method calls at the end of main(). The only situation in which all finalizers were consistently called was the combination of method calls where System.gc() precedes System.runFinalization(). Incidentally, if you were to call System.runFinalization() in a loop (and not call System.gc() anywhere), you would occasionally notice that all finalize() methods are called. However, if you call System.runFinalization() only once, you typically do not notice all finalize() methods being called. This has to do with the asynchronous nature of the garbage collector.

To understand how System.runFinalization() works, you need to understand the Reference Objects API (in package java.lang.ref) and threads. Because Java 101 has not yet explored those topics, I chose not to provide a detailed look at System.runFinalization() and finalization's inner workings. (I plan to explore those topics in a future article -- when I explore threads.) For now, here are a few points about System.runFinalization() and the finalization process, in case you wish to do some exploring:

  1. System.runFinalization() calls Runtime.getRuntime().runFinalization().
  2. Runtime.getRuntime().runFinalization() calls runFinalization0() -- a private method in class Runtime.
  3. runFinalization0() is a native method that results in a call to the runFinalization() method in the java.lang.ref.Finalizer class.
  4. It appears that the garbage collector creates Finalizer objects for objects with overridden finalize() methods and queues those objects prior to finalization.
  5. Finalizer contains a runFinalizer() method that (indirectly, through the native invokeFinalizeMethod() method) actually finalizes the objects stored in a queue. That method is called either from a background thread created when Finalizer loads (known as a primary finalizer) or from a thread created when Finalizer's runFinalization() method is called (known as a secondary finalizer, which prevents deadlock among threads) from Runtime's runFinalization0() method. (Thread scheduling determines when these threads run.)

I realize this response does not completely answer your question. However, a detailed explanation is beyond this letter's scope and would constitute an article unto itself. For that reason, I plan to explore finalization (from a threading perspective) in a future article.

Jeff Friesen

P.S. The information I've provided is based on the Java 2 Platform, Standard Edition 1.4 Beta 2. END_REPLY

"Take the fast track to text generation"

Leon Messerschmidt

LETTER_HEAD: Can JSP take you down the fast track too?

Leon,

Your solution is clean and elegant, but I am curious as to whether you could accomplish the same thing -- as far as the customized email generation you started off with -- using regular JSPs (JavaServer Pages). That is, is there some way to ask a JSP engine (let's say Tomcat) to compile and run a JSP based on what's in the session, and put the output into a string rather than sending it to a waiting browser?

While I appreciate Velocity's strengths, it seems I should be able to do these tasks without it if I choose to, but I can't find such an API anywhere. Can you offer some direction?

Moshe Sambol

AUTHOR_REPLY: Moshe,

Unfortunately, there is no easy way for JSPs to be used like Velocity. A JSP engine (Tomcat, Resin, etc.) compiles the JavaServer Page into a Java servlet. This servlet has to run in a servlet container.

I haven't done this myself, but you could probably use Tomcat to compile a JavaServer Page into a servlet, and then write some code that mimics a servlet engine. In other words, the code creates a servlet instance and passes request/response objects but, instead of sending output to a browser, it traps the output as text.

That is the best solution I can think of, and I doubt there is a much simpler one. That is one of the reasons why Velocity exists in the first place.

Leon Messerschmidt

END_REPLY Tips 'N Tricks

"Java Tip 96: Use HTTPS in your Java client code"

Matt Towers

LETTER_HEAD: JSSE not part of the standard SDK

Matt,

I saw your article and made the necessary changes to my program, but I keep getting the following error.

My program:

import java.net.*;
import java.io.*;
import java.security.*;
public class URLReaderorg
{
           public static void main(String[] args) throws Exception
           {
System.setProperty("java.protocol.handler.pkgs","com.sun.net.ssl.internal.www.protocol");
           // Need to add the Security Provider to use SSL
           java.security.Security.addProvider( new
com.sun.net.ssl.internal.ssl.Provider());
                     URL yahoo = new URL("https://ibank.amsouth.com");
                     BufferedReader in = new BufferedReader(new
InputStreamReader(yahoo.openStream()));
                     String inputLine;
                     File outputFile = new File("output.html");
                     FileWriter out = new FileWriter(outputFile);
                     while ((inputLine = in.readLine()) != null)
                     {
                               out.write(inputLine);
                               out.write('\n');
                     }
                     in.close();
                     out.close();
    }
}

And this is the error I receive:

Exception in thread "main" java.lang.NoClassDefFoundError: com/sun/net/ssl/internal/ssl/Provider

Ashwin Philar

AUTHOR_REPLY:

Ashwin,

With the advent of JDK 1.4, the JSSEs (Java Secure Socket Extensions) mentioned in my article were merged into the standard JDK. You can find more information here:

In particular, the classes in the JSSE package that were under the com.sun.* hierarchy have moved into a javax.net.* hierarchy. Therefore, if you are using JDK 1.4 and have not explicitly installed the older JSSE package, the provider I used in my sample code will not be found. It appears that the preferred method for acquiring an SSL (Secure Socket Layer) has been updated to use the new javax.net.ssl.SSLContext.getProvider() method.

Alternately, you might want to look at the new javax.net.ssl.HttpsURLConnection class. It derives from the familiar HttpURLConnection and might wrap this functionality for you. This means that you may not need to use any code from my sample.

Matt Towers END_REPLY

"J2SE 1.4 premieres Java's assertion capabilities"

Part 1: Understand the mechanics of Java's new assertion facility

Part 2: Understand the methodology impact of Java's new assertion facility

Wm. Paul Rogers

LETTER_HEAD: RuntimeExceptions should never be put after the method definition

Paul,

A little point from Effective Java by Joshua Block (Addison Wesley Professional, 2001; ISBN: 0201310058): RuntimeExceptions should never be put after the method definition (i.e., no myMethod() throws IllegalArgumentException as in your example). Only checked exceptions should be placed after the method so that the client can separate the checked/unchecked exceptions in the generated Javadoc. In both cases, though, the @throws should be specified.

Janne Nykänen AUTHOR_REPLY:

Janne,

Thanks for your message. Your point is well taken, and I would not include an IllegalArgumentException declaration in real code. For the article sample code, however, I wanted an exact parallel between the method throwing the unchecked IllegalArgumentException and the one throwing the checked SensorException, so I put the throws declaration in both -- since the latter requires it. Yes, I could simply have dropped the throws declaration from the first method, but I specifically wanted symmetry. Perhaps I could have warned against the general use of declaring unchecked exceptions in the method header, but such warning would, I believe, have sidetracked the discussion.

I'm an Effective Java fan and appreciate your note on my violation of Bloch's guidelines.

Wm. Paul Rogers END_REPLY