IBM Connections API tip – override Content-Type header

When working with the IBM Connections REST API all responses are returned with the application/atomsvc+xml Content-Type which makes it not show up natively in the browser (or at least in Firefox). A quick solution is the install the Force Content-Type extension and change the Content-Type to text/xml on the fly to make the result show up in the browser. Rules are quick and easy to define.

On plug-ins, features, update sites and extension.xml files…

I’m receiving quite a few e-mails asking questions about features, plug-ins, update sites and extension.xml files and how they relate so I thought I would try and clarify things.

Term Description
Plug-in The smallest unit of code you use to create functionality for an Eclipse based client. This is where the actual Java code is.
Feature Used to package and bundle plug-ins together. Features are thin wrappers for plug-ins and is basically a single file called feature.xml. You can bundle multiple plug-ins into a single feature. When installing code into Notes you actually install the features which in turn point to the plug-ins to copy to the client. You can only manage features through the Notes “code UI” (File/Application/Application Management) though you can install code into the platform by simply copying the plug-ins into the appropriate directories in the file system. This is not recommended… 🙂
Update site Update sites are used to deploy features to clients. An update site is simply a directory containing a

  • “plugins”-directory containing a jar-file per plug-in
  • “features”-directory containing jar-file per feature
  • site.xml file describing which features and plug-ins (and in what versions) are available on that particular update site

When an Eclipse based client contacts an update site it reads and parses the site.xml file to discover what’s available there.

Update Sites may be remote or local. A local update site is a directory on a local hard drive or LAN drive with the above structure or a zip-file with the above structure. An update site may also be remote and may be read using HTTP (any server will do) or it may be read using NRPC if you’re using a Notes 8+ client. When using NRPC you use the Update Site Notes database template.

extension.xml These files are used when installing code using the MyWidgets sidebar plug-in and is a shorthand for manually installing code. There is no magic at work here. When you drop an extension.xml file onto the sidebar panel the following steps are performed:

  1. The extension.xml file is parsed and verified to be a valid XML file
  2. The features to be installed are located and a dependency graph is assembled so any required features are identified
  3. The update site address specified in the extension.xml file is contacted and each missing feature in the dependency grapg is attempted installed “bottom up”
  4. The client is restarted

Building XPath expression from XML node

When programmatically dealing with large XML (or DXL) documents it is often beneficial to be able to indicate, for logging or similar, which node the processing stopped at or where the “thing” you are logging was found. The simplest way to do this for XML is using XPath. The code below is from a library I wrote and constructs a XPath expression to the org.w3c.dom.Node supplied to the method.

Consider a XML document like the one below and the below table. The left column shows the title we supply to the method and the right column the returned XPath. Notice how the method will try to use “known” attributes to address the specific node (id/name attribute) to make the XPath more readable. If no “known” attribute is found we fall back to the sibling index.

Supplied node XPath
Title node of “Harry Potter and the Chamber of Secrets” bookstore/book[@id=’2′]/title[1]
Second tag node of “Harry Potter and the Prisoner of Azkaban” bookstore/book[@id=’3′]/tags[1]/tag[2]

If you combine this with a nice logging engine like log4j you have a robust solution for reproducing parsing issues.

Use to your heart’s content…

<?xml version="1.0" encoding="iso-8859-1" ?>
<bookstore>
  <book id="1">
    <title>Harry Potter and the Philosopher's Stone</title>
    <isbn>0747532745</isbn>
    <tags>
      <tag>children</tag>
      <tag>stone</tag>
    </tags>
  </book>
  <book id="2">
    <title>Harry Potter and the Chamber of Secrets</title>
    <isbn>0747538484</isbn>
    <tags>
      <tag>children</tag>
      <tag>secrets</tag>
    </tags>
  </book>
  <book id="3">
    <title>Harry Potter and the Prisoner of Azkaban</title>
    <isbn>0747546290</isbn>
    <tags>
      <tag>children</tag>
      <tag>prisoner</tag>
    </tags>
  </book>
</bookstore>
/* *********************************************************************
 *                    *** DISCLAIMER ***
 * This code is covered by the Creative Commons Attribution 2.5 License
 * (http://creativecommons.org/licenses/by/2.5/).
 *
 * You may use this code in any way you see fit as long as you realize
 * that the code is provided AS IS without any warrenties and confers
 * to rights what so ever! The author cannot be held accountable for
 * any loss, direct or indirect, afflicted by using the code.
 *
 * *********************************************************************
 */

import java.util.Stack;

import org.w3c.dom.Element;
import org.w3c.dom.Node;

/**
 * Utility class for dealing with XML DOM elements.
 *
 *
 * @author Mikkel Heisterberg, lekkim@lsdoc.org
 */
public class ElementUtil {

   /**
    * Constructs a XPath query to the supplied node.
    *
    * @param n
    * @return
    */
   public static String getXPath(Node n) {
      // abort early
      if (null == n) return null;

      // declarations
      Node parent = null;
      Stack hierarchy = new Stack();
      StringBuffer buffer = new StringBuffer();

      // push element on stack
      hierarchy.push(n);

      parent = n.getParentNode();
      while (null != parent && parent.getNodeType() != Node.DOCUMENT_NODE) {
         // push on stack
         hierarchy.push(parent);

         // get parent of parent
         parent = parent.getParentNode();
      }

      // construct xpath
      Object obj = null;
      while (!hierarchy.isEmpty() && null != (obj = hierarchy.pop())) {
         Node node = (Node) obj;
         boolean handled = false;

         // only consider elements
         if (node.getNodeType() == Node.ELEMENT_NODE) {
            Element e = (Element) node;

            // is this the root element?
            if (buffer.length() == 0) {
               // root element - simply append element name
               buffer.append(node.getLocalName());
            } else {
               // child element - append slash and element name
               buffer.append("/");
               buffer.append(node.getLocalName());

               if (node.hasAttributes()) {
                  // see if the element has a name or id attribute
                  if (e.hasAttribute("id")) {
                     // id attribute found - use that
                     buffer.append("[@id='" + e.getAttribute("id") + "']");
                     handled = true;
                  } else if (e.hasAttribute("name")) {
                     // name attribute found - use that
                     buffer.append("[@name='" + e.getAttribute("name") + "']");
                     handled = true;
                  }
               }

               if (!handled) {
                  // no known attribute we could use - get sibling index
                  int prev_siblings = 1;
                  Node prev_sibling = node.getPreviousSibling();
                  while (null != prev_sibling) {
                     if (prev_sibling.getNodeType() == node.getNodeType()) {
                        if (prev_sibling.getLocalName().equalsIgnoreCase(node.getLocalName())) {
                           prev_siblings++;
                        }
                     }
                     prev_sibling = prev_sibling.getPreviousSibling();
                  }
                  buffer.append("[" + prev_siblings + "]");
               }
            }
         }
      }

      // return buffer
      return buffer.toString();
   }
}

XML entities when doing XSL transformations using LotusScript

I stumbled over an interesting post on developerWorks on external XML entities and XSL transformations in LotusScript: XSLT transform-ignoring external entity reference in R7.0.2 – but worked well on R6.5.4. I was puzzled by the post and looked a bit into it and was unable to find any real LotusScript API support for working with XML entities when processing XML in LotusScript.

I find it funny that there doesn’t appear to be any real API support for XML entities in LotusScript that I can see anyway. Hmmm – gotta go into Sherlock Holmes mode…