Maven + Apache Felix + CXF + DOSGi: An Example of DOSGi Service
Link in series
Link to two Felix instances
Here is yet another post in Maven + Apache Felix + CXF + DOSGi series.
Here I will show how to use Apache CXF DOSGi for cosuming remote services. You may see the sources on my GitHub account.
We will have three projects dosgiRemote.service, dosgiRemote.service.api and dosgiRemote.consumer. dosgiRemote.service.api provides an interface for a service. dosgiRemote.service provides implementation for the service. dosgiRemote.consume will consume the service.
dosgiRemote.service.api has to be shared between dosgiRemote.service and dosgiRemote.consumer as both has to know which service they are publishing and consuming. dosgiRemote.service.api and dosgiRemote.service will run in one OSGi container. dosgiRemote.service.api and dosgiRemote.consumer will run in another OSGi container. You may see how to do that in Eclipse in the previous post.
dosgiRemote.service.api contains the following interface to a service:
package dk.sorokin.maksim.dosgiRemote.service.api;
import javax.ws.rs.GET;
import javax.ws.rs.Path;
import javax.ws.rs.PathParam;
import javax.ws.rs.Produces;
import javax.ws.rs.core.MediaType;
@Path("greeter")
public interface Greeter {
@GET
@Path("sayHello/{name}")
@Produces(MediaType.TEXT_PLAIN)
String sayHello(@PathParam("name") String name);
}
dosgiRemote.service provides the following implementation:
package dk.sorokin.maksim.dosgiRemote.internal.service;
import dk.sorokin.maksim.dosgiRemote.service.api.Greeter;
public class GreeterImpl implements Greeter {
public String sayHello(String name) {
return "Hello, " + name;
}
}
Also, dosgiRemote.service registers a service in the following way:
package dk.sorokin.maksim.dosgiRemote.internal;
import java.util.Dictionary;
import java.util.Hashtable;
import org.osgi.framework.BundleActivator;
import org.osgi.framework.BundleContext;
import dk.sorokin.maksim.dosgiRemote.internal.service.GreeterImpl;
import dk.sorokin.maksim.dosgiRemote.service.api.Greeter;
public class Activator implements BundleActivator {
public void start(BundleContext context) throws Exception {
Dictionary<String, String> restProps = new Hashtable<String, String>();
restProps.put("service.exported.interfaces", "*");
restProps.put("service.exported.configs", "org.apache.cxf.rs");
restProps.put("service.exported.intents", "HTTP");
restProps.put("org.apache.cxf.rs.address", "http://localhost:8080/");
context.registerService(Greeter.class.getName(), new GreeterImpl(), restProps);
}
public void stop(BundleContext context) throws Exception {
//
}
}
dosgiRemote.consumer will have OSGI-INF\remote-service\remote-services.xml, according to DOSGi documentation:
<?xml version="1.0" encoding="UTF-8"?>
<service-descriptions xmlns="http://www.osgi.org/xmlns/sd/v1.0.0">
<service-description>
<provide interface="dk.sorokin.maksim.dosgiRemote.service.api.Greeter" />
<property name="service.exported.interfaces">*</property>
<property name="service.exported.configs">org.apache.cxf.rs</property>
<property name="service.exported.intents">HTTP</property>
<property name="org.apache.cxf.rs.address">http://localhost:8080</property>
</service-description>
</service-descriptions>
And the Activator class for dosgiRemote.consumer will be:
package dk.sorokin.maksim.dosgiRemote.consumer.internal;
import org.osgi.framework.BundleActivator;
import org.osgi.framework.BundleContext;
import org.osgi.framework.ServiceReference;
import org.osgi.util.tracker.ServiceTracker;
import dk.sorokin.maksim.dosgiRemote.service.api.Greeter;
public class Activator implements BundleActivator {
@Override
public void start(BundleContext context) throws Exception {
ServiceTracker serviceTracker = new ServiceTracker(context, Greeter.class.getName(), null) {
@Override
public Object addingService(ServiceReference reference) {
Object result = super.addingService(reference);
Object svc = context.getService(reference);
if (svc instanceof Greeter) {
final Greeter greeter = (Greeter) svc;
System.out.println(greeter.sayHello("Max"));
}
return result;
}
};
serviceTracker.open();
}
public void stop(BundleContext context) throws Exception {
//
}
}
We will have two startup configuration for Apache Felix, as described above. The first one:
felix.auto.deploy.action=install,start felix.log.level=1 org.osgi.framework.storage.clean=onFirstInit felix.auto.start.1 = \ assembly:/C:/projects/dosgiRemote/dosgiRemote.service.api/target/classes \ assembly:/C:/projects/dosgiRemote/dosgiRemote.service/target/classes
And the second one:
felix.auto.deploy.action=install,start felix.log.level=1 org.osgi.framework.storage.clean=onFirstInit felix.auto.start.1 = \ assembly:/C:/projects/dosgiRemote/dosgiRemote.service.api/target/classes \ assembly:/C:/projects/dosgiRemote/dosgiRemote.service/target/classes
Launch the first configuration and then the second. You should see the following message in the console:
Hello, Max
You could also see the same message in the browser on http://localhost:8080/greeter/sayHello/Max.
You may pass objects as well. Refer to previous posts to do that.
You can take the sources from may GitHub account.