Hitachi Vantara Pentaho Community Wiki
Child pages
  • Pentaho ObjectFactory and Spring Enhancements

Versions Compared

Key

  • This line was added.
  • This line was removed.
  • Formatting was changed.
Comment: Migration of unmigrated content due to installation of a new plugin

Pentaho ObjectFactory and Spring Enhancements in 5.0

Introduction

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.

Background Architecture

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.

New Enhancements

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.

PentahoSystem:

Call

Description

PentahoSystem.getAll()

Retrieve a list of implementations for a given type (i.e. all IContentGenerators). Ordered by priority

PentahoSystem.get()

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.

PentahoSystem.getObjectReference(Type)

Returns a descriptor for a registered implementation containing all attributes and a method getObject() to instantiate the referenced type.

Spring:

Spring Element

Description

<pen:bean class="com.foo.Bar"/>

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.

<pen:list class="com.foo.Bar"/>

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.

<pen:attributes>

Provide attribute metadata about a published bean, or use in conjuction with <pen:bean> or <pen:list> to query for specific implementations.
A special named attribute "priority" is used by the system to determine the order of 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.

Usage Examples

Register a single implementation of a given interface org.pentaho.IDatasource.

Code Block
xml
xml
<?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>

...

Code Block
xml
xml
<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

Code Block
xml
xml
<bean class="org.pentaho.MyDatasource"> 
  <pen:publish as-type="INTERFACES"/> 
</bean> 

<bean class="org.pentaho.MyCustomDatasource"> 
  <pen:publish as-type="INTERFACES"/>
    <pen:attributes> 
      <pen:attr key="priority" value="30"/> 
    </pen:attributes> 
  </pen:publish> 
</bean> 

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.

Code Block
xml
xml
<bean class="org.pentaho.MyDatasource"> 
  <pen:publish as-type="INTERFACES"/>
    <pen:attributes> 
      <pen:attr key="type" value="jdbc"/> 
    </pen:attributes> 
  </pen:publish> 
</bean> 

<bean class="org.pentaho.MyOlapDatasource"> 
  <pen:publish as-type="INTERFACES"/>
    <pen:attributes> 
      <pen:attr key="type" value="olap"/> 
    </pen:attributes> 
  </pen:publish> 
</bean> 

You can now query for the highest priority implementation of IDatasource matching the type=olap using the following

...

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 use to drive which one is used in the system.

Code Block
xml
xml

<bean class="com.foo.StandardWidgetProvider">
  <pen:publish as-type="INTERFACES">
    <pen:attributes>
      <pen:attr key="caching" value="false"/>
    </pen:attributes>
  </pen:publish>
</bean>

<bean class="com.foo.CachingWidgetProvider">
  <pen:publish as-type="INTERFACES">
    <pen:attributes>
      <pen:attr key="caching" value="true"/>
    </pen:attributes>
  </pen:publish>
</bean>

<!-- re-publish the correct one at a higher priority -->

<pen:bean class="com.foo.IWidgetProvider">
  <!-- find the one by confguration -->
  <pen:attributes>
    <pen:attr key="caching" value="${widgetSettings.cache}"/>
  </pen:attributes>

  <!-- re-publish at higher priority -->
  <pen:publish as-type="INTERFACES">
    <pen:attributes>
      <pen:attr key="priority" value="50"/>
    </pen:attributes>
  </pen:publish>
</pen:bean>

Now that we've re-published the correct bean, the following calls will return the correct implementation without any knowledge of the configuration itself.

Code Block

PentahoSystem.get(com.foo.IWidgetProvider.class)

<pen:bean class="com.foo.IWidgetProvider"/>

Anchor
systemConfig
systemConfig

ISystemConfig

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.

ISystemConfig holds a collection of IConfiguration(s) objects by name. You can gain a reference to a named configuration with the following:

Code Block
java
java

ISystemConfig sysConfig = PentahoSystem.get(ISystemConfig.class);
IConfiguration aConfig = sysConfig.getConfiguration("someConfig");

ISystemConfig also supports programmatically registering new IConfiguration(s) as well as listing all available configurations.

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.

Programmatic Usage:

Code Block
java
java

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);

If you're simply accessing properties, you can call a convenience method directly on ISystemConfig using a CONFIG.PROPEPRTY notation.

Code Block
java
java

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

Code Block
xml
xml

  <bean class="org.pentaho.platform.config.PentahoPropertyPlaceholderConfigurer" >
    <constructor-arg>
      <pen:bean class="org.pentaho.platform.api.engine.ISystemConfig"/>
    </constructor-arg>
  </bean>

Injection is the same as with the Spring Property replacements using the ${CONFIG.PROP} notation

Code Block
xml
xml

<bean class="MyClass">
  <property name="someProperty" value="${someConfig.someProperty}"/>
</bean>

You can provide new IConfiguration(s) from within Spring as well. The ISystemConfig is leveraging the <pen:list/> to collect all available IConfiguration implementations in the system. Below is an example from 5.0 registering the security.properties file as a "security" configuration.

Code Block
xml
xml

  <bean class="org.pentaho.platform.config.SolutionPropertiesFileConfiguration">
    <constructor-arg value="security"/>
    <constructor-arg value="security.properties"/>
    <pen:publish as-type="INTERFACES"/>
  </bean>

Other built-in configurations are available for "repository" corresponding to the pentaho-solutions/system/repository.spring.xml and "system" corresponding to the pentaho-solutions/system/system.properties

The intent of the system is to supplant the usage of pentaho.xml and Plugin settings.xml files. An IConfiguration implementation wrapping the pentaho.xml is available though not installed by default (SystemSettingsConfiguration). The decision was made to scrap pentaho.xml in a later release instead of hiding it.

Plugins should transition to this new system and provide a configuration for their internal use as well as from the system:

Code Block
xml
xml

  <bean class="org.pentaho.platform.config.SolutionPropertiesFileConfiguration">
    <constructor-arg value="myPlugin"/>
    <constructor-arg value="myPlugin/plugin.properties"/>
    <pen:publish as-type="INTERFACES"/>
  </bean>