Showing posts with label OSGi. Show all posts
Showing posts with label OSGi. Show all posts

Wednesday, June 22, 2016

camunda BPM platform OSGi 2.0.0 released

It has been a while since we had the last release of camunda BPM platform OSGi that included some new features and I am glad to be able to announce the new major version today.

The new version includes one new feature,some dependency adjustments and a restructuring of the whole project.

The new feature is the OSGi Event Bridge, which I already explained here. So now you'll be able to receive camunda process events in an OSGi way.

The most notable change in the dependencies is the change from OSGi 4.2 to version 4.3. This version enables e.g. the usage of generics and of the Require-Capabilityand Provide-Capability headers (one example how you could use them is explained in another blog post).

Finally, the whole project is now more modularized. Using one of the 1.x.x versions, many features were included in the camunda-bpm-osgi module, which you always needed. That ways, you would always have the classes for file install, process application or Blueprint present, if you used them or not. With the new structure you can better choose, which features you want to use and which not to.

Configadmin, Fileinstall and Processapplication are now separate bundles and no longer contained in camunda-bpm-osgi. What is left in the "main" module are the capabilities to find process definitions in your bundles, EL resolving, locating scripting engines and utility classes, e.g. for classloading. Also, all integration tests (except for the Karaf ones), are now located in a central itest module.

I hope all those changes ease the use for you to combine the powers of OSGi and camunda BPM. If you have any feedback or would like to make a wish for a new feature, feel free to leave a comment, open an issue on GitHub or open a pull request.

Wednesday, February 24, 2016

Extension/Service/Plugin mechanisms in Java

Since I started to deep dive into OSGi I was wondering more and more how frameworks that have some way of extension mechanism, e.g. Apache Camel where you can define your own endpoint or the Eclipse IDE with its plugins, handle finding and instantiating extensions. I remember very well a presentation from the JAX 2013, it was by Kai Tödter, where he showed the combination of Vaadin and OSGi. While the web app was running he could add and remove menu entries, just by starting and stopping the bundles.
For a while now I have taken a look at several approaches on how to create an extensible application and you can find resources for every single method. I want to give a medium sized (not short ;)) overview here of the different ways I know to make a Java application extensible. Also, I will add a list of advantages and disadvantages, from my point of view, to each method. For every method I try to give a simple example.
To avoid confusion, when I write about the advantages and disadvantages, I will write from the point of view, as if you want to provide this extension mechanism in your framework, not from the API consumer point of view.

Passing the object

This is the most obvious method. The framework defines a method which takes the SPI interface and you simply pass the object. Camel, next to other methods, makes use of this (example taken from the Camel FAQ):
CamelContext context = new DefaultCamelContext();
context.addComponent("foo", new FooComponent(context));
Internally, Camel doesn't do much magic (code taken from Camel on GitHub).
public void addComponent(String componentName, final Component component) {
    ObjectHelper.notNull(component, "component");
    synchronized (components) {
        if (components.containsKey(componentName)) {
            throw new IllegalArgumentException("Cannot add component as its already previously added: " + componentName);
        }
        component.setCamelContext(this);
        components.put(componentName, component);
        for (LifecycleStrategy strategy : lifecycleStrategies) {
            strategy.onComponentAdd(componentName, component);
        }

        // keep reference to properties component up to date
        if (component instanceof PropertiesComponent && "properties".equals(componentName)) {
            propertiesComponent = (PropertiesComponent) component;
        }
    }
}
Every component has to have an unique name and is somehow bound to a lifecycle. Removal of a component is also possible, but has to be made somewhere from the user code.

Advantages

  • Easy and straightforward
  • No need for an additional framework
  • Compiler checks for the correct interface

Disadvantages

  • Access to central class (the plugin/service/component holder) is necessary
  • Allowing changes during the runtime is possible but complicated, since it has to be assured the component is removed everywhere
  • Your framework has to take care of the whole component lifecycle and any additional requirements it enforces

Interface and Reflection

This method is used quite often (basically it is also how the ServiceLoader works, see next section) and you can find it with small variances. The differences are where and how exactly interface and implementation name reach the application. Placing them somewhere inside a properties file or passing them to the framework during startup are most common. The implementation is then instantiated using reflection. Creating a context with an InitialContextFactory works like this e.g.:
  Properties env = new Properties();
  env.put(Context.INITIAL_CONTEXT_FACTORY,
          "org.jboss.naming.remote.client.InitialContextFactory");

Advantages

  • Easy and straightforward
  • No need for an additional framework
  • No need to provide central class (in properties file approach)

Disadvantages

  • No type safety (if text based)
  • Your framework has to take care of the whole lifecycle and any additional requirements it enforces
  • Check for correct wiring only during runtime (if text based, check either at startup or when the code is being called, where the former is better than the latter)

java.util.ServiceLoader

Frameworks using the java.util.ServiceLoader can also be found quite often. What the ServiceLoader does is, it uses during runtime a ClassLoader and checks the META-INF/services directory for a text file, whose name equals the passed interface (SPI) name and then reads the class name inside that file. Then it instantiates the class via Reflection. All the magic happens in the LazyIterator inside the ServiceLoader class (see OpenJDK). Basically, it's just reading a file and instantiating the object. E.g. Camel and HiveMQ use this method.

Advantages

  • Easy and straightforward
  • ServiceLoader is part of JDK
  • No need for an additional framework

Disadvantages

  • No lifecycle
  • Class has to provide standard constructor
  • Support for runtime changes must be implemented (as mentioned here)
  • Check for correct wiring only during runtime (the filename or the string inside the file could be wrong)

(Eclipse) Extension Points

Picture under BSD license, see here
As far as I know the concept of Extension Points never got popular outside Eclipse, although it is possible to include them in every application. To achieve loose coupling the definition of places where you can add your plugin and the plugins themselves is extracted into XML files.
To define an extension point you need something like this:
<?xml version="1.0" encoding="UTF-8"?>
<?eclipse version="3.4"?>
   <extension-point
     id="de.blogspot.wrongtracks.FooService"
     name="FooService"
     schema="schema/de.blogspot.wrongtracks.FooService.exsd"/>
The extension provider then has to define an appropriate extension for that point:
<?xml version="1.0" encoding="UTF-8"?>
<?eclipse version="3.4"?>
<plugin>
   <extension
         point="de.blogspot.wrongtracks.FooService">
      <implementation
            class="com.example.impl.FooServiceImpl"
            id="com.example.impl.FooServiceImpl"
            name="FooServiceImpl">
      </implementation>
   </extension>
</plugin>
I got to admit, that I am not completely sure how exactly you can integrate the extension points, but I guess you will need quite a lot from the basic Eclipse runtime. There is a blog post, which explains how you can use extension points without depending on OSGi.

Advantages

  • Extensions can be added during runtime
  • Good tool support inside Eclipse
  • Wrong wiring only affects single extension
  • Loose coupling (more or less, since the extensions depend on the extension point id)

Disadvantages

  • Dependencies to Eclipse
  • Overhead from the Eclipse platform (I actually cannot prove this point but I assume there must be a considerate overhead involved in comparison to the previous methods)
  • Check for correct wiring only during runtime

Spring XML

The Spring framework tried to find a way for loosely coupled components long before CDI, as we know it today, appeared. Their solution was an XML file in which the different classes are being wired together (I am well aware of the fact that nowadays there are also other ways, but since they are also based on annotations they don't differ enough from CDI as that I'll give them an own paragraph). In the basic XML file you define all your beans and Spring will take care of the instantiation. It is also possible to distribute the configuration among several XML files. A very simple example (taken and modified from the Spring documentation) looks like this:
<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="http://www.springframework.org/schema/beans"
    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">
    <bean id="accountDao"
        class="org.springframework.samples.jpetstore.dao.jpa.JpaAccountDao">
    </bean>

    <bean id="petStore" class="org.springframework.samples.jpetstore.services.PetStoreServiceImpl">
        <property name="accountDao" ref="accountDao"/>
    </bean>
</beans>
If you want to provide your users a way to add their services/plugins to the framework, you'll have to provide a setter method where the users can add their object. E.g. like this (taken from camunda documentation):
<bean id="processEngineConfiguration" class="org.camunda.bpm.engine.spring.SpringProcessEngineConfiguration">
  ...
  <property name="processEnginePlugins">
    <list>
      <bean id="spinPlugin" class="org.camunda.spin.plugin.impl.SpinProcessEnginePlugin" />
    </list>
  </property>
</bean>

Advantages

  • Spring is lightweigth
  • Lifecycle support from Spring

Disadvantages

  • XML needs to be maintained
  • No auto detection, users have to write the XML when they want to add something
  • The Spring IoC container is needed
  • Correct wiring is only checked at startup

OSGi Services

OSGi was created embracing runtime changes and bundles dynamically providing and removing their services. With this in mind OSGi strongly supports applications being extended by services, provided by different bundles. The simplest approach is to implement a ServiceListener or a ServiceTracker. Both should be created on bundle start and they will react when a new implementation of the service appears. A ServiceListener can be as simple as this (taken from the Knoplerfish tutorial):
 ServiceListener sl = new ServiceListener() {
   public void serviceChanged(ServiceEvent ev) {
      ServiceReference sr = ev.getServiceReference();
      switch(ev.getType()) {
        case ServiceEvent.REGISTERED:
          {
             HttpService http = (HttpService)bc.getService(sr);
             http.registerServlet(...);
          }
          break;
        default:
          break;
      }
   }
 };

 String filter = "(objectclass=" + HttpService.class.getName() + ")";
 bc.addServiceListener(sl, filter);
Where bc is a BundleContext object. And a ServiceTracker can be used like this:
ServiceTracker<HttpService,HttpService> serviceTracker = new ServiceTracker<HttpService, HttpService>(bc, HttpService.class, null);
serviceTracker.open();
There are more elegant ways to get hold of an OSGi service using Blueprint, Declarative Services or the Apache Felix Dependency Manager but the ServiceListener is the basic way.

Advantages

  • OSGi lifecycle support
  • Changes during runtime "encouraged" ;)
  • Compiler checks wiring (not for the ServiceListener but for the rest)
  • Problems with services are restricted to single bundle

Disadvantages

  • You have to buy the whole OSGi package: imports, exports, bundles and everything
  • Having the full OSGi lifecycle makes the world more complicated since every service can disappear at every moment

Note about PojoSR/OSGi Light

Since the biggest disadvantage of OSGi is that you have to get the whole package, I want to mention here another approach, which is called PojoSR or OSGi Light. The goal of it is to give you the OSGi service concept without the rest that comes with OSGi. Unfortunately, I could not find much documentation about it and the activity around this project seems to be very low at the moment. There is an article here and the PojoSR framework itself. Also, it looks like PojoSR is now a part of Apache Felix called "Connect", but its version is 0.1.0. So if anyone of you knows more about it, please let me know.

CDI

Contexts and Dependency injection was a big step for Java EE, allowing developers to write more loosely coupled code. The CDI container takes care of automagically wiring the different parts together. The developer only has to use the correct annotations. Depending on which CDI beans are present at runtime, concrete implementations can be changed without changing the code that uses them. When trying to use a class the basic injection looks like this:
@Inject
private MyServiceInterface service;
If there is need to get all of the implementations (which we actually want here), then the class Instance must be used:
@Inject @Any
private Instance<MyServiceInterface> services;
Since Instance is an Iterable a simple for-each loop can be used to access all the objects. Alternatively the select() method can be used to further specify requirements.

Advantages

  • Compiler checks for correct type
  • CDI container checks correct wiring at startup
  • Part of JEE standard but can also be used without application serve (use a JSR-330 implementation like Guice or HK2)r
  • CDI lifecycle support

Disadvantages

  • A CDI container is needed
  • Changes during runtime are not possible
  • Annotatiomania (at least if you don't watch out)

Summary

As you can see many different frameworks/methods evolved in the Java ecosystem. Every single one with its specific advantages and disadvantages. I think we can summarize the different extension mechanisms as three types (with their members):
  1. String and well-known location ("Interface and Reflection", "ServiceLoader", "(Eclipse) Extension Points", "Spring XML")
  2. Programmatic wiring ("Passing the object", "Interface and Reflection", "OSGi Services")
  3. Classpath scanning ("CDI")
Of course the three types are not exclusive. You may provide your users more than one way and let them choose. Also CDI is not exactly the only framework that uses classpath scanning. Spring with its two other ways for configuring the IoC container relies on that method, too.

I hope this article provides an good and sufficient overview of the different methods on how to create an extensible framework. Choosing the right one will make your users surely happy. If you know another method, which I forgot, please let me know, I will gladly add it here.

Please note that the lists of advantages and disadvantages are based on my reasoning. I tried to be objective but like every programmer I have my favorites and my experiences with the frameworks that may make me a little bit biased.

Saturday, February 20, 2016

What can capabilities do for your processes?

Before we release camunda BPM OSGi 2.0 I want to do a little bit more of advertisement for it and show what is possible with the new version. One change in the new version will be, that it depends on OSGi 4.3 and no longer 4.2. One change, besides the fact that I can now use generics in the code (yay!) is that with OSGi 4.3 the capabilities headers will work. So, what's so impressive about them?

Capability headers

The capability headers are two header Provide-Capability and Require-Capability. They are a further abstraction of the Import-Package and Export-Package headers we all (should ;)) know. But with the capability headers you are not as limited as with the package headers. Arbitrary things can be defined, e.g.
Provide-Capability: sensor; type=gyro
would be a valid statement. But you are not limited to one attribute:
Provide-Capability: sensor; type=heat; minTemp=0; maxTemp=100
is also possible. And the bundle that requires such capabilities can use an LDAP filter expression:
Require-Capability: sensor; filter:="(&(type=type=heat)(minTemp=0)(maxTemp=100))"
That ways it is possible to find exactly what is needed in a way that allows to specify more than just packages and versions.
How can you use this for your business processes?

Capability headers for processes

One use-case that came quickly to my mind were process definitions that depend on each other, e.g. if you have a process with a call activity. An example could look like this (please excuse that I didn't prepare an exhaustive example):
Let's call this one the "Hunger process". And the callee process, the "Phone process" can be as simple as this:


The last time I checked there is nothing that would stop you to try to start the Hunger process although the Phone process hasn't been deployed yet. If the Hunger process would be something that you want to start automatically you would run into a nasty exception. Here, the headers can help. You could simply describe in your MANIFEST that you require the Phone process before your bundle can be started:
Require-Capability: process; filter:="(key=Phone_process)"
You could also add a version number or whatever seems useful. The bundle containing the Phone process should then of course contain the appropriate part:
Provide-Capability: process; key=Phone_process
So, when you deploy the bundle with the Hunger process it cannot be started without the bundle containing the Phone process. That ways you can manage your process interdependencies without running into exceptions.
Finally, if you use the maven-bundle-plugin I want to give you a short example.

Setting the headers with the maven-bundle-plugin

With the maven-bundle-plugin it is really easy to set the headers. I'll suppose that you use <packaging>bundle</packaging> in your POM. Here's how you can set the headers:
<plugin>
   <groupId>org.apache.felix</groupId>
   <artifactId>maven-bundle-plugin</artifactId>
   <extensions>true</extensions>
   <configuration>
     <instructions>
       <Provide-Capability>process; key=Phone_process</Provide-Capability>
     </instructions>
   </configuration>
See, piece of cake ;)

I hope I could give you some idea how you could use the capability headers that OSGi 4.3 introduced. This was just a quick example but I think it shows nicely, how OSGi can support your BPMN processes.

Saturday, February 13, 2016

camunda BPM OSGi - Event Bridge

I have implemented the eventing feature already some months ago but I haven't managed to advertise it a little bit more until now. So, let's praise my work ;)

I'll start with some background information, which you can skip if you're familiar with camunda BPM and the OSGi EventAdmin. Then, some information about the what and how follows.

Let's start with OSGi eventing.

OSGi Event Admin

The Event Admin is a part of the OSGi Compendium Specification. It is a way to communicate between bundles in a decoupled way by sending events. The communication follows a publish/subcribe scheme.

One bundle obtains the EventAdmin service, creates an Event object and sends it. Every event is created with a certain topic and can contain arbitrary String properties in a key-value way. Topics are hierarchical separated by a "/" and wildcards are allowed. E.g. org/osgi/framework/BundleEvent/STARTED is a topic used by the OSGi framework.

Events can be sent in a synchronous or asynchronous way and additional LDAP filters can be used based on the properties.

You can find a good example on the Apache Felix website.

Now that we know a little bit about the EventAdmin let's take a look at camunda BPM.

camunda BPM events

During the execution of a process certain events occur, e.g. a task is being assigned or a process end. To be able to "see" those events the user has to register either an ExecutionListener or a TaskListener (for more details see here and here).

The common way to register the listeners is to directly add them to the process definition, i.e. the .bpmn file. But there are certainly cases where we do not own the process file but would like to receive events (e.g. for monitoring).

Let's see how to achieve this in an OSGi environment.

camunda BPM OSGi - Event Bridge

I gotta admit the idea of an event bridge is not my own, because the CDI extension for camunda BPM already has an CDI event bridge. Anyways, for OSGi this feature was missing. I'll explain to you what happens internally and how you can use it.

What happens?

The OSGi event bridge implementation exports a service that is a BpmnParseListener. Whenever the engine parses a process definition this listener will become active and attach TaskListener and ExecutionListener wherever possible. But these listeners aren't full implementations. They are dynamic proxies with a special InvocationHandler.

When the InvocationHandler is being invoked it checks if the OSGi event bridge is still active and if the EventAdmin is present. If yes, it instantiates a new OSGiEventDistributor, which creates a new event and fills the properties.

I've tried to use all properties the camunda events provide and put them into the event properties. You can see a full list in this class.

This is basically what is happening. So, what can you do with the event bridge?

How to use it?

Before you can make use of the OSGi event bridge you have to add the OSGiEventBridgeActivator as a BpmnParseListener to your ProcessEngineConfiguration. You do this with the method setCustomPreBPMNParseListeners(). Unfortunately, there is no way to add the listener to an already created engine. After adding the listener events are being published. The event topics are:
  • org/camunda/bpm/extension/osgi/eventing/TaskEvent
  • org/camunda/bpm/extension/osgi/eventing/Execution
Of course you can use an asterisk after ../eventing/ to match both.

Wherever you want to listen to events, you can create your own EventHandler and subscribe to the topic you need/want. A simple example would be:

EventHandler eventHandler = new EventHandler() {
  @Override
  public void handleEvent(Event event) {
    Logger.getLogger("Event occured: " + event.getTopic());
  }
};
Dictionary props = new Hashtable();
props.put(org.osgi.service.event.EventConstants.EVENT_TOPIC, org.camunda.bpm.extension.osgi.eventing.api.Topics.ALL_EVENTING_EVENTS_TOPIC);
bundleContext.registerService(EventHandler.class.getName(), eventHandler, props);

Since many information is inside the event properties you can also use a more sophisticated LDAP filter expression based on that information. E.g. if you only want to receive events for a certain process you can do this:

EventHandler eventHandler = new EventHandler() {
...
};
Dictionary<String, String> props = new Hashtable<String, String>();props.put(EventConstants.EVENT_TOPIC, Topics.ALL_EVENTING_EVENTS_TOPIC);
props.put(EventConstants.EVENT_FILTER, "(processDefinitionId=invoice");
bundleContext.registerService(EventHandler.class.getName(), eventHandler, props);

And that's it. At the moment there is no way to limit the applications that are allowed to receive events, so everybody can see all the events if he subscribes to them. If you have an idea how to do this in a nice way, please let me know.

I hope you can make good use of the OSGi event bridge. My plan is to release camunda BPM OSGi 2.0.0 (which includes the event bridge) shortly after camunda BPM 7.5.0 is being released.

Thursday, June 11, 2015

camunda BPM Platform OSGi 1.2.0 released

Today (actually secretly last week ;) ) we released camunda BPM platform OSGi 1.2.0. The release only contains a version adjustment to camunda BPM platform 7.3. So if you want to upgrade your version of camunda BPM platform, you can now enjoy the OSGi extension without worries. As always, if you have some remarks or find some bugs, please let me know.

Thursday, January 29, 2015

Cluster your service with the ConfigurationAdmin and Apache Karaf Cellar using the camunda BPM engine as example

Introduction

Initially, this was supposed to be a short introduction about the topic in the title and an opportunity for me to get to know Apache Karaf Cellar. Unfortunately, I couldn't finish the topic until today because I had some unexpected problems. So basically this is going to be a post about the problems I encountered. At the end you'll find a TL;DR; if you just want to get started.

Short introduction into the Configuration Admin Service

From the OSGi wiki: "Configuration Admin is a service which allows configuration information to be passed into components in order to initialise them, without having a dependency on where or how that configuration information is stored."(http://wiki.osgi.org/wiki/Configuration_Admin)

Basically you write a key-value property and a service which can use it. All the "magic" is done by the ConfigurationAdminService, which is part of the OSGi Compendium Specification. A good introduction can be found here. Also the Admin will store it somewhere for you.

Short introduction into Apache Karaf Cellar

Taken from the Cellar website: "Cellar is a clustering solution for Apache Karaf powered by Hazelcast. Cellar allows you to manage a cluster of Karaf instances, providing synchronisation between instances."(http://karaf.apache.org/index/subprojects/cellar.html)

I liked the idea to provide a service on one Karaf instance and see it appear on every instance in the cluster. Especially the combination with a MangedServiceFactory seems like a great idea.

To read more about Cellar see here.

Set up your Apache Karaf

For my example I want to use my MangedProcessEngineFactory from the 1.1.0-SNAPSHOT version of camunda BPM OSGi. You can just clone the repository on GitHub and built it with mvn install.

Because I am quite lazy I started two Karaf instances on my laptop. If you want to do that, too, you'll have to change some port numbers for the second Karaf instance. First, the ports in the etc/org.apache.karaf.management.cfg:

rmiRegistryPort
rmiServerPort

Second the SSH port in the etc/org.apache.karaf.shell.cfg (forgetting this caused me a some trouble). Next we gotta install Cellar on each Karaf instance. Because we want to use the current version, we'll use version 3.0.1 of Cellar. You can find the general installation guide here for instructions about installation and start. Basically you just have to call from the Karaf console

feature:repo-add mvn:org.apache.karaf.cellar/apache-karaf-cellar/3.0.1/xml/features
feature:install cellar

If you somehow plan to build Cellar yourself, I'll recommend to comment out the "samples" module in the root POM. All your Karaf instances should discover each other automatically. Now we got to install and share the camunda-feature (or whichever you want to use) into the cluster.

Install and share a feature

To do this task we have two choices. One would be to activate the listeners in every Karaf instance and use the "basic" commands. Therefore you'll have to set the bundle listener value in the org.apache.karaf.cellar.node.cfg to true (we won't need the other ones in this example):

bundle.listener = true
config.listener = false
feature.listener = false

The other choice would be to use the cluster:* commands. Both will (should) produce the same result so choose whichever you prefer.

As I mentioned, if you prefer the first option (listeners), you can just install everything as usual because the cluster synchronizes every change:

feature:repo-add mvn:org.camunda.bpm.extension.osgi/camunda-bpm-karaf-feature/1.1.0-SNAPSHOT/xml/features
feature:install camunda-bpm-karaf-feature-minimal

(Please note that you'll need my example project installed locally to use it)

(Also please note that there is currently a bug in the camunda feature.xml. You'll have to change the version of camunda-connect-core to 1.0.0-alpha3 to make it work)

If you want to use the "cluster-versions" of those commands, you have to type:

cluster:feature-repo-add default mvn:org.camunda.bpm.extension.osgi/camunda-bpm-karaf-feature/1.1.0-SNAPSHOT/xml/features
cluster:feature-install default camunda-bpm-karaf-feature-minimal

Those commands work like the basic ones but you always have to provide a group.

You should see that the feature got installed on both Karaf instances (check e.g. with features:list | grep -i camunda). Now we need a database.

Setting up the database

I gotta admit, this is were my first problems occurred. Starting from funny and ending at a being a little bit annoyed. My first problem was that I tried to use the in-memory version of H2. This won't work because, logically, every Karaf instance runs in its own JVM. So, because of multiple applications, I started h2 in server mode (see here for more information).

java -cp h2*.jar org.h2.tools.Server jdbc:h2:tcp://localhost/~/test

The next problem was that because of some exceptions the ProcessEngines started and stopped in seemingly random orders. Having the databaseSchemaUpdate property set to create-drop caused problems with tables not being present because of random dropping/creating. I recommend to create the tables yourself (here are the sqls).

This didn't solve all of my database problems. I suspected H2 of not being capable of handling the same user logging in twice (which it is capable of as far as I know now). After that I switched to MySQL.

Setting up MySQL in Karaf

MySQL is a little bit more complicated to set up than H2 because we have to create a proper datasource. First, we need to install Apache Karaf DataSources:

feature:install jdbc

Next, create the datasource

jdbc:create -u sa -p sa -url jdbc:mysql://localhost:3306/test -t MySQL test

The datasource create command has to be executed on both Karafs because the datasource-*.xml that'll be created in the deploy directory won't be copied. For the ProcessEngine to be able to find the MySQL datasource it needs a JNDI name. To give a datasource a JNDI name we need Apache Karaf Naming.

feature:install jndi

Now the datasource will automatically get a JNDI name (check with jndi:names). If you don't see the jndi:* commands you'll have to install the feature manually on the second Karaf.

Finally we need the MySQL connector jar. We can find it here. Simply drop the jar into the deploy directory.

The MySQL database works fine for me so far. Let's take a look at the configuration file.

The configuration file

When I started with this "experiment" I thought that making the use of the etc/ directory in Karaf would be a good idea but now I gotta say: Please, don't try to do this file based. I tried a lot of combinations and it didn't work out. The closest I got was the configuration arriving on both Karafs but only one engine being created. Jean-Baptiste and Achim were really trying to help me on the mailing list. Nevertheless, I couldn't get it running. You are free to try.

Karaf watches the etc/ directory for configuration files. To deploy one for the ManagedProcessEngineFactroy you'll have to name it org.camunda.bpm.extension.osgi.configadmin.ManagedProcessEngineFactory-1.cfg.

I switched to a bundle which contains the configuration.

The configuration bundle

As mentioned before, for a ManagedServiceFactory to create a service it needs one or more configurations. We'll use a simple version of the configuration:

databaseSchemaUpdate=false
jobExecutorActivate=true
processEngineName=TestEngine
databaseType=mysql
dataSourceJndiName=osgi:service/jdbc/test

If you want to try H2, the configuration would look like this:

databaseSchemaUpdate=false
jdbcUrl=jdbc:h2:tcp://localhost/~/test
jobExecutorActivate=true
processEngineName=TestEngine
jdbcUsername=sa
jdbcPassword=sa

To make it simple the bundle just uses a BundleActivator, gets hold of the Configuration Admin and provides the property, like this:

public class Activator implements BundleActivator {

    public void start(BundleContext context) throws Exception {
        ServiceReference ref = context.getServiceReference(ConfigurationAdmin.class.getName());
        ConfigurationAdmin admin = (ConfigurationAdmin) context.getService(ref);
        String pid = "org.camunda.bpm.extension.osgi.configadmin.ManagedProcessEngineFactory";
        Configuration configuration = admin.createFactoryConfiguration(pid, null);
        Hashtable properties = new Hashtable();
        properties.put("databaseSchemaUpdate","false");
        properties.put("jobExecutorActivate","true");
        properties.put("processEngineName","TestEngine");
        properties.put("databaseType","mysql");
        properties.put("dataSourceJndiName", "osgi:service/jdbc/test");
        configuration.update(properties);
    }

The activated bundle listener should provide the bundle to all Karafs. Just drop the bundle into the deploy directory.

You should see that the configuration got shared, too. To check just run this command: config:list "(service.pid=org.camunda.bpm.extension.osgi.configadmin.ManagedProcessEngineFactory*)"

TL;DR;

  1. change port numbers in etc/org.apache.karaf.management.cfg and etc/org.apache.karaf.shell.cfg if you run two instances on one machine
  2. feature:repo-add mvn:org.apache.karaf.cellar/apache-karaf-cellar/3.0.1/xml/features
  3. feature:install cellar
    1. Decide if you want to activate the listener or use the cluster:commands for the following things
  4. git clone https://github.com/camunda/camunda-bpm-platform-osgi.git
  5. mvn install the project
  6. feature:repo-add mvn:org.camunda.bpm.extension.osgi/camunda-bpm-karaf-feature/1.1.0-SNAPSHOT/xml/features
  7. feature:install camunda-bpm-karaf-feature-minimal
  8. set up MySQL databse
  9. feature:install jdbc
  10. drop MySQL connector jar into deploy directory
  11. jdbc:create -u sa -p sa -url jdbc:mysql://localhost:3306/test -t MySQL test
  12. feature:install jndi
  13. create configuration bundle and drop it into deploy directory. Configuration:
    databaseSchemaUpdate=false
    jobExecutorActivate=true
    processEngineName=TestEngine
    databaseType=mysql
    dataSourceJndiName=osgi:service/jdbc/test

And you're good to go.

So, this was my trip into the Karaf Cellar world. I hope I could prove the feasibility to you. I'll leave the practical consequences as an exercise to the reader ;-)

Monday, September 29, 2014

Create a ProcessEngine with the ConfigurationAdminService

There is a new feature in the camunda BPM OSGi extension and I would like to introduce it to you. So, let's start with the news.

What's new?

 

The OSGi extension now exports a ManagedServiceFactory to provide another way to configure and automatically share a ProcessEngine. The factory will be automatically exported when the OSGi compendium classes are present. You can then provide your configuration and the engine will be created and exported.

If you've never heard of the ConfigurationAdminService I would like to give you a short introduction.

What is the ConfigurationAdminService?

 

The ConfigurationAdminService is supposed to make the provision and change of configuration during easier. When you provide a configuration object (a dictionary) the service will find the according ManagedService or ManagedServiceFactory based on a pid (persistent id) and pass the configuration to it.

There are (way ;-) ) better descriptions in the OSGi Alliance blog and the Apache Felix documentation if you want to learn a little bit more about it. Let's see how we can use the service.

How to use it?

 

As I mentioned before the configuration is just a dictionary. The keys have to corresspondent to the fields of a ProcessEngineConfiguration object. Simply create a HashTable and put everything in it you need to run your engine:
    Hashtable<String, Object> props = new Hashtable<String, Object>();
    props.put("databaseSchemaUpdate", ProcessEngineConfiguration.DB_SCHEMA_UPDATE_CREATE_DROP);
    props.put("jdbcUrl", "jdbc:h2:mem:camunda;DB_CLOSE_DELAY=-1");
    props.put("jobExecutorActivate", true);
    props.put("processEngineName", "TestEngine");


Next you gotta get the ConfigurationAdminService and call createFactoryConfiguration() with the following PId:
org.camunda.bpm.extension.osgi.configadmin.ManagedProcessEngineFactory

There is also a constant in the ManagedProcessEngineFactory interface. After that pass your dictionary to the Configuration object by calling the update() method. And that's it. Your ProcessEngine will be created and exported.

Now that you know how to use the service I would like to tell you what makes it special.

Why use the ConfigurationAdminService?

 

I remember when I first read about the ConfigurationAdminService my thought was: "That's a really great idea!". By using the service you have several ways of providing configuration for your ProcessEngine. The easiest thing to image is that you store your configuration files in separate bundles. Every time something changes you update that bundle.

Depending on your environment there are more ways. In Apache Karaf you could place a file named
org.camunda.bpm.extension.osgi.configadmin.ManagedProcessEngineFactory.cfg
in the etc directory. Karaf would find the factory and pass the configuration to it.
Apache Felix and Equinox also provide ways to read and use configuration files.

Also, the ConfigurationAdminServices helps you to provide different configurations for different environments. At least text files are to change and provide than .class files.

Finally I want to tell you some details about the implementation.

How is it implemented?

 

I gotta admit that the implementation is not that special. The factory uses Commons BeanUtils to find the setters for the properties. Because the setters of ProcessEngineConfiguration provide a fluent way I couldn't use the classes BeanUtils or PropertyUtils. That's why I "combine" the setter-name on my own and invoke the method with MethodUtils.

Every time the configuration of a ProcessEngine changes I stop that engine, unregister it and create a new one and register that one. That is the only way to "change" the configuration of a ProcessEngine. Maybe a ProcessEngine/Configuration needs an update() method.

I would appreciate any hints or recommendations on how to improve the factory. Since it's my first try implementing a ManagedServiceFactory.

So, enjoy the new service!

Saturday, September 27, 2014

camunda BPM platform OSGi presents: integration with Process Application API

I am happy to announce that there is a new way to configure a ProcessEngine and deploy processes.
You can now use the Process Application API.
Luckily, using this API in your project is quite easy.
There are three things you have to do:
  1.  provide a processes.xml file
  2.  make a subclass of org.camunda.bpm.extension.osgi.application.OSGiProcessApplication
  3. export it as OSGi service
After that the process will be deployed and the engine will be started and exported.
To show you how easy it can be I created an example project.

Please note that the feature is right now only usable when using Blueprint.
Also you'll have to build camunda-bpm-platform and camunda-bpm-platform-osgi yourself. But the next releases should be right around the corner ;-)

Unfortunately, I wasn't able to activate the process application local scan for process definitions (see here). I couldn't figure out a way to find resources inside an embedded jar.
Neil Bartlett mentioned the BundleWiring class. Seems like I have to wait until we upgrade the project to OSGi 4.3.
If anyone knows a way please let me know.

So, enjoy the OSGiProcessApplication and give me some feedback if you want to!

Sunday, May 25, 2014

Consuming arbitrary remote services with the OSGiELResolver (camunda BPM OSGi)

In my last blog post I promised to give a slightly more advanced example about how to use the new OSGiELResolver. And as I promised, here it is ;-)

Prerequisites


The setup is quite simple. We have three bundles:
  1. API
  2. Service Provider
  3. Service Consumer
You can find all the sources here. (feel free to suggest improvements, possible bugs, etc.)
As runtime I used two Apache Karaf instances on my computer (version 2.3.5; I had some problems with 3.0.1).
For remoting we'll use Apache CXF 1.4 (single bundle release).
And of course we'll need camunda BPM platform OSGi, which you'll have to build yourself.
Before I tell you more about the three bundles I'd like to point the book "Enterprise OSGi in Action" out. Without that great book I couldn't have provided this example. It's definitely worth reading.

So, enough advertisement, let's take a look at the bundles.

API bundle

 

The API bundle is really simple. It only contains one interface with a method. We'll need the bundle in both runtimes.

Provider bundle

 

Now we're getting a little bit more serious. The provider bundle contains the service implementation we want to use.
The context.xml contains the important parts for remoting:
<entry key="service.exported.interfaces" 
 value="de.blogspot.wrongtracks.osgielresolver.api.SomethingService"/><entry key="service.exported.configs"
       value="org.apache.cxf.ws"

<entry key="org.apache.cxf.ws.address"
       value="http://localhost:9001/somethingservice"/>


"service.exported.interfaces" should be obvious.
"service.exported.configs" tells Distributed OSGi to look for implementation specific properties.
Lastly "org.apache.cxf.ws.address" lets us define an alternative address. It is quite helpful if you don't want to type the fully qualified name of the class in your browser or other config files.

Consumer bundle

 

Let's take a look at the consumer. This bundle needs a little bit more information to work properly. To be able to consume remote services we need the OSGI-INF/remote-service/remote-services.xml. It doesn't have to be that name or that directory. You can specify the path inside the bundle with the "Remote-Service" header, which I set in the POM to:
      <Remote-Service>OSGI-INF/remote-service/*.xml</Remote-Service>
I won't walk you through the remote-services.xml. I'm sure you'll find better explanations somewhere else. (e.g. in Enterprise OSGi in Action ;-) )

After we configured this we can use the reference tag in the context.xml to find the service.
To make the service work with the OSGiELResolver we have to add two things. In the remote-services.xml the property "processExpression" has to be set and in the context.xml we have to use a filter.
As you may know the ELResolver uses the filter to search for classes. Searching only worked when both, attribute and filter, were set.

The provider Karaf

 

Like I said, I used Karaf as runtime. The "provider" Karaf needs three bundles:
  1. API
  2. Provider
  3. Apache CXF
Just drop them into the deploy directory. It worked best for me when I started them in the order API, CXF and provider. Then everything should work as expected.

The consumer Karaf

 

The "consumer" Karaf needs a little bit more bundles (and if you run it on the same machine you'll have to change three ports). You have to add:
  1. API
  2. Consumer
  3. Apache CXF
  4. camunda BPM platform OSGi and dependencies
Drop API, consumer and CXF jars into deploy (again, starting API, CXF and then consumer works best). Adding camunda BPM platform OSGi isn't very difficult because there is a feature.xml (assumed it is installed in your local Maven repository).
To install it type:
features:addurl mvn:org.camunda.bpm.extension.osgi/camunda-bpm-karaf-feature/1.0.0-SNAPSHOT/xml/features

and then:
features:install camunda-bpm-karaf-feature-minimal

This should resolve all you bundles. Now, If you start the consumer bundle you should see the log saying "Started process". Strangely the logger of the service implementation was quiet. But if you uncomment the exception you can see that the service was called.

So, as you can see, the new OSGiELResolver makes it possible to consume arbitrary remote services, which is quite an improvement. I hope my example is understandable and helps to see the possibilities.

Hint

 

When you encounter this exception:
java.lang.IllegalStateException: Invalid BundleContext
just start the CXF bundle again, then it should work.

Saturday, May 10, 2014

First steps with Apache ACE

Introduction


"Apache ACE is a software distribution framework that allows you to centrally manage and distribute software components, configuration data and other artifacts to target systems." (from https://ace.apache.org/)
Well, that sounds good enough to try it out, at least for me.
I like the idea to centrally configure deployments with different version and have a way to automatically distribute those.

Starting ACE


Setting up Apache ACE was pretty easy. The Getting started guide contains all the necessary steps.
My MacBook was the ACE server and my Raspberry Pi a target.

Using the Web GUI is easy and straightforward (nice one guys ;-) ).
But that's for little children. I wanna find a way to automate everything with scripts.

The Client Shell API

Basically there are two ways to talk to the server remotely. One is the Client Shell API and the other way is via REST API. For now I'll stick with the Shell API

1st step: connecting to the server as shell client

Before we can write a script we have to connect to the server.
With some help from the iQSpot people (see here) I figured it out.
They suggest starting the client like this:

java -Dagent.discovery.serverurls="http://server:port"
     -Dorg.apache.ace.server="server:port"
     -Dorg.apache.ace.obr="server:port"
     -Dorg.osgi.service.http.port=-1
     -jar client.jar
 
Unfortunately, that didn't work for me (even after adding some missing backslashes).
The default is that you should be in the directory of client.jar. "-jar client.jar" wasn't the problem.
The startup searches for the client/conf directory, so when you see this exception:

java.lang.IllegalArgumentException: Bad arguments; either not an existing directory or an invalid interval.
    at org.apache.ace.configurator.Configurator.<init>(Configurator.java:89)
    at org.apache.ace.configurator.Activator.init(Activator.java:33)
    at org.apache.felix.dm.DependencyActivatorBase.start(DependencyActivatorBase.java:76)
    at org.apache.felix.framework.util.SecureAction.startActivator(SecureAction.java:645)
    at org.apache.felix.framework.Felix.activateBundle(Felix.java:2146)
    at org.apache.felix.framework.Felix.startBundle(Felix.java:2064)
    at org.apache.felix.framework.Felix.setActiveStartLevel(Felix.java:1291)
    at org.apache.felix.framework.FrameworkStartLevelImpl.run(FrameworkStartLevelImpl.java:304)
    at java.lang.Thread.run(Thread.java:722)

You're probably starting the client from a different directory.
To get rid of that exception we have to set a property:
-Dorg.apache.ace.configurator.CONFIG_DIR=
All in all the command to start the client looks like this:

java -Dagent.discovery.serverurls="http://server:port"\
     -Dorg.apache.ace.server="server:port"\
     -Dorg.apache.ace.obr="server:port"\
     -Dorg.osgi.service.http.port=-1\
     -Dorg.apache.ace.configurator.CONFIG_DIR="apache-ace-2.0.1-bin/client/conf"\
     -jar apache-ace-2.0.1-bin/client/client.jar


Now we can start the client.
But to pass a script to the shell we need two more arguments. Thanks again to the iQSpot people. They already pointed out those arguments:
  • -Dgosh.args="–-args"
  • -Dace.gogo.script.delay=delay
  • -Dace.gogo.script=/path/to/script.gogo
What do those three do?
Everything you'll pass as "gosh.args" will be executed immidiately. If pass "--help" for example and start the client you'll see the help output.
The delay is helpful when you want to give your client some time to synchronize with the server.
"ace.gogo.script" should be obvious ;-)
We end up with the following command:

java -Dagent.discovery.serverurls="http://server:port"\
     -Dorg.apache.ace.server="server:port"\
     -Dorg.apache.ace.obr="server:port"\

     -Dorg.osgi.service.http.port=-1\
     -Dorg.apache.ace.configurator.CONFIG_DIR="apache-ace-2.0.1-bin/client/conf"\
     -Dace.gogo.script.delay="3000"\
     -Dace.gogo.script="script.foo"\

     -jar apache-ace-2.0.1-bin/client/client.jar

Now we have to find out, what we should put into "script.foo".
 

Shell commands


Every (basic) command is described here.
The steps are quite simple: cw, ca, cf, ca2f, cd, cf2d
If you don't like or get the abbreviations (it took me a while) there is also a nice picture in the REST API documentation:
What the picture is missing is cw or "create workspace". When using the Shell API you need a workspace, which you can commit later.

The script

 

So, what should skript.foo do? Let's assume we have to upload some generated artifacts from our CI server 
The steps are
  1. create workspace
  2. add the new Jars as artifacts from certain directory
  3. create a new feature
  4. add artifacts to feature
  5. create a new distribution
  6. add new feature and existing ones to distribution
  7. add feature to existing target 
I have to admit that it took me quite a while to figure everything out because I'm not very experienced with Apache Felix GoGo.
Creating the workspace is easy: w = (cw)
Now we can call the workspace with $w. Adding the Jars was more difficult. Let's assume the directory is ./toAdd. Then the command looks like this: 

each ([(ls toAdd)]) {$w ca (($it toURL) toString) false}

You "toAdd" can be changed to any path and you could use some wildcards, like ls toAdd/*.jar
I guess if you're used to GoGo the command won't be a surprise. If you're not used to it, I would like to explain the different parts to you:
each takes a list and a function. ls toAdd returns a File array. That's why we need the brackets. They convert the array into a list. After that comes the function, indicated by the braces.
$w ca is the method to create an arfifact. $it is the iterator over the list that is provided by each.
Then we call the methods toURL and toString because reflection makes it possible ;-)

Third step: add all artifacts to feature

each ($w la "(Bundle-SymbolicName=org.camunda.*)") {symbolicName=($it getAttribute "Bundle-SymbolicName"); $w ca2f "(Bundle-SymbolicName="$symbolicName")" "(name=test-feature)"}

Again, we use a for-each-loop.
$w la lists all the bundles that match the passed pattern. (Here, I want to add all camunda bundles, no advertisement ;-))
Then I save the symbolic name in a variable, so it's easier for me later to reference it.
org.apache.ace.client.repository.RepositoryObject has a getAttribute method, which we use here.
Also, please note the semicolon.
We use the symbolic name as part of the first argument for ca2f (create artifact2feature).
The String contains three parts
  • "(Bundle-SymbolicName="
  •  $symbolicName
  • ")"
I don't know why, but we don't ne a "+" for string concatenation. The second argument is the name of the feature. I just assume it to stay the same: "test-feature"
Creating a distribution and a feature2distribution are nothing special.

All in all we end up with the following:

w = (ace:cw)
$w cf test-feature
$w cd test-distro

each ([(ls toAdd)]) {$w ca (($it toURL) toString) false}

each ($w la "(Bundle-SymbolicName=org.camunda.*)") {symbolicName=($it getAttribute "Bundle-SymbolicName"); $w ca2f "(Bundle-SymbolicName="$symbolicName")" "(name=test-feature)"}

$w cf2d "(name=test-feature)" "(name=test-distro)"

$w commit


That should do the trick so far.
Stay tuned for my next steps with ACE ;-)

Tuesday, May 6, 2014

Glassfish 4, Commons Mail and "UnsupportedDataTypeException: no object DCH for MIME type multipart/mixed"

I know there are a bazillion posts/threads/etc. about the exception mentioned in the title and now there are a bazillion + one ;-)
Unfortunately I couldn't find the solution I want to present to you anywhere else.

First some context:
My class extends an Activiti class and uses Apache Commons Mail to send an email.
The email contains some text and has a file (txt/pdf/docs) attached.
Everything runs inside a Glassfish 4 and the Jars are deployed as OSGi bundles.

When calling email.send() the server threw the feared UnsupportedDataTypeException:

Caused by: javax.activation.UnsupportedDataTypeException: no object DCH for MIME type multipart/mixed;
    boundary="----=_Part_0_397989068.1398665205325"
    at javax.activation.ObjectDataContentHandler.writeTo(DataHandler.java:891)
    at javax.activation.DataHandler.writeTo(DataHandler.java:317)
    at javax.mail.internet.MimeBodyPart.writeTo(MimeBodyPart.java:1574)
    at javax.mail.internet.MimeMessage.writeTo(MimeMessage.java:1840)
    at com.sun.mail.smtp.SMTPTransport.sendMessage(SMTPTransport.java:1119)
    ... 120 more


Like I mentioned the Internet is full of solutions but none of them worked for me.
Because the Glassfish showed me that all of my bundles were correctly linked and resolved the problem had to be another place.

My colleague then told me I should try to change the TCCL. After some try-and-error it worked (I tried the one from commons.mail, the one from javax.activation and one I forgot ;-)).

The solution was to import javax.mail in my bundle and change the TCCL to the javax.mail classloader:

Thread.currentThread().setContextClassLoader(javax.mail.Message.class.getClassLoader());
email.send()

I am not sure why only the javax.mail classloader works. For me it is some arcane dependency/classloading/visibility problem.
Nevertheless, I hope this post helps some Glassfish/OSGi users.

Finally, I would like to thank my colleague @spost1970 for helping me find a solution.

Saturday, April 26, 2014

Integrating Apache Aries blueprint into Glassfish 4

After experimenting with Glassfish 4 lately I would like to let you know what I am up to. It's nothing big (yet) ;-)

A little bit of background

Glassfish comes with integrated OSGi support (Apache Felix) but without Blueprint (as far as I know). So putting a Blueprint container into Glassfish became my task.

The nice thing about Glassfish is that it combines Java EE (especially EJBs) and OSGi and that, in contrast to JBoss, it has a nice OSGi web console.
If you want to get to know more about the OSGi-JEE combination the keyword for your favourite search engine is "fighterfish".

Most of the credit goes to Yong Tang and his blog entry. He describes the integration of Aries Application but also describes the basic parts necessary for my task.

The problem


So, before we start, what is the problem? If you're familiar with Glassfish you certainly know there is an autodeploy/bundles directory. Why don't I just drop the necessary bundles into the autodeploy/bundles directory?
When using the autodeploy directory Glassfish doesn't start the bundles so you'll have to do it by hand every time you empty the osgi-cache directory and, of course, initially.
But there's a more convenient way.

Let's get it on


What's the better way?
Just drop the jars
  • Aries Blueprint Api(v1.0.0)
  • Aries Blueprint(v1.1.0)
  • Aries Proxy (v1.0.0) 
  • Aries Util(v1.0.0)
into glassfish/modules/autostart.
To make sure all dependencies are there add slf4j api (v1.7.2), logback core(v1.0.13) and logback classic (v1.0.13) (or whichever logging framework you prefer). You don't need any additional configuration because we didn't create a subdirectory.

See, piece of cake. The trick is to find the right directory. Now the Blueprint extender will do its job right after start up.
glassfish/modules/autostart
glassfish/modules/autostart
glassfish/modules/autostart
glassfish/modules/autostar
glassfish/modules/autostar

Wednesday, January 22, 2014

Activiti/camunda BPM: custom behavior and BPMN extension elements using Blueprint

Introduction 

 

In the last few weeks I have been working on a problem regarding OSGi-Blueprint and Activiti. Because it wasn't as easy as I would have hoped I want to share my solution with you. I will start by explaining my environment, show you the problem and then I will explain my first attempt. After that I will present my solution. Finally I will show some ideas how to make it better and things that I did not test.

Just a short hint about the writing: when I reference a class or some XML it's written in italic, e.g. Object. When you see "process engine", I am talking about the whole thing, but when you see ProcessEngine it's the actual class.

My environment

 

I use the Activiti-framework in version 5.12.1, Apache Aries in version 1.0.0 with a little modification and my own ProSt bundles. ProSt can be found here. The README.md explains why and what I changed in Aries.

I haven't tried, yet, but I am pretty sure that camunda BPM suffers the same problem because
both share the same MailActivityBehavior and BlueprintELResolver classes and use <extension-elements> for injection. So if you prefer camunda and see "activiti" somewhere you just have to replace it with "camunda" in your head ;-)

The problem 

 

In general, I just wanted to send an e-mail during my process-execution. Sounds pretty easy, right?

My SendMailWithAttachmentBehaviour class extends the previously mentioned MailActivitiBehavior class. The process definition contains all the necessary information to send the e-mail, e.g. from, to and subject. Only the attachment is missing, which I get from the execution environment.

Because I use Blueprint I cannot use the activit:class or type="mail" attributes in the process definition. I have to declare the class this way:
activiti:deleExpression="${sendMailWithAttachmentBehavior}"

A little hint: the name in the braces has to match the one used as bean id in the blueprint.xml.

The other ways do not work with OSGi because of class visibility etc.

The easy part was to extend the BlueprintELResolver class (ProStBlueprintELResolver) and add a way to add custom behavior classes at the moment.

So, what happens when the process engine tries to resolve the expression?
When the bundle is loaded Blueprint creates a dynamic proxy and registers it at the ProStBlueprintELManager.
After the process reaches the ServiceTask which delegates to the ${sendMailWithAttachmentBehaviour} the process-engine asks its ExpressionLanguageResolvers if they know something with the name "sendMailWithAttachmentBehaviour". Logically the proxy is found.
After that the process engine tries to set the extension-elements at the class.
First it tries to find setter methods and if it cannot find setters it tries field injection. (see ClassDelegate.applyFieldDeclaration())
Both ways do not work.
But why?
Of course a proxy does not have any fields. But why is it not possible to just add the setters to the SendMailWithAttachmendBehaviour class?
The call is proxy.getClass().getMethods() and according to the documentation this will return all the methods of the interfaces that the proxy was created with. ActivityBehavior does not declare the setSubject() etc. methods because they are only needed for e-mails.

First attempt

 

At first I thought the solution was quite obvious. I would just export a second interface containing the setters like this:

<bean id="sendMailWithAttachment" class="de.blogspot.wrongtracks.prost.example.behaviour.SendMailWithAttachmentBehaviour" />
  
<service ref="sendMailWithAttachment">
  <interfaces>
<value>org.activiti.engine.impl.pvm.delegate.ActivityBehavior</value>
<value>de.blogspot.wrongtracks.prost.example.behavior.ExtensionElementsMailSetter</value>
  </interfaces>
</services>
But wait, if you take a look at the (old) context.xml you can see that my reference listener just listens for ActivityBehavior and not the other interface. That's why the created proxy won't contain the methods from the other interface. Too bad...

The solution

 

I found the solution accidentally while reading the Apache Aries Blueprint documentation. This chapter points out that you can also listen for service references.
I changed the methods to accept a ServiceReference instead of a ActivitiyBehavior and when the expression should be resolved I use the BundleContext to get the service. At that point it is not a proxy, it is the implementation.

Then everything works just fine. I don't even need the setter interface anymore.
You can see the solution when you look at the new context.xml and the previously mentioned ProStBlueprintELResolver. (the previously showed link pointed to an old version so nothing would be spoiled ;-) )

That's it, that is my solution to add custom behavior to the process engine and use extension elements in the BPMN XML.

How could we improve the whole thing?

 

Strangely, I have no idea how the whole thing could be improved. I would like to hear your ideas. Also, I would like to know if you think that the way presented here is good or bad or something in between.

What didn't I try?

 

You should note that I have not tried to find out how JavaDelegates behave in the same situation. I just did not have time and I wanted to show you my solution as soon as I finished it.

Tuesday, June 4, 2013

Using the Activiti-Engine as bundle in JBoss AS 7.2

Introduction


I am quite new to OSGi and when trying to deploy and use the Activiti-Engine as OSGi bundle in JBoss (I'll usw "JBoss" as abbreviation for JBoss AS 7.2) I have had some problems. 
The only example about OSGi and Activiti I was able to find was the one from Activiti in Action which uses Apache Karaf. Of course those environments differ a lot.
So I wanna share my knowledge with you.

 

Motivation 

 

Before we start, I'd like explain why I want to use the combination of Activit, OSGi and JBoss. I won't argue about the pros and cons of using OSGi, there is enough literature about that.

The fact that Activiti scans every new bundle if it contains a process definition will become very helpful for future processes.
Also, updating a process definition by replacing a single bundle and not replacing e.g. a whole WAR-file, seems like an advantage.

But, why do I want to use JBoss and not e.g. Karaf?

When JBoss changed to version 7 they restructured their whole server to use OSGi/JBoss modules. So, OSGi is a part of JBoss.
Last time I checked, JBoss was the only fully JEE 6 compliant server with OSGi integration and because I need EJBs for client - server communication I need JBoss. (At this point, I have no idea how to combine EJBs and OSGi but I'll try to figure that out, soon)

Those are my reasons so let's see how we can get those three running.

 

Let's start

 

Environment


To make sure that everyone can easily repeat my steps, I'll start with the environment/versions:
  • JBoss AS 7.2
  • OSGi 4.2 (included in JBoss)
  • Activiti 5.12.1
Please notice, that I use JBoss AS 7.2, which you have to compile yourself at the moment. With version 7.1.1 I have had a problem.
I had the server running locally under Linux Mint 14.1.

 

Bundle dependencies 


The example from Activiti in Activiti uses a feature.xml to resolve all the dependencies and install them from a Maven repository. Unfortunately, this involves some Karaf "magic". That's why I had to download all dependencies manually. (I also tried

mvn org.apache.felix:maven-bundle-plugin:wrap/bundleall
on the activiti-engine and -osgi project, but that didn't work out for me)

We need the following JARs (I added links to make downloading them easier):

Downloading yourself Apache Aries seems a little bit odd because the JBoss documentation states that there is blueprint support. Nevertheless, I couldn't find, nor activate it, so I was forced to include it myself.

Another interesting thing is, that I couldn't start the included h2 database (com.h2database.h2). That's why I downloaded it, too. Please notice, that you will only need the h2-bundle if you want to use a h2-database (makes sense, doesn't it ;) )

We could throw all those bundles into the <<jboss-root>>/standalone/deployments directory (if you're using JBoss in standalone-mode), but I think a better approach is to place the more general JARs in the <<jboss-root>>/module directory. 
    I placed the three aries-bundles, the h2-bundle and the two slf4j-bundles there.
    For every bundle you have to repeat the following steps:
    If the bundle name is e.g. com.a.b.c.jar create in <<jboss-root>>/module the directory com/a/b/main and place the bundle in the main directory. (Don't worry about the <<jboss-root>>/module/system -directory.)

    After that, alter the standalone.xml and add a new capability under the OSGi-Subsystem, e.g.:

    <subsystem xmlns="urn:jboss:domain:osgi:1.2" activation="eager">
       <properties>

        ...
       </properties>
       <capabilities>
          <capability name="com.a.b.c" startlevel="1"/>
       </capabilities>

    </subsystem>

    Pick whichever startlevel you think is appropriate.

    In fact, you can pick any directory-structure you want to, as long as the path in the standalone.xml is correct. That means you could place the h2-bundle e.g. in <<jboss-root>>/module/org/foo/bar/main and JBoss would still be able to find it. Only the last directory has to be named "main".

    After you've done that, take the other bundles an put them into  
    <<jboss-root>>/standalone/deplyoments

    An that's all. These steps should get Activiti running as OSGi-bundle.
    My whole osgi-subsystem configuration looks like this:

    <subsystem xmlns="urn:jboss:domain:osgi:1.2" activation="eager">
                <properties>
                    <property name="org.osgi.framework.startlevel.beginning">
                        2
                    </property>
                </properties>
                <capabilities>
                    <capability name="javax.servlet.api:v25" startlevel="1"/>
                    <capability name="javax.transaction.api" startlevel="1"/>
                    <capability name="org.osgi.core" startlevel="1"/>
                    <capability name="org.osgi.enterprise" startlevel="1"/>
                    <capability name="org.slf4j" startlevel="1"/>
                    <capability name="org.slf4j.impl" startlevel="1"/>
                    <capability name="org.apache.aries.util" startlevel="1"/>
                    <capability name="org.apache.aries.proxy" startlevel="1"/>
                    <capability name="org.apache.aries.blueprint" startlevel="1"/>
                    <capability name="org.h2" startlevel="1"/>
                    <capability name="org.apache.felix.log" startlevel="2"/>
                    <capability name="org.jboss.osgi.logging" startlevel="2"/>
                    <capability name="org.apache.felix.configadmin" startlevel="2"/>
                </capabilities>
            </subsystem> 


    And in my deployments-directory you can find those jars:
    • activiti-bpmn-converter-5.12.1.jar
    • activiti-bpmn-model-5.12.1.jar
    • activiti-engine-5.12.1.jar
    • activiti-osgi-5.12.1.jar
    • com.springsource.javax.transaction-1.1.0.jar
    • com.springsource.org.apache.commons.lang-2.4.0.jar
    • joda-time_2.1.0.jar
    • org.mybatis.mybatis_3.1.1.jar

     

    Blueprint activation

     

    The Activiti-OSGi bundle contains the basic classes Blueprint needs. But we have to register all those services. That's why we need a Blueprint content.xml.

    Thanks to Tijs Rademakers we can copy that from here. It's the example code from/for Activiti in Action.
    We can also use the book-osgi-app in JBoss.
    Just run mvn package on the book-engine, book-process and book-task projects.

    After packaging those three, I had to make a minor change in the MANIFEST.MF and content.xml of the book-engine-project.
    In the content.xml you have to replace the jdbc-url with whatever fits to your database.
    In the MANIFEST.MF I had to remove the Import-Package versions for everything related to activiti, because the generated MANIFEST requires version [5.9, 6) and my activiti-bundles don't contain any version information.

    Now place those three bundles into the deployment-directory and everything should work as expected.
    To test the deployment, I wrote a simple bundle with an activator to look up the Deployment-Service and see, if a process defnition could be found. 

    Summary 

     

    Get all the bundles, place some in the modules-directory and some in the deployment-directory, copy some content.xmls and everything should work. Sounds easy, but it took
    me a while to figure it out ;)

    So have fun with Activiti, OSGi and JBoss!
    In case you find any mistake, feel free to point them out.

     

    Copyright @ 2013 Wrong tracks of a developer.

    Designed by Templateiy