Announcement Announcement Module
Collapse
No announcement yet.
Integration with platonos plugin engine Page Title Module
Move Remove Collapse
X
Conversation Detail Module
Collapse
  • Filter
  • Time
  • Show
Clear All
new posts

  • Integration with platonos plugin engine

    I don't know if there is general interest in a plugin architecture. In search of one, I found the platonos pluginengine project:

    http://platonos.sourceforge.net/quickstart/

    which uses a simple plugin.xml configuration file, which defines extension points for or dependencies on other plugins. Plugins can either be deployed in a jar or as a file system directory hierarchy.

    I have tried to integrate platonos into the Spring RC. I have an initial version which is partly tested (immediately after coding it, I had to leave
    it to do some other work).

    The idea behind it is: if an extension point has a name which is equal to a bean name in the application context and no class is specified, then a new extension is constructed during the extension loading process and
    provided to the extended plugin.

    I think I cannot express it very well, so, here is an example:

    plugin.xml contains

    Code:
    <plugin start="true">
       <uid>my.data.plugin</uid>
       <name>My Data Plugin</name>
       <lifecycleclass>xyz.plugin.data.DbMaintenance</lifecycleclass>
       <extensionpoints>
          <extensionpoint name="dataSource" />
       </extensionpoints>
    </plugin>
    Extension point "dataSource" is a bean which is configured in the main application's spring context.

    The plugin java code which uses the bean called dataSource looks like this:

    Code:
    public class DbMaintenance extends SpringPlugin &#123;
    
    	private DriverManagerDataSource ds;
    
    	public DbMaintenance&#40;&#41; &#123;
    		super&#40;&#41;;
    	&#125;
    
    	protected void onInitialize&#40;&#41; &#123;
    		// do something useful
    	&#125;
    
    	protected void onStart&#40;&#41; &#123;
    		log.info&#40;"Starting"&#41;;
    		ds = &#40;DriverManagerDataSource&#41; getBean&#40;"dataSource"&#41;;
    		log.info&#40;"data source driver&#58; " + ds.getDriverClassName&#40;&#41;&#41;;
    		// ...
    	&#125;
    
    	protected void stop&#40;&#41; &#123;
    		log.info&#40;"Stopping"&#41;;
    		// clean up by de-referencing the extensions
    		ds = null;
    	&#125;
    
    &#125;
    Additionally, I have introduced a default spring configuration file 'plugin-context.xml' which can be used to configure beans which
    are not injected from the application context, but defined in the plugin itself.

    Using this method, a bean 'hibernateDao' defined in plugin-context.xml can be retrieved with
    Code:
    	HibernateDao dao = &#40;HibernateDao&#41; getBean&#40;"hibernateDao"&#41;;
    I found this a convenient way to avoid app context creation code.

    If there is interest in this code, I could test it and submit a patch for platonos and for spring rich client.


    Kambiz

  • #2
    I am interested. I need a plugin architecture. My application must be capable of being modified dynamically as it discovers and loads/unloads plugins.

    It seems to me that your extension might belong in the Spring framework proper, not RC. Not only client apps would benefit from plugins.

    Also, shouldn't the extension point always be defined as an interface (as Platonos has it), with an extension possibly supplied as a bean? You define the extension point as a bean. That does not seem right or am I missing something?

    How about this:

    Code:
    <plugin start="true">
       <uid>my.data.plugin</uid>
       <name>My Data Plugin</name>
       <lifecycleclass>xyz.plugin.data.DbMaintenance</lifecycleclass>
       <extensionpoints>
          <extensionpoint name="dataSource"  interface="javax.sql.DataSource"/>
       </extensionpoints>
    </plugin>
    
    <plugin>
       <uid>my.data.extension</uid>
       <name>Extension pluging</name>
       <extensions>
          <extension uid="my.data.plugin" name="dataSource" bean="myDataSourceBean" /> <!-- bean defined in plugin -->
       </extensions>
    </plugin>
    The onStart() method in DbMaintenance is unaware that the extension comes from a Spring bean. It iterates over extensions as in the Platonos examples.

    The question that needs to be resolved is what exactly is the nature of the relationship between Platonos and Spring.

    Comment


    • #3
      The problem that I tried to solve for myself was: how can I hand over a Spring configured bean which exists in my application context to a plugin. In fact, this is a special case of the general use which you outline.

      What you propose for plugins which extend others, is absolutely necessary and should be implemented:

      Code:
         <extensions>
            <extension uid="my.data.plugin" name="dataSource" bean="myDataSourceBean" /> <!-- bean defined in plugin -->
         </extensions>

      The question that needs to be resolved is what exactly is the nature of the relationship between Platonos and Spring.
      Well, this is why I asked. I have solved my problem which can be roughly sketched as follows:

      - I need a way of delivering small, relatively independent modules ideally in form of a jar file to my customers.

      - If the jar is put in a certain directory, it should be loaded into the main application and start its work.

      - most such modules need services from the main application or from other plugins to be able to do their work. These services already exist either in the main application context or in the plugin context of other plugins

      Instead of creating an own api e.g. like the one Andy proposed a while back (http://forum.springframework.org/showthread.php?t=10657), I took platonos and tried to adapt it to my needs.

      And it works well: I don't have to take care of class loader issues. I just drop the jar into a directory, which is watched by the PluginManager:

      Code:
      	<bean id="pluginLauncher" class="org.springframework.richclient.plugin.PluginEngineLauncher">
      		<property name="uniqueId" value="MyApp" />
      		<property name="location" value="plugins" />
      	</bean>
      Kambiz
      Last edited by robyn; May 14th, 2006, 08:26 PM.

      Comment


      • #4
        I have the same requirements: dynamically extending a running application without class loader snafus. In fact I want an app that is configured with Spring and mostly assembled and extendable on-the-fly from plugins.

        The more specific question is: what should the relationship be between BeanFactory/ApplicationContext and PluginEngine?

        Comment


        • #5
          The more specific question is: what should the relationship be between BeanFactory/ApplicationContext and PluginEngine?
          The PluginEngine takes care of loading (possibly even unloading) the plugins and satisfying the extension points. I just sits there and waits for new jars to be dropped into the watched directory. If if finds a new plugin, it loads and starts it. This functionality fits into a 64 KB jar.

          In my implementation, each plugin has a context which is set up automatically. Beans which are not configured in plugin-context.xml can be accessed by injecting them either from other plugins or from the main application's app context.

          And you don't even have to bother whether a special bean which you are requesting from the BeanFactory is defined in the context of your plugin, or not.

          Kambiz

          Comment


          • #6
            Did you look at the Java Plugin Framework (http://jpf.sourceforge.net/index.html)?

            Comment


            • #7
              No, I didn't know of it. At a glance, it looks good, too. The DTD describes many parameters which can be defined for an extension.

              If there were others interested in a plugin architecture, I would have a closer look at it.

              Following the Spring philosophy, one could try to integrate both.

              But, I'm not sure whether there's enough interest in it.


              Kambiz

              Comment


              • #8
                I just started looking the implementation of both Platonos and JPF. One important difference is that JPF is defined with interfaces that it implements. So it is meant to be easily extended. Platonos is all classes, no interfaces.

                I also note that JPF does not define an interface as part of the contract between an extension point and an extension, the way Platonos does. Which can be remedied.

                JPF's API seems to lead to more verbose code than Platonos, but JPF should be easier to extend than Platonos to play along with Spring.

                There's also the Eclipse OSGi plugin framework which can be lifted and reused. I saw a presentation last night at the Maine JUG of a project who did just that (Quantrix - which is a very cool Java-based product).

                Comment


                • #9
                  OSGi is the Java plugin standard (adopted by Eclipse) and there's a high-quality open-source implementation from Knopflerfish (rolls off the tongue, doesn't it?)

                  I am going thru the doc and I am pretty sure that's what I'll use in conjunction with Spring.

                  Comment


                  • #10
                    Wow, this is a full-fleged osgi implementation!

                    I hope there is a simple way of integrating it with spring rich.

                    Looking forward to your results, Jean-Francois.

                    Kambiz

                    Comment


                    • #11
                      Integration should be simple and transparent.

                      OSGi bundles (the plugins) are described in their jar manifests (no XML). The manifest specifies what packages are imported and exported, what services are imported (extensions point) and exported (extensions) and where the bundle's activator class is (the lifecycle class).

                      A "Spring bundle" would be just like a normal Spring-configured application. The bundle activator class would get an ApplicationContext and get its component beans the usual way.

                      The question is how can a bundle export a bean as a service implementation (i.e. how can a bean act as an extension).

                      OSGi defines the concept of Service Factory. Instead of directly publishing a class that implements a service interface, a bundle can use indirection and publish a ServiceFactory that will dynamically provide the proper service implementation when asked. The ServiceFactory would be configured by Spring so that it provides the proper bean.

                      Voila. That should do it.

                      The downside is that Service Factories require a bit more work because of lifecycle responsibilities (clean up) that are otherwise taken care of automatically by the framework when straight services are used (i.e. no indirection).

                      See the R3 specifications on the OSGi site (free subscription required)

                      Comment


                      • #12
                        I've been working with OSGi for the past week or so, and have messed around with Spring integration. There is already an available bundle for OSGi called "ServiceBinder" which gives sort of an IoC pattern to service discovery (this ServiceBinder has made it into OSGi R4 and is called "Declarative Services").

                        Here's an example of a Spring+ServiceBinder config file that creates a Hibernate service from a bean definition (I've modified the Spring DTD a bit):

                        Code:
                        <?xml version="1.0" encoding="UTF-8" ?>
                        <!DOCTYPE beans PUBLIC "-//SPRING//DTD BEAN//EN" "binder-beans.dtd">
                        
                        <beans>
                            <bean id="hibernateServiceImpl" singleton="false"
                                class="test.orm.hibernate.impl.HibernateServiceImpl">
                        
                                <instance>
                                    <provides interface="test.orm.hibernate.HibernateService"/>
                                    <osgiproperty name="version" value="1" type="string"/>
                                    <desires
                                        service="test.service.ServiceProvider"
                                        filter="&#40;version=*&#41;"
                                        cardinality="0..1"
                                        policy="dynamic"
                                        bind-method="setService"
                                        unbind-method="unsetService"
                                    />
                                </instance>
                        		
                                <property name="dataSource"><ref bean="hibernateDataSource"/></property>
                                <property name="properties">
                                    <props>
                                        <prop key="hibernate.dialect"> org.hibernate.dialect.MySQLDialect </prop>
                                        <prop key="hibernate.jdbc.batch_size">0</prop>
                                        <prop key="hibernate.show_sql">true</prop>
                                    </props>
                                </property>
                        
                            </bean>
                        
                            <bean id="hibernateDataSource" class= "org.apache.commons.dbcp.BasicDataSource">
                                ...
                            </bean>
                        </beans>
                        This condig would be packaged with the plugin, which can be loaded, unloaded, started, and stopped at runtime.

                        More information about it can be found at this recent felix-dev thread (Felix is Apache's OSGi implementation): http://mail-archives.apache.org/mod_...l.gmail.com%3e

                        Jeremy

                        Comment


                        • #13
                          Some related notes on the OSGi.

                          There is a new JSR that addresses this subject: JSR 277 JavaTM Module System, see point 2.6 especially. http://jcp.org/en/jsr/detail?id=277

                          More info on ServiceBinder: http://gravity.sourceforge.net/servicebinder/

                          And wikipedia entry: http://en.wikipedia.org/wiki/OSGi

                          Comment


                          • #14
                            The ServiceBinder integration with Spring sounds great. I look forward to trying it out.

                            Unfortunately, the zip file at http://www.rit.edu/~jrv4595/springservicebinder.zip is corrupt

                            Also I believe the Apache incubator project is called Oscar, not Felix. You may be mixing up your Odd Couple characters...

                            Comment


                            • #15
                              I just saw that project Oscar was renamed to Felix. That's good. Felix was the neat one.

                              Comment

                              Working...
                              X