DZone
Thanks for visiting DZone today,
Edit Profile
  • Manage Email Subscriptions
  • How to Post to DZone
  • Article Submission Guidelines
Sign Out View Profile
  • Post an Article
  • Manage My Drafts
Over 2 million developers have joined DZone.
Log In / Join
Please enter at least three characters to search
Refcards Trend Reports
Events Video Library
Refcards
Trend Reports

Events

View Events Video Library

Zones

Culture and Methodologies Agile Career Development Methodologies Team Management
Data Engineering AI/ML Big Data Data Databases IoT
Software Design and Architecture Cloud Architecture Containers Integration Microservices Performance Security
Coding Frameworks Java JavaScript Languages Tools
Testing, Deployment, and Maintenance Deployment DevOps and CI/CD Maintenance Monitoring and Observability Testing, Tools, and Frameworks
Culture and Methodologies
Agile Career Development Methodologies Team Management
Data Engineering
AI/ML Big Data Data Databases IoT
Software Design and Architecture
Cloud Architecture Containers Integration Microservices Performance Security
Coding
Frameworks Java JavaScript Languages Tools
Testing, Deployment, and Maintenance
Deployment DevOps and CI/CD Maintenance Monitoring and Observability Testing, Tools, and Frameworks

Modernize your data layer. Learn how to design cloud-native database architectures to meet the evolving demands of AI and GenAI workkloads.

Secure your stack and shape the future! Help dev teams across the globe navigate their software supply chain security challenges.

Releasing software shouldn't be stressful or risky. Learn how to leverage progressive delivery techniques to ensure safer deployments.

Avoid machine learning mistakes and boost model performance! Discover key ML patterns, anti-patterns, data strategies, and more.

Related

  • Spring Boot - How To Use Native SQL Queries | Restful Web Services
  • How to Consume REST Web Service (GET/POST) in Java 11 or Above
  • Breaking Up a Monolithic Database with Kong
  • RESTful Web Services: How To Create a Context Path for Spring Boot Application or Web Service

Trending

  • Failure Handling Mechanisms in Microservices and Their Importance
  • How to Configure and Customize the Go SDK for Azure Cosmos DB
  • My LLM Journey as a Software Engineer Exploring a New Domain
  • Kubeflow: Driving Scalable and Intelligent Machine Learning Systems
  1. DZone
  2. Software Design and Architecture
  3. Integration
  4. Building CXF REST Service in OSGi for Karaf

Building CXF REST Service in OSGi for Karaf

By 
Arun Manivannan user avatar
Arun Manivannan
·
Sep. 05, 13 · Interview
Likes (0)
Comment
Save
Tweet
Share
33.1K Views

Join the DZone community and get the full member experience.

Join For Free

I’ll leave it to the experts to tell how awesome OSGi is. Among the many benefits, I could tell you why we picked up OSGi for a pet project - Modularity, avoiding JAR hell and dynamic updates (hey, why not?)

We chose Apache Felix (an OSGi framework specification implementation) and Apache Karaf (ummm, how do I put this - something like an app server for OSGi applications). Besides serving as an OSGi container, Karaf has a lot of awesome features (pun intended). And we like the idea of managing multiple Karaf instances managed through Zookeeper.

Enough talk, let’s see some code. This is a rudimentary tutorial on how to run a basic OSGi CXF-JAX Rest Service on Karaf. Given a REST parameter (a name), the service would just return Hello, (name). That’s it !! The entire project could be downloaded here

So, if the request is http://localhost:8181/cxf/karafsimple/say/hello/arun, the response would be Hello, arun

Please note that this project does not have any domain models and therefore has only two projects - one for the REST (Controller) and the other for the actual service implementation. The project structure looks like this :

Step 1 - Service Implementation

This project just has two ‘useful’ things - the HelloService interface and the HelloServiceImpl class.

HelloService
package me.rerun.karafcxf.service.impl;
public interface HelloService {
    public String sayHello(String name);
}
HelloServiceImpl
package me.rerun.karafcxf.service.impl;
public class HelloServiceImpl implements HelloService {
    @Override
    public String sayHello(String name) {
        return "Hello, "+name;
    }
}

Stupid right?

Step 2 - REST project

Similar to the Service project, this project also has just two notable things - the HelloRestService interface and the HelloRestServiceImpl class.

HelloRestService

HelloRestService
package me.rerun.karafcxf.rest;
import javax.ws.rs.GET;
import javax.ws.rs.Path;
import javax.ws.rs.PathParam;
//Maps for the `say` in the URL
@Path("say")
public interface HelloRestService {
    @GET
    @Path("hello/{name}") //Maps for the `hello/John` in the URL
    public String handleGet(@PathParam("name") String name);
}

HelloRestServiceImpl

The HelloRestServiceImpl does nothing but calls the HelloService which gets injected through Blueprint Dependency Injection. Hey, does the inject look very familiar to Spring DI? Exactly !! The Blueprint DI is heavily influenced by Spring DI. In fact, the original work for blueprint is done by Spring.

HelloRestServiceImpl
package me.rerun.karafcxf.rest;
import me.rerun.karafcxf.service.impl.HelloService;
public class HelloRestServiceImpl implements HelloRestService{
    //Just like Spring.  Please add Getters/Setters. Blueprint annotations are still work in progress
    private HelloService helloService;
    public String handleGet(String name){
        return helloService.sayHello(name);
    }
    /*
        Constructor
     */
    public HelloRestServiceImpl(){
    }
    /*
        Getters and Setters
     */
    public HelloService getHelloService() {
        return helloService;
    }
    public void setHelloService(HelloService helloService) {
        this.helloService = helloService;
    }
}

Step 3 - Injections

XMLs (of any name) inside OSGI-INF/blueprint folder will get picked up for DI scanning.

serviceimpl.xml

Does two things in one tag :

  1. Registers the HelloService into the service registry for lookup
  2. Says that its implementation is HelloServiceImpl
resources/OSGI-INF/blueprint/serviceimpl.xml
<blueprint xmlns="http://www.osgi.org/xmlns/blueprint/v1.0.0"
           xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
           xsi:schemaLocation="http://www.osgi.org/xmlns/blueprint/v1.0.0 http://www.osgi.org/xmlns/blueprint/v1.0.0/blueprint.xsd">
    <service ref="helloServiceBean" interface="me.rerun.karafcxf.service.impl.HelloService">
        <bean class="me.rerun.karafcxf.service.impl.HelloServiceImpl"/>
    </service>
</blueprint>

In fact, you could do this in two separate steps. More on that here.

resources/OSGI-INF/blueprint/serviceimpl.xml
<service id="helloServiceBean" ref="helloServiceImpl"
    interface="me.rerun.karafcxf.service.impl.HelloService" />
<bean id="helloServiceImpl" class="me.rerun.karafcxf.service.impl.HelloServiceImpl" />

rest.xml

resources/OSGI-INF/blueprint/rest.xml
<blueprint xmlns="http://www.osgi.org/xmlns/blueprint/v1.0.0"
           xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
           xmlns:cm="http://aries.apache.org/blueprint/xmlns/blueprint-cm/v1.0.0"
           xmlns:jaxws="http://cxf.apache.org/blueprint/jaxws"
           xmlns:jaxrs="http://cxf.apache.org/blueprint/jaxrs"
           xmlns:cxf="http://cxf.apache.org/blueprint/core"
           xsi:schemaLocation="
  http://www.osgi.org/xmlns/blueprint/v1.0.0 http://www.osgi.org/xmlns/blueprint/v1.0.0/blueprint.xsd
  http://cxf.apache.org/blueprint/jaxws http://cxf.apache.org/schemas/blueprint/jaxws.xsd
  http://cxf.apache.org/blueprint/jaxrs http://cxf.apache.org/schemas/blueprint/jaxrs.xsd
  http://cxf.apache.org/blueprint/core http://cxf.apache.org/schemas/blueprint/core.xsd">
<!-- 1 -->
    <cxf:bus id="cxfBus1">
        <cxf:features>
            <cxf:logging/>
        </cxf:features>
    </cxf:bus>
<!-- 2 -->
    <jaxrs:server address="/karafsimple" id="someRestService">
        <jaxrs:serviceBeans>
            <ref component-id="restServiceImpl"/>
        </jaxrs:serviceBeans>
    </jaxrs:server>
<!-- 3 -->
    <!-- Implementation of the rest service -->
    <bean id="restServiceImpl" class="me.rerun.karafcxf.rest.HelloRestServiceImpl">
        <property name="helloService" ref="helloServiceBean"/>  <!--Points to the reference below -->
    </bean>
<!-- 4 -->
    <!-- This has to point to the service registered through serviceimpl.xml in the service.impl project -->
    <reference id="helloServiceBean"
               interface="me.rerun.karafcxf.service.impl.HelloService">
    </reference>
</blueprint>

1) cxf-bus is the bus configuration for CXF. It is like the manager for all CXF services. The most common use as far as I know is to configure custom interceptors (for auditing, request/response manipulation, headers manipulation etc)

2) the jaxrs:server initiates a server which would start listening to the URLs that we mapped for. Of course, we would want to map the handlers for the URLs and those go under the serviceBeans.

3) The third note in the XML is the just the restServiceImpl configuration and the injection of the helloService as a property inside the HelloRestServiceImpl

4) The reference tag will lookup the service registry for a bean with the same id.

Step 4 - KAR - Karaf Archive (Optional but easier this way)

Technically, you could just start throwing the bundles generated through the Maven into to the deploy directory of karaf. However, as the project goes big and your dependencies are becoming many, it is advisable to use the .kar archive. Picture .kar as your .war or .ear bundle. A .kar archive, internally, looks something like this :

Building .kar

Building the .kar is composed of two steps :

Step 1

feature.xml

Similar to your web descriptor or application descriptor, we have the features descriptor in Karaf to represent the entire repository that we are bundling together to compose our application.

In our case, we don’t have any external .jar dependencies except for the cxf and the http service for which we are using the in-built features available inside karaf.

feature.xml
<?xml version="1.0" encoding="UTF-8"?>
<features xmlns="http://karaf.apache.org/xmlns/features/v1.0.0"
          name="${project.artifactId}-${project.version}">
    <feature name="karafcxf" description="karaf cxf hello" version="1.0-SNAPSHOT" resolver="(obr)">
        <details>${project.description}</details>
        <feature>http</feature>
        <feature>cxf</feature>
        <feature>this-project-dependants</feature>
        <bundle>mvn:karafcxf/karafcxf.service.impl/1.0-SNAPSHOT</bundle>
        <bundle>mvn:karafcxf/karafcxf.rest/1.0-SNAPSHOT</bundle>
    </feature>
    <feature name="this-project-dependants">
        <!-- Dependent bundles if you have any. This project doesn't have one
        <bundle>mvn:org.apache.commons/commons-lang3/3.1</bundle>
        <bundle>mvn:org.codehaus.jackson/jackson-core-asl/1.9.5</bundle>
        <bundle>mvn:org.codehaus.jackson/jackson-mapper-asl/1.9.5</bundle>
        <bundle>mvn:org.codehaus.jackson/jackson-jaxrs/1.9.5</bundle>
        <bundle>mvn:com.google.guava/guava/14.0.1</bundle>
        <bundle>wrap:mvn:org.apache.httpcomponents/httpcore/4.2.4</bundle>
        <bundle>wrap:mvn:org.apache.httpcomponents/httpmime/4.2.5</bundle>
        <bundle>wrap:mvn:org.noggit/noggit/0.5</bundle>
        <bundle>wrap:mvn:org.apache.solr/solr-solrj/4.4.0</bundle>
        -->
    </feature>
</features>

Step 2

Maven plugin configuration to create .kar, which indicates where your feature.xml is located (Note that this file is located inside your karaf project)

pom.xml
 <build>
        <plugins>
            <plugin>
                <groupId>org.apache.karaf.tooling</groupId>
                <artifactId>features-maven-plugin</artifactId>
                <version>2.3.2</version>
                <executions>
                    <execution>
                        <id>create-kar</id>
                        <goals>
                            <goal>create-kar</goal>
                        </goals>
                        <configuration>
                            <featuresFile>${project.basedir}/src/main/resources/feature.xml</featuresFile>
                        </configuration>
                    </execution>
                </executions>
            </plugin>
        </plugins>
    </build>

Wraps

Notice the wrap protocol in front of the mvn protocol in few bundles as in

<bundle>wrap:mvn:org.apache.httpcomponents/httpmime/4.2.5</bundle>

Not all Jars are OSGi ready but they would obviously be used as a dependency in our project. In those cases, Karaf notices the wrapprotocol and bundles the JAR into an OSGi bundle. In case of doubt, just drop off the wrap and Karaf would complain that the jar is not OSGi compatible. (Alternatively, you could open up each of the dependant jars and check their manifest files)

013-08-28 01:38:48,669 | WARN  | raf-2.3.2/deploy | KarArtifactInstaller             | eployer.kar.KarArtifactInstaller  192 | 24 - org.apache.karaf.deployer.kar - 2.3.2 | Unable to install Kar feature xx-xxx-xxxxxx/0.0.0
org.osgi.framework.BundleException: Jar is not a bundle, no Bundle-SymbolicName mvn:org.apache.httpcomponents/httpcore/4.2.4
  at org.apache.karaf.features.internal.FeaturesServiceImpl.installBundleIfNeeded(FeaturesServiceImpl.java:836)[26:org.apache.karaf.features.core:2.3.2]
  at org.apache.karaf.features.internal.FeaturesServiceImpl.doInstallFeature(FeaturesServiceImpl.java:618)[26:org.apache.karaf.features.core:2.3.2]
  at org.apache.karaf.features.internal.FeaturesServiceImpl.installFeatures(FeaturesServiceImpl.java:414)[26:org.apache.karaf.features.core:2.3.2]
  at org.apache.karaf.features.internal.FeaturesServiceImpl.installFeature(FeaturesServiceImpl.java:402)[26:org.apache.karaf.features.core:2.3.2]
  at Proxy508d2419_d21e_4a93_b7fb_26e28d2f03a6.installFeature(Unknown Source)[:]
  at org.apache.karaf.deployer.kar.KarArtifactInstaller.installFeatures(KarArtifactInstaller.java:189)[24:org.apache.karaf.deployer.kar:2.3.2]
  at org.apache.karaf.deployer.kar.KarArtifactInstaller.install(KarArtifactInstaller.java:134)[24:org.apache.karaf.deployer.kar:2.3.2]
  at org.apache.karaf.deployer.kar.KarArtifactInstaller.update(KarArtifactInstaller.java:348)[24:org.apache.karaf.deployer.kar:2.3.2]
  at org.apache.felix.fileinstall.internal.DirectoryWatcher.update(DirectoryWatcher.java:1103)[6:org.apache.felix.fileinstall:3.2.6]
  at org.apache.felix.fileinstall.internal.DirectoryWatcher.update(DirectoryWatcher.java:898)[6:org.apache.felix.fileinstall:3.2.6]
  at org.apache.felix.fileinstall.internal.DirectoryWatcher.process(DirectoryWatcher.java:482)[6:org.apache.felix.fileinstall:3.2.6]
  at org.apache.felix.fileinstall.internal.DirectoryWatcher.run(DirectoryWatcher.java:291)[6:org.apache.felix.fileinstall:3.2.6]

Changing Log Levels

For all our development environment, we would want to increase our log level to get more feedback from Karaf. This could be achieved by modifying the org.ops4j.pax.logging.cfg file located in your <karaf-installation-directory>/etc

Step 5 - Other Maven configuration

Not technically a step because we would have covered this from the beginning anyway. And nothing fancy here.

Parent pom.xml

  1. Has the rest of the sub-modules configured.
  2. The various library dependencies configured
pom.xml
<project xmlns="http://maven.apache.org/POM/4.0.0"
         xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
         xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
    <modelVersion>4.0.0</modelVersion>
    <groupId>karafcxf</groupId>
    <artifactId>karafcxf</artifactId>
    <packaging>pom</packaging>
    <version>1.0-SNAPSHOT</version>
    <properties>
        <cxf.version>2.7.5</cxf.version>
    </properties>
    <modules>
        <module>karafcxf.rest</module>
        <module>karafcxf.service.impl</module>
        <module>karafcxf.kar</module>
    </modules>
    <dependencies>
      …
      …

Rest and ServiceImpl pom.xml

The other poms.xmls aren’t interesting

They just affiliate themselves to the parent pom with the parent tag as in

pom.xml
<build>
        <plugins>
            <plugin>
                <groupId>org.apache.felix</groupId>
                <artifactId>maven-bundle-plugin</artifactId>
                <version>2.3.7</version>
                <extensions>true</extensions>
                <configuration>
                    <instructions>
                        <Bundle-SymbolicName>${project.artifactId}</Bundle-SymbolicName>
                        <Bundle-Version>${project.version}</Bundle-Version>
                        <Bundle-Activator>com.nutraspace.coreservices.search.rest.Activator</Bundle-Activator>
                        <Export-Package>com.nutraspace.coreservices.search.rest*;version=${project.version}</Export-Package>
                        <Import-Package>*</Import-Package>
                    </instructions>
                </configuration>
            </plugin>
        </plugins>
    </build>

Step 6 - Bring up Karaf

My Karaf installation is located at : /Users/Gabriel/apps/apache-karaf-2.3.2

Start Karaf :

<installation-dir>/bin/./karaf

Installing CXF and HTTP services

features:chooseurl cxf 2.7.5

features:install http cxf

Checking whether your bundle is installed and your service running

osgi:list

dxf:list-endpoints

Stop Karaf

Ctrl +D (Please note that Ctrl +C closes the connection abruptly instead of stopping Karaf)

In case of accidental Ctrl+C and if Karaf isn’t starting properly, do a

rm -rf <installation-dir>/data/cache/*

URL Mapping

Like I mentioned earlier, the target request URL will be something like http://localhost:8181/cxf/karafsimple/say/hello/arun and the response would be Hello, arun

1) The HelloRestService interface has all the JAX RS annotations for the URL mapping. Well, technically, the interfaces just maps for say/hello/(name)

2) The karafsimple in the URL is derived from the the JAX RS address in blueprint.xml (about that later in Step 3 - rest.xml).

3) The cxf is a default if you deploy a CXF service on Karaf which obviously you could change.

REST Web Protocols Web Service

Published at DZone with permission of Arun Manivannan, DZone MVB. See the original article here.

Opinions expressed by DZone contributors are their own.

Related

  • Spring Boot - How To Use Native SQL Queries | Restful Web Services
  • How to Consume REST Web Service (GET/POST) in Java 11 or Above
  • Breaking Up a Monolithic Database with Kong
  • RESTful Web Services: How To Create a Context Path for Spring Boot Application or Web Service

Partner Resources

×

Comments
Oops! Something Went Wrong

The likes didn't load as expected. Please refresh the page and try again.

ABOUT US

  • About DZone
  • Support and feedback
  • Community research
  • Sitemap

ADVERTISE

  • Advertise with DZone

CONTRIBUTE ON DZONE

  • Article Submission Guidelines
  • Become a Contributor
  • Core Program
  • Visit the Writers' Zone

LEGAL

  • Terms of Service
  • Privacy Policy

CONTACT US

  • 3343 Perimeter Hill Drive
  • Suite 100
  • Nashville, TN 37211
  • support@dzone.com

Let's be friends:

Likes
There are no likes...yet! 👀
Be the first to like this post!
It looks like you're not logged in.
Sign in to see who liked this post!