"Manage Users with JMS"

Amit Goel and David Marshall

ERP system updates

Amit,

How do you handle transactionality in the internals of the subscribing apps, like the ERP (enterprise resource planning) subscriber and the CRM (customer relationship management) subscriber? What if the ERP app fails (for some reason) to update its internal database app after consuming the published message? How will you failover?

Sanjaya Ganesh

Sanjaya, Good observation. Look at the code snippet provided for

ERPSubscriber

, in the section where it updates the ERP app with the user data (

// Update ERP system with new user data

)—that is where error handling and reporting takes place. Different development teams have different frameworks built for error handling. That is why the user-management framework's scope did not include error handling. Instead, we left that part of the code empty and provided a template instead. The

onMessage

handler could call a method like the following:

/* Update ERP system with new user data */
updateUserData(String username, String email, ...)
{
  // Interface with ERP app.
  // ...
  // ...
  // Also handle any errors and alert notifications.
  // ...
  // ...
}

Amit Goel

What about single sign-on?

Amit,

This article solves the problem of keeping user registrations in sync. But how would you achieve single sign-on?

Suppose instead of ERP, CRM, and XYZ apps, you have WebApp1, WebApp2, and WebApp3 apps, and wanted to ensure that a user could sign on only once to any of these apps. Of course there's no need to maintain multiple user registrations with each app.

Is there a solution that could achieve single sign-on for these applications?

Jitender Bhatia

Jitender, Our article did not intend to address the issue of single sign-on. The Web interface administrator differs from the administrators of the individual applications (ERP, CRM, etc.). The admin side and the applications side are totally decoupled. Single sign-on requires that the Web infrastructure and application infrastructure agree to some common authentication method. Current industry work with Microsoft Passport and the Liberty Alliance Project tries to address this. We did not attempt to resolve this issue, but we have implemented a solution using LDAP (lightweight directory access protocol), which allows a user to have the same user ID and password across multiple applications. If you have a full Windows environment, I know that using Windows-integrated security can allow the browser to log you on to Windows-based applications. If you are using Apache, you can use an LDAP plug-in and connect this to your ActiveDirectory and have a quasi single sign-on solution. We're using a similar approach on an internal application, but not on the application we mention in the article. If you're not using Windows, you can connect Apache to an LDAP directory using the same plug-in; this gives your users the ability to have the same user ID and password across applications. Amit Goel

Editor's note:

You can read more about the Liberty Alliance Project and single sign-on in these

JavaWorld

articles published on March 21, 2003:

Java Q&A

"Breaking Java Exception-Handling Rules is Easy "

Vladimir Roubtsov

Throw and catch

Vladimir,

There is another way for a checked exception to propagate up the call chain without the compiler noticing. Consider the following, which is modeled after a real-world situation I recently encountered:

import java.io.*;
public class InvisibleThrow
 {
  public static void main(String[] av)
   {
    try
     {
       InvisibleThrow.class.newInstance();
     }
    catch(InstantiationException e) { }
    catch(IllegalAccessException e) { }
   }
  InvisibleThrow()
   throws IOException
   {
     throw new IOException("SURPRISE!");
   }
}

The IOException gets thrown and crashes the program. What's more, you can't just try to catch the IOException directly! The compiler complains if you just add a catch(IOException e) in main, since newInstance() isn't declared to throw such an exception.

So, you have two options: you can cast a wide net and catch(Throwable e), or you can trick the compiler by rewriting main as follows:

   try
    {
     InvisibleThrow.class.newInstance();
     if(false)
        throw new IOException("NEVER THROWN");
    }
    catch(InstantiationException e) { }
    catch(IllegalAccessException e) { }
    catch(IOException e) { System.out.prinln("Gotcha!"); }

This works with my compiler, but I suppose your mileage may vary since the extra throw is technically unreachable code.

I'm puzzled as to why Class.newInstance() doesn't throw an InvocationTargetException, like Constructor.newInstance() does. Perhaps someone can provide a justification for this; it seems like a significant oversight in the API.

Michael Weiss-Malik

Michael, You bring up an excellent point. I am aware of the issues with Class.newInstance() and perhaps should have mentioned them in the article. The issues have been known for some time (http://developer.java.sun.com/developer/bugParade/bugs/4233093.html (login required)), but I'm unclear whether a corrected method should throw an InvocationTargetException (as would seem logical by analogy with the reflection APIs) or whether the exception thrown by the constructor should result in an InstantiationException (the wording "if the instantiation fails for some other reason" in the current Javadocs seems to imply that). The first option is no longer possible due to compatibility issues (which appears to be Sun Microsystems' current resolution for bug 4233093). The second option is more feasible but may still break existing (exception-handling) code at runtime. I did not want to delve too much into this discussion in my article. The salient point was that the compile time exception guarantees are not currently enforced at the byte-code level anyway. I also wanted to introduce links to the Byte Code Engineering Library (BCEL) and Jasmin, topics I might further discuss in future Java Q&A posts. Vladimir Roubtsov

Java Q&A

"The Thread Threat"

Vladimir Roubtsov

Thread safety

Vladimir,

Several questions arise from this article:

  1. Why the emphasis on static fields and accessors? Are the semantics different for instance fields and accessors? Do monitors not work the same on objects of class Class as they do on other objects? Or do thread-specific memory views have their own "independent copies" of static data only?
  2. In a threaded app, when is it safe not to declare a (static?) field volatile and/or its accessors synchronized? Only when you can assert that concurrent access is impossible by design?

Thanks for the warning. It's very useful information.

Phil Hudson

Phil, Let me address both of your questions: 1. I did not imply a difference in semantics between instance and static fields. My article was structured like that simply because of how the reader asked the question. The general rule about having all threads that communicate via shared data-exchanging monitor locks to synchronize memory views applies to instance fields too. Also, when a class uses instance state, an instance of it may or may not be used in a thread-unsafe way. For example,

java.util.HashMap

is not safe for concurrent access by multiple threads. To create an issue, you must have at least two

Thread

s sharing an instance of it. In many cases, instance usage is completely scoped to a single thread, and there are no problems. However, static APIs are almost

always

designed for concurrent use. Even if they were not intended to be used like that, it is easy to abuse them unknowingly (that is,

MaybeSafe.getFoo()

is a public static method on a globally visible public class: anyone can call it at any time). So, it's not easy to detect a thread safety bug with instance state just by examining source code. By comparison, detecting thread-unsafe static APIs is quite easy without a real static analysis tool: I ran Unix

find

coupled with an

egrep

to find all of the suspect JDK methods mentioned in the article. 2. Your second question is an excellent one. I might even turn it into another

Java Q&A

article. I can think of the following cases when protecting a static field with volatile/synchronized is not required: 2a. When the field is set up only once, which happens at class static initialization time. Class initialization occurs before anything can use that class (well, sort of: I am not detailing what happens if a class allows its static state to escape from its static initializer). What's also important is that the end of the class initializer can be considered as another memory barrier implicitly executed by the JVM, and it is a barrier for all currently active

Thread

s and all future

Thread

s. So, the static state created by the static initializer can subsequently be read without any synchronization (as long as the access remains read-only: I usually declare such fields final to ensure that). 2b. This case is somewhat subtle, and I hope I can explain it well. Reconciliation of thread memory views is not needed when the state you are talking about is

identical

between all

Thread

s, and you can afford to recreate it for each

Thread

. As it happens, the JDK offers an example just like that. If you examine the Java 2 Platform, Standard Edition (J2SE) 1.4.1 source for

java.util.Locate

, you will find the following:

   public static Locale getDefault() {
     // Do not synchronize this method - see 4071298.
     // It's OK if more than one default locale happens to be created.
     if (defaultLocale == null) {
         String language, region, country, variant;
         language = (String) AccessController.doPrivileged(
                  new GetPropertyAction("user.language", "en"));
         // For compatibility, check for old user.region property.
         region = (String) AccessController.doPrivileged(
                   new GetPropertyAction("user.region"));
         if (region != null) {
             // Region can be of form country, country_variant, or
_variant.
             int i = region.indexOf('_');
             if (i >= 0) {
                 country = region.substring(0, i);
                 variant = region.substring(i + 1);
             } else {
                 country = region;
                 variant = "";
             }
          } else {
             country = (String) AccessController.doPrivileged(
                       new GetPropertyAction("user.country",
""));
             variant = (String) AccessController.doPrivileged(
                       new GetPropertyAction("user.variant",
""));
          }
          defaultLocale = new Locale(language, country, variant);
       }
       return defaultLocale;
   }

Note the comments left by Sun Microsystems developers.

defaultLocale

is a static field that is initialized lazily, and yet the relevant code block is not synchronized. This was done intentionally, because a

Locale

instance does not take much memory; so, even if a given

Thread

does not have its view of

defaultLocale

field reconciled with that of the first

Thread

to execute

java.util.Locale.getDefault()

, it does not matter. A new

equivalent

instance of it is created for the former

Thread

. Had this been left like that, it would have been a nearly perfect getter implementation (it still suffers from the double-checked locking problem, but that will go away when the Java Memory Model spec is revised). However, this same class also has a setter for the default locale. Even though the setter is synchronized, the getter isn't, and that is a problem. Vladimir Roubtsov

Tips 'N Tricks

"Java Tip 136: Protect Web Application Control Flow"

Romain Guay

Hidden synchronization?

Romain,

Where is synchronization in all this? Without it, isn't there a possibility of isTokenValid() returning true for two requests? Or am I missing some underlying synchronization hidden inside Struts? I quickly looked through the 1.02 source and didn't see anything, but I didn't check thoroughly.

Doug Breaux

Doug, There is in fact some underlying synchronization hidden inside Struts. The method isTokenValid(request) implemented in org.apache.struts.action.Action compares the token carried in the request (from a hidden field) with the token saved in the session when saveToken(request) executes. The token is reset right after it is tested for validity (or as part of the test if you use the isTokenValid(request, reset) version), thus preventing all other requests from being valid, until saveToken(request) executes again. Romain Guay