Thursday, March 5, 2015

camunda BPM Platform OSGi 1.1.0 released

It has been more than half a year since the last release of camunda BPM Platform OSGi (version 1.0.0). The last version was something special because it was the first major release of the new OSGi module for the camunda BPM Platform. Today we release the first minor version 1.1.0 (you can find it here or on Maven Central). So, what's new?
  1. Configuration Admin Service integration with ManagedProcessEngineFactory
  2. Karaf commands now work for version 2 and 3
  3. Karaf assembly module
  4. Platform API integration (OSGiProcessApplication)

Configuration Admin Service Integration

The camunda BPM OSGi module now registers a ManagedServiceFactory when the OSGi compendium classes are present. You can find a description in the README how to use it. I have to say that I really like the idea behind the Configuration Admin.

Karaf commands now work for version 2 and 3

Until today there was a branch open for the Karaf commands under version 3. Since the API our commands implement didn't change from version 2 to 3 the range was "widened" so the imports now cover both versions.

Karaf assembly module

The project now contains a new Maven module. It's called "camunda-bpm-karaf-assembly". The module makes use of the Karaf Maven plug-in and let's you assemble a custom Apache Karaf including the camunda bundles. If you need a Karaf for test purposes you'll be able to quickly assemble a compressed Karaf and use it. Also, the camunda team will add the custom Karaf to the download section next to the other distributions.

Platform API integration

This took a lot of effort and the combined knowledge of Daniel, Roman and me. The changes were lurking for a while inside a branch until they got finally merged into camunda BPM OSGi and the camunda BPM Platform. Again, the README is a good starting point ;-)
For me, personally, the biggest reason to release 1.1.0 is to start working on version 2.0.0. As you can guess from the new major version I have planned some bigger changes. My target is to split the different parts, which are contained in camunda-bpm-osgi into separate modules. I'll post my thoughts soon in the developer forum. Feel free to join the discussion.
And, of course, have fun with the new version and its new features.

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

Tuesday, November 18, 2014

camunda BPM engine: use custom VariableType to resist the urge to flush

Introduction

I hope all of you are aware of the fact that you can provide a ProcessEnginewith your own VariableTypes. If not, I'll give you a short introduction. Please note that my descriptions are based on camunda-engine 7.1.0. There will be some changes in versoin 7.2.0 and I am not sure if my observations will still be true.

VariableType

 

VariableTypes help the ProcessEngine store your process variables in the table ACT_RU_VARIABLE. I would call them a mediator between the possible variables and the database schema. There are VariableType implementations for
  • Boolean
  • Serizable
  • Date
  • Double
  • Integer
  • JPA Entities
  • Long
  • Null
  • Short
  • String
  • and CustomObjects (about which I'll talk later)

If you try to add an object as process variable, which doesn't belong to one of those types, you'll see this exception:

org.camunda.bpm.engine.ProcessEngineException: couldn't find a variable type that is able to serialize \<object\>
    at org.camunda.bpm.engine.impl.variable.DefaultVariableTypes.findVariableType(DefaultVariableTypes.java:62)
    at org.camunda.bpm.engine.impl.persistence.entity.VariableScopeImpl.getNewVariableType(VariableScopeImpl.java:315)
    at org.camunda.bpm.engine.impl.persistence.entity.VariableScopeImpl.createVariableInstance(VariableScopeImpl.java:395)
    at org.camunda.bpm.engine.impl.persistence.entity.VariableScopeImpl.createVariableLocal(VariableScopeImpl.java:332)
    at org.camunda.bpm.engine.impl.persistence.entity.VariableScopeImpl.setVariable(VariableScopeImpl.java:259)
    at org.camunda.bpm.engine.impl.persistence.entity.VariableScopeImpl.setVariable(VariableScopeImpl.java:242)
    at de.blogspot.wrongtracks.StoreDataDelegate.execute(StoreDataDelegate.java:9)
    at org.camunda.bpm.engine.impl.delegate.JavaDelegateInvocation.invoke(JavaDelegateInvocation.java:34)
    at org.camunda.bpm.engine.impl.delegate.DelegateInvocation.proceed(DelegateInvocation.java:39)
    at org.camunda.bpm.engine.impl.delegate.DefaultDelegateInterceptor.handleInvocation(DefaultDelegateInterceptor.java:42)
    at org.camunda.bpm.engine.impl.bpmn.behavior.ServiceTaskJavaDelegateActivityBehavior.execute(ServiceTaskJavaDelegateActivityBehavior.java:49)


Provide your variable type

 

Every ProcessEngineConfiguration should have the methods setCustomPostVariableTypes(List<VariableType>) and setCustomPreVariableTypes(List<VariableType>) so you can add your variable types when configuring the engine.
But wait, why are there two methods, pre and post?
When searching which VariableType can handle the object you want to store as process variable the engine iterates over the list of VariableTypes and the first one, which can handle the object, wins. Maybe you want your own types to have precedence over the default types.

Flushing

 

Now that you know about VariableTypes I want to present to you my use case.

The case

 

Imagine a process that's supposed to run synchronously (i.e. without a wait state) within a JTA transaction and every task needs a result from the preceding one. Additionally, the results are JPA Entities. By default the JPAEntityVariableType would take care of the entity.
The implementation shows that every time setValue() is called the JPAEntityVariableType calls flush() on the EntityManager. Since the process runs synchronously within a transaction the flush results in unnecessary queries on my database during process execution.

The solution

 

Here comes the CustomObjectType class. The CustomObjectType only needs a name and a class to work. The class is used to determine if it can handle a certain object. The CustomObjectType stores all objects in the cache of the ValueField. To get rid of the flush I instantiated a CustomObjectType with the class of my result and passed it to the configuration. Now, every time I put an entity inside the process variables the CustomObjectType places them inside the cache and no flush is called.

 

 The downside

 

Well, nothing comes without a price: If I should ever need a wait state my solution won't work and I'll have to find another solution or live with the flush.

 

Alternatives

 

I am not sure if my solution is the best way to solve my problem. If anyone knows a better way please let me know.

 

Small example

 

I also created a small example to show the use of the CustomObjectType here on GitHub

Tuesday, November 11, 2014

camunda BPM engine: How many tasks can you execute without wait state

Today I got quite curious today about this topic and I don't know if anyone ever wondered/tried.
At work I introduced the camunda BPM engine a few months ago. One requirement was not to reach any wait state during the execution. That ways we want to make sure the process ends synchronously and we don't show stale data.

As you can image the stacktraces got pretty big when an exception occurred during the end of the process (>1000 lines). So I wondered how many tasks could be executed before the java stack is full (or anything else unexpected happens).
To try this I wrote a simple Java class:

public class Main {
private static final int NUMBER_TASKS = 100;

public static void main(String[] args) throws InterruptedException {

    ProcessEngineConfiguration configuration = ProcessEngineConfiguration
            .createStandaloneProcessEngineConfiguration();
    configuration.setJdbcUrl("jdbc:h2:mem:test;DB_CLOSE_DELAY=-1");
    configuration
            .setDatabaseSchemaUpdate(ProcessEngineConfiguration.DB_SCHEMA_UPDATE_CREATE_DROP);
    configuration.setJdbcUsername("sa");
    configuration.setJdbcPassword("");
    configuration.setHistory(ProcessEngineConfiguration.HISTORY_NONE);

    ProcessEngine engine = configuration.buildProcessEngine();
    BpmnModelInstance bpmn = erzeugeBpmn();
    engine.getRepositoryService().createDeployment()
            .addModelInstance("manyTasks.bpmn", bpmn).deploy();
    RuntimeService runtimeService = engine.getRuntimeService();
    ProcessInstance processInstance = runtimeService
            .startProcessInstanceByKey("manyTasks");
    System.out.println("Done");

}

private static BpmnModelInstance erzeugeBpmn() {
    AbstractFlowNodeBuilder<?, ?> builder = Bpmn.createProcess().id("manyTasks").executable().startEvent();
    for(int i = 0; i < NUMBER_TASKS; i++){
    builder = builder.serviceTask().camundaClass(EmptyDelegate.class.getName());
    }
    return builder.endEvent().done();
}

As you can see, nothing fancy (and I am still happy that there is a Java API for generating BPMN).
My computer has two Intel Core i7 with 2.9GHz and 16GB of RAM and runs Java 1.7.0_72 64bit. To run this I used the Eclipse defaults (Kepler SR2 x64):

--launcher.XXMaxPermSize
256M
--launcher.XXMaxPermSize
256m
-Xms40m
-Xmx512m


Ten and 100 tasks are no problem.
To get an overview of the size of the stacktraces I'll add a JavaDelegate, which throws an exception at the end.
So the method looks like this:

private static BpmnModelInstance erzeugeBpmn() {
   AbstractFlowNodeBuilder<?, ?> builder = Bpmn.createProcess().id("manyTasks").executable().startEvent();
      for(int i = 0; i < ANZAHL_TASKS; i++){
        builder = builder.serviceTask().camundaClass(EmptyDelegate.class.getName());
      }
      return builder.serviceTask().camundaClass(ExceptionDelegate.class.getName()).endEvent().done();
   }

Also, I'd like to see how log output grows, so here are the numbers. The additional task is always the exception task so the numbers are 11, 101, 1001...
  • 11 tasks: 392 lines log
  • 101 tasks: 1025 lines log
  • 1001 tasks: SOF
Yay, I reached the limit ;-)

Exception in thread "main" java.lang.StackOverflowError
    at java.lang.ThreadLocal$ThreadLocalMap.getEntry(ThreadLocal.java:376)
    at java.lang.ThreadLocal$ThreadLocalMap.access$000(ThreadLocal.java:261)
    at java.lang.ThreadLocal.get(ThreadLocal.java:146)
    at org.camunda.bpm.engine.impl.context.Context.getStack(Context.java:95)
    at org.camunda.bpm.engine.impl.context.Context.getCommandContext(Context.java:46)
    at org.camunda.bpm.engine.impl.persistence.entity.ExecutionEntity.performOperationSync(ExecutionEntity.java:728)
    at org.camunda.bpm.engine.impl.persistence.entity.ExecutionEntity.performOperation(ExecutionEntity.java:719)
...

It seems like I gotta take some smaller steps:
  • 501 tasks: SOF
  • 401 tasks: SOF
  • 301 tasks: SOF
  • 201 tasks: 1025 lines log
  • 151 tasks: 1025 lines log
Wait, what?
Yes, strangely Eclipse always shows me the same amount of lines for the exception after reaching a certain threshold. And no, I didn't limit the console output in Eclipse. If anyone knows why this limit exists, please let me know.

The task limit I reached was 268 tasks (267 "normal" ones and one exception task).
I am not sure about the practical implications of my "research" but as I said, I was just curious.
Maybe we can agree that processes of a certain size should reach a wait state due to organizational and technical reasons ;-)

EDIT: Please note that when executing a task as multi instance every loop counts as one (I learned that the hard way ;-) )

Thursday, October 9, 2014

Assemble your custom Apache Karaf with the karaf-maven-plugin

I was quite happy to find out there is a Maven Plugin with which you can assembly a full Apache Karaf and include your own features/bundles.
From time to time I like to test my bundles in a real environment. Because of that the plugin is a great way to save the steps of unzipping a new Karaf, adding my feature and installing it.
So the plugin basically serves my laziness ;-)
But before the lazy part starts (for me and you) we have to do some work to get the plugin running.

I will start to describe the things I figured out. Then I will show you my final configuration and at the end I will talk about the problems I encountered.
Of course you can take a look at the documentation (here and here), too.

Karaf-assembly

 

To start your assembly project you just need an empty maven project with the packaging "karaf-assembly" and the plugin, of course.

To configure the features for the plugin (so the features will end up in the Karaf) there are three options:
  1. startupFeature
  2. bootFeature
  3. installedFeature
Here is an example:

<configuration>
  <bootFeatures>
    <feature>standard</feature>
    <feature>management</feature>

    <feature>camunda-bpm-karaf-feature-minimal</feature> 
  </bootFeatures>
</configuration>

All three types result in a different configuration. Since I don't want to copy the documentation I'll give a very brief explanation.

startupFeatures

All the bundles from your feature will appear in the startup.properties, copied to system/ and started with the Karaf.

bootFeatures

All the bundles from your feature will be copied to system/. The features you listed will appear in org.apache.karaf.features.cfg and installed when starting Karaf. The path to your feature.xml will be added to org.apache.karaf.features.cfg as feature repository.

installFeatures

All the bundles from your feature will be copied to system/. The path to your feature.xml will be added to org.apache.karaf.features.cfg as feature repository.

You can see that every kind of *Features gets a little bit less serious than the one before. Please note that "compile" dependencies in your POM will be treated like a startupFeature.

All the dependencies you want to include have to be ether of type "kar" or have to have the classifier "feature" and type "xml", e.g:

<dependency>
  <groupId>org.apache.karaf.features</groupId>
  <artifactId>standard</artifactId>
  <version>3.0.2-SNAPSHOT</version>
  <classifier>features</classifier>
  <type>xml</type>
  <scope>runtime</scope>
</dependency>

Other dependencies will be ignored.

That was all I could figure out about the configuration of the plugin. Now let's have a look at my project.

My project

 

As mentioned before my project contains no classes or anything under src/resources. It just has the pom.xml that looks like this (Google Drive link).
I added a small shell script because the karaf start file wasn't executable and because I didn't want to move to target/assembly/... every time. Also I had a small problem with Java (see following heading).
The script looks like this:

export JAVA_HOME=$(/usr/libexec/java_home -v 1.6)
chmod 777 ./target/assembly/bin/karaf
./target/assembly/bin/karaf start


Nothing fancy ;-) So, that's already all about my project. Finally, I want to tell you about the problems I faced.

Issues


Plugin version

I had the problem that when a feature contained nested features the nested ones wouldn't be resolved. It took me a while and some remote debugging to find the problem. After I asked in the mailing list I was told that the problem existed in my version (3.0.1) and is fixed in the next one.
So you should definitely use the 3.0.2-SNAPSHOT version despite the fact that it's a snapshot. Jean-Baptiste did some great improvements in that version. The logging is way better and you can have nested features.

Ordering of dependencies

After upgrading my version I could see that all of my bundles were successfully installed into the system/ directory. But after starting my Karaf they weren't deployed. The "mvn:" URL for my feature was missing in the org.apache.karaf.features.cfg "featuresRepositories" property.
I found out that the problem was in the order of my dependencies.

My feature was the first dependency and then followed the Apache Karaf dependencies. Like this: 
<dependencies>
  <dependency>
    <groupId>org.camunda.bpm.extension.osgi</groupId>
    <artifactId>camunda-bpm-karaf-feature</artifactId>
    <version>1.1.0-SNAPSHOT</version>
    <classifier>features</classifier>
    <type>xml</type>
    <scope>runtime</scope>
  </dependency>
  <dependency>
    <groupId>org.apache.karaf.features</groupId>
    <artifactId>framework</artifactId>
    <version>3.0.2-SNAPSHOT</version>
    <type>kar</type>
  </dependency>
  <dependency>
    <groupId>org.apache.karaf.features</groupId>
    <artifactId>standard</artifactId>
    <version>3.0.2-SNAPSHOT</version>
    <classifier>features</classifier>
    <type>xml</type>
    <scope>runtime</scope>
  </dependency>
</dependencies>

The problem is that the framework Kar contains all the configuration files. So when the plugin tries to update the config-file with my feature it is not present. So be careful that the framework kar is your first dependency.

Java 8

 

Edit: As Jean-Baptiste told me (thank you again) the Java 8 problem is only related to version 3.0.1 which I can hereby confirm. So if you have followed my advice and use 3.0.2 you can skip this part.

Being the young and hip person I am ;-) my MacBook was already running Java 8. When I assembled and started a Karaf it would start without a problem (at least it seemed so). But hitting tab only showed this small amount of commands:


Every command, even help, would answer with a NullPointerException. The NPE itself looked like this:

2014-10-07 16:55:55,232 | ERROR | Local user karaf | ShellUtil                        | 37 - org.apache.karaf.shell.console - 3.0.1 | Exception caught while executing command
java.lang.NullPointerException
    at org.apache.felix.gogo.runtime.Reflective.invoke(Reflective.java:61)[37:org.apache.karaf.shell.console:3.0.1]
    at org.apache.felix.gogo.runtime.CommandProxy.execute(CommandProxy.java:82)[37:org.apache.karaf.shell.console:3.0.1]
    at org.apache.felix.gogo.runtime.Closure.executeCmd(Closure.java:477)[37:org.apache.karaf.shell.console:3.0.1]
    at org.apache.felix.gogo.runtime.Closure.executeStatement(Closure.java:403)[37:org.apache.karaf.shell.console:3.0.1]
    at org.apache.felix.gogo.runtime.Pipe.run(Pipe.java:108)[37:org.apache.karaf.shell.console:3.0.1]


At first I thought something was missing. But checking the logs again, looking at what happened during startup, revealed some IllegalArgumentExceptions:

2014-10-07 16:53:23,402 | INFO  | FelixStartLevel  | ServiceRecipe                    | 19 - org.apache.aries.blueprint.core - 1.4.0 | Unable to create a proxy object for the service .component-1 defined in bundle org.apache.karaf.deployer.features at version 3.0.1 with id 25. Returning the original object instead.
java.lang.IllegalArgumentException

at org.objectweb.asm.ClassReader

I found out (thank you internet) that this is a Java 8 related problem. The command

export JAVA_HOME=$(/usr/libexec/java_home -v 1.6)

solved my problem. To always start my Karaf with Java 6 I added this line to my start script (see previous heading).

That was all about my karaf-maven-plugin experience. I am sure there are some more hidden things I couldn't figure out. I hope my experience will be useful for someone else.
Have fun with your own custom Karaf!

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!

 

Copyright @ 2013 Wrong tracks of a developer.

Designed by Templateiy