How To Develop an Extension

Overview

If you wish to extend the behavior of the alakai system, and no suitable extension exists within our extensions registry, these are the steps to follow to write your own. First of all, you need to determine which type of extension you are writing. As defined within the user guide, the types include Application, Binding, Connector, Container, Engine, Expression, Message, Policy, Schema, Server, IDL and Feature. Note, that Feature extensions are a special type of Extension and are deployed and managed by alakai differently. The steps required to develop them, however, are roughly the same. Each of the aforementioned types defines a general contract in terms of the behavior expected from the extension. You are free to implement the behavior in any way you'd like, however, and may add new behaviors (by defining new API methods) as required. Ready?

Define the Extension API

To define your extension's behavior, you will create a class which exposes a set of public methods which will be invoked by the users of your extension, i.e. by the alakai system itself and by other extensions. Depending upon the type of extension you are writing, you'll need to define an interface which extends a type specific extension of the RootExtension interface. In many cases, we've created an abstract class which already implements the required interface and which has an implementation of the boiler plate stuff already built-in for you.

When deciding which interface to implement or which abstract class to extend, as may be the case, use the following table as a guide. Note that the table includes a link to an example extension of the indicated type, which you can use as a reference, when coding your extension API.

Extension Type Description Implement/Extend Example
Runtime Application Provides a static application component's runtime behavior. AbstractApplicationRT SpringApplication
Runtime Bindings Provides a static binding component's runtime behavior. BindingRT SOAPBinding
Connectors A factory for creating type specific connections to a resource manager. Connector DataSourceConnector
Container Encapsulates connector management (JCA) behavior implemented by a system. Container StandaloneContainer
Feature Encapsulates an abstract 'piece' of functionality. Feature CredentialStoreFeature
Runtime Engines Responsible for instantiating and executing a runtime application. Engine SpringEngine
Runtime Messages Provides an abstract message component's runtime behavior. Message DefaltMessage
Policy Expression Provides static policy component's runtime behavior. PolicyDocument WSPolicyDocument
Schema Documents Provides a static schema component's runtime behavior. SchemaDocument XMLSchema
Server Encapsulates feature management behavior implemented by a system. Server StandaloneServer
IDL Document Provides a static IDL document's (e.g. WSDL) runtime behavior. IDLDocument WSDL20Document

One important note regarding your Extension interface/class. By convention, the class/interface must enclose a nested interface which extends ExtensionProvider. The interface/class your interface/class extends will contain a nested instance of this interface which your nested instance will extend. A picture is worth a thousand words in this case. Take a look at the SpringEngine API Example below. Note the nested Provider interface which extends the interface EngineRT.Provider which is, as you can tell by the name, defined in the parent interface - EngineRT . We'll explain how the provider interface is used within the section on Coding the Extension Provider.

Extension API Code Examples

TODO

TODO

TODO

TODO

public final class SpringEngine extends EngineRT implements MyApplication {

  public static final String TYPE = "http://bluestemsoftware.org/open/eoa/engine/spring/1.0";
  public static final String PROVIDER_SCHEMA_LOCATION = "classpath:///schema/http.bluestemsoftware.org.open.eoa.engine.spring.1.0.xsd";
  
  private Set<String> requiredFeatures;
  
  public interface Provider extends EngineRT.Provider {

      public PartnerApplication spi_getPartner(QName engineName);

      ...

  }

  public SpringEngine(SpringEngineFactory factory, Provider provider, ComponentName name, Map<QName, EngineReference> engineReferences, Set<String> requiredFeatures) {
      super(factory, provider, name, engineReferences);
      if (requiredFeatures == null) {
          throw new IllegalArgumentException("required features null");
      }
      this.requiredFeatures = requiredFeatures;
  }

  /*
   * (non-Javadoc)
   * @see org.bluestemsoftware.specification.eoa.component.engine.rt.EngineRT#getRequiredApplicationFeatures()
   */
  @Override
  public Set<String> getRequiredApplicationFeatures() {
      return requiredFeatures;
  }

  /*
   * (non-Javadoc)
   * @see org.bluestemsoftware.specification.eoa.ext.application.spring10.api.MyApplication#getPartner(javax.xml.namespace.QName)
   */
  public PartnerApplication getPartner(QName engineName) {
      Thread thread = Thread.currentThread();
      ClassLoader cl = thread.getContextClassLoader();
      try {
          thread.setContextClassLoader(factory.getFactoryContext().getClassLoader());
          return ((Provider)provider).spi_getPartner(engineName);
      } finally {
          thread.setContextClassLoader(cl);
      }
  }

  ...

}
TODO

TODO

TODO

TODO

TODO

TODO

Define the Extension Factory API

The EOA specification uses the factory pattern to create Extension instances. So the next step in defining your extension is to define a factory class which will be used by alakai to create your extension. Again, depending upon the type of extension you are writing, you'll need to define a class which extends a type specific instance of ExtensionFactory. Use the following table as a guide. Note that the table includes a link to an example extension of the indicated type, which you can use as a reference, when coding your extension API.

Factory Type Description Extend Example
Runtime Application Factory Creates type specific runtime application instances. ApplicationFactory SpringApplicationFactory
Runtime Binding Factory Creates type specific runtime binding instances. BindingFactory SOAPBindingFactory
Connector Factory Creates connector instances. ConnectorFactory DataSourceConnectorFactory
Container Factory Creates a container instance. ContainerFactory StandaloneContainerFactory
Runtime Engine Factory Creates runtime engine instances. EngineFactory SpringEngineFactory
Feature Factory Creates feature instances. FeatureFactory CredentialStoreFeatureFactory
Runtime Message Factory Creates runtime message instances. MessageFactory DefaultMessageFactory
Policy Expression Factory Creates policy expression instances. PolicyFactory WSPolicyFactory
Schema Document Factory Creates schema document instances. SchemaFactory XMLSchemaFactory
Server Factory Creates a server instance. ServerFactory StandaloneServerFactory
IDL Document Factory Creates IDL document instances. IDLFactory WSDL20DocumentFactory

One important note regarding your ExtensionFactory class. By convention, the class must contain a nested interface which extends ExtensionFactoryProvider. The class your class extends will contain a nested instance of this interface which your nested interface will extend. Again, a picture is worth a thousand words in this case. Take a look at the SpringEngineFactory API Example below. Note the nested Provider interface. We'll explain how this interface is used within the section on on Coding the Extension Factory Provider.

Extension Factory API Code Examples

TODO

TODO

TODO

TODO

public final class SpringEngineFactory extends EngineFactory {

  public interface Provider extends EngineFactory.Provider {
      public SpringEngine.Provider spi_createEngine(SpringEngineConfiguration configuration);
  }

  /*
   * (non-Javadoc)
   * @see org.bluestemsoftware.specification.eoa.ext.ExtensionFactory#getExtensionType()
   */
  public String getExtensionType() {
      return SpringEngine.TYPE;
  }

  /*
   * (non-Javadoc)
   * @see org.bluestemsoftware.specification.eoa.component.rt.ProviderReader#readProviders(org.bluestemsoftware.specification.eoa.component.ComponentContext,
   *      javax.xml.transform.dom.DOMSource)
   */
  public Set<EngineRT> readProviders(ComponentContext componentContext, DOMSource source) throws DeploymentException {

      ...

      Thread thread = Thread.currentThread();
      ClassLoader cl = thread.getContextClassLoader();
      try {

          thread.setContextClassLoader(factoryContext.getClassLoader());
          
          ...

          SpringEngine.Provider p = ((Provider)provider).spi_createEngine(spe);
          providers.add(new SpringEngine(this, p, cname, engineReferences, requiredFeatures));

          return providers;

      } finally {
          thread.setContextClassLoader(cl);
      }

  }

  ...

}
TODO

TODO

TODO

TODO

TODO

TODO

Note also that the Extension and ExtensionFactory class, and other supporting classes, e.g. exceptions thrown by your Extension, which define your extension's API must be defined in a project whose artifact will be added to the alakai shared classpath. This is separate and apart from the project which will contain the classes which provide your extension's behavior as described in the Code the Extension Provider and the Code the Extension Factory Provider sections.

As explained within the user guide, adding the artifact which contains your extension API to the shared classpath allows the system to effectively "hide" the provider specific implementation classes from the users of your API, i.e. by confining them to the extension provider's deployment classloader. . Comprende?

If you are an Alakai project committer, the interfaces/classes should be defined within the specification-eoa-ext-api project. Otherwise, you should create a project for your particular organization (which you are free to license in any way that you'd like) which will contain all of your API interfaces/classes.

Create the Project

Next, you need to set-up your extension project. Because you may refer back to this more than once, we separated the steps out into a separate how to. When following these steps, make sure you set the archetype property to 'extension.'

Code the Extension Provider

The EOA specification makes a distinction between the provider which "provides" the Extension behavior and the API which defines the Extension behavior. The Extension provider is defined within a separate project from the project which contains the API, i.e. the provider and supporting classes will be contained within the project you created in the previous step. The only requirement being that the provider implement the nested Provider interface defined on your extension's API. Using the SpringEngine example above, your provider would implement SpringEngine.Provider.

Note that as a convention, the provider interface methods all begin with the prefix spi_ which stands for "service provider interface." This was done to avoid the potential for method name clash with other methods your class may be required to implement, i.e. as a result of implementing other interfaces. Also, note the injection of the extension's Consumer, i.e. the API class. This provides some useful hooks back into the EOA system API as indicated in the code excerpt from a Feature extension.

/*
 * (non-Javadoc)
 * @see org.bluestemsoftware.specification.eoa.ext.Extension$Provider#spi_setConsumer(Extension.Consumer)
 */
public void spi_setConsumer(Extension consumer) {
    this.consumer = (CredentialStoreFeature)consumer;
    this.factory = (CredentialStoreFeatureFactory)((CredentialStoreFeature)consumer).getExtensionFactory();
    this.deploymentContext = factory.getFactoryContext();
}

Code the Extension Factory Provider

The same requirements exist when coding your ExtensionFactory provider. Using the SpringEngineFactory example above, your provider would implement SpringEngineFactory.Provider. Now you're almost done. One last requirement. Your ExtensionFactory deployment, must contain a deployment descriptor as explained in the user guide, which identifies the fully qualified class name of your ExtensionFactory provider. And just in case you're wondering how alakai identifies the associated Extension API ...

Recall that the interface implemented by your ExtensionFactory provider must be a nested interface enclosed within the ExtensionFactory class as depicted in the above example . Alakai uses reflection to work its way up to the enclosing ExtensionFactory class. It then creates an instance of this class and registers it with the URI retrieved from the factory's getExtensionType() method. When a runtime instance of your extension, as defined within a component deployment, is encountered by alakai, the namespace used within the xml representation of the runtime component is used to retrieve an instance of the ExtensionFactory. The factory is then used to create an instance of your Extension . The factory delegates this to your ExtensionFactory provider after first switching the context class loader to the factory deployments classloader as depicted in the readProviders method in the above example. Note that your Extension is also responsible for switching the context classloader prior to invoking methods on the Extension provider as depicted in the getPartner method on the above example.

Test the Extension

Now that you've built your extension you need to test it (oops, test first - yeah right.) Because you may refer back to this more than once, we've separated the steps out into a separate how to.