Better AEM JSPs part 1: objects

2016-06-21

Tags: JSP AEM

TL/DR;

I remember attending training for AEM back in the CQ5.3-5.4 days. The material spent much of its time going over the mechanics of a hierarchical "NoSQL" data store, as well as intricacies of OSGi that it had little time left for best practices. We would expend so much effort around learning the JCR, Node and Property that we could barely notice all the typed Exceptions those APIs threw. Unfortunately, the training (at least then) didn’t include content around core JSP features such as Tag Libraries or Expression Language. The primary APIs had some also rough spots that didn’t always lend themselves to leveraging these features. The result was the example code/components often had anti-patterns such as over-leveraging scriptlets (code inside the "template" of a JSP), which meant much of our initial code was also ugly. Ugly code has a cost for understanding and maintenance.

Over time, the situation has evolved and improved. By recognizing some of the warts, AEM(c) decided to create new languages & approaches that wouldn’t have the same problems. At the same time, updates to enable cleaner approaches benefit the old languages.

Avoiding Complexity

(especially error handling and exceptions)

The foundational APIs for javax.jcr.* are designed accessing an heirarchical "NoSQL" data store. They certainly are not designed for templating or business logic. javax.jcr.\* encapsulates nodes, sessions and permissions while exposing how any of those can go wrong (just look at the 21 subclasses of RepositoryException). Unfortunately, early training materials and examples (such as /apps/geometrixx/components/asseteditor/head.jsp) show how unsuited these APIs are for JSP development.

Fortunately, Sling APIs came along to improve the state of development. org.apache.sling.api.resource.* is a much friendlier API. To start with, Exceptions are rare to non-existant. Instead of throwing errors, they frequently provide fallback mechanisms to express the business intent when the JCR API would require error or exception handling.

Compare accessing a property value with Sling APIs (in raw Java):

    String getPageTitle(@Nonnull Resource resource) {
        ValueMap properties = resource.getValueMap();
        return properties.get("pageTitle", properties.get("jcr:title", properties.get("navTitle", "")));
    }

is much easier to maintain than JCR APIs:

    String getPageTitle(@Nonnull Node currentNode) {
        try {
            Property titleProp =
                currentNode.hasProperty("pageTitle") ? currentNode.getProperty("pageTitle") :
                    currentNode.hasProperty("jcr:title") ? currentNode.getProperty("jcr:title") :
                        currentNode.hasProperty("navTitle") ? currentNode.getProperty("navTitle") : null;
            if (titleProp != null) {
                return titleProp.getString();
            }
        } catch (RepositoryException ignore) {
            // log problem so you can find in monitoring & hopefully fix (author) soon.
        } finally {
            return ""; // better than returning null and risking NPE. Web is about concatenating strings, anyway! :-)
        }
    }

Focusing on the Intent

"Boilerplate" is the term used for all the code that is for the compiler, not the developer. Functional Programming is the paradigm of declaring what you want instead of how to accomplish a task (compared to Imperative Programming). The benefit of describing what instead of how is clearer intent often with less code. Wouldn’t it be nice to encapsulate a component with a POJO instead of describing how to read the JCR and then transform into objects? Then our views or templates could leverage a simple POJO with clean data instead of accessing the data, verifying & cleaning the data, and then presenting the result.

AdapterFactory was the initial attempt to structure and separate concerns. It architected your component classes to construct your objects from a Resource/ValueMap/SlingHttpServletRequest (or other "adaptables"). As repeated patterns of component classes took form, it became obvious (and desireable) to declare classes as injection containers automatically wired from declared properties (relative to JCR node properties). Thus, Sling Models was born. Instead of imperative code describing how to construct an object, developers can use annotations to declare the mapping to the JCR.

A good comparison of examples of classes is found in the Experience Delivers blog. Their patterns are:

  1. Implement the Use interface

    1. Extend the WCMUsePojo class

  2. AdapterFactory

    1. from Resource

    2. from Request

  3. Sling Models

Conclusion

I appreciate the newer patterns for building classes. But I believe AEM(c) is disingenious when they sell Sightly as faster than JSP development when Java classes must be built and deployed as bundles before the new HTML templates can be built. For one thing, JSPs can leverage the exact same classes that are used to power Sightly. It is also possible to rapid prototype by extracting classes in JSPs and eventually move them to external bundles (with unit tests, of course!)

In the next part of this series, I hope to show how JSPs can look much closer to a template.

Simple SOAP Example

2014-10-23

Tags: groovy SOAP

All I wanted was a JVM-based script exemplifying a simple SOAP call. However, I wasn’t satisfied with their complexity and pieces.

Best practices have established using a contract-first approach is more reliable and resilient. Spring also documented the prototypical Java SOAP client: Consuming a SOAP web service. The example has a clear classes & separation of concerns, but still requires a build file to generate code from the WSDL using JAXB.

My Simple Example: in Groovy

My example breaks the client into 3 parts:

  1. Creating the Request

  2. Get the Response

  3. Extracting Data

Creating the Request

The traditional approach creates an object, then marshalls it (converts object to a string).

String buildRequest(String zip) {
    def writer = new StringWriter()
    def builder = new MarkupBuilder(writer)

    builder.GetCityForecastByZIP(xmlns: "http://ws.cdyne.com/WeatherWS/") {
        ZIP(zip)
    }
    return writer.toString()
}

Groovy’s MarkupBuilder makes it super easy to safely build XML (or HTML). It can handle attributes, escaping content, and even namespaces! The XML is patterned from the WSDL’s Request object manually, or using SoapUI to build it from the WSDL.

Get the Response

Both examples use Spring’s WebServiceTemplate methods.

String callSoapWeather(String body) {
    def msgFactory = new SaajSoapMessageFactory()
    msgFactory.afterPropertiesSet()

    def wsTemplate = new WebServiceTemplate(msgFactory)
    wsTemplate.setDefaultUri("http://wsf.cdyne.com/WeatherWS/Weather.asmx")

    def writer = new StringWriter()
    try {
        wsTemplate.sendSourceAndReceiveToResult(
            new StringSource(body),
            new SoapActionCallback("http://ws.cdyne.com/WeatherWS/GetCityForecastByZIP"),
            new StreamResult(writer)
        )
    } catch (Exception e) { println "ERROR: ${e.message} - ${e.cause}" }
    return writer.toString()
}

Spring’s WebServices and Templates handles calling the SOAP service, callback status and converting the response stream back into a string.

Extracting Data

Instead of unmarshalling (converting a string to an object):

void printResults(String response) {
    final xml = new XmlSlurper().parseText(response)
    def nodes = xml.GetCityForecastByZIPResult
    println "Forecast for ${nodes.City}, ${nodes.State}"

    def format = new SimpleDateFormat("yyyy-MMM-dd")
    nodes.ForecastResult.children().each { forecast ->
        def inDate = new Date().parse("yyyy-MM-dd'T'HH:mm:ss", forecast.Date as String)
        println "${format.format(inDate)} ${forecast.Description} ${forecast.Temperatures.MorningLow} - ${forecast.Temperatures.DaytimeHigh}"
    }
}

Groovy’s XmlSlurper takes the place of traditional JAXB unmarshalling. Instead of mapping XML into Objects, XmlSlurper parses the string into Nodes and GPathResults. As long as the names of the nodes you need don’t change, you can name the path to the data, or even .depthFirst().collect{ it }.findAll{ it.name() == "NODE_NAME" } which allows the path to change and still work.

Conclusion

SOAP doesn’t have to be intimidating on the JVM platform. I hope others find the contrast with the traditional JAXB approach informative. My full working SimpleSoap.groovy is posted as a single file in a gist.


Older posts are available in the archive.