Raymond, Thank you for your comments. My comments inline.
On 10/26/07, Raymond Feng <[EMAIL PROTECTED]> wrote: > > Hi, > > Please see my comments inline. > > Thanks, > Raymond > > ----- Original Message ----- > From: "Rajini Sivaram" <[EMAIL PROTECTED]> > To: <[email protected]> > Sent: Friday, October 26, 2007 5:00 AM > Subject: Re: Classloading in Tuscany > > > > *Classloading in Tuscany - Tuscany Extension Classloading* > > > > *Current implementation* > > > > Details on the Tuscany extension architecture are described here: > > > > > http://cwiki.apache.org/confluence/display/TUSCANY/SCA+Java+Extension+Development+Guide > > > > This extension architecture is based on standard J2SE Jar Service > > Provider, > > where service provider configuration files are provided in > > META-INF/services. Tuscany > > Runtime reads these configuration files and loads the service > > implementation > > classes provided by the extensions. > > > > > > Here is an example of the implementation of this architecture in > Tuscany: > > > > org.apache.tuscany.sca.core.DefaultExtensionPointRegistry:: > > *public <T> T getExtensionPoint(Class<T> extensionPointType) { > > ..... > > ClassLoader classLoader = extensionPointType.getClassLoader(); > > if (classLoader == null) { > > classLoader = Thread.currentThread().getContextClassLoader(); > > } > > List<String> classNames = > > ServiceConfigurationUtil.getServiceClassNames(classLoader, > > extensionPointType.getName()); > > if (!classNames.isEmpty()) { > > Class<?> extensionPointClass = > > Class.forName(classNames.iterator().next(), > > true, classLoader); > > ..... > > } > > * > > The code snippet above is one of the examples of the use of this > > architecture. The code uses a single classloader, which is the > classloader > > of the interface <extensionPointType> (or the thread context classloader > > if > > <extensionPointType> was loaded by the primordial classloader). The > code > > assumes that the service configuration file, the service implementation > > class and the service interface are visible from <classLoader>. And > this > > classloader is obtained through the interface, which is typically an > SPI. > > As > > a result the SPI classloader needs visibility of all configuration files > > and > > implementation classes loaded through this mechanism. Since extension > > modules are loaded using this architecture by searching for > > o.a.t.s.c.ModuleActivator in META-INF/services, SPI classloader requires > > visibility of all extensions. > > > > > > *Requirements* > > > > Tuscany extension architecture based on Jar Service Provider should be > > retained to enable Tuscany Runtime and SPI to find extensions without > > requiring changes to the way in which extension classes are specified. > > > > Lazy loading of extensions should continue to work, so Tuscany SPI and > > Runtime modules should be able to locate extensions, rather than > > extensions > > registering themselves. > > > > In a multi-classloader framework, SPI/Runtime classloader should not > > require > > visibility of extension classes or extension configuration files. > > > > > > *Proposed changes* > > Replace ServiceConfigurationUtil with a ServiceDiscovery SPI which finds > > services from all registered classloaders. The SPI classloader will be > > automatically registered (and hence no registration is necessary when > > Tuscany is run using a single-classloader). ServiceDiscovery will be a > > singleton class providing the functionality in ServiceConfigurationUtil > > (using new methods which work in a multi-classloader runtime) and a new > > service registration method: > > I won't call it as a singleton. It should be one instance per SCA Node. I am not sure I understand the difference in terms of code. When I said singleton, I meant a static instance, so I have one instance of the ServiceDiscovery class per classloader that ServiceDiscovery is loaded from (ok, the term singleton is misleading). Since ServiceDiscovery will be part of Tuscany SPI, any Tuscany SPI/Runtime code using this SPI classloader will find the same set of registered classloaders. By saying that it should be one instance per SCA Node, did you mean that (1) there could be another SCA node using a different classloader for the SPI, and hence a different set of registered classloaders, or (2) that there can be multiple SCA nodes using the same SPI classloader, but want to use different extension classloaders? The first case is fine. I am not sure how the second could be implemented without passing node information around. > > > > void registerClassLoader(ClassLoader classLoader) > > > > This method will be used by OSGi bundle activator to register bundle > > classloaders when Tuscany is run under OSGi as multiple bundles. It will > > also be used to test a multi-classloader framework without OSGi, after > all > > the classloading changes required to support multiple classloaders in > > Tuscany are completed. > > Two questions: > > 1) What's going to happen if the OSGi bundles are loaded lazily (Eclipse > supports it)? In such cases, the bundle activator will not be triggered > until as a class in the bundle is accessed. I was going to have one bundle activator in the module corresponding to the SPI, which created a new classloader that used OSGi bundle API to load classes. This activator also sets up a listener for bundle events so that all bundles which have symbolic names that match Tuscany bundles are added to the search path of this bundle classloader. Part of the reason for doing this was to avoid having OSGi specific code in each extension, while still enabling extensions to be packaged as separate bundles by just adding a manifest file. This new classloader will also be set as the thread context classloader when Tuscany is run under OSGi. Anyway, so I think it shouldn't matter if the bundles are loaded lazily. > 2) Should we register the classloader only if the MATA-INF/services are > present? Yes, it should be sufficient to register classloaders for modules with META-INF/services. With the current coarsely grained set of bundles, it does include all the bundles. > > > Instead of using the interface classloader, the configuration files > > provided > > by extensions will be found from all registered classloaders. The > > implementation class specified in the configuration file will always be > > loaded using the classloader which loaded the configuration file. To > > enable > > individual extensions to be packaged as separate OSGi bundles, > > configuration > > files should be located in the same maven module as the implementation > > class > > wherever possible (org.apache.tuscany.sca.work.WorkScheduler in core-spi > > is > > one example where the file needs to be moved to core along with the > > implementation class, there may be others). > > +1. > > > > > Since a service implementation may be reachable from multiple > > classloaders, > > sets should be used instead of lists in the service discovery code, > where > > multiple service implementations are read, to ensure that each class is > > processed only once. > > I think we just have to make sure the URLs of the service provider files > are > unique. If I have ClassLoaderB and ClassLoaderC with ClassLoaderA as parent, and ClassLoaderB and ClassLoaderC are registered with the service discovery class, getResources from both ClassLoaderB and ClassLoaderC will contain resources visible to ClassLoaderA. At the moment, a list of classnames is processed by all service discovery related code. I would like to replace it with a set of service declarations. Using a set will make it possible to load resources and classes relying only on visibility from classloaders without any restrictions on the possible hierarchies of the classloaders. > > > > Thank you... > > > > Regards, > > > > Rajini > > > > > --------------------------------------------------------------------- > To unsubscribe, e-mail: [EMAIL PROTECTED] > For additional commands, e-mail: [EMAIL PROTECTED] > > -- Thank you... Regards, Rajini
