You are viewing a plain text version of this content. The canonical link for it is here.
Posted to dev@river.apache.org by Peter Firmstone <ji...@zeus.net.au> on 2010/05/22 12:38:52 UTC

Maven repository Entry was Re: Codebase service?

Since we've got a few Maven people on the list how should we best 
approach utilising the Maven repository?

Patrick, have you got something in mind for a Codebase Entry?

The new StreamServiceRegistrar interface allows you to delay 
unmarshalling of ServiceItem's.  But it also prevents the Jini Public 
API from becoming dependent on the unmarshalling implementation.

Check out MarshalledServiceItem (extends ServiceItem) in SVN.

It's just an Abstract class with a couple of methods that return an 
Object (service) and Entry[], so the implementation can vary.

It means the implementation for Reggie is free to vary, so there no 
problem with a reggie that utilises and depends on Maven, it doesn't 
change the Jini public API.

I could use a little help, I'm not familiar with maven.

Cheers,

Peter.


Re: Maven repository Entry was Re: Codebase service?

Posted by Peter Firmstone <ji...@zeus.net.au>.
Tom Hobbs wrote:
> I agree with Patrick on this point.  It almost certainly requires a new type
> of Entry such as Partick's CoordinateArtifactEntry example.  How many
> developer hours might be lost because of some typo in a string that needs to
> be structured and decoded in some way!  :-)
>
> One thing that I didn't see (can someone point it out, using small words
> please) how using Maven repositories makes is easier/better/faster/whatever
> for someone?  Also, who is that someone, service developers or the support
> teams for those services?
>
> I've been keeping an eye on the recent conversations about this and the
> codebase service and didn't see the bit that said "If we swapped to Maven
> repo, it would be better because..."  I'm not saying it's not there, I just
> can't/didn't see it.
>
> I'm not anti-Maven, I'm a Maven newbie (at best).  I'd just like to be clear
> on what problem this change is trying to solve.
>
> Also, Peter (I think) made the comment about providing an upgrade path for
> those on Jini 2.1.  Is it the intention that using Maven will remain
> entirely optional, or will having a Maven repo become a requirement for
> using River services?
>   

Optional but encouraged.


Re: Maven repository Entry was Re: Codebase service?

Posted by Patrick Wright <pd...@gmail.com>.
> I've been keeping an eye on the recent conversations about this and the
> codebase service and didn't see the bit that said "If we swapped to Maven
> repo, it would be better because..."  I'm not saying it's not there, I just
> can't/didn't see it.
>
> I'm not anti-Maven, I'm a Maven newbie (at best).  I'd just like to be clear
> on what problem this change is trying to solve.
>
> Also, Peter (I think) made the comment about providing an upgrade path for
> those on Jini 2.1.  Is it the intention that using Maven will remain
> entirely optional, or will having a Maven repo become a requirement for
> using River services?

It would be optional, as far as I've been following the conversation.
What we're trying to address is how to avoid depending on a codebase
service. If the JARs you need (e.g. -dl.jar) are already installed
locally,then you can bypass the codebase download. The question is how
we get the service to identify the resource in such a way that the
client can determine if it's available locally. The local Maven
coordinate system and repo is one out-of-the-box solution. For people
who want to use it, it would mean they could push their artifacts out
to one or more (e.g. clustered) Maven repos, and they would be pulled
down to clients as needed; or they could just install the artifacts
themselves to the local Maven client repos (there are command-line
Maven tools to do this). The upside, I think, is that the codebase
download is no longer a weak link in the chain of hooking up with a
service, and certain trust issues are taken out of the equation.

It should be optional, though; I imagine that when Sun finally
polishes off the Jigsaw module work they've been doing an alternative
would be to use the local Jigsaw module repository, for example.


Patrick

Re: Maven repository Entry was Re: Codebase service?

Posted by Tom Hobbs <tv...@googlemail.com>.
I agree with Patrick on this point.  It almost certainly requires a new type
of Entry such as Partick's CoordinateArtifactEntry example.  How many
developer hours might be lost because of some typo in a string that needs to
be structured and decoded in some way!  :-)

One thing that I didn't see (can someone point it out, using small words
please) how using Maven repositories makes is easier/better/faster/whatever
for someone?  Also, who is that someone, service developers or the support
teams for those services?

I've been keeping an eye on the recent conversations about this and the
codebase service and didn't see the bit that said "If we swapped to Maven
repo, it would be better because..."  I'm not saying it's not there, I just
can't/didn't see it.

I'm not anti-Maven, I'm a Maven newbie (at best).  I'd just like to be clear
on what problem this change is trying to solve.

Also, Peter (I think) made the comment about providing an upgrade path for
those on Jini 2.1.  Is it the intention that using Maven will remain
entirely optional, or will having a Maven repo become a requirement for
using River services?

Cheers,

Tom


On Tue, May 25, 2010 at 1:12 PM, Patrick Wright <pd...@gmail.com> wrote:

> >> Yes, we can use an Entry, or as Chris pointed out, if we annotate
> MarshalledInstance's using a new Maven URL schema we can extract that info
> and make it available via MarshalledServiceItem (An abstract class that
> extends ServiceItem).
> >
> > I dont think a new Maven URL schema has actually been proposed? Why
> wouldnt we just use a String attribute in an Entry that is of the form
> groupId:artifactId:version:classifier?
>
> What I don't like about this is that it makes the client a little more
> fragile--we would essentially be sniffing a string for a certain
> format, which, if it matched, would indicate it is a Maven coordinate.
> If this is in a separate type of Entry (e.g. CoordinateArtifactEntry
> or so) then we are reacting to a type of entry, not to a format which
> needs to be documented, etc.
>
>
> Patrick
>

Re: Maven repository Entry was Re: Codebase service?

Posted by Peter Firmstone <ji...@zeus.net.au>.
Hi Dennis,

It sounds like you remain unconvinced or don't have a need to use common 
interfaces for your service proxy's?

So I guess it's a tread lightly approach, make the feature available to 
those that want common Service API (The same interface instance for all 
proxy's implementing that interface, so they can be used in collections 
or batch operations), for maximum sharing of proxy's with differing 
implementations, but let those that don't want to publish their API 
continue doing what they usually do.  A configuration parameter should 
be able to set the desired behaviour.

The approach I've taken is a simple approach to a complex problem, 
alternative approaches leave the complexity in the hands of the 
implementer, my approach will enable them to practically ignore it.

Before you write it off though, to answer your earlier question, I'll 
further explain the ClassLoader structure between multiple nodes.

                    CLIENT NODE
 ________________________________________________
|                                                |
|             System                             |
|           ClassLoader                          |
|                |                               |
|            Extension                           |
|           ClassLoader                          |
|                |                               |
|          Jini Platform &                       |
|           Service API                          |
|           ClassLoader                          |
|                |                               |
|       _________|___                            |
|      |             |                           |
| Application    Smart Proxy                     |
| ClassLoader    ClassLoader's                   |
|________________________________________________|

 
                   SERVICE NODE
 ________________________________________________
|                                                |
|             System                             |
|           ClassLoader                          |
|                |                               |
|            Extension                           |
|           ClassLoader                          |
|                |                               |
|          Jini Platform &                       |
|           Service API                          |
|           ClassLoader                          |
|                |                               |
|       _________|_____________________          |
|      |             |                 |         |
| Service Imp    Smart Proxy      Parameter Impl |
| ClassLoader    ClassLoader's    ClassLoader's  |
|________________________________________________|

 
All Proxy and Service implementations are free to vary at will, proxy 
instances can be shared in collections or iterative operations based on 
common Service API supertype's  All Proxy's and Services are isolated in 
their own Domain, the only way to communicate externally is by using 
interfaces and classes in upper level ClassLoaders, they can utilise as 
many third party libraries jar archives as they need, these will all be 
loaded into a single ClassLoader unique to that Service or Proxy's 
Codebase and Principles.  The Service or Proxy's namespace will be 
totally separate from Application or other Proxy implementation's, 
except in the case where sharing is permitted for identical 
implementations by the implementation developer.

Service API should be carefully considered and designed, it forms the 
basis of network Dependency Injection, you can discover ANY Service 
implementation variant using the same Service API.

The Service API may include other Service API or Java platform classes.

public interface SimpleBookService {

public Book get( Library lib, String name);

}

In the SimpleBookService above, given a Library and String name of a 
Book, a Book instance is returned by the proxy.

The contents of simpleBookService-api.jar:

SimpleBookService.class
Book.class
Library.class

Let's say a client has extended the Library, with a class called 
PrivateLibrary, this class is an implementation class by the client, 
that the Service knows nothing about, the Service only uses the Library 
API, but it needs the PrivateLibrary.class

The client makes an archive containing the PrivateLibrary.class publicly 
available in an archive called privateLibrary-param.jar.  This archive 
depends on simpleBookService-api.jar The jar URL is marshalled with the 
class when the parameters are sent back to the service.  When it gets to 
the service implementation, privateLibrary-param.jar is given it's own 
ClassLoader and ProtectionDomain and isn't given any Permissions.  It is 
used by a SimpleBookService implementation to decide which Book to 
return to the client, after which, it's garbage collected, eventually if 
PrivateLibrary isn't used again its ClassLoader is garbage collected too.

Each SimpleBookService proxy implementation will have their own 
ClassLoader namespace, but Client Application classes can still use any 
Service implementation or as many Service implementations as it can 
handle at the same time, all the while treating them as the same Type.

One SimpleBookService implementation proxy, contains its own 
implementation of Book, and while the client is reading the book, it 
remains available from the proxy ClassLoader via the Service API Book 
interface, when finished reading the book, the proxy, book and 
ClassLoader can be garbage collected.  Tomorrow, the client might read a 
book from another SimpleBookService

Most Service API will be relatively small bytecodes as most will be 
abstract or have simple implementations, the fact they're not garbage 
collected, doesn't matter much if the function of the node doesn't 
change, the API will remain limited to the subset in use, by the node.

Note that Jini Platform service implementations like Reggie, Outrigger 
etc, will exist in Service Impl ClassLoaders and Smart Proxy 
ClassLoaders, only the api will be in the Jini Platform ClassLoader.

Think of it as an expandable platform, everything is shared using 
implementations of Service API classes.

It's actually a good policy to be liberal with interfaces when building 
the Service API classes, even with parameters and return types.  Since 
extending interfaces is relatively straight forward, you new interfaces 
will be discovered by older client software as the old interface while 
new implementation code discovers the new interface of your service.  
Older nodes will load your new interface classes into the Service API 
space when your new proxy versions are unmarshalled. That's why it's 
important to maintain backward compatibility in the Service API space.

So best practise would be to create an experimental djinn group until 
your interfaces are stabilised and be prepared to restart your 
experimental group on a regular basis.

I have thought about using OSGi for Service API classes to be served up 
so they can be garbage collected, this might work for serialization too 
using the context ClassLoader.  I have also thought about using 
ClassLoader Tree's using bytecode dependency analysis as per Tim 
Blackman's research.  These things start to get very complicated, just 
to be able to flush the Service API classes.  Wouldn't it just be better 
to use mutiple services that are load balanced, enabling the jvm to be 
restarted if we want to?

There are other ways to make the Service API classes garbage 
collectable, such as having a tier filled with Service API ClassLoaders 
where each Service and Proxy lives in a child ClassLoader in the tree, 
however this presents the problem of what if an application wants to use 
many Service API's or a combination, the different Service API classes 
couldn't see each other from separate ClassLoaders.

Something to consider, best regards,

Peter.

Dennis Reedy wrote:
> On May 25, 2010, at 710PM, Peter Firmstone wrote:
>
>   
>> This is a good question, which gets to the heart of the Jini's pattern.
>>
>> I think the proposed ClassLoader structure will benefit Rio, by enabling increased API commonality and class sharing among Services and their clients.
>>
>> You can get around having to shutdown your jvm if you manage evolution of your API interfaces correctly, set up a separate testing Registrar, to keep new API interfaces out of your deployment, until they have stabilised.
>>     
>
> Right now the JVM doesnt need to be shut down at all, services can be loaded with different versions, unloaded, etc ... I think you're making assumptions here.
>   
>   
>> Classes, once loaded into a ClassLoader, cannot be garbage collected, but if your API classes don't change there is no problem, when was the last time ServiceRegistrar changed it's public API?   Unlike Jini's platform classes which are set in stone, new API classes can be introduced into older environments.
>>     
>
> Right, which is why service implementations get loaded into their own class loader. You define the 'platform' as whatever that needs to be for your case. For Rio it includes requisite bootstrapping and infrastructure technology. For River it most likely just includes the River 'platform', or nothing at all. 
>
> Consider ServiceStarter and the class loader created from that bootstrapping process. Please explain what is missing from that approach? Each service has it's own security policy. Why does this need to change? What and how does your approach improve on? To my eyes it seems overly complicated.
>
>   
>> Lets take Jini Platform services as an example, in Rio's ClassLoader tree below, the Interfaces for the Platform services exist in the CommonClassLoader, all classes in the CommonClassLoader are visible to any class in any child ClassLoader below in the tree.
>>
>> Platform services can be shared freely among all child ClassLoaders.
>>
>> Now take Service-1CL and Service-2CL, lets imagine for a moment that these two services both provide the same service, from different or the same node, it doesn't matter, let's imagine now another node with the same ClassLoader tree structure, which consumes these services.
>>
>> These services have their service interfaces bundled with their CodeSources, both on the client and at the Service, lets say that Service-2CL provides the same service, but has a different implementation.  Now there's a client service that consumes these services, performs an operation then discards the service.
>>
>> Now which common API do the two service proxy's share?
>>     
>
> Common API? The service proxies dont share anything. They are each loaded from an implementation of RMIClassLoaderApi
>   
>   
>>  This forces you to load both proxy's into the same ClassLoader, making their implementations visible to each other and the client.
>>     
>
> Not so sure about that Peter.
>
>   
>> By separating the API into, in your case the CommonClassLoader,
>>     
>
> APIs are not added to the CommonClassLoader, and I would argue that it should not happen. You generally do not want to add classes into a class loader that does not get GC'd.
>
>   
>> each with their own ProtectionDomains, all Services and clients in that node, share the same API classes and can be isolated in their own ClassLoader's and can have different implementations but share the same common API types.
>>
>> The client service-param.jar is for clients who create new implementations / extend parameters in API methods, the Service server node will require these classes to unmarshall the parameters.  Client parameter classes will never be granted permissions.
>>
>> I'll make up some separate ClassLoader tree diagrams showing the client node, the service node and the relationships between remote ClassLoaders.
>>     
>
>
>   
>> Peter.
>>
>> Dennis Reedy wrote:
>>     
>>> If I understand correctly I think this is the crux of the issue. I dont understand why you need to load all API classes with the same class loader. FWIW, in Rio we handle the loading (and unloading) of services with the following structure (http://www.rio-project.org/apidocs/org/rioproject/boot/package-summary.html#package_description):
>>>                  AppCL
>>>                    |
>>>            CommonClassLoader (http:// URLs of common JARs)
>>>                    +
>>>                    |
>>>                    +
>>>            +-------+-------+----...---+
>>>            |               |          |
>>>        Service-1CL   Service-2CL  Service-nCL
>>>        
>>> AppCL - 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
>>> 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.
>>>
>>> Service-nCL - Contains the service specific implementation classes.
>>> Classpath: serviceImpl.jar
>>> Codebase: "serviceX-dl.jar rio-dl.jar jsk-lib-dl.jar"
>>>
>>> Certainly not as sophisticated as OSGi (or what you are targeting), but it meets the requirements of allowing multiple service versions, applying security context per class loader using the same approach as ActivateWrapper, and allows the JVM to stay running. 
>>>  
>>>       
>
>
>   


Re: Service API, class visibility, isolation and garbage collection - ClassLoaders

Posted by Greg Trasuk <tr...@stratuscom.com>.
Comments below...

Cheers,

Greg.
On Wed, 2010-05-26 at 07:27, Peter Firmstone wrote:
> Hi Dennis,
> 
> Looking back at my earlier reply when you presented the ClassLoader 
> structure for Rio, I was unintentionally insensitive.
> 
> I didn't mean to pull it apart, probably not the right approach, Rio is 
> a success in it's own right!
> 
> What I should have said and I may not have communicated too well is that 
> I'm introducing a way for Service Proxy's to utilise ClassLoader 
> visibility for maximum API class sharing.  It is a new feature, to give 
> Service implementers the power to share their Service API's, with as 
> much local JVM visibility as the Jini Platform Service API's have.
> 

Um.. why?  API classes are the client's problem.  The service
implementer just makes a few interfaces, and possibly a few domain
classes (data types) available, and if the client wants to use them,
includes the api-jar in its classpath.  I'd argue that in almost all
cases, the client is compiled against a particular api, so can go ahead
and include those jars in its runtime classpath as well.  If a proxy has
its own classes, the codebase classloading mechanism (along with
preferred classes) just puts those classes into their own classloader,
and will garbage-collect the whole classloader if the proxy instance
becomes unreferenced.  Surely, even smart proxies will not be so huge
that a little duplication is a problem.

Now, if you're after a generic, portable module mechanism, like OSGi but
with remotely specifiable modules, that's fine, but I'm not convinced
that's in Jini/River's purview.


> As I pointed out there is a compromise, that Service API classes cannot 
> be garbage collected.  I think that if this can be well managed, using a 
> Permission, then it should not affect uptime for critical applications.
> 
I'm hard pressed to think of a case where an api class changes without
requiring a redeployment of its clients, which, even if you're in an
application container, would trigger garbage collection of the whole
classloader.  Can you give an example?

> With great power comes great responsibility... yada yada yada.
> 

In my books, simplicity always wins.

> Cheers,
> 
> Peter.
> 
> Peter Firmstone wrote:
> > Peter Firmstone wrote:
> >> IDENTICAL TO ANOTHER MESSAGE IN THREAD: Re: Maven repository Entry 
> >> was Re: Codebase service?
> >>
> >> Note: A permission will be required to allow a proxy to introduce new 
> >> Service API during unmarshalling to prevent against denial of service 
> >> attacks.
> > However in the absence of this permission, the additional ServiceAPI 
> > jar could be downloaded into the proxy's own ClassLoader, that would 
> > require a ClassLoader even for a dumb proxy with an interface you 
> > didn't want to load into your Service API space.  This would enable 
> > unmarshalling of that Proxy.  If you, at a later point decided to load 
> > that interface into your Service API space, I think you still wouldn't 
> > be able to interact with this particular proxy using it, since the 
> > interface class identity would be different.
> >
> > Denial of service here means unfairly growing a JVM's use of non 
> > garbage collectable classes.  Any ideas how to control download proxy 
> > memory consumption.
> >>
> >> Hi Dennis,
> >>
> >> It sounds like you remain unconvinced or don't have a need to use common
> >> interfaces for your service proxy's?
> >>
> >> So I guess it's a tread lightly approach, make the feature available to
> >> those that want common Service API (The same interface instance for all
> >> proxy's implementing that interface, so they can be used in collections
> >> or batch operations), for maximum sharing of proxy's with differing
> >> implementations, but let those that don't want to publish their API
> >> continue doing what they usually do.  A configuration parameter should
> >> be able to set the desired behaviour.
> >>
> >> The approach I've taken is a simple approach to a complex problem,
> >> alternative approaches leave the complexity in the hands of the
> >> implementer, my approach will enable them to practically ignore it.
> >>
> >> Before you write it off though, to answer your earlier question, I'll
> >> further explain the ClassLoader structure between multiple nodes.
> >>
> >>                    CLIENT NODE
> >> ________________________________________________
> >> |                                                |
> >> |             System                             |
> >> |           ClassLoader                          |
> >> |                |                               |
> >> |            Extension                           |
> >> |           ClassLoader                          |
> >> |                |                               |
> >> |          Jini Platform &                       |
> >> |           Service API                          |
> >> |           ClassLoader                          |
> >> |                |                               |
> >> |       _________|___                            |
> >> |      |             |                           |
> >> | Application    Smart Proxy                     |
> >> | ClassLoader    ClassLoader's                   |
> >> |________________________________________________|
> >>
> >>
> >>                   SERVICE NODE
> >> ________________________________________________
> >> |                                                |
> >> |             System                             |
> >> |           ClassLoader                          |
> >> |                |                               |
> >> |            Extension                           |
> >> |           ClassLoader                          |
> >> |                |                               |
> >> |          Jini Platform &                       |
> >> |           Service API                          |
> >> |           ClassLoader                          |
> >> |                |                               |
> >> |       _________|_____________________          |
> >> |      |             |                 |         |
> >> | Service Imp    Smart Proxy      Parameter Impl |
> >> | ClassLoader    ClassLoader's    ClassLoader's  |
> >> |________________________________________________|
> >>
> >>
> >> All Proxy and Service implementations are free to vary at will, proxy
> >> instances can be shared in collections or iterative operations based on
> >> common Service API supertype's  All Proxy's and Services are isolated in
> >> their own Domain, the only way to communicate externally is by using
> >> interfaces and classes in upper level ClassLoaders, they can utilise as
> >> many third party libraries jar archives as they need, these will all be
> >> loaded into a single ClassLoader unique to that Service or Proxy's
> >> Codebase and Principles.  The Service or Proxy's namespace will be
> >> totally separate from Application or other Proxy implementation's,
> >> except in the case where sharing is permitted for identical
> >> implementations by the implementation developer.
> >>
> >> Service API should be carefully considered and designed, it forms the
> >> basis of network Dependency Injection, you can discover ANY Service
> >> implementation variant using the same Service API.
> >>
> >> The Service API may include other Service API or Java platform classes.
> >>
> >> public interface SimpleBookService {
> >>
> >> public Book get( Library lib, String name);
> >>
> >> }
> >>
> >> In the SimpleBookService above, given a Library and String name of a
> >> Book, a Book instance is returned by the proxy.
> >>
> >> The contents of simpleBookService-api.jar:
> >>
> >> SimpleBookService.class
> >> Book.class
> >> Library.class
> >>
> >> Let's say a client has extended the Library, with a class called
> >> PrivateLibrary, this class is an implementation class by the client,
> >> that the Service knows nothing about, the Service only uses the Library
> >> API, but it needs the PrivateLibrary.class
> >>
> >> The client makes an archive containing the PrivateLibrary.class publicly
> >> available in an archive called privateLibrary-param.jar.  This archive
> >> depends on simpleBookService-api.jar The jar URL is marshalled with the
> >> class when the parameters are sent back to the service.  When it gets to
> >> the service implementation, privateLibrary-param.jar is given it's own
> >> ClassLoader and ProtectionDomain and isn't given any Permissions.  It is
> >> used by a SimpleBookService implementation to decide which Book to
> >> return to the client, after which, it's garbage collected, eventually if
> >> PrivateLibrary isn't used again its ClassLoader is garbage collected 
> >> too.
> >>
> >> Each SimpleBookService proxy implementation will have their own
> >> ClassLoader namespace, but Client Application classes can still use any
> >> Service implementation or as many Service implementations as it can
> >> handle at the same time, all the while treating them as the same Type.
> >>
> >> One SimpleBookService implementation proxy, contains its own
> >> implementation of Book, and while the client is reading the book, it
> >> remains available from the proxy ClassLoader via the Service API Book
> >> interface, when finished reading the book, the proxy, book and
> >> ClassLoader can be garbage collected.  Tomorrow, the client might read a
> >> book from another SimpleBookService
> >>
> >> Most Service API will be relatively small bytecodes as most will be
> >> abstract or have simple implementations, the fact they're not garbage
> >> collected, doesn't matter much if the function of the node doesn't
> >> change, the API will remain limited to the subset in use, by the node.
> >>
> >> Note that Jini Platform service implementations like Reggie, Outrigger
> >> etc, will exist in Service Impl ClassLoaders and Smart Proxy
> >> ClassLoaders, only the api will be in the Jini Platform ClassLoader.
> >>
> >> Think of it as an expandable platform, everything is shared using
> >> implementations of Service API classes.
> >>
> >> It's actually a good policy to be liberal with interfaces when building
> >> the Service API classes, even with parameters and return types.  Since
> >> extending interfaces is relatively straight forward, you new interfaces
> >> will be discovered by older client software as the old interface while
> >> new implementation code discovers the new interface of your service.
> >> Older nodes will load your new interface classes into the Service API
> >> space when your new proxy versions are unmarshalled. That's why it's
> >> important to maintain backward compatibility in the Service API space.
> >>
> >> So best practise would be to create an experimental djinn group until
> >> your interfaces are stabilised and be prepared to restart your
> >> experimental group on a regular basis.
> >>
> >> I have thought about using OSGi for Service API classes to be served up
> >> so they can be garbage collected, this might work for serialization too
> >> using the context ClassLoader.  I have also thought about using
> >> ClassLoader Tree's using bytecode dependency analysis as per Tim
> >> Blackman's research.  These things start to get very complicated, just
> >> to be able to flush the Service API classes.  Wouldn't it just be better
> >> to use mutiple services that are load balanced, enabling the jvm to be
> >> restarted if we want to?
> >>
> >> There are other ways to make the Service API classes garbage
> >> collectable, such as having a tier filled with Service API ClassLoaders
> >> where each Service and Proxy lives in a child ClassLoader in the tree,
> >> however this presents the problem of what if an application wants to use
> >> many Service API's or a combination, the different Service API classes
> >> couldn't see each other from separate ClassLoaders.
> >>
> >> Something to consider, best regards,
> >>
> >> Peter.
> >>
> >> Dennis Reedy wrote:
> >>> On May 25, 2010, at 710PM, Peter Firmstone wrote:
> >>>
> >>>  
> >>>> This is a good question, which gets to the heart of the Jini's 
> >>>> pattern.
> >>>>
> >>>> I think the proposed ClassLoader structure will benefit Rio, by 
> >>>> enabling increased API commonality and class sharing among Services 
> >>>> and their clients.
> >>>>
> >>>> You can get around having to shutdown your jvm if you manage 
> >>>> evolution of your API interfaces correctly, set up a separate 
> >>>> testing Registrar, to keep new API interfaces out of your 
> >>>> deployment, until they have stabilised.
> >>>>     
> >>>
> >>> Right now the JVM doesnt need to be shut down at all, services can 
> >>> be loaded with different versions, unloaded, etc ... I think you're 
> >>> making assumptions here.
> >>>   
> >>>> Classes, once loaded into a ClassLoader, cannot be garbage 
> >>>> collected, but if your API classes don't change there is no 
> >>>> problem, when was the last time ServiceRegistrar changed it's 
> >>>> public API?   Unlike Jini's platform classes which are set in 
> >>>> stone, new API classes can be introduced into older environments.
> >>>>     
> >>>
> >>> Right, which is why service implementations get loaded into their 
> >>> own class loader. You define the 'platform' as whatever that needs 
> >>> to be for your case. For Rio it includes requisite bootstrapping and 
> >>> infrastructure technology. For River it most likely just includes 
> >>> the River 'platform', or nothing at all.
> >>> Consider ServiceStarter and the class loader created from that 
> >>> bootstrapping process. Please explain what is missing from that 
> >>> approach? Each service has it's own security policy. Why does this 
> >>> need to change? What and how does your approach improve on? To my 
> >>> eyes it seems overly complicated.
> >>>
> >>>  
> >>>> Lets take Jini Platform services as an example, in Rio's 
> >>>> ClassLoader tree below, the Interfaces for the Platform services 
> >>>> exist in the CommonClassLoader, all classes in the 
> >>>> CommonClassLoader are visible to any class in any child ClassLoader 
> >>>> below in the tree.
> >>>>
> >>>> Platform services can be shared freely among all child ClassLoaders.
> >>>>
> >>>> Now take Service-1CL and Service-2CL, lets imagine for a moment 
> >>>> that these two services both provide the same service, from 
> >>>> different or the same node, it doesn't matter, let's imagine now 
> >>>> another node with the same ClassLoader tree structure, which 
> >>>> consumes these services.
> >>>>
> >>>> These services have their service interfaces bundled with their 
> >>>> CodeSources, both on the client and at the Service, lets say that 
> >>>> Service-2CL provides the same service, but has a different 
> >>>> implementation.  Now there's a client service that consumes these 
> >>>> services, performs an operation then discards the service.
> >>>>
> >>>> Now which common API do the two service proxy's share?
> >>>>     
> >>>
> >>> Common API? The service proxies dont share anything. They are each 
> >>> loaded from an implementation of RMIClassLoaderApi
> >>>   
> >>>>  This forces you to load both proxy's into the same ClassLoader, 
> >>>> making their implementations visible to each other and the client.
> >>>>     
> >>>
> >>> Not so sure about that Peter.
> >>>
> >>>  
> >>>> By separating the API into, in your case the CommonClassLoader,
> >>>>     
> >>>
> >>> APIs are not added to the CommonClassLoader, and I would argue that 
> >>> it should not happen. You generally do not want to add classes into 
> >>> a class loader that does not get GC'd.
> >>>
> >>>  
> >>>> each with their own ProtectionDomains, all Services and clients in 
> >>>> that node, share the same API classes and can be isolated in their 
> >>>> own ClassLoader's and can have different implementations but share 
> >>>> the same common API types.
> >>>>
> >>>> The client service-param.jar is for clients who create new 
> >>>> implementations / extend parameters in API methods, the Service 
> >>>> server node will require these classes to unmarshall the 
> >>>> parameters.  Client parameter classes will never be granted 
> >>>> permissions.
> >>>>
> >>>> I'll make up some separate ClassLoader tree diagrams showing the 
> >>>> client node, the service node and the relationships between remote 
> >>>> ClassLoaders.
> >>>>     
> >>>
> >>>
> >>>  
> >>>> Peter.
> >>>>
> >>>> Dennis Reedy wrote:
> >>>>   
> >>>>> If I understand correctly I think this is the crux of the issue. I 
> >>>>> dont understand why you need to load all API classes with the same 
> >>>>> class loader. FWIW, in Rio we handle the loading (and unloading) 
> >>>>> of services with the following structure 
> >>>>> (http://www.rio-project.org/apidocs/org/rioproject/boot/package-summary.html#package_description): 
> >>>>>
> >>>>>                  AppCL
> >>>>>                    |
> >>>>>            CommonClassLoader (http:// URLs of common JARs)
> >>>>>                    +
> >>>>>                    |
> >>>>>                    +
> >>>>>            +-------+-------+----...---+
> >>>>>            |               |          |
> >>>>>        Service-1CL   Service-2CL  Service-nCL
> >>>>>        AppCL - 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
> >>>>> 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.
> >>>>>
> >>>>> Service-nCL - Contains the service specific implementation classes.
> >>>>> Classpath: serviceImpl.jar
> >>>>> Codebase: "serviceX-dl.jar rio-dl.jar jsk-lib-dl.jar"
> >>>>>
> >>>>> Certainly not as sophisticated as OSGi (or what you are 
> >>>>> targeting), but it meets the requirements of allowing multiple 
> >>>>> service versions, applying security context per class loader using 
> >>>>> the same approach as ActivateWrapper, and allows the JVM to stay 
> >>>>> running.        
> >>>
> >>>
> >>>   
> >>
> >>
> >>
> >
> >
-- 
Greg Trasuk, President
StratusCom Manufacturing Systems Inc. - We use information technology to
solve business problems on your plant floor.
http://stratuscom.com


Re: Service API, class visibility, isolation and garbage collection - ClassLoaders

Posted by Peter Firmstone <ji...@zeus.net.au>.
Dennis Reedy wrote:
> On May 27, 2010, at 451AM, Peter Firmstone wrote:
>
>   
>> Hi Dennis,
>>
>> I can live with Compile time only Service API's (not dynamically loaded), as has been identified, the API is known prior by the application.
>>     
>
> I'm sorry for not answering your question directly, I want to make sure I understand you correctly. 
>
> By compile time, are you thinking of an environment that only deals with classes that are loaded at JVM start time? 
>
> Or, since a client needs to have some a-priori knowledge of what it wants to discover and use, that means the class(es) are known by the client in advance. And those classes are included in the classpath of the client. Is that what you mean by compile time?
>   

The latter.

>   
>> We should encourage developers to maker their Service API publicly available on Maven repository's, for others to implement.
>>     
>
> Well, it would be for others to 'use'. Typically artifacts are published to repositories so you can use them. You may be able to obtain the sources, and depending on the license (or other criteria) of the project create derivative implementation(s). But in general the issue is not one of creating implementations, but one of use and inclusion into the systems that you create.
>
>   
>> So we can implement any Service API, whether we have the source or not, confident that it cannot obtain any Permission's, we can guarantee this by using static immutable ProtectionDomain's for Service API, where Policy checks are excluded.  Is this the best policy?  Or should we allow dynamic Permission grants for ServiceAPI too?  We can always relax our policy later, to make it stricter would risk breaking code if we had to reverse the decision.
>>
>>
>> Service Implementers produce jar archives for:
>>
>> Smart Proxy's:
>>
>> Implementation jar: service.jar (depends on service-api.jar)
>> API jar:            service-api.jar (unless implemented already)
>> Smart proxy jar:    service-proxy.jar (depends on service-api.jar)
>>               The proxy can depend on other jar's too.
>>
>> Dumb Proxy's:
>>
>> Implementation jar: service.jar (depends on service-api.jar)
>> API jar:            service-api.jar
>>
>>
>> Client's must produce the following jar archive, if extending Parameters:
>>
>> Client Parameter extensions:   AnyNameYouLike-param.jar
>>
>>     
>
> Why do we need the -param.jar again? 
>   

If we have multiple organisations, entities or companies, cooperating 
using River, a Services API, might have some parameter classes that are 
interfaces or extendible classes.  Where a service is used as a means of 
exchanging Objects between the two companies, the client developer and 
the Service developer are independent parties.

If the client developer wishes to extend some parameter classes, he 
would need to make those available for the Service implementation.  The 
client might initially use some default parameter classes provided by 
the Service, but later decide to extend these classes for whatever reason.

It enables the client to extend or change these parameter classes 
dynamically.

It's a separation of concerns, an optional package produced by the 
client developer.

Cheers,

Peter.

Re: Service API, class visibility, isolation and garbage collection - ClassLoaders

Posted by Peter Firmstone <ji...@zeus.net.au>.
Dennis Reedy wrote:
>> We should encourage developers to maker their Service API publicly available on Maven repository's, for others to implement.
>>     
>
> Well, it would be for others to 'use'. Typically artifacts are published to repositories so you can use them. You may be able to obtain the sources, and depending on the license (or other criteria) of the project create derivative implementation(s). But in general the issue is not one of creating implementations, but one of use and inclusion into the systems that you create.
>   
Yes, but I'd like to build a reusable public library of Service API's 
for developers to utilise.  Who know's some standard interfaces for 
commerce etc, might crop up.

Do you think this would be better served as a Subproject?  Would anyone 
be interested in contributing Service API?

I suppose the thought may frighten some, as there is some benefit in an 
attacker not knowing a Service API. Security by obscurity is foolhardy, 
if they're determined, they can find it using bytecode analysis, or 
reflection.

We can use other measures such as Delayed Unmarshalling, Download 
Permission, Authentication, Integrity, Privacy (encryption), Trust and 
Isolation (Permissions, ProtectionDomains & ClassLoader vis) to secure 
public distributed programmes over untrusted networks.

Regards,

Peter.
>   
>> So we can implement any Service API, whether we have the source or not, confident that it cannot obtain any Permission's, we can guarantee this by using static immutable ProtectionDomain's for Service API, where Policy checks are excluded.  Is this the best policy?  Or should we allow dynamic Permission grants for ServiceAPI too?  We can always relax our policy later, to make it stricter would risk breaking code if we had to reverse the decision.
>>
>>
>> Service Implementers produce jar archives for:
>>
>> Smart Proxy's:
>>
>> Implementation jar: service.jar (depends on service-api.jar)
>> API jar:            service-api.jar (unless implemented already)
>> Smart proxy jar:    service-proxy.jar (depends on service-api.jar)
>>               The proxy can depend on other jar's too.
>>
>> Dumb Proxy's:
>>
>> Implementation jar: service.jar (depends on service-api.jar)
>> API jar:            service-api.jar
>>
>>
>> Client's must produce the following jar archive, if extending Parameters:
>>
>> Client Parameter extensions:   AnyNameYouLike-param.jar
>>     

Re: Service API, class visibility, isolation and garbage collection - ClassLoaders

Posted by Dennis Reedy <de...@gmail.com>.
On May 27, 2010, at 451AM, Peter Firmstone wrote:

> Hi Dennis,
> 
> I can live with Compile time only Service API's (not dynamically loaded), as has been identified, the API is known prior by the application.

I'm sorry for not answering your question directly, I want to make sure I understand you correctly. 

By compile time, are you thinking of an environment that only deals with classes that are loaded at JVM start time? 

Or, since a client needs to have some a-priori knowledge of what it wants to discover and use, that means the class(es) are known by the client in advance. And those classes are included in the classpath of the client. Is that what you mean by compile time?

> 
> We should encourage developers to maker their Service API publicly available on Maven repository's, for others to implement.

Well, it would be for others to 'use'. Typically artifacts are published to repositories so you can use them. You may be able to obtain the sources, and depending on the license (or other criteria) of the project create derivative implementation(s). But in general the issue is not one of creating implementations, but one of use and inclusion into the systems that you create.

> 
> So we can implement any Service API, whether we have the source or not, confident that it cannot obtain any Permission's, we can guarantee this by using static immutable ProtectionDomain's for Service API, where Policy checks are excluded.  Is this the best policy?  Or should we allow dynamic Permission grants for ServiceAPI too?  We can always relax our policy later, to make it stricter would risk breaking code if we had to reverse the decision.
> 
> 
> Service Implementers produce jar archives for:
> 
> Smart Proxy's:
> 
> Implementation jar: service.jar (depends on service-api.jar)
> API jar:            service-api.jar (unless implemented already)
> Smart proxy jar:    service-proxy.jar (depends on service-api.jar)
>               The proxy can depend on other jar's too.
> 
> Dumb Proxy's:
> 
> Implementation jar: service.jar (depends on service-api.jar)
> API jar:            service-api.jar
> 
> 
> Client's must produce the following jar archive, if extending Parameters:
> 
> Client Parameter extensions:   AnyNameYouLike-param.jar
> 

Why do we need the -param.jar again? 

Re: Service API, class visibility, isolation and garbage collection - ClassLoaders

Posted by Peter Firmstone <ji...@zeus.net.au>.
Hi Dennis,

I can live with Compile time only Service API's (not dynamically 
loaded), as has been identified, the API is known prior by the application.

We should encourage developers to maker their Service API publicly 
available on Maven repository's, for others to implement.

Does anyone have any recommendations for ClassLoader structure or how to 
set it up, based on the following information?

   1. Public Service API, we've assumed cannot be trusted.
   2. Service API must be in a Parent ClassLoader relative to Client's,
      Service Proxy's and Implementation's, so the Service API's
      ProtectionDomain can be removed from the stack when the proxy or
      the client need to make a SecurityManager sm.checkPermission()? 
      While the Service API is on the call stack with no Permission's,
      the Permissions of proxy's, service implementation's or client's
      cannot be elevated.
   3. It isn't safe to remove the Service API's ProtectionDomain from
      the stack if your classes are visible to that Service API,
      otherwise it could gain Permissions.
   4. The service API must not see our implementations, so it cannot
      take advantage of the fact that we remove it's ProtectionDomain
      from our security checks in child ClassLoaders.
   5. This also means that if we implement an interface that requires a
      security check and the Service API can see that interface, the
      Service API must not be removed from the stack during
      checkPermission().  The higher up the ClassLoader tree the Service
      API is, the better, there's less to worry about.
   6. For ClassLoader domains visible to the Service API, the Service
      API ProtectionDomain cannot be removed from the stack.

So we can implement any Service API, whether we have the source or not, 
confident that it cannot obtain any Permission's, we can guarantee this 
by using static immutable ProtectionDomain's for Service API, where 
Policy checks are excluded.  Is this the best policy?  Or should we 
allow dynamic Permission grants for ServiceAPI too?  We can always relax 
our policy later, to make it stricter would risk breaking code if we had 
to reverse the decision.


Service Implementers produce jar archives for:

  Smart Proxy's:

  Implementation jar: service.jar (depends on service-api.jar)
  API jar:            service-api.jar (unless implemented already)
  Smart proxy jar:    service-proxy.jar (depends on service-api.jar)
                The proxy can depend on other jar's too.

  Dumb Proxy's:

  Implementation jar: service.jar (depends on service-api.jar)
  API jar:            service-api.jar


Client's must produce the following jar archive, if extending Parameters:

  Client Parameter extensions:   AnyNameYouLike-param.jar


If we want to provide a publicly available Service, we can publish these 
artefacts on Maven's repository and anyone can use it.

My apologies to the list for sending the last message 4 times! Poor 
mobile reception was the culprit.

Cheers,

Peter.

Dennis Reedy wrote:
> On May 26, 2010, at 609PM, Peter Firmstone wrote:
>
>> Dennis Reedy wrote:
>>> Peter,
>>>
>>> No worries. Although I think there is still a misunderstanding on how the class loader structure works, 
>> Ok, I think I see it now, your ClassLoader structure represents your container.  Containers are free to come and go in Rio during the life of the application?
>
> No, services are. BTW, this is a very similar structure to what ServiceStarter produces, the big difference is the addition of the common class loader that contains platform jars that are basically immutable, and not counted on to be changing during the lifecycle of the JVM.
>
>


Re: Service API, class visibility, isolation and garbage collection - ClassLoaders

Posted by Dennis Reedy <de...@gmail.com>.
On May 26, 2010, at 609PM, Peter Firmstone wrote:

> Dennis Reedy wrote:
>> Peter,
>> 
>> No worries. Although I think there is still a misunderstanding on how the class loader structure works, 
> 
> Ok, I think I see it now, your ClassLoader structure represents your container.  Containers are free to come and go in Rio during the life of the application?

No, services are. BTW, this is a very similar structure to what ServiceStarter produces, the big difference is the addition of the common class loader that contains platform jars that are basically immutable, and not counted on to be changing during the lifecycle of the JVM.


Re: Service API, class visibility, isolation and garbage collection - ClassLoaders

Posted by Peter Firmstone <ji...@zeus.net.au>.
Dennis Reedy wrote:
> Peter,
>
> No worries. Although I think there is still a misunderstanding on how the class loader structure works, 

Ok, I think I see it now, your ClassLoader structure represents your 
container.  Containers are free to come and go in Rio during the life of 
the application?

If I've got that correct, this is very useful.

I wasn't thinking about containers, only a bare metal JVM.

What you have could be very useful to me.


> its water under the bridge - lets move on.
>
> What I cant figure out is if you want to share classes across downloaded proxies, why the classes are not part of the API jar the client has in it's classpath. This allows downloaded proxies access to these classes, since the classloader they are loaded with delegates to the classloader that the API jar has been loaded with.
>   

Thinking about dynamic application assembly, not all the API is known at 
compile time, it has to be discovered later.

> It seems you are creating an edge condition where an implementor would like downloaded proxies to share a class across implementations, but in order to do that that class needs to be injected into a parent class loader. Do I have this right?
>   

Yes.

> IMO, in this scenario, I would advise that the class(es) in question should be added to the API jar.
>   
>  AppCL
>   
Yes agreed, I just want to delay it until after startup, not known at 
compile time.

I think what I have as ServiceImpCL and SmartProxyCL and ParamterImpCL 
all map quite well to your Service-nCL'

N.B. I'm not a Programmer, so you'll have to bear with me I'm afraid, 
while I'm probably out of my depth, I couldn't let River die, I don't 
know why programmers can't see Jini's strengths.

In my job we undertake seemingly impossible tasks, Construction & Heavy 
(5000T) Machinery Overhauls we always end up figuring it out however.

Thanks Peter.
>    
> On May 26, 2010, at 727AM, Peter Firmstone wrote:
>
>   
>> Hi Dennis,
>>
>> Looking back at my earlier reply when you presented the ClassLoader structure for Rio, I was unintentionally insensitive.
>>
>> I didn't mean to pull it apart, probably not the right approach, Rio is a success in it's own right!
>>
>> What I should have said and I may not have communicated too well is that I'm introducing a way for Service Proxy's to utilise ClassLoader visibility for maximum API class sharing.  It is a new feature, to give Service implementers the power to share their Service API's, with as much local JVM visibility as the Jini Platform Service API's have.
>>
>> As I pointed out there is a compromise, that Service API classes cannot be garbage collected.  I think that if this can be well managed, using a Permission, then it should not affect uptime for critical applications.
>>
>> With great power comes great responsibility... yada yada yada.
>>
>> Cheers,
>>
>> Peter.
>>
>> Peter Firmstone wrote:
>>     
>>> Peter Firmstone wrote:
>>>       
>>>> IDENTICAL TO ANOTHER MESSAGE IN THREAD: Re: Maven repository Entry was Re: Codebase service?
>>>>
>>>> Note: A permission will be required to allow a proxy to introduce new Service API during unmarshalling to prevent against denial of service attacks.
>>>>         
>>> However in the absence of this permission, the additional ServiceAPI jar could be downloaded into the proxy's own ClassLoader, that would require a ClassLoader even for a dumb proxy with an interface you didn't want to load into your Service API space.  This would enable unmarshalling of that Proxy.  If you, at a later point decided to load that interface into your Service API space, I think you still wouldn't be able to interact with this particular proxy using it, since the interface class identity would be different.
>>>
>>> Denial of service here means unfairly growing a JVM's use of non garbage collectable classes.  Any ideas how to control download proxy memory consumption.
>>>       
>>>> Hi Dennis,
>>>>
>>>> It sounds like you remain unconvinced or don't have a need to use common
>>>> interfaces for your service proxy's?
>>>>
>>>> So I guess it's a tread lightly approach, make the feature available to
>>>> those that want common Service API (The same interface instance for all
>>>> proxy's implementing that interface, so they can be used in collections
>>>> or batch operations), for maximum sharing of proxy's with differing
>>>> implementations, but let those that don't want to publish their API
>>>> continue doing what they usually do.  A configuration parameter should
>>>> be able to set the desired behaviour.
>>>>
>>>> The approach I've taken is a simple approach to a complex problem,
>>>> alternative approaches leave the complexity in the hands of the
>>>> implementer, my approach will enable them to practically ignore it.
>>>>
>>>> Before you write it off though, to answer your earlier question, I'll
>>>> further explain the ClassLoader structure between multiple nodes.
>>>>
>>>>                   CLIENT NODE
>>>> ________________________________________________
>>>> |                                                |
>>>> |             System                             |
>>>> |           ClassLoader                          |
>>>> |                |                               |
>>>> |            Extension                           |
>>>> |           ClassLoader                          |
>>>> |                |                               |
>>>> |          Jini Platform &                       |
>>>> |           Service API                          |
>>>> |           ClassLoader                          |
>>>> |                |                               |
>>>> |       _________|___                            |
>>>> |      |             |                           |
>>>> | Application    Smart Proxy                     |
>>>> | ClassLoader    ClassLoader's                   |
>>>> |________________________________________________|
>>>>
>>>>
>>>>                  SERVICE NODE
>>>> ________________________________________________
>>>> |                                                |
>>>> |             System                             |
>>>> |           ClassLoader                          |
>>>> |                |                               |
>>>> |            Extension                           |
>>>> |           ClassLoader                          |
>>>> |                |                               |
>>>> |          Jini Platform &                       |
>>>> |           Service API                          |
>>>> |           ClassLoader                          |
>>>> |                |                               |
>>>> |       _________|_____________________          |
>>>> |      |             |                 |         |
>>>> | Service Imp    Smart Proxy      Parameter Impl |
>>>> | ClassLoader    ClassLoader's    ClassLoader's  |
>>>> |________________________________________________|
>>>>
>>>>
>>>> All Proxy and Service implementations are free to vary at will, proxy
>>>> instances can be shared in collections or iterative operations based on
>>>> common Service API supertype's  All Proxy's and Services are isolated in
>>>> their own Domain, the only way to communicate externally is by using
>>>> interfaces and classes in upper level ClassLoaders, they can utilise as
>>>> many third party libraries jar archives as they need, these will all be
>>>> loaded into a single ClassLoader unique to that Service or Proxy's
>>>> Codebase and Principles.  The Service or Proxy's namespace will be
>>>> totally separate from Application or other Proxy implementation's,
>>>> except in the case where sharing is permitted for identical
>>>> implementations by the implementation developer.
>>>>
>>>> Service API should be carefully considered and designed, it forms the
>>>> basis of network Dependency Injection, you can discover ANY Service
>>>> implementation variant using the same Service API.
>>>>
>>>> The Service API may include other Service API or Java platform classes.
>>>>
>>>> public interface SimpleBookService {
>>>>
>>>> public Book get( Library lib, String name);
>>>>
>>>> }
>>>>
>>>> In the SimpleBookService above, given a Library and String name of a
>>>> Book, a Book instance is returned by the proxy.
>>>>
>>>> The contents of simpleBookService-api.jar:
>>>>
>>>> SimpleBookService.class
>>>> Book.class
>>>> Library.class
>>>>
>>>> Let's say a client has extended the Library, with a class called
>>>> PrivateLibrary, this class is an implementation class by the client,
>>>> that the Service knows nothing about, the Service only uses the Library
>>>> API, but it needs the PrivateLibrary.class
>>>>
>>>> The client makes an archive containing the PrivateLibrary.class publicly
>>>> available in an archive called privateLibrary-param.jar.  This archive
>>>> depends on simpleBookService-api.jar The jar URL is marshalled with the
>>>> class when the parameters are sent back to the service.  When it gets to
>>>> the service implementation, privateLibrary-param.jar is given it's own
>>>> ClassLoader and ProtectionDomain and isn't given any Permissions.  It is
>>>> used by a SimpleBookService implementation to decide which Book to
>>>> return to the client, after which, it's garbage collected, eventually if
>>>> PrivateLibrary isn't used again its ClassLoader is garbage collected too.
>>>>
>>>> Each SimpleBookService proxy implementation will have their own
>>>> ClassLoader namespace, but Client Application classes can still use any
>>>> Service implementation or as many Service implementations as it can
>>>> handle at the same time, all the while treating them as the same Type.
>>>>
>>>> One SimpleBookService implementation proxy, contains its own
>>>> implementation of Book, and while the client is reading the book, it
>>>> remains available from the proxy ClassLoader via the Service API Book
>>>> interface, when finished reading the book, the proxy, book and
>>>> ClassLoader can be garbage collected.  Tomorrow, the client might read a
>>>> book from another SimpleBookService
>>>>
>>>> Most Service API will be relatively small bytecodes as most will be
>>>> abstract or have simple implementations, the fact they're not garbage
>>>> collected, doesn't matter much if the function of the node doesn't
>>>> change, the API will remain limited to the subset in use, by the node.
>>>>
>>>> Note that Jini Platform service implementations like Reggie, Outrigger
>>>> etc, will exist in Service Impl ClassLoaders and Smart Proxy
>>>> ClassLoaders, only the api will be in the Jini Platform ClassLoader.
>>>>
>>>> Think of it as an expandable platform, everything is shared using
>>>> implementations of Service API classes.
>>>>
>>>> It's actually a good policy to be liberal with interfaces when building
>>>> the Service API classes, even with parameters and return types.  Since
>>>> extending interfaces is relatively straight forward, you new interfaces
>>>> will be discovered by older client software as the old interface while
>>>> new implementation code discovers the new interface of your service.
>>>> Older nodes will load your new interface classes into the Service API
>>>> space when your new proxy versions are unmarshalled. That's why it's
>>>> important to maintain backward compatibility in the Service API space.
>>>>
>>>> So best practise would be to create an experimental djinn group until
>>>> your interfaces are stabilised and be prepared to restart your
>>>> experimental group on a regular basis.
>>>>
>>>> I have thought about using OSGi for Service API classes to be served up
>>>> so they can be garbage collected, this might work for serialization too
>>>> using the context ClassLoader.  I have also thought about using
>>>> ClassLoader Tree's using bytecode dependency analysis as per Tim
>>>> Blackman's research.  These things start to get very complicated, just
>>>> to be able to flush the Service API classes.  Wouldn't it just be better
>>>> to use mutiple services that are load balanced, enabling the jvm to be
>>>> restarted if we want to?
>>>>
>>>> There are other ways to make the Service API classes garbage
>>>> collectable, such as having a tier filled with Service API ClassLoaders
>>>> where each Service and Proxy lives in a child ClassLoader in the tree,
>>>> however this presents the problem of what if an application wants to use
>>>> many Service API's or a combination, the different Service API classes
>>>> couldn't see each other from separate ClassLoaders.
>>>>
>>>> Something to consider, best regards,
>>>>
>>>> Peter.
>>>>
>>>> Dennis Reedy wrote:
>>>>         
>>>>> On May 25, 2010, at 710PM, Peter Firmstone wrote:
>>>>>
>>>>>
>>>>>           
>>>>>> This is a good question, which gets to the heart of the Jini's pattern.
>>>>>>
>>>>>> I think the proposed ClassLoader structure will benefit Rio, by enabling increased API commonality and class sharing among Services and their clients.
>>>>>>
>>>>>> You can get around having to shutdown your jvm if you manage evolution of your API interfaces correctly, set up a separate testing Registrar, to keep new API interfaces out of your deployment, until they have stabilised.
>>>>>>    
>>>>>>             
>>>>> Right now the JVM doesnt need to be shut down at all, services can be loaded with different versions, unloaded, etc ... I think you're making assumptions here.
>>>>>  
>>>>>           
>>>>>> Classes, once loaded into a ClassLoader, cannot be garbage collected, but if your API classes don't change there is no problem, when was the last time ServiceRegistrar changed it's public API?   Unlike Jini's platform classes which are set in stone, new API classes can be introduced into older environments.
>>>>>>    
>>>>>>             
>>>>> Right, which is why service implementations get loaded into their own class loader. You define the 'platform' as whatever that needs to be for your case. For Rio it includes requisite bootstrapping and infrastructure technology. For River it most likely just includes the River 'platform', or nothing at all.
>>>>> Consider ServiceStarter and the class loader created from that bootstrapping process. Please explain what is missing from that approach? Each service has it's own security policy. Why does this need to change? What and how does your approach improve on? To my eyes it seems overly complicated.
>>>>>
>>>>>
>>>>>           
>>>>>> Lets take Jini Platform services as an example, in Rio's ClassLoader tree below, the Interfaces for the Platform services exist in the CommonClassLoader, all classes in the CommonClassLoader are visible to any class in any child ClassLoader below in the tree.
>>>>>>
>>>>>> Platform services can be shared freely among all child ClassLoaders.
>>>>>>
>>>>>> Now take Service-1CL and Service-2CL, lets imagine for a moment that these two services both provide the same service, from different or the same node, it doesn't matter, let's imagine now another node with the same ClassLoader tree structure, which consumes these services.
>>>>>>
>>>>>> These services have their service interfaces bundled with their CodeSources, both on the client and at the Service, lets say that Service-2CL provides the same service, but has a different implementation.  Now there's a client service that consumes these services, performs an operation then discards the service.
>>>>>>
>>>>>> Now which common API do the two service proxy's share?
>>>>>>    
>>>>>>             
>>>>> Common API? The service proxies dont share anything. They are each loaded from an implementation of RMIClassLoaderApi
>>>>>  
>>>>>           
>>>>>> This forces you to load both proxy's into the same ClassLoader, making their implementations visible to each other and the client.
>>>>>>    
>>>>>>             
>>>>> Not so sure about that Peter.
>>>>>
>>>>>
>>>>>           
>>>>>> By separating the API into, in your case the CommonClassLoader,
>>>>>>    
>>>>>>             
>>>>> APIs are not added to the CommonClassLoader, and I would argue that it should not happen. You generally do not want to add classes into a class loader that does not get GC'd.
>>>>>
>>>>>
>>>>>           
>>>>>> each with their own ProtectionDomains, all Services and clients in that node, share the same API classes and can be isolated in their own ClassLoader's and can have different implementations but share the same common API types.
>>>>>>
>>>>>> The client service-param.jar is for clients who create new implementations / extend parameters in API methods, the Service server node will require these classes to unmarshall the parameters.  Client parameter classes will never be granted permissions.
>>>>>>
>>>>>> I'll make up some separate ClassLoader tree diagrams showing the client node, the service node and the relationships between remote ClassLoaders.
>>>>>>    
>>>>>>             
>>>>>
>>>>>           
>>>>>> Peter.
>>>>>>
>>>>>> Dennis Reedy wrote:
>>>>>>  
>>>>>>             
>>>>>>> If I understand correctly I think this is the crux of the issue. I dont understand why you need to load all API classes with the same class loader. FWIW, in Rio we handle the loading (and unloading) of services with the following structure (http://www.rio-project.org/apidocs/org/rioproject/boot/package-summary.html#package_description): 
>>>>>>>                 AppCL
>>>>>>>                   |
>>>>>>>           CommonClassLoader (http:// URLs of common JARs)
>>>>>>>                   +
>>>>>>>                   |
>>>>>>>                   +
>>>>>>>           +-------+-------+----...---+
>>>>>>>           |               |          |
>>>>>>>       Service-1CL   Service-2CL  Service-nCL
>>>>>>>       AppCL - 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
>>>>>>> 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.
>>>>>>>
>>>>>>> Service-nCL - Contains the service specific implementation classes.
>>>>>>> Classpath: serviceImpl.jar
>>>>>>> Codebase: "serviceX-dl.jar rio-dl.jar jsk-lib-dl.jar"
>>>>>>>
>>>>>>> Certainly not as sophisticated as OSGi (or what you are targeting), but it meets the requirements of allowing multiple service versions, applying security context per class loader using the same approach as ActivateWrapper, and allows the JVM to stay running.        
>>>>>>>               
>>>>>  
>>>>>           
>>>>
>>>>         
>>>       
>
>
>   


Re: Service API, class visibility, isolation and garbage collection - ClassLoaders

Posted by Peter Firmstone <ji...@zeus.net.au>.
Dennis Reedy wrote:
> Peter,
>
> No worries. Although I think there is still a misunderstanding on how the class loader structure works, 

Ok, I think I see it now, your ClassLoader structure represents your 
container.  Containers are free to come and go in Rio during the life of 
the application?

If I've got that correct, this is very useful.

I wasn't thinking about containers, only a bare metal JVM.

What you have could be very useful to me.


> its water under the bridge - lets move on.
>
> What I cant figure out is if you want to share classes across downloaded proxies, why the classes are not part of the API jar the client has in it's classpath. This allows downloaded proxies access to these classes, since the classloader they are loaded with delegates to the classloader that the API jar has been loaded with.
>   

Thinking about dynamic application assembly, not all the API is known at 
compile time, it has to be discovered later.

> It seems you are creating an edge condition where an implementor would like downloaded proxies to share a class across implementations, but in order to do that that class needs to be injected into a parent class loader. Do I have this right?
>   

Yes.

> IMO, in this scenario, I would advise that the class(es) in question should be added to the API jar.
>   
>  AppCL
>   
Yes agreed, I just want to delay it until after startup, not known at 
compile time.

I think what I have as ServiceImpCL and SmartProxyCL and ParamterImpCL 
all map quite well to your Service-nCL'

N.B. I'm not a Programmer, so you'll have to bear with me I'm afraid, 
while I'm probably out of my depth, I couldn't let River die, I don't 
know why programmers can't see Jini's strengths.

In my job we undertake seemingly impossible tasks, Construction & Heavy 
(4000T) Machinery Overhauls we always end up figuring it out however.

Thanks Peter.
>    
> On May 26, 2010, at 727AM, Peter Firmstone wrote:
>
>   
>> Hi Dennis,
>>
>> Looking back at my earlier reply when you presented the ClassLoader structure for Rio, I was unintentionally insensitive.
>>
>> I didn't mean to pull it apart, probably not the right approach, Rio is a success in it's own right!
>>
>> What I should have said and I may not have communicated too well is that I'm introducing a way for Service Proxy's to utilise ClassLoader visibility for maximum API class sharing.  It is a new feature, to give Service implementers the power to share their Service API's, with as much local JVM visibility as the Jini Platform Service API's have.
>>
>> As I pointed out there is a compromise, that Service API classes cannot be garbage collected.  I think that if this can be well managed, using a Permission, then it should not affect uptime for critical applications.
>>
>> With great power comes great responsibility... yada yada yada.
>>
>> Cheers,
>>
>> Peter.
>>
>> Peter Firmstone wrote:
>>     
>>> Peter Firmstone wrote:
>>>       
>>>> IDENTICAL TO ANOTHER MESSAGE IN THREAD: Re: Maven repository Entry was Re: Codebase service?
>>>>
>>>> Note: A permission will be required to allow a proxy to introduce new Service API during unmarshalling to prevent against denial of service attacks.
>>>>         
>>> However in the absence of this permission, the additional ServiceAPI jar could be downloaded into the proxy's own ClassLoader, that would require a ClassLoader even for a dumb proxy with an interface you didn't want to load into your Service API space.  This would enable unmarshalling of that Proxy.  If you, at a later point decided to load that interface into your Service API space, I think you still wouldn't be able to interact with this particular proxy using it, since the interface class identity would be different.
>>>
>>> Denial of service here means unfairly growing a JVM's use of non garbage collectable classes.  Any ideas how to control download proxy memory consumption.
>>>       
>>>> Hi Dennis,
>>>>
>>>> It sounds like you remain unconvinced or don't have a need to use common
>>>> interfaces for your service proxy's?
>>>>
>>>> So I guess it's a tread lightly approach, make the feature available to
>>>> those that want common Service API (The same interface instance for all
>>>> proxy's implementing that interface, so they can be used in collections
>>>> or batch operations), for maximum sharing of proxy's with differing
>>>> implementations, but let those that don't want to publish their API
>>>> continue doing what they usually do.  A configuration parameter should
>>>> be able to set the desired behaviour.
>>>>
>>>> The approach I've taken is a simple approach to a complex problem,
>>>> alternative approaches leave the complexity in the hands of the
>>>> implementer, my approach will enable them to practically ignore it.
>>>>
>>>> Before you write it off though, to answer your earlier question, I'll
>>>> further explain the ClassLoader structure between multiple nodes.
>>>>
>>>>                   CLIENT NODE
>>>> ________________________________________________
>>>> |                                                |
>>>> |             System                             |
>>>> |           ClassLoader                          |
>>>> |                |                               |
>>>> |            Extension                           |
>>>> |           ClassLoader                          |
>>>> |                |                               |
>>>> |          Jini Platform &                       |
>>>> |           Service API                          |
>>>> |           ClassLoader                          |
>>>> |                |                               |
>>>> |       _________|___                            |
>>>> |      |             |                           |
>>>> | Application    Smart Proxy                     |
>>>> | ClassLoader    ClassLoader's                   |
>>>> |________________________________________________|
>>>>
>>>>
>>>>                  SERVICE NODE
>>>> ________________________________________________
>>>> |                                                |
>>>> |             System                             |
>>>> |           ClassLoader                          |
>>>> |                |                               |
>>>> |            Extension                           |
>>>> |           ClassLoader                          |
>>>> |                |                               |
>>>> |          Jini Platform &                       |
>>>> |           Service API                          |
>>>> |           ClassLoader                          |
>>>> |                |                               |
>>>> |       _________|_____________________          |
>>>> |      |             |                 |         |
>>>> | Service Imp    Smart Proxy      Parameter Impl |
>>>> | ClassLoader    ClassLoader's    ClassLoader's  |
>>>> |________________________________________________|
>>>>
>>>>
>>>> All Proxy and Service implementations are free to vary at will, proxy
>>>> instances can be shared in collections or iterative operations based on
>>>> common Service API supertype's  All Proxy's and Services are isolated in
>>>> their own Domain, the only way to communicate externally is by using
>>>> interfaces and classes in upper level ClassLoaders, they can utilise as
>>>> many third party libraries jar archives as they need, these will all be
>>>> loaded into a single ClassLoader unique to that Service or Proxy's
>>>> Codebase and Principles.  The Service or Proxy's namespace will be
>>>> totally separate from Application or other Proxy implementation's,
>>>> except in the case where sharing is permitted for identical
>>>> implementations by the implementation developer.
>>>>
>>>> Service API should be carefully considered and designed, it forms the
>>>> basis of network Dependency Injection, you can discover ANY Service
>>>> implementation variant using the same Service API.
>>>>
>>>> The Service API may include other Service API or Java platform classes.
>>>>
>>>> public interface SimpleBookService {
>>>>
>>>> public Book get( Library lib, String name);
>>>>
>>>> }
>>>>
>>>> In the SimpleBookService above, given a Library and String name of a
>>>> Book, a Book instance is returned by the proxy.
>>>>
>>>> The contents of simpleBookService-api.jar:
>>>>
>>>> SimpleBookService.class
>>>> Book.class
>>>> Library.class
>>>>
>>>> Let's say a client has extended the Library, with a class called
>>>> PrivateLibrary, this class is an implementation class by the client,
>>>> that the Service knows nothing about, the Service only uses the Library
>>>> API, but it needs the PrivateLibrary.class
>>>>
>>>> The client makes an archive containing the PrivateLibrary.class publicly
>>>> available in an archive called privateLibrary-param.jar.  This archive
>>>> depends on simpleBookService-api.jar The jar URL is marshalled with the
>>>> class when the parameters are sent back to the service.  When it gets to
>>>> the service implementation, privateLibrary-param.jar is given it's own
>>>> ClassLoader and ProtectionDomain and isn't given any Permissions.  It is
>>>> used by a SimpleBookService implementation to decide which Book to
>>>> return to the client, after which, it's garbage collected, eventually if
>>>> PrivateLibrary isn't used again its ClassLoader is garbage collected too.
>>>>
>>>> Each SimpleBookService proxy implementation will have their own
>>>> ClassLoader namespace, but Client Application classes can still use any
>>>> Service implementation or as many Service implementations as it can
>>>> handle at the same time, all the while treating them as the same Type.
>>>>
>>>> One SimpleBookService implementation proxy, contains its own
>>>> implementation of Book, and while the client is reading the book, it
>>>> remains available from the proxy ClassLoader via the Service API Book
>>>> interface, when finished reading the book, the proxy, book and
>>>> ClassLoader can be garbage collected.  Tomorrow, the client might read a
>>>> book from another SimpleBookService
>>>>
>>>> Most Service API will be relatively small bytecodes as most will be
>>>> abstract or have simple implementations, the fact they're not garbage
>>>> collected, doesn't matter much if the function of the node doesn't
>>>> change, the API will remain limited to the subset in use, by the node.
>>>>
>>>> Note that Jini Platform service implementations like Reggie, Outrigger
>>>> etc, will exist in Service Impl ClassLoaders and Smart Proxy
>>>> ClassLoaders, only the api will be in the Jini Platform ClassLoader.
>>>>
>>>> Think of it as an expandable platform, everything is shared using
>>>> implementations of Service API classes.
>>>>
>>>> It's actually a good policy to be liberal with interfaces when building
>>>> the Service API classes, even with parameters and return types.  Since
>>>> extending interfaces is relatively straight forward, you new interfaces
>>>> will be discovered by older client software as the old interface while
>>>> new implementation code discovers the new interface of your service.
>>>> Older nodes will load your new interface classes into the Service API
>>>> space when your new proxy versions are unmarshalled. That's why it's
>>>> important to maintain backward compatibility in the Service API space.
>>>>
>>>> So best practise would be to create an experimental djinn group until
>>>> your interfaces are stabilised and be prepared to restart your
>>>> experimental group on a regular basis.
>>>>
>>>> I have thought about using OSGi for Service API classes to be served up
>>>> so they can be garbage collected, this might work for serialization too
>>>> using the context ClassLoader.  I have also thought about using
>>>> ClassLoader Tree's using bytecode dependency analysis as per Tim
>>>> Blackman's research.  These things start to get very complicated, just
>>>> to be able to flush the Service API classes.  Wouldn't it just be better
>>>> to use mutiple services that are load balanced, enabling the jvm to be
>>>> restarted if we want to?
>>>>
>>>> There are other ways to make the Service API classes garbage
>>>> collectable, such as having a tier filled with Service API ClassLoaders
>>>> where each Service and Proxy lives in a child ClassLoader in the tree,
>>>> however this presents the problem of what if an application wants to use
>>>> many Service API's or a combination, the different Service API classes
>>>> couldn't see each other from separate ClassLoaders.
>>>>
>>>> Something to consider, best regards,
>>>>
>>>> Peter.
>>>>
>>>> Dennis Reedy wrote:
>>>>         
>>>>> On May 25, 2010, at 710PM, Peter Firmstone wrote:
>>>>>
>>>>>
>>>>>           
>>>>>> This is a good question, which gets to the heart of the Jini's pattern.
>>>>>>
>>>>>> I think the proposed ClassLoader structure will benefit Rio, by enabling increased API commonality and class sharing among Services and their clients.
>>>>>>
>>>>>> You can get around having to shutdown your jvm if you manage evolution of your API interfaces correctly, set up a separate testing Registrar, to keep new API interfaces out of your deployment, until they have stabilised.
>>>>>>    
>>>>>>             
>>>>> Right now the JVM doesnt need to be shut down at all, services can be loaded with different versions, unloaded, etc ... I think you're making assumptions here.
>>>>>  
>>>>>           
>>>>>> Classes, once loaded into a ClassLoader, cannot be garbage collected, but if your API classes don't change there is no problem, when was the last time ServiceRegistrar changed it's public API?   Unlike Jini's platform classes which are set in stone, new API classes can be introduced into older environments.
>>>>>>    
>>>>>>             
>>>>> Right, which is why service implementations get loaded into their own class loader. You define the 'platform' as whatever that needs to be for your case. For Rio it includes requisite bootstrapping and infrastructure technology. For River it most likely just includes the River 'platform', or nothing at all.
>>>>> Consider ServiceStarter and the class loader created from that bootstrapping process. Please explain what is missing from that approach? Each service has it's own security policy. Why does this need to change? What and how does your approach improve on? To my eyes it seems overly complicated.
>>>>>
>>>>>
>>>>>           
>>>>>> Lets take Jini Platform services as an example, in Rio's ClassLoader tree below, the Interfaces for the Platform services exist in the CommonClassLoader, all classes in the CommonClassLoader are visible to any class in any child ClassLoader below in the tree.
>>>>>>
>>>>>> Platform services can be shared freely among all child ClassLoaders.
>>>>>>
>>>>>> Now take Service-1CL and Service-2CL, lets imagine for a moment that these two services both provide the same service, from different or the same node, it doesn't matter, let's imagine now another node with the same ClassLoader tree structure, which consumes these services.
>>>>>>
>>>>>> These services have their service interfaces bundled with their CodeSources, both on the client and at the Service, lets say that Service-2CL provides the same service, but has a different implementation.  Now there's a client service that consumes these services, performs an operation then discards the service.
>>>>>>
>>>>>> Now which common API do the two service proxy's share?
>>>>>>    
>>>>>>             
>>>>> Common API? The service proxies dont share anything. They are each loaded from an implementation of RMIClassLoaderApi
>>>>>  
>>>>>           
>>>>>> This forces you to load both proxy's into the same ClassLoader, making their implementations visible to each other and the client.
>>>>>>    
>>>>>>             
>>>>> Not so sure about that Peter.
>>>>>
>>>>>
>>>>>           
>>>>>> By separating the API into, in your case the CommonClassLoader,
>>>>>>    
>>>>>>             
>>>>> APIs are not added to the CommonClassLoader, and I would argue that it should not happen. You generally do not want to add classes into a class loader that does not get GC'd.
>>>>>
>>>>>
>>>>>           
>>>>>> each with their own ProtectionDomains, all Services and clients in that node, share the same API classes and can be isolated in their own ClassLoader's and can have different implementations but share the same common API types.
>>>>>>
>>>>>> The client service-param.jar is for clients who create new implementations / extend parameters in API methods, the Service server node will require these classes to unmarshall the parameters.  Client parameter classes will never be granted permissions.
>>>>>>
>>>>>> I'll make up some separate ClassLoader tree diagrams showing the client node, the service node and the relationships between remote ClassLoaders.
>>>>>>    
>>>>>>             
>>>>>
>>>>>           
>>>>>> Peter.
>>>>>>
>>>>>> Dennis Reedy wrote:
>>>>>>  
>>>>>>             
>>>>>>> If I understand correctly I think this is the crux of the issue. I dont understand why you need to load all API classes with the same class loader. FWIW, in Rio we handle the loading (and unloading) of services with the following structure (http://www.rio-project.org/apidocs/org/rioproject/boot/package-summary.html#package_description): 
>>>>>>>                 AppCL
>>>>>>>                   |
>>>>>>>           CommonClassLoader (http:// URLs of common JARs)
>>>>>>>                   +
>>>>>>>                   |
>>>>>>>                   +
>>>>>>>           +-------+-------+----...---+
>>>>>>>           |               |          |
>>>>>>>       Service-1CL   Service-2CL  Service-nCL
>>>>>>>       AppCL - 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
>>>>>>> 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.
>>>>>>>
>>>>>>> Service-nCL - Contains the service specific implementation classes.
>>>>>>> Classpath: serviceImpl.jar
>>>>>>> Codebase: "serviceX-dl.jar rio-dl.jar jsk-lib-dl.jar"
>>>>>>>
>>>>>>> Certainly not as sophisticated as OSGi (or what you are targeting), but it meets the requirements of allowing multiple service versions, applying security context per class loader using the same approach as ActivateWrapper, and allows the JVM to stay running.        
>>>>>>>               
>>>>>  
>>>>>           
>>>>
>>>>         
>>>       
>
>
>   


Re: Service API, class visibility, isolation and garbage collection - ClassLoaders

Posted by Peter Firmstone <ji...@zeus.net.au>.
Peter Firmstone wrote:
> So client Proxy trust is currently:
>
>   1. Download the Proxy codebase.
>   2. Unmarshall the Proxy.
>   3. Ask the Proxy for the Proxy verifier.
>   4. Ask the Server if it trusts the proxy.
>   5. Grant trust to the proxy ClassLoader.
>
Another minor clarification, I missed out Authentication above, which 
comes before proxy Verification.

Re: ServiceRegistrar

Posted by Peter Firmstone <ji...@zeus.net.au>.
Thanks you comments are all much appreciated.

I'm having some thoughts about a ServiceRegistrar that is only a 
downloadable proxy without a server, that contains only the marshalled 
smart proxy instances of Services, that a single host provides, decided 
prior to deployment.  Sort of like an advertising medium found using 
discovery.

In other words, a static ServiceRegistrar smart proxy.

This would allow all languages to participate in providing services, in 
untrusted uncontrolled networks, using any Protocol they want.  To work 
where Surrogate doesn't, in environments, where there may be no 
Registrar at all.

It would require a standard tool for developers to create the Serialized 
form of the Registrar, containing the Marshalled Proxy's of the Services 
that are going to be advertised.  We could provide a standard download 
codebase for the Static Registrar, the implementing developer would need 
to create codebases for his / her service smart proxy's.

The problem of course is, how do you provide security for the client, 
when you don't know what protocol the Service is using.  I'm thinking 
that it is simpler to deny trust.  The codebases, however they are 
attained, would need to advertise their size, in an Entry.  The codebase 
download would be aborted if the codebase size exceeded the advertised size.

Even without trust, and a restriction on codebase size, a misbehaving 
Service Proxy can enter an endless loop, perhaps it should be 
encapsulated inside a Security Layer Delegate, that runs a time limited 
thread that executes the Proxy methods on the clients behalf, if the 
proxy doesn't return within a set time limit, it terminates the proxy's 
thread and throws an IOException.

When you think about the possibility of Permission's being advertised in 
the jar file, if it was signed by a trusted developer, and there was a 
way for the codebase to also indicate if it uses, a communication 
protocol with privacy and integrity (another Entry?), you could grant 
that codebase some Permission's but you still couldn't trust who or what 
was on the Server end of that proxy, even if the communication was 
private.  However it does allow enough trust to be established to 
authenticate the Service

You might say that there's a flaw in the above, a protocol that is 
considered secure at the time of development may no longer be secure 
when the client access the Service.

There is a simple way to fix this without un-abstracting the underlying 
protocol used, it is simply another service that developers use to 
advertise codebase implementations with security flaws, with a list of 
permissions that if revoked, will prevent the security attack.

Of course you'll need to look at the code from my latest commit to see 
how this is possible ;)

Thoughts?  What have I missed?

Cheers,

Peter.

Gregg Wonderly wrote:
> I agree, doing both would be the best choice of implementation.
>
> Gregg Wonderly
>
> Christopher Dolan wrote:
>> Best would be to block on both client and server side.  Client to 
>> help performance and server to prevent malicious intent.  Server side 
>> would be the minimum implementation.
>>
>> Chris
>>
>> -----Original Message-----
>> From: Patrick Wright [mailto:pdoubleya@gmail.com] Sent: Monday, June 
>> 28, 2010 3:17 AM
>> To: river-dev@incubator.apache.org
>> Subject: Re: ServiceRegistrar
>>
>> On Mon, Jun 28, 2010 at 10:11 AM, Tom Hobbs <tv...@googlemail.com> 
>> wrote:
>>> Does this not hook into the security discussions on internet-visible
>>> services?
>>>
>>> You can satisfy your use case with authorisation levels and just not 
>>> give
>>> "everyone" the authority to register services.  To my mind, this seems
>>> cleaner (although not necessarily better or easier), than having two 
>>> breeds
>>> of ServiceRegistrar.
>>
>> Just a thought--it seems to me you would want to block this on the
>> client side, to prevent DDOS attacks on the LUS if the LUS is visible
>> "globally". Block all attempts to register with a locally-generated
>> and thrown exception (via smart proxy returned by LUS on lookup).
>>
>>
>> Patrick
>>
>
>



Re: ServiceRegistrar

Posted by Gregg Wonderly <gr...@wonderly.org>.
I agree, doing both would be the best choice of implementation.

Gregg Wonderly

Christopher Dolan wrote:
> Best would be to block on both client and server side.  Client to help performance and server to prevent malicious intent.  Server side would be the minimum implementation.
> 
> Chris
> 
> -----Original Message-----
> From: Patrick Wright [mailto:pdoubleya@gmail.com] 
> Sent: Monday, June 28, 2010 3:17 AM
> To: river-dev@incubator.apache.org
> Subject: Re: ServiceRegistrar
> 
> On Mon, Jun 28, 2010 at 10:11 AM, Tom Hobbs <tv...@googlemail.com> wrote:
>> Does this not hook into the security discussions on internet-visible
>> services?
>>
>> You can satisfy your use case with authorisation levels and just not give
>> "everyone" the authority to register services.  To my mind, this seems
>> cleaner (although not necessarily better or easier), than having two breeds
>> of ServiceRegistrar.
> 
> Just a thought--it seems to me you would want to block this on the
> client side, to prevent DDOS attacks on the LUS if the LUS is visible
> "globally". Block all attempts to register with a locally-generated
> and thrown exception (via smart proxy returned by LUS on lookup).
> 
> 
> Patrick
> 


RE: ServiceRegistrar

Posted by Christopher Dolan <ch...@avid.com>.
Best would be to block on both client and server side.  Client to help performance and server to prevent malicious intent.  Server side would be the minimum implementation.

Chris

-----Original Message-----
From: Patrick Wright [mailto:pdoubleya@gmail.com] 
Sent: Monday, June 28, 2010 3:17 AM
To: river-dev@incubator.apache.org
Subject: Re: ServiceRegistrar

On Mon, Jun 28, 2010 at 10:11 AM, Tom Hobbs <tv...@googlemail.com> wrote:
> Does this not hook into the security discussions on internet-visible
> services?
>
> You can satisfy your use case with authorisation levels and just not give
> "everyone" the authority to register services.  To my mind, this seems
> cleaner (although not necessarily better or easier), than having two breeds
> of ServiceRegistrar.

Just a thought--it seems to me you would want to block this on the
client side, to prevent DDOS attacks on the LUS if the LUS is visible
"globally". Block all attempts to register with a locally-generated
and thrown exception (via smart proxy returned by LUS on lookup).


Patrick

Re: ServiceRegistrar

Posted by Patrick Wright <pd...@gmail.com>.
On Mon, Jun 28, 2010 at 10:11 AM, Tom Hobbs <tv...@googlemail.com> wrote:
> Does this not hook into the security discussions on internet-visible
> services?
>
> You can satisfy your use case with authorisation levels and just not give
> "everyone" the authority to register services.  To my mind, this seems
> cleaner (although not necessarily better or easier), than having two breeds
> of ServiceRegistrar.

Just a thought--it seems to me you would want to block this on the
client side, to prevent DDOS attacks on the LUS if the LUS is visible
"globally". Block all attempts to register with a locally-generated
and thrown exception (via smart proxy returned by LUS on lookup).


Patrick

Re: ServiceRegistrar

Posted by Tom Hobbs <tv...@googlemail.com>.
Does this not hook into the security discussions on internet-visible
services?

You can satisfy your use case with authorisation levels and just not give
"everyone" the authority to register services.  To my mind, this seems
cleaner (although not necessarily better or easier), than having two breeds
of ServiceRegistrar.

Just a thought.

Tom


On Sun, Jun 27, 2010 at 1:29 AM, Peter Firmstone <ji...@zeus.net.au> wrote:

> For a ServiceRegistrar implementation where you don't want to register
> Services (A static ServiceRegistrar used only for lookup) would returning a
> null ServiceRegistration suffice?  Or is this fraught with danger, has
> anyone ever tried it?
>
> Use case:  You've got an internet facing Registrar and you don't want
> external Services to register.
>
> Cheers,
>
> Peter.
>
>
>
>

ServiceRegistrar

Posted by Peter Firmstone <ji...@zeus.net.au>.
For a ServiceRegistrar implementation where you don't want to register 
Services (A static ServiceRegistrar used only for lookup) would 
returning a null ServiceRegistration suffice?  Or is this fraught with 
danger, has anyone ever tried it?

Use case:  You've got an internet facing Registrar and you don't want 
external Services to register.

Cheers,

Peter.




Re: Service API, class visibility, isolation and garbage collection - ClassLoaders

Posted by Peter Firmstone <ji...@zeus.net.au>.
Peter Firmstone wrote:
> We can base Codebase trust on:
>
>   1. Certificates[]  "Who wrote it?"
>   2. CodeSource "Who wrote it and the name of the Codebase?"
Just a minor clarification, a CodeSource object's state, is the URL and 
the signer Certificates[], so it's currently "Who signed it, where it 
comes from and its name", I'd like to change that to "Who signed it, 
what's its name and version"  Lets hope the original developer signs it 
or the people who do sign it can "vet the code" so we can equate 
developers with Certificates[].  I'd like to take location out of the 
equation for systems like Maven and OSGi.

Cheers,

Peter.

Re: Service API, class visibility, isolation and garbage collection - ClassLoaders

Posted by Peter Firmstone <ji...@zeus.net.au>.
Thanks Gregg, much appreciated.

Gregg Wonderly wrote:
> Getting back around to some of these, hopefully no confusion...
Yea, can be difficult to express things using only text communication, 
especially with something so complex.  Replies inline below.

>
> Peter Firmstone wrote:
>> Hi Gregg,
>>
>> Sorry I missed this earlier, have a look at my latest messages, they 
>> might provide some more background to my thoughts.
>>
>> Mike Warres has a good example of when the existing mechanism causes 
>> codebase annotation loss and type conflicts on page 23 of his paper 
>> "Class Loading Issues in Java RMI and Jini Network Technology".
>>
>> https://issues.apache.org/jira/secure/attachment/12413650/Java+Classloader+issues+relating+to+Jini+smli_tr-2006-149.pdf 
>>
>> Because the Service API is loaded from the local file system and 
>> isn't dynamically downloaded, it may not have an annotation, I'm 
>> thinking about creating a new URL scheme, that provides information 
>> about all Jar files, whether local or downloaded dynamically, such as 
>> jar name and version annotation.  This should help people who wish to 
>> provision their codebases.
>
> For me, the important thing to understand about class 
> resolution/loading, is that there are two distinct issues.  First, do 
> you have the correct version of the class somewhere in the class 
> loading system in use, and Second, if the right version or no version 
> is available, do you have a way to go look for a definition that would 
> be the right version to use?
>
> ClassLoaders have historically been the domain of issue #1.  Issue #2 
> has been dealt with in a surprisingly large number of ways.  
> Serialization annotations that MarshalledObject et.al. provide one way 
> to deal with #2.  But we also have later development of things like 
> OSGi, Maven and other packaging systems which include ways to declare 
> or facilitate resolution of missing dependencies.
>
> RMIClassLoaderSPI is the pluggable way to deal with the String 
> annotations on classes.  It can facilitate a wide number of 
> possibilities.  The predominate issues is that it doesn't include an 
> "implementation" indication in concert with the String value, so you 
> don't know how to "delegate" to other mechanisms to make use of that 
> String value in a "varied" way.
>
> It seems to me that if we do something with a new RMIClassLoaderSPI 
> implementation.  My changes add no real value other than facilitating 
> the addition of another implementation that is offered remotely or 
> through some other path.  What we really need is the ability to look 
> at the annotation and use it intelligently to ask a factory mechanism 
> to use it to create a class loader.
>
>> Note I haven't had any thoughts about removing 
>> PreferredClassProvider, but I'm thinking about another ClassLoader 
>> structure, although I'm prone to changing my mind as I struggle to 
>> understand it all.  I haven't got any implementations, yet, still 
>> working it all out.
>
> PreferredClassLoading allows you to fix code that is generally used 
> across an application "suite", by overriding the use of something in 
> the classpath with something you provide in your -dl.jar (or other 
> codebase content) by making it preferred.
Ok, this is something I'm trying to fix using a different approach with 
Classloaders.  If the Application code is not visible to the proxy, the 
proxy can have it's own independent classes, with no class sharing 
between the proxy and application other than platform and API classes.   
I'd like a way to define classes for loading into an application or 
service classloader too, similar to a classpath.  Smart Proxy's can 
utilise their own libraries without conflicting with the application's 
library versions.

This is sort of what I'm thinking, evolved since last post, based on 
comments:

                                      CLASS LOADER VISIBILITY

 _______________________________________________________________________
|                                                                       |
|           Platform & API ClassLoader (incl Dumb Proxy Objects)        |
|----------------|------------------------------------------------------|
|       _________|________________________________                      |
|      |         |        |                       |                     |
|  ServiceUI     |   Smart Proxy        Extended Service API            |
|  ClassLoader   |  (incl ServiceUI)   & Dumb Proxy ClassLoader         |
| (UI that uses  |   ClassLoader's                |                     |
|  Dumb Proxy's) |             ___________________|___________          |
|                |_________   |             |                 |         |
|                |         |  |         ServiceUI        Smart Proxy    |
|                |    Parameter Imp     ClassLoader's    ClassLoader's  |
|                |    ClassLoader's   (for Dumb Proxy's)                |
|                |    (Server side)                                     |
|----------------|------------------------------------------------------|
|                |                                                      |
|          Common Classloader (As Per Dennis' comments)                 |
|       _________|________________________                              |
|      |                                  |                             |
| Service Imp                       Application                         |
| ClassLoader's                     ClassLoader                         |
|                                (incl Parameter Imp classes)           |
|_______________________________________________________________________|

Everything between the two --- lines is downloaded dynamically, cached 
or provisioned.
Dumb Proxy's have no download archives or classes other than those in 
the API,
so can be safely loaded into the Platform API ClassLoader or Extended 
Service API
ClassLoader.   These classloaders will be available via a weak reference 
index.

All classes in child ClassLoaders can see all parent ClassLoaders above 
in the tree, but classes in parent ClassLoaders cannot see the classes 
below them in child ClassLoaders.  For example, classes in the Platform 
& API CL, Common CL are visible to the Application CL classes.

This visibility, between ClassLoader's mapped out above, prevents 
implementations from interfering with each other, they can only 
cooperate between each other using common API classes.  No more worries 
about versioning conflicts etc.  Versions can be specified by 
implementations to allow codebase caching and provisioning to ensure 
that Serialization and implementation compatibility remains between the 
Server and it's Proxy.

This may cause some libraries to become duplicated in memory, however we 
must ensure a particular version is only downloaded once.

Something that has my attention about security is, currently we've based 
proxy security on the ClassLoader.  However when the AccessController 
checks permission, it allows only the permissions common to all 
ProtectionDomains on the Stack (see AccessControlContext).  Permissions 
really should be dynamically granted to ProtectionDomains, not the 
ClassLoader.

A ProtectionDomain, might represent a Principal, or it might represent a 
downloaded codebase, any number of which may exist in a single 
ClassLoader (so long as classes are not duplicated, this should be 
avoided since duplicate classes cannot be loaded into a ClassLoader).

Hence if a number of Services use the same codebases for their smart 
proxy's then that codebases ProtectionDomain will need the required 
Permissions and so will the ProtectionDomain for a Principal in order 
for those Permissions to become effective.  So we can preserve security 
and have multiple Services share the same proxy code.  But to do so we 
must forget about ClassLoader based Permission grants.

We can base Codebase trust on:

   1. Certificates[]  "Who wrote it?"
   2. CodeSource "Who wrote it and the name of the Codebase?"


We can base Principal trust on:

   1. Principals[] "Who are you?"


When a ProtectionDomain is created with the constructor:

public ProtectionDomain(CodeSource codesource,
                        PermissionCollection permissions,
                        ClassLoader classloader,
                        Principal[] principals)

The permissions granted to the ProtectionDomain will be dynamic and the 
current Policy will always be asked prior to the PermissionCollection 
passed into the constructor (Performance Hint: make sure permissions is 
null, use the Policy only)

The Principal[] can be java.security.acl.Group[] objects (Group extends 
Principal), then your free to add and remove Principals to that Group 
and hence the Group's ProtectionDomain, that associated with the 
CodeSource of the Proxy.  A group might represent each type of Service.

ProtectionDomains representing each will be on the stack and only the 
Permissions common to all ProtectionDomains on the stack will be granted.

Some observations:

   1. Codebases should advertise their required Permissions if trust is
      required.
   2. Codebases should be signed if trust is required.
   3. Utility Library Codebases can be released and signed for others to
      "trust" to be utilised in proxy's.  You might not trust unknown
      proxy code, but you might trust the utility library that provides
      trusted functionality for it.

So client Proxy trust is currently:

   1. Download the Proxy codebase.
   2. Unmarshall the Proxy.
   3. Ask the Proxy for the Proxy verifier.
   4. Ask the Server if it trusts the proxy.
   5. Grant trust to the proxy ClassLoader.

We can optionally do this too instead (feel free to correct any poorly 
conceived assumptions):

   1. Download the Proxy codebase (unless cached or downloaded prior)
   2. Record the Permissions required by the CodeSource advertised in
      the jar file.
   3. If Permissions are required, Create a Group and Create a
      ProtectionDomain for that CodeSource, passing the new Group
      (Principal) to the constructor (on first use of the codebase).  A
      Group might be specific a particular Service Interface and may
      already exist.
   4. Unmarshall the Proxy
   5. Check Constraints.
   6. Authenticate the Service if required.
   7. Authenticate the Client if required.
   8. Ask the Proxy for the Proxy Verifier.
   9. Does the Server trust the Proxy?
  10. Add the Service's Principal (or it's Group) to the Group, in the
      ProtectionDomain.
  11. Grant trust
         1. Using  grantCodeSource(CodeSource cs, Principal[] groups,
            Permission[] permissions)
         2. OR grantProtectionDomain(Class cl, Permission[] permissions)
         3. OR grant(Class cl, Principal[] principals, Permission[]
            permissions) - ClassLoader grant.
         4. OR grant(Certificate[] certs, Principal[] principals,
            Permission[] permissions)

Notes:

    * The permissions granted are limited to those declared in the jar file.
    * If the Trust grant is performed using 11.3. then permission grants
      are the same as the current ClassLoader based behaviour, all other
      libraries in with the proxy will be loaded into that ClassLoader
      and also receive those permissions.
    * Permissions granted using 11.4 are granted based on the codebase
      signers (developers) and Principals (groups) and may be granted at
      any time prior.
    * Permissions granted using 11.2 are granted directly to the proxy
      ProtectionDomain and only apply to the proxy's Code source, not
      bundled libraries or other jar archives distributed with the proxy.
    * Permissions granted using 11.1 are granted directly to the
      CodeSource and Principals (groups) and may be applied prior to
      downloading the code source.
    * Other proxy objects from different services, with identical proxy
      CodeSource may share the ProtectionDomain and class files, in this
      case the trust sequence is limited to steps 4 to 10 as the
      CodeSource itself is already trusted, the only thing that remains
      is to verify the proxy and perform authentication if required.

These Dynamic Grants have been implemented in 
DynamicConcurrentPolicyProvider.  Permissions granted to Groups differ 
from current Policy implementations that test Principals for equality 
only, this new Policy implementation also implies true when Principals 
are members of Groups that have been granted Permissions.

It might help to provide a Principal and Group framework implementation 
to make Authentication easier.

So this does actually point to a use for Patrick's suggested Codebase 
Entry?  Yes, for example if many services existed on the internet that 
utilise the same codebase versions, then a client could specify only a 
particular version, to ensure it only downloads one codebase, once for 
all matching instances of a Service.  It might first get the Codebase 
Entry's for a particular Service type, then lookup by each codebase 
version and deal with them in compatible batches.  Waiting for the 
Codebase URL annotation would be too late, filtering would be performed 
at the client rather than by the ServiceRegistrar.

We do need to implement something like RMIClassLoaderSPI, where 
ClassLoaders are created based on the names of jar archives *proxy.jar, 
*ext-api.jar, *ui.jar and *param.jar.  Where versioning is taken into 
consideration and a new URL format is created that allows for the needed 
flexibility.  Then of course class resolution needs to be figured out 
with the new URL annotation.

This may take some time to digest.  Please see the code in:

https://svn.apache.org/repos/asf/incubator/river/jtsk/trunk/src/org/apache/river/

Cheers,

Peter.
> I find this mechanism extremely useful in my service UI client that 
> has the same classes as all my UIs use for Swing and AWT stuff.  If I 
> need additional functionality or to fix something that only the UI of 
> a service needs, then I can make that class preferred and not have to 
> update all of my service UI client instances.  Mobile code solutions 
> are very convenient.
>
> Gregg Wonderly
>
>> Gregg Wonderly wrote:
>>> I have a Jini based application that is a content based router 
>>> system for satellite networks.  There are multiple servers running 
>>> with comms cards, and the ServiceUI needs to see all of them at 
>>> once, because I use transactions to commit data changes to all 
>>> servers.  In this case, one clients ServiceUI must lookup all of the 
>>> services, ignoring itself, and then get the service proxies to work 
>>> with.  All of the services proxies need to share interfaces and data 
>>> classes that are commonly exchanged.
>>>
>>> I didn't need a different kind of classloader tree, I just needed to 
>>> make sure that the parent class loader of the RMIClassLoaderSPI was 
>>> the ClassLoader of the client (The context ClassLoader which is a 
>>> PreferredClassLoader), which was already happening.  All the other 
>>> service instance unmarshalling would in fact make use of the 
>>> PreferredClassLoader, so that versioning could be done by preferring 
>>> classes, for example, and each services preferred classes would be 
>>> honored.
>>>
>>> There is only one -dl.jar involved in the commonality aspects of the 
>>> involved Classes.  I could break the common classes into a separate 
>>> jar, but I have not done that, yet.
>>>
>>> This type of application must be restarted fairly rarely, so class 
>>> compatibility is a very key issue.
>>>
>>> Peter, can you provide a more specific example of when you think the 
>>> structure you are proposing would be valuable, i.e. the existing 
>>> mechanism would break?
>>>
>>> Gregg Wonderly
>>>
>>
>>
>
>



Re: Service API, class visibility, isolation and garbage collection - ClassLoaders

Posted by Gregg Wonderly <ge...@cox.net>.
Getting back around to some of these, hopefully no confusion...

Peter Firmstone wrote:
> Hi Gregg,
> 
> Sorry I missed this earlier, have a look at my latest messages, they 
> might provide some more background to my thoughts.
> 
> Mike Warres has a good example of when the existing mechanism causes 
> codebase annotation loss and type conflicts on page 23 of his paper 
> "Class Loading Issues in Java RMI and Jini Network Technology".
> 
> https://issues.apache.org/jira/secure/attachment/12413650/Java+Classloader+issues+relating+to+Jini+smli_tr-2006-149.pdf 
> 
> Because the Service API is loaded from the local file system and isn't 
> dynamically downloaded, it may not have an annotation, I'm thinking 
> about creating a new URL scheme, that provides information about all Jar 
> files, whether local or downloaded dynamically, such as jar name and 
> version annotation.  This should help people who wish to provision their 
> codebases.

For me, the important thing to understand about class resolution/loading, is 
that there are two distinct issues.  First, do you have the correct version of 
the class somewhere in the class loading system in use, and Second, if the right 
version or no version is available, do you have a way to go look for a 
definition that would be the right version to use?

ClassLoaders have historically been the domain of issue #1.  Issue #2 has been 
dealt with in a surprisingly large number of ways.  Serialization annotations 
that MarshalledObject et.al. provide one way to deal with #2.  But we also have 
later development of things like OSGi, Maven and other packaging systems which 
include ways to declare or facilitate resolution of missing dependencies.

RMIClassLoaderSPI is the pluggable way to deal with the String annotations on 
classes.  It can facilitate a wide number of possibilities.  The predominate 
issues is that it doesn't include an "implementation" indication in concert with 
the String value, so you don't know how to "delegate" to other mechanisms to 
make use of that String value in a "varied" way.

It seems to me that if we do something with a new RMIClassLoaderSPI 
implementation.  My changes add no real value other than facilitating the 
addition of another implementation that is offered remotely or through some 
other path.  What we really need is the ability to look at the annotation and 
use it intelligently to ask a factory mechanism to use it to create a class loader.

> Note I haven't had any thoughts about removing PreferredClassProvider, 
> but I'm thinking about another ClassLoader structure, although I'm prone 
> to changing my mind as I struggle to understand it all.  I haven't got 
> any implementations, yet, still working it all out.

PreferredClassLoading allows you to fix code that is generally used across an 
application "suite", by overriding the use of something in the classpath with 
something you provide in your -dl.jar (or other codebase content) by making it 
preferred.  I find this mechanism extremely useful in my service UI client that 
has the same classes as all my UIs use for Swing and AWT stuff.  If I need 
additional functionality or to fix something that only the UI of a service 
needs, then I can make that class preferred and not have to update all of my 
service UI client instances.  Mobile code solutions are very convenient.

Gregg Wonderly

> Gregg Wonderly wrote:
>> I have a Jini based application that is a content based router system 
>> for satellite networks.  There are multiple servers running with comms 
>> cards, and the ServiceUI needs to see all of them at once, because I 
>> use transactions to commit data changes to all servers.  In this case, 
>> one clients ServiceUI must lookup all of the services, ignoring 
>> itself, and then get the service proxies to work with.  All of the 
>> services proxies need to share interfaces and data classes that are 
>> commonly exchanged.
>>
>> I didn't need a different kind of classloader tree, I just needed to 
>> make sure that the parent class loader of the RMIClassLoaderSPI was 
>> the ClassLoader of the client (The context ClassLoader which is a 
>> PreferredClassLoader), which was already happening.  All the other 
>> service instance unmarshalling would in fact make use of the 
>> PreferredClassLoader, so that versioning could be done by preferring 
>> classes, for example, and each services preferred classes would be 
>> honored.
>>
>> There is only one -dl.jar involved in the commonality aspects of the 
>> involved Classes.  I could break the common classes into a separate 
>> jar, but I have not done that, yet.
>>
>> This type of application must be restarted fairly rarely, so class 
>> compatibility is a very key issue.
>>
>> Peter, can you provide a more specific example of when you think the 
>> structure you are proposing would be valuable, i.e. the existing 
>> mechanism would break?
>>
>> Gregg Wonderly
>>
> 
> 


Re: Service API, class visibility, isolation and garbage collection - ClassLoaders

Posted by Peter Firmstone <ji...@zeus.net.au>.
Hi Gregg,

Sorry I missed this earlier, have a look at my latest messages, they 
might provide some more background to my thoughts.

Mike Warres has a good example of when the existing mechanism causes 
codebase annotation loss and type conflicts on page 23 of his paper 
"Class Loading Issues in Java RMI and Jini Network Technology".

https://issues.apache.org/jira/secure/attachment/12413650/Java+Classloader+issues+relating+to+Jini+smli_tr-2006-149.pdf

Because the Service API is loaded from the local file system and isn't 
dynamically downloaded, it may not have an annotation, I'm thinking 
about creating a new URL scheme, that provides information about all Jar 
files, whether local or downloaded dynamically, such as jar name and 
version annotation.  This should help people who wish to provision their 
codebases.

Note I haven't had any thoughts about removing PreferredClassProvider, 
but I'm thinking about another ClassLoader structure, although I'm prone 
to changing my mind as I struggle to understand it all.  I haven't got 
any implementations, yet, still working it all out.

Gregg Wonderly wrote:
> I have a Jini based application that is a content based router system 
> for satellite networks.  There are multiple servers running with comms 
> cards, and the ServiceUI needs to see all of them at once, because I 
> use transactions to commit data changes to all servers.  In this case, 
> one clients ServiceUI must lookup all of the services, ignoring 
> itself, and then get the service proxies to work with.  All of the 
> services proxies need to share interfaces and data classes that are 
> commonly exchanged.
>
> I didn't need a different kind of classloader tree, I just needed to 
> make sure that the parent class loader of the RMIClassLoaderSPI was 
> the ClassLoader of the client (The context ClassLoader which is a 
> PreferredClassLoader), which was already happening.  All the other 
> service instance unmarshalling would in fact make use of the 
> PreferredClassLoader, so that versioning could be done by preferring 
> classes, for example, and each services preferred classes would be 
> honored.
>
> There is only one -dl.jar involved in the commonality aspects of the 
> involved Classes.  I could break the common classes into a separate 
> jar, but I have not done that, yet.
>
> This type of application must be restarted fairly rarely, so class 
> compatibility is a very key issue.
>
> Peter, can you provide a more specific example of when you think the 
> structure you are proposing would be valuable, i.e. the existing 
> mechanism would break?
>
> Gregg Wonderly
>


Re: Service API, class visibility, isolation and garbage collection - ClassLoaders

Posted by Gregg Wonderly <gr...@wonderly.org>.
I have a Jini based application that is a content based router system for 
satellite networks.  There are multiple servers running with comms cards, and 
the ServiceUI needs to see all of them at once, because I use transactions to 
commit data changes to all servers.  In this case, one clients ServiceUI must 
lookup all of the services, ignoring itself, and then get the service proxies to 
work with.  All of the services proxies need to share interfaces and data 
classes that are commonly exchanged.

I didn't need a different kind of classloader tree, I just needed to make sure 
that the parent class loader of the RMIClassLoaderSPI was the ClassLoader of the 
client (The context ClassLoader which is a PreferredClassLoader), which was 
already happening.  All the other service instance unmarshalling would in fact 
make use of the PreferredClassLoader, so that versioning could be done by 
preferring classes, for example, and each services preferred classes would be 
honored.

There is only one -dl.jar involved in the commonality aspects of the involved 
Classes.  I could break the common classes into a separate jar, but I have not 
done that, yet.

This type of application must be restarted fairly rarely, so class compatibility 
is a very key issue.

Peter, can you provide a more specific example of when you think the structure 
you are proposing would be valuable, i.e. the existing mechanism would break?

Gregg Wonderly

Dennis Reedy wrote:
> Peter,
> 
> No worries. Although I think there is still a misunderstanding on how the class loader structure works, its water under the bridge - lets move on.
> 
> What I cant figure out is if you want to share classes across downloaded proxies, why the classes are not part of the API jar the client has in it's classpath. This allows downloaded proxies access to these classes, since the classloader they are loaded with delegates to the classloader that the API jar has been loaded with.
> 
> It seems you are creating an edge condition where an implementor would like downloaded proxies to share a class across implementations, but in order to do that that class needs to be injected into a parent class loader. Do I have this right?
> 
> IMO, in this scenario, I would advise that the class(es) in question should be added to the API jar.
> 
>  AppCL
> 
>    
> On May 26, 2010, at 727AM, Peter Firmstone wrote:
> 
>> Hi Dennis,
>>
>> Looking back at my earlier reply when you presented the ClassLoader structure for Rio, I was unintentionally insensitive.
>>
>> I didn't mean to pull it apart, probably not the right approach, Rio is a success in it's own right!
>>
>> What I should have said and I may not have communicated too well is that I'm introducing a way for Service Proxy's to utilise ClassLoader visibility for maximum API class sharing.  It is a new feature, to give Service implementers the power to share their Service API's, with as much local JVM visibility as the Jini Platform Service API's have.
>>
>> As I pointed out there is a compromise, that Service API classes cannot be garbage collected.  I think that if this can be well managed, using a Permission, then it should not affect uptime for critical applications.
>>
>> With great power comes great responsibility... yada yada yada.
>>
>> Cheers,
>>
>> Peter.
>>
>> Peter Firmstone wrote:
>>> Peter Firmstone wrote:
>>>> IDENTICAL TO ANOTHER MESSAGE IN THREAD: Re: Maven repository Entry was Re: Codebase service?
>>>>
>>>> Note: A permission will be required to allow a proxy to introduce new Service API during unmarshalling to prevent against denial of service attacks.
>>> However in the absence of this permission, the additional ServiceAPI jar could be downloaded into the proxy's own ClassLoader, that would require a ClassLoader even for a dumb proxy with an interface you didn't want to load into your Service API space.  This would enable unmarshalling of that Proxy.  If you, at a later point decided to load that interface into your Service API space, I think you still wouldn't be able to interact with this particular proxy using it, since the interface class identity would be different.
>>>
>>> Denial of service here means unfairly growing a JVM's use of non garbage collectable classes.  Any ideas how to control download proxy memory consumption.
>>>> Hi Dennis,
>>>>
>>>> It sounds like you remain unconvinced or don't have a need to use common
>>>> interfaces for your service proxy's?
>>>>
>>>> So I guess it's a tread lightly approach, make the feature available to
>>>> those that want common Service API (The same interface instance for all
>>>> proxy's implementing that interface, so they can be used in collections
>>>> or batch operations), for maximum sharing of proxy's with differing
>>>> implementations, but let those that don't want to publish their API
>>>> continue doing what they usually do.  A configuration parameter should
>>>> be able to set the desired behaviour.
>>>>
>>>> The approach I've taken is a simple approach to a complex problem,
>>>> alternative approaches leave the complexity in the hands of the
>>>> implementer, my approach will enable them to practically ignore it.
>>>>
>>>> Before you write it off though, to answer your earlier question, I'll
>>>> further explain the ClassLoader structure between multiple nodes.
>>>>
>>>>                   CLIENT NODE
>>>> ________________________________________________
>>>> |                                                |
>>>> |             System                             |
>>>> |           ClassLoader                          |
>>>> |                |                               |
>>>> |            Extension                           |
>>>> |           ClassLoader                          |
>>>> |                |                               |
>>>> |          Jini Platform &                       |
>>>> |           Service API                          |
>>>> |           ClassLoader                          |
>>>> |                |                               |
>>>> |       _________|___                            |
>>>> |      |             |                           |
>>>> | Application    Smart Proxy                     |
>>>> | ClassLoader    ClassLoader's                   |
>>>> |________________________________________________|
>>>>
>>>>
>>>>                  SERVICE NODE
>>>> ________________________________________________
>>>> |                                                |
>>>> |             System                             |
>>>> |           ClassLoader                          |
>>>> |                |                               |
>>>> |            Extension                           |
>>>> |           ClassLoader                          |
>>>> |                |                               |
>>>> |          Jini Platform &                       |
>>>> |           Service API                          |
>>>> |           ClassLoader                          |
>>>> |                |                               |
>>>> |       _________|_____________________          |
>>>> |      |             |                 |         |
>>>> | Service Imp    Smart Proxy      Parameter Impl |
>>>> | ClassLoader    ClassLoader's    ClassLoader's  |
>>>> |________________________________________________|
>>>>
>>>>
>>>> All Proxy and Service implementations are free to vary at will, proxy
>>>> instances can be shared in collections or iterative operations based on
>>>> common Service API supertype's  All Proxy's and Services are isolated in
>>>> their own Domain, the only way to communicate externally is by using
>>>> interfaces and classes in upper level ClassLoaders, they can utilise as
>>>> many third party libraries jar archives as they need, these will all be
>>>> loaded into a single ClassLoader unique to that Service or Proxy's
>>>> Codebase and Principles.  The Service or Proxy's namespace will be
>>>> totally separate from Application or other Proxy implementation's,
>>>> except in the case where sharing is permitted for identical
>>>> implementations by the implementation developer.
>>>>
>>>> Service API should be carefully considered and designed, it forms the
>>>> basis of network Dependency Injection, you can discover ANY Service
>>>> implementation variant using the same Service API.
>>>>
>>>> The Service API may include other Service API or Java platform classes.
>>>>
>>>> public interface SimpleBookService {
>>>>
>>>> public Book get( Library lib, String name);
>>>>
>>>> }
>>>>
>>>> In the SimpleBookService above, given a Library and String name of a
>>>> Book, a Book instance is returned by the proxy.
>>>>
>>>> The contents of simpleBookService-api.jar:
>>>>
>>>> SimpleBookService.class
>>>> Book.class
>>>> Library.class
>>>>
>>>> Let's say a client has extended the Library, with a class called
>>>> PrivateLibrary, this class is an implementation class by the client,
>>>> that the Service knows nothing about, the Service only uses the Library
>>>> API, but it needs the PrivateLibrary.class
>>>>
>>>> The client makes an archive containing the PrivateLibrary.class publicly
>>>> available in an archive called privateLibrary-param.jar.  This archive
>>>> depends on simpleBookService-api.jar The jar URL is marshalled with the
>>>> class when the parameters are sent back to the service.  When it gets to
>>>> the service implementation, privateLibrary-param.jar is given it's own
>>>> ClassLoader and ProtectionDomain and isn't given any Permissions.  It is
>>>> used by a SimpleBookService implementation to decide which Book to
>>>> return to the client, after which, it's garbage collected, eventually if
>>>> PrivateLibrary isn't used again its ClassLoader is garbage collected too.
>>>>
>>>> Each SimpleBookService proxy implementation will have their own
>>>> ClassLoader namespace, but Client Application classes can still use any
>>>> Service implementation or as many Service implementations as it can
>>>> handle at the same time, all the while treating them as the same Type.
>>>>
>>>> One SimpleBookService implementation proxy, contains its own
>>>> implementation of Book, and while the client is reading the book, it
>>>> remains available from the proxy ClassLoader via the Service API Book
>>>> interface, when finished reading the book, the proxy, book and
>>>> ClassLoader can be garbage collected.  Tomorrow, the client might read a
>>>> book from another SimpleBookService
>>>>
>>>> Most Service API will be relatively small bytecodes as most will be
>>>> abstract or have simple implementations, the fact they're not garbage
>>>> collected, doesn't matter much if the function of the node doesn't
>>>> change, the API will remain limited to the subset in use, by the node.
>>>>
>>>> Note that Jini Platform service implementations like Reggie, Outrigger
>>>> etc, will exist in Service Impl ClassLoaders and Smart Proxy
>>>> ClassLoaders, only the api will be in the Jini Platform ClassLoader.
>>>>
>>>> Think of it as an expandable platform, everything is shared using
>>>> implementations of Service API classes.
>>>>
>>>> It's actually a good policy to be liberal with interfaces when building
>>>> the Service API classes, even with parameters and return types.  Since
>>>> extending interfaces is relatively straight forward, you new interfaces
>>>> will be discovered by older client software as the old interface while
>>>> new implementation code discovers the new interface of your service.
>>>> Older nodes will load your new interface classes into the Service API
>>>> space when your new proxy versions are unmarshalled. That's why it's
>>>> important to maintain backward compatibility in the Service API space.
>>>>
>>>> So best practise would be to create an experimental djinn group until
>>>> your interfaces are stabilised and be prepared to restart your
>>>> experimental group on a regular basis.
>>>>
>>>> I have thought about using OSGi for Service API classes to be served up
>>>> so they can be garbage collected, this might work for serialization too
>>>> using the context ClassLoader.  I have also thought about using
>>>> ClassLoader Tree's using bytecode dependency analysis as per Tim
>>>> Blackman's research.  These things start to get very complicated, just
>>>> to be able to flush the Service API classes.  Wouldn't it just be better
>>>> to use mutiple services that are load balanced, enabling the jvm to be
>>>> restarted if we want to?
>>>>
>>>> There are other ways to make the Service API classes garbage
>>>> collectable, such as having a tier filled with Service API ClassLoaders
>>>> where each Service and Proxy lives in a child ClassLoader in the tree,
>>>> however this presents the problem of what if an application wants to use
>>>> many Service API's or a combination, the different Service API classes
>>>> couldn't see each other from separate ClassLoaders.
>>>>
>>>> Something to consider, best regards,
>>>>
>>>> Peter.
>>>>
>>>> Dennis Reedy wrote:
>>>>> On May 25, 2010, at 710PM, Peter Firmstone wrote:
>>>>>
>>>>>
>>>>>> This is a good question, which gets to the heart of the Jini's pattern.
>>>>>>
>>>>>> I think the proposed ClassLoader structure will benefit Rio, by enabling increased API commonality and class sharing among Services and their clients.
>>>>>>
>>>>>> You can get around having to shutdown your jvm if you manage evolution of your API interfaces correctly, set up a separate testing Registrar, to keep new API interfaces out of your deployment, until they have stabilised.
>>>>>>    
>>>>> Right now the JVM doesnt need to be shut down at all, services can be loaded with different versions, unloaded, etc ... I think you're making assumptions here.
>>>>>  
>>>>>> Classes, once loaded into a ClassLoader, cannot be garbage collected, but if your API classes don't change there is no problem, when was the last time ServiceRegistrar changed it's public API?   Unlike Jini's platform classes which are set in stone, new API classes can be introduced into older environments.
>>>>>>    
>>>>> Right, which is why service implementations get loaded into their own class loader. You define the 'platform' as whatever that needs to be for your case. For Rio it includes requisite bootstrapping and infrastructure technology. For River it most likely just includes the River 'platform', or nothing at all.
>>>>> Consider ServiceStarter and the class loader created from that bootstrapping process. Please explain what is missing from that approach? Each service has it's own security policy. Why does this need to change? What and how does your approach improve on? To my eyes it seems overly complicated.
>>>>>
>>>>>
>>>>>> Lets take Jini Platform services as an example, in Rio's ClassLoader tree below, the Interfaces for the Platform services exist in the CommonClassLoader, all classes in the CommonClassLoader are visible to any class in any child ClassLoader below in the tree.
>>>>>>
>>>>>> Platform services can be shared freely among all child ClassLoaders.
>>>>>>
>>>>>> Now take Service-1CL and Service-2CL, lets imagine for a moment that these two services both provide the same service, from different or the same node, it doesn't matter, let's imagine now another node with the same ClassLoader tree structure, which consumes these services.
>>>>>>
>>>>>> These services have their service interfaces bundled with their CodeSources, both on the client and at the Service, lets say that Service-2CL provides the same service, but has a different implementation.  Now there's a client service that consumes these services, performs an operation then discards the service.
>>>>>>
>>>>>> Now which common API do the two service proxy's share?
>>>>>>    
>>>>> Common API? The service proxies dont share anything. They are each loaded from an implementation of RMIClassLoaderApi
>>>>>  
>>>>>> This forces you to load both proxy's into the same ClassLoader, making their implementations visible to each other and the client.
>>>>>>    
>>>>> Not so sure about that Peter.
>>>>>
>>>>>
>>>>>> By separating the API into, in your case the CommonClassLoader,
>>>>>>    
>>>>> APIs are not added to the CommonClassLoader, and I would argue that it should not happen. You generally do not want to add classes into a class loader that does not get GC'd.
>>>>>
>>>>>
>>>>>> each with their own ProtectionDomains, all Services and clients in that node, share the same API classes and can be isolated in their own ClassLoader's and can have different implementations but share the same common API types.
>>>>>>
>>>>>> The client service-param.jar is for clients who create new implementations / extend parameters in API methods, the Service server node will require these classes to unmarshall the parameters.  Client parameter classes will never be granted permissions.
>>>>>>
>>>>>> I'll make up some separate ClassLoader tree diagrams showing the client node, the service node and the relationships between remote ClassLoaders.
>>>>>>    
>>>>>
>>>>>
>>>>>> Peter.
>>>>>>
>>>>>> Dennis Reedy wrote:
>>>>>>  
>>>>>>> If I understand correctly I think this is the crux of the issue. I dont understand why you need to load all API classes with the same class loader. FWIW, in Rio we handle the loading (and unloading) of services with the following structure (http://www.rio-project.org/apidocs/org/rioproject/boot/package-summary.html#package_description): 
>>>>>>>                 AppCL
>>>>>>>                   |
>>>>>>>           CommonClassLoader (http:// URLs of common JARs)
>>>>>>>                   +
>>>>>>>                   |
>>>>>>>                   +
>>>>>>>           +-------+-------+----...---+
>>>>>>>           |               |          |
>>>>>>>       Service-1CL   Service-2CL  Service-nCL
>>>>>>>       AppCL - 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
>>>>>>> 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.
>>>>>>>
>>>>>>> Service-nCL - Contains the service specific implementation classes.
>>>>>>> Classpath: serviceImpl.jar
>>>>>>> Codebase: "serviceX-dl.jar rio-dl.jar jsk-lib-dl.jar"
>>>>>>>
>>>>>>> Certainly not as sophisticated as OSGi (or what you are targeting), but it meets the requirements of allowing multiple service versions, applying security context per class loader using the same approach as ActivateWrapper, and allows the JVM to stay running.        
>>>>>
>>>>>  
>>>>
>>>>
>>>
> 
> 


Re: Service API, class visibility, isolation and garbage collection - ClassLoaders

Posted by Peter Firmstone <ji...@zeus.net.au>.
Dennis Reedy wrote:
> Peter,
>
> No worries. Although I think there is still a misunderstanding on how the class loader structure works, 

Ok, I think I see it now, your ClassLoader structure represents your 
container.  Containers are free to come and go in Rio during the life of 
the application?

If I've got that correct, this is very useful.

I wasn't thinking about containers, only a bare metal JVM.

What you have could be very useful to me.


> its water under the bridge - lets move on.
>
> What I cant figure out is if you want to share classes across downloaded proxies, why the classes are not part of the API jar the client has in it's classpath. This allows downloaded proxies access to these classes, since the classloader they are loaded with delegates to the classloader that the API jar has been loaded with.
>   

Thinking about dynamic application assembly, not all the API is known at 
compile time, it has to be discovered later.

> It seems you are creating an edge condition where an implementor would like downloaded proxies to share a class across implementations, but in order to do that that class needs to be injected into a parent class loader. Do I have this right?
>   

Yes.

> IMO, in this scenario, I would advise that the class(es) in question should be added to the API jar.
>   
>  AppCL
>   
Yes agreed, I just want to delay it until after startup, not known at 
compile time.

I think what I have as ServiceImpCL and SmartProxyCL and ParamterImpCL 
all map quite well to your Service-nCL'

N.B. I'm not a Programmer, so you'll have to bear with me I'm afraid, 
while I'm probably out of my depth, I couldn't let River die, I don't 
know why programmers can't see Jini's strengths.

In my job we undertake seemingly impossible tasks, Construction & Heavy 
(5000T) Machinery Overhauls we always end up figuring it out however.

Thanks Peter.
>    
> On May 26, 2010, at 727AM, Peter Firmstone wrote:
>
>   
>> Hi Dennis,
>>
>> Looking back at my earlier reply when you presented the ClassLoader structure for Rio, I was unintentionally insensitive.
>>
>> I didn't mean to pull it apart, probably not the right approach, Rio is a success in it's own right!
>>
>> What I should have said and I may not have communicated too well is that I'm introducing a way for Service Proxy's to utilise ClassLoader visibility for maximum API class sharing.  It is a new feature, to give Service implementers the power to share their Service API's, with as much local JVM visibility as the Jini Platform Service API's have.
>>
>> As I pointed out there is a compromise, that Service API classes cannot be garbage collected.  I think that if this can be well managed, using a Permission, then it should not affect uptime for critical applications.
>>
>> With great power comes great responsibility... yada yada yada.
>>
>> Cheers,
>>
>> Peter.
>>
>> Peter Firmstone wrote:
>>     
>>> Peter Firmstone wrote:
>>>       
>>>> IDENTICAL TO ANOTHER MESSAGE IN THREAD: Re: Maven repository Entry was Re: Codebase service?
>>>>
>>>> Note: A permission will be required to allow a proxy to introduce new Service API during unmarshalling to prevent against denial of service attacks.
>>>>         
>>> However in the absence of this permission, the additional ServiceAPI jar could be downloaded into the proxy's own ClassLoader, that would require a ClassLoader even for a dumb proxy with an interface you didn't want to load into your Service API space.  This would enable unmarshalling of that Proxy.  If you, at a later point decided to load that interface into your Service API space, I think you still wouldn't be able to interact with this particular proxy using it, since the interface class identity would be different.
>>>
>>> Denial of service here means unfairly growing a JVM's use of non garbage collectable classes.  Any ideas how to control download proxy memory consumption.
>>>       
>>>> Hi Dennis,
>>>>
>>>> It sounds like you remain unconvinced or don't have a need to use common
>>>> interfaces for your service proxy's?
>>>>
>>>> So I guess it's a tread lightly approach, make the feature available to
>>>> those that want common Service API (The same interface instance for all
>>>> proxy's implementing that interface, so they can be used in collections
>>>> or batch operations), for maximum sharing of proxy's with differing
>>>> implementations, but let those that don't want to publish their API
>>>> continue doing what they usually do.  A configuration parameter should
>>>> be able to set the desired behaviour.
>>>>
>>>> The approach I've taken is a simple approach to a complex problem,
>>>> alternative approaches leave the complexity in the hands of the
>>>> implementer, my approach will enable them to practically ignore it.
>>>>
>>>> Before you write it off though, to answer your earlier question, I'll
>>>> further explain the ClassLoader structure between multiple nodes.
>>>>
>>>>                   CLIENT NODE
>>>> ________________________________________________
>>>> |                                                |
>>>> |             System                             |
>>>> |           ClassLoader                          |
>>>> |                |                               |
>>>> |            Extension                           |
>>>> |           ClassLoader                          |
>>>> |                |                               |
>>>> |          Jini Platform &                       |
>>>> |           Service API                          |
>>>> |           ClassLoader                          |
>>>> |                |                               |
>>>> |       _________|___                            |
>>>> |      |             |                           |
>>>> | Application    Smart Proxy                     |
>>>> | ClassLoader    ClassLoader's                   |
>>>> |________________________________________________|
>>>>
>>>>
>>>>                  SERVICE NODE
>>>> ________________________________________________
>>>> |                                                |
>>>> |             System                             |
>>>> |           ClassLoader                          |
>>>> |                |                               |
>>>> |            Extension                           |
>>>> |           ClassLoader                          |
>>>> |                |                               |
>>>> |          Jini Platform &                       |
>>>> |           Service API                          |
>>>> |           ClassLoader                          |
>>>> |                |                               |
>>>> |       _________|_____________________          |
>>>> |      |             |                 |         |
>>>> | Service Imp    Smart Proxy      Parameter Impl |
>>>> | ClassLoader    ClassLoader's    ClassLoader's  |
>>>> |________________________________________________|
>>>>
>>>>
>>>> All Proxy and Service implementations are free to vary at will, proxy
>>>> instances can be shared in collections or iterative operations based on
>>>> common Service API supertype's  All Proxy's and Services are isolated in
>>>> their own Domain, the only way to communicate externally is by using
>>>> interfaces and classes in upper level ClassLoaders, they can utilise as
>>>> many third party libraries jar archives as they need, these will all be
>>>> loaded into a single ClassLoader unique to that Service or Proxy's
>>>> Codebase and Principles.  The Service or Proxy's namespace will be
>>>> totally separate from Application or other Proxy implementation's,
>>>> except in the case where sharing is permitted for identical
>>>> implementations by the implementation developer.
>>>>
>>>> Service API should be carefully considered and designed, it forms the
>>>> basis of network Dependency Injection, you can discover ANY Service
>>>> implementation variant using the same Service API.
>>>>
>>>> The Service API may include other Service API or Java platform classes.
>>>>
>>>> public interface SimpleBookService {
>>>>
>>>> public Book get( Library lib, String name);
>>>>
>>>> }
>>>>
>>>> In the SimpleBookService above, given a Library and String name of a
>>>> Book, a Book instance is returned by the proxy.
>>>>
>>>> The contents of simpleBookService-api.jar:
>>>>
>>>> SimpleBookService.class
>>>> Book.class
>>>> Library.class
>>>>
>>>> Let's say a client has extended the Library, with a class called
>>>> PrivateLibrary, this class is an implementation class by the client,
>>>> that the Service knows nothing about, the Service only uses the Library
>>>> API, but it needs the PrivateLibrary.class
>>>>
>>>> The client makes an archive containing the PrivateLibrary.class publicly
>>>> available in an archive called privateLibrary-param.jar.  This archive
>>>> depends on simpleBookService-api.jar The jar URL is marshalled with the
>>>> class when the parameters are sent back to the service.  When it gets to
>>>> the service implementation, privateLibrary-param.jar is given it's own
>>>> ClassLoader and ProtectionDomain and isn't given any Permissions.  It is
>>>> used by a SimpleBookService implementation to decide which Book to
>>>> return to the client, after which, it's garbage collected, eventually if
>>>> PrivateLibrary isn't used again its ClassLoader is garbage collected too.
>>>>
>>>> Each SimpleBookService proxy implementation will have their own
>>>> ClassLoader namespace, but Client Application classes can still use any
>>>> Service implementation or as many Service implementations as it can
>>>> handle at the same time, all the while treating them as the same Type.
>>>>
>>>> One SimpleBookService implementation proxy, contains its own
>>>> implementation of Book, and while the client is reading the book, it
>>>> remains available from the proxy ClassLoader via the Service API Book
>>>> interface, when finished reading the book, the proxy, book and
>>>> ClassLoader can be garbage collected.  Tomorrow, the client might read a
>>>> book from another SimpleBookService
>>>>
>>>> Most Service API will be relatively small bytecodes as most will be
>>>> abstract or have simple implementations, the fact they're not garbage
>>>> collected, doesn't matter much if the function of the node doesn't
>>>> change, the API will remain limited to the subset in use, by the node.
>>>>
>>>> Note that Jini Platform service implementations like Reggie, Outrigger
>>>> etc, will exist in Service Impl ClassLoaders and Smart Proxy
>>>> ClassLoaders, only the api will be in the Jini Platform ClassLoader.
>>>>
>>>> Think of it as an expandable platform, everything is shared using
>>>> implementations of Service API classes.
>>>>
>>>> It's actually a good policy to be liberal with interfaces when building
>>>> the Service API classes, even with parameters and return types.  Since
>>>> extending interfaces is relatively straight forward, you new interfaces
>>>> will be discovered by older client software as the old interface while
>>>> new implementation code discovers the new interface of your service.
>>>> Older nodes will load your new interface classes into the Service API
>>>> space when your new proxy versions are unmarshalled. That's why it's
>>>> important to maintain backward compatibility in the Service API space.
>>>>
>>>> So best practise would be to create an experimental djinn group until
>>>> your interfaces are stabilised and be prepared to restart your
>>>> experimental group on a regular basis.
>>>>
>>>> I have thought about using OSGi for Service API classes to be served up
>>>> so they can be garbage collected, this might work for serialization too
>>>> using the context ClassLoader.  I have also thought about using
>>>> ClassLoader Tree's using bytecode dependency analysis as per Tim
>>>> Blackman's research.  These things start to get very complicated, just
>>>> to be able to flush the Service API classes.  Wouldn't it just be better
>>>> to use mutiple services that are load balanced, enabling the jvm to be
>>>> restarted if we want to?
>>>>
>>>> There are other ways to make the Service API classes garbage
>>>> collectable, such as having a tier filled with Service API ClassLoaders
>>>> where each Service and Proxy lives in a child ClassLoader in the tree,
>>>> however this presents the problem of what if an application wants to use
>>>> many Service API's or a combination, the different Service API classes
>>>> couldn't see each other from separate ClassLoaders.
>>>>
>>>> Something to consider, best regards,
>>>>
>>>> Peter.
>>>>
>>>> Dennis Reedy wrote:
>>>>         
>>>>> On May 25, 2010, at 710PM, Peter Firmstone wrote:
>>>>>
>>>>>
>>>>>           
>>>>>> This is a good question, which gets to the heart of the Jini's pattern.
>>>>>>
>>>>>> I think the proposed ClassLoader structure will benefit Rio, by enabling increased API commonality and class sharing among Services and their clients.
>>>>>>
>>>>>> You can get around having to shutdown your jvm if you manage evolution of your API interfaces correctly, set up a separate testing Registrar, to keep new API interfaces out of your deployment, until they have stabilised.
>>>>>>    
>>>>>>             
>>>>> Right now the JVM doesnt need to be shut down at all, services can be loaded with different versions, unloaded, etc ... I think you're making assumptions here.
>>>>>  
>>>>>           
>>>>>> Classes, once loaded into a ClassLoader, cannot be garbage collected, but if your API classes don't change there is no problem, when was the last time ServiceRegistrar changed it's public API?   Unlike Jini's platform classes which are set in stone, new API classes can be introduced into older environments.
>>>>>>    
>>>>>>             
>>>>> Right, which is why service implementations get loaded into their own class loader. You define the 'platform' as whatever that needs to be for your case. For Rio it includes requisite bootstrapping and infrastructure technology. For River it most likely just includes the River 'platform', or nothing at all.
>>>>> Consider ServiceStarter and the class loader created from that bootstrapping process. Please explain what is missing from that approach? Each service has it's own security policy. Why does this need to change? What and how does your approach improve on? To my eyes it seems overly complicated.
>>>>>
>>>>>
>>>>>           
>>>>>> Lets take Jini Platform services as an example, in Rio's ClassLoader tree below, the Interfaces for the Platform services exist in the CommonClassLoader, all classes in the CommonClassLoader are visible to any class in any child ClassLoader below in the tree.
>>>>>>
>>>>>> Platform services can be shared freely among all child ClassLoaders.
>>>>>>
>>>>>> Now take Service-1CL and Service-2CL, lets imagine for a moment that these two services both provide the same service, from different or the same node, it doesn't matter, let's imagine now another node with the same ClassLoader tree structure, which consumes these services.
>>>>>>
>>>>>> These services have their service interfaces bundled with their CodeSources, both on the client and at the Service, lets say that Service-2CL provides the same service, but has a different implementation.  Now there's a client service that consumes these services, performs an operation then discards the service.
>>>>>>
>>>>>> Now which common API do the two service proxy's share?
>>>>>>    
>>>>>>             
>>>>> Common API? The service proxies dont share anything. They are each loaded from an implementation of RMIClassLoaderApi
>>>>>  
>>>>>           
>>>>>> This forces you to load both proxy's into the same ClassLoader, making their implementations visible to each other and the client.
>>>>>>    
>>>>>>             
>>>>> Not so sure about that Peter.
>>>>>
>>>>>
>>>>>           
>>>>>> By separating the API into, in your case the CommonClassLoader,
>>>>>>    
>>>>>>             
>>>>> APIs are not added to the CommonClassLoader, and I would argue that it should not happen. You generally do not want to add classes into a class loader that does not get GC'd.
>>>>>
>>>>>
>>>>>           
>>>>>> each with their own ProtectionDomains, all Services and clients in that node, share the same API classes and can be isolated in their own ClassLoader's and can have different implementations but share the same common API types.
>>>>>>
>>>>>> The client service-param.jar is for clients who create new implementations / extend parameters in API methods, the Service server node will require these classes to unmarshall the parameters.  Client parameter classes will never be granted permissions.
>>>>>>
>>>>>> I'll make up some separate ClassLoader tree diagrams showing the client node, the service node and the relationships between remote ClassLoaders.
>>>>>>    
>>>>>>             
>>>>>
>>>>>           
>>>>>> Peter.
>>>>>>
>>>>>> Dennis Reedy wrote:
>>>>>>  
>>>>>>             
>>>>>>> If I understand correctly I think this is the crux of the issue. I dont understand why you need to load all API classes with the same class loader. FWIW, in Rio we handle the loading (and unloading) of services with the following structure (http://www.rio-project.org/apidocs/org/rioproject/boot/package-summary.html#package_description): 
>>>>>>>                 AppCL
>>>>>>>                   |
>>>>>>>           CommonClassLoader (http:// URLs of common JARs)
>>>>>>>                   +
>>>>>>>                   |
>>>>>>>                   +
>>>>>>>           +-------+-------+----...---+
>>>>>>>           |               |          |
>>>>>>>       Service-1CL   Service-2CL  Service-nCL
>>>>>>>       AppCL - 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
>>>>>>> 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.
>>>>>>>
>>>>>>> Service-nCL - Contains the service specific implementation classes.
>>>>>>> Classpath: serviceImpl.jar
>>>>>>> Codebase: "serviceX-dl.jar rio-dl.jar jsk-lib-dl.jar"
>>>>>>>
>>>>>>> Certainly not as sophisticated as OSGi (or what you are targeting), but it meets the requirements of allowing multiple service versions, applying security context per class loader using the same approach as ActivateWrapper, and allows the JVM to stay running.        
>>>>>>>               
>>>>>  
>>>>>           
>>>>
>>>>         
>>>       
>
>
>   


Re: Service API, class visibility, isolation and garbage collection - ClassLoaders

Posted by Peter Firmstone <ji...@zeus.net.au>.
Dennis Reedy wrote:
> Peter,
>
> No worries. Although I think there is still a misunderstanding on how the class loader structure works, 

Ok, I think I see it now, your ClassLoader structure represents your 
container.  Containers are free to come and go in Rio during the life of 
the application?

If I've got that correct, this is very useful.

I wasn't thinking about containers, only a bare metal JVM.

What you have could be very useful to me.


> its water under the bridge - lets move on.
>
> What I cant figure out is if you want to share classes across downloaded proxies, why the classes are not part of the API jar the client has in it's classpath. This allows downloaded proxies access to these classes, since the classloader they are loaded with delegates to the classloader that the API jar has been loaded with.
>   

Thinking about dynamic application assembly, not all the API is known at 
compile time, it has to be discovered later.

> It seems you are creating an edge condition where an implementor would like downloaded proxies to share a class across implementations, but in order to do that that class needs to be injected into a parent class loader. Do I have this right?
>   

Yes.

> IMO, in this scenario, I would advise that the class(es) in question should be added to the API jar.
>   
>  AppCL
>   
Yes agreed, I just want to delay it until after startup, not known at 
compile time.

I think what I have as ServiceImpCL and SmartProxyCL and ParamterImpCL 
all map quite well to your Service-nCL'

N.B. I'm not a Programmer, so you'll have to bear with me I'm afraid, 
while I'm probably out of my depth, I couldn't let River die, I don't 
know why programmers can't see Jini's strengths.

In my job we undertake seemingly impossible tasks, Construction & Heavy 
(5000T) Machinery Overhauls we always end up figuring it out however.

Thanks Peter.
>    
> On May 26, 2010, at 727AM, Peter Firmstone wrote:
>
>   
>> Hi Dennis,
>>
>> Looking back at my earlier reply when you presented the ClassLoader structure for Rio, I was unintentionally insensitive.
>>
>> I didn't mean to pull it apart, probably not the right approach, Rio is a success in it's own right!
>>
>> What I should have said and I may not have communicated too well is that I'm introducing a way for Service Proxy's to utilise ClassLoader visibility for maximum API class sharing.  It is a new feature, to give Service implementers the power to share their Service API's, with as much local JVM visibility as the Jini Platform Service API's have.
>>
>> As I pointed out there is a compromise, that Service API classes cannot be garbage collected.  I think that if this can be well managed, using a Permission, then it should not affect uptime for critical applications.
>>
>> With great power comes great responsibility... yada yada yada.
>>
>> Cheers,
>>
>> Peter.
>>
>> Peter Firmstone wrote:
>>     
>>> Peter Firmstone wrote:
>>>       
>>>> IDENTICAL TO ANOTHER MESSAGE IN THREAD: Re: Maven repository Entry was Re: Codebase service?
>>>>
>>>> Note: A permission will be required to allow a proxy to introduce new Service API during unmarshalling to prevent against denial of service attacks.
>>>>         
>>> However in the absence of this permission, the additional ServiceAPI jar could be downloaded into the proxy's own ClassLoader, that would require a ClassLoader even for a dumb proxy with an interface you didn't want to load into your Service API space.  This would enable unmarshalling of that Proxy.  If you, at a later point decided to load that interface into your Service API space, I think you still wouldn't be able to interact with this particular proxy using it, since the interface class identity would be different.
>>>
>>> Denial of service here means unfairly growing a JVM's use of non garbage collectable classes.  Any ideas how to control download proxy memory consumption.
>>>       
>>>> Hi Dennis,
>>>>
>>>> It sounds like you remain unconvinced or don't have a need to use common
>>>> interfaces for your service proxy's?
>>>>
>>>> So I guess it's a tread lightly approach, make the feature available to
>>>> those that want common Service API (The same interface instance for all
>>>> proxy's implementing that interface, so they can be used in collections
>>>> or batch operations), for maximum sharing of proxy's with differing
>>>> implementations, but let those that don't want to publish their API
>>>> continue doing what they usually do.  A configuration parameter should
>>>> be able to set the desired behaviour.
>>>>
>>>> The approach I've taken is a simple approach to a complex problem,
>>>> alternative approaches leave the complexity in the hands of the
>>>> implementer, my approach will enable them to practically ignore it.
>>>>
>>>> Before you write it off though, to answer your earlier question, I'll
>>>> further explain the ClassLoader structure between multiple nodes.
>>>>
>>>>                   CLIENT NODE
>>>> ________________________________________________
>>>> |                                                |
>>>> |             System                             |
>>>> |           ClassLoader                          |
>>>> |                |                               |
>>>> |            Extension                           |
>>>> |           ClassLoader                          |
>>>> |                |                               |
>>>> |          Jini Platform &                       |
>>>> |           Service API                          |
>>>> |           ClassLoader                          |
>>>> |                |                               |
>>>> |       _________|___                            |
>>>> |      |             |                           |
>>>> | Application    Smart Proxy                     |
>>>> | ClassLoader    ClassLoader's                   |
>>>> |________________________________________________|
>>>>
>>>>
>>>>                  SERVICE NODE
>>>> ________________________________________________
>>>> |                                                |
>>>> |             System                             |
>>>> |           ClassLoader                          |
>>>> |                |                               |
>>>> |            Extension                           |
>>>> |           ClassLoader                          |
>>>> |                |                               |
>>>> |          Jini Platform &                       |
>>>> |           Service API                          |
>>>> |           ClassLoader                          |
>>>> |                |                               |
>>>> |       _________|_____________________          |
>>>> |      |             |                 |         |
>>>> | Service Imp    Smart Proxy      Parameter Impl |
>>>> | ClassLoader    ClassLoader's    ClassLoader's  |
>>>> |________________________________________________|
>>>>
>>>>
>>>> All Proxy and Service implementations are free to vary at will, proxy
>>>> instances can be shared in collections or iterative operations based on
>>>> common Service API supertype's  All Proxy's and Services are isolated in
>>>> their own Domain, the only way to communicate externally is by using
>>>> interfaces and classes in upper level ClassLoaders, they can utilise as
>>>> many third party libraries jar archives as they need, these will all be
>>>> loaded into a single ClassLoader unique to that Service or Proxy's
>>>> Codebase and Principles.  The Service or Proxy's namespace will be
>>>> totally separate from Application or other Proxy implementation's,
>>>> except in the case where sharing is permitted for identical
>>>> implementations by the implementation developer.
>>>>
>>>> Service API should be carefully considered and designed, it forms the
>>>> basis of network Dependency Injection, you can discover ANY Service
>>>> implementation variant using the same Service API.
>>>>
>>>> The Service API may include other Service API or Java platform classes.
>>>>
>>>> public interface SimpleBookService {
>>>>
>>>> public Book get( Library lib, String name);
>>>>
>>>> }
>>>>
>>>> In the SimpleBookService above, given a Library and String name of a
>>>> Book, a Book instance is returned by the proxy.
>>>>
>>>> The contents of simpleBookService-api.jar:
>>>>
>>>> SimpleBookService.class
>>>> Book.class
>>>> Library.class
>>>>
>>>> Let's say a client has extended the Library, with a class called
>>>> PrivateLibrary, this class is an implementation class by the client,
>>>> that the Service knows nothing about, the Service only uses the Library
>>>> API, but it needs the PrivateLibrary.class
>>>>
>>>> The client makes an archive containing the PrivateLibrary.class publicly
>>>> available in an archive called privateLibrary-param.jar.  This archive
>>>> depends on simpleBookService-api.jar The jar URL is marshalled with the
>>>> class when the parameters are sent back to the service.  When it gets to
>>>> the service implementation, privateLibrary-param.jar is given it's own
>>>> ClassLoader and ProtectionDomain and isn't given any Permissions.  It is
>>>> used by a SimpleBookService implementation to decide which Book to
>>>> return to the client, after which, it's garbage collected, eventually if
>>>> PrivateLibrary isn't used again its ClassLoader is garbage collected too.
>>>>
>>>> Each SimpleBookService proxy implementation will have their own
>>>> ClassLoader namespace, but Client Application classes can still use any
>>>> Service implementation or as many Service implementations as it can
>>>> handle at the same time, all the while treating them as the same Type.
>>>>
>>>> One SimpleBookService implementation proxy, contains its own
>>>> implementation of Book, and while the client is reading the book, it
>>>> remains available from the proxy ClassLoader via the Service API Book
>>>> interface, when finished reading the book, the proxy, book and
>>>> ClassLoader can be garbage collected.  Tomorrow, the client might read a
>>>> book from another SimpleBookService
>>>>
>>>> Most Service API will be relatively small bytecodes as most will be
>>>> abstract or have simple implementations, the fact they're not garbage
>>>> collected, doesn't matter much if the function of the node doesn't
>>>> change, the API will remain limited to the subset in use, by the node.
>>>>
>>>> Note that Jini Platform service implementations like Reggie, Outrigger
>>>> etc, will exist in Service Impl ClassLoaders and Smart Proxy
>>>> ClassLoaders, only the api will be in the Jini Platform ClassLoader.
>>>>
>>>> Think of it as an expandable platform, everything is shared using
>>>> implementations of Service API classes.
>>>>
>>>> It's actually a good policy to be liberal with interfaces when building
>>>> the Service API classes, even with parameters and return types.  Since
>>>> extending interfaces is relatively straight forward, you new interfaces
>>>> will be discovered by older client software as the old interface while
>>>> new implementation code discovers the new interface of your service.
>>>> Older nodes will load your new interface classes into the Service API
>>>> space when your new proxy versions are unmarshalled. That's why it's
>>>> important to maintain backward compatibility in the Service API space.
>>>>
>>>> So best practise would be to create an experimental djinn group until
>>>> your interfaces are stabilised and be prepared to restart your
>>>> experimental group on a regular basis.
>>>>
>>>> I have thought about using OSGi for Service API classes to be served up
>>>> so they can be garbage collected, this might work for serialization too
>>>> using the context ClassLoader.  I have also thought about using
>>>> ClassLoader Tree's using bytecode dependency analysis as per Tim
>>>> Blackman's research.  These things start to get very complicated, just
>>>> to be able to flush the Service API classes.  Wouldn't it just be better
>>>> to use mutiple services that are load balanced, enabling the jvm to be
>>>> restarted if we want to?
>>>>
>>>> There are other ways to make the Service API classes garbage
>>>> collectable, such as having a tier filled with Service API ClassLoaders
>>>> where each Service and Proxy lives in a child ClassLoader in the tree,
>>>> however this presents the problem of what if an application wants to use
>>>> many Service API's or a combination, the different Service API classes
>>>> couldn't see each other from separate ClassLoaders.
>>>>
>>>> Something to consider, best regards,
>>>>
>>>> Peter.
>>>>
>>>> Dennis Reedy wrote:
>>>>         
>>>>> On May 25, 2010, at 710PM, Peter Firmstone wrote:
>>>>>
>>>>>
>>>>>           
>>>>>> This is a good question, which gets to the heart of the Jini's pattern.
>>>>>>
>>>>>> I think the proposed ClassLoader structure will benefit Rio, by enabling increased API commonality and class sharing among Services and their clients.
>>>>>>
>>>>>> You can get around having to shutdown your jvm if you manage evolution of your API interfaces correctly, set up a separate testing Registrar, to keep new API interfaces out of your deployment, until they have stabilised.
>>>>>>    
>>>>>>             
>>>>> Right now the JVM doesnt need to be shut down at all, services can be loaded with different versions, unloaded, etc ... I think you're making assumptions here.
>>>>>  
>>>>>           
>>>>>> Classes, once loaded into a ClassLoader, cannot be garbage collected, but if your API classes don't change there is no problem, when was the last time ServiceRegistrar changed it's public API?   Unlike Jini's platform classes which are set in stone, new API classes can be introduced into older environments.
>>>>>>    
>>>>>>             
>>>>> Right, which is why service implementations get loaded into their own class loader. You define the 'platform' as whatever that needs to be for your case. For Rio it includes requisite bootstrapping and infrastructure technology. For River it most likely just includes the River 'platform', or nothing at all.
>>>>> Consider ServiceStarter and the class loader created from that bootstrapping process. Please explain what is missing from that approach? Each service has it's own security policy. Why does this need to change? What and how does your approach improve on? To my eyes it seems overly complicated.
>>>>>
>>>>>
>>>>>           
>>>>>> Lets take Jini Platform services as an example, in Rio's ClassLoader tree below, the Interfaces for the Platform services exist in the CommonClassLoader, all classes in the CommonClassLoader are visible to any class in any child ClassLoader below in the tree.
>>>>>>
>>>>>> Platform services can be shared freely among all child ClassLoaders.
>>>>>>
>>>>>> Now take Service-1CL and Service-2CL, lets imagine for a moment that these two services both provide the same service, from different or the same node, it doesn't matter, let's imagine now another node with the same ClassLoader tree structure, which consumes these services.
>>>>>>
>>>>>> These services have their service interfaces bundled with their CodeSources, both on the client and at the Service, lets say that Service-2CL provides the same service, but has a different implementation.  Now there's a client service that consumes these services, performs an operation then discards the service.
>>>>>>
>>>>>> Now which common API do the two service proxy's share?
>>>>>>    
>>>>>>             
>>>>> Common API? The service proxies dont share anything. They are each loaded from an implementation of RMIClassLoaderApi
>>>>>  
>>>>>           
>>>>>> This forces you to load both proxy's into the same ClassLoader, making their implementations visible to each other and the client.
>>>>>>    
>>>>>>             
>>>>> Not so sure about that Peter.
>>>>>
>>>>>
>>>>>           
>>>>>> By separating the API into, in your case the CommonClassLoader,
>>>>>>    
>>>>>>             
>>>>> APIs are not added to the CommonClassLoader, and I would argue that it should not happen. You generally do not want to add classes into a class loader that does not get GC'd.
>>>>>
>>>>>
>>>>>           
>>>>>> each with their own ProtectionDomains, all Services and clients in that node, share the same API classes and can be isolated in their own ClassLoader's and can have different implementations but share the same common API types.
>>>>>>
>>>>>> The client service-param.jar is for clients who create new implementations / extend parameters in API methods, the Service server node will require these classes to unmarshall the parameters.  Client parameter classes will never be granted permissions.
>>>>>>
>>>>>> I'll make up some separate ClassLoader tree diagrams showing the client node, the service node and the relationships between remote ClassLoaders.
>>>>>>    
>>>>>>             
>>>>>
>>>>>           
>>>>>> Peter.
>>>>>>
>>>>>> Dennis Reedy wrote:
>>>>>>  
>>>>>>             
>>>>>>> If I understand correctly I think this is the crux of the issue. I dont understand why you need to load all API classes with the same class loader. FWIW, in Rio we handle the loading (and unloading) of services with the following structure (http://www.rio-project.org/apidocs/org/rioproject/boot/package-summary.html#package_description): 
>>>>>>>                 AppCL
>>>>>>>                   |
>>>>>>>           CommonClassLoader (http:// URLs of common JARs)
>>>>>>>                   +
>>>>>>>                   |
>>>>>>>                   +
>>>>>>>           +-------+-------+----...---+
>>>>>>>           |               |          |
>>>>>>>       Service-1CL   Service-2CL  Service-nCL
>>>>>>>       AppCL - 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
>>>>>>> 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.
>>>>>>>
>>>>>>> Service-nCL - Contains the service specific implementation classes.
>>>>>>> Classpath: serviceImpl.jar
>>>>>>> Codebase: "serviceX-dl.jar rio-dl.jar jsk-lib-dl.jar"
>>>>>>>
>>>>>>> Certainly not as sophisticated as OSGi (or what you are targeting), but it meets the requirements of allowing multiple service versions, applying security context per class loader using the same approach as ActivateWrapper, and allows the JVM to stay running.        
>>>>>>>               
>>>>>  
>>>>>           
>>>>
>>>>         
>>>       
>
>
>   


Re: Service API, class visibility, isolation and garbage collection - ClassLoaders

Posted by Dennis Reedy <de...@gmail.com>.
Peter,

No worries. Although I think there is still a misunderstanding on how the class loader structure works, its water under the bridge - lets move on.

What I cant figure out is if you want to share classes across downloaded proxies, why the classes are not part of the API jar the client has in it's classpath. This allows downloaded proxies access to these classes, since the classloader they are loaded with delegates to the classloader that the API jar has been loaded with.

It seems you are creating an edge condition where an implementor would like downloaded proxies to share a class across implementations, but in order to do that that class needs to be injected into a parent class loader. Do I have this right?

IMO, in this scenario, I would advise that the class(es) in question should be added to the API jar.

 AppCL

   
On May 26, 2010, at 727AM, Peter Firmstone wrote:

> Hi Dennis,
> 
> Looking back at my earlier reply when you presented the ClassLoader structure for Rio, I was unintentionally insensitive.
> 
> I didn't mean to pull it apart, probably not the right approach, Rio is a success in it's own right!
> 
> What I should have said and I may not have communicated too well is that I'm introducing a way for Service Proxy's to utilise ClassLoader visibility for maximum API class sharing.  It is a new feature, to give Service implementers the power to share their Service API's, with as much local JVM visibility as the Jini Platform Service API's have.
> 
> As I pointed out there is a compromise, that Service API classes cannot be garbage collected.  I think that if this can be well managed, using a Permission, then it should not affect uptime for critical applications.
> 
> With great power comes great responsibility... yada yada yada.
> 
> Cheers,
> 
> Peter.
> 
> Peter Firmstone wrote:
>> Peter Firmstone wrote:
>>> IDENTICAL TO ANOTHER MESSAGE IN THREAD: Re: Maven repository Entry was Re: Codebase service?
>>> 
>>> Note: A permission will be required to allow a proxy to introduce new Service API during unmarshalling to prevent against denial of service attacks.
>> However in the absence of this permission, the additional ServiceAPI jar could be downloaded into the proxy's own ClassLoader, that would require a ClassLoader even for a dumb proxy with an interface you didn't want to load into your Service API space.  This would enable unmarshalling of that Proxy.  If you, at a later point decided to load that interface into your Service API space, I think you still wouldn't be able to interact with this particular proxy using it, since the interface class identity would be different.
>> 
>> Denial of service here means unfairly growing a JVM's use of non garbage collectable classes.  Any ideas how to control download proxy memory consumption.
>>> 
>>> Hi Dennis,
>>> 
>>> It sounds like you remain unconvinced or don't have a need to use common
>>> interfaces for your service proxy's?
>>> 
>>> So I guess it's a tread lightly approach, make the feature available to
>>> those that want common Service API (The same interface instance for all
>>> proxy's implementing that interface, so they can be used in collections
>>> or batch operations), for maximum sharing of proxy's with differing
>>> implementations, but let those that don't want to publish their API
>>> continue doing what they usually do.  A configuration parameter should
>>> be able to set the desired behaviour.
>>> 
>>> The approach I've taken is a simple approach to a complex problem,
>>> alternative approaches leave the complexity in the hands of the
>>> implementer, my approach will enable them to practically ignore it.
>>> 
>>> Before you write it off though, to answer your earlier question, I'll
>>> further explain the ClassLoader structure between multiple nodes.
>>> 
>>>                   CLIENT NODE
>>> ________________________________________________
>>> |                                                |
>>> |             System                             |
>>> |           ClassLoader                          |
>>> |                |                               |
>>> |            Extension                           |
>>> |           ClassLoader                          |
>>> |                |                               |
>>> |          Jini Platform &                       |
>>> |           Service API                          |
>>> |           ClassLoader                          |
>>> |                |                               |
>>> |       _________|___                            |
>>> |      |             |                           |
>>> | Application    Smart Proxy                     |
>>> | ClassLoader    ClassLoader's                   |
>>> |________________________________________________|
>>> 
>>> 
>>>                  SERVICE NODE
>>> ________________________________________________
>>> |                                                |
>>> |             System                             |
>>> |           ClassLoader                          |
>>> |                |                               |
>>> |            Extension                           |
>>> |           ClassLoader                          |
>>> |                |                               |
>>> |          Jini Platform &                       |
>>> |           Service API                          |
>>> |           ClassLoader                          |
>>> |                |                               |
>>> |       _________|_____________________          |
>>> |      |             |                 |         |
>>> | Service Imp    Smart Proxy      Parameter Impl |
>>> | ClassLoader    ClassLoader's    ClassLoader's  |
>>> |________________________________________________|
>>> 
>>> 
>>> All Proxy and Service implementations are free to vary at will, proxy
>>> instances can be shared in collections or iterative operations based on
>>> common Service API supertype's  All Proxy's and Services are isolated in
>>> their own Domain, the only way to communicate externally is by using
>>> interfaces and classes in upper level ClassLoaders, they can utilise as
>>> many third party libraries jar archives as they need, these will all be
>>> loaded into a single ClassLoader unique to that Service or Proxy's
>>> Codebase and Principles.  The Service or Proxy's namespace will be
>>> totally separate from Application or other Proxy implementation's,
>>> except in the case where sharing is permitted for identical
>>> implementations by the implementation developer.
>>> 
>>> Service API should be carefully considered and designed, it forms the
>>> basis of network Dependency Injection, you can discover ANY Service
>>> implementation variant using the same Service API.
>>> 
>>> The Service API may include other Service API or Java platform classes.
>>> 
>>> public interface SimpleBookService {
>>> 
>>> public Book get( Library lib, String name);
>>> 
>>> }
>>> 
>>> In the SimpleBookService above, given a Library and String name of a
>>> Book, a Book instance is returned by the proxy.
>>> 
>>> The contents of simpleBookService-api.jar:
>>> 
>>> SimpleBookService.class
>>> Book.class
>>> Library.class
>>> 
>>> Let's say a client has extended the Library, with a class called
>>> PrivateLibrary, this class is an implementation class by the client,
>>> that the Service knows nothing about, the Service only uses the Library
>>> API, but it needs the PrivateLibrary.class
>>> 
>>> The client makes an archive containing the PrivateLibrary.class publicly
>>> available in an archive called privateLibrary-param.jar.  This archive
>>> depends on simpleBookService-api.jar The jar URL is marshalled with the
>>> class when the parameters are sent back to the service.  When it gets to
>>> the service implementation, privateLibrary-param.jar is given it's own
>>> ClassLoader and ProtectionDomain and isn't given any Permissions.  It is
>>> used by a SimpleBookService implementation to decide which Book to
>>> return to the client, after which, it's garbage collected, eventually if
>>> PrivateLibrary isn't used again its ClassLoader is garbage collected too.
>>> 
>>> Each SimpleBookService proxy implementation will have their own
>>> ClassLoader namespace, but Client Application classes can still use any
>>> Service implementation or as many Service implementations as it can
>>> handle at the same time, all the while treating them as the same Type.
>>> 
>>> One SimpleBookService implementation proxy, contains its own
>>> implementation of Book, and while the client is reading the book, it
>>> remains available from the proxy ClassLoader via the Service API Book
>>> interface, when finished reading the book, the proxy, book and
>>> ClassLoader can be garbage collected.  Tomorrow, the client might read a
>>> book from another SimpleBookService
>>> 
>>> Most Service API will be relatively small bytecodes as most will be
>>> abstract or have simple implementations, the fact they're not garbage
>>> collected, doesn't matter much if the function of the node doesn't
>>> change, the API will remain limited to the subset in use, by the node.
>>> 
>>> Note that Jini Platform service implementations like Reggie, Outrigger
>>> etc, will exist in Service Impl ClassLoaders and Smart Proxy
>>> ClassLoaders, only the api will be in the Jini Platform ClassLoader.
>>> 
>>> Think of it as an expandable platform, everything is shared using
>>> implementations of Service API classes.
>>> 
>>> It's actually a good policy to be liberal with interfaces when building
>>> the Service API classes, even with parameters and return types.  Since
>>> extending interfaces is relatively straight forward, you new interfaces
>>> will be discovered by older client software as the old interface while
>>> new implementation code discovers the new interface of your service.
>>> Older nodes will load your new interface classes into the Service API
>>> space when your new proxy versions are unmarshalled. That's why it's
>>> important to maintain backward compatibility in the Service API space.
>>> 
>>> So best practise would be to create an experimental djinn group until
>>> your interfaces are stabilised and be prepared to restart your
>>> experimental group on a regular basis.
>>> 
>>> I have thought about using OSGi for Service API classes to be served up
>>> so they can be garbage collected, this might work for serialization too
>>> using the context ClassLoader.  I have also thought about using
>>> ClassLoader Tree's using bytecode dependency analysis as per Tim
>>> Blackman's research.  These things start to get very complicated, just
>>> to be able to flush the Service API classes.  Wouldn't it just be better
>>> to use mutiple services that are load balanced, enabling the jvm to be
>>> restarted if we want to?
>>> 
>>> There are other ways to make the Service API classes garbage
>>> collectable, such as having a tier filled with Service API ClassLoaders
>>> where each Service and Proxy lives in a child ClassLoader in the tree,
>>> however this presents the problem of what if an application wants to use
>>> many Service API's or a combination, the different Service API classes
>>> couldn't see each other from separate ClassLoaders.
>>> 
>>> Something to consider, best regards,
>>> 
>>> Peter.
>>> 
>>> Dennis Reedy wrote:
>>>> On May 25, 2010, at 710PM, Peter Firmstone wrote:
>>>> 
>>>> 
>>>>> This is a good question, which gets to the heart of the Jini's pattern.
>>>>> 
>>>>> I think the proposed ClassLoader structure will benefit Rio, by enabling increased API commonality and class sharing among Services and their clients.
>>>>> 
>>>>> You can get around having to shutdown your jvm if you manage evolution of your API interfaces correctly, set up a separate testing Registrar, to keep new API interfaces out of your deployment, until they have stabilised.
>>>>>    
>>>> 
>>>> Right now the JVM doesnt need to be shut down at all, services can be loaded with different versions, unloaded, etc ... I think you're making assumptions here.
>>>>  
>>>>> Classes, once loaded into a ClassLoader, cannot be garbage collected, but if your API classes don't change there is no problem, when was the last time ServiceRegistrar changed it's public API?   Unlike Jini's platform classes which are set in stone, new API classes can be introduced into older environments.
>>>>>    
>>>> 
>>>> Right, which is why service implementations get loaded into their own class loader. You define the 'platform' as whatever that needs to be for your case. For Rio it includes requisite bootstrapping and infrastructure technology. For River it most likely just includes the River 'platform', or nothing at all.
>>>> Consider ServiceStarter and the class loader created from that bootstrapping process. Please explain what is missing from that approach? Each service has it's own security policy. Why does this need to change? What and how does your approach improve on? To my eyes it seems overly complicated.
>>>> 
>>>> 
>>>>> Lets take Jini Platform services as an example, in Rio's ClassLoader tree below, the Interfaces for the Platform services exist in the CommonClassLoader, all classes in the CommonClassLoader are visible to any class in any child ClassLoader below in the tree.
>>>>> 
>>>>> Platform services can be shared freely among all child ClassLoaders.
>>>>> 
>>>>> Now take Service-1CL and Service-2CL, lets imagine for a moment that these two services both provide the same service, from different or the same node, it doesn't matter, let's imagine now another node with the same ClassLoader tree structure, which consumes these services.
>>>>> 
>>>>> These services have their service interfaces bundled with their CodeSources, both on the client and at the Service, lets say that Service-2CL provides the same service, but has a different implementation.  Now there's a client service that consumes these services, performs an operation then discards the service.
>>>>> 
>>>>> Now which common API do the two service proxy's share?
>>>>>    
>>>> 
>>>> Common API? The service proxies dont share anything. They are each loaded from an implementation of RMIClassLoaderApi
>>>>  
>>>>> This forces you to load both proxy's into the same ClassLoader, making their implementations visible to each other and the client.
>>>>>    
>>>> 
>>>> Not so sure about that Peter.
>>>> 
>>>> 
>>>>> By separating the API into, in your case the CommonClassLoader,
>>>>>    
>>>> 
>>>> APIs are not added to the CommonClassLoader, and I would argue that it should not happen. You generally do not want to add classes into a class loader that does not get GC'd.
>>>> 
>>>> 
>>>>> each with their own ProtectionDomains, all Services and clients in that node, share the same API classes and can be isolated in their own ClassLoader's and can have different implementations but share the same common API types.
>>>>> 
>>>>> The client service-param.jar is for clients who create new implementations / extend parameters in API methods, the Service server node will require these classes to unmarshall the parameters.  Client parameter classes will never be granted permissions.
>>>>> 
>>>>> I'll make up some separate ClassLoader tree diagrams showing the client node, the service node and the relationships between remote ClassLoaders.
>>>>>    
>>>> 
>>>> 
>>>> 
>>>>> Peter.
>>>>> 
>>>>> Dennis Reedy wrote:
>>>>>  
>>>>>> If I understand correctly I think this is the crux of the issue. I dont understand why you need to load all API classes with the same class loader. FWIW, in Rio we handle the loading (and unloading) of services with the following structure (http://www.rio-project.org/apidocs/org/rioproject/boot/package-summary.html#package_description): 
>>>>>>                 AppCL
>>>>>>                   |
>>>>>>           CommonClassLoader (http:// URLs of common JARs)
>>>>>>                   +
>>>>>>                   |
>>>>>>                   +
>>>>>>           +-------+-------+----...---+
>>>>>>           |               |          |
>>>>>>       Service-1CL   Service-2CL  Service-nCL
>>>>>>       AppCL - 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
>>>>>> 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.
>>>>>> 
>>>>>> Service-nCL - Contains the service specific implementation classes.
>>>>>> Classpath: serviceImpl.jar
>>>>>> Codebase: "serviceX-dl.jar rio-dl.jar jsk-lib-dl.jar"
>>>>>> 
>>>>>> Certainly not as sophisticated as OSGi (or what you are targeting), but it meets the requirements of allowing multiple service versions, applying security context per class loader using the same approach as ActivateWrapper, and allows the JVM to stay running.        
>>>> 
>>>> 
>>>>  
>>> 
>>> 
>>> 
>> 
>> 
> 


Re: Service API, class visibility, isolation and garbage collection - ClassLoaders

Posted by Peter Firmstone <ji...@zeus.net.au>.
Hi Dennis,

Looking back at my earlier reply when you presented the ClassLoader 
structure for Rio, I was unintentionally insensitive.

I didn't mean to pull it apart, probably not the right approach, Rio is 
a success in it's own right!

What I should have said and I may not have communicated too well is that 
I'm introducing a way for Service Proxy's to utilise ClassLoader 
visibility for maximum API class sharing.  It is a new feature, to give 
Service implementers the power to share their Service API's, with as 
much local JVM visibility as the Jini Platform Service API's have.

As I pointed out there is a compromise, that Service API classes cannot 
be garbage collected.  I think that if this can be well managed, using a 
Permission, then it should not affect uptime for critical applications.

With great power comes great responsibility... yada yada yada.

Cheers,

Peter.

Peter Firmstone wrote:
> Peter Firmstone wrote:
>> IDENTICAL TO ANOTHER MESSAGE IN THREAD: Re: Maven repository Entry 
>> was Re: Codebase service?
>>
>> Note: A permission will be required to allow a proxy to introduce new 
>> Service API during unmarshalling to prevent against denial of service 
>> attacks.
> However in the absence of this permission, the additional ServiceAPI 
> jar could be downloaded into the proxy's own ClassLoader, that would 
> require a ClassLoader even for a dumb proxy with an interface you 
> didn't want to load into your Service API space.  This would enable 
> unmarshalling of that Proxy.  If you, at a later point decided to load 
> that interface into your Service API space, I think you still wouldn't 
> be able to interact with this particular proxy using it, since the 
> interface class identity would be different.
>
> Denial of service here means unfairly growing a JVM's use of non 
> garbage collectable classes.  Any ideas how to control download proxy 
> memory consumption.
>>
>> Hi Dennis,
>>
>> It sounds like you remain unconvinced or don't have a need to use common
>> interfaces for your service proxy's?
>>
>> So I guess it's a tread lightly approach, make the feature available to
>> those that want common Service API (The same interface instance for all
>> proxy's implementing that interface, so they can be used in collections
>> or batch operations), for maximum sharing of proxy's with differing
>> implementations, but let those that don't want to publish their API
>> continue doing what they usually do.  A configuration parameter should
>> be able to set the desired behaviour.
>>
>> The approach I've taken is a simple approach to a complex problem,
>> alternative approaches leave the complexity in the hands of the
>> implementer, my approach will enable them to practically ignore it.
>>
>> Before you write it off though, to answer your earlier question, I'll
>> further explain the ClassLoader structure between multiple nodes.
>>
>>                    CLIENT NODE
>> ________________________________________________
>> |                                                |
>> |             System                             |
>> |           ClassLoader                          |
>> |                |                               |
>> |            Extension                           |
>> |           ClassLoader                          |
>> |                |                               |
>> |          Jini Platform &                       |
>> |           Service API                          |
>> |           ClassLoader                          |
>> |                |                               |
>> |       _________|___                            |
>> |      |             |                           |
>> | Application    Smart Proxy                     |
>> | ClassLoader    ClassLoader's                   |
>> |________________________________________________|
>>
>>
>>                   SERVICE NODE
>> ________________________________________________
>> |                                                |
>> |             System                             |
>> |           ClassLoader                          |
>> |                |                               |
>> |            Extension                           |
>> |           ClassLoader                          |
>> |                |                               |
>> |          Jini Platform &                       |
>> |           Service API                          |
>> |           ClassLoader                          |
>> |                |                               |
>> |       _________|_____________________          |
>> |      |             |                 |         |
>> | Service Imp    Smart Proxy      Parameter Impl |
>> | ClassLoader    ClassLoader's    ClassLoader's  |
>> |________________________________________________|
>>
>>
>> All Proxy and Service implementations are free to vary at will, proxy
>> instances can be shared in collections or iterative operations based on
>> common Service API supertype's  All Proxy's and Services are isolated in
>> their own Domain, the only way to communicate externally is by using
>> interfaces and classes in upper level ClassLoaders, they can utilise as
>> many third party libraries jar archives as they need, these will all be
>> loaded into a single ClassLoader unique to that Service or Proxy's
>> Codebase and Principles.  The Service or Proxy's namespace will be
>> totally separate from Application or other Proxy implementation's,
>> except in the case where sharing is permitted for identical
>> implementations by the implementation developer.
>>
>> Service API should be carefully considered and designed, it forms the
>> basis of network Dependency Injection, you can discover ANY Service
>> implementation variant using the same Service API.
>>
>> The Service API may include other Service API or Java platform classes.
>>
>> public interface SimpleBookService {
>>
>> public Book get( Library lib, String name);
>>
>> }
>>
>> In the SimpleBookService above, given a Library and String name of a
>> Book, a Book instance is returned by the proxy.
>>
>> The contents of simpleBookService-api.jar:
>>
>> SimpleBookService.class
>> Book.class
>> Library.class
>>
>> Let's say a client has extended the Library, with a class called
>> PrivateLibrary, this class is an implementation class by the client,
>> that the Service knows nothing about, the Service only uses the Library
>> API, but it needs the PrivateLibrary.class
>>
>> The client makes an archive containing the PrivateLibrary.class publicly
>> available in an archive called privateLibrary-param.jar.  This archive
>> depends on simpleBookService-api.jar The jar URL is marshalled with the
>> class when the parameters are sent back to the service.  When it gets to
>> the service implementation, privateLibrary-param.jar is given it's own
>> ClassLoader and ProtectionDomain and isn't given any Permissions.  It is
>> used by a SimpleBookService implementation to decide which Book to
>> return to the client, after which, it's garbage collected, eventually if
>> PrivateLibrary isn't used again its ClassLoader is garbage collected 
>> too.
>>
>> Each SimpleBookService proxy implementation will have their own
>> ClassLoader namespace, but Client Application classes can still use any
>> Service implementation or as many Service implementations as it can
>> handle at the same time, all the while treating them as the same Type.
>>
>> One SimpleBookService implementation proxy, contains its own
>> implementation of Book, and while the client is reading the book, it
>> remains available from the proxy ClassLoader via the Service API Book
>> interface, when finished reading the book, the proxy, book and
>> ClassLoader can be garbage collected.  Tomorrow, the client might read a
>> book from another SimpleBookService
>>
>> Most Service API will be relatively small bytecodes as most will be
>> abstract or have simple implementations, the fact they're not garbage
>> collected, doesn't matter much if the function of the node doesn't
>> change, the API will remain limited to the subset in use, by the node.
>>
>> Note that Jini Platform service implementations like Reggie, Outrigger
>> etc, will exist in Service Impl ClassLoaders and Smart Proxy
>> ClassLoaders, only the api will be in the Jini Platform ClassLoader.
>>
>> Think of it as an expandable platform, everything is shared using
>> implementations of Service API classes.
>>
>> It's actually a good policy to be liberal with interfaces when building
>> the Service API classes, even with parameters and return types.  Since
>> extending interfaces is relatively straight forward, you new interfaces
>> will be discovered by older client software as the old interface while
>> new implementation code discovers the new interface of your service.
>> Older nodes will load your new interface classes into the Service API
>> space when your new proxy versions are unmarshalled. That's why it's
>> important to maintain backward compatibility in the Service API space.
>>
>> So best practise would be to create an experimental djinn group until
>> your interfaces are stabilised and be prepared to restart your
>> experimental group on a regular basis.
>>
>> I have thought about using OSGi for Service API classes to be served up
>> so they can be garbage collected, this might work for serialization too
>> using the context ClassLoader.  I have also thought about using
>> ClassLoader Tree's using bytecode dependency analysis as per Tim
>> Blackman's research.  These things start to get very complicated, just
>> to be able to flush the Service API classes.  Wouldn't it just be better
>> to use mutiple services that are load balanced, enabling the jvm to be
>> restarted if we want to?
>>
>> There are other ways to make the Service API classes garbage
>> collectable, such as having a tier filled with Service API ClassLoaders
>> where each Service and Proxy lives in a child ClassLoader in the tree,
>> however this presents the problem of what if an application wants to use
>> many Service API's or a combination, the different Service API classes
>> couldn't see each other from separate ClassLoaders.
>>
>> Something to consider, best regards,
>>
>> Peter.
>>
>> Dennis Reedy wrote:
>>> On May 25, 2010, at 710PM, Peter Firmstone wrote:
>>>
>>>  
>>>> This is a good question, which gets to the heart of the Jini's 
>>>> pattern.
>>>>
>>>> I think the proposed ClassLoader structure will benefit Rio, by 
>>>> enabling increased API commonality and class sharing among Services 
>>>> and their clients.
>>>>
>>>> You can get around having to shutdown your jvm if you manage 
>>>> evolution of your API interfaces correctly, set up a separate 
>>>> testing Registrar, to keep new API interfaces out of your 
>>>> deployment, until they have stabilised.
>>>>     
>>>
>>> Right now the JVM doesnt need to be shut down at all, services can 
>>> be loaded with different versions, unloaded, etc ... I think you're 
>>> making assumptions here.
>>>   
>>>> Classes, once loaded into a ClassLoader, cannot be garbage 
>>>> collected, but if your API classes don't change there is no 
>>>> problem, when was the last time ServiceRegistrar changed it's 
>>>> public API?   Unlike Jini's platform classes which are set in 
>>>> stone, new API classes can be introduced into older environments.
>>>>     
>>>
>>> Right, which is why service implementations get loaded into their 
>>> own class loader. You define the 'platform' as whatever that needs 
>>> to be for your case. For Rio it includes requisite bootstrapping and 
>>> infrastructure technology. For River it most likely just includes 
>>> the River 'platform', or nothing at all.
>>> Consider ServiceStarter and the class loader created from that 
>>> bootstrapping process. Please explain what is missing from that 
>>> approach? Each service has it's own security policy. Why does this 
>>> need to change? What and how does your approach improve on? To my 
>>> eyes it seems overly complicated.
>>>
>>>  
>>>> Lets take Jini Platform services as an example, in Rio's 
>>>> ClassLoader tree below, the Interfaces for the Platform services 
>>>> exist in the CommonClassLoader, all classes in the 
>>>> CommonClassLoader are visible to any class in any child ClassLoader 
>>>> below in the tree.
>>>>
>>>> Platform services can be shared freely among all child ClassLoaders.
>>>>
>>>> Now take Service-1CL and Service-2CL, lets imagine for a moment 
>>>> that these two services both provide the same service, from 
>>>> different or the same node, it doesn't matter, let's imagine now 
>>>> another node with the same ClassLoader tree structure, which 
>>>> consumes these services.
>>>>
>>>> These services have their service interfaces bundled with their 
>>>> CodeSources, both on the client and at the Service, lets say that 
>>>> Service-2CL provides the same service, but has a different 
>>>> implementation.  Now there's a client service that consumes these 
>>>> services, performs an operation then discards the service.
>>>>
>>>> Now which common API do the two service proxy's share?
>>>>     
>>>
>>> Common API? The service proxies dont share anything. They are each 
>>> loaded from an implementation of RMIClassLoaderApi
>>>   
>>>>  This forces you to load both proxy's into the same ClassLoader, 
>>>> making their implementations visible to each other and the client.
>>>>     
>>>
>>> Not so sure about that Peter.
>>>
>>>  
>>>> By separating the API into, in your case the CommonClassLoader,
>>>>     
>>>
>>> APIs are not added to the CommonClassLoader, and I would argue that 
>>> it should not happen. You generally do not want to add classes into 
>>> a class loader that does not get GC'd.
>>>
>>>  
>>>> each with their own ProtectionDomains, all Services and clients in 
>>>> that node, share the same API classes and can be isolated in their 
>>>> own ClassLoader's and can have different implementations but share 
>>>> the same common API types.
>>>>
>>>> The client service-param.jar is for clients who create new 
>>>> implementations / extend parameters in API methods, the Service 
>>>> server node will require these classes to unmarshall the 
>>>> parameters.  Client parameter classes will never be granted 
>>>> permissions.
>>>>
>>>> I'll make up some separate ClassLoader tree diagrams showing the 
>>>> client node, the service node and the relationships between remote 
>>>> ClassLoaders.
>>>>     
>>>
>>>
>>>  
>>>> Peter.
>>>>
>>>> Dennis Reedy wrote:
>>>>   
>>>>> If I understand correctly I think this is the crux of the issue. I 
>>>>> dont understand why you need to load all API classes with the same 
>>>>> class loader. FWIW, in Rio we handle the loading (and unloading) 
>>>>> of services with the following structure 
>>>>> (http://www.rio-project.org/apidocs/org/rioproject/boot/package-summary.html#package_description): 
>>>>>
>>>>>                  AppCL
>>>>>                    |
>>>>>            CommonClassLoader (http:// URLs of common JARs)
>>>>>                    +
>>>>>                    |
>>>>>                    +
>>>>>            +-------+-------+----...---+
>>>>>            |               |          |
>>>>>        Service-1CL   Service-2CL  Service-nCL
>>>>>        AppCL - 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
>>>>> 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.
>>>>>
>>>>> Service-nCL - Contains the service specific implementation classes.
>>>>> Classpath: serviceImpl.jar
>>>>> Codebase: "serviceX-dl.jar rio-dl.jar jsk-lib-dl.jar"
>>>>>
>>>>> Certainly not as sophisticated as OSGi (or what you are 
>>>>> targeting), but it meets the requirements of allowing multiple 
>>>>> service versions, applying security context per class loader using 
>>>>> the same approach as ActivateWrapper, and allows the JVM to stay 
>>>>> running.        
>>>
>>>
>>>   
>>
>>
>>
>
>


Re: Service API, class visibility, isolation and garbage collection - ClassLoaders

Posted by Peter Firmstone <ji...@zeus.net.au>.
Peter Firmstone wrote:
> IDENTICAL TO ANOTHER MESSAGE IN THREAD: Re: Maven repository Entry was 
> Re: Codebase service?
>
> Note: A permission will be required to allow a proxy to introduce new 
> Service API during unmarshalling to prevent against denial of service 
> attacks.
However in the absence of this permission, the additional ServiceAPI jar 
could be downloaded into the proxy's own ClassLoader, that would require 
a ClassLoader even for a dumb proxy with an interface you didn't want to 
load into your Service API space.  This would enable unmarshalling of 
that Proxy.  If you, at a later point decided to load that interface 
into your Service API space, I think you still wouldn't be able to 
interact with this particular proxy using it, since the interface class 
identity would be different.

Denial of service here means unfairly growing a JVM's use of non garbage 
collectable classes.  Any ideas how to control download proxy memory 
consumption.
>
> Hi Dennis,
>
> It sounds like you remain unconvinced or don't have a need to use common
> interfaces for your service proxy's?
>
> So I guess it's a tread lightly approach, make the feature available to
> those that want common Service API (The same interface instance for all
> proxy's implementing that interface, so they can be used in collections
> or batch operations), for maximum sharing of proxy's with differing
> implementations, but let those that don't want to publish their API
> continue doing what they usually do.  A configuration parameter should
> be able to set the desired behaviour.
>
> The approach I've taken is a simple approach to a complex problem,
> alternative approaches leave the complexity in the hands of the
> implementer, my approach will enable them to practically ignore it.
>
> Before you write it off though, to answer your earlier question, I'll
> further explain the ClassLoader structure between multiple nodes.
>
>                    CLIENT NODE
> ________________________________________________
> |                                                |
> |             System                             |
> |           ClassLoader                          |
> |                |                               |
> |            Extension                           |
> |           ClassLoader                          |
> |                |                               |
> |          Jini Platform &                       |
> |           Service API                          |
> |           ClassLoader                          |
> |                |                               |
> |       _________|___                            |
> |      |             |                           |
> | Application    Smart Proxy                     |
> | ClassLoader    ClassLoader's                   |
> |________________________________________________|
>
>
>                   SERVICE NODE
> ________________________________________________
> |                                                |
> |             System                             |
> |           ClassLoader                          |
> |                |                               |
> |            Extension                           |
> |           ClassLoader                          |
> |                |                               |
> |          Jini Platform &                       |
> |           Service API                          |
> |           ClassLoader                          |
> |                |                               |
> |       _________|_____________________          |
> |      |             |                 |         |
> | Service Imp    Smart Proxy      Parameter Impl |
> | ClassLoader    ClassLoader's    ClassLoader's  |
> |________________________________________________|
>
>
> All Proxy and Service implementations are free to vary at will, proxy
> instances can be shared in collections or iterative operations based on
> common Service API supertype's  All Proxy's and Services are isolated in
> their own Domain, the only way to communicate externally is by using
> interfaces and classes in upper level ClassLoaders, they can utilise as
> many third party libraries jar archives as they need, these will all be
> loaded into a single ClassLoader unique to that Service or Proxy's
> Codebase and Principles.  The Service or Proxy's namespace will be
> totally separate from Application or other Proxy implementation's,
> except in the case where sharing is permitted for identical
> implementations by the implementation developer.
>
> Service API should be carefully considered and designed, it forms the
> basis of network Dependency Injection, you can discover ANY Service
> implementation variant using the same Service API.
>
> The Service API may include other Service API or Java platform classes.
>
> public interface SimpleBookService {
>
> public Book get( Library lib, String name);
>
> }
>
> In the SimpleBookService above, given a Library and String name of a
> Book, a Book instance is returned by the proxy.
>
> The contents of simpleBookService-api.jar:
>
> SimpleBookService.class
> Book.class
> Library.class
>
> Let's say a client has extended the Library, with a class called
> PrivateLibrary, this class is an implementation class by the client,
> that the Service knows nothing about, the Service only uses the Library
> API, but it needs the PrivateLibrary.class
>
> The client makes an archive containing the PrivateLibrary.class publicly
> available in an archive called privateLibrary-param.jar.  This archive
> depends on simpleBookService-api.jar The jar URL is marshalled with the
> class when the parameters are sent back to the service.  When it gets to
> the service implementation, privateLibrary-param.jar is given it's own
> ClassLoader and ProtectionDomain and isn't given any Permissions.  It is
> used by a SimpleBookService implementation to decide which Book to
> return to the client, after which, it's garbage collected, eventually if
> PrivateLibrary isn't used again its ClassLoader is garbage collected too.
>
> Each SimpleBookService proxy implementation will have their own
> ClassLoader namespace, but Client Application classes can still use any
> Service implementation or as many Service implementations as it can
> handle at the same time, all the while treating them as the same Type.
>
> One SimpleBookService implementation proxy, contains its own
> implementation of Book, and while the client is reading the book, it
> remains available from the proxy ClassLoader via the Service API Book
> interface, when finished reading the book, the proxy, book and
> ClassLoader can be garbage collected.  Tomorrow, the client might read a
> book from another SimpleBookService
>
> Most Service API will be relatively small bytecodes as most will be
> abstract or have simple implementations, the fact they're not garbage
> collected, doesn't matter much if the function of the node doesn't
> change, the API will remain limited to the subset in use, by the node.
>
> Note that Jini Platform service implementations like Reggie, Outrigger
> etc, will exist in Service Impl ClassLoaders and Smart Proxy
> ClassLoaders, only the api will be in the Jini Platform ClassLoader.
>
> Think of it as an expandable platform, everything is shared using
> implementations of Service API classes.
>
> It's actually a good policy to be liberal with interfaces when building
> the Service API classes, even with parameters and return types.  Since
> extending interfaces is relatively straight forward, you new interfaces
> will be discovered by older client software as the old interface while
> new implementation code discovers the new interface of your service.
> Older nodes will load your new interface classes into the Service API
> space when your new proxy versions are unmarshalled. That's why it's
> important to maintain backward compatibility in the Service API space.
>
> So best practise would be to create an experimental djinn group until
> your interfaces are stabilised and be prepared to restart your
> experimental group on a regular basis.
>
> I have thought about using OSGi for Service API classes to be served up
> so they can be garbage collected, this might work for serialization too
> using the context ClassLoader.  I have also thought about using
> ClassLoader Tree's using bytecode dependency analysis as per Tim
> Blackman's research.  These things start to get very complicated, just
> to be able to flush the Service API classes.  Wouldn't it just be better
> to use mutiple services that are load balanced, enabling the jvm to be
> restarted if we want to?
>
> There are other ways to make the Service API classes garbage
> collectable, such as having a tier filled with Service API ClassLoaders
> where each Service and Proxy lives in a child ClassLoader in the tree,
> however this presents the problem of what if an application wants to use
> many Service API's or a combination, the different Service API classes
> couldn't see each other from separate ClassLoaders.
>
> Something to consider, best regards,
>
> Peter.
>
> Dennis Reedy wrote:
>> On May 25, 2010, at 710PM, Peter Firmstone wrote:
>>
>>  
>>> This is a good question, which gets to the heart of the Jini's pattern.
>>>
>>> I think the proposed ClassLoader structure will benefit Rio, by 
>>> enabling increased API commonality and class sharing among Services 
>>> and their clients.
>>>
>>> You can get around having to shutdown your jvm if you manage 
>>> evolution of your API interfaces correctly, set up a separate 
>>> testing Registrar, to keep new API interfaces out of your 
>>> deployment, until they have stabilised.
>>>     
>>
>> Right now the JVM doesnt need to be shut down at all, services can be 
>> loaded with different versions, unloaded, etc ... I think you're 
>> making assumptions here.
>>    
>>> Classes, once loaded into a ClassLoader, cannot be garbage 
>>> collected, but if your API classes don't change there is no problem, 
>>> when was the last time ServiceRegistrar changed it's public API?   
>>> Unlike Jini's platform classes which are set in stone, new API 
>>> classes can be introduced into older environments.
>>>     
>>
>> Right, which is why service implementations get loaded into their own 
>> class loader. You define the 'platform' as whatever that needs to be 
>> for your case. For Rio it includes requisite bootstrapping and 
>> infrastructure technology. For River it most likely just includes the 
>> River 'platform', or nothing at all.
>> Consider ServiceStarter and the class loader created from that 
>> bootstrapping process. Please explain what is missing from that 
>> approach? Each service has it's own security policy. Why does this 
>> need to change? What and how does your approach improve on? To my 
>> eyes it seems overly complicated.
>>
>>  
>>> Lets take Jini Platform services as an example, in Rio's ClassLoader 
>>> tree below, the Interfaces for the Platform services exist in the 
>>> CommonClassLoader, all classes in the CommonClassLoader are visible 
>>> to any class in any child ClassLoader below in the tree.
>>>
>>> Platform services can be shared freely among all child ClassLoaders.
>>>
>>> Now take Service-1CL and Service-2CL, lets imagine for a moment that 
>>> these two services both provide the same service, from different or 
>>> the same node, it doesn't matter, let's imagine now another node 
>>> with the same ClassLoader tree structure, which consumes these 
>>> services.
>>>
>>> These services have their service interfaces bundled with their 
>>> CodeSources, both on the client and at the Service, lets say that 
>>> Service-2CL provides the same service, but has a different 
>>> implementation.  Now there's a client service that consumes these 
>>> services, performs an operation then discards the service.
>>>
>>> Now which common API do the two service proxy's share?
>>>     
>>
>> Common API? The service proxies dont share anything. They are each 
>> loaded from an implementation of RMIClassLoaderApi
>>    
>>>  This forces you to load both proxy's into the same ClassLoader, 
>>> making their implementations visible to each other and the client.
>>>     
>>
>> Not so sure about that Peter.
>>
>>  
>>> By separating the API into, in your case the CommonClassLoader,
>>>     
>>
>> APIs are not added to the CommonClassLoader, and I would argue that 
>> it should not happen. You generally do not want to add classes into a 
>> class loader that does not get GC'd.
>>
>>  
>>> each with their own ProtectionDomains, all Services and clients in 
>>> that node, share the same API classes and can be isolated in their 
>>> own ClassLoader's and can have different implementations but share 
>>> the same common API types.
>>>
>>> The client service-param.jar is for clients who create new 
>>> implementations / extend parameters in API methods, the Service 
>>> server node will require these classes to unmarshall the 
>>> parameters.  Client parameter classes will never be granted 
>>> permissions.
>>>
>>> I'll make up some separate ClassLoader tree diagrams showing the 
>>> client node, the service node and the relationships between remote 
>>> ClassLoaders.
>>>     
>>
>>
>>  
>>> Peter.
>>>
>>> Dennis Reedy wrote:
>>>    
>>>> If I understand correctly I think this is the crux of the issue. I 
>>>> dont understand why you need to load all API classes with the same 
>>>> class loader. FWIW, in Rio we handle the loading (and unloading) of 
>>>> services with the following structure 
>>>> (http://www.rio-project.org/apidocs/org/rioproject/boot/package-summary.html#package_description): 
>>>>
>>>>                  AppCL
>>>>                    |
>>>>            CommonClassLoader (http:// URLs of common JARs)
>>>>                    +
>>>>                    |
>>>>                    +
>>>>            +-------+-------+----...---+
>>>>            |               |          |
>>>>        Service-1CL   Service-2CL  Service-nCL
>>>>        AppCL - 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
>>>> 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.
>>>>
>>>> Service-nCL - Contains the service specific implementation classes.
>>>> Classpath: serviceImpl.jar
>>>> Codebase: "serviceX-dl.jar rio-dl.jar jsk-lib-dl.jar"
>>>>
>>>> Certainly not as sophisticated as OSGi (or what you are targeting), 
>>>> but it meets the requirements of allowing multiple service 
>>>> versions, applying security context per class loader using the same 
>>>> approach as ActivateWrapper, and allows the JVM to stay running.  
>>>>       
>>
>>
>>   
>
>
>


Service API, class visibility, isolation and garbage collection - ClassLoaders

Posted by Peter Firmstone <ji...@zeus.net.au>.
IDENTICAL TO ANOTHER MESSAGE IN THREAD: Re: Maven repository Entry was 
Re: Codebase service?

Note: A permission will be required to allow a proxy to introduce new 
Service API during unmarshalling to prevent against denial of service 
attacks.

Hi Dennis,

It sounds like you remain unconvinced or don't have a need to use common
interfaces for your service proxy's?

So I guess it's a tread lightly approach, make the feature available to
those that want common Service API (The same interface instance for all
proxy's implementing that interface, so they can be used in collections
or batch operations), for maximum sharing of proxy's with differing
implementations, but let those that don't want to publish their API
continue doing what they usually do.  A configuration parameter should
be able to set the desired behaviour.

The approach I've taken is a simple approach to a complex problem,
alternative approaches leave the complexity in the hands of the
implementer, my approach will enable them to practically ignore it.

Before you write it off though, to answer your earlier question, I'll
further explain the ClassLoader structure between multiple nodes.

                    CLIENT NODE
________________________________________________
|                                                |
|             System                             |
|           ClassLoader                          |
|                |                               |
|            Extension                           |
|           ClassLoader                          |
|                |                               |
|          Jini Platform &                       |
|           Service API                          |
|           ClassLoader                          |
|                |                               |
|       _________|___                            |
|      |             |                           |
| Application    Smart Proxy                     |
| ClassLoader    ClassLoader's                   |
|________________________________________________|


                   SERVICE NODE
________________________________________________
|                                                |
|             System                             |
|           ClassLoader                          |
|                |                               |
|            Extension                           |
|           ClassLoader                          |
|                |                               |
|          Jini Platform &                       |
|           Service API                          |
|           ClassLoader                          |
|                |                               |
|       _________|_____________________          |
|      |             |                 |         |
| Service Imp    Smart Proxy      Parameter Impl |
| ClassLoader    ClassLoader's    ClassLoader's  |
|________________________________________________|


All Proxy and Service implementations are free to vary at will, proxy
instances can be shared in collections or iterative operations based on
common Service API supertype's  All Proxy's and Services are isolated in
their own Domain, the only way to communicate externally is by using
interfaces and classes in upper level ClassLoaders, they can utilise as
many third party libraries jar archives as they need, these will all be
loaded into a single ClassLoader unique to that Service or Proxy's
Codebase and Principles.  The Service or Proxy's namespace will be
totally separate from Application or other Proxy implementation's,
except in the case where sharing is permitted for identical
implementations by the implementation developer.

Service API should be carefully considered and designed, it forms the
basis of network Dependency Injection, you can discover ANY Service
implementation variant using the same Service API.

The Service API may include other Service API or Java platform classes.

public interface SimpleBookService {

public Book get( Library lib, String name);

}

In the SimpleBookService above, given a Library and String name of a
Book, a Book instance is returned by the proxy.

The contents of simpleBookService-api.jar:

SimpleBookService.class
Book.class
Library.class

Let's say a client has extended the Library, with a class called
PrivateLibrary, this class is an implementation class by the client,
that the Service knows nothing about, the Service only uses the Library
API, but it needs the PrivateLibrary.class

The client makes an archive containing the PrivateLibrary.class publicly
available in an archive called privateLibrary-param.jar.  This archive
depends on simpleBookService-api.jar The jar URL is marshalled with the
class when the parameters are sent back to the service.  When it gets to
the service implementation, privateLibrary-param.jar is given it's own
ClassLoader and ProtectionDomain and isn't given any Permissions.  It is
used by a SimpleBookService implementation to decide which Book to
return to the client, after which, it's garbage collected, eventually if
PrivateLibrary isn't used again its ClassLoader is garbage collected too.

Each SimpleBookService proxy implementation will have their own
ClassLoader namespace, but Client Application classes can still use any
Service implementation or as many Service implementations as it can
handle at the same time, all the while treating them as the same Type.

One SimpleBookService implementation proxy, contains its own
implementation of Book, and while the client is reading the book, it
remains available from the proxy ClassLoader via the Service API Book
interface, when finished reading the book, the proxy, book and
ClassLoader can be garbage collected.  Tomorrow, the client might read a
book from another SimpleBookService

Most Service API will be relatively small bytecodes as most will be
abstract or have simple implementations, the fact they're not garbage
collected, doesn't matter much if the function of the node doesn't
change, the API will remain limited to the subset in use, by the node.

Note that Jini Platform service implementations like Reggie, Outrigger
etc, will exist in Service Impl ClassLoaders and Smart Proxy
ClassLoaders, only the api will be in the Jini Platform ClassLoader.

Think of it as an expandable platform, everything is shared using
implementations of Service API classes.

It's actually a good policy to be liberal with interfaces when building
the Service API classes, even with parameters and return types.  Since
extending interfaces is relatively straight forward, you new interfaces
will be discovered by older client software as the old interface while
new implementation code discovers the new interface of your service.
Older nodes will load your new interface classes into the Service API
space when your new proxy versions are unmarshalled. That's why it's
important to maintain backward compatibility in the Service API space.

So best practise would be to create an experimental djinn group until
your interfaces are stabilised and be prepared to restart your
experimental group on a regular basis.

I have thought about using OSGi for Service API classes to be served up
so they can be garbage collected, this might work for serialization too
using the context ClassLoader.  I have also thought about using
ClassLoader Tree's using bytecode dependency analysis as per Tim
Blackman's research.  These things start to get very complicated, just
to be able to flush the Service API classes.  Wouldn't it just be better
to use mutiple services that are load balanced, enabling the jvm to be
restarted if we want to?

There are other ways to make the Service API classes garbage
collectable, such as having a tier filled with Service API ClassLoaders
where each Service and Proxy lives in a child ClassLoader in the tree,
however this presents the problem of what if an application wants to use
many Service API's or a combination, the different Service API classes
couldn't see each other from separate ClassLoaders.

Something to consider, best regards,

Peter.

Dennis Reedy wrote:
> On May 25, 2010, at 710PM, Peter Firmstone wrote:
>
>   
>> This is a good question, which gets to the heart of the Jini's pattern.
>>
>> I think the proposed ClassLoader structure will benefit Rio, by enabling increased API commonality and class sharing among Services and their clients.
>>
>> You can get around having to shutdown your jvm if you manage evolution of your API interfaces correctly, set up a separate testing Registrar, to keep new API interfaces out of your deployment, until they have stabilised.
>>     
>
> Right now the JVM doesnt need to be shut down at all, services can be loaded with different versions, unloaded, etc ... I think you're making assumptions here.
>   
>   
>> Classes, once loaded into a ClassLoader, cannot be garbage collected, but if your API classes don't change there is no problem, when was the last time ServiceRegistrar changed it's public API?   Unlike Jini's platform classes which are set in stone, new API classes can be introduced into older environments.
>>     
>
> Right, which is why service implementations get loaded into their own class loader. You define the 'platform' as whatever that needs to be for your case. For Rio it includes requisite bootstrapping and infrastructure technology. For River it most likely just includes the River 'platform', or nothing at all. 
>
> Consider ServiceStarter and the class loader created from that bootstrapping process. Please explain what is missing from that approach? Each service has it's own security policy. Why does this need to change? What and how does your approach improve on? To my eyes it seems overly complicated.
>
>   
>> Lets take Jini Platform services as an example, in Rio's ClassLoader tree below, the Interfaces for the Platform services exist in the CommonClassLoader, all classes in the CommonClassLoader are visible to any class in any child ClassLoader below in the tree.
>>
>> Platform services can be shared freely among all child ClassLoaders.
>>
>> Now take Service-1CL and Service-2CL, lets imagine for a moment that these two services both provide the same service, from different or the same node, it doesn't matter, let's imagine now another node with the same ClassLoader tree structure, which consumes these services.
>>
>> These services have their service interfaces bundled with their CodeSources, both on the client and at the Service, lets say that Service-2CL provides the same service, but has a different implementation.  Now there's a client service that consumes these services, performs an operation then discards the service.
>>
>> Now which common API do the two service proxy's share?
>>     
>
> Common API? The service proxies dont share anything. They are each loaded from an implementation of RMIClassLoaderApi
>   
>   
>>  This forces you to load both proxy's into the same ClassLoader, making their implementations visible to each other and the client.
>>     
>
> Not so sure about that Peter.
>
>   
>> By separating the API into, in your case the CommonClassLoader,
>>     
>
> APIs are not added to the CommonClassLoader, and I would argue that it should not happen. You generally do not want to add classes into a class loader that does not get GC'd.
>
>   
>> each with their own ProtectionDomains, all Services and clients in that node, share the same API classes and can be isolated in their own ClassLoader's and can have different implementations but share the same common API types.
>>
>> The client service-param.jar is for clients who create new implementations / extend parameters in API methods, the Service server node will require these classes to unmarshall the parameters.  Client parameter classes will never be granted permissions.
>>
>> I'll make up some separate ClassLoader tree diagrams showing the client node, the service node and the relationships between remote ClassLoaders.
>>     
>
>
>   
>> Peter.
>>
>> Dennis Reedy wrote:
>>     
>>> If I understand correctly I think this is the crux of the issue. I dont understand why you need to load all API classes with the same class loader. FWIW, in Rio we handle the loading (and unloading) of services with the following structure (http://www.rio-project.org/apidocs/org/rioproject/boot/package-summary.html#package_description):
>>>                  AppCL
>>>                    |
>>>            CommonClassLoader (http:// URLs of common JARs)
>>>                    +
>>>                    |
>>>                    +
>>>            +-------+-------+----...---+
>>>            |               |          |
>>>        Service-1CL   Service-2CL  Service-nCL
>>>        
>>> AppCL - 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
>>> 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.
>>>
>>> Service-nCL - Contains the service specific implementation classes.
>>> Classpath: serviceImpl.jar
>>> Codebase: "serviceX-dl.jar rio-dl.jar jsk-lib-dl.jar"
>>>
>>> Certainly not as sophisticated as OSGi (or what you are targeting), but it meets the requirements of allowing multiple service versions, applying security context per class loader using the same approach as ActivateWrapper, and allows the JVM to stay running. 
>>>  
>>>       
>
>
>   



Re: Maven repository Entry was Re: Codebase service?

Posted by Dennis Reedy <de...@gmail.com>.
On May 25, 2010, at 710PM, Peter Firmstone wrote:

> This is a good question, which gets to the heart of the Jini's pattern.
> 
> I think the proposed ClassLoader structure will benefit Rio, by enabling increased API commonality and class sharing among Services and their clients.
> 
> You can get around having to shutdown your jvm if you manage evolution of your API interfaces correctly, set up a separate testing Registrar, to keep new API interfaces out of your deployment, until they have stabilised.

Right now the JVM doesnt need to be shut down at all, services can be loaded with different versions, unloaded, etc ... I think you're making assumptions here.

> 
> Classes, once loaded into a ClassLoader, cannot be garbage collected, but if your API classes don't change there is no problem, when was the last time ServiceRegistrar changed it's public API?   Unlike Jini's platform classes which are set in stone, new API classes can be introduced into older environments.

Right, which is why service implementations get loaded into their own class loader. You define the 'platform' as whatever that needs to be for your case. For Rio it includes requisite bootstrapping and infrastructure technology. For River it most likely just includes the River 'platform', or nothing at all. 

Consider ServiceStarter and the class loader created from that bootstrapping process. Please explain what is missing from that approach? Each service has it's own security policy. Why does this need to change? What and how does your approach improve on? To my eyes it seems overly complicated.

> 
> Lets take Jini Platform services as an example, in Rio's ClassLoader tree below, the Interfaces for the Platform services exist in the CommonClassLoader, all classes in the CommonClassLoader are visible to any class in any child ClassLoader below in the tree.
> 
> Platform services can be shared freely among all child ClassLoaders.
> 
> Now take Service-1CL and Service-2CL, lets imagine for a moment that these two services both provide the same service, from different or the same node, it doesn't matter, let's imagine now another node with the same ClassLoader tree structure, which consumes these services.
> 
> These services have their service interfaces bundled with their CodeSources, both on the client and at the Service, lets say that Service-2CL provides the same service, but has a different implementation.  Now there's a client service that consumes these services, performs an operation then discards the service.
> 
> Now which common API do the two service proxy's share?

Common API? The service proxies dont share anything. They are each loaded from an implementation of RMIClassLoaderApi

>  This forces you to load both proxy's into the same ClassLoader, making their implementations visible to each other and the client.

Not so sure about that Peter.

> 
> By separating the API into, in your case the CommonClassLoader,

APIs are not added to the CommonClassLoader, and I would argue that it should not happen. You generally do not want to add classes into a class loader that does not get GC'd.

> each with their own ProtectionDomains, all Services and clients in that node, share the same API classes and can be isolated in their own ClassLoader's and can have different implementations but share the same common API types.
> 
> The client service-param.jar is for clients who create new implementations / extend parameters in API methods, the Service server node will require these classes to unmarshall the parameters.  Client parameter classes will never be granted permissions.
> 
> I'll make up some separate ClassLoader tree diagrams showing the client node, the service node and the relationships between remote ClassLoaders.


> 
> Peter.
> 
> Dennis Reedy wrote:
>> If I understand correctly I think this is the crux of the issue. I dont understand why you need to load all API classes with the same class loader. FWIW, in Rio we handle the loading (and unloading) of services with the following structure (http://www.rio-project.org/apidocs/org/rioproject/boot/package-summary.html#package_description):
>>                  AppCL
>>                    |
>>            CommonClassLoader (http:// URLs of common JARs)
>>                    +
>>                    |
>>                    +
>>            +-------+-------+----...---+
>>            |               |          |
>>        Service-1CL   Service-2CL  Service-nCL
>>        
>> AppCL - 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
>> 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.
>> 
>> Service-nCL - Contains the service specific implementation classes.
>> Classpath: serviceImpl.jar
>> Codebase: "serviceX-dl.jar rio-dl.jar jsk-lib-dl.jar"
>> 
>> Certainly not as sophisticated as OSGi (or what you are targeting), but it meets the requirements of allowing multiple service versions, applying security context per class loader using the same approach as ActivateWrapper, and allows the JVM to stay running. 
>>  
> 


Re: Maven repository Entry was Re: Codebase service?

Posted by Peter Firmstone <ji...@zeus.net.au>.
This is a good question, which gets to the heart of the Jini's pattern.

I think the proposed ClassLoader structure will benefit Rio, by enabling 
increased API commonality and class sharing among Services and their 
clients.

You can get around having to shutdown your jvm if you manage evolution 
of your API interfaces correctly, set up a separate testing Registrar, 
to keep new API interfaces out of your deployment, until they have 
stabilised.

Classes, once loaded into a ClassLoader, cannot be garbage collected, 
but if your API classes don't change there is no problem, when was the 
last time ServiceRegistrar changed it's public API?   Unlike Jini's 
platform classes which are set in stone, new API classes can be 
introduced into older environments.

Lets take Jini Platform services as an example, in Rio's ClassLoader 
tree below, the Interfaces for the Platform services exist in the 
CommonClassLoader, all classes in the CommonClassLoader are visible to 
any class in any child ClassLoader below in the tree.

Platform services can be shared freely among all child ClassLoaders.

Now take Service-1CL and Service-2CL, lets imagine for a moment that 
these two services both provide the same service, from different or the 
same node, it doesn't matter, let's imagine now another node with the 
same ClassLoader tree structure, which consumes these services.

These services have their service interfaces bundled with their 
CodeSources, both on the client and at the Service, lets say that 
Service-2CL provides the same service, but has a different 
implementation.  Now there's a client service that consumes these 
services, performs an operation then discards the service.

Now which common API do the two service proxy's share?  This forces you 
to load both proxy's into the same ClassLoader, making their 
implementations visible to each other and the client.

By separating the API into, in your case the CommonClassLoader, each 
with their own ProtectionDomains, all Services and clients in that node, 
share the same API classes and can be isolated in their own 
ClassLoader's and can have different implementations but share the same 
common API types.

The client service-param.jar is for clients who create new 
implementations / extend parameters in API methods, the Service server 
node will require these classes to unmarshall the parameters.  Client 
parameter classes will never be granted permissions.

I'll make up some separate ClassLoader tree diagrams showing the client 
node, the service node and the relationships between remote ClassLoaders.

Peter.

Dennis Reedy wrote:
> If I understand correctly I think this is the crux of the issue. I 
> dont understand why you need to load all API classes with the same 
> class loader. FWIW, in Rio we handle the loading (and unloading) of 
> services with the following structure 
> (http://www.rio-project.org/apidocs/org/rioproject/boot/package-summary.html#package_description):
>                   AppCL
>                     |
>             CommonClassLoader (http:// URLs of common JARs)
>                     +
>                     |
>                     +
>             +-------+-------+----...---+
>             |               |          |
>         Service-1CL   Service-2CL  Service-nCL
>         
>
> AppCL - 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
> 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.
>
> Service-nCL - Contains the service specific implementation classes.
> Classpath: serviceImpl.jar
> Codebase: "serviceX-dl.jar rio-dl.jar jsk-lib-dl.jar"
>
> Certainly not as sophisticated as OSGi (or what you are targeting), but it meets the requirements of allowing multiple service versions, applying security context per class loader using the same approach as ActivateWrapper, and allows the JVM to stay running. 
>
>   


Re: Maven repository Entry was Re: Codebase service?

Posted by Dennis Reedy <de...@gmail.com>.
On May 25, 2010, at 842AM, Patrick Wright wrote:

>> Okay, I agree with you here. This also means the we dont need to refactor MarshalledInstance right? If not then we may need another entry type, one for non-maven artifacts as well.
> 
> I have no opinion (and almost no knowledge) of MarshalledInstance...
> 
>> 
>> Also lets remember that for maven resolution, I think you'll also want to either provide support for parsing your maven settings.xml or include the repositories to go find the artifact if it's not present. If we dont do this then we need to include some wiring to include the repository location(s) that the primary artifact can be resolved from in the entry as well.
> 
> What I was imagining is that in the client configuration, one would
> provide the class which could handle these special entry types. That
> class (for Maven) would most likely use the home/local repository by
> default, and an extended version could use some or all of the maven
> embedder to handle more complex (and transitive) lookup in other
> archives.

I think its absolutely key to provide support for the resolution of transitive dependencies out of the gate. The resolution of a maven artifact needs to do 2 things:

1. If necessary download the artifact and it's dependencies (transitive included)
2. Produce a classpath from the resolved artifact(s) 

> I haven't actually used these APIs in Maven but my
> understanding is that they are exposed and can be used. Sorry if I
> can't be more specific. I have an idea of how this could work but
> don't have a grasp of the plumbing involved.

I went through the investigation of embedding maven for this use and ended up writing my own resolver for the following reasons:

• For starters, we want to abstract the underlying dependency resolution implementation in order to give the flexibility to potentially support other repository based dependency management approaches. 
In the future we may seek to provide support for Ivy or the OSGi Bundle Repository. Providing an abstraction on top of the concrete dependency management solutions gives us flexibility going forward. The resolver itself is configurable. The resolver provider can be specified by providing a resource named "META-INF/services/org.rioproject.resolver.Resolver" containing the name of the provider class. If multiple resources with that name are available, then the one used will be the first one returned by ServiceLoader.load. A similar approach can be used for River I would think.

• Secondly, the ability to embed a Maven resolver into the Rio runtime was initially tried, but we found that the Maven Embedder would not be supported until the 3.0 betas. As of this release Maven 3.0 is still at alpha. So in an effort to be in control of our own destiny, a Resolver that interacts with Maven2 repositories was created.

(more here http://www.rio-project.org/resolver.html)

> 
> What does concern me a little is the impact on the time required to
> load a service if it needs to download JAR files from remote
> repositories. This is especially an issue with 3rd party libraries
> included via transitive dependencies. I don't have a solution, but
> it's probably something we need to warn people about.

Yep. BTW, this is why we recommend the use of repository managers. It really takes the pain out of resolving transitive dependencies. Key to this is also making sure settings.xml is set up, and/or you have access to the artifact's pom.xml


> On the other
> hand, there are two good competition repository hosts for Maven so
> it's not that much of a problem for people to set this up.
> 

Re: Maven repository Entry was Re: Codebase service?

Posted by Patrick Wright <pd...@gmail.com>.
> Okay, I agree with you here. This also means the we dont need to refactor MarshalledInstance right? If not then we may need another entry type, one for non-maven artifacts as well.

I have no opinion (and almost no knowledge) of MarshalledInstance...

>
> Also lets remember that for maven resolution, I think you'll also want to either provide support for parsing your maven settings.xml or include the repositories to go find the artifact if it's not present. If we dont do this then we need to include some wiring to include the repository location(s) that the primary artifact can be resolved from in the entry as well.

What I was imagining is that in the client configuration, one would
provide the class which could handle these special entry types. That
class (for Maven) would most likely use the home/local repository by
default, and an extended version could use some or all of the maven
embedder to handle more complex (and transitive) lookup in other
archives. I haven't actually used these APIs in Maven but my
understanding is that they are exposed and can be used. Sorry if I
can't be more specific. I have an idea of how this could work but
don't have a grasp of the plumbing involved.

What does concern me a little is the impact on the time required to
load a service if it needs to download JAR files from remote
repositories. This is especially an issue with 3rd party libraries
included via transitive dependencies. I don't have a solution, but
it's probably something we need to warn people about. On the other
hand, there are two good competition repository hosts for Maven so
it's not that much of a problem for people to set this up.


Patrick

Re: Maven repository Entry was Re: Codebase service?

Posted by Dennis Reedy <de...@gmail.com>.
On May 25, 2010, at 812AM, Patrick Wright wrote:

>>> Yes, we can use an Entry, or as Chris pointed out, if we annotate MarshalledInstance's using a new Maven URL schema we can extract that info and make it available via MarshalledServiceItem (An abstract class that extends ServiceItem).
>> 
>> I dont think a new Maven URL schema has actually been proposed? Why wouldnt we just use a String attribute in an Entry that is of the form groupId:artifactId:version:classifier?
> 
> What I don't like about this is that it makes the client a little more
> fragile--we would essentially be sniffing a string for a certain
> format, which, if it matched, would indicate it is a Maven coordinate.
> If this is in a separate type of Entry (e.g. CoordinateArtifactEntry
> or so) then we are reacting to a type of entry, not to a format which
> needs to be documented, etc.

Okay, I agree with you here. This also means the we dont need to refactor MarshalledInstance right? If not then we may need another entry type, one for non-maven artifacts as well. 

Also lets remember that for maven resolution, I think you'll also want to either provide support for parsing your maven settings.xml or include the repositories to go find the artifact if it's not present. If we dont do this then we need to include some wiring to include the repository location(s) that the primary artifact can be resolved from in the entry as well.

Re: Maven repository Entry was Re: Codebase service?

Posted by Patrick Wright <pd...@gmail.com>.
>> Yes, we can use an Entry, or as Chris pointed out, if we annotate MarshalledInstance's using a new Maven URL schema we can extract that info and make it available via MarshalledServiceItem (An abstract class that extends ServiceItem).
>
> I dont think a new Maven URL schema has actually been proposed? Why wouldnt we just use a String attribute in an Entry that is of the form groupId:artifactId:version:classifier?

What I don't like about this is that it makes the client a little more
fragile--we would essentially be sniffing a string for a certain
format, which, if it matched, would indicate it is a Maven coordinate.
If this is in a separate type of Entry (e.g. CoordinateArtifactEntry
or so) then we are reacting to a type of entry, not to a format which
needs to be documented, etc.


Patrick

Re: Maven repository Entry was Re: Codebase service?

Posted by Dennis Reedy <de...@gmail.com>.
Hi Peter,

Thanks for the detailed reply, comments interspersed below, Also, from a housekeeping point of view (if not already done), it would be great if Jira issues could be created for items below.

Dennis

On May 25, 2010, at 205AM, Peter Firmstone wrote:

> Hi Dennis,
> 
> Reasoning and hopefully the why's? below.

> 
> Dennis Reedy wrote:
>> Hi Peter,
>> 
>> I was hoping to take a step back for a second, perhaps its just me that seems to have my head spinning of late on this list. I may have missed some things, but we've discussed many issues over the past week:
>> 
>> - How to advertise the DL jar(s) a service vends, allowing a client to download requisite jars that allow the jars to be loaded from a local (trusted) location
>>  
> Yes, we can use an Entry, or as Chris pointed out, if we annotate MarshalledInstance's using a new Maven URL schema we can extract that info and make it available via MarshalledServiceItem (An abstract class that extends ServiceItem).

I dont think a new Maven URL schema has actually been proposed? Why wouldnt we just use a String attribute in an Entry that is of the form groupId:artifactId:version:classifier?

> 
>> - Given the capability above, the need for a codebase service may not be required
>>  
> Agreed
>> - Conventions on how to develop River services, as it relates to jar naming, packaging and what dependencies are between the various artifacts
>> - How to possibly move forward with utilizing Maven repositories and the implied capabilities of published artifacts
>> - The development of a maven archetype to allow a developer to easily create a working project in seconds
>>  
> Yes to all above.
>> Your attention to detail and the documentation of how class loader interactions with regards to security is great. I'd like to understand the requirements of what you have documented below, the urge to refactor MarshalledInstance, and why the new class loader hierarchy needs to be added to River.
>>  
> 
> The urge to refactor MarshalledInstance is to allow the URL annotation to be requested directly and passed via StreamServiceRegistrar and combined with delayed unmarshalling of proxy's via MarshalledServiceItem, to allow the client to provision and provide an alternate CodeSource if need be.

So this is related to the first bullet above, allowing a client to download requisite jars. I dont see why MarshalledInstance needs refactoring if we already have the jar(s)/artifact that can be provisioned. In the case of an artifact, it may not matter what the MarshalledInstance provides, because the artifact's location will most likely be in a repository.

> 
> StreamServiceRegistrar returns a ResultStream<ServiceItem> , so you have check with instanceof MarshalledServiceItem.
> 
> The new packaging Scheme

packaging scheme?

> can be applied to distributed objects also, provided we create an implementation of CodebaseAccessClassLoader (contributed by Gregg to replace RMIClassLoaderSPI) that performs or requests local Maven archive provisioning.

As I have pointed out earlier you'll need more information on where to get the artifacts from, specifically the maven repositories to access. I dont know if the RMICLassLoaderSpi is the right place to put this added functionality or not at this time.

> 
> The new ClassLoader hierarchy is needed, to solve class identity (fully qualified runtime classname = class + ClassLoader), class visibility, isolation and versioning problems, that PreferredClassProvider partially solves.

>> Perhaps I'm just missing some fundamental issues, but maybe we need to take some time and determine the whys before the hows? Is this direction fundamental to the OSGi direction that you're taking? If so, how does this impact non-OSGi based systems?
>>  
> The changes are OSGi agnostic, OSGi will live in the application space, so while they benefit OSGi, they are independent of it, so the same benefits will apply to other software and OSGi isn't required.
> 
> I realised that fundamentally OSGi uses ClassLoaders for isolating software into components, so implementation classes aren't exposed outside of their module, something which OSGi does very well, it also manages security concerns very well.  Something else I realised, OSGi's use of ClassLoaders is not optimum for distributed systems, there are difficulties determining the correct ClassLoader during deserialization. OSGi wasn't designed with Serialization in mind.  Distributed computing introduces another dimension, like going from 2D to 3D,  in OSGi, you only have one bundle version combination loaded (you can have many bundles of different versions but I believe typically only one of each unique bundle instance, you can have the same package version exported by differently versioned bundles). So how do you determine the correct ClassLoader during unmarshalling.  In River we may have many proxy's using the same jar version, however we don't want the proxy's implementation to get all tied up in the local application bundles, we'd be allowing the smart proxy to pollute the local application space, some parts of the local application could see the proxy implementation.
> 
> In our new ClassLoader tree, a smart proxy can have it's own personal ClassLoader,

As it would today through the class loader the RMIClassLoaderSPi returns right?

> because the ContextClassLoader will be that of the proxy's during returning object deserialization, since it initiated the communication with the remote Service host.  The reason a clients parameter implementation cannot have it's own ClassLoader and must share with other clients that use the same codebase and version is that they have no link to the ClassLoader at the remote Service host, with ony the Codebase and Version to go by, since they didn't initiate the communication, there could otherwise be many ClassLoaders containing that codebase version, there not enough information to find it, the last thing I want to do is require the client have an identity or location to deal with that deserialization of parameters at the Service node.

If the client has the service-api.jar in it's classpath, why are there issues surrounding the client's parameter implementation's class loader?

> 
> Rather than take, "how you use OSGi" and apply it to River, I decided to understand why they solved their problems the way they did and learn from it.  It is a very good solution to the problem they've solved.  However with our solution we can solve the deserialization issue for distributed applications utilising OSGi.
> 
> Currently River uses Permission grants based on ClassLoader, (so does OSGi), what I realised was I needed a finer grained Permission grant and having many ProtectionDomain's inside one ClassLoader is about as fine as you can get.  Only one ClassLoader is used for the API space for class identity reasons, to allow maximum sharing of API classes because you just can't control and coordinate someone else's JVM's ClassLoader visibility, without overcoming some serious trust issues (Simpler is better I don't even want to attempt to solve them!). There is however one compromise with my approach.
> 
> By loading all API classes into the same ClassLoader, we cannot have duplicate classes, so we must always load the latest API version, that must not break backward compatibility. If the backward compatibility constraints are hampering your design, it's simply better to deprecate a package and append a number to change the package name.  (Or create a completely new API jar)

If I understand correctly I think this is the crux of the issue. I dont understand why you need to load all API classes with the same class loader. FWIW, in Rio we handle the loading (and unloading) of services with the following structure (http://www.rio-project.org/apidocs/org/rioproject/boot/package-summary.html#package_description):

                  AppCL
                    |
            CommonClassLoader (http:// URLs of common JARs)
                    +
                    |
                    +
            +-------+-------+----...---+
            |               |          |
        Service-1CL   Service-2CL  Service-nCL
        

AppCL - 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
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.

Service-nCL - Contains the service specific implementation classes.
Classpath: serviceImpl.jar
Codebase: "serviceX-dl.jar rio-dl.jar jsk-lib-dl.jar"

Certainly not as sophisticated as OSGi (or what you are targeting), but it meets the requirements of allowing multiple service versions, applying security context per class loader using the same approach as ActivateWrapper, and allows the JVM to stay running. 

> 
> org.some.thing
> org.some.thing2
> 
> The reason we version packages is so we don't have to rename them when they break backward compatibility, this makes sense for implementations, but not API.  If your going to have long lived persistent objects they belong in the API space, if you don't need to persist your objects, why not have an interface and throwaway class implementations, this solves Serialization exposing class internal state and evolution.  Extend the interface if you wan't new methods.
> 
> If a JVM has been running a long time, a new API version may have been released, clients using the old API functionality only, won't be able to see or utilise the new functionality until we restart the jvm.  That is the compromise.  But I figure it's not too bad a compromise once API's have stabilised and go into longer development cycles.  I can handle having to restart my JVM once every 6 months.
> 
> I think Michael Warres got to the crux of the problem with his publication on ClassLoader issues, my interpretation of what he said, is perhaps java should tear apart the multiple ClassLoader concerns, of Security, Isolation and Identity and start again.  I've chosen what appears to me to be the best compromise based on Java ClassLoader's today.
> 
> So this new ClassLoader hierarchy should play nice with Maven,

I would suggest it has nothing to do with Maven. Maven is just used as a repository for us, and optionally as a way to build services.


> OSGi and other stuff too, because now the API is visible to everything below in the ClassLoader hierarchy, while the implementations below, don't expose themselves, instead, everything cooperates through the API.
> 
> OSGi can be used to synchronize ClassLoader visibility between two separate JVM's, however that still requires the implementer deal with deserialization issues, with our solution, we won't have to worry much about ClassLoader issues.  With Maven, we won't have to worry about lost codebases either.
> 
> Yep, it has been a bit of a head spin, needed your help to work out the details before I forgot them.
> 
> There is one more detail, I'd like to include in the jar archive: a list of permissions the jar needs.  I'd like to use the same format OSGi uses, because it's been done before, why be different.  This is to solve the: "what grants does it need?" Problem. So we can minimise permission grants.

Yes, I'm interested in this as well.


Re: Maven repository Entry was Re: Codebase service?

Posted by Patrick Wright <pd...@gmail.com>.
> So what's the downside of dynamic download, specifically?  I can see the
> issue in a bandwidth limited situation (which is actually not Jini's
> original target, but could probably be handled with sufficiently bright
> jar caching), but in a well-connected local area network environment
> (Jini's design center) what problems do we face, and might there be
> simpler ways to handle them?

Hi Greg

I'll just give my perspective. In our environment we control both the
client and service-side updates and deployments, and we never have a
need for dynamic changes to proxy classes or anything related to the
-dl.jar files. This has two implications: we're performing a download
for all -dl.jar files from all services each time we restart our
clients, and we have a weak spot in our system related to codebase
availability. On each restart, our clients pretend they don't know the
classes from the services, even though in our deployment process they
obviously have a right to--and on top of that that the -dl.jars are
static following a deployment--and this means there is this extra
lookup effort which all has to work perfectly, each and every time. It
just doesn't make sense; we ourselves don't need this feature of Jini,
by and large, although we appreciate the reasoning behind it.

As an example of where this has bitten us--our admins has set up a new
hosting environment for one of our clients, and forgot that the
client's container was configured to write temp files to a special
directory, and didn't create this directory. The Jini infrastructure
had no place to write the downloadable JAR files. What sort of
information did we have to go on?
- client logs report that the class com.sun.jini.blah can't be found, wtf?
- service codebase logs report broken pipe from connection from ip xyz
port (randomly-assigned port number)
- all other clients are able to see and interact with this service
- end users of the application aren't able to use the application
because a critical service is unavailable

We've had similar "unavailable codebase" problems cropping up due to
any number of configuration issues over the years. In each and every
case, it's completely mysterious to almost all of us that codebase
might even be an issue, it's also mysterious how to track down the
specific problem and fix it (the reporting by and large is so deep in
the Jini infrastructure that logging rarely helps), and, worst of all,
this is arising from a feature that we don't even care to use.

I'll just add to that that after 3 or more years of using Jini as the
backbone of our synchronous communication, we've had a hard time
growing the number of people who have more than passing knowledge of
it, making problem resolution more difficult.

Hence, for people in our situation, I'd like there to be a drop-dead
simple alternative to dynamic code loading, and where the dynamic code
loading was an interesting option, but not a requirement. I do look
forward to the day when I find a real need for it, though, because I
think it's a rocking good idea (really).

My perspective,
Patrick

Re: Maven repository Entry was Re: Codebase service?

Posted by Peter Firmstone <ji...@zeus.net.au>.
Gregg Wonderly wrote:
> Gregg Wonderly wrote:
>> Dennis Reedy wrote:
>>> On May 25, 2010, at 1156AM, Patrick Wright wrote:
>>>>  I myself would just
>>>> like to see River move away from the idea that dynamic download via
>>>> codebase services is a requirement, more or less, of using Jini, and
>>>> to provide a reasonable/workable alternative for those that don't need
>>>> it.
>>>
>>> Sums up the entire impetus to this thread, well said!
>>
>> We all know that there are references to java.rmi.* in various parts 
>> of what Jini is.  But, the plugability of RMIClassLoaderSPI (and now 
>> my changes to remove dependency on the system class loader resolving 
>> the replacement SPI), it has always been possible for the 
>> "annotation" to be pretty arbitrarily resolved to mean whatever.
>>
>> The real problem is that the annotation is untyped.  What I'd like to 
>> suggest, is that we amend some of my work to include a typed 
>> annotation which could actually be contained in a Map that might look 
>> like Map<String,List<A>> that would allow multiple types of 
>> annotations to be used.  The key to the map, should be the class name 
>> of the replacement CodebaseClassAccess implementation.
>>
>> Then we could put <A> on CodebaseClassAccess as the annotation type 
>> provide a bit richer opportunity to really compartmentalize and fully 
>> qualify how annotations are used.
>>
>> Thoughts?
>
> As I go look at the code regarding this, I see that the implementation 
> details don't make this so easy because CodebaseAccessClassLoader is a 
> singleton and the types are thus fixed.  I need to look at this more.
>
> Gregg Wonderly
>
Thanks Gregg, that's much appreciated.

Peter.

Re: Maven repository Entry was Re: Codebase service?

Posted by Gregg Wonderly <gr...@wonderly.org>.
Gregg Wonderly wrote:
> Dennis Reedy wrote:
>> On May 25, 2010, at 1156AM, Patrick Wright wrote:
>>>  I myself would just
>>> like to see River move away from the idea that dynamic download via
>>> codebase services is a requirement, more or less, of using Jini, and
>>> to provide a reasonable/workable alternative for those that don't need
>>> it.
>>
>> Sums up the entire impetus to this thread, well said!
> 
> We all know that there are references to java.rmi.* in various parts of 
> what Jini is.  But, the plugability of RMIClassLoaderSPI (and now my 
> changes to remove dependency on the system class loader resolving the 
> replacement SPI), it has always been possible for the "annotation" to be 
> pretty arbitrarily resolved to mean whatever.
> 
> The real problem is that the annotation is untyped.  What I'd like to 
> suggest, is that we amend some of my work to include a typed annotation 
> which could actually be contained in a Map that might look like 
> Map<String,List<A>> that would allow multiple types of annotations to be 
> used.  The key to the map, should be the class name of the replacement 
> CodebaseClassAccess implementation.
> 
> Then we could put <A> on CodebaseClassAccess as the annotation type 
> provide a bit richer opportunity to really compartmentalize and fully 
> qualify how annotations are used.
> 
> Thoughts?

As I go look at the code regarding this, I see that the implementation details 
don't make this so easy because CodebaseAccessClassLoader is a singleton and the 
types are thus fixed.  I need to look at this more.

Gregg Wonderly

Re: Maven repository Entry was Re: Codebase service?

Posted by Gregg Wonderly <gr...@wonderly.org>.
Dennis Reedy wrote:
> On May 25, 2010, at 1156AM, Patrick Wright wrote:
>>  I myself would just
>> like to see River move away from the idea that dynamic download via
>> codebase services is a requirement, more or less, of using Jini, and
>> to provide a reasonable/workable alternative for those that don't need
>> it.
> 
> Sums up the entire impetus to this thread, well said!

We all know that there are references to java.rmi.* in various parts of what 
Jini is.  But, the plugability of RMIClassLoaderSPI (and now my changes to 
remove dependency on the system class loader resolving the replacement SPI), it 
has always been possible for the "annotation" to be pretty arbitrarily resolved 
to mean whatever.

The real problem is that the annotation is untyped.  What I'd like to suggest, 
is that we amend some of my work to include a typed annotation which could 
actually be contained in a Map that might look like Map<String,List<A>> that 
would allow multiple types of annotations to be used.  The key to the map, 
should be the class name of the replacement CodebaseClassAccess implementation.

Then we could put <A> on CodebaseClassAccess as the annotation type provide a 
bit richer opportunity to really compartmentalize and fully qualify how 
annotations are used.

Thoughts?

Gregg Wonderly


Re: Maven repository Entry was Re: Codebase service?

Posted by Dennis Reedy <de...@gmail.com>.
On May 26, 2010, at 856AM, Greg Trasuk wrote:

> 
> On Tue, 2010-05-25 at 13:20, Dennis Reedy wrote:
>> On May 25, 2010, at 1156AM, Patrick Wright wrote:
>>> I myself would just
>>> like to see River move away from the idea that dynamic download via
>>> codebase services is a requirement, more or less, of using Jini, and
>>> to provide a reasonable/workable alternative for those that don't need
>>> it.
>> 
>> Sums up the entire impetus to this thread, well said!
> 
> Just curious, here...
> 
> Dynamic loading of proxy classes has always seemed (to me) to be at the
> core of the Jini philosophy.  Much of the dynamic discovery, dynamic
> redeployment, the concepts in Jim Waldo's "The End of Protocols"
> (http://java.sun.com/developer/technicalArticles/jini/protocols.html),
> Frank Somers' "Survival of the Fittest Jini Services"
> (http://www.javaworld.com/javaworld/jw-04-2001/jw-0413-jiniology.html),
> etc, goes away if you take out dynamic proxy loading.
> 
> So what's the downside of dynamic download, specifically?  

Lost codebase issue for one. Figuring out how to best deploy the artifacts for services is another. And having each developer/deployer figure that out for themselves exacerbates the issue. Also, we have found that in a large distributed system composed of (lots of) services, relying on http(md:) based class loading has definite issues as it relates to the infamous "too many open files" exception [1]. 

Using a maven repository to access artifacts that have been built & tested, both in development (snapshots) and deployed (immutable artifacts) allows River to take advantage of managed repositories of available artifacts. Using the dependency management capabilities we can easily derive the classpath of a service's artifacts, in the exact same way as the service has been developed and tested.

You can still load the classes dynamically, you just load them locally as opposed to remotely each time. And, if local, trust becomes implicit since the classes do not come from a remote location (each time).

So all of the jewels of Jini still are still intact, this approach just allows the requisite jars to be first downloaded to the client from a maven repository, then loaded locally.

Dennis

[1] Bug ID 4166799, manifests itself on RHEL. If you scroll down you'll see it is not fixed.


Re: Maven repository Entry was Re: Codebase service?

Posted by Greg Trasuk <tr...@stratuscom.com>.
On Tue, 2010-05-25 at 13:20, Dennis Reedy wrote:
> On May 25, 2010, at 1156AM, Patrick Wright wrote:
> >  I myself would just
> > like to see River move away from the idea that dynamic download via
> > codebase services is a requirement, more or less, of using Jini, and
> > to provide a reasonable/workable alternative for those that don't need
> > it.
> 
> Sums up the entire impetus to this thread, well said!

Just curious, here...

Dynamic loading of proxy classes has always seemed (to me) to be at the
core of the Jini philosophy.  Much of the dynamic discovery, dynamic
redeployment, the concepts in Jim Waldo's "The End of Protocols"
(http://java.sun.com/developer/technicalArticles/jini/protocols.html),
Frank Somers' "Survival of the Fittest Jini Services"
(http://www.javaworld.com/javaworld/jw-04-2001/jw-0413-jiniology.html),
etc, goes away if you take out dynamic proxy loading.

So what's the downside of dynamic download, specifically?  I can see the
issue in a bandwidth limited situation (which is actually not Jini's
original target, but could probably be handled with sufficiently bright
jar caching), but in a well-connected local area network environment
(Jini's design center) what problems do we face, and might there be
simpler ways to handle them?


Cheers,

Greg.
-- 
Greg Trasuk, President
StratusCom Manufacturing Systems Inc. - We use information technology to
solve business problems on your plant floor.
http://stratuscom.com


Re: Maven repository Entry was Re: Codebase service?

Posted by Dennis Reedy <de...@gmail.com>.
On May 25, 2010, at 1156AM, Patrick Wright wrote:
>  I myself would just
> like to see River move away from the idea that dynamic download via
> codebase services is a requirement, more or less, of using Jini, and
> to provide a reasonable/workable alternative for those that don't need
> it.

Sums up the entire impetus to this thread, well said!

Re: Maven repository Entry was Re: Codebase service?

Posted by Patrick Wright <pd...@gmail.com>.
> These are all good issues. I think more rigor needs to be put into how service artifacts are updated, and what attributes we look for when we seek to discover services. Using version numbers in both the produced artifacts and ensuring that services advertise version numbers (as part of net.jini.lookup.entry.ServiceInfo), and that we look for specific version numbers for a service we want to use can help with this issue.
>
> Perhaps (and I'm not sure this has been discussed before) having a range of versions that a service provides support for could also help address this issue. If the client determines it is out of synch, the deferred update approach certainly allows the client to choose to use remote class loading or provision that requisite jars.

To add to that--two solutions that we have to address "does the client
have the latest (and correct) version of the service downloadable
JARs?" are first, to always download those JARs on discovering the
service, and second, to implement a versioning scheme such that the
client, on discovery, verifies that it has the version available
locally and in classpath.

>From my perspective, I'm happy to apply a version number/string as we
have already converged on Maven at our shop, and there are rules for
when we update version numbers. There are some cases where a developer
working in a branch will not update versions during their development
work, and versions are overwritten in-place (not exactly, Maven will
track multiple instances of the same version using a timestamp). But
in deployment the versions are fixed. We haven't (in around 3 years of
using Jini here) had to update the -dl.jars at runtime and have the
clients pick up the new versions. We just have a different deployment
process that works for us. I understand that different users of Jini
have other needs.

I think posting the artifact's hash along with other identifying
information helps you here--if the version of the local file matches,
but the hash doesn't, then the client either has to find the correct
version or give up. Since the hash would presumably be posted along
with the service Entries, it would prevent clients from trying to use
outdated artifacts for a given service.

I think River needs to support both dynamic codebase downloading (via
codebase services) and local repository storage. Some way to mix the
two as per Gregg's suggestion sounds good as well (e.g. local lookup
but allowing dynamic downloading when needed). I myself would just
like to see River move away from the idea that dynamic download via
codebase services is a requirement, more or less, of using Jini, and
to provide a reasonable/workable alternative for those that don't need
it.


Patrick

Re: Maven repository Entry was Re: Codebase service?

Posted by Jeff Ramsdale <je...@gmail.com>.
On Tue, May 25, 2010 at 7:57 AM, Dennis Reedy <de...@gmail.com> wrote:
> These are all good issues. I think more rigor needs to be put into how service artifacts are updated, and what attributes we look for when we seek to discover services. Using version numbers in both the produced artifacts and ensuring that services advertise version numbers (as part of net.jini.lookup.entry.ServiceInfo), and that we look for specific version numbers for a service we want to use can help with this issue.
>
> Perhaps (and I'm not sure this has been discussed before) having a range of versions that a service provides support for could also help address this issue. If the client determines it is out of synch, the deferred update approach certainly allows the client to choose to use remote class loading or provision that requisite jars.

Normally I'm not a fan of using version ranges in Maven, but with long
running services I think it probably makes sense.

-jeff

Re: Maven repository Entry was Re: Codebase service?

Posted by Dennis Reedy <de...@gmail.com>.
On May 25, 2010, at 1041AM, Gregg Wonderly wrote:

> Peter Firmstone wrote:
>> Dennis Reedy wrote:
>>> - Given the capability above, the need for a codebase service may not be required
>>>  
>> Agreed
> 
> One of the things that we need to consider, I believe, is the ability for a client/UI to run without any service/network visability.  Imagine devices using a services UI in a disconnected environment and later connecting for interaction with the service.  The codebase server, today requires caching downloading and many interesting twists to how the content of the clients "classpath" is managed for disconnected operation.  Using a more detached update mechanism more like we see in more modern network environments can really help.  It does, however, present more of an opportunity for codebase rot to occur which can cause a client to run without the right software in place when it attempts to connect to a service.
> 
> The existing codebase mechanism has the benefit that you automatically, always get exactly the software that the service needs you to use on the client end.
> 
> We should think about how to deal with the chasm that exists between these two mechanisms.
> 
> It is true that there are some service evolution practices that make this less likely.
> 
> If there are things that we can document or compartmentalize to make it easier to use a deferred update mechanism that would be great.
> 
> I worry about what might happen if a client is started off the network, and then brought into a network environment where it can make contact with the service without having updated the code because of how the order of events transpired.


These are all good issues. I think more rigor needs to be put into how service artifacts are updated, and what attributes we look for when we seek to discover services. Using version numbers in both the produced artifacts and ensuring that services advertise version numbers (as part of net.jini.lookup.entry.ServiceInfo), and that we look for specific version numbers for a service we want to use can help with this issue.

Perhaps (and I'm not sure this has been discussed before) having a range of versions that a service provides support for could also help address this issue. If the client determines it is out of synch, the deferred update approach certainly allows the client to choose to use remote class loading or provision that requisite jars.

Re: Maven repository Entry was Re: Codebase service?

Posted by Gregg Wonderly <gr...@wonderly.org>.
Peter Firmstone wrote:
> Dennis Reedy wrote:
>> - Given the capability above, the need for a codebase service may not 
>> be required
>>   
> Agreed

One of the things that we need to consider, I believe, is the ability for a 
client/UI to run without any service/network visability.  Imagine devices using 
a services UI in a disconnected environment and later connecting for interaction 
with the service.  The codebase server, today requires caching downloading and 
many interesting twists to how the content of the clients "classpath" is managed 
for disconnected operation.  Using a more detached update mechanism more like we 
see in more modern network environments can really help.  It does, however, 
present more of an opportunity for codebase rot to occur which can cause a 
client to run without the right software in place when it attempts to connect to 
a service.

The existing codebase mechanism has the benefit that you automatically, always 
get exactly the software that the service needs you to use on the client end.

We should think about how to deal with the chasm that exists between these two 
mechanisms.

It is true that there are some service evolution practices that make this less 
likely.

If there are things that we can document or compartmentalize to make it easier 
to use a deferred update mechanism that would be great.

I worry about what might happen if a client is started off the network, and then 
brought into a network environment where it can make contact with the service 
without having updated the code because of how the order of events transpired.

Gregg Wonderly

Re: Maven repository Entry was Re: Codebase service?

Posted by Peter Firmstone <ji...@zeus.net.au>.
Hi Dennis,

Reasoning and hopefully the why's? below.

Dennis Reedy wrote:
> Hi Peter,
>
> I was hoping to take a step back for a second, perhaps its just me that seems to have my head spinning of late on this list. I may have missed some things, but we've discussed many issues over the past week:
>
> - How to advertise the DL jar(s) a service vends, allowing a client to download requisite jars that allow the jars to be loaded from a local (trusted) location
>   
Yes, we can use an Entry, or as Chris pointed out, if we annotate 
MarshalledInstance's using a new Maven URL schema we can extract that 
info and make it available via MarshalledServiceItem (An abstract class 
that extends ServiceItem).

> - Given the capability above, the need for a codebase service may not be required
>   
Agreed
> - Conventions on how to develop River services, as it relates to jar naming, packaging and what dependencies are between the various artifacts
> - How to possibly move forward with utilizing Maven repositories and the implied capabilities of published artifacts
> - The development of a maven archetype to allow a developer to easily create a working project in seconds
>   
Yes to all above.
> Your attention to detail and the documentation of how class loader interactions with regards to security is great. I'd like to understand the requirements of what you have documented below, the urge to refactor MarshalledInstance, and why the new class loader hierarchy needs to be added to River.
>   

The urge to refactor MarshalledInstance is to allow the URL annotation 
to be requested directly and passed via StreamServiceRegistrar and 
combined with delayed unmarshalling of proxy's via 
MarshalledServiceItem, to allow the client to provision and provide an 
alternate CodeSource if need be.

StreamServiceRegistrar returns a ResultStream<ServiceItem> , so you have 
check with instanceof MarshalledServiceItem.

The new packaging Scheme can be applied to distributed objects also, 
provided we create an implementation of CodebaseAccessClassLoader 
(contributed by Gregg to replace RMIClassLoaderSPI) that performs or 
requests local Maven archive provisioning.

The new ClassLoader hierarchy is needed, to solve class identity (fully 
qualified runtime classname = class + ClassLoader), class visibility, 
isolation and versioning problems, that PreferredClassProvider partially 
solves.
> Perhaps I'm just missing some fundamental issues, but maybe we need to take some time and determine the whys before the hows? Is this direction fundamental to the OSGi direction that you're taking? If so, how does this impact non-OSGi based systems?
>   
The changes are OSGi agnostic, OSGi will live in the application space, 
so while they benefit OSGi, they are independent of it, so the same 
benefits will apply to other software and OSGi isn't required.

I realised that fundamentally OSGi uses ClassLoaders for isolating 
software into components, so implementation classes aren't exposed 
outside of their module, something which OSGi does very well, it also 
manages security concerns very well.  Something else I realised, OSGi's 
use of ClassLoaders is not optimum for distributed systems, there are 
difficulties determining the correct ClassLoader during deserialization. 
OSGi wasn't designed with Serialization in mind.  Distributed computing 
introduces another dimension, like going from 2D to 3D,  in OSGi, you 
only have one bundle version combination loaded (you can have many 
bundles of different versions but I believe typically only one of each 
unique bundle instance, you can have the same package version exported 
by differently versioned bundles). So how do you determine the correct 
ClassLoader during unmarshalling.  In River we may have many proxy's 
using the same jar version, however we don't want the proxy's 
implementation to get all tied up in the local application bundles, we'd 
be allowing the smart proxy to pollute the local application space, some 
parts of the local application could see the proxy implementation.

In our new ClassLoader tree, a smart proxy can have it's own personal 
ClassLoader, because the ContextClassLoader will be that of the proxy's 
during returning object deserialization, since it initiated the 
communication with the remote Service host.  The reason a clients 
parameter implementation cannot have it's own ClassLoader and must share 
with other clients that use the same codebase and version is that they 
have no link to the ClassLoader at the remote Service host, with ony the 
Codebase and Version to go by, since they didn't initiate the 
communication, there could otherwise be many ClassLoaders containing 
that codebase version, there not enough information to find it, the last 
thing I want to do is require the client have an identity or location to 
deal with that deserialization of parameters at the Service node.

Rather than take, "how you use OSGi" and apply it to River, I decided to 
understand why they solved their problems the way they did and learn 
from it.  It is a very good solution to the problem they've solved.  
However with our solution we can solve the deserialization issue for 
distributed applications utilising OSGi.

Currently River uses Permission grants based on ClassLoader, (so does 
OSGi), what I realised was I needed a finer grained Permission grant and 
having many ProtectionDomain's inside one ClassLoader is about as fine 
as you can get.  Only one ClassLoader is used for the API space for 
class identity reasons, to allow maximum sharing of API classes because 
you just can't control and coordinate someone else's JVM's ClassLoader 
visibility, without overcoming some serious trust issues (Simpler is 
better I don't even want to attempt to solve them!). There is however 
one compromise with my approach.

By loading all API classes into the same ClassLoader, we cannot have 
duplicate classes, so we must always load the latest API version, that 
must not break backward compatibility. If the backward compatibility 
constraints are hampering your design, it's simply better to deprecate a 
package and append a number to change the package name.  (Or create a 
completely new API jar)

org.some.thing
org.some.thing2

The reason we version packages is so we don't have to rename them when 
they break backward compatibility, this makes sense for implementations, 
but not API.  If your going to have long lived persistent objects they 
belong in the API space, if you don't need to persist your objects, why 
not have an interface and throwaway class implementations, this solves 
Serialization exposing class internal state and evolution.  Extend the 
interface if you wan't new methods.

If a JVM has been running a long time, a new API version may have been 
released, clients using the old API functionality only, won't be able to 
see or utilise the new functionality until we restart the jvm.  That is 
the compromise.  But I figure it's not too bad a compromise once API's 
have stabilised and go into longer development cycles.  I can handle 
having to restart my JVM once every 6 months.

I think Michael Warres got to the crux of the problem with his 
publication on ClassLoader issues, my interpretation of what he said, is 
perhaps java should tear apart the multiple ClassLoader concerns, of 
Security, Isolation and Identity and start again.  I've chosen what 
appears to me to be the best compromise based on Java ClassLoader's today.

So this new ClassLoader hierarchy should play nice with Maven, OSGi and 
other stuff too, because now the API is visible to everything below in 
the ClassLoader hierarchy, while the implementations below, don't expose 
themselves, instead, everything cooperates through the API.

OSGi can be used to synchronize ClassLoader visibility between two 
separate JVM's, however that still requires the implementer deal with 
deserialization issues, with our solution, we won't have to worry much 
about ClassLoader issues.  With Maven, we won't have to worry about lost 
codebases either.

Yep, it has been a bit of a head spin, needed your help to work out the 
details before I forgot them.

There is one more detail, I'd like to include in the jar archive: a list 
of permissions the jar needs.  I'd like to use the same format OSGi 
uses, because it's been done before, why be different.  This is to solve 
the: "what grants does it need?" Problem. So we can minimise permission 
grants.

One more step towards the net...
> Thanks
>
> Dennis
>
> On May 24, 2010, at 1034PM, Peter Firmstone wrote:
>
>   
>> Thanks Chris,
>>
>> Sound like it's time for some MarshalledInstance Refactoring?
>>
>> Perhaps a Maven (generic if possible) URL schema (with message digest support), we need an annotation (or name convention) that indicates whether proxy's can share ClassLoader & ProtectionDomain space, dictated by static variables and common Principals.
>>
>> A new constructor for MarshalledInstance that accepts an alternate URL too.
>>
>> ... and two new methods in MarshalledInstance:
>> Object get(ClassLoader cl, CodeSource[] cs, boolean verifyCodeBaseIntegrity);
>> URL[] getCodeSourceAnnotation();
>>
>> Then MarshalledServiceItem could include new methods:
>>
>> public URL[] getCodeSourceAnnotation();
>> public Object getService( CodeSource[] cs );
>> //If cs == null || cs missing a CodeSource use default URL.
>>
>> Note here that while unmarshalling has been delayed, I haven't relinquished control of ClassLoaders or ProtectionDomains, eg the client can use OSGi, without dictating the Service must also, none of the serialized instances from method returns will need to be deserialized by OSGi, avoiding altogether the OSGi deserialization issue. 
>> The client application doesn't have to deal with these concerns directly, we could write multiple ResultStreamFilters that can be chained, the filter that matches the URL schema will unmarshall the service, the filter sequence will dictate the preferred unmarshalling.  The filter responsible for successful unmarshalling would construct a new ServiceItem, that isn't unmarshalled, the next unmarshalling filter would ignore it, allowing it to pass through.  After it is unmarshalled another filter will check method constraints.
>>
>> Method Parameters that originate from client ClassLoaders will be unmarshalled in the Application ClassLoader space on the Service implementation node, this is where things get hairy if the Service API method parameters are non final, abstract or interfaces.  Any class that belongs to a Service API jar will be safely loaded into the Jini Platform ClassLoader space in it's own ProtectionDomain.  Client returned parameter classes however will need their own ClassLoader's
>>
>> If the Service API is loaded into a Parent ClassLoader (Jini Platform ClassLoader) at the Service implementation node and API parameters are extended, the client classes will need their own ClassLoader space at the Service Implementation end, Since a service may serve many clients, these ClassLoaders must be shared, based on identical CodeSource and Principals.  The client classes will only be accessible via the Service API interfaces or classes (they are abstracted).
>>
>> ANY CLIENT THAT IMPLEMENTS AN API Interface or extends an API parameter, will need to make it's implementation package jar publicly available.  Like the proxy implementation, it is free to change, however it should be versioned appropriately, like the proxy and have it's own jar.  ( This is where the Java Package Version Spec comes in handy,  we can annotate classes with Package version and local CodeSource).  The CodeSource might contain a file URL, however it will contain the jar archive name (which is why Dennis want's to name packages with their versions, which can't hurt!) and given the Package Version Spec, it will work for OSGi bundles as well as Maven.  A client using an OSGi bundle must remember that all of the implementing classes should be in the same bundle and the Service node and may not be utilising OSGi, so shouldn't attempt to use any OSGi services in Service API parameter implementations.
>>
>> The version spec will identify compatiblity of classes, the closed compatible local CodeSource may be used, otherwise a new ClassLoader will be used.  Each client will either share all compatible CodeSource and Principals or have their own ClassLoader space.
>>
>> Greg, do you think we could use your service-client.jar for client parameter implementations or would this cause confusion?
>>
>> Perhaps we should use:
>>
>> service-param.jar
>>
>> So to really round if off:
>>
>> Service Implementers must produce versioned manifest jar archives of:
>>
>>   Smart Proxy:
>>
>>   Implementation jar: service.jar (depends on service-api.jar)
>>   API jar:            service-api.jar
>>   Smart proxy jar:    service-proxy.jar (depends on service-api.jar)
>>   Selfish Smart proxy jar:  service-iproxy.jar (depends on
>>   service-api.jar)
>>
>>   Dumb Proxy:
>>
>>   Implementation jar: service.jar (depends on service-api.jar)
>>   API jar:            service-api.jar
>>
>>
>> Client Implementers must produce version manifest jar archives of:
>>
>>   Client Parameter extensions:   service-param.jar
>>
>> If you didn't guess correctly the Selfish Smart proxy jar is the one that proxy's cannot share in the same ClassLoader and ProtectionDomain.
>>
>>
>> ClassLoader Structure (In addition to all your helpful comments on river-dev, thanks also to Jim, Tim & Mike, planting the seed):
>>
>>              System ClassLoader
>>                      |
>>             Extension ClassLoader (incl jsk-policy.jar)
>>                      |
>>             Jini Platform ClassLoader (incl jsk-platform.jar, *-api.jar)
>>                      |
>>       _______________|__________________________________
>>      |                            |                     |
>> Application ClassLoader    Proxy ClassLoader's    Parameter Impl ClassLoader's
>> (Apps & Service Impl)      (Smart Proxy's)        (Remote client parameter classes)
>>
>>
>> Advise History:
>>
>> Jim:     Use common Interfaces and classes in Parent ClassLoaders
>> Tim:    Thanks for research on Dependency Tree and ClassLoader Tree's and guidance.
>> Mike:  Research paper on ClassLoader issues.
>>
>> Thanks & Praise worth mentioning:
>>
>> Bob Scheifler and others for Jini's strong Security foundation.
>> Bill Venners for the ServiceUI, it is truly innovative
>>
>> (hint: come back)
>>
>>
>> Christopher Dolan wrote:
>>     
>>> Isn't List<URL> already present in the MarshalledInstance?  Why repeat
>>> this as an Entry?  Wouldn't it be easier to just add a public accessor
>>> to deserialize the list of URLs from MarshalledInstance.locBytes?
>>>
>>> I apologize if this was already explained, but there's been a LOT of
>>> email to read on this list lately.
>>>
>>> Chris
>>>
>>> -----Original Message-----
>>> From: Dennis Reedy [mailto:dennis.reedy@gmail.com] Sent: Saturday, May 22, 2010 9:29 AM
>>> To: river-dev@incubator.apache.org
>>> Subject: Re: Maven repository Entry was Re: Codebase service?
>>>
>>> [CJD] ... <snip> ...
>>>
>>> I would just go with a 
>>> List<String> dlJars;
>>>
>>> With this you could provide support for retrieving the DL jar(s) for
>>> non-maven systems as well. If the dlJars property contains 1 element and
>>> is of the form groupId:artifactId:version:classifier, then maven
>>> resolution gets used. Otherwise the DL jars can be obtained using the
>>> codebase of the advertising service.
>>>
>>> For maven resolution, I think you'll also want to either provide support
>>> for parsing your maven settings.xml or include the repositories to go
>>> find the artifact if it's not present. If the artifact is retrieved from
>>> the repository it will have a message digest along side of it (with
>>> either a .sha1 or .md5 extension). That can be used to compare a locally
>>> computed digest HttpmdUtil.computeDigest() for updates. But that
>>> comparison really only needs to take place for snapshots, since by
>>> definition releases are considered immutable.
>>>
>>> IMO supporting transitive deps is a must have, without that we really
>>> dont get that far. A DL artifact may depend on another DL artifact, and
>>> that DL artifact may have deps as well. 
>>>
>>>
>>>
>>>  
>>>       
>
>
>   




Re: Maven repository Entry was Re: Codebase service?

Posted by Dennis Reedy <de...@gmail.com>.
Hi Peter,

I was hoping to take a step back for a second, perhaps its just me that seems to have my head spinning of late on this list. I may have missed some things, but we've discussed many issues over the past week:

- How to advertise the DL jar(s) a service vends, allowing a client to download requisite jars that allow the jars to be loaded from a local (trusted) location
- Given the capability above, the need for a codebase service may not be required
- Conventions on how to develop River services, as it relates to jar naming, packaging and what dependencies are between the various artifacts
- How to possibly move forward with utilizing Maven repositories and the implied capabilities of published artifacts
- The development of a maven archetype to allow a developer to easily create a working project in seconds

Your attention to detail and the documentation of how class loader interactions with regards to security is great. I'd like to understand the requirements of what you have documented below, the urge to refactor MarshalledInstance, and why the new class loader hierarchy needs to be added to River. 

Perhaps I'm just missing some fundamental issues, but maybe we need to take some time and determine the whys before the hows? Is this direction fundamental to the OSGi direction that you're taking? If so, how does this impact non-OSGi based systems?

Thanks

Dennis

On May 24, 2010, at 1034PM, Peter Firmstone wrote:

> Thanks Chris,
> 
> Sound like it's time for some MarshalledInstance Refactoring?
> 
> Perhaps a Maven (generic if possible) URL schema (with message digest support), we need an annotation (or name convention) that indicates whether proxy's can share ClassLoader & ProtectionDomain space, dictated by static variables and common Principals.
> 
> A new constructor for MarshalledInstance that accepts an alternate URL too.
> 
> ... and two new methods in MarshalledInstance:
> Object get(ClassLoader cl, CodeSource[] cs, boolean verifyCodeBaseIntegrity);
> URL[] getCodeSourceAnnotation();
> 
> Then MarshalledServiceItem could include new methods:
> 
> public URL[] getCodeSourceAnnotation();
> public Object getService( CodeSource[] cs );
> //If cs == null || cs missing a CodeSource use default URL.
> 
> Note here that while unmarshalling has been delayed, I haven't relinquished control of ClassLoaders or ProtectionDomains, eg the client can use OSGi, without dictating the Service must also, none of the serialized instances from method returns will need to be deserialized by OSGi, avoiding altogether the OSGi deserialization issue. 
> The client application doesn't have to deal with these concerns directly, we could write multiple ResultStreamFilters that can be chained, the filter that matches the URL schema will unmarshall the service, the filter sequence will dictate the preferred unmarshalling.  The filter responsible for successful unmarshalling would construct a new ServiceItem, that isn't unmarshalled, the next unmarshalling filter would ignore it, allowing it to pass through.  After it is unmarshalled another filter will check method constraints.
> 
> Method Parameters that originate from client ClassLoaders will be unmarshalled in the Application ClassLoader space on the Service implementation node, this is where things get hairy if the Service API method parameters are non final, abstract or interfaces.  Any class that belongs to a Service API jar will be safely loaded into the Jini Platform ClassLoader space in it's own ProtectionDomain.  Client returned parameter classes however will need their own ClassLoader's
> 
> If the Service API is loaded into a Parent ClassLoader (Jini Platform ClassLoader) at the Service implementation node and API parameters are extended, the client classes will need their own ClassLoader space at the Service Implementation end, Since a service may serve many clients, these ClassLoaders must be shared, based on identical CodeSource and Principals.  The client classes will only be accessible via the Service API interfaces or classes (they are abstracted).
> 
> ANY CLIENT THAT IMPLEMENTS AN API Interface or extends an API parameter, will need to make it's implementation package jar publicly available.  Like the proxy implementation, it is free to change, however it should be versioned appropriately, like the proxy and have it's own jar.  ( This is where the Java Package Version Spec comes in handy,  we can annotate classes with Package version and local CodeSource).  The CodeSource might contain a file URL, however it will contain the jar archive name (which is why Dennis want's to name packages with their versions, which can't hurt!) and given the Package Version Spec, it will work for OSGi bundles as well as Maven.  A client using an OSGi bundle must remember that all of the implementing classes should be in the same bundle and the Service node and may not be utilising OSGi, so shouldn't attempt to use any OSGi services in Service API parameter implementations.
> 
> The version spec will identify compatiblity of classes, the closed compatible local CodeSource may be used, otherwise a new ClassLoader will be used.  Each client will either share all compatible CodeSource and Principals or have their own ClassLoader space.
> 
> Greg, do you think we could use your service-client.jar for client parameter implementations or would this cause confusion?
> 
> Perhaps we should use:
> 
> service-param.jar
> 
> So to really round if off:
> 
> Service Implementers must produce versioned manifest jar archives of:
> 
>   Smart Proxy:
> 
>   Implementation jar: service.jar (depends on service-api.jar)
>   API jar:            service-api.jar
>   Smart proxy jar:    service-proxy.jar (depends on service-api.jar)
>   Selfish Smart proxy jar:  service-iproxy.jar (depends on
>   service-api.jar)
> 
>   Dumb Proxy:
> 
>   Implementation jar: service.jar (depends on service-api.jar)
>   API jar:            service-api.jar
> 
> 
> Client Implementers must produce version manifest jar archives of:
> 
>   Client Parameter extensions:   service-param.jar
> 
> If you didn't guess correctly the Selfish Smart proxy jar is the one that proxy's cannot share in the same ClassLoader and ProtectionDomain.
> 
> 
> ClassLoader Structure (In addition to all your helpful comments on river-dev, thanks also to Jim, Tim & Mike, planting the seed):
> 
>              System ClassLoader
>                      |
>             Extension ClassLoader (incl jsk-policy.jar)
>                      |
>             Jini Platform ClassLoader (incl jsk-platform.jar, *-api.jar)
>                      |
>       _______________|__________________________________
>      |                            |                     |
> Application ClassLoader    Proxy ClassLoader's    Parameter Impl ClassLoader's
> (Apps & Service Impl)      (Smart Proxy's)        (Remote client parameter classes)
> 
> 
> Advise History:
> 
> Jim:     Use common Interfaces and classes in Parent ClassLoaders
> Tim:    Thanks for research on Dependency Tree and ClassLoader Tree's and guidance.
> Mike:  Research paper on ClassLoader issues.
> 
> Thanks & Praise worth mentioning:
> 
> Bob Scheifler and others for Jini's strong Security foundation.
> Bill Venners for the ServiceUI, it is truly innovative
> 
> (hint: come back)
> 
> 
> Christopher Dolan wrote:
>> Isn't List<URL> already present in the MarshalledInstance?  Why repeat
>> this as an Entry?  Wouldn't it be easier to just add a public accessor
>> to deserialize the list of URLs from MarshalledInstance.locBytes?
>> 
>> I apologize if this was already explained, but there's been a LOT of
>> email to read on this list lately.
>> 
>> Chris
>> 
>> -----Original Message-----
>> From: Dennis Reedy [mailto:dennis.reedy@gmail.com] Sent: Saturday, May 22, 2010 9:29 AM
>> To: river-dev@incubator.apache.org
>> Subject: Re: Maven repository Entry was Re: Codebase service?
>> 
>> [CJD] ... <snip> ...
>> 
>> I would just go with a 
>> List<String> dlJars;
>> 
>> With this you could provide support for retrieving the DL jar(s) for
>> non-maven systems as well. If the dlJars property contains 1 element and
>> is of the form groupId:artifactId:version:classifier, then maven
>> resolution gets used. Otherwise the DL jars can be obtained using the
>> codebase of the advertising service.
>> 
>> For maven resolution, I think you'll also want to either provide support
>> for parsing your maven settings.xml or include the repositories to go
>> find the artifact if it's not present. If the artifact is retrieved from
>> the repository it will have a message digest along side of it (with
>> either a .sha1 or .md5 extension). That can be used to compare a locally
>> computed digest HttpmdUtil.computeDigest() for updates. But that
>> comparison really only needs to take place for snapshots, since by
>> definition releases are considered immutable.
>> 
>> IMO supporting transitive deps is a must have, without that we really
>> dont get that far. A DL artifact may depend on another DL artifact, and
>> that DL artifact may have deps as well. 
>> 
>> 
>> 
>>  
> 


Re: Maven repository Entry was Re: Codebase service?

Posted by Peter Firmstone <ji...@zeus.net.au>.
Thanks Chris,

Sound like it's time for some MarshalledInstance Refactoring?

Perhaps a Maven (generic if possible) URL schema (with message digest 
support), we need an annotation (or name convention) that indicates 
whether proxy's can share ClassLoader & ProtectionDomain space, dictated 
by static variables and common Principals.

A new constructor for MarshalledInstance that accepts an alternate URL too.

... and two new methods in MarshalledInstance:
Object get(ClassLoader cl, CodeSource[] cs, boolean 
verifyCodeBaseIntegrity);
URL[] getCodeSourceAnnotation();

Then MarshalledServiceItem could include new methods:

public URL[] getCodeSourceAnnotation();
public Object getService( CodeSource[] cs );
//If cs == null || cs missing a CodeSource use default URL.

Note here that while unmarshalling has been delayed, I haven't 
relinquished control of ClassLoaders or ProtectionDomains, eg the client 
can use OSGi, without dictating the Service must also, none of the 
serialized instances from method returns will need to be deserialized by 
OSGi, avoiding altogether the OSGi deserialization issue. 

The client application doesn't have to deal with these concerns 
directly, we could write multiple ResultStreamFilters that can be 
chained, the filter that matches the URL schema will unmarshall the 
service, the filter sequence will dictate the preferred unmarshalling.  
The filter responsible for successful unmarshalling would construct a 
new ServiceItem, that isn't unmarshalled, the next unmarshalling filter 
would ignore it, allowing it to pass through.  After it is unmarshalled 
another filter will check method constraints.

Method Parameters that originate from client ClassLoaders will be 
unmarshalled in the Application ClassLoader space on the Service 
implementation node, this is where things get hairy if the Service API 
method parameters are non final, abstract or interfaces.  Any class that 
belongs to a Service API jar will be safely loaded into the Jini 
Platform ClassLoader space in it's own ProtectionDomain.  Client 
returned parameter classes however will need their own ClassLoader's

If the Service API is loaded into a Parent ClassLoader (Jini Platform 
ClassLoader) at the Service implementation node and API parameters are 
extended, the client classes will need their own ClassLoader space at 
the Service Implementation end, Since a service may serve many clients, 
these ClassLoaders must be shared, based on identical CodeSource and 
Principals.  The client classes will only be accessible via the Service 
API interfaces or classes (they are abstracted).

ANY CLIENT THAT IMPLEMENTS AN API Interface or extends an API parameter, 
will need to make it's implementation package jar publicly available.  
Like the proxy implementation, it is free to change, however it should 
be versioned appropriately, like the proxy and have it's own jar.  ( 
This is where the Java Package Version Spec comes in handy,  we can 
annotate classes with Package version and local CodeSource).  The 
CodeSource might contain a file URL, however it will contain the jar 
archive name (which is why Dennis want's to name packages with their 
versions, which can't hurt!) and given the Package Version Spec, it will 
work for OSGi bundles as well as Maven.  A client using an OSGi bundle 
must remember that all of the implementing classes should be in the same 
bundle and the Service node and may not be utilising OSGi, so shouldn't 
attempt to use any OSGi services in Service API parameter implementations.

The version spec will identify compatiblity of classes, the closed 
compatible local CodeSource may be used, otherwise a new ClassLoader 
will be used.  Each client will either share all compatible CodeSource 
and Principals or have their own ClassLoader space.

Greg, do you think we could use your service-client.jar for client 
parameter implementations or would this cause confusion?

Perhaps we should use:

service-param.jar

So to really round if off:

Service Implementers must produce versioned manifest jar archives of:

    Smart Proxy:

    Implementation jar: service.jar (depends on service-api.jar)
    API jar:            service-api.jar
    Smart proxy jar:    service-proxy.jar (depends on service-api.jar)
    Selfish Smart proxy jar:  service-iproxy.jar (depends on
    service-api.jar)

    Dumb Proxy:

    Implementation jar: service.jar (depends on service-api.jar)
    API jar:            service-api.jar


Client Implementers must produce version manifest jar archives of:

    Client Parameter extensions:   service-param.jar

If you didn't guess correctly the Selfish Smart proxy jar is the one 
that proxy's cannot share in the same ClassLoader and ProtectionDomain.


ClassLoader Structure (In addition to all your helpful comments on 
river-dev, thanks also to Jim, Tim & Mike, planting the seed):

               System ClassLoader
                       |
              Extension ClassLoader (incl jsk-policy.jar)
                       |
              Jini Platform ClassLoader (incl jsk-platform.jar, *-api.jar)
                       |
        _______________|__________________________________
       |                            |                     |
Application ClassLoader    Proxy ClassLoader's    Parameter Impl 
ClassLoader's
(Apps & Service Impl)      (Smart Proxy's)        (Remote client 
parameter classes)


Advise History:

Jim:     Use common Interfaces and classes in Parent ClassLoaders
Tim:    Thanks for research on Dependency Tree and ClassLoader Tree's 
and guidance.
Mike:  Research paper on ClassLoader issues.

Thanks & Praise worth mentioning:

Bob Scheifler and others for Jini's strong Security foundation.
Bill Venners for the ServiceUI, it is truly innovative

(hint: come back)


Christopher Dolan wrote:
> Isn't List<URL> already present in the MarshalledInstance?  Why repeat
> this as an Entry?  Wouldn't it be easier to just add a public accessor
> to deserialize the list of URLs from MarshalledInstance.locBytes?
>
> I apologize if this was already explained, but there's been a LOT of
> email to read on this list lately.
>
> Chris
>
> -----Original Message-----
> From: Dennis Reedy [mailto:dennis.reedy@gmail.com] 
> Sent: Saturday, May 22, 2010 9:29 AM
> To: river-dev@incubator.apache.org
> Subject: Re: Maven repository Entry was Re: Codebase service?
>
> [CJD] ... <snip> ...
>
> I would just go with a 
>
> List<String> dlJars;
>
> With this you could provide support for retrieving the DL jar(s) for
> non-maven systems as well. If the dlJars property contains 1 element and
> is of the form groupId:artifactId:version:classifier, then maven
> resolution gets used. Otherwise the DL jars can be obtained using the
> codebase of the advertising service.
>
> For maven resolution, I think you'll also want to either provide support
> for parsing your maven settings.xml or include the repositories to go
> find the artifact if it's not present. If the artifact is retrieved from
> the repository it will have a message digest along side of it (with
> either a .sha1 or .md5 extension). That can be used to compare a locally
> computed digest HttpmdUtil.computeDigest() for updates. But that
> comparison really only needs to take place for snapshots, since by
> definition releases are considered immutable.
>
> IMO supporting transitive deps is a must have, without that we really
> dont get that far. A DL artifact may depend on another DL artifact, and
> that DL artifact may have deps as well. 
>
>
>
>
>   


RE: Maven repository Entry was Re: Codebase service?

Posted by Christopher Dolan <ch...@avid.com>.
Isn't List<URL> already present in the MarshalledInstance?  Why repeat
this as an Entry?  Wouldn't it be easier to just add a public accessor
to deserialize the list of URLs from MarshalledInstance.locBytes?

I apologize if this was already explained, but there's been a LOT of
email to read on this list lately.

Chris

-----Original Message-----
From: Dennis Reedy [mailto:dennis.reedy@gmail.com] 
Sent: Saturday, May 22, 2010 9:29 AM
To: river-dev@incubator.apache.org
Subject: Re: Maven repository Entry was Re: Codebase service?

[CJD] ... <snip> ...

I would just go with a 

List<String> dlJars;

With this you could provide support for retrieving the DL jar(s) for
non-maven systems as well. If the dlJars property contains 1 element and
is of the form groupId:artifactId:version:classifier, then maven
resolution gets used. Otherwise the DL jars can be obtained using the
codebase of the advertising service.

For maven resolution, I think you'll also want to either provide support
for parsing your maven settings.xml or include the repositories to go
find the artifact if it's not present. If the artifact is retrieved from
the repository it will have a message digest along side of it (with
either a .sha1 or .md5 extension). That can be used to compare a locally
computed digest HttpmdUtil.computeDigest() for updates. But that
comparison really only needs to take place for snapshots, since by
definition releases are considered immutable.

IMO supporting transitive deps is a must have, without that we really
dont get that far. A DL artifact may depend on another DL artifact, and
that DL artifact may have deps as well. 




Re: Maven repository Entry was Re: Codebase service?

Posted by Dennis Reedy <de...@gmail.com>.
On May 22, 2010, at 717AM, Patrick Wright wrote:

> Hi
> 
> On Sat, May 22, 2010 at 12:38 PM, Peter Firmstone <ji...@zeus.net.au> wrote:
>> Since we've got a few Maven people on the list how should we best approach
>> utilising the Maven repository?
>> 
>> Patrick, have you got something in mind for a Codebase Entry?
> 
> I'll just brainstorm here a bit. Let's keep the example simple to
> start with: a service has registered itself in the LUS, and has entry
> meta-data indicating which JAR files must be on the classpath, or must
> be downloaded (the "impl" JAR, or -dl.jar files). Let's assume that
> these JAR files have already been installed in the Maven repository of
> the local, client, machine. In Maven terminology, we want the service
> to specify the coordinates[1] to the artifacts required;

In general the DL jar is derivable if you know the service's main artifact (the impl jar). The way we've done this is to simply use a "dl" classifier to distinguish the DL jar (and "ui" classifie for the ui jar). The same can be done for the api jar as well.

Something to think about up front is that you also need to figure out how to build a service using maven, especially since with a Jini type system a service has multiple artifacts, up to 4 (impl, dl, ui, api).

If you're interested in work thats been completed surrounding these areas, please check out http://www.rio-project.org/resolver.html and http://www.rio-project.org/classdepandjar-mojo.html for info on utilities surrounding the construction and resolving of artifacts. I only mention this because it may help refine some thoughts and goals you're trying to achieve here. If anything makes sense for you to use, I'd be glad to help.


> these
> coordinates need to be present in an array of Entry instances in the
> service registration
> 
> MavenBasedServiceEntry {
>  public MavenCoordinateEntry[] coordinatesToRequiredArtifacts;
> }
> 
> MavenCoordinateEntry {
>  public String groupId;
>  public String artifactId;
>  public String version;
>  public String classifier;
>  public byte[] optionalArtifactHash;
>  public int optionalHashConstantIdentifier; // e.g. SHA1
> }
> 
> 

I would just go with a 

List<String> dlJars;

With this you could provide support for retrieving the DL jar(s) for non-maven systems as well. If the dlJars property contains 1 element and is of the form groupId:artifactId:version:classifier, then maven resolution gets used. Otherwise the DL jars can be obtained using the codebase of the advertising service.

For maven resolution, I think you'll also want to either provide support for parsing your maven settings.xml or include the repositories to go find the artifact if it's not present. If the artifact is retrieved from the repository it will have a message digest along side of it (with either a .sha1 or .md5 extension). That can be used to compare a locally computed digest HttpmdUtil.computeDigest() for updates. But that comparison really only needs to take place for snapshots, since by definition releases are considered immutable.

IMO supporting transitive deps is a must have, without that we really dont get that far. A DL artifact may depend on another DL artifact, and that DL artifact may have deps as well. 




Re: Maven repository Entry was Re: Codebase service?

Posted by Patrick Wright <pd...@gmail.com>.
Hi

On Sat, May 22, 2010 at 12:38 PM, Peter Firmstone <ji...@zeus.net.au> wrote:
> Since we've got a few Maven people on the list how should we best approach
> utilising the Maven repository?
>
> Patrick, have you got something in mind for a Codebase Entry?

I'll just brainstorm here a bit. Let's keep the example simple to
start with: a service has registered itself in the LUS, and has entry
meta-data indicating which JAR files must be on the classpath, or must
be downloaded (the "impl" JAR, or -dl.jar files). Let's assume that
these JAR files have already been installed in the Maven repository of
the local, client, machine. In Maven terminology, we want the service
to specify the coordinates[1] to the artifacts required; these
coordinates need to be present in an array of Entry instances in the
service registration

MavenBasedServiceEntry {
  public MavenCoordinateEntry[] coordinatesToRequiredArtifacts;
}

MavenCoordinateEntry {
  public String groupId;
  public String artifactId;
  public String version;
  public String classifier;
  public byte[] optionalArtifactHash;
  public int optionalHashConstantIdentifier; // e.g. SHA1
}

Normally, the coordinates are converted into a path relative to a
"local Maven repository". The local repository installs by default to
~/.m2/repository, though when using the Maven tools the location can
be overridden with a property setting. River should probably also
allow overriding this location.

The group id is normally a Java package name, e.g. net.jini or
com.sun.jini. The dots are converted to directory separators. The
artifact name is another directory, the version is yet another, and
the classifier is usually appended to the end of the artifact name.
Note that classifier is often left out and can be used when you
publish different artifacts for a single module. So if I need
commons-io 1.3.2, the path would be

~/.m2/repository/org/apache/commons/commons-io/1.3.2/commons-io-1.3.2.jar

The artifact (commons-io-1.3.2.jar) may or may not have a version
number in the name; it's up to the package distributor to decide.

In this simple case, if you assume the artifacts are already
downloaded locally, you just need to read the entry instances and
build a class path entry pointing to the JAR file. It's common, but
not required, for a hash file to be included in the distribution,
which could be used for verification.

Phase 2 would be to use the Maven machinery to download the file if it
isn't present locally. You can configure your local Maven settings
with a list of remote repositories to query for the artifact. I don't
think I would include that in River itself, but it may be nice for
people to know how to bind it in if they need it. It simplifies
distribution, because the deployment manager just pushes the artifact
to an upstream repository, and clients synchronize those artifacts to
their local repositories lazily, when they first need them. River
could use the embedded Maven support to handle this synchronization,
as a pluggable utility.

Phase 3 might be adding support for transitive dependencies. This
would be helpful for cases where the -dl.jar/impl required 3rd-party
libraries that might not be present in the client already. I'm
hesitant to say you should support automatic transitive dependency
resolution, which Maven supports, as it's not always perfect--you
sometimes include much more in your classpath than is really needed
because the dependency lists upstream haven't been properly
maintained. A better approach would be just to include those in the
Entry array as separate items.

I think adding support for using the Maven repository is at least a
short-term win. However, in the wider open-source JVM community there
is a good deal of anti-Maven sentiment, although some build tools
(Groovy has one, and Clojure as well) use their own configuration
system but rely on the Maven repositories for artifact management,
just because so much of the infrastructure is already in place and
there is such a mass of 3rd-party libraries already available in Maven
repositories online. I mention this because medium term, if for River
you decide that the coordinate system is a decent way of uniquely
identifying an artifact, then the resolution from coordinate to local
path can be handled in various ways, e.g. it's just a Strategy that
can be selected by the developer.

There are a few corner cases to handle which we can discuss later.

Anyway, this is a bit of brainstorming on how I think this might work.
I think it's enough to prototype with.

Regards
Patrick


[1] http://maven.apache.org/pom.html#Maven_Coordinates