Cq5 Guide Developer
Cq5 Guide Developer
Cq5 Guide Developer
Contents
1. Introduction ........................................................................................................................ 1 1.1. Introduction ............................................................................................................. 1 1.2. Purpose of this Document ........................................................................................ 1 1.3. Target Audience ...................................................................................................... 1 1.4. Prerequisites for development within CQ .................................................................. 1 2. CQ in-depth ....................................................................................................................... 2 2.1. JSR-170 and the JCR API ....................................................................................... 2 2.2. CQ DAM ................................................................................................................. 2 2.3. Widgets .................................................................................................................. 2 2.4. FileVault (source revision system) ............................................................................ 2 2.5. Workflow Engine ..................................................................................................... 2 2.6. Dispatcher ............................................................................................................... 2 2.7. Localization ............................................................................................................. 2 2.8. Sling Request Processing ........................................................................................ 3 2.8.1. Introduction to Sling ...................................................................................... 3 2.8.2. Sling is Content Centric ................................................................................ 3 2.8.3. RESTful Sling ............................................................................................... 3 2.8.4. URL Decomposition ...................................................................................... 3 2.8.5. From URL to Content and Scripts .................................................................. 4 2.8.6. Sling API ...................................................................................................... 8 2.8.7. Referencing existing elements using sling:include ........................................... 8 2.8.8. First Steps - an example for using Sling ......................................................... 8 2.9. OSGI ...................................................................................................................... 8 3. CQ5 WCM - Architecture and Concepts ............................................................................ 10 3.1. Development objects ............................................................................................. 10 3.2. Structure within the repository ................................................................................ 11 4. Development Tools ........................................................................................................... 12 4.1. Working with the CQ Development Environment (CQDE) ......................................... 12 4.1.1. Setting up CQDE ........................................................................................ 12 4.1.2. Configuring CQDE ...................................................................................... 12 4.2. How to Set Up the Development Environment with Eclipse ....................................... 12 4.2.1. Creating the Project Structure in CQ5 .......................................................... 13 4.2.2. Installing FileVault (VLT) ............................................................................. 13 4.2.3. Installing Eclipse ......................................................................................... 14 4.2.4. Creating the Project Structure in Eclipse ...................................................... 14 4.2.5. Scripting with Eclipse and CQ5 .................................................................... 19 4.2.6. Java Developing with Eclipse and CQ5 ........................................................ 20 4.2.7. Building collaborative and automated projects ............................................... 22 5. Designer .......................................................................................................................... 24 6. Templates ........................................................................................................................ 25 6.1. What are Templates? ............................................................................................ 25 6.2. Overview of templates ........................................................................................... 25 6.3. How Templates are structured ................................................................................ 25 6.3.1. The structure of a Template ........................................................................ 25 6.3.2. The content produced by a Template ........................................................... 27 6.4. Developing Page Templates ................................................................................... 28 6.4.1. Creating a new Template (based on an existing template) ............................. 28 6.5. Summary .............................................................................................................. 29 7. Components ..................................................................................................................... 30 7.1. What exactly is a Component? ............................................................................... 30 7.2. Default Components within CQ WCM ..................................................................... 30 7.3. Components and their structure .............................................................................. 31 7.3.1. Component definitions ................................................................................. 31 7.3.2. Component definitions and the content they create ....................................... 33 7.3.3. Component Hierarchy and Inheritance .......................................................... 35
7.3.4. Summary .................................................................................................... 35 7.4. Developing Components ........................................................................................ 36 7.4.1. Developing a new component by adapting an existing component .................. 36 7.4.2. Adding a new component to the paragraph system (design mode) .................. 37 7.4.3. Extending the Text and Image Component - An Example .............................. 38 7.5. Further Development of Specific Components and Tools .......................................... 44 7.5.1. Developing the Bulk Editor .......................................................................... 44 7.6. Scripts .................................................................................................................. 52 7.6.1. global.jsp .................................................................................................... 52 7.6.2. JSP Tag Libraries ....................................................................................... 53 7.7. A closer look at a few of the foundation components... ............................................. 60 7.7.1. Top Navigation Component ......................................................................... 60 7.7.2. List Children Component ............................................................................. 62 7.7.3. Logo Component ........................................................................................ 63 7.7.4. Paragraph System ...................................................................................... 64 7.7.5. Image Component ...................................................................................... 64 7.7.6. Text & Image Component ........................................................................... 66 7.7.7. Search Component ..................................................................................... 67 8. Guidelines for Using Templates and Components .............................................................. 68 9. Java WCM API ................................................................................................................ 69 10. Multi Site Manager for Developers ................................................................................... 70 10.1. MSM in the Repository ........................................................................................ 70 10.1.1. MSM-specific Nodes, Node Types, and Properties ...................................... 70 10.1.2. MSM mechanisms in the repository ............................................................ 73 10.2. Extending MSM Functionalities ............................................................................. 74 10.2.1. How to extend synchronization actions ....................................................... 74 10.2.2. How to define the properties and the nodes that are copied to the Live Copy .................................................................................................................... 83 10.2.3. How to remove the "Chapters" step in the "Create Site" wizard ..................... 84 11. How to Create a Fully Featured Internet Website ............................................................. 85 12. DAM Media Handlers ..................................................................................................... 86 12.1. Default Media Handlers ........................................................................................ 86 12.2. Using Media Handlers in Workflows to perform tasks on Assets .............................. 87 12.3. Disabling/Enabling a Media Handler ...................................................................... 90 12.4. Creating a new Media Handler ............................................................................. 91 12.4.1. Important Classes and Interfaces ............................................................... 91 12.4.2. Example: create a specific Text Handler ..................................................... 91 13. Data Modelling ............................................................................................................... 98 13.1. Data Modeling - David Nuescheler's Model ........................................................... 98 13.1.1. Source ...................................................................................................... 98 13.1.2. Introduction from David ............................................................................. 98 13.1.3. Seven Simple Rules .................................................................................. 98 A. Keyboard Shortcuts ........................................................................................................ 104 B. Security Checklist ........................................................................................................... 105 B.1. Use the user session, not the administrative session ............................................. 105 B.2. Check for Cross-Site Scripting (XSS) .................................................................... 105 C. Copyright, Licenses and Formatting Conventions ............................................................. 106 C.1. Formatting Conventions ....................................................................................... 106
Page iv of 106
1 Introduction
1.1 Introduction
Day's CQ5 platform allows you to build compelling content-centric applications that combine Web Content Management, Workflow Management, Digital Asset Management and Social Collaboration. The product has been completely redesigned from Communiqu 4, allowing Day to use new architecture and technologies, thus increasing functionality while reducing complexity. Extensive use of standards helps ensure long-term stability.
Page 1 of 106
2 CQ in-depth
2.1 JSR-170 and the JCR API
JSR 170 is the Java Specification Request for the Content Repository for JavaTM technology API. Specification lead is held by Day Software AG. The JCR API package, javax.jcr.* is used for the direct access and manipulation of repository content. CRX is Day's proprietary implementation of the JCR. Apache Jackrabbit is an open source, fully conforming, implementation of this API.
2.2 CQ DAM
CQ DAM (Communiqu Digital Asset Management) is used to centrally manage all digital media files and essential metadata information.
2.3 Widgets
CQ WCM has been developed using the ExtJS library of widgets.
2.6 Dispatcher
The Dispatcher is Day's tool for both caching and/or load balancing. Further information can be found under Tools - the Dispatcher.
2.7 Localization
Localization is at the core of CQ5. It provides support for adapting applications, created using the CQ5 platform, into different languages and regional configurations . While processing the request, the Locale is extracted. This is then used to reference a language code, and optionally a country code, which can be used for controlling either the specific content or format of certain output. Localization will be used throughout CQ5 - wherever reasonable. One notable exception is the system log information of CQ5 itself, this is never localized and always in English.
Page 2 of 106
CQ in-depth
Page 3 of 106
CQ in-depth
protocol HTTP. host Name of the website. content path Path specifying the content to be rendered. Is used in combination with the extension; in this example they translate to tools/spy.html. selector(s) Used for alternative methods of rendering the content; in this example a printer-friendly version in A4 format. extension Content format; also specifies the script to be used for rendering. suffix Can be used to specify additional information. param(s) Any parameters required for dynamic content.
Therefore:
CQ 5.2 WCM Copyright 1993-2009 Day Management AG
Page 4 of 106
CQ in-depth
DO NOT specify which data entities to access in your scripts (as an SQL statement in a PHP script would do) DO specify which script renders a certain entity (by setting the sling:resourceType property in the JCR node)
CQ in-depth
Additionally, Apache Sling supports integration with other popular scripting engines (e.g., Groovy, JRuby, Freemarker), and provides a way of integrating new scripting engines. Using the above example, if the sling:resourceType is hr/jobs then for: GET/HEAD requests, and URLs ending in .html (default request types, default format) The script will be /apps/hr/jobs/jobs.esp; the last section of the sling:resourceType forms the file name. POST requests (all request types excluding GET/HEAD, the method name must be uppercase) POST will be used in the script name. The script will be /apps/hr/jobs/POST.esp. URLs in other formats, not ending with .html For example ../content/corporate/jobs/developer.pdf The script will be /apps/hr/jobs/jobs.pdf.esp; the suffix is added to the script name. URLs with selectors Selectors can be used to display the same content in an alternative format. For example a printer friendly version, an rss feed or a summary. If we look at a printer friendly version where the selector could be print; as in ../content/ corporate/jobs/developer.print.html The script will be /apps/hr/jobs/jobs.print.esp; the selector is added to the script name. If no sling:resourceType has been defined then: the content path will be used to search for an appropriate script (if the path based ResourceTypeProvider is active). For example, the script for ../content/corporate/jobs/developer.html would generate a search in /apps/content/corporate/jobs/. the primary node type will be used. If no script is found at all then the default script will be used. The default rendition is currently supported as plain text (.txt), HTML (.html) and JSON (.json), all of which will list the node's properties (suitably formatted). The default rendition for the extension .res, or requests without a request extension, is to spool the resource (where possible). For http error handling (codes 404 or 500) Sling will look for a script at /libs/sling/ servlet/errorhandler/404.esp, or 500.esp, respectively. If multiple scripts apply for a given request, the script with the best match is selected. The more specific a match is, the better it is; in other words, the more selector matches the better, regardless of any request extension or method name match. For example, consider a request to access the resource /content/corporate/jobs/ developer.print.a4.html of type sling:resourceType="hr/jobs". Assuming we have the following list of scripts in the correct location: 1. jobs.esp 2. jobs.GET.esp
CQ 5.2 WCM Copyright 1993-2009 Day Management AG
Page 6 of 106
CQ in-depth
3. jobs.GET.html.esp 4. jobs.html.esp 5. jobs.print.esp 6. jobs.print.a4.esp 7. jobs.print.html.esp 8. jobs.print.GET.html.esp 9. jobs.print.a4.html.esp 10.jobs.print.a4.GET.html.esp Then the order of preference would be (10) - (9) - (6) - (8) - (7) - (5) - (3) - (4) - (2) - (1). Note (6) is a better match than (8), because it matches more selectors even though (8) has a method name and extension match where (6) does not. In addition to the resource types (primarily defined by the sling:resourceType property) there is also the resource super type. This is generally indicated by the sling:resourceSuperType property. These super types are also considered when trying to find a script. The advantage of resource super types is that they may form a hierarchy of resources where the default resource type sling/servlet/default (used by the default servlets) is effectively the root. The resource super type of a resource may be defined in two ways: 1. by the sling:resourceSuperType property of the resource. 2. by the sling:resourceSuperType property of the node to which the sling:resourceType points. For example: / a b sling:resourceSuperType = a c sling:resourceSuperType = b x sling:resourceType = c y sling:resourceType = c sling:resourceSuperType = a The type hierarchy of /x is [ c, b, a, <default> ] while for /y the hierarchy is [ c, a, <default> ] because /y has the slingresourceSuperType property whereas /x does not and therefore its supertype is taken from its resource type.
Page 7 of 106
CQ in-depth
2.9 OSGI
OSGi defines an architecture for developing and deploying modular applications and libraries (it is also known as the Dynamic Module System for Java). OSGi containers allow you to break your application into individual modules (are jar files with additional meta information and called bundles in OSGi terminology) and manage the cross-dependencies between them with: services implemented within the container a contract between the container and your application These services and contracts provide an architecture which enables individual elements to dynamically discover each other for collaboration. An OSGi framework then offers you dynamic loading/unloading, configuration and control of these bundles - without requiring restarts. Note Full information on OSGi technology can be found at the OSGi Alliance Technology Overview.
CQ 5.2 WCM Copyright 1993-2009 Day Management AG
Page 8 of 106
CQ in-depth
In particular, their Basic Education page holds a collection of presentations and tutorials. This architecture allows you to extend Sling with application specific modules. Sling, and therefore CQ5, uses the Apache Felix implementation of OSGI (Open Services Gateway initiative). They are both collections of OSGi bundles running within an OSGi framework. This enables you to perform the following actions on any of the packages within your installation: install start stop update uninstall see the current status access more detailed information (e.g. symbolic name, version, location, etc) about the specific bundles
Page 9 of 106
Page 10 of 106
A template is a hierarchy of nodes that has the same structure as the page to be created, but without any actual content. It defines the page component used to render the page and the default content (primary toplevel content). The content defines how it is rendered as CQ is content-centric. Page Component (Top-Level Component) The component to be used to render the page. Page A page is an 'instance' of a template. A page has a hierarchy node of type cq:Page and a content node of type cq:PageContent. The property sling:resourceType of the content node points to the Page Component used for rendering the page.
Page 11 of 106
4 Development Tools
4.1 Working with the CQ Development Environment (CQDE)
The CQ5 IDE (CQDE) provides a development platform for CQ5 applications. It is custom-built specifically for CQ and therefore recommended by Day. CQDE is built on Eclipse RCP and EFS and comes as a set of Eclipse plugins.
Page 12 of 106
Development Tools
The setup described here is an alternative among others and may vary from project to project. The local development environment involves: A CQ5 installation that will act as your local environment. CRX Explorer within the CQ5 instance to create and edit nodes and properties within the CRX repository. FileVault (VLT), a Day developed utility that maps the CRX repository to your file system. Eclipse to edit the project source on your local file system. Apache Maven to run local snapshot builds.
In your browser, navigate to the Tools tab. Under designs, create the design page of your application: Title: My Application Design Page. Name: myApp. Template: Design Page Template.
Page 13 of 106
Development Tools
4.
Open a command line shell and execute vlt --help. Make sure it displays the following help screen:
b. 4. 5.
Create a new workspace for your project and name it myApp. Install the Maven plugin (m2) from Sonatype. Disable Maven SCM handler for Subclipse (Optional) and Maven Integration for AJDT (Optional). After installation it is recommended to restart Eclipse.
6.
Page 14 of 106
Development Tools
the other called Core which contains the Java code (source and compiled). The compiled code is stored in a jar file. The advantage of such a structure is that it adds modularity and autonomy to the logic of your application because each jar file (bundle) can be managed separately.
4.
Set the Java Compiler to version 1.5: 1. 2. Right-click the ui project, select Properties. Select Java Compiler and set following properties to 1.5: Compiler compliance level Generated .class files compatibility Source compatibility 3. 4. Click OK. In the dialog window, click Yes.
4.
Create the filter.xml file which defines the content that will be exported by VLT: 1. 2. 3. 4. 5. In Eclipse, navigate to ui/scr/main and create the content folder. Under content, create the META-INF folder. Under META-INF, create the vault folder. Under vault, create the filter.xml file. In filter.xml, copy the following code to filter.xml:
<?xml version="1.0" encoding="UTF-8"?>
Page 15 of 106 CQ 5.2 WCM Copyright 1993-2009 Day Management AG
Development Tools
<!-Defines which repository items are generally included --> <workspaceFilter vesion="1.0"> <filter root="/apps/myApp" /> <filter root="/etc/designs/myApp" /> </workspaceFilter>
6. 5.
Check out the CQ5 content into your ui project with VLT: 1. 2. From the system command line, navigate to the directory holding your Eclipse workspace <eclipse>/<workspace>/myApp/ui/src/main/content. Execute the command: vlt --credentials admin:admin co http://localhost:4502/crx This command creates the folder jcr_root under <eclipse>/<workspace>/ myApp/ui/src/main/content. This maps to the CRX root (/). Under jcr_root the following files and folders are created, as defined in filter.xml: apps/myApp etc/designs/myApp It also creates two files, config.xml and settings.xml in <eclipse>/ <workspace>/myApp/ui/src/main/content/META-INF/vault. These are used by VLT.
6.
To enable Eclipse to map the file paths used in the JSP scripts, create a link to the apps folder under ui: 1. 2. 3. 4. 5. Right-click ui, select New, then Folder. In the dialog window, click Advanced and check the Link to folder in the file system box. Click Browse, then specify <eclipse>/<workspace>/myApp/ui/src/main/ content/jcr_root/apps. Click OK. Click Finish.
7.
To enable Eclipse to identify the Java classes, methods and objects used in the JSP scripts, export the needed Java libraries from the CQ5 server to your file system and reference them in the ui project. In this example, you will reference the following libraries: libs/cq/install stored in the CQ5 server libs/sling/install stored in the CQ5 server libs/wcm/install stored in the CQ5 server <cq-installation-dir>/crx-quickstart/server/lib/container stored in your file system Proceed as follows: 1. In your file system, create a CQ5 libraries folder called cq5libs. This folder can be created anywhere.
Page 16 of 106
Development Tools
2. 3.
Under cq5libs, create the folders: cq, sling and wcm. From the system command line go to .../cq5libs/cq and execute vlt co http:// localhost:4502/crx /libs/cq/install . to export the libraries stored under /libs/cq/ install from the CQ5 server. From the system command line go to .../cq5libs/sling and execute vlt co http:// localhost:4502/crx /libs/sling/install . to export the libraries stored under /libs/ sling/install from the CQ5 server. From the system command line go to .../cq5libs/wcm and execute vlt co http:// localhost:4502/crx /libs/wcm/install . to export the libraries stored under /libs/wcm/ install from the CQ5 server. In Eclipse, right-click the ui project, select Build Path, then Configure Build Path. In the dialog select the Libraries tab. Click Add External JARS..., navigate to .../cq5libs/cq/jcr_root, select all the jar files and click Open. Click Add External JARS..., navigate to .../cq5libs/sling/jcr_root, select all the jar files and click Open. Click Add External JARS..., navigate to .../cq5libs/wcm/jcr_root, select all the jar files and click Open.
4.
5.
6.
7.
8.
9.
10. Click Add External JARS..., navigate to <cq-installation-dir>/crxquickstart/server/lib/container, select all the jar files and click Open. 11. Click OK.
4.
Add the necessary plugins and dependencies to the core project: 1. 2. Open the pom.xml file under core. Copy-paste following code before the </project> tag:
CQ 5.2 WCM Copyright 1993-2009 Day Management AG
Page 17 of 106
Development Tools
<packaging>bundle</packaging> <build> <plugins> <plugin> <groupId>org.apache.maven.plugins</groupId> <artifactId>maven-compiler-plugin</artifactId> <configuration> <source>1.5</source> <target>1.5</target> </configuration> </plugin> <plugin> <groupId>org.apache.felix</groupId> <artifactId>maven-bundle-plugin</artifactId> <version>1.4.3</version> <extensions>true</extensions> <configuration> <instructions> <Export-Package> com.day.cq5.myapp.*;version= ${pom.version} </Export-Package> </instructions> </configuration> </plugin> </plugins> </build> <dependencies> <dependency> <groupId>com.day.cq.wcm</groupId> <artifactId>cq-wcm-api</artifactId> <version>5.1.20</version> </dependency> <dependency> <groupId>com.day.cq</groupId> <artifactId>cq-commons</artifactId> <version>5.1.18</version> </dependency> <dependency> <groupId>org.apache.sling</groupId> <artifactId>org.apache.sling.api</artifactId> <version>2.0.3-incubator-R708951</version> </dependency> </dependencies>
3. 3.
Deploy the CQ5 specific artifacts as defined in the pom.xml (cq-wcm-api, cq-commons and org.apache.sling.api) to the local Maven repository: 1. From the system command line go to <your-user-dir>/.m2/repository/com/ day/cq/wcm/cq-wcm-api/5.1.20 (create the folders if they don't exist) and execute vlt co http://localhost:4502/crx /libs/wcm/install/cq-wcm-api-5.1.20.jar . to export the library from the CQ5 server. From the system command line go to <your-user-dir>/.m2/repository/com/ day/cq/cq-commons/5.1.18 (create the folders if they don't exist) and execute vlt co http://localhost:4502/crx /libs/cq/install/cq-commons-5.1.18.jar . to export the library from the CQ5 server.
2.
Page 18 of 106
Development Tools
3.
From the system command line go to <your-user-dir>/.m2/repository/org/ apache/sling/org.apache.sling.api/2.0.3-incubator-R708951 (create the folders if they don't exist) and execute vlt co http://localhost:4502/crx /libs/sling/ install/org.apache.sling.api-2.0.3-incubator-R708951.jar . to export the library from the CQ5 server. Note You don't need to perform this step if the three CQ5 artifacts are globally deployed for the project on a Maven repository (e.g. using Apache Archiva).
4.
Set the Java Compiler to version 1.5: 1. 2. Right-click the core project, select Properties. Select Java Compiler and set following properties to 1.5: Compiler compliance level Generated .class files compatibility Source compatibility 3. 4. Click OK. In the dialog window, click Yes.
5.
Create the package com.day.cq5.myapp that will contain the Java classes under core/ src/main/java: 1. 2. Under core, right-click src/main/java, select New, then Package. Name it com.day.cq5.myapp and click Finish.
2.
3.
4.
Page 19 of 106
Development Tools
5.
Under the jcr:content Node, add a new Property: Name: personName Value: myName
2.
Create a new component with the CRX Explorer: In the CRX Explorer, under /apps/myApp/components, create a new component: Name: contentpage Type: cq:Component
3.
Use VLT to update the changes made from your repository to your file system, and therefore Eclipse: 1. From the system command line navigate to <eclipse>/<workspace>/myApp/ui/ src/main/content/jcr_root. Execute: vlt st --show-update to see the changes made on the repository. Execute: vlt up to update the changes from the repository to your file system.
2. 3. 4.
Create the component script (JSP) with Eclipse: 1. In Eclipse, navigate to ui/src/main/content/jcr_root/apps/myApp/ components/contentpage. Right-click contentpage, select New, then File. In the dialog, name the file contentpage.jsp and click Finish. Copy the following code into contentpage.jsp:
This is the contentpage component.
2. 3. 4.
5. 5.
With VLT check in the changes from the file system into the repository: 1. From the system command line navigate to <eclipse>/<workspace>/myApp/ui/ src/main/content/jcr_root. Execute: vlt st to see the changes made on the file system. Execute: vlt add apps/myApp/components/contentpage/contentpage.jsp to add the contentpage.jsp file to VLT control. Execute: vlt ci to commit the contentpage.jsp file to the repository.
2. 3.
4. 6.
From CQ5 create a page based on this template. Open the page to make sure it displays the following message:
This is the contentpage component.
Tip It is possible to define the VLT commands as External Tools in Eclipse. This enables you to run the VLT commands from within Eclipse.
Page 20 of 106
Development Tools
Compile the Java class. Reference the jar file in the ui library. Embed the Java Class logic into the JSP script. Use VLT to check these changes to the JSP script (in the file system) into the repository. Use VLT to deploy the jar file (with the compiled class) from the file system into the repository. The following example illustrates this process: 1. Create the Java class: 1. 2. 3. In Eclipse, under core/src/main/java, right-click the com.day.cq5.myapp package, select New, then Class. In the dialog window, name the Java Class HelloPerson and click Finish. Eclipse creates and opens the file HelloPerson.java. In HelloPerson.java replace the existing code with the following:
package com.day.cq5.myapp; import com.day.cq.wcm.api.Page; public class HelloPerson { private Page personPage; public static final String PN_PERSON_NAME = "personName"; public HelloPerson(Page personPage) { this.personPage = personPage; } public String getHelloMessage() { String personName = personPage.getProperties().get(PN_PERSON_NAME).toString(); return personName != null ? personName : "--empty--"; } }
4. 2.
Compile the Java class: 1. 2. Right-click the core project, select Run As, then Maven Install. Make sure that a new file core-0.0.1-SNAPSHOT.jar (containing the compiled class) is created under core/target.
3.
Reference this jar file in the ui library to enable the code completion when accessing this class with the JSP script: 1. 2. 3. In Eclipse, right-click the ui project, select Build Path, then Configure Build Path. In the dialog select the Libraries tab. Click Add JARS... and navigate to core/target, select the core-0.0.1SNAPSHOT.jar file and click OK. Click OK to close the dialog.
4.
Page 21 of 106
Development Tools
1.
In Eclipse, open the JSP script contentpage.jsp in ui/src/main/content/ jcr_root/apps/myApp/components/contentpage. Replace the existing code with the following:
<%@ page import="com.day.cq5.myapp.HelloPerson" %> <%@include file="/libs/wcm/global.jsp"%> <% HelloPerson hello = new HelloPerson(currentPage); String msg = hello.getHelloMessage(); %> Hello, <%= msg %>.</br></br> This is the contenpage component.
2.
3. 5.
With VTL check in the changes to the JSP script from the file system to the repository: 1. From the system command line navigate to <eclipse>/<workspace>/myApp/ui/ src/main/content/jcr_root. Execute: vlt st to see the changes made on the file system. Execute: vlt ci to commit the modified contentpage.jsp file to the repository.
2. 3. 6.
Deploy the jar file containing the compiled class from the file system into the repository with VLT: 1. 2. In Eclipse, under core/target, copy the core-0.0.1-SNAPSHOT.jar file. In Eclipse navigate to ui/scr/main/content/jcr_root/apps/myapp/install and paste the copied file. From the system command line navigate to <eclipse>/<workspace>/myApp/ui/ src/main/content/jcr_root. Execute: vlt st to see the changes made on the file system. Execute: vlt add apps/myApp/install/core-0.0.1-SNAPSHOT.jar to add the jar file to VLT control. Execute: vlt ci to commit the jar file to the repository.
3.
4. 5.
6. 7.
In your browser, refresh the CQ5 page to make sure it displays following message:
Hello, myName. This is the contentpage component.
8.
In CRX Explorer, change the value myName and make sure that the new value is displayed when you refresh the page.
Development Tools
Page 23 of 106
5 Designer
You will need a design to define for your website. Your design can be defined in the designs section of the Tools tab:
Here you can create the structure required to store the design and upload the cascaded style sheets and images required. Designs are stored under /etc/designs. The path to the design to be used for a website is specified using the cq:designPath property of the jcr:content node.
Page 24 of 106
6 Templates
6.1 What are Templates?
A Template is used to create a Page and defines which components can be used within the selected scope. A template is a hierarchy of nodes that has the same structure as the page to be created, but without any actual content. Each Template will present you with a selection of components available for use. Templates are built up of Components; Components use, and allow access to, Widgets and these are used to render the Content.
geometrixx The Geometrixx home page template. geometrixx The Geometrixx content page template. libs Redirect. Component and Template.
Page 25 of 106
Templates
Various properties can be set, in particular: jcr:title - title for the template; appears in the dialog when creating a page. jcr:description - description for the template; appears in the dialog when creating a page. This node contains a jcr:content (cq:PageContent) node which be used as the basis for the content node of resulting pages; this references, using sling:resourceType, the component to be used for rendering the actual content of a new page.
This component is used to define the structure and design of the content when a new page is created.
CQ 5.2 WCM Copyright 1993-2009 Day Management AG
Page 26 of 106
Templates
Page 27 of 106
Templates
3.
Page 28 of 106
Templates
Note Components are usually stored in /apps/<website-name>/components/ <component-name>. 4. 5. 6. 7. Update the jcr:title and jcr:description of the new component. Replace the thumbnail.png if you want a new thumbnail picture to be shown in the template selection list. Update the sling:resourceType of the template's jcr:content node to reference the new component. Make any further changes to the functionality or design of the template and/or its underlying component. Changes made to the /apps/<website>/templates/<template-name> node will affect the template instance (as in the selection list). Changes made to the /apps/<website>/components/<component-name> node will affect the content page created when the template is used. You can now create a page within your website using the new template.
6.5 Summary
Summary: Location: /apps/<myapp>/templates Root Node: <mytemplate> (cq:Template) - Hierarchy node of the template Vital Properties: jcr:title - Template title, appears in the Create Page Dialog jcr:description - Template description, appears in the Create Page Dialog Vital Child Nodes: jcr:content (cq:PageContent) - Content node for template instantiations Vital Properties of Child Node jcr:content: sling:resourceType - Reference to the rendering component The template is a blueprint of a specific type of page. To create a page the template must be copied (node-tree /apps/<myapp>/templates/<mytemplate>) to the corresponding position in the site-tree (this is what happens if a page is created using the siteadmin). This copy action also gives the page its initial content (usually Top-Level Content only) and the property sling:resourceType, the path to the page component that is used to render the page (everything in the child node jcr:content).
Page 29 of 106
7 Components
7.1 What exactly is a Component?
Components: are modular units which realize specific functionality to present your content on your website are re-usable are developed as self-contained units within one folder of the repository have no hidden configuration files can contain other components run anywhere within any CQ system have a standardized user interface use widgets As components are modular, you can develop a new component on your local instance, then deploy this seamlessly to your test, then live environments. Each CQ component: is a resource type is a collection of scripts that completely realize a specific function can function in "isolation"; this means either within CQ or a portal Components included with CQ include: paragraph system header image, with accompanying text toolbar Note The functionality provided by Components and Widgets was implemented by the cfc libraries in Communiqu 4.
Page 30 of 106
Components
/libs/foundation/components /apps/geometrixx/components /libs/collab/components /libs/collab/blog/components /libs/collab/calendar/components /libs/dam/components /libs/personalization/components /libs/replication/components /libs/search/components /libs/security/components /libs/tagging/components For detailed information on all the default components, including those that are not available out-ofthe-box in CQ WCM, see Chapter 4,
Page 31 of 106
Components
Properties of particular interest include: jcr:title - title of the component; for example, appears in the component list within sidekick jcr:description - description for the component; again appears in the component list within sidekick allowedChildren - components which are allowed as children allowedParents - components which can be specified as parents icon.png - graphics file to be used as an icon for the component thumbnail.png - graphics file to be used as a thumbnail for the component Child nodes of particular interest include: cq:editConfig (cq:EditConfig) - this controls visual aspects; for example, it can define the appearance of a bar or widget, or can add customized controls cq:childEditConfig(cq:EditConfig) - this controls the visual aspects for child components that do not have their own definitions dialog (nt:unstructured) - defines the dialog for editing content of this component design_dialog (nt:unstructured) - specifies the design editing options for this component
7.3.1.1 Dialogs
Dialogs are a key element of your component as they provide an interface for authors to configure and provide input to that component.
CQ 5.2 WCM Copyright 1993-2009 Day Management AG
Page 32 of 106
Components
Depending on the complexity of the component your dialog may need one or more tabs - to keep the dialog short and to sort the input fields. For example, you can create the dialog as cq:Dialog, which will provide a single tab - as in the text component, or if you need multiple tabs, as with the textimage component, the dialog can be defined as cq:TabPanel:
Within a dialog, a cq:WidgetCollection (items) is used to provide a base for either input fields (cq:Widget) or further tabs (cq:Widget). This hierarchy can be extended.
Page 33 of 106
Components
then we can see the structure of the content created within the repository:
Page 34 of 106
Components
the definition of /libs/foundation/components/text/dialog/items/title has the property name=./jcr:title within the content, this generates the property jcr:title holding the input Test Title. The properties defined are dependent on the individual definitions, which although they can be more complex than above, follow the same basic principles.
7.3.4 Summary
The following summary applies for every component. Summary: Location: /apps/<myapp>/components Root Node: <mycomponent> (cq:Component) - Hierarchy node of the component. Vital Properties: jcr:title - Component title; for example, used as a label when the component is listed within the sidekick. jcr:description - Component description; for example, also shown in the component list of the sidekick.
Page 35 of 106
Components
allowedChildren - Specifies the allowed child components. allowedParents - Specifies the allowed parent components. icon.png/thumbnail.png - Icon & thumbnail for this component. Vital Child Nodes: cq:editConfig (cq:EditConfig) - Controls author UI aspects; for example, bar or widget appearance, adds custom controls. cq:childEditConfig (cq:EditConfig) - Controls author UI aspects for child components that do not define their own cq:editConfig. dialog (cq:Dialog) - Content editing dialog for this component. design_dialog (cq:Dialog) - Design editing for this component.
2.
In the CRX Explorer, modify the jcr:description and jcr:title to reflect its new name.
CQ 5.2 WCM Copyright 1993-2009 Day Management AG
Page 36 of 106
Components
3.
Open the new component folder and make the changes you require; also, delete any extraneous information in the folder. You can make changes such as: adding a new field in the dialog box replacing the .jsp file (name it after your new component) or completely reworking the entire component if you want For example, if you take a copy of the standard Text component, you can add an additional field to the dialog box, then update the .jsp to process the input made there.
4.
In the Content Explorer, navigate to the component and change the allowedParents property to */parsys, which makes it available to the paragraph system. Note Either cq:editConfig node, dialog, or design_dialog node should be present and properly initialized for the new component to appear.
5.
Activate the new component in your paragraph system either by adding /apps/<websitename>/components/<MyComponent> to the /etc/designs/default/<websitename>/jcr:content/contentpage/parsys/components property in CRX or by following the instructions in Adding new components to paragraph systems. In CQ WCM, open a page in your web site and insert a new paragraph of the type you just created to make sure the component is working properly. Note To see timing statistics for page loading, you can use Ctrl-Shift-U - with ? debugClientLibs=true set in the URL.
6.
2.
3.
Click Edit. A list of components belonging to the paragraph system are shown (all those defined with the property allowedParents=*/parsys). Your new component is also listed. The components can be activated (or deactivated) to determine which are offered to the author when editing a page.
Page 37 of 106 CQ 5.2 WCM Copyright 1993-2009 Day Management AG
Components
4.
Activate your component, then return to normal edit mode to confirm that it is available for use.
Page 38 of 106
Components
2.
To keep this example simple, navigate to the component you copied and delete all the subnodes of the new textimage node except for the following ones: dialog definition: textimage/dialog component script: textimage/textimage.jsp
3.
Edit the component metadata: Component name Set jcr:description to Text Image Component (Extended) Set jcr:title to Text Image (Extended) Component listing in the paragraph (parsys component) system (leave as is) Leave allowedParents defined as */parsys Group, where the component is listed in the sidekick (leave as is) Leave componentGroup set to General Parent component for the new component (the standard textimage component) Set sling:resourceSuperType to foundation/components/textimage After these steps the component node looks like the following:
Page 39 of 106
Components
4.
Modify the component's dialog box to include the new option. The new component inherits the parts of the dialog box that are the same as in the original. The only addition we make is to extend the Advanced tab, adding an Image Position dropdown list, with options Left and Right: Leave the textimage/dialog properties unchanged. Note how textimage/dialog/items has three subnodes, tab1 to tab3, representing the three tabs of the textimage dialog box. For the first two tabs (tab1 and tab2): Change xtype to cqinclude (to inherit from the standard component). Add a pathParameter property with values /libs/foundation/components/ textimage/dialog/items/tab1.infinity.json and /libs/foundation/ components/textimage/dialog/items/tab2.infinity.json, respectively. Remove all other properties or subnodes. For tab3: Leave the properties and subnodes without changes Add a new field definition to tab3/items, node position of type cq:Widget Set the following properties (of type String) for the new tab3/items/position node name: ./imagePosition xtype: selection fieldLabel: Image Position type: select Add subnode position/options of type cq:WidgetCollection to represent the two choices for image placement, and under it create two nodes, o1 and o2 of type nt:unstructured For node position/options/o1 set the properties: text to Left and value to left For node position/options/o2 set the properties: text to Right and value to right Image position is persisted in content as the imagePosition property of the node CQ 5.2 WCM representing textimage paragraph. 40 of 106 Page Copyright 1993-2009 Day Management AG
Components
After these steps, the component dialog box looks like this:
5.
Extend the component script, textimage.jsp, with extra handling of the new parameter. Open the /apps/geometrixx/components/textimage/textimage.jsp script for editing. We are going to manipulate the style of the <div class="image"> tag, generated by the component, to float the image to the right. It is located in the following area of the code:
Image img = new Image(resource, "image"); if (img.hasContent() || WCMMode.fromRequest(request) == WCMMode.EDIT) { %><div class="image"><% img.loadStyleData(currentStyle);
We are going to replace the emphasized code fragment %><div class="image"><% with new code generating a custom style for this tag. Copy the following code fragment, and replace the %><div class="image"><% line with it:
// todo: add new CSS class for the 'right image' instead of using // the style attribute String style=""; if (properties.get("imagePosition", "left").equals("right")) { style = "style=\"float:right\""; } %><div <%= style %> class="image"><%
Note that for simplicity we are hard-coding the style to the HTML tag. The proper way to do it would be to add a new CSS class to the application styles and just add the class to the tag in the code in the case of a right-aligned image. The code fragment, after the change, should look like this (new code emphasized):
Image img = new Image(resource, "image"); if (img.hasContent() || WCMMode.fromRequest(request) == WCMMode.EDIT) { // todo: add new CSS class for the 'right image' instead of using // the style attribute
Page 41 of 106
Components
String style=""; if (properties.get("imagePosition", "left").equals("right")) { style = "style=\"float:right\""; } %><div <%= style %> class="image"><% img.loadStyleData(currentStyle);
4. 5.
6.
Open the dialog of the text and image paragraph, and change the Image Position on the Advanced tab to Right, and click OK to save the changes.
Page 42 of 106
Components
7.
You see the paragraph rendered with the image on the right:
8.
The component stores its content in a paragraph on the Company page. The following screenshot shows how our new configuration parameter is persisted in the repository, with the node representing the paragraph we have just created.
Page 43 of 106
Components
The textimage/imagePosition parameter represents the position of the image for this paragraph on /content/geometrixx/en/company page.
Page 44 of 106
Components
search query String queryParams = getString(request,"queryParams","qp"); is content mode enabled Properties are read on jcr:content node and not on search result node Boolean contentMode = getBoolean(request,"contentMode","cm"); searched properties (checked values from colsSelection displayed as checkboxes) String[] colsValue = getStringArray(request,"colsValue","cv"); extra searched properties (displayed in a comma-separated text field) String[] extraCols = getStringArray(request,"extraCols","ec"); is query performed on page load Boolean initialSearch = getBoolean(request,"initialSearch","is"); searched properties selection (displayed as checkboxes) String[] colsSelection = getStringArray(request,"colsSelection","cs"); show only the grid and not the search panel Note: Be sure to set initialSearch to true Boolean showGridOnly = getBoolean(request,"showGridOnly","sgo"); on load, search panel is collapsed Boolean searchPanelCollapsed = getBoolean(request,"searchPanelCollapsed","spc"); hide root path field Boolean hideRootPath = getBoolean(request,"hideRootPath","hrp"); hide query field Boolean hideQueryParams = getBoolean(request,"hideQueryParams","hqp"); hide content mode field Boolean hideContentMode = getBoolean(request,"hideContentMode","hcm"); hide cols selection field Boolean hideColsSelection = getBoolean(request,"hideColsSelection","hcs"); hide extra cols field Boolean hideExtraCols = getBoolean(request,"hideExtraCols","hec"); hide search button Boolean hideSearchButton = getBoolean(request,"hideSearchButton","hsearchb"); hide save button Boolean hideSaveButton = getBoolean(request,"hideSaveButton","hsavep"); hide export button Boolean hideExportButton = getBoolean(request,"hideExportButton","hexpb"); hide import button Boolean hideImportButton = getBoolean(request,"hideImportButton","hib"); hide grid search result number text Boolean hideResultNumber = getBoolean(request,"hideResultNumber","hrn");
CQ 5.2 WCM Copyright 1993-2009 Day Management AG
Page 45 of 106
Components
hide grid insert button Boolean hideInsertButton = getBoolean(request,"hideInsertButton","hinsertb"); hide grid delete button Boolean hideDeleteButton = getBoolean(request,"hideDeleteButton","hdelb"); hide grid "path" column Boolean hidePathCol = getBoolean(request,"hidePathCol","hpc");
Page 46 of 106
Components
initialSearch="true" insertedResourceType="geometrixx/components/productlist/sku" queryParams="" queryURL="/etc/importers/bulkeditor/query.json" xtype="bulkeditor"> <saveButton jcr:primaryType="nt:unstructured" text="Save modifications"/> <searchButton jcr:primaryType="nt:unstructured" text="Apply filter"/> <queryParamsInput jcr:primaryType="nt:unstructured" fieldDescription="Enter here your filters" fieldLabel="Filters"/> <searchPanel jcr:primaryType="nt:unstructured" height="200"> <defaults jcr:primaryType="nt:unstructured" labelWidth="150"/> </searchPanel> <grid jcr:primaryType="nt:unstructured" height="275"/> <store jcr:primaryType="nt:unstructured"> <sortInfo jcr:primaryType="nt:unstructured" direction="ASC" field="Attribute2"/> </store> <colModel jcr:primaryType="nt:unstructured" width="150"/> <colsMetadata jcr:primaryType="nt:unstructured"> <CatalogCode jcr:primaryType="nt:unstructured" cellStyle="background-color: #EDEDED;"/> <GroupId jcr:primaryType="nt:unstructured" cellStyle="background-color: #8080FE;"/> <ProductName jcr:primaryType="nt:unstructured" cellStyle="background-color: #FFCC99;"/> <SellingSku jcr:primaryType="nt:unstructured" cellCls="productlist-cell-sellingSku"/> <Selection> jcr:primaryType="nt:unstructured" checkbox="true" forcedPosition="0"/> </colsMetadata> </editor>
Definition Search root path Search query True to enable content mode: properties are read on jcr:content node and not on search result node
Page 47 of 106
Components
Property name
extraCols initialSearch colsSelection showGridOnly searchPanelCollapsed hideRootPath hideQueryParams hideContentMode hideColsSelection hideExtraCols hideSearchButton hideSaveButton hideExportButton hideImportButton hideResultNumber hideInsertButton hideDeleteButton hidePathCol queryURL exportURL importURL insertedResourceType saveButton searchButton exportButton importButton searchPanel grid store colModel rootPathInput queryParamsInput contentModeInput colsSelectionInput extraColsInput colsMetadata
Extra searched properties (displayed in a textfield comma separated) True to perform query on page load Searched properties selection (displayed as checkboxes) True to show only the grid and not the search panel (do not forget to set the initialSearch to true) True to collapse search panel by default Hide root path field Hide query field Hide content mode field Hide cols selection field Hide extra cols field Hide search button Hide save button Hide export button Hide import button Hide grid search result number text Hide grid insert button Hide grid delete button Hide grid "path" column Path to query servlet Path to export servlet Path to import servlet Resource type added to node when a row is inserted Save button widget config Search button widget config Export button widget config Import button widget config Search panel widget config Grid widget config Store config Grid column model config rootPath widget config queryParams widget config contentMode widget config colsSelection widget config extraCols widget config Column metadata config. Possible properties are (applied to all cells of the column):
Page 48 of 106
Components
Definition
readOnly: true to not being able to change value checkbox: true to define all cells of the column as checkboxes (true/false values) forcedPosition: integer value to specify where column must be placed in grid (between 0 and number of colums-1)
Each hit corresponds to one node and its properties and is displayed as a row in the grid. For example, a query could be query: "path /content/brand/ chair" cols: "nameID,sku,catalogCode" You can extend the Query servlet to return a complex inheritance model or return nodes stored at a specific logic place. The Query servlet can be used to do any kind of complex computation. The grid can then display rows that are an aggregate of several nodes in the repository. The modification and the saving of these rows must in that case be managed by the Save Servlet.
Page 49 of 106
Components
Page 50 of 106
Components
<colsMetadata jcr:primaryType="nt:unstructured"> <CatalogCode jcr:primaryType="nt:unstructured" cellStyle="background-color: #EDEDED;"/> <GroupId jcr:primaryType="nt:unstructured" cellStyle="background-color: #8080FE;"/> <ProductName jcr:primaryType="nt:unstructured" cellStyle="background-color: #FFCC99;"/> <SellingSku jcr:primaryType="nt:unstructured" cellCls="productlist-cell-sellingSku"/> </colsMetadata>
7.5.1.2.4.2 Checkbox If the checkbox configuration property is set to true, then all the cells of the columns are rendered as checkboxes. A checked box sends true to server Save servlet, false otherwise. In the header menu, you can also select all and select none. These options are enabled if the selected header is the header of a checkbox column. This example can be found in the productlist component (/apps/geometrixx/components/productlist/ dialog/items/editor/colsMetadata): selection column contains only checkboxes and is always the first column.
<colsMetadata jcr:primaryType="nt:unstructured"> <CatalogCode jcr:primaryType="nt:unstructured" cellStyle="background-color: #EDEDED;"/> <GroupId jcr:primaryType="nt:unstructured" cellStyle="background-color: #8080FE;"/> <ProductName jcr:primaryType="nt:unstructured" cellStyle="background-color: #FFCC99;"/> <SellingSku jcr:primaryType="nt:unstructured" cellCls="productlist-cell-sellingSku"/> <Selection jcr:primaryType="nt:unstructured" checkbox="true" forcedPosition="0"/> </colsMetadata>
7.5.1.2.4.3 Forced position Forced position (forcedPosition) metadata lets you specify where the column must always be placed within the grid: 0 is the first place and <number of columns>-1 is the last position. Any other value is ignored.
<colsMetadata jcr:primaryType="nt:unstructured"> <CatalogCode jcr:primaryType="nt:unstructured" cellStyle="background-color: #EDEDED;"/> <GroupId jcr:primaryType="nt:unstructured" cellStyle="background-color: #8080FE;"/> <ProductName jcr:primaryType="nt:unstructured" cellStyle="background-color: #FFCC99;"/> <SellingSku jcr:primaryType="nt:unstructured" cellCls="productlist-cell-sellingSku"/> <Selection jcr:primaryType="nt:unstructured" checkbox="true" forcedPosition="0"/>
Page 51 of 106
Components
</colsMetadata>
7.6 Scripts
JSP Scripts or Servlets are usually used to render components. According to the request processing rules of Sling the name for the default script is <componentname>.jsp.
7.6.1 global.jsp
The JSP script file global.jsp is used to provide quick access to specific objects (i.e. to access content) to any JSP script file used to render a component. Therefore global.jsp should be included in every component rendering JSP script where one or more of the objects provided in global.jsp are used.
Page 52 of 106
Components
The properties object is an instance of a ValueMap (see Sling API) and contains all properties of the current resource. Example: String pageTitle = properties.get("jcr:title", "no title"); used in the rendering script of a page component. Example: String paragraphTitle = properties.get("jcr:title", "no title"); used in the rendering script of a standard paragraph component. Via the currentPage object introduced in global.jsp: The currentPage object is an instance of a page (see CQ5 API). The page class provides some methods to access content. Example: String pageTitle = currentPage.getTitle(); Via currentNode object introduced in global.jsp: The currentNode object is an instance of a node (see JCR API). The properties of a node can be accessed by the getProperty() method. Example: String pageTitle = currentNode.getProperty("jcr:title"); Note Day does not recommend using the JCR API directly in CQ5 if not really necessary; CQ5 is a Sling Application and therefore we deal with resources and not nodes.
Note When the /libs/wcm/global.jsp file is included in the script, the cq taglib is automatically declared. Tip When you develop the jsp script of a CQ5 component, it is recommended to include following code at the top of the script:
<%@include file="/libs/wcm/global.jsp"%>
It declares the sling, cq and jstl taglibs and exposes the regularly used scripting objects defined by the <cq:defineObjects /> tag. This shortens and simplifies the jsp code of your component.
7.6.2.1.1 <cq:setContentBundle>
The <cq:setContentBundle> tag creates an i18n localization context and stores it in the javax.servlet.jsp.jstl.fmt.localizationContext configuration variable.
Page 53 of 106
Components
It has the following attribute: language The language of the locale for which to retrieve the resource bundle. The "content bundle" can be simply used by standard JSTL <fmt:message> tags. The lookup of messages by keys is two-fold: 1. First, the JCR properties of the underlying resource that is currently rendered are searched for translations. This allows you to define a simple component dialog to edit those values. 2. If the node does not contain a property named exactly like the key, the fallback is to load a resource bundle from the sling request (SlingHttpServletRequest.getResourceBundle(Locale)). The language or locale for this bundle is defined this way: a. First, if the parameter language of the<cq:setContentBundle> tag is set, this is used. b. Otherwise, the locale of the page is looked up. This is defined by the LanguageManager of CQ5 (language copy function), which is typically taken from the page path (eg. the path / content/site/en/some/page produces the "en" locale). c. Finally, if there is no page language defined, the default locale of the current request is used, which is equivalent to calling request.getResourceBundle(null). Example:
<%@include file="/libs/wcm/global.jsp"%><% %><%@ page import="com.day.cq.wcm.foundation.forms.ValidationInfo, com.day.cq.wcm.foundation.forms.FormsConstants, com.day.cq.wcm.foundation.forms.FormsHelper, org.apache.sling.api.resource.Resource, org.apache.sling.api.resource.ResourceUtil, org.apache.sling.api.resource.ValueMap" %><% %><cq:setContentBundle/>
7.6.2.1.2 <cq:include>
The <cq:include> tag includes a resource into the current page. It has the following attributes: flush A boolean defining whether to flush the output before including the target. path The path to the resource object to be included in the current request processing. If this path is relative it is appended to the path of the current resource whose script is including the given resource. Either path and resourceType, or script must be specified. resourceType The resource type of the resource to be included. If the resource type is set, the path must be the exact path to a resource object: in this case, adding parameters, selectors and extensions to the path is not supported. If the resource to be included is specified with the path attribute that cannot be resolved to a resource, the tag may create a synthetic resource object out of the path and this resource type. Either path and resourceType, or script must be specified. script The jsp script to include. Either path and resourceType, or script must be specified.
CQ 5.2 WCM Copyright 1993-2009 Day Management AG
Page 54 of 106
Components
ignoreComponentHierarchy A boolean controlling whether the component hierarchy should be ignored for script resolution. If true, only the search paths are respected. Example:
<%@taglib prefix="cq" uri="http://www.day.com/taglibs/cq/1.0" %><% %><div class="center"> <cq:include path="trail" resourceType="foundation/components/breadcrumb" /> <cq:include path="title" resourceType="foundation/components/title" /> <cq:include script="redirect.jsp"/> <cq:include path="par" resourceType="foundation/components/parsys" /> </div>
Note Should you use <%@ include file="myScript.jsp" %> or <cq:include script="myScript.jsp" %> to include a script? The <%@ include file="myScript.jsp" %> directive informs the JSP compiler to include a complete file into the current file. It is as if the contents of the included file were pasted directly into the original file. With the <cq:include script="myScript.jsp" %> directive, the file is included at runtime. Note Should you use <cq:include> or <sling:include>? When developing CQ5 components, Day recommends that you use <cq:include>. <cq:include> allows you to directly include script files by their name when using the script attribute. This takes component and resource type inheritance into account, and is often simpler than strict adherence to Sling's script resolution using selectors and extensions.
7.6.2.1.3 <cq:defineObjects>
The <cq:defineObjects> tag exposes the following, regularly used, scripting objects which can be referenced by the developer. It also exposes the objects defined by the <sling:defineObjects> tag. componentContext the current component context object of the request (com.day.cq.wcm.api.components.ComponentContext interface). component the current CQ5 component object of the current resource (com.day.cq.wcm.api.components.Component interface). currentDesign the current design object of the current page (com.day.cq.wcm.api.designer.Design interface). currentPage the current CQ WCM page object (com.day.cq.wcm.api.Page interface). currentStyle the current style object of the current cell (com.day.cq.wcm.api.designer.Style interface). designer the designer object used to access design information (com.day.cq.wcm.api.designer.Designer interface).
Page 55 of 106 CQ 5.2 WCM Copyright 1993-2009 Day Management AG
Components
editContext the edit context object of the CQ5 component (com.day.cq.wcm.api.components.EditContext interface). pageManager the page manager object for page level operations (com.day.cq.wcm.api.PageManager interface). pageProperties the page properties object of the current page (org.apache.sling.api.resource.ValueMap). properties the properties object of the current resource (org.apache.sling.api.resource.ValueMap). resourceDesign the design object of the resource page (com.day.cq.wcm.api.designer.Design interface). resourcePage the resource page object (com.day.cq.wcm.api.Page interface). It has the following attributes: requestName inherited from sling responseName inherited from sling resourceName inherited from sling nodeName inherited from sling logName inherited from sling resourceResolverName inherited from sling slingName inherited from sling componentContextName specific to wcm editContextName specific to wcm propertiesName specific to wcm pageManagerName specific to wcm currentPageName specific to wcm resourcePageName specific to wcm
CQ 5.2 WCM Copyright 1993-2009 Day Management AG
Page 56 of 106
Components
pagePropertiesName specific to wcm componentName specific to wcm designerName specific to wcm currentDesignName specific to wcm resourceDesignName specific to wcm currentStyleName specific to wcm Example:
<%@page session="false" contentType="text/html; charset=utf-8" %><% %><%@ page import="com.day.cq.wcm.api.WCMMode" %><% %><%@taglib prefix="cq" uri="http://www.day.com/taglibs/cq/1.0" %><% %><cq:defineObjects/>
Note When the /libs/wcm/global.jsp file is included in the script, the <cq:defineObjects / > tag is automatically included.
7.6.2.1.4 <cq:requestURL>
The <cq:requestURL> tag writes the current request URL to the JspWriter. The two tags <cq:addParam> and <cq:removeParam> may be used inside the body of this tag to modify the current request URL before it is written. It allows you to create links to the current page with varying parameters. For example, it enables you to transform the request: mypage.html?mode=view&query=something into mypage.html?query=something. The use of addParam or removeParam only changes the occurence of the given parameter, all other parameters are unaffected. <cq:requestURL> does not have any attribute. Examples:
<a href="<cq:requestURL><cq:removeParam name="language"/></cq:requestURL>">remove filter</ a> <a title="filter results" href="<cq:requestURL><cq:addParam name="language" value="${bucket.value}"/></cq:requestURL>">${label} (${bucket.count})</a>
7.6.2.1.5 <cq:addParam>
The <cq:addParam> tag adds a request parameter with the given name and value to the enclosing <cq:requestURL> tag. It has the following attributes: name name of the parameter to be added
CQ 5.2 WCM Copyright 1993-2009 Day Management AG
Page 57 of 106
Components
7.6.2.1.6 <cq:removeParam>
The <cq:removeParam> tag removes a request parameter with the given name and value from the enclosing <cq:requestURL> tag. If no value is provided all parameters with the given name are removed. It has the following attributes: name name of the parameter to be removed Example:
<a href="<cq:requestURL><cq:removeParam name="language"/></cq:requestURL>">remove filter</ a>
Note When the /libs/wcm/global.jsp file is included in the script, the sling taglib is automatically declared.
7.6.2.2.1 <sling:include>
The <sling:include> tag includes a resource into the current page. It has the following attributes: flush A boolean defining whether to flush the output before including the target. resource The resource object to be included in the current request processing. Either resource or path must be specified. If both are specified, the resource takes precedence. path The path to the resource object to be included in the current request processing. If this path is relative it is appended to the path of the current resource whose script is including the given resource. Either resource or path must be specified. If both are specified, the resource takes precedence. resourceType The resource type of the resource to be included. If the resource type is set, the path must be the exact path to a resource object: in this case, adding parameters, selectors and extensions to the path is not supported.
CQ 5.2 WCM Copyright 1993-2009 Day Management AG
Page 58 of 106
Components
If the resource to be included is specified with the path attribute that cannot be resolved to a resource, the tag may create a synthetic resource object out of the path and this resource type. replaceSelectors When dispatching, the selectors are replaced with the value of this attribute. addSelectors When dispatching, the value of this attribute is added to the selectors. replaceSuffix When dispatching, the suffix is replaced by the value of this attribute. Note The resolution of the resource and the script that are included with the <sling:include> tag is the same as for a normal sling URL resolution. By default, the selectors, extension, etc. from the current request are used for the included script as well. They can be modified through the tag attributes: for example replaceSelectors="foo.bar" allows you to overwrite the selectors. Examples:
<div class="item"><sling:include path="<%= pathtoinclude %>"/></div> <sling:include resource="<%= par %>"/> <sling:include addSelectors="spool"/> <sling:include resource="<%= par %>" resourceType="<%= newType %>"/> <sling:include replaceSelectors="content" />
7.6.2.2.2 <sling:defineObjects>
The <sling:defineObjects> tag exposes the following, regularly used, scripting objects which can be referenced by the developer: slingRequest SlingHttpServletRequest object, providing access to the HTTP request header information extends the standard HttpServletRequest - and provides access to Sling-specific things like resource, path info, selector, etc. slingResponse SlingHttpServletResponse object, providing access for the HTTP response that is created by the server. This is currently the same as the HttpServletResponse from which it extends. request The standard JSP request object which is a pure HttpServletRequest. response The standard JSP response object which is a pure HttpServletResponse. resourceResolver The current ResourceResolver object. It is the same as slingRequest.getResourceResolver(). sling A SlingScriptHelper object, containing convenience methods for scripts, mainly sling.include('/ some/other/resource') for including the responses of other resources inside this response (eg. embedding header html snippets) and sling.getService(foo.bar.Service.class) to retrieve OSGi services available in Sling (Class notation depending on scripting language).
CQ 5.2 WCM Copyright 1993-2009 Day Management AG
Page 59 of 106
Components
resource the current Resource object to handle, depending on the URL of the request. It is the same as slingRequest.getResource(). currentNode If the current resource points to a JCR node (which is typically the case in Sling), this gives direct access to the Node object. Otherwise this object is not defined. log Provides an SLF4J Logger for logging to the Sling log system from within scripts, eg. log.info("Executing my script"). It has the following attributes: requestName responseName resourceName nodeName logName resourceResolverName slingName Example:
<%@page session="false" %><% %><%@page import="com.day.cq.wcm.foundation.forms.ValidationHelper"%><% %><%@taglib prefix="sling" uri="http://sling.apache.org/taglibs/sling/1.0" %><% %><sling:defineObjects/>
Page 60 of 106
Components
Page 61 of 106
Components
Page 62 of 106
Components
Vital Properties: name - Defines the name of the property where the content provided by this widget is stored (usually something like ./mypropertyname) xtype - Defines the widget's xtype fieldLabel - The text displayed in the dialog as a label for this widget
7.7.3.1 Designer
The Designer is used to manage the look-and-feel of the global content; including the path to the tool-pages, image of the logo, design values such as text family, size and so on. Summary: Location: /etc/designs Root Node: <mydesign> (cq:Page) - Hierarchy node of the design page Vital Child Nodes: jcr:content (cq:PageContent) - Content node for the design Vital Properties of Child Node jcr:content: sling:resourceType = wcm/designer - Reference to the designer rendering component The Designer values can be accessed by the currentStyle object provided in global.jsp. Design dialogs are structured in the same way as normal dialogs but are named design_dialog.
CQ 5.2 WCM Copyright 1993-2009 Day Management AG
Page 63 of 106
Components
Page 64 of 106
Components
sizeLimit - Maximum size limit, i.e. 100. uploadUrl - The path to be used when storing data temporarily, usually /tmp/uploaded_test/ *.
Page 65 of 106
Components
draw getDescription com.day.cq.wcm.api.components.DropTarget com.day.cq.wcm.api.components.EditConfig com.day.cq.wcm.commons.WCMUtils For more detailed information please look at the Javadoc provided with CQ5 WCM.
Page 66 of 106
Components
com.day.cq.wcm.foundation.TextFormat com.day.cq.wcm.api.WCMMode For more detailed information please have a look at the Javadoc provided with CQ5 WCM.
Page 67 of 106
Page 68 of 106
Page 69 of 106
Page 70 of 106
the three properties defined by the cqLiveRelationship mixin, which is the supertype of cq:LiveSync, which has the following three properties: cq:lastRolledout, cq:lastRolledoutBy and cq:msmSyncState. the cq:LiveSyncConfig and the cq:LiveSyncAction nodes (see the following description).
Page 71 of 106
Page 72 of 106
Page 73 of 106
The configuration of a Live Copy page is defined as follows: if a cq:LiveSyncConfig node is stored under its jcr:content node, the configuration is taken from this cq:LiveSyncConfig node. otherwise, the configuration is inherited from the first parent page with a cq:LiveSyncConfig node stored to it. The actions to be performed on a Live Copy page are defined according to the following process: 1. In a first step: if a cq:LiveSyncAction node is stored under its jcr:content node, the actions are taken from the cq:LiveSyncAction node. otherwise, the actions are inherited from the first parent page with a cq:LiveSyncAction node stored to it. 2. If for this given Live Copy page, an action is defined on its Blueprint page (it has a cq:LiveSyncAction node stored to it): if the action does not exist on the Live Copy page, the Blueprint action is added to the action set and is performed. if the action exists on the Live Copy page, the Blueprint action replaces it and is performed. When a Live Copy is suspended, the cq:LiveSyncCancelled mixin is added to the jcr:content node of the page or to the paragraph node.
CQ.wcm.msm.MSM.UpdateContentAction, CQ.wcm.msm.MSM.NotifyAction, CQ.wcm.msm.MSM.WorkflowAction and CQ.wcm.msm.MSM.MandatoryAction are objects representing the default configurations for standard synchronization actions.
Page 74 of 106
2.
4.
Note To connect to the CRX repository using the WebDAV protocol, check the CRX documentation on WebDAV access. 5. Create the myMsmActions.js file with the following code and store it under /apps/myApp/ widgets/source (for example with WebDAV):
CQ.wcm.msm.MSM.MandatoryStructureAction = { "xtype": "combo", "fieldLabel": CQ.I18n.getMessage("Mandatory Structure for"), "name": "actionMandatoryStructure", "hiddenName": "msm:actionMandatoryStructure/target", "actionName":"msm:actionMandatoryStructure", "stateful": false, "typeAhead":true, "triggerAction":"all", "inputType":"text", "displayField":"name", "emptyText": "", "minChars":0, "editable":true, "lazyInit": false, "queryParam": "filter",
Page 75 of 106 CQ 5.2 WCM Copyright 1993-2009 Day Management AG
"fieldDescription": CQ.I18n.getMessage("Select the groups that will not be able to modify the Live Copy structure."), "tpl" :new CQ.Ext.XTemplate( '<tpl for=".">', '<div class="cq-msm-list cq-msm-mandatory-list">', '<div class="cq-msm-list-entry cq-msm-mandatory-listentry">{[values.name==""? values.id: values.name]}</div>', '</div>', '</tpl>'), "itemSelector" :"div.cq-msm-mandatory-list", "store": new CQ.Ext.data.Store({ "autoLoad":false, "proxy": new CQ.Ext.data.HttpProxy({ "url": "/bin/security/authorizables.json?limit=25&hideUsers=true", "method":"GET" }), "reader": new CQ.Ext.data.JsonReader({ "root":"authorizables", "totalProperty":"results", "id":"id", "fields":["name","id"]}) }), "defaultValue": "" }; // Adds the new action to the CQ.wcm.msm.MSM.ACTIONS array CQ.wcm.msm.MSM.ACTIONS.push(CQ.wcm.msm.MSM.MandatoryStructureAction);
6.
7.
In CQ5, open a Live Copy page. In the Page tab of the sidekick, click Page Properties.... Select the Live Copy tab to view the newly created widget:
Page 76 of 106
Page 77 of 106
2.
Set the Java Compiler to version 1.5: 1. 2. Right-click the core project, select Properties. Select Java Compiler and set following properties to 1.5: Compiler compliance level Generated .class files compatibility Source compatibility 3. 4. Click OK. In the dialog window, click Yes.
3.
Page 78 of 106
</build> <dependencies> <dependency> <groupId>com.day.cq.wcm</groupId> <artifactId>cq-wcm-api</artifactId> <version>5.2.22</version> <scope>provided</scope> </dependency> <dependency> <groupId>com.day.cq</groupId> <artifactId>cq-security</artifactId> <version>5.2.22</version> <scope>provided</scope> </dependency> <dependency> <groupId>com.day.cq</groupId> <artifactId>cq-security-api</artifactId> <version>5.2.6</version> <scope>provided</scope> </dependency> <dependency> <groupId>com.day.crx.sling</groupId> <artifactId>com.day.crx.sling.client</artifactId> <version>1.4.2</version> <scope>provided</scope> </dependency> <dependency> <groupId>org.apache.sling</groupId> <artifactId>org.apache.sling.jcr.api</artifactId> <version>2.0.2-incubator</version> <scope>provided</scope> </dependency> <dependency> <groupId>com.day.cq</groupId> <artifactId>cq-commons</artifactId> <version>5.2.20</version> <scope>provided</scope> </dependency> <dependency> <groupId>org.apache.sling</groupId> <artifactId>org.apache.sling.api</artifactId> <version>2.0.3-incubator-R746167</version> <scope>provided</scope> </dependency> <dependency> <groupId>org.osgi</groupId> <artifactId>osgi_R4_core</artifactId> <version>1.0</version> <scope>provided</scope> </dependency> <dependency> <groupId>org.osgi</groupId> <artifactId>osgi_R4_compendium</artifactId> <version>1.0</version> <scope>provided</scope> </dependency> </dependencies> <repositories> <repository>
Page 79 of 106
<id>day-external-central</id> <name>Day Central Repository</name> <url>http://repo.day.com/archiva/repository/day-central</url> <releases> <enabled>true</enabled> </releases> <snapshots> <enabled>false</enabled> </snapshots> </repository> <repository> <id>apache-incubating-repository</id> <name>Apache Incubating Repository</name> <url>http://people.apache.org/repo/m2-incubating-repository</url> <releases> <enabled>true</enabled> </releases> <snapshots> <enabled>false</enabled> </snapshots> </repository> </repositories> <pluginRepositories> <pluginRepository> <id>day-external-central</id> <name>Day Central Repository</name> <url>http://repo.day.com/archiva/repository/day-central</url> <releases> <enabled>true</enabled> </releases> <snapshots> <enabled>false</enabled> </snapshots> </pluginRepository> <pluginRepository> <id>apache-incubating-repository</id> <name>Apache Incubating Repository</name> <url>http://people.apache.org/repo/m2-incubating-repository</url> <releases> <enabled>true</enabled> </releases> <snapshots> <enabled>false</enabled> </snapshots> </pluginRepository> </pluginRepositories> </project>
4.
Add the credentials into the settings.xml file of your <maven-install-dir>/.m2 directory: copy/paste the following code into the <servers></servers> tags:
<server> <id>day-external-central</id> <username>cq5_training</username> <password>tr41n1ng</password> </server>
5.
Create the package com.day.cq5.mymsm that will contain the Java classes under core/ src/main/java: 1. 2. Under core, right-click src/main/java, select New, then Package. Name it com.day.cq5.mymsm and click Finish.
CQ 5.2 WCM Copyright 1993-2009 Day Management AG
Page 80 of 106
6.
Create the Java class MandatoryStructureAction: 1. In Eclipse, under core/src/main/java, right-click the com.day.cq5.mymsm package, select New, then Class. In the dialog window, name the Java Class MandatoryStructureAction and click Finish. Eclipse creates and opens the file MandatoryStructureAction.java. In MandatoryStructureAction.java replace the existing code with the following:
package com.day.cq5.mymsm; import javax.jcr.Node; import org.apache.sling.api.resource.Resource; import org.apache.sling.api.resource.ResourceResolver; import org.osgi.service.component.ComponentContext; import import import import import import import import import import import com.day.cq.security.util.ActionSet; com.day.cq.security.util.CRXPolicyManager; com.day.cq.wcm.api.NameConstants; com.day.cq.wcm.api.Page; com.day.cq.wcm.api.PageManager; com.day.cq.wcm.api.WCMException; com.day.cq.wcm.api.msm.ActionConfig; com.day.cq.wcm.api.msm.ActionManager; com.day.cq.wcm.api.msm.LiveAction; com.day.cq.wcm.api.msm.LiveRelationship; com.day.crx.CRXSession;
2.
3.
/** * Set read-ony to group defined in the action config of the relationship (for pages only). Denied ACL are: <ul> * <li>ActionSet.ACTION_NAME_REMOVE</li> * <li>ActionSet.ACTION_NAME_SET_PROPERTY</li> * <li>ActionSet.ACTION_NAME_ACL_MODIFY</li> * </ul> * @scr.component metatype="false" name="com.day.cq5.mymsm.MandatoryStructureAction" immediate="true" * label="%mandatoryaction.name" description="%mandatoryaction.description" * @scr.service interface="com.day.cq.wcm.api.msm.LiveAction" */ public class MandatoryStructureAction implements LiveAction { //name of the action in the repository public static final String ACTION_NAME = "mandatoryStructure"; //name of the request parameter used to get/post action properties public static final String ACTION_PARAM_NAME = "msm:actionMandatoryStructure"; public static final int ACTION_RANK = 602; public static final String ACTION_PARAM_TARGET = "target"; //name of the request parameter used to get/post action properties private String[] properties = {MandatoryStructureAction.ACTION_PARAM_TARGET}; /** * @scr.reference */ @SuppressWarnings("UnusedDeclaration") private ActionManager actionManager; protected void activate(ComponentContext context) { actionManager.registerAcion(this); } protected void deactivate(ComponentContext context) { actionManager.unregisterAcion(this); }
Page 81 of 106
public String getName() { return ACTION_NAME; } public int getRank() { return ACTION_RANK; } public String[] getPropertiesNames() { return properties; } public String getParameterName() { return ACTION_PARAM_NAME; } public void execute(ResourceResolver resolver, LiveRelationship relation, ActionConfig config, boolean autoSave) throws WCMException { try { if (!relation.getStatus().isCancelled() && config != null) { if (config.hasProperty(ACTION_PARAM_TARGET)) { String target = config.getProperty(ACTION_PARAM_TARGET); if (target != null && !target.equals("")) { Resource r = resolver.getResource(relation.getTargetPath()); Node slaveNode = r != null ? r.adaptTo(Node.class): null;//Utils.getNode(resolver, relation.getTargetPath()); if (slaveNode != null) { //set mandatory only on pages if (NameConstants.NN_CONTENT.equals(slaveNode.getName()) && slaveNode.getParent().isNodeType(NameConstants.NT_PAGE)) { //at this point, action is executed only for a page. PageManager pm = resolver.adaptTo(PageManager.class); Page p = pm.getContainingPage(resolver.getResource(slaveNode.getPath())); if (p != null) { CRXPolicyManager policyMgr = new CRXPolicyManager((CRXSession) slaveNode.getSession()); policyMgr.enact(p.getPath(), target, false, ActionSet.create(new String[]{ ActionSet.ACTION_NAME_REMOVE, // ActionSet.ACTION_NAME_SET_PROPERTY, // ActionSet.ACTION_NAME_ACL_MODIFY}) ); } } } } } } } catch (Exception re) { throw new WCMException("Error while executing " + getName() + " action", re); } } }
4.
Save the changes. Note The synchronization action parameter name must match the value returned by LiveAction#getParameterName.
Page 82 of 106
A synchronization action is an OSGI service that must implement the interface com.day.cq.wcm.api.msm.LiveAction and must register itself to the RolloutManager. As you can see in the above code, a rank has been set to the action (the value of the field ACTION_RANK). The actions are executed by following the order of the ranks. For the default synchronization actions, the ranks are: UpdateContentAction = CUDAction service: 301 NotifyAction = NotifyAction service: 501 MandatoryAction = MandatoryAction service: 601 WorkflowAction = WorkflowAction service: 701 7. Compile the Java class and create the bundle: 1. 2. Right-click the core project, select Run As, then Maven Install. The bundle core-0.0.1-SNAPSHOT.jar (containing the compiled class) is created under core/target.
8.
In CRX Explorer, create a new node under /apps/myApp. Name = install, Type = nt:folder. Copy the bundle core-0.0.1-SNAPSHOT.jar and store it under /apps/myApp/install (for example with WebDAV).
9.
10. In your browser, in CQ5: 1. Open a Live Copy page. In the Live Copy tab of the Page Properties, select a group beside Mandatory Structure for. Click OK. Rollout the corresponding Blueprint page. Log out of CQ5 and log in as a member of the selected group. Refresh the Live Copy page: you can now edit the page but not delete it.
2. 3. 4.
10.2.2 How to define the properties and the nodes that are copied to the Live Copy
The MSM in CQ5 lets you define: which properties are copied by the Update Content synchronization action. which node types are part of the rollout process, that is, which synchronization actions are performed on the node. To do so: 1. In your browser, open the Apache Felix Web Management Console Configuration (for example: http://localhost:4502/system/console/configMgr). In Configuration, select CQ WCM Rollout Manager.
2.
Page 83 of 106
3.
Configure these two parameters: Excluded Properties java regexes that define the property names to not copy. If the property name matches one regex, it will not be copied. Excluded Nodetypes java regexes that define the node types to exclude from rollout. If the node type matches one regex, it will not be included by the rollout manager.
10.2.3 How to remove the "Chapters" step in the "Create Site" wizard
In some cases, the Chapters selection is not required in the Create Site wizard but only the Languages selection. To remove this step in the default Geometrixx blueprint: 1. 2. 3. In CRX Explorer, remove the node /etc/blueprints/geometrixx/jcr:content/ dialog/items/tabs/items/tab_chap. Navigate to /libs/wcm/msm/templates/blueprint/defaults/livecopy_tab/ items and create a new node. Name = chapters, Type = cq:Widget. Add following properties to the new node: Name = name, Type = String, Value = msm:chapterPages Name = value, Type = String, Value = all Name = xtype, Type = String, Value = hidden
Page 84 of 106
Page 85 of 106
Table 12.1.
Handler name TextHandler PdfHandler JpegHandler Service Name (in the System Console) Supported MIME types
Mp3Handler ZipHandler
PictHandler
com.day.cq.dam.handler.standard.pict.PictHandler image/pict
StandardImageHandler com.day.cq.dam.core.impl.handler.StandardImageHandler image/gif image/png application/photoshop image/jpeg image/tiff image/x-ms-bmp image/bmp GenericAssetHandler com.day.cq.dam.core.impl.handler.GenericAssetHandler handler was found to fallback in case no other extract data from an asset All the handlers perform the following tasks: extracting all available metadata from the asset. creating a thumbnail image out of the asset.
Page 86 of 106
Beside those tasks other MIME type specific tasks are available: refer to the Javadocs for detailed information. It is possible to view the active media handlers: 1. 2. 3. In your browser, navigate to http://<host>:<port>/system/console/components. Click the link com.day.cq.dam.core.impl.store.AssetStoreImpl. A list with all the active media handlers is displayed. For example:
Page 87 of 106
generates a thumbnail creates sub-assets: each page of the document becomes a sub-asset The following example shows how to disable the sub-asset creation for PDF documents by extending the workflow: the Process Subassets step will be replaced by an OR-split that checks the asset filename: if it ends with .pdf, the asset reaches the End step. if it does not end with .pdf, the asset goes through a Process Subassets step that generates sub-assets. The workflow will look as follows:
Proceed as follows: 1. Create a service (for example com.day.cq5.myprocess.DoNothingProcess) that does not affect the asset and install it in CQ5. This service will be used to bypass the sub-asset creation step. Tip You can refer to the section called Example: create a specific Text Handler to see how to create a service and install it in CQ5.
CQ 5.2 WCM Copyright 1993-2009 Day Management AG
Page 88 of 106
2. 3. 4. 5.
In your browser, open the Workflow Console (for example: http://localhost:4502/ libs/workflow/content/console.html). Select the Models tab and edit the DAM Asset Sync and Metadata Extractor workflow. Drag and drop an OR Split between the Thumbnail Creation step and the Process Subassets step. Click the configuration button of the left step of the OR Split and set the following properties in the right panel: Type: select Process Description: This process creates subassets if handler is able to extract subassets Handler Advance: true Implementation: select com.day.cq.dam.core.process.CreateSubAssetsProcess Process Arguments: /etc/workflow/models/dam/sub_asset_processor Timeout: Off Timeout Handler: Title: Process Subassets
6.
Click the configuration button of the right step of the OR Split and set the following properties in the right panel: Type: select Process Description: This process does not affect the asset and leads to the next step Handler Advance: true Implementation: type the name of the service here (the service created in step 1; for example: com.day.cq5.myprocess.DoNothingProcess) Process Arguments: Timeout: Off Timeout Handler: Title: Do Nothing
7. 8.
Delete the Process Subassets step that comes after the end of the OR Split. Create an ecma-script function that is set to true if the filename ends with .pdf, to false otherwise: 1. 2. In CQDE, create a file under /etc/workflow/scripts and call it myPdfCheck.ecma. Copy-paste the following code into it:
function check() { if (workflowData.getPayloadType() == "JCR_PATH") { var path = workflowData.getPayload().toString();
Page 89 of 106
var node = jcrSession.getItem(path); if (node.getPath().indexOf(".pdf") >= 0) { return true; } else { return false; } } else { return false; } }
3. 9.
Create an ecma-script function that is set to true if the filename does not end with .pdf, to false otherwise: 1. 2. In CQDE, create a file under /etc/workflow/scripts and call it myNotPdfCheck.ecma. Copy-paste the following code into it:
function check() { if (workflowData.getPayloadType() == "JCR_PATH") { var path = workflowData.getPayload().toString(); var node = jcrSession.getItem(path); if (node.getPath().indexOf(".pdf") >= 0) { return false; } else { return true; } } else { return true; } }
3.
10. In your browser, set the rule of the Process Subassets step of the OR Split: type /etc/ workflow/scripts/myPdfCheck.ecma as value of the Rule. 11. Set the rule of the Do Nothing step of the OR Split: type /etc/workflow/scripts/ myNotPdfCheck.ecma as value of the Rule. 12. Save the workflow. From now on, whenever a pdf file is uploaded into the /var/dam/geometrixx/documents folder, the file is copied into /content/dam/geometrixx/documents, its metadata are extracted and thumbnails are generated. Subassets are not created anymore.
Page 90 of 106
The interface and classes include: com.day.cq.dam.api.handler.AssetHandler Interface This interface describes the service which adds support for specific mime types. Adding a new mime type requires to implement this interface. The interface contains methods for importing and exporting the specific documents, for creating thumbnails and extracting metadata. For more information refer to the Javadocs. com.day.cq.dam.core.AbstractAssetHandler Class This class serves as basis for all other asset handler implementations and provides common used functionality. For more information refer to the Javadocs. com.day.cq.dam.core.AbstractSubAssetHandler Class: This class serves as basis for all other asset handler implementations and provides common used functionality plus common used functionality for subasset extraction For more information refer to the Javadocs.
Page 91 of 106
Note Refer to the section called Installing Eclipse for installing and setting up Eclipse with a Maven plugin and for setting up the dependencies that are needed for the Maven project. 1. In Eclipse, create the myBundle Maven project: 1. 2. 3. 4. In the Menu bar, click File, select New, then Other... . In the dialog, expand the Maven folder, select Maven Project and click Next. Check the Create a simple project box and the Use default Workspace locations box, then click Next. Define the Maven project: Group Id: com.day.cq5.myhandler Artifact Id: myBundle Name: My CQ5 bundle Description: This is my CQ5 bundle 5. 2. Click Finish.
Set the Java Compiler to version 1.5: 1. 2. Right-click the myBundle project, select Properties. Select Java Compiler and set following properties to 1.5: Compiler compliance level Generated .class files compatibility Source compatibility 3. 4. Click OK. In the dialog window, click Yes.
3.
Replace the code in the pom.xml file with the following code:
<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/maven-v4_0_0.xsd"> <modelVersion>4.0.0</modelVersion> <!-- ====================================================================== --> <!-- P A R E N T P R O J E C T D E S C R I P T I O N --> <!-- ====================================================================== --> <parent> <groupId>com.day.cq.dam</groupId> <artifactId>dam</artifactId> <version>5.2.14</version> <relativePath>../parent</relativePath> </parent> <!-- ====================================================================== --> <!-- P R O J E C T D E S C R I P T I O N --> <!-- ====================================================================== --> <groupId>com.day.cq5.myhandler</groupId> <artifactId>myBundle</artifactId> <name>My CQ5 bundle</name> <version>0.0.1-SNAPSHOT</version> <description>This is my CQ5 bundle</description>
Page 92 of 106
<packaging>bundle</packaging> <!-- ====================================================================== --> <!-- B U I L D D E F I N I T I O N --> <!-- ====================================================================== --> <build> <plugins> <plugin> <groupId>org.apache.felix</groupId> <artifactId>maven-scr-plugin</artifactId> </plugin> <plugin> <groupId>org.apache.sling</groupId> <artifactId>maven-sling-plugin</artifactId> <configuration> <slingUrlSuffix>/libs/dam/install/</slingUrlSuffix> </configuration> </plugin> <plugin> <groupId>org.apache.felix</groupId> <artifactId>maven-bundle-plugin</artifactId> <extensions>true</extensions> <configuration> <instructions> <Bundle-Category>cq5</Bundle-Category> <Export-Package> com.day.cq5.myhandler </Export-Package> </instructions> </configuration> </plugin> </plugins> </build> <!-- ====================================================================== --> <!-- D E P E N D E N C I E S --> <!-- ====================================================================== --> <dependencies> <dependency> <groupId>com.day.cq.dam</groupId> <artifactId>cq-dam-api</artifactId> <version>5.2.10</version> <scope>provided</scope> </dependency> <dependency> <groupId>com.day.cq.dam</groupId> <artifactId>cq-dam-core</artifactId> <version>5.2.10</version> <scope>provided</scope> </dependency> <dependency> <groupId>com.day.cq</groupId> <artifactId>cq-commons</artifactId> </dependency> <dependency> <groupId>javax.jcr</groupId> <artifactId>jcr</artifactId> </dependency> <dependency> <groupId>org.apache.felix</groupId> <artifactId>org.osgi.compendium</artifactId> </dependency> <dependency> <groupId>org.slf4j</groupId> <artifactId>slf4j-api</artifactId> </dependency> <dependency> <groupId>commons-lang</groupId> <artifactId>commons-lang</artifactId> </dependency> <dependency> <groupId>commons-collections</groupId>
Page 93 of 106
<artifactId>commons-collections</artifactId> </dependency> <dependency> <groupId>commons-io</groupId> <artifactId>commons-io</artifactId> </dependency> <dependency> <groupId>com.day.commons</groupId> <artifactId>day-commons-gfx</artifactId> </dependency> <dependency> <groupId>com.day.commons</groupId> <artifactId>day-commons-text</artifactId> </dependency> <dependency> <groupId>com.day.cq.workflow</groupId> <artifactId>cq-workflow-api</artifactId> </dependency> <dependency> <groupId>com.day.cq.wcm</groupId> <artifactId>cq-wcm-foundation</artifactId> <version>5.2.22</version> </dependency> </dependencies> </project>
4.
Create the package com.day.cq5.myhandler that will contain the Java classes under myBundle/src/main/java: 1. 2. Under myBundle, right-click src/main/java, select New, then Package. Name it com.day.cq5.myhandler and click Finish.
5.
Create the Java class MyHandler: 1. In Eclipse, under myBundle/src/main/java, right-click the com.day.cq5.myhandler package, select New, then Class. In the dialog window, name the Java Class MyHandler and click Finish. Eclipse creates and opens the file MyHandler.java. In MyHandler.java replace the existing code with the following:
package com.day.cq5.myhandler; import import import import import import java.awt.Color; java.awt.Rectangle; java.awt.image.BufferedImage; java.io.IOException; java.io.InputStream; java.io.InputStreamReader;
2.
3.
import javax.jcr.Node; import javax.jcr.RepositoryException; import javax.jcr.Session; import org.apache.commons.io.IOUtils; import org.slf4j.Logger; import org.slf4j.LoggerFactory; import import import import import /**
CQ 5.2 WCM Copyright 1993-2009 Day Management AG
Page 94 of 106
* The <code>MyHandler</code> can extract text files * * @scr.component inherit="true" immediate="true" metatype="false" * @scr.service */ public class MyHandler extends AbstractAssetHandler { /** * Logger instance for this class. */ private static final Logger log = LoggerFactory.getLogger(MyHandler.class); /** * Music icon margin */ private static final int MARGIN = 10; /** * @see com.day.cq.dam.api.handler.AssetHandler#getMimeTypes() */ public String[] getMimeTypes() { return new String[] {"text/plain"}; } public ExtractedMetadata extractMetadata(Node asset) { ExtractedMetadata extractedMetadata = new ExtractedMetadata(); InputStream data = getInputStream(asset); try { // read text data InputStreamReader reader = new InputStreamReader(data); char[] buffer = new char[4096]; String text = ""; while (reader.read(buffer) != -1) { text += new String(buffer); } reader.close(); long wordCount = this.wordCount(text); extractedMetadata.setProperty("text", text); extractedMetadata.setMetaDataProperty("Word Count",wordCount); setMimetype(extractedMetadata, asset); } catch (Throwable t) { log.error("handling error: " + t.toString(), t); } finally { IOUtils.closeQuietly(data); } return extractedMetadata; } // ----------------------< helpers >---------------------------------------protected BufferedImage getThumbnailImage(Node node) { ExtractedMetadata metadata = extractMetadata(node); final String text = (String) metadata.getProperty("text"); // create text layer final Layer layer = new Layer(500, 600, Color.WHITE); layer.setPaint(Color.black); Font font = new Font("Arial", 12); String displayText = this.getDisplayText(text, 600, 12); if(displayText!=null && displayText.length() > 0) { // commons-gfx Font class would throw IllegalArgumentException on empty or null text layer.drawText(10, 10, 500, 600, displayText, font, Font.ALIGN_LEFT, 0, 0); } // create watermark and merge with text layer Layer watermarkLayer; try { final Session session = node.getSession();
Page 95 of 106
watermarkLayer = ImageHelper.createLayer(session, "/var/dam/geometrixx/icons/ certificate.png"); watermarkLayer.setX(MARGIN); watermarkLayer.setY(MARGIN); layer.merge(watermarkLayer); } catch (RepositoryException e) { // TODO Auto-generated catch block e.printStackTrace(); } catch (IOException e) { // TODO Auto-generated catch block e.printStackTrace(); } layer.crop(new Rectangle(510, 600)); return layer.getImage(); } // ---------------< private >----------------------------------------------/** * This method cuts lines if the text file is too long.. * * @param text * text to check * @param height * text box height (px) * @param fontheight * font height (px) * @return the text which will fit into the box */ private String getDisplayText(String text, int height, int fontheight) { String trimmedText = text.trim(); int numOfLines = height / fontheight; String lines[] = trimmedText.split("\n"); if (lines.length <= numOfLines) { return trimmedText; } else { String cuttetText = ""; for (int i = 0; i < numOfLines; i++) { cuttetText += lines[i] + "\n"; } return cuttetText; } } /** * This method counts the number of words in a string * * @param text the String whose words would like to be counted * @return the number of words in the string */ private long wordCount(String text) { // We need to keep track of the last character, if we have two white spaces in a row we dont want to double count // The starting of the document is always a whitespace boolean prevWhiteSpace = true; boolean currentWhiteSpace = true; char c; long numwords = 0; int j = text.length(); int i = 0; while (i < j) { c = text.charAt(i++); if (c == 0) { break; } currentWhiteSpace = Character.isWhitespace(c); if (currentWhiteSpace && !prevWhiteSpace) { numwords++; } prevWhiteSpace = currentWhiteSpace; }
Page 96 of 106
// If we do not end with a white space then we need to add one extra word if (!currentWhiteSpace) { numwords++; } return numwords; } }
4. 6.
Compile the Java class and create the bundle: 1. 2. Right-click the myBundle project, select Run As, then Maven Install. The bundle myBundle-0.0.1-SNAPSHOT.jar (containing the compiled class) is created under myBundle/target.
7. 8.
In CRX Explorer, create a new node under /apps/myApp. Name = install, Type = nt:folder. Copy the bundle myBundle-0.0.1-SNAPSHOT.jar and store it under /apps/myApp/ install (for example with WebDAV). Note The new text handler is now active in CQ5.
9.
In your browser, open the Apache Felix Web Management Console and disable the default text handler com.day.cq.dam.core.impl.handler.TextHandler.
From now on, whenever you upload a txt file into CQ5 under the /var/dam/documents folder, the file is copied into /content/dam/documents, its metadata are extracted and two thumbnails with a watermark are generated.
Page 97 of 106
13 Data Modelling
13.1 Data Modeling - David Nuescheler's Model
13.1.1 Source
The following details are ideas and comments expressed by David Nuescheler. David is co-founder and CTO of Day Software AG, a leading provider of global content management and content infrastructure software. He also leads the development of JSR-170, the Java Content Repository (JCR) application programming interface (API), the technology standard for content management. Further updates can also be seen on http://wiki.apache.org/jackrabbit/DavidsModel.
13.1.3 Seven Simple Rules 13.1.3.1 Rule #1: Data First, Structure Later. Maybe.
13.1.3.1.1 Explanation
I recommend not to worry about a declared data structure in an ERD sense. Initially. Learn to love nt:unstructured (& friends) in development. I think Stefano pretty much sums this one up. My bottom-line: Structure is expensive and in many cases it is entirely unnecessary to explicitly declare structure to the underlying storage. There is an implicit contract about structure that your application inherently uses. Let's say I store the modification date of a blog post in a lastModified property. My App will automatically know to read the modification date from that same property again, there is really no need to declare that explicitly. Further data constraints like mandatory or type and value constraints should only be applied where required for data integrity reasons.
CQ 5.2 WCM Copyright 1993-2009 Day Management AG
Page 98 of 106
Data Modelling
13.1.3.1.2 Example
The above example of using a "lastModified" Date property on for example "blog post" node, really does not mean that there is a need for a special nodetype. I would definitely use "nt:unstructured" for my blog post nodes at least initially. Since in my blogging application all I am going to do is to display the lastModified date anyway (possibly "order by" it) I barely care if it is a Date at all. Since I implicitly trust my blog-writing application to put a "date" there anyway, there really is no need to declare the presence of a "lastModified" date in the form a of nodetype.
13.1.3.1.3 Discussion
http://www.nabble.com/DM-Rule-#1:-Data-First,-Structure-Later.-Maybe.-tf4039967.html
13.1.3.2 Rule #2: Drive the content hierarchy, don't let it happen.
13.1.3.2.1 Explanation
The content hierarchy is a very valuable asset. So don't just let it happen, design it. If you don't have a "good", human-readable name for a node, that's probably that you should reconsider. Arbitrary numbers are hardly ever a "good name". While it may be extremely easy to quickly put an existing relational model into a hierarchical model, one should put some thought in that process. In my experience if one thinks of access control and containment usually good drivers for the content hierarchy. Think of it as if it was your file system. Maybe even use files and folders to model it on your local disk. Personally I prefer hierarchy conventions over the nodetyping system in a lot of cases initially, and introduce the typing later.
13.1.3.2.2 Example
I would model a simple blogging system as follows. Please note that initially I don't even care about the respective nodetypes that I use at this point.
/content/myblog /content/myblog/posts /content/myblog/posts/what_i_learned_today /content/myblog/posts/iphone_shipping /content/myblog/comments/iphone_shipping/i_like_it_too /content/myblog/comments/iphone_shipping/i_like_it_too/i_hate_it
I think one of the things that become apparent is that we all understand the structure of the content based on the example without any further explanations. What may be unexpected initially is why I wouldn't store the "comments" with the "post", which is due to access control which I would like to be applied in a reasonably hierarchical way. Using the above content model I can easily allow the "anonymous" user to "create" comments, but keep the anonymous user on a read-only basis for the rest of the workspace.
13.1.3.2.3 Discussion
http://www.nabble.com/DM-Rule-#2:-Drive-the-content-hierarchy,-don't-let-it-happen.tf4039994.html
13.1.3.3 Rule #3: Workspaces are for clone(), merge() and update().
13.1.3.3.1 Explanation
If you don't use clone(), merge() or update() methods in your application a single workspace is probably the way to go.
CQ 5.2 WCM Copyright 1993-2009 Day Management AG
Page 99 of 106
Data Modelling
"Corresponding nodes" is a concept defined in the JCR spec. Essentially, it boils down to nodes that represent the same content, in different so-called workspaces. JCR introduces the very abstract concept of Workspaces which leaves a lot of developers unclear on what to do with them. I would like to propose to put your use of workspaces to the following to test. If you have a considerable overlap of "corresponding" nodes (essentially the nodes with the same UUID) in multiple workspaces you probably put workspaces to good use. If there is no overlap of nodes with the same UUID you are probably abusing workspaces. Workspaces should not be used for access control. Visibility of content for a particular group of users is not a good argument to separate things into different workspaces. JCR features "Access Control" in the content repository to provide for that. Workspaces are the boundary for references and query.
13.1.3.3.2 Example
Use workspaces for things like: v1.2 of your project vs. a v1.3 of your project a "development", "QA" and a "published" state of content Do not use workspaces for things like: user home directories distinct content for different target audiences like public, private, local, ... mail-inboxes for different users
13.1.3.3.3 Discussion
http://www.nabble.com/DM-Rule-#3:-Workspaces-are-for-corresponding-nodes.-tf4040010.html
13.1.3.4.2 Example
Use
/content/myblog/posts/what_i_learned_today /content/myblog/posts/iphone_shipping
instead of
CQ 5.2 WCM Copyright 1993-2009 Day Management AG
Data Modelling
/content/blog[1]/post[1] /content/blog[1]/post[2]
13.1.3.4.3 Discussion
http://www.nabble.com/DM-Rule-#4:-Beware-of-Same-Name-Siblings.-tf4040024.html
13.1.3.5.2 Example
Let's assume I allow "references" from a document (a) to another document (b). If I model this relation using reference properties this means that the two documents are linked on a repository level. I cannot export/import document (a) individually, since the reference property's target may not exist. Other operations like merge, update, restore or clone are affected as well. So I would either model those references as "weak-references" (in JCR v1.0 this essentially boils down to string properties that contain the uuid of the target node) or simply use a path. Sometimes the path is more meaningful to begin with. I think there are use cases where a system really can't work if a reference is dangling, but I just can't come up with a good "real" yet simple example from my direct experience.
13.1.3.5.3 Discussion
http://www.nabble.com/DM-Rule-#5:-References-considered-harmful.-tf4040042.html
13.1.3.6.2 Example
Let's assume that someone would like to upload an image to a blog entry at:
/content/myblog/posts/iphone_shipping
Data Modelling
and maybe the initial gut reaction would be to add a binary property containing the picture. While there certainly are good use cases to use just a binary property (let's say the name is irrelevant and the mime-type is implicit) in this case I would recommend the following structure for my blog example.
/content/myblog/posts/iphone_shipping/attachments [nt:folder] /content/myblog/posts/iphone_shipping/attachments/front.jpg [nt:file] /content/myblog/posts/iphone_shipping/attachments/front.jpg/jcr:content [nt:resource]
13.1.3.6.3 Discussion
http://www.nabble.com/DM-Rule-#6:-Files-are-Files-are-Files.-tf4040063.html
13.1.3.7.2 Example
use:
/content/myblog/posts/iphone_shipping/attachments/front.jpg
instead of:
[Blog] - blogId - author [Post] - postId - blogId - title - text - date [Attachment] - attachmentId - postId - filename
Data Modelling
+ resource (nt:resource)
13.1.3.7.3 Discussion
http://www.nabble.com/DM-Rule-#7:-IDs-are-evil.-tf4040076.html
right-arrow (on a suggested path) left-arrow (on a suggested path) Enter (on a suggested path) Esc Drag assets, drop on destination Content Window (Edit Mode) - Paragraphs Alt+drag Shift-Click Ctrl-Click Ctrl-C Ctrl-X
Close suggestions layer. The drop action produces a new paragraph; instead of replacing the asset in the destination. Select multiple paragraphs. Select multiple paragraphs. Copy selected paragraph(s). Cut selected paragraph(s). Note: The cut paragraph will not disappear until it has been pasted to the new location.
Paste paragraphs from clipboard. Paste as reference. Delete selected paragraph(s). Delete selected paragraph(s). Force default (browser) context menu.
Link
Code
Link to anchor-points within the current document and/or external sources. Example of programming code. Example of text, or commands, that you type. Example of variable text - you type the actual value needed. An optional parameter. Logging and error messages.
ls *.xml
ls <cq-installation-dir>
ls [<option>] [<filename>]