Letters to the Editor

1 2 Page 2
Page 2 of 2

The problem is readily apparent. If you try to call A.getInstance(), the constructor A() cannot return without calling B.getInstance(). Likewise, the constructor B() cannot return without calling A.getInstance(). The result is an infinite recursive, which will eventually overflow your stack and crash the program. Of course, the situation can become even more confusing if multiple threads are involved, along with instruction reordering and/or improper synchronization. I had three singletons, so A used B, B used C. I caused the problem when I added a simple feature so that C used A. Surprise!

Of course, the fix is simple: singletons should not hold instance variables that are references to other singletons. The fixed version is as follows:

Class A

{
   private static A a;
   private A()
      { // whatever...  }
   public static getInstance()
   {
      if ( a == null )
      {
         a = new A();
      }
      return a;
   }
   public doWork()
   {
      B b = B.getInstance();
      // b is used here
   }
}

Class B

{
   private static B b;
   private B()
      { // whatever...  }
   public static getInstance()
   {
      if ( b == null )
      {
         b = new B();
      }
      return b;
   }
   public workHard()
   {
      A a = A.getInstance();
      // a is used here
   }
}

The instance variables were only present in the first place so I could have a convenient reference available for use in the methods doWork(), workHard(), etc. It doesn't cost much in either code or execution time to convert the instance variables to method variables, which breaks the infinite recursion cycle in the singleton constructors.

So that is one more item to add to the list of things one shouldn't do.

Alan Thompson

Alan, Thanks for that great example. Yes, I can see the problem. Perhaps that relates to the principle of not replicating state in separate places. The Singleton class or other singleton factory is the single point of access to the singleton; you should always rely on it to produce the singleton reference. Who knows, the factory may be giving you different objects every time you call it, even if, from your perspective, it is the same object (as can happen with entity Enterprise JavaBeans). The trouble is that every time you want to call the method foobar(), you can end up with wordy code like SingletonFactory().getInstance().getSingletonInstance().foobar() (when the SingletonFactory is itself a singleton), but I think it's worth it. Joshua Fox

XML Tutorial

'XML document processing in Java using XPath and XSLT'

André Tost

What is the purpose of locations sets?

André,

Currently I am working on XPath. I have gone through some issues on XPointer. The primary difference between XPointer and XPath is that XPointer refers to location sets, not node sets. A location is either a node, a point, or a range. The tests and predicates from XPath are also extended to handle points and ranges.

I don't understand the purpose of location sets. As I understand it, XPath will solve most of the problems. Please enlighten me. N.V. Sairam

N.V., Those are good questions. Clearly, there are differences between XPath and XPointer, as you mentioned. XPointer is built on top of XPath, but allows you to select areas of an XML document that a pure XPath could not address. That is where the ranges come in. A range, for example, can be part of a text element, like a substring. XPath cannot address such a substring; it can only point to an entire node. Now, given all that, the XPointer standard is not finalized yet, and I am not sure how widely implemented it is. If you can solve all your problems with XPath, I see nothing wrong with using it. In fact, you could argue about the value of being able to work with ranges and points. You should usually be able to define the structure of the target XML document so that XPath will always suffice. Finally, since XPointer is built on top of XPath, you're set for the future should XPointer become necessary for you. Hope this helps. André Tost

Java Servlets

'Take control of the servlet environment'

Part 1: Invisibly extend the functionality of the servlet API

Part 2: Alternatives to servlet session management

Part 3: Beware of the cookie monster

Thomas Davis and Craig Walker

Thomas or Craig,

I was wondering why setting a cookie on the top-level domain -- using Cookie.setDomain() -- is not a good solution. Why shouldn't the cookie be set for the whole of the rudiment.net domain, thereby ensuring that all its subdomains see the cookie?

Sudhakar

Sudhakar, You are correct to think that the

Cookie.setDomain()

record would be a good solution for the cookie domain problem we encountered. The problem is that a cookie's domain attribute is optional, so the functionality required for the

setDomain()

and

getDomain()

methods is not necessarily implemented by the Web server, browser, or servlet engine. We came across that problem during our development (the

setDomain()

and

getDomain()

methods simply didn't do anything!), so we came up with the idea of prepending the domain to the name of the cookie as a workaround. For your reference, we are using:

  • Allaire JRun 2.3.3
  • Microsoft IIS 4
  • MS Internet Explorer 5 / Netscape 4

If you come across a combination of servers and clients that support cookie domains, please let us know. Craig Walker

Beginner Java

'Calculating Java dates'

Robert Nielsen

No daylight savings in Java

Robert,

Your article describing date manipulations was interesting, but it left out a real humdinger of a bug. If you're not in the US, the standard Date in JDK 1.1 and 1.2 doesn't understand daylight savings time. That can put your times (and dates, around midnight) off by one hour. The only solution I have found is to initialize the DateFormat with a SimpleTimeZone thus:

   // set up date format
   // Timezone with zero offset from GMT
   SimpleTimeZone tz = new SimpleTimeZone(0, "GMT");
   // Offset by one hour on the last sunday in March at 2:00am, clocks
go back one hour
   tz.setStartRule(Calendar.MARCH, -1, Calendar.SUNDAY, 2*60*60*1000);
   // Change clocks back on the last sunday in October at 2:00am, clocks
go forward (i.e. GMT again).
   tz.setEndRule(Calendar.OCTOBER, -1, Calendar.SUNDAY, 2*60*60*1000);
   DateFormat df = DateFormat.getDateTimeInstance(DateFormat.SHORT,
DateFormat.SHORT);
   df.setTimeZone(tz);

I don't know if this is fixed in JDK 1.3 yet.

Nick

Nick, Very interesting. I will have to look closely at the point you raised. I found an error in Sun's code in the version of Java (1.2.1) I was using. It seems that if you add months to dates that are B.C., the year actually goes backward. Sun's Website indicated that the bug had been fixed in a later 1.2 version. I think it is easier to make mistakes in computer code that deals with dates and time than in code that deals with other stuff. Whether that is just my impression or actually the case, I don't know, but your example supports my suspicions. Robert Nielsen

1 2 Page 2
Page 2 of 2