org.jafer.conf.Config.java Source code

Java tutorial

Introduction

Here is the source code for org.jafer.conf.Config.java

Source

/**
 * JAFER Toolkit Poject.
 * Copyright (C) 2002, JAFER Toolkit Project, Oxford University.
 *
 * This library is free software; you can redistribute it and/or
 * modify it under the terms of the GNU Lesser General Public
 * License as published by the Free Software Foundation; either
 * version 2.1 of the License, or (at your option) any later version.
 *
 * This library is distributed in the hope that it will be useful,
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
 * Lesser General Public License for more details.
 *
 * You should have received a copy of the GNU Lesser General Public
 * License along with this library; if not, write to the Free Software
 * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
 */

package org.jafer.conf;

import org.jafer.exception.JaferException;
import org.jafer.util.xml.DOMFactory;
import org.jafer.util.xml.XMLTransformer;

import java.io.InputStream;
import java.util.Enumeration;
import java.util.Hashtable;
import java.util.Vector;

import javax.xml.transform.Templates;

import org.apache.xpath.CachedXPathAPI;
import org.bouncycastle.util.Arrays;
import org.w3c.dom.Document;
import org.w3c.dom.Element;
import org.w3c.dom.Node;
import org.w3c.dom.NodeList;

/**
 * <p>Parses XML files used for configuration of client and server and provides static look up methods eg. getRecordSerializer (configured via recordDescriptor.xml), getBib1Message (bib1Messages.xml).
 * Also, has static utility methods eg. isSyntaxEqual, String convertSyntax(int[]), String getValue(Node), Node selectSingleNode(Node node, String xPath), URL getResource(String path).</p>
 * @author Antony Corfield; Matthew Dovey; Colin Tatham
 * @version 1.0
 */
public class Config {

    public final static String RECORD_DESCRIPTOR_FILE = "org/jafer/conf/recordDescriptor.xml";
    public final static String BIB1_ATTRIBUTES_FILE = "org/jafer/conf/bib1Attributes.xml";
    public final static String BIB1_DIAGNOSTICS_FILE = "org/jafer/conf/bib1Diagnostics.xml";
    public final static String SEARCH_PROFILES_FILE = "org/jafer/conf/searchProfiles.xml";
    public static final String CHARACTER_SETS_FILE = "org/jafer/conf/characterSets/characterSets.xml";
    public static final String SERVER_CONFIG_FILE = "org/jafer/conf/server.xml";
    public static final String SERVER_DECODE_FILE = "org/jafer/xsl/server/server-decode.xsl";
    public static final String SERVER_ENCODE_FILE = "org/jafer/xsl/server/server-encode.xsl";

    private static Templates serverDecode;

    private static Templates serverEncode;

    private static Document recordTransformDocument;
    private static Hashtable<String, String> recordName;
    private static Hashtable<String, String> recordSyntax;
    private static Hashtable<String, String> recordSerializer;
    private static Hashtable<String, String> recordSerializerTargetSchema;
    private static Hashtable<String, Hashtable<String, Hashtable<String, Node>>> recordTransformations;
    private static Hashtable<String, int[]> syntaxCache;
    /** @todo SRW/XMLRecord hack: */
    private static Vector<String> targetSchemaNames;
    private static Vector<String> sourceSchemaNames;
    private static Vector<String> stylesheetNames;

    private static Hashtable<String, Hashtable<String, Hashtable<String, String>>> attributeSets;
    private static Hashtable<String, String> attributeTypeName;
    private static Hashtable<String, String> attributeTypeValue;
    private static Hashtable<String, String> searchProfileSyntax;
    private static Hashtable<String, String> searchProfileName;
    private static Hashtable<String, String> bib1DiagMessage;
    private static Hashtable<String, String> bib1DiagAddInfo;

    private static String attributeSetName;
    private static String attributeSetSyntax;

    private static CachedXPathAPI xPathAPI;
    private static Config config;

    public Config() {
    }

    static {
        xPathAPI = new CachedXPathAPI();
        config = new Config();//
        try {
            buildRecordConfig(RECORD_DESCRIPTOR_FILE);
            buildBib1AttributeConfig(BIB1_ATTRIBUTES_FILE);
            buildBib1DiagnosticConfig(BIB1_DIAGNOSTICS_FILE);
            buildSearchProfileConfig(SEARCH_PROFILES_FILE);
        } catch (Exception e) {
            /** @todo handle exception */
            System.out.println("org.jafer.conf.Config - Error attempting to build configuration!");
            e.printStackTrace();
        }
    }

    public static InputStream getResource(String path) {

        return new Config().getClass().getClassLoader().getResourceAsStream(path);
    }

    private static void buildRecordConfig(String recordDescriptorFile) throws JaferException {
        //Builds XML structure like the following e.g.:
        // <serializer priority="1" syntax="1.2.840.10003.5.10" targetSchema="http://www.openarchives.org/OAI/oai_marc">
        //   from OAI to MODS:
        //   <transform sourceSchema="http://www.openarchives.org/OAI/oai_marc" targetSchema="http://www.loc.gov/mods/">org/jafer/xsl/MARC21.xsl</transform>
        //   from OAI to MARC21:
        //   <transform sourceSchema="http://www.openarchives.org/OAI/oai_marc" targetSchema="http://www.loc.gov/MARC21/slim">org/jafer/xsl/OAIMARC2MARC21slim.xsl
        //       with nested transform from MARC21 to DC:
        //       <transform sourceSchema="http://www.loc.gov/MARC21/slim" targetSchema="http://purl.org/dc/elements/1.1/">org/jafer/xsl/MARC21slim2DC.xsl</transform>
        //  </transform>

        recordName = new Hashtable<String, String>();
        recordSyntax = new Hashtable<String, String>();
        recordSerializer = new Hashtable<String, String>();
        recordSerializerTargetSchema = new Hashtable<String, String>();
        recordTransformations = new Hashtable<String, Hashtable<String, Hashtable<String, Node>>>();
        syntaxCache = new Hashtable<String, int[]>();
        /** @todo SRW/XMLRecord hack: *//////
        targetSchemaNames = new Vector<String>();
        sourceSchemaNames = new Vector<String>();
        stylesheetNames = new Vector<String>();
        /////////////////////////////////////////

        Document recordDescriptorDocument = config.parseDocument(recordDescriptorFile);
        recordTransformDocument = DOMFactory.newDocument();
        Node transformRoot = recordTransformDocument.createElement("transformRoot");
        recordTransformDocument.appendChild(transformRoot);

        Hashtable<String, Hashtable<String, Node>> transformNodes;
        String syntax, oidName, serializer, schema, priority;
        Node oidNode, serializerNode, transformNode;
        NodeList oidNodes = selectNodeList(recordDescriptorDocument, "recordDescriptor/oid");
        for (int i = 0; i < oidNodes.getLength(); i++) {
            oidNode = oidNodes.item(i);
            oidName = getNodeAttributeValue(oidNode, "name");
            syntax = getNodeAttributeValue(oidNode, "syntax");
            priority = getNodeAttributeValue(oidNode, "priority");
            serializerNode = selectSingleNode(oidNode, "serializer");
            recordName.put(syntax, oidName);
            recordSyntax.put(oidName, syntax);
            if (serializerNode != null) {
                serializer = getValue(serializerNode);
                schema = getNodeAttributeValue(serializerNode, "targetSchema");
                transformNode = recordTransformDocument.importNode(serializerNode, false);
                ((Element) transformNode).setAttribute("priority", priority);
                ((Element) transformNode).setAttribute("syntax", syntax);
                transformRoot.appendChild(transformNode);
                transformNodes = new Hashtable<String, Hashtable<String, Node>>();
                transformNodes.put("fromSerializer", new Hashtable<String, Node>());
                transformNodes.put("toSerializer", new Hashtable<String, Node>());
                transformNodes.get("fromSerializer").put(schema, transformNode);
                transformNodes.get("toSerializer").put(schema, transformNode);
                buildTransformNodes(oidNode, transformNode, new Vector<String>(), new Hashtable<String, Integer>(),
                        transformNodes, schema, true);
                buildTransformNodes(oidNode, transformNode, new Vector<String>(), new Hashtable<String, Integer>(),
                        transformNodes, schema, false);
                recordTransformations.put(syntax, transformNodes);
                recordSerializerTargetSchema.put(syntax, schema);
                recordSerializer.put(syntax, serializer);
            }
            /** @todo SRW/XMLRecord hack: */
            buildSchemaTransforms(oidNode);
        }
    }

    private static void buildTransformNodes(Node oidNode, Node transformNode, Vector<String> path,
            Hashtable<String, Integer> schemaDepth, Hashtable<String, Hashtable<String, Node>> schemaNodes,
            String fromSchema, boolean fromSerializer) throws JaferException {

        if (path.contains(fromSchema))
            return;
        path = new Vector<String>(path);
        path.add(fromSchema);

        NodeList nodes;
        Hashtable<String, Node> transformNodes;
        if (fromSerializer) {
            transformNodes = schemaNodes.get("fromSerializer");
            nodes = selectNodeList(oidNode, "transform[@sourceSchema='" + fromSchema + "']");
        } else {
            transformNodes = schemaNodes.get("toSerializer");
            nodes = selectNodeList(oidNode, "transform[@targetSchema='" + fromSchema + "']");
        }

        for (int i = 0; i < nodes.getLength(); i++) {
            String toSchema;
            if (fromSerializer)
                toSchema = getNodeAttributeValue(nodes.item(i), "targetSchema");
            else
                toSchema = getNodeAttributeValue(nodes.item(i), "sourceSchema");

            if (!path.contains(toSchema)) {

                if (transformNodes.containsKey(toSchema)
                        && path.size() < ((Integer) schemaDepth.get(toSchema)).intValue()) {
                    Node child = (Node) transformNodes.get(toSchema);
                    Node parent = child.getParentNode();
                    parent.removeChild(child);
                    transformNodes.remove(toSchema);
                    schemaDepth.remove(toSchema);
                }

                if (!transformNodes.containsKey(toSchema)) {
                    Node child = recordTransformDocument.importNode(nodes.item(i), true);
                    transformNode.appendChild(child);
                    schemaDepth.put(toSchema, Integer.valueOf(path.size()));
                    transformNodes.put(toSchema, child);
                    buildTransformNodes(oidNode, child, path, schemaDepth, schemaNodes, toSchema, fromSerializer);
                }
            }
        }
    }

    private static void buildSchemaTransforms(Node oidNode) throws JaferException {
        /** @todo No priorities, just a list of possible transforms... */
        NodeList nodes = selectNodeList(oidNode, "./*");
        String stylesheetName;
        Element el;

        for (int i = 0; i < nodes.getLength(); i++) {
            el = (Element) nodes.item(i);
            if (el.getNodeName().equals("transform")) {
                stylesheetName = getValue(el);
                if (!stylesheetNames.contains(stylesheetName)) {
                    sourceSchemaNames.add(el.getAttribute("sourceSchema"));
                    targetSchemaNames.add(el.getAttribute("targetSchema"));
                    stylesheetNames.add(stylesheetName);
                }
            }
        }
    }

    public static Document getRecordTransformDocument() {

        return recordTransformDocument;
    }

    public static String getRecordSerializer(String syntax) throws JaferException {

        if (recordSerializer.containsKey(syntax))
            return recordSerializer.get(syntax);
        else
            throw new JaferException(
                    "recordSyntax " + syntax + " not found in recordDescriptor file " + RECORD_DESCRIPTOR_FILE);
    }

    public static String getRecordSerializerTargetSchema(String syntax) throws JaferException {

        if (recordSerializerTargetSchema.containsKey(syntax))
            return recordSerializerTargetSchema.get(syntax);
        else
            throw new JaferException(
                    "recordSyntax " + syntax + " not found in recordDescriptor file " + RECORD_DESCRIPTOR_FILE);
    }

    public static String getRecordNameFromSyntax(String syntax) throws JaferException {

        if (recordName.containsKey(syntax))
            return recordName.get(syntax);
        else
            throw new JaferException(
                    "recordSyntax " + syntax + " not found in recordDescriptor file " + RECORD_DESCRIPTOR_FILE);
    }

    public static String getRecordSyntaxFromName(String name) throws JaferException {

        if (recordSyntax.containsKey(name))
            return recordSyntax.get(name);
        else
            throw new JaferException(
                    "syntax Name " + name + " not found in recordDescriptor file " + RECORD_DESCRIPTOR_FILE);
    }

    public static boolean isSyntaxEqual(String syntaxA, String syntaxB) {

        return isSyntaxEqual(convertSyntax(syntaxA), convertSyntax(syntaxB));
    }

    public static boolean isSyntaxEqual(int[] syntaxA, int[] syntaxB) {

        return Arrays.areEqual(syntaxA, syntaxB);
    }

    public static int[] convertSyntax(String syntaxString) {
        /** @todo rename to convertSyntaxString()? */
        if (syntaxString == null || syntaxString.equals("") || syntaxString.indexOf('.') < 1)
            return new int[0];
        int[] result = syntaxCache.get(syntaxString);
        if (result == null) {
            String[] oidStringArray = syntaxString.split("\\.");
            result = new int[oidStringArray.length];

            for (int i = 0; i < result.length; i++)
                result[i] = Integer.parseInt(oidStringArray[i]);
            /** @todo catch NumberFormatException */
            syntaxCache.put(syntaxString, result);
        }
        return result;
    }

    public static String convertSyntax(int[] syntaxArray) {

        StringBuffer syntaxString = new StringBuffer(syntaxArray.length * 4);
        syntaxString.append(syntaxArray[0]);
        for (int i = 1; i < syntaxArray.length; i++) {
            syntaxString.append('.');
            syntaxString.append(String.valueOf(syntaxArray[i]));
        }
        return syntaxString.toString();
    }

    public static String getRecordSyntax(String schema) throws JaferException {

        int currentPriority = 0, priority = Integer.MAX_VALUE;
        String currentSyntax = null, syntax = null;
        Hashtable<String, Node> transformsNodes;
        Node transformNode;

        Enumeration<String> syntaxKeys = recordTransformations.keys();
        while (syntaxKeys.hasMoreElements()) {
            currentSyntax = (String) syntaxKeys.nextElement();
            transformsNodes = recordTransformations.get(currentSyntax).get("fromSerializer");
            transformNode = (Node) transformsNodes.get(schema);
            if (transformNode != null) {
                currentPriority = getTransforms(true, transformNode, new Vector<String>());
                if (currentPriority <= priority) {
                    priority = currentPriority;
                    syntax = currentSyntax;
                }
            }
        }
        if (syntax == null)
            throw new JaferException("NULL recordSyntax: schema " + schema + " not found in recordDescriptor file "
                    + RECORD_DESCRIPTOR_FILE);
        return syntax;
    }
    //
    //  public static Vector getTransformsToSerializer(String syntax, String schema) throws JaferException {
    //
    //      return getTransforms(false, syntax, schema);
    //  }
    //
    //  public static Vector getTransformsFromSerializer(String syntax, String schema) throws JaferException {
    //
    //      return getTransforms(true, syntax, schema);
    //  }

    public static Vector<String> getTransforms(boolean fromSerializer, String syntax, String schema)
            throws JaferException {

        Hashtable<String, Node> nodes;
        Hashtable<String, Hashtable<String, Node>> transformNodes = recordTransformations.get(syntax);
        if (fromSerializer && transformNodes.get("fromSerializer").containsKey(schema)) {
            nodes = transformNodes.get("fromSerializer");
        } else if ((!fromSerializer) && transformNodes.get("toSerializer").containsKey(schema)) {
            nodes = transformNodes.get("toSerializer");
        } else
            throw new JaferException("Schema " + schema + " for recordSyntax " + syntax
                    + " not found in recordDescriptor file " + RECORD_DESCRIPTOR_FILE);

        Node transformNode = (Node) nodes.get(schema);
        Vector<String> transforms = new Vector<String>();
        getTransforms(fromSerializer, transformNode, transforms);
        return transforms;
    }

    public static Vector<String> getTransforms(String recordSchema, String requestedRecordSchema)
            throws JaferException {

        /** order of transforms in recordDescriptor.xml dictates priority. */
        /** @todo optimize by caching Vectors of all possible paths. */
        Vector<String> transforms;
        String currentTargetSchemaName, currentSourceSchemaName;
        String firstmatch = null, stylesheetName = null;

        currentTargetSchemaName = requestedRecordSchema;

        for (int i = 0; i < targetSchemaNames.size(); i++) {
            if (targetSchemaNames.get(i).equals(currentTargetSchemaName)) {
                currentSourceSchemaName = (String) sourceSchemaNames.get(i);
                if (currentSourceSchemaName.equals(recordSchema)) {
                    transforms = new Vector<String>();
                    transforms.add(stylesheetNames.get(i));
                    return transforms;
                }
                if (firstmatch == null) {
                    firstmatch = currentSourceSchemaName;
                    stylesheetName = (String) stylesheetNames.get(i);
                }
            }
        }
        if (firstmatch == null) /** @todo: message */
            throw new JaferException("Message about failing to find suitable schema combinations.");

        transforms = getTransforms(recordSchema, firstmatch);
        transforms.add(stylesheetName);

        return transforms;
    }

    private static int getTransforms(boolean fromSerializer, Node transformNode, Vector<String> transforms)
            throws JaferException {

        int priority;

        if (transformNode.getNodeName().equals("serializer")) {
            try {
                return Integer.parseInt(getNodeAttributeValue(transformNode, "priority"));
            } catch (NumberFormatException ex) {
                return Integer.MAX_VALUE;
            }
        }
        priority = getTransforms(fromSerializer, transformNode.getParentNode(), transforms);
        if (fromSerializer)
            transforms.add(getValue(transformNode));
        else
            transforms.add(0, getValue(transformNode));

        return priority;
    }

    /////////////////////////
    private static Hashtable<String, String> schemaMappings;

    private static void buildSRWSchemaMappings() {

        schemaMappings = new Hashtable<String, String>();
        NodeList list = null;
        try {
            Document doc = config.parseDocument("org/jafer/conf/SRWSchemaMappings.xml");
            list = selectNodeList(doc, "schemaMappings/schema");
        } catch (JaferException ex) {
            /** @todo handle this when moving method call to constructor... */
        }
        Element el;
        for (int i = 0; i < list.getLength(); i++) {
            el = (Element) list.item(i);
            schemaMappings.put(el.getAttribute("srwSchema"), el.getAttribute("schemaNamespace"));
        }
    }

    public static String translateSRWSchemaName(String SRWSchemaValue) {

        String schemaName = null;
        if (schemaMappings == null)
            buildSRWSchemaMappings();

        schemaName = (String) schemaMappings.get(SRWSchemaValue);

        return schemaName;
    }

    /////////////////////////
    private static Hashtable<String, String> bib1ToCQLMappings;

    private static void buildBib1ToCQLMappings() {

        bib1ToCQLMappings = new Hashtable<String, String>();
        NodeList list = null;
        try {
            Document doc = config.parseDocument("org/jafer/conf/cqlContextSets.xml");
            list = selectNodeList(doc, "contextSets/contextSet");
        } catch (JaferException ex) {
            ex.printStackTrace();
            /** @todo handle this when moving method call to constructor... */
        }
        Element el;
        for (int i = 0; i < list.getLength(); i++) {
            el = (Element) list.item(i);
            String prefix = el.getAttribute("shortId");
            NodeList indexlist = null;
            try {
                indexlist = selectNodeList(el, "indexes/index");
            } catch (JaferException ex1) {
                /** @todo handle this when moving method call to constructor... */
            }
            Element el2;
            for (int j = 0; j < indexlist.getLength(); j++) {
                el2 = (Element) indexlist.item(j);
                if (el2.getAttribute("attributeSet").equalsIgnoreCase("bib1")) {
                    bib1ToCQLMappings.put(el2.getAttribute("useAttribute"),
                            prefix + "." + el2.getAttribute("name"));
                }
            }
        }
    }

    public static String translateBib1ToCQLIndex(String use) {

        String cqlIndex = null;
        if (bib1ToCQLMappings == null)
            buildBib1ToCQLMappings();

        cqlIndex = (String) bib1ToCQLMappings.get(use);

        return cqlIndex;
    }

    ////////////////////////

    private static void buildBib1AttributeConfig(String bib1AttributesFile) throws JaferException {

        Document attributeDocument = config.parseDocument(bib1AttributesFile);

        attributeSets = new Hashtable<String, Hashtable<String, Hashtable<String, String>>>();
        attributeTypeName = new Hashtable<String, String>();
        attributeTypeValue = new Hashtable<String, String>();

        String name, value;
        Node node;
        NodeList attributeSetNodes, attributeTypeNodes, attributeNodes;
        boolean defaultAttributeSet;

        attributeSetSyntax = getValue(selectSingleNode(attributeDocument, "attributeSets/@syntax"));
        attributeSetNodes = selectNodeList(attributeDocument, "attributeSets/attributeSet");
        for (int i = 0; i < attributeSetNodes.getLength(); i++) {
            node = attributeSetNodes.item(i);
            name = getNodeAttributeValue(node, "name");
            Hashtable<String, Hashtable<String, String>> attributeSet = new Hashtable<String, Hashtable<String, String>>();
            attributeSets.put(name, attributeSet);

            if (Boolean.valueOf(getNodeAttributeValue(node, "default")).booleanValue()) {
                defaultAttributeSet = true;
                attributeSetName = name;
            } else
                defaultAttributeSet = false;

            attributeTypeNodes = selectNodeList(node, "attributeType");
            for (int j = 0; j < attributeTypeNodes.getLength(); j++) {
                node = attributeTypeNodes.item(j);
                name = getNodeAttributeValue(node, "name");
                value = getNodeAttributeValue(node, "value");
                Hashtable<String, String> attributes = new Hashtable<String, String>();
                attributeSet.put(name, attributes);

                if (defaultAttributeSet) {
                    attributeTypeName.put(value, name);
                    attributeTypeValue.put(name, value);
                }

                attributeNodes = selectNodeList(node, "attribute");
                for (int k = 0; k < attributeNodes.getLength(); k++) {
                    node = attributeNodes.item(k);
                    name = getNodeAttributeValue(node, "name");
                    value = getNodeAttributeValue(node, "value");
                    attributes.put(name, value);
                }
            }
        }
    }

    public static String getAttributeSetName() {

        return attributeSetName;
    }

    public static String getAttributeSetSyntax() {

        return attributeSetSyntax;
    }

    public static int getAttributeValue(String attributeSetName, String attributeTypeName, String attributeName)
            throws JaferException {
        /** @todo throw exception lookup fails */
        int value;
        Hashtable<String, Hashtable<String, String>> attributeSet = attributeSets.get(attributeSetName);
        Hashtable<String, String> attributes = attributeSet.get(attributeTypeName);
        try {
            value = Integer.parseInt((String) attributes.get(attributeName));
        } catch (NumberFormatException ex) {
            throw new JaferException("attribute type (" + attributeName + ") not found in " + attributeSetName
                    + " attribute lookup table.");
        }
        return value;
    }

    //////////////////////////////////////////////////////////
    /**
     * Following methods added temporarily for use in CQL query generation:
     */
    public static String getSemanticAttributeName(String attributeValue) throws JaferException {
        /** @todo rename method................ */
        /** @todo throw exception if lookup fails */
        Document attributeDocument = config.parseDocument(BIB1_ATTRIBUTES_FILE);
        String name = "";
        Node node = selectSingleNode(attributeDocument,
                "attributeSets/attributeSet[@name='bib1']/attributeType[@name='semantic']/attribute[@value='"
                        + attributeValue + "']");

        if (node != null)
            name = getNodeAttributeValue(node, "name");
        return name;

    }

    public static String getRelationSymbol(String attributeValue) throws JaferException {
        /** @todo rename method................ */
        /** @todo convert all methods to use XPath? */
        /** @todo throw exception if lookup fails */
        Document attributeDocument = config.parseDocument(BIB1_ATTRIBUTES_FILE);
        String symbol = "";
        Node node = selectSingleNode(attributeDocument,
                "attributeSets/attributeSet[@name='bib1']/attributeType[@name='relation']/attribute[@value='"
                        + attributeValue + "']");

        if (node != null)
            symbol = getNodeAttributeValue(node, "symbol");
        return symbol;
    }

    /////////////////////////////////////////////////////////

    public static int getAttributeType(String attributeTypeName) throws JaferException {

        try {
            return Integer.parseInt((String) attributeTypeValue.get(attributeTypeName));
        } catch (NumberFormatException ex) {
            throw new JaferException("attributeTypeName not found");
        }
    }

    public static String getAttributeType(int attributeTypeValue) throws JaferException {

        String value = String.valueOf(attributeTypeValue);
        if (attributeTypeName.containsKey(value))
            return (String) attributeTypeName.get(value);
        else
            throw new JaferException("attributeTypeValue not found");
    }

    private static void buildBib1DiagnosticConfig(String bib1DiagnosticsFile) throws JaferException {

        Document diagnosticDocument = config.parseDocument(bib1DiagnosticsFile);
        bib1DiagMessage = new Hashtable<String, String>();
        bib1DiagAddInfo = new Hashtable<String, String>();

        String message, value, addInfo;
        Node node;
        NodeList nodes;

        nodes = selectNodeList(diagnosticDocument, "bib1Diagnostics/condition");
        for (int i = 0; i < nodes.getLength(); i++) {
            node = nodes.item(i);
            value = getNodeAttributeValue(node, "value");
            message = getValue(node);
            bib1DiagMessage.put(value, message);
            addInfo = getNodeAttributeValue(node, "addInfo");
            if (addInfo != null) {
                bib1DiagAddInfo.put(value, addInfo);
            }
        }
    }

    private static void buildSearchProfileConfig(String searchProfilesFile) throws JaferException {

        Document profileDocument = config.parseDocument(searchProfilesFile);
        searchProfileSyntax = new Hashtable<String, String>();
        searchProfileName = new Hashtable<String, String>();

        String name, syntax;
        Node node;
        NodeList searchProfileNodes;

        searchProfileNodes = selectNodeList(profileDocument, "searchProfiles/searchProfile");
        for (int i = 0; i < searchProfileNodes.getLength(); i++) {
            node = searchProfileNodes.item(i);
            name = getNodeAttributeValue(node, "name");
            syntax = getNodeAttributeValue(node, "syntax");
            searchProfileName.put(syntax, name);
            searchProfileSyntax.put(name, syntax);
        }
    }

    public static String getBib1Diagnostic(int condition) {

        return (String) bib1DiagMessage.get(String.valueOf(condition));
    }

    public static String getBib1DiagnosticAddInfo(int condition) {

        if (bib1DiagAddInfo.get(String.valueOf(condition)) != null)
            return (String) bib1DiagAddInfo.get(String.valueOf(condition));
        return "additional info";
    }

    public static String getSearchProfileSyntaxFromName(String searchProfileName) {

        return (String) searchProfileSyntax.get(searchProfileName);
    }

    public static String getSearchProfileNameFromSyntax(String searchProfileSyntax) {

        return (String) searchProfileName.get(searchProfileSyntax);
    }

    public static Document getCharacterSetsMap() throws JaferException {

        return config.parseDocument(CHARACTER_SETS_FILE);
    }

    public static Document getServerConfigDocument() throws JaferException {

        return config.parseDocument(SERVER_CONFIG_FILE);
    }

    public static Templates getServerDecodeTemplate() throws JaferException {
        if (serverDecode == null) {
            serverDecode = XMLTransformer.createTemplate(getServerDecode());
        }
        return serverDecode;
    }

    public static InputStream getServerDecode() throws JaferException {

        return getResource(SERVER_DECODE_FILE);
    }

    public static Templates getServerEncodeTemplate() throws JaferException {
        if (serverEncode == null) {
            serverEncode = XMLTransformer.createTemplate(getServerEncode());
        }
        return serverEncode;
    }

    public static InputStream getServerEncode() throws JaferException {

        return getResource(SERVER_ENCODE_FILE);
    }

    public static NodeList selectNodeList(Node node, String xPath) throws JaferException {
        return selectNodeList(node, xPath, false);
    }

    private static NodeList selectNodeList(Node node, String xPath, boolean retry) throws JaferException {
        NodeList nodeList = null;
        xPathAPI = new CachedXPathAPI();
        try {
            nodeList = xPathAPI.selectNodeList(node, xPath);
        } catch (javax.xml.transform.TransformerException e) {
            String message = "Error selecting Nodes: " + e.getMessage();
            throw new JaferException(message, e);
        } catch (ArrayIndexOutOfBoundsException e) {
            /**
             * There appears to be a problem with some versions of CachedXPathAPI
             * which produces array out of bounds when used for a long time
             * This is an attempt to workaround - i.e. refresh the Cache if this occurs
             */
            if (retry) {
                xPathAPI = new CachedXPathAPI();
                return selectNodeList(node, xPath, true);
            } else {
                String message = "Error selecting Nodes: " + e.getMessage();
                throw new JaferException(message, e);
            }
        }
        return nodeList;
    }

    private static String getNodeAttributeValue(Node node, String name) {
        Node att = node.getAttributes().getNamedItem(name);
        return (att == null) ? null : att.getNodeValue();
    }

    public static Node selectSingleNode(Node node, String xPath) throws JaferException {
        return selectSingleNode(node, xPath, false);
    }

    private static Node selectSingleNode(Node node, String xPath, boolean retry) throws JaferException {
        Node selection = null;
        try {
            selection = xPathAPI.selectSingleNode(node, xPath);
        } catch (javax.xml.transform.TransformerException e) {
            String message = "Error selecting Node: " + e.getMessage();
            throw new JaferException(message, e);
        } catch (ArrayIndexOutOfBoundsException e) {
            /**
             * There appears to be a problem with some versions of CachedXPathAPI
             * which produces array out of bounds when used for a long time
             * This is an attempt to workaround - i.e. refresh the Cache if this occurs
             */
            if (retry) {
                xPathAPI = new CachedXPathAPI();
                return selectSingleNode(node, xPath, true);
            } else {
                String message = "Error selecting Node: " + e.getMessage();
                throw new JaferException(message, e);
            }
        }

        return selection;
    }

    public static String getValue(Node node) {
        /** @todo Should method throw exception instead of returning empty string?? */
        if (node == null)
            return null;

        if (node.getNodeType() == Node.ATTRIBUTE_NODE)
            return node.getNodeValue();

        if (node.hasChildNodes() && node.getFirstChild().getNodeType() == Node.TEXT_NODE) {
            if (node.getFirstChild().getNodeValue() != null)
                return node.getFirstChild().getNodeValue();
            else
                return ""; //example: text node created with null content.
        }

        if (node.getNodeValue() != null)
            return node.getNodeValue();
        else
            return ""; //example: empty node.
    }

    private Document parseDocument(String documentPath) throws JaferException {

        InputStream stream = null;
        Document document = null;
        try {
            stream = this.getClass().getClassLoader().getResourceAsStream(documentPath);
            document = DOMFactory.parse(stream);
        } catch (JaferException e) {
            String message = "Error parsing document; could not find resource: " + documentPath;
            throw new JaferException(message, e);
        }
        return document;
    }
}