Thursday, 26 June 2014

Select Default Values in Selection Box in CQ5 Dialogs

During project Development, I was facing an issue -

"how to select a default value in Selection box (Combobox or Dropdown) or in checkbox group where, option fields are static or dynamically generated."

Solution
For Selection Box(dropdown or Combobox) having static option values or dynamically generated options values, as I show in my last post, declare two properties.
  1. defaultValue
  2. value

Note: defaultValue is prerequisite & option selection will take place using value property. 

Set these properties as show below -












Points to be remember

1. defaultValue property could be of type String  or String[]. For default value selection you have to declare this property. It depends on your requirement. ex. String[] for checkbox, String for combobox.
If you don't declare this property and add only value property then option selection doesn't take place.


2. value property could also be type String  or String[]It's only requirement is you have declared defaultValue property.

3. there is no need to define any value in defaultValue property just leave it empty but define.

4. selection of default options will take place on the basis of value property.


For a Selection Box (Combobox) 

1. defaultValue should of type String &
2. value should also be type String as only one value could be selected at one time.

For a CheckBox

1. defaultValue could be of type String or String[]. and it may or may not have values.
2. value Should be of type String[] as you may want to select multiple checkbox at the time of loading.

Namah Shivay

Wednesday, 25 June 2014

Dialog using widgets from another Dialog in CQ5

In this post, I will show you 

how to use existing widgets in one dialog into another dialog in CQ5i.e. 
Use of widgets of one dialog into another dialog in CQ5.

My project structure is - 
For this demo I have created a component named as customDialogDemo under /apps/blogs/content.

Under this component I have created a dialog with two tabs.
1. textTab
2. NewFields

I have show you the use of NewFields tab in my last blog where, I create a combobox with dinamically generated options

for this post, I will use textTab. create a cq:WidgetCollection, named as items under textTab node.

Under this items node create a cq:Widget node & name it as text.

Now, this text widget points to the Out Of The Box (OOTB) text component. i.e. you don't have to create the child node and config nodes for new dialog you can directly include these properties from OOTB Text component.

for including a widget from one dialog into another dialog you have to use two properties.
xtype = cqinclude
path = <url to parent widget node>.infinity.json

<url>.infinity.json return JSON related to that particular node with its all sub child data.

just set these two properties as show below -













Your dialog is ready just drop your component and check it will show you a rich textbox under textTab tab.

you output screen will be same as that of original text component. this text value will be stored under this component node with property name text.

Note : use similar nodes types for including i.e. panel for panel, cq:Widget for cq:Widget, cq:WidgetCollection for cq:WidgetCollection.

Namah Shivay

Combobox with dynamically generated Options in CQ5 Dialog

This post I'll show you how to create combobox with dynamically generated option values in Adobe CQ5 dialog i.e. Combobox options will come from a JSON Object created by a servlet.

Project Structure
For showing this demo I have created a customDialogDemo component under blogs/content/ directory.

Then I create dialog with 2 tabs-
textTab
NewFields

You don't have a need to create two tabs just rename your tab with NewFields or let it be as it is.

Under NewFields Node 

1. Create a cq:widgetCollection Node named as items.

2. Under this items node create a new node cq
:widget  
    named as srcLanguage.

set the properties of this node as show in figure.












for creating a combobox use
xtype = "selection"
type   = "select"
all other properties are explained below - 

allowBlank - It restrict you from submitting the dialog without selecting any option from this combobox.

fieldLable - Text that will be shown before the combobox.

options - This property is used to define the servlet path that returns the JSON those will act the option values for this combobox. In my case it's value is /bin/target-list.1.html. & it returns a JSON as shown below

{"1":[{"text":"English","value":"ENG"},{"text":"French","value":"FRA"}]}

optionsRoot - This property defines what property of the given JSON act as the source of options for this combobox. As my JSON object contains an Array corresponding to a key "1", So your optionsRoot property values will be "1".
Note :  You may write your servlet that may return only array in that case, optionsRoot property is not required.
optionsTextField - This field represent that with key from the JSON object will be treated as a options text values i.e. the text that will be displayed in the combobox.

optionsValueField - This field represent that which key from the JSON object will be treated as the value of that option i.e. on selecting a value from combobox what will be returned to server.

Now this array have multiple JSON objects having two keys with corresponding values. these keys are
"text" & "value".

In my case I want to show "text" as option text value, i.e. it will be visible to author &
"value" is for returning a value to the server when a user select a text value from combobox.

i.e. if user select "English" then "ENG" will be returned to the server for further processing.

for doing this my

optionsTextField property value will be "text" &
optionsValueField property value will be "value"

Note : optionsTextField & optionsValueField are required only when your keys names are different from  "text" & "value". if these are "text" & "value" then no need to declare these properties. It will pick "text" key as a optionsTextField and "value" as a optionsValueField.

using above properties your combobox will work successfully.

Tuesday, 3 June 2014

Adobe CQ5 Integration With Apache CXF

During project development, I got a task in which I have to integrate CQ 5.6.1 with Apache CXF. In this post I'll discuss first approach for this integration. 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."

Platform used
  1. JDK 1.6 or higher version.
  2. Maven 3.0.4.
  3. Adobe CQ 5.6.
Goals of this Post

  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.
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, wsdl url is -
 http://www.webservicex.net/ConvertTemperature.asmx

 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 copy & paste these dependencies in to your projects parent pom.xml file.

<!-- Apache CXF Dependencies -->
            <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>

In parent pom.xml file and search for maven-bundle-plugin & replace this plugin definition with given configuration

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


Copy & paste the given dependencies into your bundle pom.xml file.

<!-- Apache CXF Dependencies -->
            <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 that plugin 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 -
  1. <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.
  2. <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 from 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.

package com.ig.integration.impl;

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

make sure your CQ instance is up and running.