river-dev mailing list archives

Site index · List index
Message view « Date » · « Thread »
Top « Date » · « Thread »
From Peter Firmstone <j...@zeus.net.au>
Subject Re: Service API, class visibility, isolation and garbage collection - ClassLoaders
Date Wed, 26 May 2010 22:11:04 GMT
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.
       
>>>>>>>               
>>>>>  
>>>>>           
>>>>
>>>>         
>>>       
>
>
>   


Mime
View raw message