Adobe CQ5 integration with Apache CXF
In this post I’ll discuss how to integrate Adobe CQ 5.6.1 with Apache CXF. This post is based on the discussion in adaptTo() conference 2011.
Brief Introduction to Apache CXF
“Apache CXF is an open source services framework. It uses JAX-WS and JAX-RS APIs so that it can handle a variety of protocols such as SOAP, XML/HTTP, RESTful HTTP, or CORBA and work over a variety of transports such as HTTP, JMS or JBI.”
Goals of this Post are –
1. Adobe CQ integration with Apache CXF.
2. Java proxy classes generation from a wsdl file Using Apache CXF in CQ project.
3. Use these proxy classes in Adobe CQ5.
For this integration, I have created a maven project with two sub-modules one is bundle & other is content so that there are three pom.xml files one for each i.e. parent, bundle, content.
My project structure looks like –
First I will create proxy classes based on wsdl file using Apache CXF. For this post, I have used a open source WSDL.
It is a temperature converter service. In this service, I provide temperature in Celcius & it convert it into Fahrenheit.
When you Open this link you will see a link “service Description”.
Click on It, you will get a wsdl related to this service.
Save this wsdl file with a name ConvertTemperature.wsdl.
Go to your project and create a folder named as wsdl as shown in fig. & place ConvertTemperature.wsdl file in this folder.
Now, Add given dependencies into your project parent pom.xml file.
<dependency>
<groupId>org.apache.cxf</groupId>
<artifactId>cxf-bundle-minimal</artifactId>
<version>2.7.11</version>
<exclusions>
<exclusion>
<groupId>org.springframework</groupId>
<artifactId>spring-jms</artifactId>
</exclusion>
<exclusion>
<groupId>org.springframework</groupId>
<artifactId>spring-aop</artifactId>
</exclusion>
<exclusion>
<groupId>org.springframework</groupId>
<artifactId>spring-beans</artifactId>
</exclusion>
<exclusion>
<groupId>org.springframework</groupId>
<artifactId>spring-core</artifactId>
</exclusion>
<exclusion>
<groupId>org.springframework</groupId>
<artifactId>spring-context</artifactId>
</exclusion>
<exclusion>
<groupId>org.springframework</groupId>
<artifactId>spring-expression</artifactId>
</exclusion>
<exclusion>
<groupId>org.springframework</groupId>
<artifactId>spring-asm</artifactId>
</exclusion>
<exclusion>
<groupId>org.springframework</groupId>
<artifactId>spring-tx</artifactId>
</exclusion>
<exclusion>
<groupId>org.eclipse.jetty</groupId>
<artifactId>jetty-server</artifactId>
</exclusion>
<exclusion>
<groupId>org.eclipse.jetty</groupId>
<artifactId>jetty-continuation</artifactId>
</exclusion>
<exclusion>
<groupId>org.eclipse.jetty</groupId>
<artifactId>jetty-http</artifactId>
</exclusion>
<exclusion>
<groupId>org.eclipse.jetty</groupId>
<artifactId>jetty-io</artifactId>
</exclusion>
<exclusion>
<groupId>org.eclipse.jetty</groupId>
<artifactId>jetty-util</artifactId>
</exclusion>
<exclusion>
<groupId>org.eclipse.jetty</groupId>
<artifactId>jetty-security</artifactId>
</exclusion>
<exclusion>
<groupId>org.slf4j</groupId>
<artifactId>slf4j-api</artifactId>
</exclusion>
</exclusions>
</dependency>
<dependency>
<groupId>com.sun.xml.bind</groupId>
<artifactId>jaxb-xjc</artifactId>
<version>2.2.6</version>
<scope>compile</scope>
</dependency>
After adding these dependencies, search for maven-bundle-plugin in parent pom.xml file and replace it with given settings.
<plugin>
<groupId>org.apache.felix</groupId>
<artifactId>maven-bundle-plugin</artifactId>
<version>2.3.7</version>
<extensions>true</extensions>
<configuration>
<instructions>
<Export-Package>
com.ig.integration;version=${project.version},
com.ig.util.*;version=${project.version},
</Export-Package>
<Include-Resource>{maven-resources}</Include-Resource>
<Private-Package>
javax.wsdl;-split-package:=merge-first,
org.apache.cxf;-split-package:=merge-first,
org.apache.cxf.*;-split-package:=merge-first,
javax.xml.*;-split-package:=merge-first,
org.apache.ws.commons.schema.resolver.*;-split-package:=merge-first,
org.apache.ws.commons.schema.extensions.*;-split-package:=merge-first,
org.apache.ws.commons.schema.*;-split-package:=merge-first,
com.ig.integration.impl.*,
net.webservicex,
</Private-Package>
<Include-Resource>{maven-resources}</Include-Resource>
<Embed-Dependency>*;scope=compile|runtime;inline=false</Embed-Dependency>
<Embed-Transitive>true</Embed-Transitive>
<DynamicImport-Package>
com.sun.javadoc,
com.sun.tools.javadoc,
org.eclipse.jetty,
com.wordnik.swagger.jaxrs.config,
com.wordnik.swagger.jaxrs.listing,
com.sun.mirror.type,
com.sun.msv.*,
com.sun.source.tree,
com.sun.source.util,
com.sun.xml.fastinfoset.sax,
com.sun.xml.fastinfoset.stax,
javax.persistence,
javax.persistence.criteria,
javax.persistence.metamodel,
javax.resource.spi.endpoint,
jp.co.swiftinc.relax.schema,
jp.co.swiftinc.relax.verifier,
junit.framework,
net.jcip.annotations,
net.sf.cglib.proxy,
org.apache.aries.blueprint,
org.apache.aries.blueprint.mutable,
org.apache.avalon.framework.logger,
org.apache.axiom.om,
org.apache.commons.ssl,
org.apache.crimson.jaxp,
org.apache.cxf.tools.common,
org.apache.cxf.tools.common.model,
org.apache.cxf.tools.util,
org.apache.cxf.tools.validator,
org.apache.cxf.tools.wsdlto.core,
org.apache.cxf.ws.mex,
org.apache.cxf.ws.mex.model._2004_09,
org.apache.geronimo.osgi.registry.api,
org.apache.log4j.spi,
org.apache.lucene.document,
org.apache.lucene.index,
org.apache.lucene.search,
org.apache.mina.core.buffer,
org.apache.mina.core.filterchain,
org.apache.mina.core.future,
org.apache.mina.core.service,
org.apache.mina.core.session,
org.apache.mina.filter.codec,
org.apache.mina.filter.logging,
org.apache.mina.transport.socket.nio,
org.apache.tools.ant,
org.apache.tools.ant.taskdefs,
org.apache.tools.ant.taskdefs.compilers,
org.apache.tools.ant.types,
org.apache.velocity,
org.apache.velocity.app,
org.apache.velocity.context,
org.apache.xerces.impl.xpath.regex,
org.apache.xerces.parsers,
org.apache.xml.dtm,
org.apache.xml.utils,
org.apache.xpath,
org.apache.xpath.compiler,
org.apache.xpath.functions,
org.apache.xpath.objects,
org.bouncycastle.asn1,
org.bouncycastle.asn1.x509,
org.bouncycastle.util,
org.bouncycastle.util.encoders,
org.bouncycastle.x509.extension,
org.codehaus.jettison,
org.codehaus.jettison.badgerfish,
org.codehaus.jettison.json,
org.codehaus.jettison.mapped,
org.codehaus.jettison.util,
org.dom4j,
org.dom4j.io,
org.eclipse.jetty.continuation,
org.eclipse.jetty.http,
org.eclipse.jetty.io,
org.eclipse.jetty.security,
org.eclipse.jetty.server,
org.eclipse.jetty.server.handler,
org.eclipse.jetty.server.nio,
org.eclipse.jetty.server.session,
org.eclipse.jetty.server.ssl,
org.eclipse.jetty.util.component,
org.eclipse.jetty.util.thread,
org.hibernate,
org.hibernate.cache,
org.hibernate.cache.access,
org.hibernate.cfg,
org.hibernate.impl,
org.hibernate.stat,
org.hibernate.transaction,
org.jdom,
org.joda.convert,
org.junit,
org.jvnet.fastinfoset,
org.jvnet.staxex,
org.springframework.aop,
org.springframework.aop.framework,
org.springframework.aop.support,
org.springframework.beans,
org.springframework.beans.factory,
org.springframework.beans.factory.annotation,
org.springframework.beans.factory.config,
org.springframework.beans.factory.support,
org.springframework.beans.factory.wiring,
org.springframework.beans.factory.xml,
org.springframework.context,
org.springframework.context.annotation,
org.springframework.context.event,
org.springframework.context.support,
org.springframework.core,
org.springframework.core.io,
org.springframework.core.io.support,
org.springframework.core.task,
org.springframework.jms,
org.springframework.jms.connection,
org.springframework.jms.core,
org.springframework.jms.listener,
org.springframework.jms.support,
org.springframework.jms.support.converter,
org.springframework.jms.support.destination,
org.springframework.jndi,
org.springframework.transaction,
org.springframework.transaction.support,
org.springframework.util,
org.springframework.web.context,
org.springframework.web.context.support,
org.springframework.web.servlet,
org.springframework.web.servlet.handler,
org.springframework.web.servlet.mvc,
org.apache.log,
org.osgi.service.blueprint.container,
org.osgi.service.blueprint.reflect,
org.owasp.esapi,
sun.misc,
sun.nio.cs
</DynamicImport-Package>
</instructions>
</configuration>
</plugin>
Now, we have done with parent pom.xml file. Move to bundle pom.xml file.
Add these dependencies to bundle pom.xml file.
<dependency>
<groupId>org.apache.cxf</groupId>
<artifactId>cxf-bundle-minimal</artifactId>
</dependency>
<dependency>
<groupId>com.sun.xml.bind</groupId>
<artifactId>jaxb-xjc</artifactId>
</dependency>
In bundle pom.xml file search for maven-bundle-plugin and replace it with –
<plugin>
<groupId>org.apache.felix</groupId>
<artifactId>maven-bundle-plugin</artifactId>
<extensions>true</extensions>
<configuration>
<instructions>
<Bundle-SymbolicName>integration_cq_cxf</Bundle-SymbolicName>
</instructions>
</configuration>
</plugin>
Also add given plugin into <plugins> tag in your bundle pom.xml file.
<plugin>
<groupId>org.apache.cxf</groupId>
<artifactId>cxf-codegen-plugin</artifactId>
<version>2.6.2</version>
<executions>
<execution>
<id>generate-sources</id>
<phase>generate-sources</phase>
<configuration>
<sourceRoot>${basedir}/src/main/java</sourceRoot>
<wsdlRoot>${basedir}/src/main/wsdl</wsdlRoot>
<wsdlOptions>
<wsdlOption>
<wsdl>${basedir}/src/main/wsdl/ConvertTemperature.wsdl</wsdl>
</wsdlOption>
</wsdlOptions>
</configuration>
<goals>
<goal>wsdl2java</goal>
</goals>
</execution>
</executions>
</plugin>
This plugin is used to create Java files based on ConvertTemperature.wsdl file. This plugin have two paths. These are discussed below-
<sourceRoot> </sourceRoot> It indicates the location where all the java class files will be generated. i.e. It will generate all java file under /<project>/src/main/java folder.
<wsdlOption></wsdlOption> It indicates the location of wsdl file.
Note :
” If you don’t want to save wsdl file locally then just write the url of your web service wsdl file in <wsdl> tag under <wsdlOption> tag in cxf-codegen-plugin so that your cxf-codegen-plugin looks like”…..
<wsdlOptions>
<wsdlOption>
<wsdl>http://www.webservicex.net/ConvertTemperature.asmx?WSDL</wsdl>
</wsdlOption>
<wsdlOptions>
…..
Configuration part has been completed i.e. your code have all the required dependencies to interact with Apache CXF.
First check whether your code-generation-plugin is working or not. For checking go to your project location on your console and run mvn generate-sources command. It will generate the required Java proxy files based on the ConvertTemperature.wsdl file.
Note: “Before running this command first delete all the file form your project target folders else it will not generate these classes. Your project may need some other dependencies related to your code, make sure all those dependencies are also available.”
After running this command you will see net.webservice package under /src/java.
Let’s write some code for testing what we have done. Create a JaxWsClientFactory.java class in any of your package in my case it is com.util; Copy this code into that file.
package com.ig.util;
import org.apache.cxf.BusFactory;
import org.apache.cxf.jaxws.JaxWsProxyFactoryBean;
public class JaxWsClientFactory {
private JaxWsClientFactory() { /* NO CONSTRUCTOR */}
public static <T> T create(Class<T> ParentClass, String portUrl) {
return JaxWsClientFactory.create(ParentClass, portUrl, null, null);
}
public static <T> T create(Class<T> ParentClass, String portUrl, String userName, String password) {
JaxWsProxyFactoryBean jaxWsProxyFactoryBean = new JaxWsProxyFactoryBean();
try {
jaxWsProxyFactoryBean.setServiceClass(ParentClass);
jaxWsProxyFactoryBean.setAddress(portUrl);
jaxWsProxyFactoryBean.setUsername(userName);
jaxWsProxyFactoryBean.setPassword(password);
} catch (Exception e) {
e.printStackTrace();
}
return (T) jaxWsProxyFactoryBean.create();
}
}
For testing purpose- First create a interface named as ConvertTemperatureService.java under src/java/com/service directory. This interface having only one method as shown below –
package com.ig.integration;
public interface ConvertTemperatureService {
double convertCelsiusToFahrenheit(double temperatureInCelsius);
}
Second create a service implementation class named as ConvertTemperatureImpl.java under src/java/com/service/impl directory as shown in previous fig. and copy & paste this code.
import com.ig.integration.ConvertTemperatureService;
import com.ig.util.JaxWsClientFactory;
import net.webservicex.ConvertTemperatureSoap;
import net.webservicex.TemperatureUnit;
import org.apache.cxf.BusFactory;
import org.apache.felix.scr.annotations.Activate;
import org.apache.felix.scr.annotations.Component;
import org.apache.felix.scr.annotations.Service;
import org.osgi.service.component.ComponentContext;
@Service
@Component(immediate = true,metatype = false,enabled = true)
public class ConvertTemperatureImpl implements ConvertTemperatureService{
private ConvertTemperatureSoap convertTemperatureSoap;
@Override
public double convertCelsiusToFahrenheit(double valueToConvert) {
double convertedTemperature = 0.0;
try {
convertTemperatureSoap = JaxWsClientFactory.create(ConvertTemperatureSoap.class,
“http://www.webservicex.net/ConvertTemperature.asmx”);
convertedTemperature = convertTemperatureSoap.convertTemp(valueToConvert,
TemperatureUnit.DEGREE_CELSIUS, TemperatureUnit.DEGREE_FAHRENHEIT);
} catch (Exception e) {
e.printStackTrace();
}
return convertedTemperature;
}
public ConvertTemperatureSoap getInstance() {
return convertTemperatureSoap;
}
@Activate
protected void activate(final ComponentContext componentContext) {
System.out.println(“inside activate method”);
}
}
Here is the turning point you will get a exception in your stdout.log file.
exception is
Caused by: java.lang.ClassNotFoundException: com.sun.xml.bind.v2.ContextFactory
at org.apache.sling.commons.classloader.impl.ClassLoaderFacade.loadClass(ClassLoaderFacade.java:127)
at java.lang.ClassLoader.loadClass(ClassLoader.java:358)
at javax.xml.bind.ContextFinder.newInstance(ContextFinder.java:192)
… 175 more
The reason for this is the illegal class loading in the OSGI context, and the fault is not on CXF but on the JAXB implementation, and we cannot fix this third-party implementation. By default, the Thread context class loader is not aware of OSGi and thus doesn’t see any of the classes imported in the bundle. That’s why loading the class fails.
Now just go to your factory classes (i.e. JaxWsClientFactory) and make some changes as shown below-
package com.ig.util;
import org.apache.cxf.BusFactory;
import org.apache.cxf.jaxws.JaxWsProxyFactoryBean;
public class JaxWsClientFactory {
private JaxWsClientFactory() { /* NO CONSTRUCTOR */}
public static <T> T create(Class<T> ParentClass, String portUrl) {
ClassLoader oldClassLoader = Thread.currentThread().getContextClassLoader();
Thread.currentThread().setContextClassLoader(BusFactory.class.getClassLoader());
try {
return JaxWsClientFactory.create(ParentClass, portUrl, null, null);
} finally {
Thread.currentThread().setContextClassLoader(oldClassLoader);
}
}
public static <T> T create(Class<T> ParentClass, String portUrl, String userName, String password) {
JaxWsProxyFactoryBean jaxWsProxyFactoryBean = new JaxWsProxyFactoryBean();
try {
jaxWsProxyFactoryBean.setServiceClass(ParentClass);
jaxWsProxyFactoryBean.setAddress(portUrl);
jaxWsProxyFactoryBean.setUsername(userName);
jaxWsProxyFactoryBean.setPassword(password);
} catch (Exception e) {
e.printStackTrace();
}
return (T) jaxWsProxyFactoryBean.create();
}
}
Lines in bold format are the extra code written into your service class. The reason is that you have to change your class loader till you are dealing with web-service. first save the old class loader into some variable & at the time of completing the request set old class loader class.
Demo Project Location
You can clone this open source project from given git repository.
git@github.com:vietankur009/CQ_CXF_integration.git
Go to target Folder where you want this project and run git clone command as shown below.
git clone git@github.com:vietankur009/CQ_CXF_integration.git
Then you will see this project in target directory.
then run these commands –
cd integration_cq_cxf
mvn clean install -P autoInstallPackage
Im grateful for the article post.Really thank you! Much obliged.
The project on github is not deployed according to provided instruction. When running
mvn clean install -PautoInstallPackage i’ve got
Failed to execute goal on project content: Could not resolve dependencies for project integration_cq_cxf:content:content-package:1.0-SNAPSHOT: The following artifacts could not be resolved: integration_cq_cxf:integration_cq_cxf-bundle:jar:1.0-SNAPSHOT, cxf:cxf:pom:1.0-SNAPSHOT: Failure to find integration_cq_cxf:integration_cq_cxf-bundle:jar:1.0-SNAPSHOT in http://repo.adobe.com/nexus/content/groups/public/ was cached in the local repository, resolution will not be reattempted until the update interval of adobe-snapshots has elapsed or updates are forced ->