The weight of a property name in AEM

Jackrabbit 2.x / CQ5

Back in Jackrabbit 2.x, and therefore in CQ/AEM 5.x, everything was indexed by default other than you stated otherwise.

This translated that every time you run a query, Lucene was there for you serving an indexed answer.

In this scenario it didn’t really matter what property name you used for you application or if you defined additional node types.

This had the advantage that everything was indexed and therefore an index was almost always there serving your query and you didn’t have to think about it.

On the other hand we all know that the bigger the index is, the slower it will be in serving you the result set, as it will simply have to analyse more data.

Jackrabbit Oak / AEM6

Nowadays Apache Jackrabbit Oak, aka Jackrabbit 3.x, is the foundation of AEM6.

Opposed to JR2, in Oak almost nothing is indexed by default. Which means that if you would take a vanilla Oak and run a query, you have very good chances you’re going to traverse the repository (depending on your query).

This has the advantage that you can create very dedicated indexes that will overall perform better as they will be as tailored as possible to your query.

The disadvantage are that you’ll have to define each index and that you’ll have to know how fine tune your queries for getting the most out of this approach.

Not going deeply into the configuration of each individual available index type I think the two main properties, you’ll end-up tuning for better performances are

  • propertyNames
  • declaringNodeTypes

the first one will define what property your index is going to index while the second will restrict the index to a specific node type. In other words the condition for a node to be included into an index are

$nodetype in ($declaringNodeTypes) AND $property = $propertyNames

caveats

  • indexes on more than one property are not supported (yet)
  • an index cannot serve conditions where you ask something like WHERE property IS NULL.

This take us to the very topic of this post: be careful on how you use your property or structure your queries.

Remember the rule: the smaller the index the more efficient the query.

Let’s see how important is a property and a node type with an example then.

If you have a custom application in which you want to extract nodes after a specific date, a way of doing so would be

SELECT * FROM [nt:base]
WHERE [jcr:lastModified] >= CAST('...' AS DATE)

this query is very bad. It can’t really makes use of any index.

Let’s say you create an index on jcr:lastModified. The index itself will be almost as big as the repository as by default in AEM (almost?) every node as mix:lastModified.

A better way would be

SELECT * FROM [nt:base]
WHERE [myLastModified] >= CAST('...' AS DATE)

this will allow you to define an index on the property mylastModified which you’ll know it will contain only your application data. But we can get even better.

Let’s assume you have a very sparse and large content structure so you can’t apply path filters and you don’t want on the other side to create tons of myLastModified for addressing different aspects of your information.

Let’s assume then, for sake of example, that you categorise your data into:

  • comments
  • news
  • articles.

What you could do is create three different node types:

  • my:comments
  • my:news
  • my:articles

now you can define three different, very dedicated indexes

  • declaringNodeTypes = my:comments AND propertyNames = myLastModified
  • declaringNodeTypes = my:news AND propertyNames = myLastModified
  • declaringNodeTypes = my:articles AND propertyNames = myLastModified

One eventual query will look like

SELECT * FROM [my:comments]
WHERE [myLastModified] >= CAST('...' AS DATE)

Actually in the example above, assuming your nodes comes with mix:lastModified, as soon as you create a custom node type you could have simply used the jcr:lastModified date as they will be (I expect) the same size. You can change the exercise above with any property name like: colours, size, tags, etc.

References

Advertisements

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

How many CQ5 concurrent users?

Defining the concept of concurrent user in the web world is difficult and it’s even more difficult to do it in CQ as it doesn’t keep any session informantion. Technically speaking I define two users as concurrent when a request from user A has not finished yet that the one from B starts.

Don’t know if it’s possible to achieve such information just by looking at CQ logs but the analyse-access tool help you in the analysis of the access.log files that CQ produces giving you some numbers in a very handy markdown format that can be then converted to PDF for presenting it to the business.

References:

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.