river-dev mailing list archives

Site index · List index
Message view « Date » · « Thread »
Top « Date » · « Thread »
From Bharath Kumar <bharathkuma...@gmail.com>
Subject Re: OSGi
Date Fri, 27 Jan 2017 17:39:57 GMT
Yes Peter. Usage of thread context class loader is discouraged in OSGi
environment.

http://njbartlett.name/2012/10/23/dreaded-thread-context-classloader.html

Some of the problems are hard to solve in OSGi environment. For example,
creating dynamic java proxy from 2 or more interfaces that are located in
different bundles.

http://blog.osgi.org/2008/08/classy-solutions-to-tricky-proxies.html?m=1

This problem can be solved using composite class loader. But it is
difficult to write it correctly. Because OSGi environment is dynamic.

I believe that it is possible to provide enough abstraction in river code,
so that service developers don't even require to use context class loader
in their services.



Thanks & Regards,
Bharath


On 27-Jan-2017 6:25 PM, "Peter" <jini@zeus.net.au> wrote:

> Thanks Gregg,
>
> Thoughts inline below.
>
> Cheers,
>
> Peter.
>
>
> On 27/01/2017 12:35 AM, Gregg Wonderly wrote:
>
>> Is there any thought here about how a single client might use both an
>> OSGi deployed service and a conventionally deployed service?
>>
>
> Not yet, I'm currently considering how to support OSGi by implementing an
> RMIClassLoaderSPI, similar to how Dennis has for Maven in Rio.
>
> I think once a good understanding of OSGi has developed, we can consider
> how an implementation could support that, possibly by exploiting something
> like Pax URL built into PreferredClassProvider.
>
>
>   The ContextClassLoader is a good abstraction mechanism for finding “the”
>> approriate class loader.  It allows applications to deploy a composite
>> class loader in some form that would be able to resolve classes from many
>> sources and even provide things like preferred classes.
>>
>
> Yes, it works well for conventional frameworks and is utilised by
> PreferredClassProvider, but it's use in OSGi is discouraged, I'd like to
> consider how it's use can be avoided in an OSGi env.
>
>
>>
>> In a Java desktop application, would a transition from a background
>> thread, interacting with a service to get an object from a service which is
>> not completely resolved to applicable loaders still resolve correctly in an
>> EventDispatch Thread?  That event dispatch thread can have the context
>> class loader set on it by the thread which got the object, to be the class
>> loader of the service object, to make sure that the resolution of classes
>> happens with the correct class loader such that there will not be a problem
>> with the service object having one set of definitions and another service
>> or the application classpath having a conflicting class definition by the
>> same name.
>>
>> I’ve had to spend quite a bit of time to make sure that these scenarios
>> work correctly in my Swing applications.
>>
>
> Have you got more information?  I'm guessing this relates to delayed
> unmarshalling into the EventDispatch thread.
>
> It's early days yet, I'm still working it out what information is required
> to resolve the correct ClassLoaders & bundles, but this is an important
> question, Bharath mentioned Entry's can be utilised for versioning and this
> seems like a good idea.
>
> What follows are thoughts and observations.
>
> A bundle can be created from a URL, provided the codebase the URL refers
> to has an OSGi bundle manifest, so this could allow any of the existing URL
> formats to deliver a proxy codebase for an OSGi framework.  When OSGi loads
> the bundle, the package dependencies will be wired up by the local env.  If
> the URL doesn't reference a bundle, then we could use Bharath's approach
> and subclass the client's ClassLoader, this does make all the clients
> classes visible to the proxy however, but that would happen anyway in a
> standard Jini / River environment.
>
> OSGi gives preference to already loaded bundles when resolving package
> dependencies, so the client should be careful not to unmarshall any proxy's
> that might require a higher version than the bundle already installed when
> the client bundle resolved its dependencies.
>
> One of the proxy bundle dependencies will be the service api bundle.  The
> proxy bundle can limit the service api package / packages to a specific
> version or version range, which it could advertise in an Entry.  Boolean
> logic comparison of Entry's would have to be performed locally, after
> matching on the service type (this requires delayed unmarshalling to
> prevent the resolution of unwanted versions).
>
> So, the OSGi bundles installed in remote JVM's communicating with each
> other, may not be exactly the same version, but should be compatible.
> Multiple versions of a package or bundle may be available in a JVM, so we
> need to ensure we've selected one imported by the proxy.
>
> We could define a simple rule, that the first URL in an annotation, must
> be the proxy bundle, with all dependencies to be provisioned by the OSGi
> Framework, which would allow the same codebase annotation to be utilised in
> a non OSGi environment, but this will probably mean the loss of any
> trailing URL annotations if the proxy's remarshalled.
>
> Once the proxy bundle has been loaded, its ClassLoader needs to be the
> default for the remaining stream classes (smart proxy fields), since it
> knows the most about what dependencies are required, these will be visible
> to the proxy's ClassLoader.
>
> If a class doesn't have an existing ClassLoader referenced by annotatation
> and cannot be resolved from the proxy's Bundle, it probably requres a new
> bundle to be resolved.
>
> What's next?  Determine what annotations to retrieve from OSGi Bundles.
>
> How PreferredClassProvider currently obtains codebase annotations (Trivia:
> the application/system ClassLoader is a URLClassLoader up to Java 8, but is
> no longer an instance of URLClassLoader in Java 9):
>
> Summary, If ClassLoader:
>
>   1. Is local loader? return java.rmi.server.codebase property or null
>      if not defined.
>   2. Is instance of ClassAnnoation, get annotation and return.
>   3. Is instance of URLClassLoader, get URL's as string and return.
>   4. else return java.rmi.server.codebase property or null if not defined.
>
>
> /**
>      * Returns the annotation string for the specified class loader
>      * (possibly null).  If check is true and the annotation would be
>      * determined from an invocation of URLClassLoader.getURLs() on
>      * the loader, only return the true annotation if the current
>      * security context has permission to connect to all of the URLs.
>      **/
>     private String getLoaderAnnotation(ClassLoader loader, boolean check)
> {
>
>     if (isLocalLoader(loader)) {
>         return getClassAnnotation(loader);
>     }
>
>         /*
>      * Get the codebase URL path for the class loader, if it supports
>      * such a notion (i.e., if it is a URLClassLoader or subclass).
>      */
>     String annotation = null;
>     if (loader instanceof ClassAnnotation) {
>         /*
>          * If the class loader is one of our RMI class loaders, we have
>          * already computed the class annotation string, and no
>          * permissions are required to know the URLs.
>          */
>         annotation = ((ClassAnnotation) loader).getClassAnnotation();
>
>     } else if (loader instanceof java.net.URLClassLoader) {
>         try {
>         URL[] urls = ((java.net.URLClassLoader) loader).getURLs();
>         if (urls != null) {
>             if (check) {
>             SecurityManager sm = System.getSecurityManager();
>             if (sm != null) {
>                 Permissions perms = new Permissions();
>                 for (int i = 0; i < urls.length; i++) {
>                 Permission p =
>                     urls[i].openConnection().getPermission();
>                 if (p != null) {
>                     if (!perms.implies(p)) {
>                     sm.checkPermission(p);
>                     perms.add(p);
>                     }
>                 }
>                 }
>             }
>             }
>             annotation = PreferredClassLoader.urlsToPath(urls);
>         }
>         } catch (SecurityException e) {
>         /*
>          * If access was denied to the knowledge of the class
>          * loader's URLs, fall back to the default behavior.
>          */
>         } catch (IOException e) {
>         /*
>          * This shouldn't happen, although it is declared to be
>          * thrown by openConnection() and getPermission().  If it
>          * does happen, forget about this class loader's URLs and
>          * fall back to the default behavior.
>          */
>         }
>     }
>
>     if (annotation != null) {
>         return annotation;
>     } else {
>         return getClassAnnotation(loader);
>     }
>     }
>
> /**
>      * Returns the annotation string for the specified class loader.
>      *
>      * <p>This method is invoked in order to determine the annotation
>      * string for the system class loader, an ancestor of the system
>      * class loader, any class loader that is not an instance of
>      * {@link ClassAnnotation} or {@link URLClassLoader}, or (for an
>      * invocation of {@link #getClassAnnotation(Class)
>      * getClassAnnotation(Class)}) a <code>URLClassLoader</code> for
>      * which the current security context does not have the
>      * permissions necessary to connect to all of its URLs.
>      *
>      * <p><code>PreferredClassProvider</code> implements this method
>      * as follows:
>      *
>      * <p>This method returns the value of the system property
>      * <code>"java.rmi.server.codebase"</code> (or possibly an earlier
>      * cached value).
>      *
>      * @param loader the class loader to obtain the annotation string
>      * for
>      *
>      * @return the annotation string for the class loader, or
>      * <code>null</code>
>      **/
>     protected String getClassAnnotation(ClassLoader loader) {
>     checkInitialized();
>     return codebaseProperty;
>     }
>
>
> Gregg
>>
>> On Jan 20, 2017, at 6:08 PM, Peter<jini@zeus.net.au>  wrote:
>>>
>>> Looking at your modifications to ServiceDiscoveryManager, I noticed
>>> you've made changes to set the context ClassLoader prior to calling the
>>> lookup service.
>>>
>>> This is eventually utilised by PreferredClassProvider to lookup the
>>> necessary loader to utilise for deserialization of the lookup results.
>>>
>>> I think if we develop a RMIClassLoader provider for OSGi, we can avoid
>>> utilising the context ClassLoader.
>>>
>>> Since all OSGi ClassLoader's are instances of BundleReference, it's easy
>>> to utilise OSGi bundle url anotations (I think this needs to incorporate
>>> bundle versions).  I'd also like to utilise Java 9 jrt style URL's.
>>>
>>> Cheers,
>>>
>>> Peter.
>>>
>>> On 20/01/2017 11:09 PM, Bharath Kumar wrote:
>>>
>>>> Thanks Peter for the review.
>>>>
>>>> While creating this POC, I tried to make RIO framework as set of OSGI.
>>>> bundles. Rio project extends LookupDiscoveryManager class in one of the
>>>> class .org.rioproject.impl.client.DiscoveryManagementPool.SharedDi
>>>> scoveryManager.
>>>> That's why I removed the final modifier.
>>>>
>>>>
>>>> Regarding groovy files,
>>>> I have made the org.apache.river as system fragment bundle. So we can't
>>>> import any packages from other bundles. But we can use system bundle's
>>>> packages,. That's why i removed groovy files. If we use these groovy
>>>> files,
>>>> we need to import packages from groovy bundle which is not possible
>>>> here. I
>>>> will check JGDMS to see how it is used.
>>>>
>>>>
>>>> Thanks&   Regards,
>>>> Bharath
>>>>
>>>>
>>>> On Fri, Jan 20, 2017 at 6:09 PM, Peter<jini@zeus.net.au>   wrote:
>>>>
>>>> Hi Bharath,
>>>>>
>>>>> Re your changes (I've found so far):
>>>>>
>>>>> LookupDiscoveryManager is non final, I'm interested why?
>>>>>
>>>>> BasicInvocationDispatcher, you've set the context class loader around
a
>>>>> block of code, to use the ClassLoader passed in during construction.
>>>>> I'm
>>>>> currently investigating addong methods where ClassLoader can be passed
>>>>> in
>>>>> for OSGi.
>>>>>
>>>>> Regarding bundle structure, I've restructured the layout here (so you
>>>>> don't need to delete Groovy config):
>>>>>
>>>>> https://github.com/pfirmstone/JGDMS/tree/Maven_build/modularize/JGDMS
>>>>>
>>>>> The full commit history has been retained, so u can see all changes.
>>>>>
>>>>> Cheers,
>>>>>
>>>>> Peter.
>>>>>
>>>>> Sent from my Samsung device.
>>>>>
>>>>>   Include original message
>>>>> ---- Original message ----
>>>>> From: Bharath Kumar<bharathkumar.a@gmail.com>
>>>>> Sent: 20/01/2017 09:42:38 pm
>>>>> To: dev@river.apache.org
>>>>> Subject: Re: OSGi
>>>>>
>>>>> Hello all,
>>>>>
>>>>> I have also added a package in org.apache.river bundle to create the
>>>>> river
>>>>> service in osgi environment ( Here RIver
>>>>> uses NonActivatableServiceDescriptor).
>>>>>
>>>>> package name is  org.apache.river.start.ext
>>>>>
>>>>>
>>>>> As river bundle is system fragment, i have to remove
>>>>> the groovy dependency.
>>>>> So i removed groovy files.
>>>>>
>>>>> net.jini.config.Component.groovy
>>>>>
>>>>> net.jini.config.GroovyConfig.groovy
>>>>>
>>>>>
>>>>>
>>>>> Thanks&   Regards,
>>>>>
>>>>> Bharath
>>>>>
>>>>>
>>>>>
>>>>>
>

Mime
  • Unnamed multipart/alternative (inline, None, 0 bytes)
View raw message