Required skillset to learn CQ5

I just fell over the blog post by Robert Sumner where he describes what the required skillsets are to become a “WEM/WCM architect”, “J2EE integration specialist” and “CQ5 developer” for CQ5.

He states, that before you become an architect, you should have experience in the integration specialist role. Agreed to that. But then for the integration specialist role Robert says:

“J2EE – it’s all about JAVA here….experience with SSO, SEO, integration, databases, web services, and Caching is essential to implementing and delivering a robust WEMs tool.  These folks can learn the CQ5 technology in a day, because Adobe CQ5 is based on standards.”

In my opinion, this is simply wrong. You cannot learn CQ5 in a day, just because it is based on standards. It’s nice, that something is built on standards. But still: You need to learn to work with these standards, learn the APIs and the way they are supposed to be used. You need to learn the Do’s and Don’ts and the best practices. And even if CQ5 is built on standards: There are a lot of proprietary APIs on top of the standards you should at least be aware of.

So my answer to the question “What’s the required skill set” is: “Know HTTP! Know the impact of latency and the importance and ways of caching. Know some web frameworks and start to think in pages and request/response instead of transactions.” And if you know Java: even better!

Performance tests (4): Executing a test scenario

Now that we have prepared test scenarios, we have to execute them. Till here we did only some preparation work (but I cannot stress enough, that you really need to do this step!), but now you need to get your hands dirty. This means:

  • Decide which system you use to execute the test scenario. A developers laptop is usually not sufficient anymore to simulate a production-like scenario.. This information should be already contained in the test scenario description.
  • Implement the test scenario, so it is a machine executable format. Usually you record the specified user activities with a tool, modify them and then execute the recorded behavior using a tool.
  • Get test data. Having always the same test makes the analysis much easier.
  • Inform all parties, that you are running performance tests and that the results are sensible to any other activity on these systems.
  • Run the tests
  • Do the analysis.
  • React accordingly.

Let me point out a few important aspects of this execution. First, the choice of the systems to run the performance tests. I recommend to have them as similar to the production as possible. So, choosing the same hardware platform, same number of systems, same SAN, same content. This makes if much more easier, if someone asks the important question: “That’s all nice, but can we apply the results of this test also to our production environment?”. If you have identical hardware and the identical setup, it does not require much arguments to get to a answer everyone can agree on: “If we would run this scenario on production, we would get the same results”. And that’s a very important step later on when you need to decide about follow-up activities.

Secondly the test data. It is crucial, that if run a test multiple times, that you run it always on the same test data. This is not only required for the functional aspects (your most critical function regarding performance should not fail because of missing test data), but also the test data might impact performance. So it makes a difference, if you test your application on a 20 gigabyte repository or on a 200 gigabyte. repository. I usually recommend to create a copy of the instances before you start the first execution run of a performance scenario; before the execution of the second run, this copy will be restored, so we start the same point. This is important, so can you actually compare the results of multiple test runs.

healthcheck 1.0 now available via public maven repository

Finally we made it. Thanks to Alex the healthcheck binaries are available now in the public sonatype repository. If you have already included the this repository to your pom.xml, you only need to add these dependencies to your pom.xml:

<dependency>
<groupId>de.joerghoh.cq5.healthcheck</groupId>
  <artifactId>core</artifactId>
  <version>1.0.0</version>
  <type>pom</type>
</dependency>
<dependency>
  <groupId>de.joerghoh.cq5.healthcheck</groupId>
  <artifactId>core</artifactId>
  <version>1.0.0</version>
  <type>pom</type>
</dependency>

I also recommend you to add the jmx-extension bundle, as it adds some really useful MBeans.

<dependency>
  <groupId>de.joerghoh.cq5.healthcheck</groupId>
  <artifactId>jmx-extension</artifactId>
  <version>1.0.0</version>
  <type>pom</type>
</dependency>

We will continue the development over at github, we appreciate your feedback.

Performance tests (3): Test scenarios

The overall performance test is usually grouped into smaller test chunks (I call them scenarios), which replicate certain aspects of the daily operation like:

  • normal operation
  • many people login into the system during the start of the business hours
  • your marketing campaign got viral and now huge traffic spikes come over from Twitter/Facebook/G+/…
  • how can your system handles traffic when some are down for maintenance?
  • you are preparing a huge amount of new content on authoring
  • (and many more …)

Collect the scenarios you know you will have, and detail them out. If you have historical data on them, use them. If you don’t have such data, start with rough estimations. You will adjust them afterwards anyway by any feedback of your production system.

A performance test scenario consists at least of these items:

  1. Objectives what should be tested (the “questions” of part 2); this objectives should detailled and clear, usually they are oriented on the aspect of the daily operations you just identified.
  2. A number of test cases, which are executed during the performance test; in most real-life situations multiple different activities are carried out in parallel, and your performance test scenarios should reflect that.
  3. Systems and environments, where the tests are executed and can deliver meaningful results.
  4. Facilities to monitor the systems, which are involved in the test execution; it should be described, which information is considered valuable for this test scenario and which should preserved for analysis.
  5. Instructions how to interpret the monitoring data gathered throughout the test execution.
  6. Instructions how the test should be executed.
  7. In the end there should be a clear answer if the objectives have been met.

All of the aspects should be covered. And now it is clear, why good performance test is nothing which can done without preparation and within 1 day. Such adhoc tests usually never deliver proper results, because they heavily focus on the test execution and less on proper preparation of the test cases and the interpretation of the results.

Even if you plan much more scenarios than you will ever execute: Just thinking of them, planning and defining them often gives you valuable input for your application design. As in many cases functional test planning makes you think about system, about expected behaviour and error handling. It’s the same here.

(Applying the TDD mechanisms to performance tests would be an interesting exercise …)

Performance tests (part 2): What can you expect from a performance test?

Performance tests sometimes have a myth around them, depending on the personal experience people have made with them. For some it’s just a waste of time and effort, because the last test they conducted has not delivered any value. For others it’s the best since sliced bread.

With performance tests it’s the same as with every test: You need to ask a question and model an appropriate test case, then you get an answer for it. A performance test cannot tell you things about your system, which you have not asked. Especially it cannot give you any guarantee, that you system is rock-solid and fast (even if you ask this question :-))
It is not a silver bullet for any problem. But it is an important step to a point where you can start to trust your system to function properly.

So, what’s this “asking”? In Performance testing you ask questions by designing and executing a test case. When your test case is like this “Execute 100 requests to this specific URL with 10 concurrent threads, the response should be received within 500 milliseconds, no errors are allowed”, the question could be like this “Can my system copy with 10 concurrent users and respond to them within 0.5 seconds with no  errors”. The execution of the performance test can then answer the question with “yes” or “no”, depending on the outcome.

If the outcome is “no”, we obviously have to change this and work on our systems and our code to get the answer we are aiming for: “ok”. But our success is limited then. Even in the “ok” case we cannot infer, that with 15 concurrent users the system is still working ok, but slower than with 10 concurrent requests. This is an assumption we often do because we have only a limited set of validated results, and technically we should validate them all. So every test case answers exactly one question, gives us only one piece of information about the performance behavior of the system. For all other questions we have to create different performance test cases. (There will be a follow-up article on this topic…)

So, as a conclusion, the quality of the results of your performance result is directly depending on the questions you ask. For this reason you should invest a good amount for the preparation of your performance tests to define the right questions.

JCR sessions and CQ5

The JCR 2.0 specifications says about sessions:

A user connects to a repository by passing a set of credentials and the name of the workspace that the user wishes to access. The repository returns a session which binds the user to the requested persistent workspace with a level of authorization determined by that user’s credentials. A session is always bound to exactly one persistent workspace, though a single persistent workspace may be bound to multiple sessions.

In the implementation of Jackrabbit/CRX it means that the session enforce authorization; if a user is not authorized to see nodes, the session will not expose them to the user. It’s just as they are not there. Workspace handling is in the case of CQ5 not really relevant, as only the “crx.default” workspace is used.

But what does this mean for your work with CQ5?

  • So first of all, sessions are an integral concept of security within CQ5. A normal user session is different from an admin session. In a user session normally less nodes than in an admin session are visible. You cannot just switch the user context within a session, but you create a new one.
  • In an admin session you are not restricted at all, you can do everything.
  • In the context of requests to templates and components, you will work with an authenticated session (or anonymous sessions in the standard publish case). Sling authenticates the request and provides you an appropriately authenticated session, and closes this specific session when the request processing is done. Do not close this session!
  • In a request scope you normally should not need to create a new session. You should leverage the session associated with the request.
  • Not closing a single session isn’t a problem, but not closing many session will cause a serious memory leak.
  • Sessions are cheap. You can create as many of them as you need. So it’s perfectly ok to open a session to change a few properties and then close that session again. Try to have sessions as short-lived as possible.
  • The only exception from this rule are sessions, in which you have registered a JCR observation listener. But use these sessions only for reading. If you need to write to the repository in an observation listener, create a new session for these write operations.
  • In most cases Unix daemons work in the context of a specialized user to limit the impact of a security breach through this daemon. You should act alike and use specialized user sessions if you work with JCR sessions. For 99% of all usecases you should not use an admin session!
  • If you want to run a session with a less privileged user than the admin, you should use the impersonation feature of JCR. Do not hardcode any user password in your code. This code fragment shows how you can use impersonation to create a session with a different user than admin, but without hardcoding the password of that user:
private static final RUNAS_USER="technical_user";
@Reference
SlingRepository repo;
Session adminSession = null;
Session userSession = null;
try {
  Session adminSession = repo.loginAdministrative(null);
  userSession = adminSession.impersonate(new SimpleCredentials(RUNAS_USER,"".toCharArray()));
  adminSession.logout();
  adminSession = null;
  doSomethingWith(userSession);
} catch (RepositoryException e) {
  // report exception
} finally {
  if (adminSession != null) {
    adminSession.logout();
  }
  if (userSession != null) {
    userSession.logout();
  }
}

Update March 19th 2013: My colleague Alex Klimetschek recommended me to add this statement: “Admin sessions sound so useful. But they are dangerous!”
Update April 9th 2013: SimpleCredentials take in the constructor a char array as password, not a String. Thanks Anand.

Logging best practices

In between all the hyping of the CQ5 healthcheck I want to tell you some bits which has more impact on your daily life as a developer. Today I want to tell you some bits and pieces about logging.

Logging is one of the unloved children of a web project. It’s mostly never stated in the project requirements, but every developer adds logging statements. Everybody has some ideas, what should be logged, but it is never explicitly defined. While I base my recommendations on CQ5 projects, they can be applied widely. And for Java there are — of course — lot of great postings out there, which have tips and tricks on that topic. I just found 10 tips for proper application logging. Sounds pretty good.

But here goes my personal list of best practices (all of them pretty obvious, right?)

  • Use the SLF4J logging framework, as it is the standard logging for sling; there’s no need to introduce another logging framework.
  • Do not use the log levels INFO,WARN and ERROR for debugging your code during development. You won’t have the time to fix them, and then you will pollute the production log with your debugging statements. Your operation people will hate for that, because the CQ5 standard loglevel is “INFO”.
  • Instead use the loglevel “DEBUG” and a special logging configuration for your development environment, which logs your debug statements.
  • Cleanup your debug statements when you are done with development. In production environment I recommend to setup logging on level DEBUG if there are problems with some parts of the application. The last thing I want to see are statements like “loop1”, “Inside for-loop” and “1234” (yes, I have seen them.)
  • Ask yourself: Does a piece of code, which does not have logging statements, really perform any function? Even it is perfect written code with no bugs it is sometimes interesting, what information are processed. So every code should contain debug statements.
  • Stacktraces are sometimes a valuable asset. Which also means, that not always a full stacktrace is required.
  • And the most important: Do not use “System.out.println()”!

If you ask yourself “What should I log”, change perspective. Just imaging that someone strongly assumes an issue in your code. What information do you need to investigate on this? — Add this information in proper DEBUG statements.

So, that’s for today’s lesson. Stay tuned! CQ 5.6 is coming …

Meta: What happend in 2012

2012 was a very successful CQ5-year for me (and I hope also for you). The CQ 5.5 release early in 2012 brought interesting new features (mostly notable: the new hotfix policy) and also interesting projects. I worked with some great people on these projects.

I also “revived” this blog with a number of new blog entries, which seem pretty popular. Because of you! So many thanks to all of my readers. A wide audience (and feedback) keeps me motivated to blog for more topics regarding CQ5.

In 2012 I wasn’t able to attend any conference. I will change this for 2013, so maybe you can meet me in person, but currently there aren’t plans made yet.

So, I wish you and your families a happy and successful year 2013.

CQ5 coding patterns: Sling vs JCR (part 1)

CQ5 as a complex framework is built on top of various other frameworks, on the server-side the most notably ones are JCR (with its implementation Apache Jackrabbit) and Apache Sling. Both are very powerful frameworks, but both of them have some overlap in functionality:

In these 2 areas you can work with both frameworks, and achieve good results with both. So, the question is, in what situation should you prefer Sling and in what situation pure JCR.

First, and I hope you agree here, in 99% of all cases use the an abstracted framework is recommended over the use of concrete technology (everybody uses JDBC and noone a direct database interface for e.g. MySQL) . It usually offers more flexibility and an easier learning cure. Same here. While on pure JCR you only work with raw repository structures (nodes and properties), the Sling resource abstraction offers you easier handling (no need to deal with the repository exceptions any more) and much more options to interact with you business objects and services.

As an example let’s assume, that we need to read the title of CQ page /content/geometrixx/en/services. Using the JCR API it would look like this:

String readTitle (Session session) {
  Node page = session.getNode("/content/geometrixx/en/services");
  Node jcrcontent = page.getChild("jcr:content");
  Property titleProp= jcrcontent.getProperty ("title"):
  String title = titleProp.getValue().getString();
  return title;
}

This is a very small example, but it shows 3 problems:

  • We need to know, that all CQ page properties are stored on the jcr:content node below the page
  • the title of the page is encoded in the property “title”.
  • Properties are not available immediately as basic types, and need to be converted from Properties to a Value to our expected type (String)

The same example with Sling:

String readTitle (ResourceResolver resolver) {
  Resource r = resolver.getResource(/content/geometrixx/en/services");
  Page page = r.adaptTo(Page.class);
  String title = page.getTitle();
  return title;
}

We don’t need to deal with the low-level information (like the jcr:content node) and properties, but we use the appropriate business object (a CQ page object), which is available out of the box and offers a better level of abstraction.

On a Sling resource level we also a bunch of helpers available, which offer some great benefits over the use of plain nodes and properties:

  • * the adaptTo()  mechanism allows to convert a resource into appropriate objects representing a certain aspect of this resource, for example:
     
     LiveCopyStatus lcs = resource.adaptTo (LiveCopyStatus.class);
    PageManager pm = resource.adaptTo (PageManager.class);

    see http://localhost:4502/system/console/adapters for a (incomplete?) list.

  • The ValueMap is abstracting away the Property type, type conversions are then done implicitly.
  • And likely many many more.
  • And if you ever need to deal with JCR directly, just use
    Node node = resource.adaptTo(Node.class);

So, there are many reasons to use Sling instead of the JCR API.

CQ Exams

In the past months Adobe has released 2 exams for CQ5 developers:

Both exams cover a broad range of topics regarding CQ5 and its building blocks. For most developers surprising, also sysadmin related questions are asked, like details on the dispatcher configuration. The topic list in the referenced PDFs are quite comprehensive and give you some good overview which areas are covered by the questions. Be prepared to answer some questions down to the property level…  And just as a warning: You need practice experience with CQ5, from my point of view you cannot pass with just having attended all trainings!

I wish you all, who want to take that exam, good luck. It’s doable.