Pentaho ObjectFactory and Spring Enhancements in 5.0
Version 5.0 of the Pentaho Suite introduces several enhancements to core architecture of Platform. These enhancements are designed to aid the development of new features as well as allowing more customization options for existing features.
The Pentaho Platform started with a pure service-locator facility to provide plugability of implementations and factoring of objects. Static access to this service-locator was provided through PentahoSystem.get() calls and it was backed by a rudimentary Object Factory and registery.
Anyone trying to customize the system prior to 5.0 had to drop jars into the WAR and modify core Spring files. Maintainability was difficult.
To start with, the ObjectFactory backing PentahoSystem is no longer based on a single Spring ApplicationContext. There can now be any number of registered ObjectFactories registered with the system. Queries for a particular type will find the most appropriate implementation from the registered ObjectFactories.
5.0 brings features both to the PentahoSystem service locator as well as Spring. Though as stated, usage of PentahoSystem should be avoided where possible.
Retrieve a list of implementations for a given type (i.e. all IContentGenerators). Ordered by priority
Now returns the highest priority implementation registered in the system.
PentahoSystem.get(Type, Map<String, String>)
Query for an implementation with the given properties. Ordered by priority.
Returns a descriptor for a registered implementation containing all attributes and a method getObject() to instantiate the referenced type.
Retrieve the highest priority implementation for the given type. Published beans are given highest priority when searching for an implementation. If no beans have been published for the type, each registered ObjectFactory will be checked to see if they have an implementation (simple <bean>). The first one found will be returned.
Retrieve a list of implementations for a given type (i.e. all IContentGenerators). Ordered by priority. unlike <pen:bean> only published implementations will be included in the list.
Provide attribute metadata about a published bean, or use in conjuction with <pen:bean> or <pen:list> to query for specific implementations.
Once published the bean can be found by others calling <pen:bean> or <pen:list>. the as-Type attribute controls how the bean is registered. The options are INTERFACES, CLASSES, ALL or a specific class as seen above. INTERFACES will publish the bean registering it as an implementation of all interfaces for which the bean implements. CLASSES will publish it as an implementation of all classes from which it inherits, including itself. ALL publishes as both Classes and Interfaces. The default is to publish as the class itself.
Register a single implementation of a given interface org.pentaho.IDatasource.
<?xml version="1.0" encoding="UTF-8"?> <beans xmlns="http://www.springframework.org/schema/beans" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:pen="http://www.pentaho.com/schema/pentaho-system" xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans-2.5.xsd http://jax-ws.dev.java.net/spring/core http://jax-ws.dev.java.net/spring/core.xsd http://www.pentaho.com/schema/pentaho-system http://www.pentaho.com/schema/pentaho-system.xsd"> <!-- Register this ApplicationContext so it can publish beans --> <bean class="org.pentaho.platform.engine.core.system.objfac.spring.ApplicationContextPentahoSystemRegisterer" scope="singleton"/> <bean class="org.pentaho.MyDatasource"> <pen:publish as-type="INTERFACES"/> </bean> </beans>
<bean class="com.foo.MyObject"> <property name="datasource"> <pen:bean class="org.pentaho.IDatasource"/> </property> </bean>
Register multiple implementations, using Priority to determine which will be provided
By default all beans are given a priority of 20. You control which will be returned by PentahoSystem.get() and <pen:bean> by specifying a higher priority in one of the published beans
Even though two implementations of IDatasource are registered, the second will be returned by PentahoSystem.get() and <pen:bean> as it's now the highest priority. Calls to PentahoSystem.getAll() or <pen:list> will return both, ordered by priority.
Register multiple implementations, using attributes to determine which will be provided
Lets say you know need an implementation of IDatasource which provides connections to a particular system. You could create a sub-type and query for that, or you can use the Attribute metadata feature to return the one you need.
Of course in this example the list will contain only one entry.
Republish a bean based on configuration.
There are times when you want the implementation found to be based on configuration and not priority, but updating every PentahoSystem.get() call or <pen:bean> reference is burdensome. To avoid this you can combine the concepts above to achieve the same effect without having to modify every area. This technique is used in several places in 5.0
Say you have two implementations of com.foo.IWidgetProvider, one with aggressive caching and the other without. You setup a property file using the ISystemConfig detailed in the next section which you want use to drive which one is used in the system.
Prior to 5.0 configuration of objects was accomplished by either the SystemSettings object (pentaho.xml), through Spring property replacement, or if within a plugin by way of the settings.xml file. Unfortunately, these systems didn't interoperate well at all. ISystemConfig has been designed to unify configuration with access both programmatically and through Spring.
IConfiguration provides two methods to the user. getProperties() returning a standard java Properties object and update(Properties) which will write-back to the underlying storage if supported.
ISystemConfig sysConfig = PentahoSystem.get(ISystemConfig.class); IConfiguration aConfig = sysConfig.getConfiguration("someConfig"); Properties props = aConfig.getProperties(); String someStr = props.getProperty("someProperty"); // update a config props.setProperty("someProperty", "newValue"); aConfig.update(props);
ISystemConfig sysConfig = PentahoSystem.get(ISystemConfig.class); String someStr = sysConfig.getProperty("someConfig.someProperty");
Interaction with Spring
If you're familiar with Spring Property Replacement system the following will look familiar. You can inject values from the ISystemConfig into your beans by adding the following to your ApplicationContent XML document