org.rhq.modules.plugins.jbossas7.helper.JBossCliConfiguration.java Source code

Java tutorial

Introduction

Here is the source code for org.rhq.modules.plugins.jbossas7.helper.JBossCliConfiguration.java

Source

/*
 * RHQ Management Platform
 * Copyright (C) 2005-2015 Red Hat, Inc.
 * All rights reserved.
 *
 * This program is free software; you can redistribute it and/or modify
 * it under the terms of the GNU General Public License as published by
 * the Free Software Foundation version 2 of the License.
 *
 * This program 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 General Public License for more details.
 *
 * You should have received a copy of the GNU General Public License
 * along with this program; if not, write to the Free Software Foundation, Inc.,
 * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA
 */

package org.rhq.modules.plugins.jbossas7.helper;

import java.io.File;
import java.io.FileInputStream;
import java.io.IOException;
import java.io.InputStream;
import java.util.Map;
import java.util.Map.Entry;

import javax.xml.namespace.QName;
import javax.xml.parsers.DocumentBuilder;
import javax.xml.parsers.DocumentBuilderFactory;
import javax.xml.transform.OutputKeys;
import javax.xml.transform.Transformer;
import javax.xml.transform.TransformerFactory;
import javax.xml.transform.dom.DOMSource;
import javax.xml.transform.stream.StreamResult;
import javax.xml.xpath.XPath;
import javax.xml.xpath.XPathConstants;
import javax.xml.xpath.XPathExpression;
import javax.xml.xpath.XPathExpressionException;
import javax.xml.xpath.XPathFactory;

import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory;
import org.w3c.dom.Comment;
import org.w3c.dom.Document;
import org.w3c.dom.Element;
import org.w3c.dom.Node;

import org.rhq.core.util.file.FileUtil;

/**
 * A JBoss CLI configuration - loaded from jboss-cli.xml
 *
 * @author Libor Zoubek
 */
public class JBossCliConfiguration {

    private final Log log = LogFactory.getLog(JBossCliConfiguration.class);

    private Document document;
    private XPathFactory xpathFactory;
    private final File jbossCliXml;
    private final ServerPluginConfiguration serverConfig;

    /**
     *
     * @param jbossCliXml absolute path to jboss-cli.xml file
     */
    public JBossCliConfiguration(File jbossCliXml, ServerPluginConfiguration serverConfig) throws Exception {
        this.jbossCliXml = jbossCliXml;
        this.serverConfig = serverConfig;
        DocumentBuilderFactory factory = DocumentBuilderFactory.newInstance();
        DocumentBuilder builder = factory.newDocumentBuilder();
        InputStream is = new FileInputStream(jbossCliXml);
        try {
            this.document = builder.parse(is);
        } finally {
            is.close();
        }
        this.xpathFactory = XPathFactory.newInstance();
    }

    private Comment createComment() {
        return this.document.createComment(" added by RHQ plugin ");
    }

    /**
     * Setup SSL configuration properties by reading it from HostConfiguration (XML File) and expecting VAULT 
     * to be present. 
     * @param hostConfig
     * @return
     */
    public String configureSecurityUsingVault(HostConfiguration hostConfig) {
        Map<String, String> vaultOptions = hostConfig.getVault();
        if (vaultOptions == null) {
            return "Vault definition was not found in server configuration file";
        }
        TruststoreConfig serverIdentity = hostConfig.getServerIdentityKeystore();
        if (serverIdentity == null) {
            return "Could not find ssl configuration for management interface";
        }

        JBossCliConstants constants = getCliConstants();
        if (constants.version().compareTo("1.3") < 0) {
            return "Cannot store truststore passwords using vault, because it is not supported by this version of EAP";
        }

        Node sslNode = (Node) xpathExpression("/jboss-cli/ssl", XPathConstants.NODE);
        // clean-up existing ssl node
        if (sslNode != null) {
            this.document.getDocumentElement().removeChild(sslNode);
        }
        sslNode = addChildElement(document.getDocumentElement(), "ssl");
        sslNode.appendChild(createComment());

        Node vaultNode = this.document.createElement("vault");
        sslNode.appendChild(vaultNode);

        for (Entry<String, String> vaultOpt : vaultOptions.entrySet()) {
            Element opt = addChildElement(vaultNode, "vault-option");
            opt.setAttribute("name", vaultOpt.getKey());
            opt.setAttribute("value", vaultOpt.getValue());
        }

        addChildElement(sslNode, constants.alias(), serverIdentity.getAlias());
        addChildElement(sslNode, constants.truststore(), serverIdentity.getPath());
        // in standalone.xml vault value is referred as ${VAULT:...} we need to strip it for jboss-cli.xml
        addChildElement(sslNode, constants.truststorePassword(),
                stripBrackets(serverIdentity.getKeystorePassword()));

        TruststoreConfig clientKeystore = hostConfig.getClientAuthenticationTruststore();
        if (clientKeystore != null) { // 2-way authentication properties
            addChildElement(sslNode, constants.keystore(), clientKeystore.getPath());
            addChildElement(sslNode, constants.keystorePassword(),
                    stripBrackets(clientKeystore.getKeystorePassword()));
            addChildElement(sslNode, constants.keyPassword(), stripBrackets(clientKeystore.getKeyPassword()));
        }
        return null;
    }

    /**
     * Setup SSL configuration properties by reading it from ServerPluginConfiguration and writing it as plain text
     * @return null if any configuration change has been made, otherwise message indicating reason why it was not changed
     */
    public String configureSecurity() {
        if (serverConfig.isSecure()) {
            if (serverConfig.getTruststore() != null) {
                Node sslNode = (Node) xpathExpression("/jboss-cli/ssl", XPathConstants.NODE);
                // clean-up existing ssl node
                if (sslNode != null) {
                    this.document.getDocumentElement().removeChild(sslNode);
                }
                sslNode = addChildElement(document.getDocumentElement(), "ssl");
                sslNode.appendChild(createComment());

                JBossCliConstants constants = getCliConstants();

                addChildElement(sslNode, constants.truststore(), serverConfig.getTruststore());
                addChildElement(sslNode, constants.truststorePassword(), serverConfig.getTruststorePassword());
                if (serverConfig.isClientcertAuthentication()) {
                    addChildElement(sslNode, constants.keystore(), serverConfig.getKeystore());
                    addChildElement(sslNode, constants.keystorePassword(), serverConfig.getKeystorePassword());
                    addChildElement(sslNode, constants.keyPassword(), serverConfig.getKeyPassword());
                }
                return null;
            }
            return "Truststore path is not set";
        }
        return "Secure connection is not enabled";
    }

    /**
     * 
     * @return corresponding constants based on xml namespace version
     */
    JBossCliConstants getCliConstants() {
        String ns = this.document.getDocumentElement().getAttribute("xmlns");
        String[] split = ns.split(":"); // urn:jboss:cli:1.3
        if (split.length != 4) {
            // unable to parse
            return new JBossCliConstants10();
        }
        String versionStr = split[3];
        // 1.3 and all future versions
        if (versionStr.compareTo("1.3") >= 0) {
            return new JBossCliConstants13();
        }
        if (versionStr.compareTo("1.2") == 0) {
            return new JBossCliConstants12();
        }
        if (versionStr.compareTo("1.1") == 0) {
            return new JBossCliConstants11();
        }
        return new JBossCliConstants10();
    }

    /**
     * strips ${} expression from given string
     * @param value
     * @return
     */
    private String stripBrackets(String value) {
        if (value != null && value.length() > 3 && value.startsWith("${")) {
            return value.substring(2, value.length() - 1);
        }
        return value;
    }

    /**
     * Setup controller host and port defaults
     * @return null if any configuration change has been made, otherwise message indicating reason why it was not changed
     */
    public String configureDefaultController() {
        Node ctrlNode = this.document.createElement("default-controller");
        ctrlNode.appendChild(createComment());
        addChildElement(ctrlNode, "host", serverConfig.getNativeHost());
        addChildElement(ctrlNode, "port", String.valueOf(serverConfig.getNativePort()));
        Node existing = (Node) xpathExpression("/jboss-cli/default-controller", XPathConstants.NODE);
        if (existing != null) {
            this.document.getDocumentElement().replaceChild(ctrlNode, existing);
        }
        return null;
    }

    /**
     * Write changes to file - flushes changes made by i.e. {@link #configureSecurity()}. This also creates backup of the 
     * file (appends ".original" suffix)
     * @throws Exception
     */
    public void writeToFile() throws Exception {
        if (!jbossCliXml.canWrite()) {
            throw new IOException(jbossCliXml + " is not writable");
        }
        File backup = new File(jbossCliXml.getParentFile(), jbossCliXml.getName() + ".original");
        try {
            log.debug("Backup " + jbossCliXml + " to " + backup);
            FileUtil.copyFile(jbossCliXml, backup);
        } catch (IOException ex) {
            throw new IOException("Could not create backup file " + backup, ex);
        }

        Transformer transformer = TransformerFactory.newInstance().newTransformer();
        transformer.setOutputProperty(OutputKeys.INDENT, "yes");
        transformer.setOutputProperty("{http://xml.apache.org/xslt}indent-amount", "4");
        //initialize StreamResult with File object to save to file
        StreamResult result = new StreamResult(this.jbossCliXml);
        DOMSource source = new DOMSource(this.document);
        transformer.transform(source, result);
    }

    private void addChildElement(Node parent, String tagName, String textContent) {
        if (tagName != null && textContent != null && !textContent.isEmpty()) {
            Node element = this.document.createElement(tagName);
            element.setTextContent(textContent);
            parent.appendChild(element);
        }
    }

    private Element addChildElement(Node parent, String tagName) {
        Element element = this.document.createElement(tagName);
        parent.appendChild(element);
        return element;
    }

    public String obtainXmlPropertyViaXPath(String xpathExpression) {
        return (String) xpathExpression(xpathExpression, XPathConstants.STRING);
    }

    private Object xpathExpression(String xpathExpression, QName returnType) {
        XPath xpath = this.xpathFactory.newXPath();
        try {
            XPathExpression expr = xpath.compile(xpathExpression);
            return expr.evaluate(this.document, returnType);
        } catch (XPathExpressionException e) {
            log.error("Evaluation of XPath expression failed: " + e.getMessage());
            return null;
        }
    }

    /**
     * tagNames in jboss-cli.xml were changing overtime. We need to provide the right set of tagNames for 
     * each known version of jboss-cli.xml schema
     * @author lzoubek
     *
     */
    static interface JBossCliConstants {
        String version();

        String truststore();

        String truststorePassword();

        String keystore();

        String keystorePassword();

        String alias();

        String keyPassword();
    }

    private static class JBossCliConstants10 implements JBossCliConstants {

        @Override
        public String version() {
            return "1.0";
        }

        @Override
        public String truststore() {
            return "trustStore";
        }

        @Override
        public String truststorePassword() {
            return "trustStorePassword";
        }

        @Override
        public String keystore() {
            return "keyStore";
        }

        @Override
        public String keystorePassword() {
            return "keyStorePassword";
        }

        @Override
        public String alias() {
            return null;
        }

        @Override
        public String keyPassword() {
            return null;
        }
    }

    private static class JBossCliConstants11 extends JBossCliConstants10 {
        @Override
        public String version() {
            return "1.1";
        }

        @Override
        public String truststore() {
            return "trust-store";
        }

        @Override
        public String truststorePassword() {
            return "trust-store-password";
        }

        @Override
        public String keystore() {
            return "key-store";
        }

        @Override
        public String keystorePassword() {
            return "key-store-password";
        }

        @Override
        public String alias() {
            return "alias";
        }

        @Override
        public String keyPassword() {
            return "key-password";
        }
    }

    static class JBossCliConstants12 extends JBossCliConstants11 {
        @Override
        public String version() {
            return "1.2";
        }
    }

    static class JBossCliConstants13 extends JBossCliConstants12 {
        @Override
        public String version() {
            return "1.3";
        }
    }
}