com.runwaysdk.request.ClientRequestManager.java Source code

Java tutorial

Introduction

Here is the source code for com.runwaysdk.request.ClientRequestManager.java

Source

/**
 * Copyright (c) 2015 TerraFrame, Inc. All rights reserved.
 *
 * This file is part of Runway SDK(tm).
 *
 * Runway SDK(tm) 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 3 of the
 * License, or (at your option) any later version.
 *
 * Runway SDK(tm) 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 Runway SDK(tm).  If not, see <http://www.gnu.org/licenses/>.
 */
package com.runwaysdk.request;

import java.io.IOException;
import java.io.InputStream;
import java.net.URL;
import java.util.HashMap;
import java.util.Map;

import javax.xml.parsers.DocumentBuilder;
import javax.xml.parsers.DocumentBuilderFactory;
import javax.xml.parsers.ParserConfigurationException;

import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory;
import org.w3c.dom.Document;
import org.w3c.dom.Node;
import org.w3c.dom.NodeList;
import org.xml.sax.ErrorHandler;
import org.xml.sax.SAXException;
import org.xml.sax.SAXParseException;

import com.runwaysdk.configuration.ConfigurationManager;
import com.runwaysdk.configuration.ConfigurationManager.ConfigGroup;
import com.runwaysdk.configuration.RunwayConfigurationException;
import com.runwaysdk.constants.XMLConstants;

/**
 * Manages connections through an XML file for RMI and web services.
 */
public class ClientRequestManager {
    private Log log = LogFactory.getLog(ClientRequestManager.class);

    /**
     * HashMap to hold mappings between labels and Connection objects.
     */
    private Map<String, ConnectionLabel> connections;

    // /**
    // * The path to the XML file holding the connections.
    // */
    // private static String CONNECTIONS_XML_FILE = ClientProperties.getConnectionsFile();
    //
    // /**
    // * The path to the schema file defining the XML connection file.
    // */
    // private static String CONNECTIONS_SCHEMA_FILE = ClientProperties
    // .getConnectionsSchemaFile();

    /**
     * The string label denoting the default connection for all connections.
     */
    private static String DEFAULT_LABEL = "default";

    /**
     * The string denoting the element that represents a connection.
     */
    private static String CONNECTION_ELEMENT = "connection";

    /**
     * The position of the label.
     */
    private static String LABEL_ELEMENT = "label";

    /**
     * The position of the type element.
     */
    private static String TYPE_ELEMENT = "type";

    /**
     * The position of the address element.
     */
    private static String ADDRESS_ELEMENT = "address";

    /**
     * The single instance of this class.
     */
    public static class Singleton {
        public static final ClientRequestManager INSTANCE = new ClientRequestManager();
    }

    /**
     * Constructs a new ConnectionManager object by reading in an xml file detailing connections to servers and then populating a HashMap of Connection objects.
     */
    private ClientRequestManager() {
        // initialize the connections and proxies.
        connections = new HashMap<String, ConnectionLabel>();

        URL connectionsXmlFile;
        try {
            connectionsXmlFile = ConfigurationManager.getResource(ConfigGroup.CLIENT, "connections.xml");
        } catch (RunwayConfigurationException e) {
            log.warn("connections.xml configuration file not found.", e);
            return;
        }

        InputStream connectionsSchemaFile;
        try {
            connectionsSchemaFile = ConfigurationManager.getResource(ConfigGroup.XSD, "connectionsSchema.xsd")
                    .openStream();
        } catch (IOException e) {
            throw new RunwayConfigurationException(e);
        }

        Document document = null;
        DocumentBuilderFactory factory = DocumentBuilderFactory.newInstance();
        factory.setValidating(true);
        factory.setAttribute(XMLConstants.JAXP_SCHEMA_LANGUAGE, XMLConstants.W3C_XML_SCHEMA);
        factory.setAttribute(XMLConstants.JAXP_SCHEMA_SOURCE, connectionsSchemaFile);

        DocumentBuilder builder;
        try {
            builder = factory.newDocumentBuilder();
            builder.setErrorHandler(new XMLConnectionsErrorHandler());
            document = builder.parse(connectionsXmlFile.openStream());
        } catch (ParserConfigurationException e) {
            throw new ClientRequestException(e);
        } catch (SAXException e) {
            throw new ClientRequestException(e);
        } catch (IOException e) {
            throw new ClientRequestException(e);
        }
        parseDocument(document);
    }

    /**
     * Parses an XML document to extract connection information, ultimately creating Connection objects.
     * 
     * @param document
     */
    private void parseDocument(Document document) {
        NodeList connectionsList = document.getElementsByTagName(CONNECTION_ELEMENT);

        // go through each connection
        for (int i = 0; i < connectionsList.getLength(); i++) {
            Node connection = connectionsList.item(i);
            NodeList connectionData = connection.getChildNodes();

            // get the data for each connection
            String label = null;
            ConnectionLabel.Type type = null;
            String address = null;

            // we have to loop through all child nodes since whitespace
            // counts as a text node
            for (int j = 0; j < connectionData.getLength(); j++) {
                Node data = connectionData.item(j);

                // ignore all \n\t text nodes
                if (data.getNodeType() == Node.TEXT_NODE) {
                    continue;
                }

                if (data.getNodeName().equals(LABEL_ELEMENT)) {
                    label = data.getTextContent();
                } else if (data.getNodeName().equals(TYPE_ELEMENT)) {
                    String typeValue = data.getTextContent();
                    type = ConnectionLabel.Type.dereference(typeValue);
                } else if (data.getNodeName().equals(ADDRESS_ELEMENT)) {
                    address = data.getTextContent();
                }
            }

            connections.put(label, new ConnectionLabel(label, type, address));
        }
    }

    /**
     * Returns a ClientRequest object associated with the default connection for all connection types.
     * 
     * @return ClientRequest object associated with the default connection.
     */
    public static ConnectionLabel getDefaultConnection() {
        return getConnection(DEFAULT_LABEL);
    }

    /**
     * Returns a ClientRequest object that is associated with the specified label.
     * 
     * @param label
     *          The label to uniquely identify a connection.
     * @return The specified Connection object.
     */
    public static ConnectionLabel getConnection(String label) {
        // create the singleton instance if needed
        synchronized (ClientRequestManager.class) {
            if (Singleton.INSTANCE.connections.containsKey(label)) {
                return Singleton.INSTANCE.connections.get(label);
            } else {
                String error = "The client requested a connection to an unknown connection endpoint with the label ["
                        + label + "]";
                throw new ClientRequestException(error);
            }
        }
    }

    /**
     * Adds a new connection label, available for use in methods that create a new session. A programmatic way of modifying connections.xml at runtime. The connection is not saved to the connections.xml
     * file, it is stored in memory.
     * 
     * @param conn
     */
    public static void addConnection(ConnectionLabel conn) {
        Singleton.INSTANCE.connections.put(conn.getLabel(), conn);
    }

    /**
     * Error handler for connections.
     */
    private class XMLConnectionsErrorHandler implements ErrorHandler {

        public void warning(SAXParseException exception) throws SAXException {
            throw new ClientRequestException(exception);
        }

        public void error(SAXParseException exception) throws SAXException {
            throw new ClientRequestException(exception);
        }

        public void fatalError(SAXParseException exception) throws SAXException {
            throw new ClientRequestException(exception);
        }
    }
}