Extension points in Taverna are interfaces which can be implemented by different modules and plugins to extend and add functionality to the workflow engine and workbench.
SPIs
Taverna uses a Java technique called SPI - Service Provider Interface
. Implementations of such an interface are described in a resource of the JAR file named according to the pattern META-INF/services/com.example.MySPIInterface.
Internally in Taverna pretty much every module is loaded as such a plugin, so for any of Taverna's SPI there's no distinction between implementations from the base Taverna distribution or a third-party plugin.
So for instance implementing the interface net.sf.taverna.t2.servicedescriptions.ServiceDescriptionProvider allows you to provide a list of services to the 'Available services' panel in the workbench. Creating service description providers are covered by the Tutorial - Service discovery plugin.
So if you have implemented this interface in org.example.myfancytool.ui.ExampleServiceProvider you would have the source code in src/main/java/org/example/myfancytool/ui/ExampleServiceProvider.java - but you would also have to list the implementation in the SPI file so that Taverna can discover it. The SPI file is named after the interface and must be available as a resource in the classpath of the same module as the implementation class. That means you have to have the file src/main/resources/META-INF/services/net.sf.taverna.t2.servicedescriptions.ServiceDescriptionProvider which should be a plain text file, where each line should simply list the fully qualified class name of the implementation, ie:
Unlike most SPIs built-in to Java (like for SSL providers), Taverna's SPI are not generally listing equivalent implementations of which only one would be used - rather they contain a list of implementations which will all be made available within the Taverna, loaded from an SPI registry (see below). The SPI instance registry will take care of traversing every JAR to find every such SPI file for the desired interface, make a single instance of the class, and provide a list of those instances to the application.
The current SPI registry is implemented using Raven, but a version of these SPIs are done in the OSGified platform as well, but there class implementations are listed as [OSGi services] instead of the META-INF/services file.
Taverna 2 extensions
SPIs of Taverna 2.x engine (as of 2.2)
Note that a few of these SPIs have been created mainly to work around class loader isolation forced by Raven, in particular to separate the engine and UI code. In many cases this gives added flexibility, for instance CredentialProviderSPI allows the engine to not have any UI code, but still allow activities to get credentials for connecting to password protected services. In the workbench a UI implementation of CredentialProviderSPI will know how to pop-up on the screen to ask the user for a password - but the command line version of Taverna could have an alternative implementation which asks the user on the console, while Taverna Server could ask on a web page, etc.
Other examples are not as extensible, like the SPI Edits is simply to allow the UI to get access to a factory class for creating workflow model objects (like Processors and InputPorts) without directly depending on workflowmodel-impl. The initial idea was to be make it possible to upgrade *-impl without breaking any GUI, but in practice this turned difficult as in several cases the UI still used *-impl directly instead of introducing a new SPI. (See notes about ui-api and ui-impl in UI modules)
| net.sf.taverna.t2.compatibility.activity.ActivityTranslator | Translate a type of Activity from Taverna 1.x workflows |
| net.sf.taverna.t2.reference.ExternalReferenceBuilderSPI | Constructs an ExternalReferenceSPI instance from a byte stream. |
| net.sf.taverna.t2.reference.ExternalReferenceSPI | A reference to a single piece of data |
| net.sf.taverna.t2.reference.ExternalReferenceTranslatorSPI | Translate from one type of ExternalReferenceSPI to another (like http -> file) |
| net.sf.taverna.t2.reference.h3.HibernateComponentClass | Class to load for Hibernate mapping |
| net.sf.taverna.t2.reference.h3.HibernateMappedEntity | Class to load for Hibernate mapping |
| net.sf.taverna.t2.reference.StreamToValueConverterSPI | Parse a byte-value to a Java object (String/Integer, etc) |
| net.sf.taverna.t2.reference.ValueToReferenceConverterSPI | Register a Java value (String/Integer, etc) as an ExternalReferenceSPI |
| net.sf.taverna.t2.provenance.connector.ProvenanceConnector | Method for storing provenance (like MySQL) |
| net.sf.taverna.t2.provenance.ProvenanceConnectorFactory | Factory to create a ProvenanceConnector |
| net.sf.taverna.t2.security.credentialmanager.CredentialProviderSPI | Provide credentials for credential manager, like pop up a UI asking for password |
| net.sf.taverna.t2.visit.fragility.FragilityChecker | Check if a workflow component (like an activity) is fragile/unreachable/failing |
| net.sf.taverna.t2.visit.VisitKind | A type of 'visit' to a workflow component (like FragilityCheck) |
| net.sf.taverna.t2.workflowmodel.Edits | Implementation of Edits from workflowmodel-impl (just one implementation) |
| net.sf.taverna.t2.workflowmodel.health.HealthChecker | Check the 'health' of an activity (like if the WSDL is reachable) |
| net.sf.taverna.t2.workflowmodel.serialization.xml.XMLDeserializer | Implementation of XMLDeserializer - to parse .t2flow |
| net.sf.taverna.t2.workflowmodel.serialization.xml.XMLSerializer | Implementation of XMLSerializer - to create .t2flow |
For a description of SPIs that are useful when implementing a new activity type for Taverna, see the tutorials Tutorial - Service invocation plugin and Tutorial - Service discovery plugin.
SPIs of Taverna 2.x workbench (as of 2.2)
| net.sf.taverna.raven.launcher.Launchable | Provide the main() method as configured in raven-launcher.properties |
| net.sf.taverna.t2.annotation.AnnotationBeanSPI | A type of annotation on a workflow component, like DescriptiveTitle, Author or ExampleValue (Not extensible due to serialisation issues) |
| net.sf.taverna.t2.reference.ui.referenceactions.ReferenceActionSPI | Linking 'Run workflow' input dialogue to Result panel |
| net.sf.taverna.t2.renderers.Renderer | Render an output value in the UI, ie. plain text, SVG image, etc. |
| net.sf.taverna.t2.servicedescriptions.ServiceDescriptionProvider | Provide {{ServiceDescription}}s for "Available services" |
| net.sf.taverna.t2.ui.menu.MenuComponent | Provide a menu item for application and/or context menus |
| net.sf.taverna.t2.ui.menu.MenuManager | Find all MenuComponent's and create corresponding JMenu (just one implementation) |
| net.sf.taverna.t2.workbench.activityicons.ActivityIconSPI | Provide an icon for a particular activity type |
| net.sf.taverna.t2.workbench.configuration.ConfigurationUIFactory | Provide a UI for configuring say a Beanshell activity |
| net.sf.taverna.t2.workbench.edits.EditManager | Handle undo/redo of a set of Edit's (just one implementation) |
| net.sf.taverna.t2.workbench.file.DataflowPersistenceHandler | How to open/save a workflow in a particular format like .t2flow or .xml |
| net.sf.taverna.t2.workbench.file.FileManager | Handle file opening/closing/saving (just one implementation) |
| net.sf.taverna.t2.workbench.report.explainer.VisitExplainer | Give the user helpful explanation for a type of Visit |
| net.sf.taverna.t2.workbench.ShutdownSPI | Actions to perform on shutting down workbench |
| net.sf.taverna.t2.workbench.StartupSPI | Actions to perform on starting up workbench |
| net.sf.taverna.t2.workbench.ui.views.contextualviews.activity.ContextualViewFactory | Provide a contextual view for a workflow item (like a Processor) |
| net.sf.taverna.t2.workbench.ui.views.contextualviews.AddLayerFactorySPI | Provide a button for adding dispatch layers (like the Loop) |
| net.sf.taverna.t2.workbench.ui.zaria.PerspectiveSPI | Provide a perspective for the workbench. Screen is split into areas populated by {{UIComponentSPI}}s. |
| net.sf.taverna.t2.workbench.ui.zaria.UIComponentFactorySPI | A method for inserting a UI component when editing a perspective |
| net.sf.taverna.t2.workbench.ui.zaria.UIComponentSPI | A UI component that can be used in one or more perspective, like "Available services" or "Workflow diagram" |
| net.sf.taverna.t2.workbench.views.results.saveactions.SaveAllResultsSPI | A method for saving all the results, like files, .xml, .xls |
| net.sf.taverna.t2.workbench.views.results.saveactions.SaveIndividualResultSPI | A method for saving a single result, like .txt |
Deprecated SPIs of Taverna 2.x
| net.sf.taverna.t2.partition.PartitionAlgorithmSetSPI | Used by "Service panel" in 2.0 |
| net.sf.taverna.t2.partition.PropertyExtractorSPI | Used by "Service panel" in 2.0 |
| net.sf.taverna.t2.partition.QueryFactory | Used by "Service panel" in 2.0 |
| net.sf.taverna.t2.workbench.views.results.saveactions.SaveResultActionSPI | now split into SaveAllResultsSPI and SaveIndividualResultSPI |
| net.sf.taverna.t2.annotation.AnnotationSourceSPI | An external source of an annotation, like an URI (not really used) |
| net.sf.taverna.t2.annotation.CurationEventBeanSPI | A type of curation event on annotation, like DisputeEventDetails (not really used) |
SPI Registries
How do different bits of Taverna find these implementations?
The lazy answer is by creating an SPI registry
:
However, for most SPIs you will find that there already exists such a registry. Most of them are implemented as simple subclasses of SPIRegistry. See for instance RendererRegistry
.
Some registries are not as interesting as there will only be one particular implementation (as for the MenuManager) - in which case there is typically a static method in the abstract class of the SPI itself to find the implementation, like MenuManager.getInstance()
.
| Which SPIRegistry class?? In addition to net.sf.taverna.t2.spi.SPIRegistry there's also a legacy class {{net.sf.taverna.t2.spi.SpiRegistry and net.sf.taverna.t2.spi.InstanceRegistry. If you look under the hood, confusingly:
The recommended class to use is net.sf.taverna.t2.spi.SPIRegistry which hides the need to discover and find the correct net.sf.taverna.raven.repository.Repository - and also works if you happen to run outside of Raven. You might however still find a few instances of the two deprecated registry types. Historically, {net.sf.taverna.raven.spi.SpiRegistry was the original SPI registry - but it only listed java.lang.Class'es directly. net.sf.taverna.raven.spi.InstanceRegistry improved on this by maintaining instances of the classes. net.sf.taverna.t2.spi.SPIRegistry was so called because almost every SPI registry in Taverna listed instances rather than classes, and was made to be easier to use, and to provide a way to list SPIs independently of Raven, the idea being that the backend could be changed if needed. |
Java 6 introduces java.util.ServiceLoader
, which works similar to Taverna's SPIRegistry. It does however not understand the multiple classloaders of Raven - so it would not work as well within the Taverna 2.2 workbench, and probably does not work well within OSGi.
Observables
Many objects within the Taverna workbench can be 'observed' for any changes. This will allow your class to be notified, for instance when a workflow is opened or a service has been added to a workflow. Within Taverna these notifications drive most of the UI, for instance making sure the diagram is updated.
Most of these are implemented by use of the class Observable
, which will allow you to register an Observer, which will called back with a Message (often different subclasses depending on the event).
So for instance to see when the current open workflow is changed, register an observer with the FileManager
(which handles all opening/saving of workflows):
Here are the different observables of Taverna:
| Class | Notifies |
|---|---|
| net.sf.taverna.t2.spi.SPIRegistry (and subclasses) | New/removed SPI instances after plugin installation |
| net.sf.taverna.t2.security.credentialmanager.CredentialManager | Keystore has changed |
| net.sf.taverna.t2.workbench.file.FileManager | Workflow was opened, saved, closed or made current |
| net.sf.taverna.t2.workbench.edits.EditManager | Dataflow edit was performed, undone or redone |
| net.sf.taverna.t2.workbench.ui.DataflowSelectionModel | Change of selected dataflow element (like when clicking on a Processor) |
| net.sf.taverna.t2.ui.menu.MenuManager | When menu has changed (and UI must be updated) |
| net.sf.taverna.t2.lang.ui.ModelMap | (deprecated) When a 'model' has changed (typically current workflow and perspective) |
| net.sf.taverna.t2.workbench.views.monitor.graph.MonitorGraphComponent | When an object is selected in a diagram (useful in Result perspective, in which case it's used to update the selected output values) |
| net.sf.taverna.t2.monitor.MonitorManager | Details of workflow run, such as processor started/finished |
| net.sf.taverna.t2.workflowmodel.Processor | That the processor has finished all executions of a particular run |
| net.sf.taverna.t2.workbench.report.ReportManager | A new dataflow report is available (typically after a change or user clicking Check button) |
| net.sf.taverna.t2.servicedescriptions.ServiceDescriptionRegistry | A service provider was added/removed/changed |
In addition there are a few classes which have more 'traditional' add*Listener() methods like in AWT/Swing:
| net.sf.taverna.t2.workflowmodel.DataflowOutputPort | (internal) A result has been delivered on an output port |
| net.sf.taverna.t2.workflowmodel.facade.WorkflowInstanceFacade | A result has been delivered, a failure has occurred |
| net.sf.taverna.t2.spi.SpiRegistry | (deprecated) SPI classes discovered/removed |
| net.sf.taverna.t2.spi.InstanceRegistry | (deprecated) SPI instances discovered/removed |
| net.sf.taverna.raven.repository.Repository | Raven plugins added/removed |
Taverna 1.x extensions
Not covered in detail in this documentation.
See http://www.taverna.org.uk/developers/taverna-1-7-x/plugins/
for a general overview, and the Taverna 1.7 plugin documentation
.
SPIs of Taverna 1.x
| net.sf.taverna.perspectives.PerspectiveSPI | Perspective (and its button) in the workbench. Divides the screen into sections, filled by UIComponentSPI instances |
| org.embl.ebi.escience.scuflui.actions.ScuflModelActionSPI | Actions for the toolbar of Advanced Model Explorer |
| org.embl.ebi.escience.scuflui.spi.FacetFinderSPI | Some kind of magic.. |
| org.embl.ebi.escience.scuflui.spi.ProcessorActionSPI | Right-click actions for a Processor |
| org.embl.ebi.escience.scuflui.spi.RendererSPI | Renderer for displaying a particular type of output data |
| org.embl.ebi.escience.scuflui.spi.ResultMapSaveSPI | A way to save multiple output values (like .csv, Excel) |
| org.embl.ebi.escience.scuflui.spi.UIComponentFactorySPI | Factory for creating UIComponentSPI instances |
| org.embl.ebi.escience.scuflui.spi.UIComponentSPI | A UI component that can be composed into a perspective. |
| org.embl.ebi.escience.scuflui.workbench.Scavenger | Discover services for "Available services", like parsing a WSDL to find operations |
| org.embl.ebi.escience.scuflui.workbench.scavenger.spi.ScavengerActionSPI | A right-click action on a discovered service |
| org.embl.ebi.escience.scuflworkers.java.LocalWorker | Light-weight service which appears under "Local services" |
| org.embl.ebi.escience.scuflworkers.ProcessorInfoBean | Look up textual descriptions of a processor type (by loading property file) |
| org.embl.ebi.escience.scuflworkers.ScavengerHelper | UI support for creating Scavengers by right-click, from workflow or defaults |
| org.embl.ebi.escience.scuflui.spi.WorkflowModelViewSPI | Any UI in the workbench observing the current ScuflModel |