This time, it’s not the usual blog entry. I want to point out that my blog post about Gatling load testing has been published on my employer’s blog. If you want to read it you can find it here. Feel free to make comments!
Posts about the experiences I gather when developing and getting in touch with new technologies. They will include programming languages, tools, version control and so on.
This time, it’s not the usual blog entry. I want to point out that my blog post about Gatling load testing has been published on my employer’s blog. If you want to read it you can find it here. Feel free to make comments!
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.
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.InitialContextFactory works like this e.g.: Properties env = new Properties();
env.put(Context.INITIAL_CONTEXT_FACTORY,
"org.jboss.naming.remote.client.InitialContextFactory");
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.![]() |
| Picture under BSD license, see here |
<?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.<?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>
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.ServiceListener but for the rest)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.
@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.
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.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.<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 ;)Copyright @ 2013 Wrong tracks of a developer.