Hello Stian, thank you for your assistance and that you have taken the time to support my plugin development. I will adept my sources to your suggestions. Wish you a nice weekend!
Regards Andreas Stian Soiland-Reyes schrieb: > On Thu, May 27, 2010 at 19:36, Andreas Truszkowski <[email protected]> > wrote: > >> if I try to install my plugin via "Find new plugins" the updates and >> plugins manager installs all dependencies without an error. But when I >> restart Taverna the plugin is not visible. Starting Taverna in debug >> mode shows also no errors or any sign for a problem. How can I find the >> reason why the plugin is not loaded accurate. Here is the URL to the plugin: >> http://www.ts-concepts.de/cdk-taverna2/plugin/ >> > > The log file in ~/.taverna-2.1.2/logs says: > > INFO 2010-05-28 11:19:40,187 > (net.sf.taverna.t2.workbench.ui.servicepanel.ServicePanel:131) - > Updating My example service > .. > INFO 2010-05-28 11:19:40,288 > (net.sf.taverna.t2.workbench.ui.servicepanel.ServicePanel:131) - Found > 0 services My example service > > .. so it is installed, just not listed under "Import new services" > > > >> >From what I see in >> > http://www.ts-concepts.de/cdk-taverna2/maven/release_repository/org/openscience/cdk/applications/taverna/cdk-taverna-2-activity-ui/0.1/cdk-taverna-2-activity-ui-0.1-sources.jar > in CDKServiceProvider: > > List<ServiceDescription> results = new ArrayList<ServiceDescription>(); > List<Class> classes = > CDKClassGrabber.getClassessOfSuperclass("org.openscience.cdk.applications.taverna", > AbstractCDKActivity.class); > // Register activities > for (Class<? extends AbstractCDKActivity> activityClass : > classes) { > AbstractCDKActivity activity = activityClass.newInstance(); > service = new CDKServiceDescriptor(activityClass); > service.setActivityName(activity.getActivityName()); > service.setFolderName(activity.getFolderName()); > // TODO set description > service.setDescription(activity.getDescription()); > > service.setConfigurationPanelClass(CDKClassGrabber.getClassByName("org.openscience.cdk.applications.taverna", > activity.getConfigurationPanelClass())); > > service.setAdditionalProperties(activity.getAdditionalProperties()); > results.add(service); > } > > As this is returning 0 services, I believe that the list "classes" is empty. > > It seems we are moving into the dark territory of classloaders. Here be > dragons! > > > There seems to be a big hint that some Class.forName() or similar is > being done here in this CDKClassGrabber.getClassessOfSuperclass - but > remember that when installed as a plugin you will not have the CDK > classes on the System classloader, only on the classloader of your > plugin as you will now be running inside the plugin system Raven. > > So it depends on how CDKClassGrabber looks up those classes. If it > tries to use ClassLoader.getSystemClassLoader() it would not find any > implementations, as this would only find classes in JARs that are in > Taverna's lib/ folder. > > your CDKClassGrabber.getClassesForPackage does: > > ClassLoader cld = Thread.currentThread().getContextClassLoader(); > > .. and tries to use this to look for URLs matching your package name. > > > While running from Eclipse this should work, as the context class > loader is the system class loader, which knows about everything on > your classpath, including the project with CDKClassGrabber etc. While > running in Taverna the default context class loader will just know > about the lib/ folder. > > > A quick fix would therefore be to change the context class loader in > CDKServiceProvider before calling CDKClassGrabber. This should be > fairly safe, as each service provider is run in a different thread. > Try something like: > > Thread.currentThread().setContextClassLoader(getClass().getClassLoader()); > > > Another important thing to know in this aspect is that Raven class > loaders are arranged hierarchical, one per POM file. Tthe classloader > for > cdk-taverna-2-activity-ui will search the classloaders for each of its > dependencies, so it will search cdk-taverna-2-activity, which then > again will search its dependencies, like org.openscience.cdk:cdk. But > it is important to know that this does not go backwards, so > cdk-taverna-2-activity is not able to find any classes in > cdk-taverna-2-activity-ui as it does not depend on it. (Doing so would > form a loop). > > So if you wanted CDKClassGrabber in cdk-taverna-2-activity to find any > classes in cdk-taverna-2-activity-ui, then the only way would be > either to pass in the ClassLoader itself as a parameter, or to set the > context classloader and use that from within CDKClassGrabber. > > > Now as for the clever bit that looks at the JAR files, I would > recommend rather to go for the slightly more standard SPI approach as > you've already seen in > ./META-INF/services/net.sf.taverna.t2.servicedescriptions.ServiceDescriptionProvider > and > ./META-INF/services/net.sf.taverna.t2.workbench.ui.views.contextualviews.activity.ContextualViewFactory > > > So I would go for > META-INF/services/org.openscience.cdk.applications.taverna.AbstractCDKActivity > - and in that file(s) list: > > org.openscience.cdk.applications.taverna.io.MDLSDFileWriterActivity > org.openscience.cdk.applications.taverna.io.SMILESFileReaderActivity > > etc. > > To find those implementations of AbstractCDKActivity you can use our > SPI registry, which would check all plugins (and not just your own) > for the SPI description files, and use the classloaders where it finds > such files to instantiate those activities. > > We have two versions, one that can find the classes, and another one > that finds the classes and makes a (singleton) instance of that class. > As you'll > > You can use it like this: > > import net.sf.taverna.t2.spi.SPIRegistry; > .. > protected SPIRegistry<AbstractCDKActivity> cdkActivityRegistry = new > SPIRegistry<AbstractCDKActivity>( > AbstractCDKActivity.class); > > .. > for (AbstractCDKActivity cdkActivity : cdkActivityRegistry.getInstances()) { > service = new CDKServiceDescriptor(cdkActivity.getClass()); > service.setActivityName(activity.getActivityName()); > service.setFolderName(activity.getFolderName()); > service.setDescription(activity.getDescription()); > > service.setAdditionalProperties(activity.getAdditionalProperties()); > results.add(service); > } > > If you go for this approach you would not need to use the package name > restrictions or the context loader tricks. You would still need to > sort something out about this service.setConfigurationPanelClass - > which I guess has to do with finding the configuration panel for your > activity. > > You could do a similar interface and SPI registry for finding the > right ActivityConfigurationPanel - they would have to be > instantiatable (is that a word?) with a default constructor, and some > canHandle(AbstractCDKActivity activity) method which you check to be > able to find the right panel. We would normally do this as a factory > that could then return the ActivityConfigurationPanel. > > On the other hand I'm not sure why this would be needed, it seems to > be because you have a common CDKContextualView which simply calls > these panels - I would just avoid this indirection and additional SPI > by having several contextual views and configuration actions, one > could say it handles activities MDLSDFileWriterActivity, > MDLMolFileWriterActivity, etc. (or a common FileWriter interface?) - > and another for the FileReader. > > > These are just my suggestions, to get it working inside the plugin all > I believe you will need to do is set the Thread contextual view using > Thread.currentThread().setContextClassLoader(getClass().getClassLoader()); > > .. I tested this for your code, and it seems to work, except I got > this exception: > > org.openscience.cdk.applications.taverna.ui.serviceprovider.CDKServiceProvider > java.lang.ClassNotFoundException: > org.openscience.cdk.applications.taverna.ui.serviceprovider.CDKServiceProvider > at > net.sf.taverna.raven.repository.impl.LocalArtifactClassLoader.findClass(LocalArtifactClassLoader.java:343) > at > net.sf.taverna.raven.repository.impl.LocalArtifactClassLoader.findClass(LocalArtifactClassLoader.java:276) > at java.lang.ClassLoader.loadClass(ClassLoader.java:307) > at java.lang.ClassLoader.loadClass(ClassLoader.java:248) > at java.lang.Class.forName0(Native Method) > at java.lang.Class.forName(Class.java:169) > at > org.openscience.cdk.applications.taverna.CDKClassGrabber.getClassesForPackage(CDKClassGrabber.java:68) > at > org.openscience.cdk.applications.taverna.CDKClassGrabber.getClassessOfSuperclass(CDKClassGrabber.java:92) > at > org.openscience.cdk.applications.taverna.ui.serviceprovider.CDKServiceProvider.findServiceDescriptionsAsync(CDKServiceProvider.java:29) > at > net.sf.taverna.t2.servicedescriptions.impl.ServiceDescriptionRegistryImpl$FindServiceDescriptionsThread.run(ServiceDescriptionRegistryImpl.java:502) > > Here, and a few other places you are using Java's Class.forName() when > loading a class, which tries to find the class loader via a hack of > looking in the stack to find what is the calling class's classLoader, > in this case it will be cdk-taverna-2-activity and not > cdk-taverna-2-activity-ui where > org.openscience.cdk.applications.taverna.ui.serviceprovider.CDKServiceProvider > lives. Remember that inside Raven cdk-taverna-2-activity can't see > cdk-taverna-2-activity-ui. (In this case you don't actually need > CDKServiceProvider - but your method is looking up ALL classes of the > given package name - another good hint to rather go for a more normal > SPI approach) > > You will need to use the correct classloader, ie. the one where you > found the class (or SPI file). So try using cld.loadClass(className) > instead. > > ------------------------------------------------------------------------------ _______________________________________________ taverna-hackers mailing list [email protected] Web site: http://www.taverna.org.uk Mailing lists: http://www.taverna.org.uk/about/contact-us/ Developers Guide: http://www.taverna.org.uk/developers/
