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. -- Stian Soiland-Reyes ------------------------------------------------------------------------------ _______________________________________________ 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/
