diff --git a/Doc/course.xml b/Doc/course.xml
index 91d8cfb6836028fdec9bb64323b700734a29efee..da9f1f15f98aa348119cce0963e8ac6d5a32ab88 100644
--- a/Doc/course.xml
+++ b/Doc/course.xml
@@ -5996,7 +5996,7 @@ public interface Node {
    ...
  }</programlisting>
 
-          <para>We take <methodname>getChildNodes()</methodname> as an
+          <para>We take <methodname>org.w3c.dom.Node.getChildNodes()</methodname> as an
           example:</para>
 
           <figure xml:id="domRetrieveChildren">
@@ -6527,7 +6527,7 @@ public class HtmlTree {
                     <callout arearefs="programlisting_catalog2html_insertproduct"
                              xml:id="programlisting_catalog2html_insertproduct_co">
                       <para>Calling
-                      <methodname>appendIteprogramlisting_catalog2html_insertproduct_com(...)</methodname>
+                      <methodname>solve.dom.HtmlTree.appendItem(String,String)</methodname>
                       once per product completes the creation of our HTML DOM
                       tree:</para>
 
@@ -7251,7 +7251,7 @@ INSERT INTO Product VALUES('w-124', 110.40);</programlisting>
                 <answer>
                   <para>The additional functionality on top of <xref
                   linkend="xml2xml"/> is represented by a method
-                  <methodname>addPrices</methodname>. This method modifies the
+                  <methodname>dom.xsl.XmlRdbms2Html.addPrices()</methodname>. This method modifies the
                   <acronym xlink:href="http://www.w3.org/DOM">DOM</acronym>
                   input tree prior to applying the XSL. Prices are being
                   inserting based on data received from an RDBMS via
@@ -11177,8 +11177,7 @@ PersistenceHandler.username=foo&lt;/pre&gt;
                   <para>Notice also the
                   <classname>java.awt.event.WindowAdapter</classname>
                   implementation being executed when closing the application's
-                  main window. The <methodname>windowClosing(WindowEvent
-                  e)</methodname> method disconnects any existing database
+                  main window. The <methodname>java.awt.event.WindowAdapter.windowClosing(java.awt.event.WindowEvent)</methodname> method disconnects any existing database
                   connection thus freeing resources.</para>
 
                   <programlisting language="java">package sda.jdbc.intro.v1;
@@ -12713,8 +12712,8 @@ public class HashProvider {
 ...}</programlisting>
 
                   <para>We may test the two class methods
-                  <methodname>getSaltedHash</methodname>(...) and
-                  <methodname>check(...)</methodname> by a separate driver
+                  <methodname>sda.jdbc.intro.auth.HashProvider.getSaltedHash(char[])</methodname>(...) and
+                  <methodname>sda.jdbc.intro.auth.HashProvider.check(char[],String)</methodname> by a separate driver
                   class. Notice the <quote>$</quote> sign <coref
                   linkend="saltPwhashSeparator"/> separating salt and password
                   hash:</para>
@@ -16253,7 +16252,7 @@ Exception in thread "main" org.hibernate.ObjectNotFoundException: <co
                   <classname>org.hibernate.ObjectNotFoundException</classname>.</para>
 
                   <para>The documentation also tells us to use the
-                  corresponding <methodname>get()</methodname> method which
+                  corresponding <methodname>org.hibernate.Session.get(Class,Serializable)</methodname> method which
                   actually returns <code>null</code> in case a primary key
                   value does not exist:</para>
 
@@ -16351,7 +16350,7 @@ uid=wings, Fred Wings</programlisting>
                       xml:id="hqlWithSelect"/>);
 final Object queryResult <co xml:id="queryResultFromSelect"/>= searchUsers.list();</programlisting>
 
-                  <para>Use the <methodname>getSimpleName()</methodname>
+                  <para>Use the <methodname>Class.getSimpleName()</methodname>
                   reflection method to iteratively analyze the
                   <code>queryResult</code> <coref
                   linkend="queryResultFromSelect"/> instance's structure. This
@@ -16428,7 +16427,7 @@ Found user 'Fred Wings'</programlisting>
       </section>
 
       <section xml:id="mappingSingleClasses">
-        <title>Mapping single classes and database tables</title>
+        <title>Mapping single entities and database tables</title>
 
         <section xml:id="transientProperties">
           <title>Transient properties</title>
@@ -16789,8 +16788,7 @@ public class Project {
             <qandadiv>
               <qandaentry>
                 <question>
-                  <para>The setter void <methodname>setId(int
-                  id)</methodname>in
+                  <para>The setter void <methodname annotations="nojavadoc">setId(int)</methodname>in
                   <classname>hibintro.v6.Project</classname> has protected
                   access. Explain this choice.</para>
                 </question>
@@ -17754,12 +17752,67 @@ CREATE TABLE BankAccount (
         <section xml:id="inheritTablePerConcrete">
           <title>Table per concrete class</title>
 
-          <para/>
+          <para>Not covered here.</para>
         </section>
       </section>
 
-      <section xml:id="mappingRelatedClasses">
-        <title>Mapping related classes</title>
+      <section xml:id="mappingRelatedEntities">
+        <title>Mapping related entities</title>
+
+        <section xml:id="primaryKeyRevisit">
+          <title>Primary keys revisited</title>
+
+          <para>Following <xref linkend="Bauer05"/> (p.88) we list important
+          properties of primary keys with respect to <quote>best
+          practices</quote> on top of their relational counterparts:</para>
+
+          <itemizedlist>
+            <listitem>
+              <para>A primary key's values never change </para>
+            </listitem>
+
+            <listitem>
+              <para>Primary key values should not have a business
+              meaning</para>
+            </listitem>
+
+            <listitem>
+              <para>Primary keys should be chosen to have proper indexing
+              support with respect to the database product in question.</para>
+            </listitem>
+          </itemizedlist>
+
+          <para>Regarding persistence we have three different concepts
+          regarding an object's identity:</para>
+
+          <glosslist>
+            <glossentry>
+              <glossterm>Java Object identity</glossterm>
+
+              <glossdef>
+                <para>The operator == checks whether two identifiers point to
+                the same memory address.</para>
+              </glossdef>
+            </glossentry>
+
+            <glossentry>
+              <glossterm>Java Object equality</glossterm>
+
+              <glossdef>
+                <para>The
+                <methodname>Object.equals(Object)</methodname>.</para>
+              </glossdef>
+            </glossentry>
+
+            <glossentry>
+              <glossterm/>
+
+              <glossdef>
+                <para/>
+              </glossdef>
+            </glossentry>
+          </glosslist>
+        </section>
 
         <section xml:id="sect_MappingEmbeddedClass">
           <title>Mapping a single embedded class</title>
diff --git a/ws/Docbook/Dbtools/Testdata/method.xml b/ws/Docbook/Dbtools/Testdata/method.xml
new file mode 100644
index 0000000000000000000000000000000000000000..6d65e50d2febe2145c679794c7da2aba3daab5be
--- /dev/null
+++ b/ws/Docbook/Dbtools/Testdata/method.xml
@@ -0,0 +1,34 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<book version="5.0" xmlns="http://docbook.org/ns/docbook"
+      xmlns:xlink="http://www.w3.org/1999/xlink"
+      xmlns:xi="http://www.w3.org/2001/XInclude"
+      xmlns:svg="http://www.w3.org/2000/svg"
+      xmlns:m="http://www.w3.org/1998/Math/MathML"
+      xmlns:html="http://www.w3.org/1999/xhtml"
+      xmlns:db="http://docbook.org/ns/docbook">
+  <info>
+    <title/>
+
+    <author>
+      <personname><firstname/><surname/></personname>
+
+      <affiliation>
+        <orgname/>
+      </affiliation>
+    </author>
+
+    <pubdate/>
+  </info>
+
+  <chapter xml:id="chap">
+    <title>Methods</title>
+
+    <para>Lets assume a static method
+    <methodname>java.lang.String.equals(java.lang.Object)</methodname> an a
+    non-static method <methodname>String.indexOf(String,int)</methodname>,
+    <methodname>String.hashCode()</methodname>.</para>
+
+    <para> <methodname>String.getChars(int,int,char[],int)</methodname>
+    </para>
+  </chapter>
+</book>
diff --git a/ws/Docbook/Dbtools/src/main/java/de/hdm_stuttgart/mi/codeformat/Docbook2docbook.java b/ws/Docbook/Dbtools/src/main/java/de/hdm_stuttgart/mi/codeformat/Docbook2docbook.java
index 910a1dd570ae055f1e9a5fccb6af6f1c9951730d..d7b1ae55c01fdb209373d5f2f7d9ebe2ab127087 100644
--- a/ws/Docbook/Dbtools/src/main/java/de/hdm_stuttgart/mi/codeformat/Docbook2docbook.java
+++ b/ws/Docbook/Dbtools/src/main/java/de/hdm_stuttgart/mi/codeformat/Docbook2docbook.java
@@ -7,6 +7,11 @@ import java.lang.reflect.Method;
 import java.net.MalformedURLException;
 import java.net.URL;
 import java.net.URLClassLoader;
+import java.util.ArrayList;
+import java.util.HashMap;
+import java.util.List;
+import java.util.Map;
+import java.util.concurrent.ConcurrentHashMap;
 import java.util.regex.Matcher;
 import java.util.regex.Pattern;
 
@@ -37,331 +42,466 @@ import org.w3c.dom.ls.LSSerializer;
  *
  */
 public class Docbook2docbook {
-	
+
 	private static final Logger logger = Logger.getLogger(Docbook2docbook.class);
-  private final static String srcPrefixDir = "Ref/api",
-                          docbookNamespace = "http://docbook.org/ns/docbook";
-
-  private final XPathFactory xpf = XPathFactory.newInstance();
-  
-  /** Searching a document of type docbook for programlistings with java classes. If the class can be retrieved
-   * a url reference is being constructed.
-   * @param args
-   * @throws ClassCastException
-   * @throws FileNotFoundException
-   * @throws ClassNotFoundException
-   * @throws InstantiationException
-   * @throws IllegalAccessException
-   * @throws XPathExpressionException
-   */
-  public static void main(String[] args) throws 
-      ClassCastException, FileNotFoundException, ClassNotFoundException,
-      InstantiationException, IllegalAccessException, XPathExpressionException {
-    if (1 != args.length) {
-      logger.fatal("Usage: Docbook2docbook <xmlfileBasename>");
-    } else {
-      Docbook2docbook d2d = new Docbook2docbook(args[0]);
-      d2d.process();
-      logger.info("Successfully finished conversion");
-    }
-  }
-  private 
-  final String docbookBasename;
-  /**
-   * @param basename the XML document's basename e.g. for a XML instance "somdirectory/mydoc.xml"
-   * this will be "somdirectory/mydoc"
-   */
-  public Docbook2docbook (final String basename){
-    this.docbookBasename = basename;
-  }
-  private void process() throws ClassCastException, ClassNotFoundException,
-   InstantiationException, IllegalAccessException,
-   XPathExpressionException {
-    final DOMImplementationRegistry registry =
-      DOMImplementationRegistry.newInstance();
-
-    DOMImplementationLS impl = (DOMImplementationLS)registry.getDOMImplementation("LS");
-
-    LSParser db = impl.createLSParser(DOMImplementationLS.MODE_SYNCHRONOUS, null);
-    final DOMConfiguration config = db.getDomConfig();
-    config.setParameter("error-handler", new DomErrorHandler(System.err));
-    final String xmlInfileName = docbookBasename + ".xml";
-    final Document dbInput = db.parseURI(xmlInfileName);
-    addClassReferences(dbInput);
-    
-    final LSSerializer serial = impl.createLSSerializer();
-    serial.getDomConfig().setParameter("format-pretty-print", false);
-    final LSOutput lsOut = impl.createLSOutput();
-    PrintWriter out;
-    try {
-      out = new PrintWriter(docbookBasename + ".convert.xml");
-      lsOut.setCharacterStream(out);
-      serial.write(dbInput, lsOut);
-      out.flush();
-    } catch (FileNotFoundException e) {
-      logger.fatal("Unable to parse xml file " + xmlInfileName);
-    }
-  }
-  
-  private void addClassReferences(final Document top) throws XPathExpressionException{
-    
-    final XPath searchBlockObjects = xpf.newXPath();
-    searchBlockObjects.setNamespaceContext(new MyNamespaceContexts());
-
-    final NodeList classnames = 
-        (NodeList) searchBlockObjects.evaluate(
-          "//db:classname[not(contains(@annotations, 'nojavadoc'))]",
-            top, XPathConstants.NODESET);
-      for (int i = 0; i < classnames.getLength(); i++){
-          processClassName((Element) classnames.item(i));
-      }
-
-      final NodeList listings = 
-        (NodeList) searchBlockObjects.evaluate(
-          "//db:programlisting[not(contains(@annotations, 'nojavadoc'))]",
-            top, XPathConstants.NODESET);
-      for (int i = 0; i < listings.getLength(); i++){
-        processListing((Element) listings.item(i));
-      }      
-        // Not yet ready!
-//        final NodeList methodNames = 
-//            (NodeList) searchProgramlisting.evaluate(
-//              "//db:methodname",
-//                top, XPathConstants.NODESET);
-//          for (int i = 0; i < methodNames.getLength(); i++){
-//              processMethodName((Element) methodNames.item(i));
-//          }
-  }
-  
-  private void processClassName(final Element classnameElement) {
-    final Node firstClassnameNode =  classnameElement.getFirstChild();
-    if (firstClassnameNode instanceof Text) {
-      final Text firstClassnameTextNode = (Text) firstClassnameNode;
-      final String fullyQualifiedClassname = firstClassnameTextNode.getData().trim();
-      
-      final Class<?> cl = testClassAvailability(fullyQualifiedClassname);
-      if (null == cl) {
-    	  logger.warn("Unable to find prefix for '" + fullyQualifiedClassname);
-      } else {
-    	  final String urlPrefix, implementationVendor;
-    	  if (fullyQualifiedClassname.startsWith("javax.")) {
-    		  urlPrefix="http://docs.oracle.com/javase/7/docs/api";
-    		  implementationVendor = "oracle corporation (fixed by javax.*)";
-    	  } else {
-    		  implementationVendor = cl.getPackage().getImplementationVendor();
-    		  if (null == implementationVendor) {
-    			  urlPrefix = srcPrefixDir;
-    		  } else {
-    			  switch(implementationVendor.toLowerCase()) {
-    			  case "oracle corporation":
-    				  urlPrefix="http://docs.oracle.com/javase/7/docs/api";
-    				  break;
-    			  case "jdom.org":
-    				  urlPrefix="http://www.jdom.org/docs/apidocs";
-    				  break;
-    			  case "hibernate.org":
-    				  urlPrefix = "http://docs.jboss.org/hibernate/orm/4.1/javadocs";
-    				  break;
-    			  default:
-    				  urlPrefix="unknown vendor '" + implementationVendor + "'";
-    				  logger.warn("No vendor found for " + fullyQualifiedClassname);
-    				  break;
-    			  }
-    		  }
-    		  final Element link = createLink(classnameElement, cl, cl.getSimpleName());
-    		  link.setAttributeNS("http://www.w3.org/1999/xlink", "xlink:href",
-    				  urlPrefix + "/" + package2path(cl.getCanonicalName()) + ".html");
-    		  classnameElement.replaceChild(link, firstClassnameTextNode);
-    	  }
-    	  logger.info("Mapping '" + fullyQualifiedClassname + "' to base URL " +
-    			  urlPrefix + ", vendor = " + implementationVendor);
-      }
-    }
-  }
-  
-  private void processMethodName(final Element methodNameElement) {
-    final Node firstMethodNameNode =  methodNameElement.getFirstChild();
-    if (firstMethodNameNode instanceof Text) {
-      final Text firstMethodNameTextNode = (Text) firstMethodNameNode;
-      final String fullyQualifiedMethodName = firstMethodNameTextNode.getData().trim();
-//      final Class<?> cl = testClassAvailability(fullyQualifiedClassname);
-//      if (null != cl) {
-//        final String urlPrefix;
-//        final String implementationVendor = cl.getPackage().getImplementationVendor();
-//        if (null != implementationVendor && implementationVendor.equals("Oracle Corporation")){
-//          urlPrefix="http://docs.oracle.com/javase/7/docs/api";
-//        } else {
-//          urlPrefix = srcPrefixDir;
-//        }
-//        final Element link = createLink(classnameElement, cl, cl.getSimpleName());
-//        link.setAttributeNS("http://www.w3.org/1999/xlink", "xlink:href",
-//            urlPrefix + "/" + package2path(cl.getCanonicalName()) + ".html");
-//        classnameElement.replaceChild(link, firstClassnameTextNode);
-//      }
-    }
-  }
-
-  private void processListing(final Element plisting) throws XPathExpressionException{
-    final Text[] textNodes = findTextNodes(plisting);
-    
-    final Pattern searchPackage = Pattern.compile(
-        "(?s).*package[ \\t]+" + 
-        "([\\w]|\\w[\\w|.]*[\\w])"+
-        "[ \t]*;.*");
-
-    String packageName = null;
-    for (final Text tNode : textNodes){
-      Matcher matchPackage = searchPackage.matcher(tNode.getData());
-      if (matchPackage.find()){
-        packageName = matchPackage.group(1);
-        break;
-      }
-    }
-    if (null != packageName){
-      final Pattern searchClass = Pattern.compile(
-          "(?s)(.*[ \\t]+class[ \\t]+)" +
-          "(\\w+)" +
-          "(.*)");
-      // May use the following regexp excluding non-public classes with group(4):
-      //      "(?s)(.*public)([ \\t]+\\w+)*[ \\t]+(class[ \\t]+)" +
-      //      "(\\w+)" +
-      //      "(.*)");
-      for (final Text tNode : textNodes){
-        Matcher matchClass = searchClass.matcher(tNode.getData());
-        if (matchClass.find()){
-          final String className = matchClass.group(2);
-
-          final Class<?> cl = testClassAvailability(packageName + "." + className);
-          if (null != cl){
-            final Text beforeText = createTextNode(plisting, matchClass.group(1)),
-            afterText = createTextNode(plisting, matchClass.group(3));
-            plisting.replaceChild(afterText, tNode);
-            final Element link = createLink(plisting, cl, className);
-            link.setAttributeNS("http://www.w3.org/1999/xlink", "xlink:href",
-                srcPrefixDir + "/" + package2path(cl.getCanonicalName()) + ".html");
-            plisting.insertBefore(link, afterText);
-            plisting.insertBefore(beforeText, link);
-          }
-          break;
-        }
-      }
-    }
-  }
-  private Element createLink(final Element root, final Class<?> cl, final String className) {
-    final Element link = createElementNode(
-        root,
-        "uri", docbookNamespace,
-        className);
-    link.setAttributeNS("http://www.w3.org/1999/xlink", "xlink:href",
-        srcPrefixDir + "/" + package2path(cl.getCanonicalName()) + ".html");
-    return link;
-  }
-  private Class<?> testClassAvailability(final String fullyQualifiedClassName){
-      try {
-        return Class.forName(fullyQualifiedClassName);
-      } catch (ClassNotFoundException e) {
-        if (fullyQualifiedClassName.contains(".")) {
-          logger.warn("Warning: Unable to access class " + fullyQualifiedClassName);
-        }
-        return null;
-      }
-  }
-  //Helper functions
-  
-  /**
-   * @param current
-   * @return
-   */
-  public String findExtraClasspath(final Element current) {
-    
-    logger.info("line:" + current.getUserData("lineNumber"));
-//    final String annotations = current.getAttributeNS(docbookNamespace, "annotations");
-    final String annotations = current.getAttribute("annotations");
-    if (null != annotations) {
-      final String ret = annotations.trim();
-      if (!ret.equals("")) {
-        return ret;
-      } 
-    }
-    final Node parentNode = current.getParentNode();
-    
-    if (parentNode instanceof Document) {
-      logger.error("Document root being reached while scanning for classpath related annotation");
-      System.exit(1);
-    }
-    final Element parent = (Element) parentNode;
-    return findExtraClasspath(parent);
-  }
-  
-  /**
-   * @param path
-   */
-  public static void addURL(String path)  {
-    File filePath = new File(path);
-    try {
-      addURL(filePath.toURI().toURL());
-    } catch (MalformedURLException e) {
-      e.printStackTrace();
-      logger.fatal("Error, could not create URL from '" + path + "'");
-      System.exit(1);
-    }
-  }
-
-  /**
-   * @param u
-   */
-  public static void addURL(URL u) {
-
-    URLClassLoader sysloader = (URLClassLoader) ClassLoader.getSystemClassLoader();
-    Class<URLClassLoader> sysclass = URLClassLoader.class;
-    final Class[] parameters = new Class[]{URL.class};
-
-    try {
-      Method method = sysclass.getDeclaredMethod("addURL", parameters);
-      method.setAccessible(true);
-      method.invoke(sysloader, new Object[]{u});
-    } catch (Throwable t) {
-      t.printStackTrace();
-      logger.error("Error, could not add URL to system classloader");
-      System.exit(1);
-    }
-  }
-  
-  private final String package2path(final String packageName){
-    String searchDot = "\\.";
-    Pattern pattern = Pattern.compile(searchDot);
-    Matcher matcher = pattern.matcher(packageName);
-    return matcher.replaceAll("/");
-  }
-  private Text createTextNode(final Node node, final String data){
-    if (node instanceof Document){
-      return ((Document) node).createTextNode(data);
-    } else{
-      return node.getOwnerDocument().createTextNode(data);
-    }
-  }
-  private Element createElementNode(final Node node,
-      final String type, final String ns, final String data){
-    final Element ret;
-    if (node instanceof Document){
-      ret = ((Document) node).createElementNS(ns, type);
-    } else{
-      ret = node.getOwnerDocument().createElementNS(ns, type);
-    }
-    final Text t = createTextNode(node, data);
-    ret.appendChild(t);
-    return ret;
-  }
-  private Text[] findTextNodes(final Element parent) throws XPathExpressionException{
-    final XPath searchTextNodes = xpf.newXPath();
-    final NodeList textNodes = 
-      (NodeList) searchTextNodes.evaluate(
-        "text()",
-          parent, XPathConstants.NODESET);
-    final Text [] t = new Text[textNodes.getLength()];
-    for (int i = 0; i < textNodes.getLength(); i++){
-      t[i] = (Text) textNodes.item(i);
-    }
-    return t;
-  }
+	private final static String srcPrefixDir = "Ref/api",
+			docbookNamespace = "http://docbook.org/ns/docbook";
+	private final static Package[] knownPackages;
+	private final static Map<String, Package> package2name;
+	private static final Map<String, Class<?>> BUILT_IN_MAP = 
+			new ConcurrentHashMap<String, Class<?>>();
+
+
+	private final XPathFactory xpf = XPathFactory.newInstance();
+
+	/** Searching a document of type docbook for programlistings with java classes. If the class can be retrieved
+	 * a url reference is being constructed.
+	 * @param args
+	 * @throws ClassCastException
+	 * @throws FileNotFoundException
+	 * @throws ClassNotFoundException
+	 * @throws InstantiationException
+	 * @throws IllegalAccessException
+	 * @throws XPathExpressionException
+	 */
+
+	static {
+		knownPackages = Package.getPackages();
+		package2name = new HashMap<String, Package>();
+		for (final Package p: Package.getPackages()) {
+			package2name.put(p.getName(), p);
+		}
+		for (Class<?> c : new Class[]{void.class,
+				boolean.class,   byte.class,   char.class,   short.class,   int.class,
+				boolean[].class, byte[].class, char[].class, short[].class, int[].class,
+
+				float.class,   double.class,   long.class,
+				float[].class, double[].class, long[].class
+		})
+			BUILT_IN_MAP.put(c.getCanonicalName(), c);
+	}
+	public static Class<?> forName(String name) throws ClassNotFoundException {
+		Class<?> c = BUILT_IN_MAP.get(name);
+		if (c == null) {
+			return Class.forName(name);
+		} else {
+			return c;
+		}
+	}
+	public static void main(String[] args) throws 
+	ClassCastException, FileNotFoundException, ClassNotFoundException,
+	InstantiationException, IllegalAccessException, XPathExpressionException {
+		if (1 != args.length) {
+			logger.fatal("Usage: Docbook2docbook <xmlfileBasename>");
+		} else {
+			Docbook2docbook d2d = new Docbook2docbook(args[0]);
+			d2d.process();
+			logger.info("Successfully finished conversion");
+		}
+	}
+	private 
+	final String docbookBasename;
+	/**
+	 * @param basename the XML document's basename e.g. for a XML instance "somdirectory/mydoc.xml"
+	 * this will be "somdirectory/mydoc"
+	 */
+	public Docbook2docbook (final String basename){
+		this.docbookBasename = basename;
+	}
+	private void process() throws ClassCastException, ClassNotFoundException,
+	InstantiationException, IllegalAccessException,
+	XPathExpressionException {
+		final DOMImplementationRegistry registry =
+				DOMImplementationRegistry.newInstance();
+
+		DOMImplementationLS impl = (DOMImplementationLS)registry.getDOMImplementation("LS");
+
+		LSParser db = impl.createLSParser(DOMImplementationLS.MODE_SYNCHRONOUS, null);
+		final DOMConfiguration config = db.getDomConfig();
+		config.setParameter("error-handler", new DomErrorHandler(System.err));
+		final String xmlInfileName = docbookBasename + ".xml";
+		final Document dbInput = db.parseURI(xmlInfileName);
+		addClassReferences(dbInput);
+
+		final LSSerializer serial = impl.createLSSerializer();
+		serial.getDomConfig().setParameter("format-pretty-print", false);
+		final LSOutput lsOut = impl.createLSOutput();
+		PrintWriter out;
+		try {
+			out = new PrintWriter(docbookBasename + ".convert.xml");
+			lsOut.setCharacterStream(out);
+			serial.write(dbInput, lsOut);
+			out.flush();
+		} catch (FileNotFoundException e) {
+			logger.fatal("Unable to parse xml file " + xmlInfileName);
+		}
+	}
+
+	private void addClassReferences(final Document top) throws XPathExpressionException{
+
+		final XPath searchBlockObjects = xpf.newXPath();
+		searchBlockObjects.setNamespaceContext(new MyNamespaceContexts());
+
+		final NodeList classnames = 
+				(NodeList) searchBlockObjects.evaluate(
+						"//db:classname[not(contains(@annotations, 'nojavadoc'))]",
+						top, XPathConstants.NODESET);
+		for (int i = 0; i < classnames.getLength(); i++){
+			processClassName((Element) classnames.item(i));
+		}
+
+		final NodeList listings = 
+				(NodeList) searchBlockObjects.evaluate(
+						"//db:programlisting[not(contains(@annotations, 'nojavadoc'))]",
+						top, XPathConstants.NODESET);
+		for (int i = 0; i < listings.getLength(); i++){
+			processListing((Element) listings.item(i));
+		}      
+		final NodeList methodNames = 
+				(NodeList) searchBlockObjects.evaluate(
+						"//db:methodname[not(contains(@annotations, 'nojavadoc'))]",
+						top, XPathConstants.NODESET);
+		for (int i = 0; i < methodNames.getLength(); i++){
+			processMethodName((Element) methodNames.item(i));
+		}
+	}
+
+	private void processClassName(final Element classnameElement) {
+		final Node firstClassnameNode =  classnameElement.getFirstChild();
+		if (firstClassnameNode instanceof Text) {
+			final Text firstClassnameTextNode = (Text) firstClassnameNode;
+			final String fullyQualifiedClassname = firstClassnameTextNode.getData().trim();
+
+			final Class<?> cl = findClass(fullyQualifiedClassname);
+			if (null == cl) {
+				logger.warn("Unable to find prefix for '" + fullyQualifiedClassname);
+			} else {
+
+				final Element link = createLink(classnameElement, cl.getSimpleName(), urlPrefix (cl));
+				classnameElement.replaceChild(link, firstClassnameTextNode);
+			}
+		}
+	}
+
+	final String urlPrefix (final Method method) {
+		final Class<?> cl = method.getDeclaringClass();
+		final StringBuffer buff = new StringBuffer();
+		buff.append(urlPrefix(cl));
+		buff.append('#');
+		buff.append(method.getName());
+		buff.append('(');
+		for (int i = 0; i < method.getParameterTypes().length; i++) {
+			final Class<?> type = method.getParameterTypes()[i];
+			buff.append(type.getCanonicalName());
+			if (i < method.getParameterTypes().length - 1) {
+				buff.append(", ");
+			}
+		}
+		buff.append(')');
+		return buff.toString();
+	}
+
+	final String urlPrefix (final Class<?> cl) {
+		final String urlPrefix, implementationVendor;
+		final String fullyQualifiedClassname = cl.getCanonicalName();
+		if (fullyQualifiedClassname.startsWith("javax.")) {
+			urlPrefix="http://docs.oracle.com/javase/7/docs/api";
+			implementationVendor = "oracle corporation (fixed by javax.*)";
+		} else {
+			implementationVendor = cl.getPackage().getImplementationVendor();
+			if (null == implementationVendor) {
+				urlPrefix = srcPrefixDir;
+			} else {
+				switch(implementationVendor.toLowerCase()) {
+				case "oracle corporation":
+					urlPrefix="http://docs.oracle.com/javase/7/docs/api";
+					break;
+				case "jdom.org":
+					urlPrefix="http://www.jdom.org/docs/apidocs";
+					break;
+				case "hibernate.org":
+					urlPrefix = "http://docs.jboss.org/hibernate/orm/4.1/javadocs";
+					break;
+				default:
+					urlPrefix="unknown vendor '" + implementationVendor + "'";
+					logger.warn("No vendor found for " + fullyQualifiedClassname);
+					break;
+				}
+			}
+		}
+		return urlPrefix + "/" + package2path(cl.getCanonicalName()) + ".html";
+	}
+
+	private static String join(final String[] components, final String seperator, int start, int length) {
+		final StringBuffer b = new StringBuffer();
+		for (int i = start; i < start + length; i++) {
+			b.append(components[i]);
+			if (i < start + length - 1) {
+				b.append(seperator);
+			}
+		}
+		return b.toString();
+	}
+
+	private static Package package2name(final String[] components, int startIndex, int length) {
+		for (String c: components) {
+			logger.info("component:" + c);
+		}
+
+		final String packageName = join(components, ".", startIndex, length);
+		logger.info("searching for package '" + packageName + "'");
+		return  Package.getPackage(packageName);
+	}
+	private final Class<?> findUniqueClass(final String classname) {
+
+		try {
+			return forName(classname); //primitive type?
+		} catch (ClassNotFoundException ex) {}
+
+
+		int packageCount = 0;
+		Class<?> lastFound = null;
+		for (final Package p: knownPackages) {
+			final String fullyQualifiedClassName = p.getName().concat(".").concat(classname);
+			final Class<?> candidate = findClass(fullyQualifiedClassName);
+			if (null != candidate) {
+				lastFound = candidate;
+				packageCount++;
+				logger.info("found class '" + lastFound.getCanonicalName());
+			}
+		}
+		if (0 == packageCount) {
+			logger.warn("Class '" + classname + "' not found in any package");
+		} else if (1 < packageCount) {
+			logger.warn("Class '" + classname + "' found in " + packageCount + " packages");
+		}
+		return lastFound;
+	}
+	private final Class<?> findClass(final String className) {
+		if (className.contains(".")) {
+			try {
+				//logger.info("Looking for class '" + className + "'");
+				return forName(className) ;
+			} catch (ClassNotFoundException ex) {
+				//logger.info("No such class '" + fullyQualifiedClassName + "'");
+				return null;
+			}
+		} else {
+			return findUniqueClass(className);
+		}
+	}
+	private void processMethodName(final Element methodNameElement) {
+		final Node firstMethodNameNode =  methodNameElement.getFirstChild();
+		if (firstMethodNameNode instanceof Text) {
+			final Text firstMethodNameTextNode = (Text) firstMethodNameNode;
+			final String fullyQualifiedMethodName = firstMethodNameTextNode.getData().trim().replaceAll("[ \t\n]+", " ");
+			final String mainSignatureComponents[] = fullyQualifiedMethodName.split("[()]");
+			logger.info("----------------------------------------------------------");
+			final String returnQualifiedMethodname = mainSignatureComponents[0];
+			//argumentList = mainSignatureComponents[1];
+			logger.info("return plus methodname:'" + returnQualifiedMethodname + "'");
+			final String[] methodComponents = returnQualifiedMethodname.split("\\.");
+
+			final Class<?> uniqueClass;
+			final String errMsg;
+			final String methodName;
+			if (2 == methodComponents.length) { //Unqualified Class, e.g. String.clone()
+				final String unqualifiedClassname = methodComponents [0];
+				methodName = methodComponents [1];
+				uniqueClass = findUniqueClass(unqualifiedClassname);
+				errMsg = "No unique lookup of class '" + unqualifiedClassname + "'";
+			} else {
+				final Package pack = package2name(methodComponents, 0, methodComponents.length - 2);
+				methodName = methodComponents [methodComponents.length - 1];
+				final String fullyQualifiedClassName = pack.getName().concat(".").concat(methodComponents[methodComponents.length - 2]);
+
+				uniqueClass = findClass(fullyQualifiedClassName);
+				errMsg = "Unable to find class '" + fullyQualifiedClassName + "'";
+			}
+			if (null == uniqueClass) {
+				logger.fatal(errMsg);
+				System.exit(1);
+			}
+			logger.info("found class '" + uniqueClass.getCanonicalName() + "'");
+
+			final List<Class<?>> parameterTypes = new ArrayList<Class<?>>();
+			if (1 < mainSignatureComponents.length) { // Argument list may be void
+				final String[] argumentStrings = mainSignatureComponents[1].split("[,]");
+				for (final String a: argumentStrings) {
+					final Class<?> argType = findClass(a);
+					if (null == argType) {
+						logger.fatal("No such type '" + a + "' in method '" +
+								methodName + "'");
+						System.exit(1);
+					}
+					parameterTypes.add(argType);
+				}
+			}
+			Method method = null;
+			try {
+				method = uniqueClass.getDeclaredMethod(methodName, parameterTypes.toArray(new Class<?>[0]));
+			} catch (NoSuchMethodException ex) {
+				logger.error("Unable to find method '" + uniqueClass.getCanonicalName() + "." 
+						+ methodName + "'");
+				System.exit(1);
+			}
+			logger.info("Adding Link '" + urlPrefix(method) + "'");
+
+			if (method.isAccessible()) {
+				final Element link = createElementNode(methodNameElement, "link", docbookNamespace, method.getName());
+				link.setAttributeNS("http://www.w3.org/1999/xlink", "xlink:href", urlPrefix(method));
+				methodNameElement.replaceChild(link, firstMethodNameTextNode);
+			}
+		}
+	}
+
+	private void processListing(final Element plisting) throws XPathExpressionException{
+		final Text[] textNodes = findTextNodes(plisting);
+
+		final Pattern searchPackage = Pattern.compile(
+				"(?s).*package[ \\t]+" + 
+						"([\\w]|\\w[\\w|.]*[\\w])"+
+				"[ \t]*;.*");
+
+		String packageName = null;
+		for (final Text tNode : textNodes){
+			Matcher matchPackage = searchPackage.matcher(tNode.getData());
+			if (matchPackage.find()){
+				packageName = matchPackage.group(1);
+				break;
+			}
+		}
+		if (null != packageName){
+			final Pattern searchClass = Pattern.compile(
+					"(?s)(.*[ \\t]+class[ \\t]+)" +
+							"(\\w+)" +
+					"(.*)");
+			// May use the following regexp excluding non-public classes with group(4):
+			//      "(?s)(.*public)([ \\t]+\\w+)*[ \\t]+(class[ \\t]+)" +
+			//      "(\\w+)" +
+			//      "(.*)");
+			for (final Text tNode : textNodes){
+				Matcher matchClass = searchClass.matcher(tNode.getData());
+				if (matchClass.find()){
+					final String className = matchClass.group(2);
+
+					final Class<?> cl = findClass(packageName + "." + className);
+					if (null != cl){
+						final Text beforeText = createTextNode(plisting, matchClass.group(1)),
+								afterText = createTextNode(plisting, matchClass.group(3));
+						plisting.replaceChild(afterText, tNode);
+						final Element link = createLink(plisting, className, srcPrefixDir + "/" + package2path(cl.getCanonicalName()) + ".html");
+						plisting.insertBefore(link, afterText);
+						plisting.insertBefore(beforeText, link);
+					}
+					break;
+				}
+			}
+		}
+	}
+
+	private Element createLink(final Element root, final String content, final String href) {
+		final Element link = createElementNode(root, "link", docbookNamespace, content);
+		link.setAttributeNS("http://www.w3.org/1999/xlink", "xlink:href", href);
+		return link;
+	}
+
+	//Helper functions
+
+	/**
+	 * @param current
+	 * @return
+	 */
+	public String findExtraClasspath(final Element current) {
+
+		logger.info("line:" + current.getUserData("lineNumber"));
+		//    final String annotations = current.getAttributeNS(docbookNamespace, "annotations");
+		final String annotations = current.getAttribute("annotations");
+		if (null != annotations) {
+			final String ret = annotations.trim();
+			if (!ret.equals("")) {
+				return ret;
+			} 
+		}
+		final Node parentNode = current.getParentNode();
+
+		if (parentNode instanceof Document) {
+			logger.error("Document root being reached while scanning for classpath related annotation");
+			System.exit(1);
+		}
+		final Element parent = (Element) parentNode;
+		return findExtraClasspath(parent);
+	}
+
+	/**
+	 * @param path
+	 */
+	public static void addURL(String path)  {
+		File filePath = new File(path);
+		try {
+			addURL(filePath.toURI().toURL());
+		} catch (MalformedURLException e) {
+			e.printStackTrace();
+			logger.fatal("Error, could not create URL from '" + path + "'");
+			System.exit(1);
+		}
+	}
+
+	/**
+	 * @param u
+	 */
+	public static void addURL(URL u) {
+
+		URLClassLoader sysloader = (URLClassLoader) ClassLoader.getSystemClassLoader();
+		Class<URLClassLoader> sysclass = URLClassLoader.class;
+		final Class[] parameters = new Class[]{URL.class};
+
+		try {
+			Method method = sysclass.getDeclaredMethod("addURL", parameters);
+			method.setAccessible(true);
+			method.invoke(sysloader, new Object[]{u});
+		} catch (Throwable t) {
+			t.printStackTrace();
+			logger.error("Error, could not add URL to system classloader");
+			System.exit(1);
+		}
+	}
+
+	private final String package2path(final String packageName){
+		String searchDot = "\\.";
+		Pattern pattern = Pattern.compile(searchDot);
+		Matcher matcher = pattern.matcher(packageName);
+		return matcher.replaceAll("/");
+	}
+	private Text createTextNode(final Node node, final String data){
+		if (node instanceof Document){
+			return ((Document) node).createTextNode(data);
+		} else{
+			return node.getOwnerDocument().createTextNode(data);
+		}
+	}
+	private Element createElementNode(final Node node,
+			final String type, final String ns, final String data){
+		final Element ret;
+		if (node instanceof Document){
+			ret = ((Document) node).createElementNS(ns, type);
+		} else{
+			ret = node.getOwnerDocument().createElementNS(ns, type);
+		}
+		final Text t = createTextNode(node, data);
+		ret.appendChild(t);
+		return ret;
+	}
+	private Text[] findTextNodes(final Element parent) throws XPathExpressionException{
+		final XPath searchTextNodes = xpf.newXPath();
+		final NodeList textNodes = 
+				(NodeList) searchTextNodes.evaluate(
+						"text()",
+						parent, XPathConstants.NODESET);
+		final Text [] t = new Text[textNodes.getLength()];
+		for (int i = 0; i < textNodes.getLength(); i++){
+			t[i] = (Text) textNodes.item(i);
+		}
+		return t;
+	}
 }