Switch from Docbook to Markdown for documentation.
Added README.markdown with the current state of the reference docs in Markdown.
This commit is contained in:
@@ -1,317 +0,0 @@
|
||||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<!DOCTYPE chapter PUBLIC "-//OASIS//DTD DocBook XML V4.5//EN"
|
||||
"http://www.oasis-open.org/docbook/xml/4.5/docbookx.dtd">
|
||||
<chapter>
|
||||
<title>Core</title>
|
||||
|
||||
<section>
|
||||
<title>Introduction</title>
|
||||
|
||||
<para>Host system provides a plugin interface providers have to implement.
|
||||
Core system is build to hold a container of instances of this interface
|
||||
and works with them.</para>
|
||||
|
||||
<example>
|
||||
<title>Basic example of plugin interface and host</title>
|
||||
|
||||
<programlisting language="java">/**
|
||||
* Interface contract for the providers to be implemented.
|
||||
*/
|
||||
public interface MyPluginInterface {
|
||||
|
||||
public void bar();
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* A host application class working with instances of the plugin
|
||||
* interface.
|
||||
*/
|
||||
public class HostImpl implements Host {
|
||||
|
||||
private List<MyPluginInterface> plugins;
|
||||
|
||||
/**
|
||||
* Setter to inject the plugins
|
||||
*/
|
||||
public void setPlugins(List<MyPluginInterface> plugins) {
|
||||
this.plugins = plugins;
|
||||
}
|
||||
|
||||
/**
|
||||
* Some business method actually working with the given plugins.
|
||||
*/
|
||||
public void someBusinessMethod() {
|
||||
|
||||
for (MyPluginInterface plugin : plugins) {
|
||||
plugin.bar();
|
||||
}
|
||||
}
|
||||
}</programlisting>
|
||||
</example>
|
||||
|
||||
<para>This is the way you would typically construct a host component in
|
||||
general. Leveraging dependency injection via setters allows flexible usage
|
||||
in a variety of environments. Thus you could easily provide a factory
|
||||
class that is able to lookup
|
||||
<interfacename>MyPluginInterface</interfacename> implementations from the
|
||||
classpath, instantiate them and inject them into HostImpl.</para>
|
||||
|
||||
<para>Using Spring as component container you could configure something
|
||||
like this:</para>
|
||||
|
||||
<example>
|
||||
<title>Configuring HostImpl with Spring</title>
|
||||
|
||||
<programlisting language="xml"><bean id="host" class="com.acme.HostImpl">
|
||||
<property name="plugins">
|
||||
<list>
|
||||
<bean class="MyPluginImplementation" />
|
||||
</list>
|
||||
</property>
|
||||
</bean></programlisting>
|
||||
</example>
|
||||
|
||||
<para>This is pretty much well known to Spring developers and let's us
|
||||
face the wall that this is rather static. Everytime you want to add a new
|
||||
plugin implementation instance you have to modify configuration of the
|
||||
core. Let's see how we can get this dance a little more.</para>
|
||||
</section>
|
||||
|
||||
<section id="core.collecting-beans">
|
||||
<title>Collecting Spring beans dynamically</title>
|
||||
|
||||
<para>With the <classname>BeanListBeanFactory</classname>
|
||||
<productname>Spring Plugin</productname> provides a Spring container
|
||||
extension, that allows to lookup beans of a given type in the current
|
||||
<interfacename>ApplicationContext</interfacename> and register them as
|
||||
list under a given name. Take a look at the configuration now:</para>
|
||||
|
||||
<example>
|
||||
<title>Host and plugin configuration with Spring Plugin support</title>
|
||||
|
||||
<programlisting lang="" language="xml"><import resource="classpath*:com/acme/**/plugins.xml" />
|
||||
|
||||
<bean id="host" class="com.acme.HostImpl">
|
||||
<property name="plugins" ref="plugins" />
|
||||
</bean>
|
||||
|
||||
<bean class="org.springframework.plugin.support.BeanListBeanFactory">
|
||||
<property name="lists">
|
||||
<map>
|
||||
<entry key="plugins" value="org.acme.MyPluginInterface" />
|
||||
</map>
|
||||
</property>
|
||||
</bean></programlisting>
|
||||
|
||||
<programlisting language="xml"><!-- In a file called plugins.xml in the plugin project -->
|
||||
<bean class="MyPluginimplementation" /></programlisting>
|
||||
</example>
|
||||
|
||||
<para>You can see that we include a wildcarded configurationfile that
|
||||
allows plugin projects to easily contribute plugin implementations by
|
||||
declaring them as beans in configuration files matching the wildcarded
|
||||
path. If you use Spring 2.5 component scanning you don't have to use the
|
||||
import trick at all as Spring would detect the implementation
|
||||
automatically as long as it is annotated with <code>@Component</code>,
|
||||
<code>@Service</code> a.s.o.</para>
|
||||
|
||||
<para>The <classname>BeanListBeanFactory</classname> in turn allows
|
||||
registering a map of lists to be created, where the maps entry key is the
|
||||
id under which the list will be registered and the entry's value is the
|
||||
type to be looked up.</para>
|
||||
|
||||
<note>
|
||||
<para>The design of the <classname>BeanListBeanFactory</classname> might
|
||||
seem a little confusing at first (especially to set a map on a property
|
||||
named lists). This is due to the posibility to register more than one
|
||||
list to be looked up. We think about dropping this functionality for the
|
||||
sake of simplicity in future versions.</para>
|
||||
</note>
|
||||
|
||||
<simplesect>
|
||||
<title>A whole lotta XML - namespace to help!</title>
|
||||
|
||||
<para>Actually this already serves a lot of requirements we listed in
|
||||
<xref linkend="preface.context" />. Nevertheless the amount of XML to be
|
||||
written is quite large. Furthermore it's rather not intuitive to
|
||||
configure a bean id as key, and a type as value. We can heavily shrink
|
||||
the XML required to a single line by providing a Spring namespace
|
||||
boiling configuration down to this:</para>
|
||||
|
||||
<example>
|
||||
<title>Host configuration using the plugin namespace</title>
|
||||
|
||||
<programlisting language="xml"><beans xmlns="http://www.springframework.org/schema/beans"
|
||||
xmlns:plugin="http://www.springframework.org/schema/plugin"
|
||||
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
|
||||
xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans.xsd
|
||||
http://www.springframework.org/schema/plugin http://www.springframework.org/schema/plugin/spring-plugin.xsd">
|
||||
|
||||
<import resource="classpath*:com/acme/**/plugins.xml" />
|
||||
|
||||
<bean id="host" class="com.acme.HostImpl">
|
||||
<property name="plugins" ref="plugins" />
|
||||
</bean>
|
||||
|
||||
<plugin:list id="plugins" class="org.acme.MyPluginInterface" />
|
||||
</beans></programlisting>
|
||||
</example>
|
||||
|
||||
<para>Suggested you have added the namespace XSD into Eclipse and
|
||||
installed Spring IDE, you should get code completion on filling the
|
||||
class attribute.</para>
|
||||
</simplesect>
|
||||
|
||||
<simplesect>
|
||||
<title>Using inner beans</title>
|
||||
|
||||
<para>The listing above features an indirection for the
|
||||
<code>plugin</code> bean definition. Defining the plugin list as top
|
||||
level bean can have advantages: you easily could place all plugin lists
|
||||
in a dedicated configuration file, presenting all application extension
|
||||
points in one single place. Nevertheless you also might choose to define
|
||||
the list directly in the property declaration:</para>
|
||||
|
||||
<example>
|
||||
<title>Using internal bean definition</title>
|
||||
|
||||
<programlisting language="xml"><import resource="classpath*:com/acme/**/plugins.xml" />
|
||||
|
||||
<bean id="host" class="com.acme.HostImpl">
|
||||
<property name="plugins">
|
||||
<plugin:list class="org.acme.MyPluginInterface" />
|
||||
</property>
|
||||
</bean></programlisting>
|
||||
</example>
|
||||
|
||||
<para>This way you have a more compact configuration, paying the prica
|
||||
of tangling all extention points though possibly various config
|
||||
files.</para>
|
||||
</simplesect>
|
||||
</section>
|
||||
|
||||
<section>
|
||||
<title>Plugin beans</title>
|
||||
|
||||
<para>Using plain interfaces and
|
||||
<classname>BeanListBeanFactory</classname> offers an easy way to
|
||||
dynamically lookup beans in Spring environments. Nevertheless, very often
|
||||
you face the situation that you want to have dedicated access to a subset
|
||||
of all plugins, choose plugins by a given criteria or use a decent default
|
||||
plugin or the like. Thus we need a basic infrastructure interface for
|
||||
plugin interfaces to extend and a more sophisticated plugin
|
||||
container.</para>
|
||||
|
||||
<simplesect>
|
||||
<title>Plugin</title>
|
||||
|
||||
<para>Hera's central infrastructure interfacte is
|
||||
<interfacename>Plugin<S></interfacename>, where S defines the
|
||||
delimiter type you want to let implementations decide on, whether they
|
||||
shall be invoked or not. Thus the plugin implementation have to
|
||||
implement <methodname>supports(S delimiter)</methodname> to come to the
|
||||
decision. Consider the following example:</para>
|
||||
|
||||
<example>
|
||||
<title>Usage of Plugin interface</title>
|
||||
|
||||
<programlisting language="java">public enum ProductType {
|
||||
|
||||
SOFTWARE, HARDWARE;
|
||||
}
|
||||
|
||||
public interface ProductProcessor extends Plugin<ProductType> {
|
||||
|
||||
public void process(Product product);
|
||||
}</programlisting>
|
||||
</example>
|
||||
|
||||
<para>This design would allow plugin providers to implement
|
||||
<methodname>supports(ProductType productType)</methodname> to decide
|
||||
which product types they want to process and provide actual processing
|
||||
logic in <methodname>process(Product product)</methodname>.</para>
|
||||
</simplesect>
|
||||
|
||||
<simplesect id="core.plugin-registry">
|
||||
<title>PluginRegistry</title>
|
||||
|
||||
<para>Using a <interfacename>List</interfacename> as plugin container as
|
||||
well as the <interfacename>Plugin</interfacename> interface you can now
|
||||
select plugins supporting the given delimiter. To not reimplement the
|
||||
lookup logic for common cases Spring Plugin provides a
|
||||
<classname>PluginRegistry<T extends Plugin<S>,
|
||||
S></classname> interface that provides sophisticated methods to
|
||||
access certain plugins:</para>
|
||||
|
||||
<example>
|
||||
<title>Usage of the PluginRegistry</title>
|
||||
|
||||
<programlisting language="java">PluginRegistry<ProductProcessor, ProductType> registry =
|
||||
SimplePluginRegistry.create();
|
||||
|
||||
// Add plugin instances
|
||||
registry.add(new FooImplementation());
|
||||
|
||||
// Returns the first plugin supporting SOFTWARE
|
||||
registry.getPluginFor(ProductType.SOFTWARE);
|
||||
|
||||
// Returns the first plugin supporting SOFTWARE,
|
||||
// or DefaultPlugin if none found
|
||||
registry.getPluginFor(ProductType.SOFTWARE, new DefaultPlugin());
|
||||
|
||||
// Returns all plugins supporting HARDWARE,
|
||||
// throwing the given exception if none found
|
||||
registry.getPluginsFor(ProductType.HARDWARE, new MyException("Damn!");</programlisting>
|
||||
</example>
|
||||
</simplesect>
|
||||
|
||||
<simplesect>
|
||||
<title>Configuration and namespace</title>
|
||||
|
||||
<para>Similar to the <classname>BeanListBeanFactory</classname>
|
||||
described in <xref linkend="core.collecting-beans" /> Spring Plugin
|
||||
provides a <classname>PluginRegistryBeanFactory</classname> to
|
||||
automatically lookup beans of a dedicated type to be aggregated in a
|
||||
<classname>PluginRegistry</classname>. Note that the type has to be
|
||||
assignable to <interfacename>Plugin</interfacename> to let the registry
|
||||
work as expected.</para>
|
||||
|
||||
<para>Furthermore there is also an element in the namespace to shrink
|
||||
down configuration XML:</para>
|
||||
|
||||
<example>
|
||||
<title>Using the XML namespace to configure a registry</title>
|
||||
|
||||
<programlisting language="xml"><plugin:registry id="plugins" class="com.acme.MyPluginInterface" /></programlisting>
|
||||
</example>
|
||||
</simplesect>
|
||||
|
||||
<simplesect>
|
||||
<title>Ordering plugins</title>
|
||||
|
||||
<para>Declaring plugin beans sometimes it is necessary to preserve a
|
||||
certain order of plugins. Suppose you have a plugin host that already
|
||||
defines one plugin that shall always be executed after all plugins
|
||||
declared by extensions. Actually the Spring container typically returnes
|
||||
beans in the order they were declared, so that you could import you
|
||||
wildcarded config files right before declaring the default plugin.
|
||||
Unfortunately the order of the beans is not contracted to be preserved
|
||||
for the Spring container. Thus we need a different solution.</para>
|
||||
|
||||
<para>Spring provides two ways to order beans. First, you can implement
|
||||
<interfacename>Ordered</interfacename> interface and implement
|
||||
<methodname>getOrder</methodname> to place a plugin at a certain point
|
||||
in the list. Secondly you can user the <classname>@Order</classname>
|
||||
annotation. For more information on ordering capabilities of Spring see
|
||||
the <ulink url="???">section on this topic in the Spring reference
|
||||
documentation</ulink>.</para>
|
||||
|
||||
<para>Using the Spring Plugin namespace you will get a
|
||||
<interfacename>PluginRegistry</interfacename> instance that is capable
|
||||
of preserving the order defined by the mentioned means. Using Spring
|
||||
Plugin programatically use
|
||||
<classname>OrderAwarePluginRegistry</classname>.</para>
|
||||
</simplesect>
|
||||
</section>
|
||||
</chapter>
|
||||
Reference in New Issue
Block a user