ForgeRock documentation tools 1.2.0 released

ForgeRock Community Logo It felt good to send the release announcement for the 1.2.0 release of ForgeRock documentation tools, including the forgerock-doc-maven-plugin, sites where we post documentation, and the documentation about documentation. Thanks especially to Lana Frost, Vanessa Richie, Mike Jang, & Peter Major for your good work on this release!

As mentioned on the mailing list, “This release includes the following improvements, new features, and bug fixes,” everything from support for JCite, to boilerplate doc with definitions to release levels and interface stability, to helpful Wiki articles, to a little bit of love for PDFs (though they still do need more).

A formatted copy of the release notes is posted with the sources of the forgerock-doc-maven-plugin on GitHub, where you can also find a README on how to use the plugin.

Releasing Maven Artifacts on Slow Networks

Maven logo Peter Major found this for me. I was running mvn release:perform and failing in the deploy goal, but only for a .jar, not for the POM.

[INFO] --- maven-deploy-plugin:2.7:deploy (default-deploy) @ forgerock-doc-maven-plugin ---
   Uploading: http://maven.forgerock.org/repo/releases/org/forgerock/commons/forgerock-doc-maven-plugin/1.2.0/forgerock-doc-maven-plugin-1.2.0.jar
   Uploading: http://maven.forgerock.org/repo/releases/org/forgerock/commons/forgerock-doc-maven-plugin/1.2.0/forgerock-doc-maven-plugin-1.2.0.pom
   Uploaded: http://maven.forgerock.org/repo/releases/org/forgerock/commons/forgerock-doc-maven-plugin/1.2.0/forgerock-doc-maven-plugin-1.2.0.pom (8 KB at 3.2 KB/sec)
   [INFO] ------------------------------------------------------------------------
   [INFO] BUILD FAILURE
   [INFO] ------------------------------------------------------------------------
   [INFO] Total time: 1:22.027s
   [INFO] Finished at: Thu May 23 13:17:03 CEST 2013
   [INFO] Final Memory: 30M/360M
   [INFO] ------------------------------------------------------------------------
   [ERROR] Failed to execute goal org.apache.maven.plugins:maven-deploy-plugin:2.7:deploy (default-deploy) on project forgerock-doc-maven-plugin: Failed to deploy artifacts: Could not transfer artifact org.forgerock.commons:forgerock-doc-maven-plugin:jar:1.2.0 from/to forgerock-staging (http://maven.forgerock.org/repo/releases): Error transferring file: Error writing to server -> [Help 1]

This was with mvn 3.0.3.

The tcpdump capture showed that the HTTP PUT for the .jar was done without authentication. Artifactory was responding with HTTP 401 before our slow ADSL uplink could finish the request, and the client was not trying again with authentication for the .jar. But the client was trying again with authentication for the much smaller pom.xml. So the pom.xml was successfully uploaded, but the deploy failed because the .jar was not.

It feels odd for the deploy plugin to try an HTTP PUT without authenticating, but it turns out that performing authentication like this requires some preemptive authentication configuration in ~/.m2/settings.xml. That works apparently with mvn 3.0.4 or later.

So I updated the configuration for the release repository and tried again with mvn 3.0.5.

PATH=~/Downloads/apache-maven-3.0.5/bin:$PATH ~/Downloads/apache-maven-3.0.5/bin/mvn release:perform
...
    [INFO] ------------------------------------------------------------------------
    [INFO] BUILD SUCCESS
    [INFO] ------------------------------------------------------------------------
    [INFO] Total time: 2:10.512s
    [INFO] Finished at: Thu May 23 15:19:47 CEST 2013
    [INFO] Final Memory: 31M/358M
    [INFO] ------------------------------------------------------------------------

Glad that’s done.

CRUDPAQ

Maybe you noticed that Matt has been building a foundation for common ForgeRock REST APIs. What makes the APIs common is that they all let you do the same seven kinds of operations.

  1. Create: Add a resource that does not yet exist
  2. Read: Retrieve a single resource
  3. Update: Replace an existing resource
  4. Delete: Remove an existing resource
  5. Patch: Modify part of an existing resource
  6. Action: Perform a predefined action
  7. Query: List a set of resources

When you hear someone from ForgeRock talking about CRUDPAQ, there’s nothing dirty involved. Just a mnemonic device.

(Note: In practice, action operations depend on the resource server, so actions might differ from server to server. Also, some bits of work remain. For example, patch is still to be finished as of this writing.)

Matt put together a JSON Resource Java library. With that he built a JSON Resource Servlet, which implements an in-memory store for your resources. (See the project page for instructions on getting JSON Resource Servlet up and running.) JSON Resource Servlet provides a simple example of how these common REST APIs are likely to look and feel.

Matt included two endpoints by default, /users and /groups. Objects in this version do not have schema, so you can add whatever you like. I’ve played with arrays of SCIM-like users and groups based on the traditional example data we use in the directory server world.

The advantage of this is that it’s all language independent. Take your pick.

After getting a rise out of Jake’s cool work, especially on the OpenIDM UI, I felt it was high time to learn some JavaScript.

Even with my beginner’s confusion about JavaScript, it did not take long to write CRUD and Q functions for use in building a web page. (Creating a page that doesn’t look like I pulled it out of a time capsule from 1996 is a different story, however. My stance with respect to modern web development is 2nd or 3rd order ignorance, depending on the topic.) There are slicker ways to do this, but as you can see, it is not hard to…

Create a resource from an object and a resource URI (ending in the resource ID like /users/bjensen, or more likely /users/e7fa64c0-70dc-47fb-b102-7106ee480421):

function create(object, uri) {
    var xhr = new XMLHttpRequest();
    xhr.open('PUT', uri, false);
    xhr.setRequestHeader("Content-Type", "application/json");
    xhr.setRequestHeader("If-None-Match", "*");
    xhr.send(JSON.stringify(object));
    return xhr.responseText;
}

Read a resource, optionally limiting the resource fields in the response (check the response field “_id” for the resource ID):

function read(uri, fields) {
    fields = (typeof fields === "undefined") ? [] : fields;

    var args = "";
    if (fields.length > 0) {
        args = "?_fields=" + fields[0];
        for (var i = 1; i < fields.length; i++) {
            args = args + "," + fields[i];
        }
    }
    uri = uri + args;

    var xhr = new XMLHttpRequest();
    xhr.open('GET', uri, false);
    xhr.send("");
    return xhr.responseText;
}

Update a resource, for which you need the revision (check the resource “_rev” field):

function update(object, revision, uri) {
    var xhr = new XMLHttpRequest();
    xhr.open('PUT', uri, false);
    xhr.setRequestHeader("Content-Type", "application/json");
    xhr.setRequestHeader("If-Match", revision);
    xhr.send(JSON.stringify(object));
    return xhr.responseText;
}

Delete a resource:

function remove(uri) { // delete is a keyword
    var xhr = new XMLHttpRequest();
    xhr.open('DELETE', uri, false);
    xhr.setRequestHeader("Content-Type", "application/json");
    xhr.send("");
    return xhr.responseText;
}

Query resources. Query lets you do a lot more than this example (filters, sorting, paging, … Scroll down the JSON Resource Servlet page to the section on Querying/listing resources). This one just lists resources. Here containerUri is /users, or /groups:

function queryObjects(containerUri, fields) {
    fields = (typeof fields === "undefined") ? [] : fields;

    var query = containerUri + "?_filter=true";
    var args = "";
    if (fields.length > 0) {
        args = "&_fields=" + fields[0];
        for (var i = 1; i < fields.length; i++) {
            args = args + "," + fields[i];
        }
        query = query + args;
    }

    var xhr = new XMLHttpRequest();
    xhr.open('GET', query, false);
    xhr.send("");

    var allObjects = [];
    if (xhr.status === 200) { // OK
        allObjects = JSON.parse(xhr.responseText);
        if (allObjects.result.length > 0) {
            allObjects = allObjects.result;
        } else {
            allObjects = [];
        }
    }
    return allObjects;
}

Not shown here are actions. The JSON Resource Servlet for example lets you create a resource and let the servlet create the ID. (Hint: Use a POST with ?_action=create to the container URI.)

As you can see, the basic operations are fairly easy to use.

By the way, not all ForgeRock REST APIs will look like this. The REST API for OAuth 2.0 in OpenAM will not, for example, because that API is already clearly defined at the IETF. But there’s a good chance that many APIs will follow this pattern.

forgerock-doc-maven-plugin 1.1.0 released

ForgeRock Community Logo It’s always satisfying to release something, even if you’re just scratching your own itch. Today the ForgeRock doc build plugin reached 1.1.0.

As mentioned on the mailing list, “This release fixes a few issues, and includes a number of improvements that have already been visible in the documentation for a while now.” Basically, it’s something stable before we embark on 2.0.0, which I hope will reach release in the fall next year, and include many significant improvements to doc layout and usability.

JCite and DocBook Together

Peter Arrenbrecht‘s JCite – Java Source Code Citation System – looks like something we could use to keep our DocBook-based developer documentation in sync with Java examples.DocBook Colophon

One of JCite’s strengths is in generating HTML content with <span>s for syntax highlighting. Yet, JCite also supports “plain” citations, pulling in content without extra markup, instead only escaping special characters like <, >, and &.

I tried it with a small sample DocBook <chapter>, chap-jcite.xml. That chapter uses JCite to cite Java code from a Test class. (Sorry, no, I haven’t yet worked out how to plug JCite for DocBook into WordPress.)

 <para>The following example cites an entire Java class.</para>

 <programlisting language="java"
 >[jcp:org.forgerock.doc.jcite.test.Test]</programlisting>

 <para>The following example cites a single Java method.</para>

 <programlisting language="java"
 >[jcp:org.forgerock.doc.jcite.test.Test:--- mainMethod]</programlisting>

When the file is processed, the output contains cited code from Test.java

 <programlisting language="java"
 >package org.forgerock.doc.jcite.test;

/**
 * Test class for trying JCite.
 */
public final class Test {
    /**
     * Print a message, then print args one per line.
     * @param args Program arguments.
     */
  // --- mainMethod
    public static void main(final String[] args) {
        System.out.println(&quot;This is just a test.&quot;);
        for (String arg : args) {
            System.out.println(&quot;\t&quot; + arg);
        }
    }
  // --- mainMethod
}</programlisting>

 <para>The following example cites a single Java method.</para>

 <programlisting language="java"
 >public static void main(final String[] args) {
    System.out.println(&quot;This is just a test.&quot;);
    for (String arg : args) {
        System.out.println(&quot;\t&quot; + arg);
    }
}</programlisting>

Pretty nifty. The ForgeRock doc build plugin gets syntax highlighting elsewhere, so in principle this should work for ForgeRock docs.

Where’s the JCite Maven plugin?

Maven doc plugin: Single chapter output

ForgeRock Community LogoAs Lana mentioned to me the other day, if you make small changes to core docs, it can be painful to wait for the entire documentation set to generate just to see how your changes look in HTML or PDF for example. The fix for DOCS-29 lets you generate output for a single format. You can use the documentSrcName parameter to restrict what gets built to a single file, such as an individual chapter.

The following command generates PDF only for a single chapter of the forgerock-doc-maven-plugin-test project.

$ mvn -DdocumentSrcName=chap-one.xml -Dinclude=pdf clean pre-site

Find the pre-site output under target/docbkx/.

$ ls target/docbkx/pdf/*.pdf 
target/docbkx/pdf/ForgeRock-Bogus-Guide.pdf

Caveats:

  • If you defined <excludes>, then you cannot use <include> in the same configuration.
  • If you have multiple chapters with the same name, this might not work as expected. My guess is the last one wins.
  • The documentSrcName must correspond to a file. You cannot currently generate output for a part of a file, nor for several arbitrary files.

Searching ForgeRock Community Sites

ForgeRock Community Logo Someone said it is hard to find the search box on the *.forgerock.org community sites. Also, the searches were scoped too narrowly to look in the mailing lists.

Before the changes the search box is tucked away in the left menu, and scoped to site:<project>.forgerock.org.

OpenDJ site before the change
OpenDJ Before: Search box in left menu

The new, improved version has a more obvious search box. Searches now cover everything at site:forgerock.org.

OpenAM after improving the search box
OpenAM After: Search box top right, now with colors