On Thursday 28 of October 2010 10:36:38 Peter Firmstone wrote: > Ok Interesting, anyone implementing a Service should be quite capable of > implementing equals, we should then specify that equals and hashcode > methods should be implemented for ProxyTrust. > > For my benefit can you go over the process of how your new code works? > I'm interested in the choices you've made & why. >
Sure. Several choices were made because: 1. I wanted to reuse as much as possible from existing River 2. I wanted to have a working prototype fast :) Anyway: 1. The main idea is to have annotations as objects that could be verified using standard River proxy verification facilities. To be honest the idea of having Module interface that enables plugging different classloading mechanisms is something completely optional. 2. For the client the basic scenario is: a) The client gets a serialized object b) When it is deserialized annotations (Modules) are read and "installed" c) Installing a Module means: c1) checking if it was already installed c2) if not - prepare it using VerifyingProxyPreparer (I've choosen not to place any InvocationConstraints on Modules - I don't think it is necessary) d) after a Module is installed it is used to load classes 3. There are several places in River that depend on annotations being Strings provided by RMIClassLoader. The most important places are a) Discovery b) Reggie implementation c) ProxyTrustVerifier Since I did not want to modify this code I had to implement RMIClassLoaderSpi so that it would provide serialized Modules as Strings. I've choosen to simply serialize them to byte arrays and Base64 encode them. 4. There are two important Module implementations available: a) DefaultRmiModule b) ProxyTrustModule DefaultRmiModule can be trusted by the client without contacting any service - it uses RequireDlPermissionClassProvider to load classes. ProxyTrustModule on the other hand uses a simple PreferredClassProvider to load classes. It is a smart proxy that implements getProxyTrustIterator() so that it can be verified by ProxyTrustVerifier. On the server before we can annotate our objects with modules we have to register a Module that will be used as annotation. If the server does not register any Module - DefaultRmiModule is going to be used as annotation. The server can register a ProxyTrustModule as annotation - to do that it first must export an object that can be contacted to obtain a Module verifier. In other words - a service must either: a) export two ProxyTrusts (one for Modules and another one for the service itself) b) its ProxyTrust must provide a verifier that is able to verify both a Module and a service proxy To make it possible to use my code with existing services without modifying them I've decided to implement a special ModuleExporter which will override the service ServerProxyTrust implementation so that getProxyVerifier will return a Verifier capable of verifying both a Module and the service proxy. This verifier works as follows: 1. Check if an object being verified is a Module. 2. If so - delegate to a module verifier 3. If not it means we're verifying a service proxy so delegate to a default verifier. The problem is though that when this verifier is deserialized the module that is capable of loading the service proxy verifier is not yet installed (the client got this verifier to verify a Module before it can load any classes). That's why I called it LazyCompositeVerifier - the default verifier is not deserialized until it is actually needed. The only problem left is that every time a client gets a service proxy it will issue a remote call twice to get a verifier: first to get a verifier for a Module and then to get a verifier for a service proxy. But it is going to be the same verifier!!! So I've decided to implement a CachingProxyTrust that 1) can be trusted by the client without the need to issue any remote call (so we need a CachingProxyTrustVerifier configured on the client) 2) Will cache a verifier it obtains from its delegate The problem with CachingProxyTrust is that it has to be used by: a) a Module b) a service proxy That's why we need OverrideProxy - it is returned from ModuleExporter to the service so that the service is unaware of the CachingProxyTrust but still can use it to obtain its verifier. To trust OverrideProxy the client has to have OverrideProxyVerifier configured locally. I hope I clarified everything a little bit... Michal
