Letters to the Editor
JavaWorld.com, 08/30/02
"Repair Invalid Cached Services in the Service Locator Pattern"
Paulo Caroli
The Verified Service Locator Pattern doesn't eliminate invalid services
Paulo,
My application could call VerifiedServiceLocator.lookUp(), which could return an invalid (that is, expired) service. Imagine this sequence:
- At 10:00,
checkService() is called—it determines the service is available
- At 10:01, the service becomes unavailable (for whatever reason), and the cached service is now no longer valid
- At 10:03, my application calls
VerifiedServiceLocator.lookUp(), which returns the expired cached service
So we're right back where we started. The Verified Service Locator (VSL) pattern may alleviate the problem of expired cached
entries returned from lookUp() by returning them less frequently, but it does not seem to eliminate the problem completely.
Am I missing something here?
Tony
Tony, You didn't miss anything. Your scenario really shows a situation where the client would get an invalid cached service.
If a cached service becomes invalid, the service also remains invalid for a short time period, and we can't do much else besides
wait for recovery. Usually, the server handles the service recovery. The key point is how often to check for the cached services'
validity. In my last project environment, it took about three minutes to recognize a down server and restart it. That means
our application would have problems for at least three minutes, and we could do nothing about it in our code. We set the verification
frequency in the Verified Service Locator for two minutes. That way, in the worst scenario, the application could reach the
invalid service for, at most, five minutes. You can reduce the verification frequency to almost zero seconds, in which case,
the application could reach the invalid service for three minutes at most, but it would be constantly checking the cached
services' validity. For an application using the Verified Service Locator, the problem would exist only for at most these
five minutes (service recovery time plus verification frequency); for an application not using it, the problem would remain
until the application restarts. The perfect alternative would be a server that kept all services always valid; Verified Service
Locator gives a server-independent alternative to reduce the problem. Paulo Caroli
How do you handle an invalid service on the client side?
Paulo,
I agree that the Verified Service Locator pattern reduces the problem of invalid services. When the server shuts down, eventually
no more invalid services will return to clients, which improves the original pattern.
However, the chance still exists that an invalid service will return. How do you handle that on the client side? You do not
want client code to check for a service's validity, but at the same time, a service may be invalid (however small the chance).
The client must handle that eventuality.
Ronald
Ronald, I agree with you. The solution reduces the problem, but doesn't reach 100 percent robustness. I would consider treating
the exception in the client code when it happens. However, I don't like that the code replicates for each client or that the
client must handle the problem. Some EJB (Enterprise JavaBean) servers have specific solutions to avoid the problem. I heard
WebLogic provides a clustered Home interface that would redirect EJB Homes internally in case one container is down. Paulo Caroli
Paulo,
Unfortunately the VSL pattern can't guarantee 100 percent robustness, but it does improve the previous situation.
In WebLogic, you can replace your home stubs with cluster-aware home stubs that provide load-balancing and failover support.
I've never used this myself, but read it once in the documentation.
Ronald
"Empower RMI with TRMI"
Guy Gur-Ari
Can Transparent Remote Method Invocation help with serializable objects?
Guy,
We recently made something similar to the TRMI (Transparent Remote Method Invocation) API by using proxies from Reflection.
The idea behind our implementation was similar.
We had one problem with serializable objects when calling remote objects' methods. What do you do when it is assumed that
the method should modify its serializable parameter? Does TRMI provide such possibility? Example:
interface SimpleRemote {
void updateProperties(Properties props) {
//...
}
}
The SimpleRemote implementation is assumed to be on the server side. The updateProperties() method should modify the props object when it is called from the client side. This is normal behavior for local classes. Can you perform the same trick
with TRMI?
Maxim
Maxim, I can't think of a transparent way to do what you're asking. Making the serialized object's changes appear in the original
object requires intimate knowledge of a specific class's construction. However, I have an idea for a nontransparent approach.
You can declare a new interface:
interface CopyBackSerializable extends Serializable {
public void copyBack(CopyBackSerializable copyObj);
}
copyBack() will re-initialize the instance with the
copyObj, and classes that need to be copied back to the caller will implement it instead of
Serializable. To send the changed copy from the server to the caller, TRMI can recognize when a parameter is
CopyBackSerializable and when the method call ends. Then TRMI can call
copyBack() on the original object to make the remote changes appear in it. Implementing this solution isn't trivial, and it also seems
quite esoteric. Guy Gur-Ari
Tips 'N Tricks
"Java Tip 127: See JAR Run"
Shawn Silverman
How does JAR work with third-party libraries?
Shawn,
Great article, but it doesn't address an application that uses additional third-party libraries already in a .jar file. I've tried in vain to add the kunststoff.jar into the app's JAR and then modify Class-Path to include kunststoff.jar.
I can't seem to get it to work. java -jar runs the app, but still reports a missing KunstoffLookAndFeel class (which is in the kunststoff.jar, of course, and runs nicely from my IDE, where it is in the classpath).
Tim
Tim, The
Class-Path attribute specifies additional paths or JARs from which to load classes not found in the JAR or the VM's default classpath.
Relative URLs are used, and each URL is referenced relative to the JAR's code base. In plain English, that means that if you
specify a JAR here, the VM will look for it in the same place as the first JAR (and not inside the first JAR). For example,
say you type
java -jar myjar.jar, and a manifest is inside
myjar.jar containing a
Class-Path reference to an
extras.jar:
Suppose all of a sudden, the VM needs access to a class inside
extras.jar. A file called
extras.jar must be in the same directory as
myjar.jar. If it is, the VM can load classes from this new archive. If it is not, the class cannot load. Placing
extras.jar inside
myjar.jar is the same as placing it
beneath myjar.jar, and not at the
same place or
same codebase. For more details about this attribute, see:
http://java.sun.com/j2se/1.3/docs/guide/extensions/spec.html Shawn Silverman
Shawn,
After researching a bit more, the clarification you give makes good sense in explaining the Class-Path header. However, the tidbit still missing is specifically how to access classes inside extra.jar if the JAR is indeed placed inside myjar.jar?
Again, after a bit more research, it would appear that for Java Web Server (JWS), the solution is to have only myapp.jar contain my app-specific classes, then place additional libraries on the Web server, and load them as additional JAR resources.
Perhaps like so:
<resources
<j2se version="1.2+"/
<jar href="myapp.jar"/
<jar href="commonlibs/extras.jar"/
</resources
From various documents at Sun Microsystems, it seems there should be some way to further specify the commonlibs directory absolutely (that is, not relative to myapp codebase) so that the extras.jar could be shared/cached between multiple jws instances.
Tim
Tim, As for your first question of accessing classes inside a JAR inside another JAR: You could use
getResource("extras.jar"), which would return a URL pointing to that file inside
myjar.jar. Then, you could use
URLClassLoader to get the classes from inside this URL. This method, however, is not efficient. You probably want something like a
.war file (Web archive), which can contain multiple items such as classes and libraries. As a starting point, look in the Servlet
2.2 or 2.3 specifications, under "Web Applications." WARs, however, are not runnable, as JARs are. A server that properly
uses WARs will look in the correct places for any additional JARs. As for the relative paths, I suppose it is up to the server
to share loaded libraries and be clever enough to distribute them properly among different instances. A comment in the
Extension Mechanism Architecture I referred you to mentions that absolute paths in the
Class-Path manifest attribute are relative for security reasons, and that absolute paths may be supported in the future. Shawn Silverman