The SPI API is defined totaly by one class and one interface. {@link org.embl.ebi.escience.scuflui.renderers.RendererSPI} defines the interface that must be implemented by a provider. {@link org.embl.ebi.escience.scuflui.renderers.RendererRegistry} is a registry for all known renderers. There are additional classes in this package, such as {@link org.embl.ebi.escience.scuflui.renderers.TextRtf} which are implementations of the SPI, and these provide support for rendering common data formats.
When data needs to be rendered, the GUI componet will use the registry to find out which, if any, renderers are registered for that data type. The GUI may optionaly chose to present the user with a list of possible renderers, or it may just take the default.
The registry is the way that most client code will discover what renderers are available. The registry itself is impemented as a system-wide singleton. Use the {@link org.embl.ebi.escience.scuflui.renderers.RendererRegistry#instance()} method to get the registry. If concurrency is an issue, you should synchronize on this instance.
The first part of the API provides list-like access to all registered renderers through the {@link org.embl.ebi.escience.scuflui.renderers.RendererRegistry#addRenderer(org.embl.ebi.escience.scuflui.renderers.RendererSPI)}, {@link org.embl.ebi.escience.scuflui.renderers.RendererRegistry#removeRenderer(org.embl.ebi.escience.scuflui.renderers.RendererSPI)}, {@link org.embl.ebi.escience.scuflui.renderers.RendererRegistry#size()}, {@link org.embl.ebi.escience.scuflui.renderers.RendererRegistry#get(int)} and {@link org.embl.ebi.escience.scuflui.renderers.RendererRegistry#iterator()} methods. You can use these to manually update and scan the available renderers.
The second part of the API is used to query for renderers by the data type. {@link org.embl.ebi.escience.scuflui.renderers.RendererRegistry#getRenderer(org.embl.ebi.escience.baclava.DataThing)} and {@link org.embl.ebi.escience.scuflui.renderers.RendererRegistry#getRenderers(org.embl.ebi.escience.baclava.DataThing)} return the default SPI and a list of all SPIs respectively for the given object and MIME type. This SPI can then be used to create a GUI component that displays that data and MIME type.
The SPI interface, {@link org.embl.ebi.escience.scuflui.renderers.RendererSPI}, is very simple. It publishes a name (which should remain constant), icon (conditioned on the data to display), a method to see if the SPI can handle an object and MIME type, and a factory method to create a GUI component for the data object and MIME type.
As a user of the SPI, you can assume that if you obtained the renderer from one of the registry lookup methods, that the renderer can handle that data. Calling the factory method {@link org.embl.ebi.escience.scuflui.renderers.RendererSPI#getComponent(org.embl.ebi.escience.scuflui.renderers.RendererRegistry,org.embl.ebi.escience.baclava.DataThing)} should just work. If you are manually looping over some renderers, you should only call this method on the renderers that return true for {@link org.embl.ebi.escience.scuflui.renderers.RendererSPI#canHandle(org.embl.ebi.escience.scuflui.renderers.RendererRegistry,org.embl.ebi.escience.baclava.DataThing)}.
If you have a new data type and wish to develop a renderer for it, you should implement the {@link org.embl.ebi.escience.scuflui.renderers.RendererSPI} interface and arrange for it to be registered with the registry. You can name your SPI implementation in any way you wish. Make sure it's a public class and has a public no-args constructor. This is the constructor that will be called by the registry. Your SPI should be thread-safe, as one instance of the SPI will be loaded into the registry and used multiple times, possibly with parallel invocations.
Ensure that the canHandle() method returns true for all data that can be rendererd. This must match the data for which getComponent() works with, or you may confuse the users of this SPI. The getComponent() method can return any JComponent you wish for displaying the data. In the future, we may add API for registering menu items and so forth. At the moment, this JComponent should be totaly self-contained.
The getName() method should always return the same string. The getIcon() method can check the object and MIME type to return an apropreate image for the data but can also return the same icon for all cases.
Lastly, package your renderer up in a .jar file. To this .jar, add a file at
META-INF/services/org.embl.ebi.escience.scuflui.renderers.RendererSPI
containing the full class-name of your SPI implementation. If you have
several different SPIs in your .jar file, then add each class name on its own
line. The registry will take care of loading all of the classes listed in this
file, and will be able to load in classes from multiple .jar files.
The {@link org.embl.ebi.escience.scuflui.renderers.AbstractRenderer} class provides a convenient base-class for making renderers. This will take care of unpacking the mime type list, and stooring a name and icon. It also contains a static inner class ByPattern that will scan mime types with a regular expression, leaving you needing to just implement the getComponent() method.