What’s my CQ WCM mode?

CQ offers you 4 different type of WCM modes: edit, preview, design and disabled. The first three are actually different modes while the forth is when none of them is available and, at the end, always represent the situation on the publish site.

Differentiate on the Java side is very easy as it provides java API and it provides Javascript API for doing it as well. Nevertheless the same object that gives you the mode is not (and should not be) available on the publish which will always end in ifs here and there.

This script should help you and it should be possible to drop it as part of your clientlibs and ready to be used for he use case.

Something very simple that hopefully will help your daily life. 🙂

https://github.com/davidegiannella/cq-misc/blob/master/EditMode.js

CQ5/OSGi reference a unique service implementation

You should never ever do it. If you find yourself in the need of this; there’s something extremely wrong in your code. Nevertheless I found myself in needing it for some old legacy code that was almost impossible to fix in a reasonable time.

The question is: how can I reference a specific implementation of a service/component in an OSGi (therefore CQ5 as well) environment?

In the component, where you need to reference the implementation you can specify something like the following

@Reference(target="(component.name=com.foo.BarImpl)")
Bar bar;

In the component implementing the service you’ll have something like

@Component(immediate=true, metatype=false, name="com.foo.BarImpl")
@Service
class BarImpl implements Bar{
...

By default the framework will assign the fully qualified class name as component name. I prefer to specify it for making the code more readable and no one prohibit you to specify any arbitrary string like mickey mouse or goofy as component name.

Reference:

Customising CQ5’s SiteAdmin actions

You could have the need to customise the actions available via the siteadmin interface in CQ

For better understaing the one highlighted in the below screenshot

Screen shot 2013-02-28 at 16.04.10

to do so you simply have to copy the

/libs/wcm/core/content/siteadmin/actions

as

/apps/wcm/core/content/siteadmin/actions

having care of recreating the correct folder structure and node types.

here a json extract

{

    "jcr:createdBy": "admin",
    "jcr:created": "Thu Oct 18 2012 16:55:43 GMT+0100",
    "jcr:primaryType": "nt:folder",
    "core": {
        "jcr:createdBy": "admin",
        "jcr:created": "Thu Oct 18 2012 16:55:43 GMT+0100",
        "jcr:primaryType": "nt:folder",
        "content": {
            "jcr:mixinTypes": [
                  "rep:AccessControllable"
             ],
             "jcr:createdBy": "admin",
             "jcr:created": "Thu Oct 18 2012 16:55:43 GMT+0100",
             "jcr:primaryType": "sling:Folder",
             "siteadmin": {
                "xtype": "siteadmin",
                "sling:redirect": false,
                "sling:resourceType": "cq/ui/components/widget",
                "jcr:mixinTypes": [
                   "cq:Console"
                ],
                "jcr:title": "CQ5 WCM",
                "consoleDescription": "Create and manage multiple websites.",
                "iconClass": "siteadmin",
                "jsLibs": [
                   "cq.wcm.admin"
                ],
                "sling:vanityPath": "/siteadmin",
                "consoleTitle": "Websites",
                "jcr:primaryType": "cq:Widget",
                "sling:vanityOrder": 300,
                "actions": {
                   "jcr:primaryType": "nt:unstructured"
                   //........
                   // here all the actions as subnodes
                   //........
                }
            }
        }
    }
}

Then you can simply customise the action you want: for example you could change the target, the conditions, the text or even the handler if you implement your own one.

Following an extract of the “Activate” menu (the OOTB one). I find each attribute self-explainatory.

"activate": {
    "iconCls": "cq-siteadmin-activate-icon",
    "cls": "cq-siteadmin-activate",
    "context": [
      "toolbar"
    ],
    "jcr:primaryType": "nt:unstructured",
    "split": true,
    "text": "Activate",
    "menu": {
      "jcr:primaryType": "nt:unstructured",
      "activateNow": {
        "isDefaultAction": true,
        "handler": "CQ.wcm.SiteAdmin.activatePage",
        "cls": "cq-siteadmin-activate-now",
        "conditions": [
          "CQ.wcm.SiteAdmin.hasAnySelection",
          "CQ.wcm.SiteAdmin.notLocked"
        ],
        "context": [
          "toolbar",
          "contextmenu"
        ],
        "target": "CQ.wcm.SiteAdmin.getAnyTarget",
        "jcr:primaryType": "nt:unstructured",
        "text": "Activate"
      },
      "activateLater": {
        "privileges": [
          "replicate"
        ],
        "handler": "CQ.wcm.SiteAdmin.scheduleForActivation",
        "cls": "cq-siteadmin-activate-later",
        "context": [
          "toolbar"
        ],
        "conditions": [
          "CQ.wcm.SiteAdmin.hasAnySelection",
          "CQ.wcm.SiteAdmin.notLocked"
        ],
        "target": "CQ.wcm.SiteAdmin.getTargetFromList",
        "jcr:primaryType": "nt:unstructured",
        "text": "Activate Later..."
      }
    }
}

if you instead just need to hide/show some commands on certain groups of users, you won’t need to custimise anything, just play with ACL! (See reference).

Once you overlayed you could realise that your changes are not reflected by the UI. This is done by the sling:vanityOrder. As
/siteadmin is a vanity path pointing to wcm/core/content/siteadmin. The /libs one are picked up. The default value (as of 5.5) is 300. Just update the one under /apps to a greater value. 301 is enough. As practice I like to have my vanitypath order as 400+ though.

Reference

Where’s my welcome page? (CQ5)

It could happen that on CQ5.5 SP2 after restarting the instance you see the CRX welcome page and not the CQ one.

Screen shot 2013-04-08 at 14.24.12

This is due to the fact that within the repository there are two Sling vanity paths both referencing ‘/welcome’. The sling:VanityOrder is 200 for CQ and 900 for the CRX one. The higher wins.

you can find the nodes by doing a search in CrxDE Lite.

SELECT * FROM [nt:base] AS s WHERE s.[sling:vanityPath] = '/welcome'

To solve once and for all the issue I remove the sling:vanityPath property from /libs/crx/core/content/welcome. Another option could be by changing the vanityOrder to something lower than 200.

It should not happen in 5.5 SP2.1 but in case this is how I went around it.

AEM/CQ5 AuthenticationSupport service missing

My computer crashed and on restart my local instance was not working property (blank pages). Looking at the error.log there was

org.apache.sling.engine.impl.SlingHttpContext handleSecurity: AuthenticationSupport service missing. Cannot authenticate request.

After a quick look at the felix console and having seen all the bundles up and running I went to reading backwards the error.log. I saw that during the start-up Lucene was failing to start and therefore the repository was not initialized correctly.

I managed to have my local instace back to work by having CQ fully regenerate my Lucene indexes.

See How to check and repair search index inconsistencies (Completely rebuild the index)

Removing the design icon from SideKick in CQ5

When you set-up a proper website management in large organisations you’ll end up in having two main groups: designers and content editors.

Normally you want the designers to be a more powerful content editors; with added functionality like selecting which components you can use for contributing the pages.

In order to remove the “design icon” from the Sidekick for a specific group/user you simply have to act on ACL and remove everything but Read permissions on /etc/designs.

Having so

               Read Modify Create Delete R/ACL E/ACL Repl.
/etc/designs    V     x      x      x     x      x    x

Installing big packages in CQ5/CRX

If you have to install big packages in CQ5 it can be cumbersome. Uploading 2GB even locally take some time and the browsers uses memory. Here’s a nice workaround/solution.

cp ~/my-big-package.zip /path/to/cq/crx-quickstart/install

(create the install directory if not there)

monitoring the error.log you’ll see that OsgiInstallerImpl is monitoring that directory and will install the package.

I prefer to delete the package once the installation is completed but it’s not mdandatory.

If you’re installing a big set of DAM remember to disable the DAM workflows from the workflow launcher.

As installing packages is resource intensive, if you’re doing it on a live instance it’s better to plan and disconnect it for not causing disruption.

CQ5 Maven Archetype

Add the Adobe profile in your ~/.m2/settings.xml

    <profile>
      <id>adobe-public</id>
      <activation>
        <activeByDefault>false</activeByDefault>
      </activation>
      <properties>
        <releaseRepository-Id>adobe-public-releases</releaseRepository-Id>
        <releaseRepository-Name>Adobe Public Releases</releaseRepository-Name>
        <releaseRepository-URL>http://repo.adobe.com/nexus/content/groups/public</releaseRepository-URL>
      </properties>
      <repositories>
        <repository>
          <id>adobe-public-releases</id>
          <name>Adobe Basel Public Repository</name>
          <url>http://repo.adobe.com/nexus/content/groups/public</url>
          <releases>
            <enabled>true</enabled>
            <updatePolicy>never</updatePolicy>
          </releases>
          <snapshots>
            <enabled>false</enabled>
          </snapshots>
        </repository>
      </repositories>
      <pluginRepositories>
        <pluginRepository>
          <id>adobe-public-releases</id>
          <name>Adobe Basel Public Repository</name>
          <url>http://repo.adobe.com/nexus/content/groups/public</url>
          <releases>
            <enabled>true</enabled>
            <updatePolicy>never</updatePolicy>
          </releases>
          <snapshots>
            <enabled>false</enabled>
          </snapshots>
        </pluginRepository>
      </pluginRepositories>
    </profile>
  </profiles>

Creating a multi-module project:

mvn archetype:generate -DarchetypeGroupId=com.day.jcr.vault \
 -DarchetypeArtifactId=multimodule-content-package-archetype \
 -DarchetypeVersion=1.0.0 \
 -DarchetypeRepository=adobe-public-releases \
 -P adobe-public

Check about any update to the archetypeVersion.

For not specifying the profile at every mvn command add to the ${project}/pom.xml (the parent one). This is no longer needed with archetype 1.0.2+

   <repositories>
     <repository>
         <id>adobe-ext.hoc</id>
         <name>Adobe External Central Repository</name>
         <url>http://repo.adobe.com/nexus/content/groups/public</url>
     </repository>
   </repositories>
   <pluginRepositories>
      <pluginRepository>
          <id>adobe-public-releases</id>
          <name>Adobe Basel Public Repository</name>
          <url>http://repo.adobe.com/nexus/content/groups/public</url>
          <releases>
              <enabled>true</enabled>
              <updatePolicy>never</updatePolicy>
          </releases>
          <snapshots>
              <enabled>false</enabled>
          </snapshots>
      </pluginRepository>
   </pluginRepositories>

In ${project}/pom.xml check the content-package-maven-plugin pluging version. For example the content-package plugin in the archetype is 0.0.13 but as at 10th September 2012 the latest one is 0.0.19

To install everything execute from the root project

sampleapp$ mvn install -P autoInstallPackage

To install only the bundle

sampleapp/bundle$ mvn sling:install

To install only the content package

sampleapp/content$ mvn install -P autoInstallPackage

Adding some exclude filtering to the contet package to avoid any spurius includes.

In sampleapp/content/pom.xml replace the exclude section with the
following

<excludes>
    <exclude>**/.vlt</exclude>
    <exclude>**/.vltignore</exclude>
    <exclude>**/*.iml</exclude>
    <exclude>**/.classpath</exclude>
    <exclude>**/.project</exclude>
    <exclude>**/.DS_Store</exclude>
    <exclude>**/target/**</exclude>
    <exclude>libs/**</exclude>
</excludes>

Optional step

Personally I don’t like a package name like “sampleapp-content-x.y.z”
as I’m actually deploying a codebase and not content. So I find it a
bit misleading. In order to have the package named as
“sampleapp-codebase-x.y.z” in the sampleapp/content/pom.xml in the
build->plugin->configuration for the content-package-maven-pluing add
the name and finalName definition as following

<plugin>
  <groupId>com.day.jcr.vault</groupId>
  <artifactId>content-package-maven-plugin</artifactId>
  <extensions>true</extensions>
  <configuration>
    <name>sampleapp-codebase</name>
    <finalName>sampleapp-codebase</finalName>
    <failOnError>true</failOnError>
...

Maven import

if you’re using CQ 5.5+ you can avoid checking and importing each dependency version by using the com.day.cq:cq-quickstart-product-dependencies dependency in parent pom.

JSP Support in Eclipse

Don’t forget to add the JSP support for eclipse by following: How to work with JSP.

In eclipse then by converting the project to a faceted, dynamic web project and with the proper context root path you’ll have the proper JSP support. Don’t forget to delete the rubbish that eclipse puts in when converting to a dynamic web project.

Screen Shot 2013-10-16 at 12.35.55

Screen Shot 2013-10-16 at 12.36.14

References

http://dev.day.com/docs/en/cq/current/core/how_to/how_to_use_the_vlttool/vlt-mavenplugin.html

CQ & Sling servlets: resourceType

Last time we see how to use Sling servlets with old legacy URL. Today we’ll see how to create Sling Servlets in the Sling-way: using resourceType.

Scenario

We want a component that can be dragged into a parsys. With a form that submit data to a sling servlet. Then the servlet will do the operations required.

Process

Let’s create the component following the CQ guidelines for making it drag-droppable into a parsys (allowedParents): geometrixx/components/test003. The test003.jsp will look like the following:

<%@include file="/libs/foundation/global.jsp"%>
<form name="frm" method="post" action="<c:out value="${resource.path}" />.c">
    <input type="submit" />
</form>

This JSP will answer at a GET http call showing the form. In order to use, create a content page and drag the component into a parsys.

Now it’s time to create the servlet. As usual you’ll have to register it using some felix annotations. The following servlet will be used when posting (HTTP POST) to a resource of type geometrixx/components/test003 with an extension of “c”.

package com.samples.sling;

import java.io.IOException;
import javax.servlet.ServletException;
import org.apache.sling.api.SlingHttpServletRequest;
import org.apache.sling.api.SlingHttpServletResponse;
import org.apache.sling.api.servlets.SlingAllMethodsServlet;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

/**
 * @scr.component immediate="true" metatype="false"
 * @scr.service interface="javax.servlet.Servlet"
 * @scr.property name="sling.servlet.methods" values.0="POST"
 * @scr.property name="sling.servlet.resourceTypes" values.0="geometrixx/components/test003"
 * @scr.property name="sling.servlet.extensions" values.0="c"
 */

public class ResourceTypePostServlet extends SlingAllMethodsServlet {
   private static final long serialVersionUID = 8795673847499208743L;
   private final static Logger logger = LoggerFactory.getLogger(ResourceTypePostServlet.class);

   @Override
   protected void doPost(SlingHttpServletRequest request, SlingHttpServletResponse response) throws ServletException, IOException {
      logger.debug("ResourceTypePostServlet::doPost()");
      response.setContentType("text/plain");
      response.getOutputStream().print("Hello ResourceTypePostServlet World!");
   }
}

We used the sling.servlet.methods to specify which HTTP method the servlet listen to, the sling.servlet.resourceTypes to specify all the resource types is should listen to and the .extensions if you wish to specify an extension.

Remember that if you specify a sling.servlet.paths, resourceTypes, extensions and selectors will be ignored.

Now build the bundle and refresh the previously created content page (should not necessary actually). If you click on the “submit” button you’ll see the Hello World.

References: