Wednesday, 20 February 2013

Creating Custom Namespaces


Adobe CQ uses namespaces to maintain modularity between the properties and also tags.  namespaces help in distinguishing different modules of the project. We create thousand of properties in our project and many times it consists of just words. Hence to make the properties names meaningful we can add a namespace to project related namespaces.
Note that the namespace is unique to your project and doesn’t conflict with existing namespaces.
Steps for creating Custom Namespace:
Step 1: Log into CRX and follow this path:http://servername:port/crx/explorer/nodetypes/index.jsp  or click on Node Administration link from the CRX Console.
Step 2:  You will be navigated to the below screen. On the left panel, all the node types will be displayed. Click on the Namespaces link on the right as displayed below:
  
Click on namespaces





 Step 3: Below screen will appear and click on New button and enter the namespace URI and prefix . The namespace provided below is just an example.
enter new





 Step 4: The namespace will be created and it can now be used in your project.
Namespace created





 Let me know if any questions.
Hope this helps. Thanks!

Custom Tag Libs for Adobe CQ


Follow the below steps for creating custom Tab libraries:
Step 1: Write a java Class with the method  you want as a tag lib.
I’m providing an example java class here:
/**
*
*/
package com.company.cq.taglibs;
import javax.servlet.jsp.JspException;
import javax.servlet.jsp.JspWriter;
import javax.servlet.jsp.tagext.DynamicAttributes;
import javax.servlet.jsp.tagext.TagSupport;
/**
* @author apelluru
*
*/
public class ReusableTagLibs extends TagSupport implements DynamicAttributes {
@Override
public int doStartTag() throws JspException {
try {
JspWriter out = pageContext.getOut();
out.print(getLabel(“”,”"));
}catch (Exception e) {
// TODO: handle exception
}
return SKIP_BODY;
}
private String getLabel(String prop, String value) {
return “hello”;
}
public void setDynamicAttribute(String uri, String localName, Object value) {
}
}
Step 2: Write a tld file for your tab library
The path of the tld file may be in  resource/META-INF folder of your src folder. If META-INF folder is not present then create it.
The tld file will look like this:
<?xml version=”1.0″ encoding=”UTF-8″?>
<taglib>
<tlibversion>1.0</tlibversion>
<jspversion>1.1</jspversion>
<shortname>locale</shortname>
<info>Taglib for CQ localization</info>
<tag>
<name>label</name>
<tagclass>com.company.cq.taglibs.ReusableTagLibs</tagclass>
<info>Localization function</info>
<attribute>
<name>property</name>
<required>true</required>
<rtexprvalue>true</rtexprvalue>
<dynamic-attributes>true</dynamic-attributes>
</attribute>
<attribute>
<name>context</name>
<required>true</required>
<rtexprvalue>true</rtexprvalue>
<dynamic-attributes>true</dynamic-attributes>
</attribute>
<attribute>
<name>encoding</name>
<required>false</required>
</attribute>
<dynamic-attributes>true</dynamic-attributes>
</tag>
</taglib>
Step 3: Build the bundle.
Step 4: Include the tag library in your jsp
<%@taglib prefix=”reusable” uri=”/apps/reusablecomponents/dm/src/impl/src/main/resources/META-INF/reusable.tld” %>
Use the tag in your JSP like this:    <reusable:label  property=”hello” context=”<%= pageContext %>”/>

CQ 5.5 upgrade from 5.4 learnings


Here are few learning that I got when we upgraded CQ 5.4 to CQ 5.5:
1. DO NOT customize the out of the box libraries until unless it’s really required. Customizing the OOTB functionality will be problematic when new version of the product add more features on the libraries you’ve overridden.
2. Analytics integration with CQ 5.5 has been made very simple and all the configuration are provided on the CQ side. We used analytics integration in CQ 5.4 hence we re-integrated by modifying the settings.
3. If you have overridden init.jsp(CQ 5.4) in your project then UNDO/REDO won’t work. This is because a new service class has been introduced which handles the undo/redo request and initialized in init.jsp. Hence you need to merge the init.jsp (CQ 5.4) to init.jsp (CQ 5.5).
4. Few API changes has been made. Please checkhttp://dev.day.com/docs/en/cq/current/diff_5-4_5-5/changes.h… for more information. If a class you’ve used in 5.4 doesn’t work, search for alternate class. (Examples: AnalyticsHelper.java has been removed, wrote my own method to get the analytics resource).
5. Maintain at least one instance of CQ 5.4 running as a backup. It will also help in comparing between 5.5 & 5.4.
6. Dropdown/Tag fields in dialogs shrink after upgrade. I fixed it by adding a width property to the fields.
7. If you’ve customized OOTB functionality then you may see many Internal Server Errors. This is due to the Resource Not found Exception since class/configuration in 5.5 has been modified/removed.
8. Delete your workflow instances and temporary data (unused package, tmp files) from CRX before the upgrade. This will help in faster upgrade.
9. Continuous log monitoring will help in finding the issues which doesn’t appear on the UI.
10. Most importantly if New Page options or Page Properties are disabled completely then it may be due to missing “jcr:content” node on the page. Also this may cause due to permissions.
11. LDAP permission were getting wiped out with every deployment of our project package. Adobe has provided a fix for it.
12. Install CQ 5.5.1, it fixes may of the internal issues.
13. Old Scr annotations (E.g., scr.reference) has been deprecated and hence you need to use new scr annotations (@Reference()). Bundles won’t build with the old annotations.
Note: Though our upgrade instance was running fine in Pre-PROD environments, we had a meeting with Adobe, they have validated all the configuration settings, logs and showed a green flag.

Tuesday, 19 February 2013

Create custom xtype multi textfield, pathfield, new window options


CQ.form.CustomMultiField = CQ.Ext.extend(CQ.form.CompositeField, {

hiddenField: null,

linkText: null,

linkURL: null,

openInNewWindow: null,

constructor: function (config) {

config = config || {};

var defaults = {
    "border": true,
    "labelWidth": 75,
    "layout": "form"
    };  
config = CQ.Util.applyDefaults(config, defaults);
CQ.form.CustomMultiField.superclass.constructor.call(this, config);
},

initComponent: function () {
 
    CQ.form.CustomMultiField.superclass.initComponent.call(this);
 
    // Hidden field
    this.hiddenField = new CQ.Ext.form.Hidden({
         name: this.name
    });
    this.add(this.hiddenField);
 
    this.linkText = new CQ.Ext.form.TextField({
        cls: "customwidget-1",
        maxLength: 100,
        emptyText: "Enter Title",
        maxLengthText: "A maximum of 100 characters is allowed for the Link Text.",
        width: 335,
        allowBlank: true,
        name : "item",
        listeners: {
        change: {
        scope: this,
        fn: this.updateHidden
    }
    }
    });  
    this.add(this.linkText);
 
    this.linkURL = new CQ.form.PathField({
        cls: "customwidget-2",
        allowBlank: true,
        emptyText: "Enter Title URL",
        width: 335,
        listeners: {
         change: {
            scope: this,
            fn: this.updateHidden
        },      
        dialogclose: {
            scope: this,
            fn: this.updateHidden
        }
       }
    });
    this.add(this.linkURL);
 
    // Link openInNewWindow
    this.openInNewWindow = new CQ.Ext.form.Checkbox({
        cls: "customwidget-3",
        boxLabel: "New window",
        listeners: {
        change: {
        scope: this,
        fn: this.updateHidden
        },
        check: {
        scope: this,
        fn: this.updateHidden
    }
    }
    });
    this.add(this.openInNewWindow);
 
},

processInit: function (path, record) {  
    this.linkText.processInit(path, record);
    this.linkURL.processInit(path, record);
    this.openInNewWindow.processInit(path, record);
},

setValue: function (value) {
    var link = JSON.parse(value);
    this.linkText.setValue(link.text);
    this.linkURL.setValue(link.url);
    this.openInNewWindow.setValue(link.openInNewWindow);
},
getValue: function () {
return this.getRawValue();
},

getRawValue: function () {  
    var link = {
    "url": this.linkURL.getValue(),
    "text": this.linkText.getValue(),
    "openInNewWindow": this.openInNewWindow.getValue()
    };  
    return JSON.stringify(link);
},
updateHidden: function () {
this.hiddenField.setValue(this.getValue());
}
});

CQ.Ext.reg("CustomMultiField", CQ.form.CustomMultiField);



Then Dialog



<?xml version="1.0" encoding="UTF-8"?>
<jcr:root xmlns:cq="http://www.day.com/jcr/cq/1.0" xmlns:jcr="http://www.jcp.org/jcr/1.0"
    jcr:primaryType="cq:Dialog"
    width="550"
    xtype="dialog">
    <items
        jcr:primaryType="cq:Widget"
        xtype="tabpanel">
        <items jcr:primaryType="cq:WidgetCollection">
            <tab1
                jcr:primaryType="cq:Panel"
                title="Links Component">
                <items jcr:primaryType="cq:WidgetCollection">
                    <links
                        jcr:primaryType="cq:Widget"
                        border="false"
                        fieldDescription="Press + to add more links"
                        fieldLabel="Links"
                        hideLabel="true"
                        name="./links"
                        xtype="multifield">
                        <fieldConfig
                            jcr:primaryType="cq:Widget"
                            xtype="CustomMultiField"/>
                    </links>
                </items>
            </tab1>
        </items>
    </items>
</jcr:root>