river-dev mailing list archives

Site index · List index
Message view « Date » · « Thread »
Top « Date » · « Thread »
From Peter Firmstone <j...@zeus.net.au>
Subject Service API, Interfaces, Evolution, Lookup & ClassLoader's again
Date Sat, 29 May 2010 11:48:28 GMT
You know something I realised about Evolving code, Interfaces and Lookup?

It's a little difficult to explain, Jini veterans are probably well 
aware of it.

I'll give you a hint,

   1. It makes Versioning unnecessary.
   2. It enables easy backward compatibility.
   3. Implementation is isolated from API.
   4. API is easily extended.

Well it's Jini Lookup semantics.

Clients lookup Service instances, based on their Service Interface 
(API), so they only discover compatible Services.  Ok that probably 
sounds obvious and "So What", well the Service implementation is free to 
change, it can extend the Service Interface, old clients continue to 
lookup with the earlier interface while new clients will find extended 
service interfaces with added functionality.

The Service knows nothing of the Client, the Client know's nothing of 
the Service's implementation.  But even better, if we use Interfaces for 
return values and Parameters, neither the client or the service need to 
know anything about each others implementation objects.

The service is free to change and the client is free to change.  All 
interfaces can be extended, so the service API has flexibility in all 
directions, new methods can be added by extending existing interfaces, 
return values and parameters can change and implement new interfaces too.

This is an extremely flexible communication contract point.  So not only 
can the protocols change but so can the API be extended, while remaining 
fully backward compatible.

Back to the humble isolated JVM for a moment, I guess the problem with 
using classes without interfaces is, a class has an API and an 
implementation.

Suddenly the flexibility is gone.

Take String as a case in point, new methods were added in Java 5, this 
means later code that utilise the new methods, can't run on Java 1.4.

So we're forced to use versioning to work around these issues of 
incompatibility.

But Service Interfaces don't need to be versioned, they have many 
degrees of freedom in which to maneuver to accommodate change, 
developers use versioning when their implementation would be compromised 
by maintaining complete backward compatibility.

It gets better though, all implementations in Services, Proxy's and 
Clients can be isolated in their own ClassLoader's and so not step on 
each other's classes if we structure the ClassLoader tree properly.

Versioning is a concern of implementations.

We must prevent any implementation from being visible to another - 
seeing the other's classes while running in the same JVM.

So there is something that concerns me about Application code, running 
in a ClassLoader that is parent to a proxy or a Service.

Applications could depend on classes, while not part of Service API, may 
be present in other implementation code, eg, the Proxy, but being free 
to vary as implementation classes are, if implementations vary (has 
another version!) and an incompatible class is loaded into a Parent 
ClassLoader, the wrong class will be used, causing runtime errors.

So without fleshing out all the details and leaving as much out as 
possible to allow others to advise of their needs and concerns, I'd like 
to suggest that the following ClassLoader relationship based on the Rio 
ClassLoader structure provided by Dennis, invisibility between 
implementations is fundamental.

              
 _______________________________________________________________
|                                                               |
|           AppClassLoader                                      |
|                |                                              |
|          Common Classloader (As Per Dennis' comments)         |
|       _________|_______________________________________       |
|      |             |                 |                 |      |
| Service Imp    Smart Proxy      Parameter Impl   Application  |
| ClassLoader's  ClassLoader's    ClassLoader's    ClassLoader  |
|_______________________________________________________________|


AppClassLoader - Contains the main() class of the container. Main-Class in manifest points
to com.sun.jini.start.ServiceStarter
Classpath:  boot.jar, start.jar, jsk-platform.jar, service-api.jar (mulitple Service API jar's
allowed, can be untrusted)
Codebase: none
 
CommonClassLoader - Contains the common Rio and Jini technology classes (and other declared
common platform JARs) to be made available to its children.
Classpath: Common JARs such as rio.jar
Codebase: Context dependent. The codebase returned is the codebase of the specific child CL
that is the current context of the request. (Not Sure about the last sentence please explain?)
 
Child ClassLoader's - Contains the service specific implementation classes and client application
classes.
Classpath: serviceImpl.jar
Codebase: "serviceX-dl.jar rio-dl.jar jsk-lib-dl.jar"


Evolution of Service API is important and to avoid unmarshalling errors, 
due to classes missing from the client's Static Service API, when a 
proxy uses a Service API extending one present in the client.  For 
example, when a proxy contains additional Service API, the client lacks, 
it should be loaded into the Proxy's ClassLoader.  I think this is why 
Service API might exist in downloadable archives, for safety reasons.

So perhaps as a protection against unmarshalling error's the proxy's 
codebase should contain the Service API too, however the Service API 
present in the client is given preference due to ClassLoader hierarchy.

Thoughts?

Cheers,

Peter.

Mime
View raw message