org.rhq.cassandra.Deployer.java Source code

Java tutorial

Introduction

Here is the source code for org.rhq.cassandra.Deployer.java

Source

/*
 *
 *  * RHQ Management Platform
 *  * Copyright (C) 2005-2012 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, version 2, as
 *  * published by the Free Software Foundation, and/or the GNU Lesser
 *  * General Public License, version 2.1, also as published by the Free
 *  * Software Foundation.
 *  *
 *  * 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 and the GNU Lesser General Public License
 *  * for more details.
 *  *
 *  * You should have received a copy of the GNU General Public License
 *  * and the GNU Lesser 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.cassandra;

import java.io.File;
import java.io.FileReader;
import java.io.FileWriter;
import java.io.IOException;
import java.io.InputStream;
import java.io.StringReader;
import java.util.Map;
import java.util.Properties;
import java.util.Set;

import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory;

import org.rhq.core.util.PropertiesFileUpdate;
import org.rhq.core.util.StringUtil;
import org.rhq.core.util.TokenReplacingReader;
import org.rhq.core.util.ZipUtil;
import org.rhq.core.util.stream.StreamUtil;

/**
 * Deployment consists of a few steps.
 *
 * <ol>
 *   <li>Unzip Cassandra to disk.</li>
 *   <li>Update configuration files like casssandra.yaml. This involves performing variable substitution.</li>
 *   <li>Update file permissions to make scripts in the bin directory executable.</li>
 * </ol>
 *
 * The values used in the variable substitution are supplied by an instance of {@link DeploymentOptions}.
 *
 * @author John Sanda
 */
public class Deployer {

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

    private DeploymentOptions deploymentOptions;

    public void setDeploymentOptions(DeploymentOptions deploymentOptions) {
        this.deploymentOptions = deploymentOptions;
    }

    public void unzipDistro() throws DeploymentException {
        InputStream inputStream = getClass().getResourceAsStream("/cassandra.zip");
        File deployDir = new File(deploymentOptions.getBasedir());
        deployDir.mkdir();
        try {
            log.info("Unzipping storage node to " + deployDir);
            ZipUtil.unzipFile(inputStream, deployDir);
        } catch (IOException e) {
            log.error("An error occurred while unzipping the storage zip file", e);
            throw new DeploymentException("An error occurred while unzipping the storage zip file", e);
        }
    }

    public void applyConfigChanges() throws DeploymentException {
        File deployDir = new File(deploymentOptions.getBasedir());
        File confDir = new File(deployDir, "conf");
        Map<String, String> tokens = deploymentOptions.toMap();
        tokens.put("cluster.name", "rhq");

        applyConfigChanges(confDir, "cassandra.yaml", tokens);
        applyConfigChanges(confDir, "log4j-server.properties", tokens);
        applyChangesToCassandraJvmProps(confDir, deploymentOptions);

        // For windows, update the service wrapper env. It may not ne necessary to have updated cassandra-jvm.properties
        // as well as this file, but for now we'll update both, leaving the former as a dependably set file.
        if (File.separatorChar == '\\') {
            applyChangesToWindowsServiceWrapper(deployDir);
        }

        //        applyConfigChanges(confDir, "cassandra-env.sh", tokens);
    }

    private void applyConfigChanges(File confDir, String fileName, Map<String, String> tokens)
            throws DeploymentException {

        File filteredFile = new File(confDir, fileName);
        try {
            if (log.isInfoEnabled()) {
                log.info("Applying configuration changes to " + filteredFile);
            }
            File rhqFile = new File(confDir, "rhq." + fileName);
            TokenReplacingReader reader = new TokenReplacingReader(new FileReader(rhqFile), tokens);

            StreamUtil.copy(reader, new FileWriter(filteredFile));
            rhqFile.delete();
        } catch (IOException e) {
            log.error("An unexpected error occurred while apply configuration changes to " + filteredFile, e);
            throw new DeploymentException(
                    "An unexpected error occurred while apply configuration changes to " + filteredFile, e);
        }
    }

    private void applyChangesToCassandraJvmProps(File confDir, DeploymentOptions deploymentOptions)
            throws DeploymentException {

        File jvmPropsFile = new File(confDir, "cassandra-jvm.properties");
        try {
            log.info("Applying configuration changes to " + jvmPropsFile);

            PropertiesFileUpdate propertiesUpdater = new PropertiesFileUpdate(jvmPropsFile.getAbsolutePath());
            Properties properties = propertiesUpdater.loadExistingProperties();

            properties.setProperty("heap_min", "-Xms" + deploymentOptions.getHeapSize());
            properties.setProperty("heap_max", "-Xmx" + deploymentOptions.getHeapSize());
            properties.setProperty("heap_new", "-Xmn" + deploymentOptions.getHeapNewSize());
            properties.setProperty("thread_stack_size", "-Xss" + deploymentOptions.getStackSize());
            properties.setProperty("jmx_port", deploymentOptions.getJmxPort().toString());

            String javaVersion = System.getProperty("java.version");
            // The check here is taken right from cassandra-env.sh
            if ((!isOpenJDK() || javaVersion.compareTo("1.6.0") > 0)
                    || (javaVersion.equals("1.6.0") && getJavaPatchVersion() > 23)) {
                properties.put("java_agent", "-javaagent:$CASSANDRA_HOME/lib/jamm-0.2.5.jar");
            }

            propertiesUpdater.update(properties);
        } catch (IOException e) {
            log.error("An error occurred while updating " + jvmPropsFile, e);
            throw new DeploymentException("An error occurred while updating " + jvmPropsFile, e);
        }
    }

    private boolean isOpenJDK() {
        String javaVMName = System.getProperty("java.vm.name");
        return javaVMName.startsWith("OpenJDK");
    }

    private boolean isJava1_6() {
        String javaVersion = System.getProperty("java.version");
        return javaVersion.startsWith("1.6.0");
    }

    private int getJavaPatchVersion() {
        String javaVersion = System.getProperty("java.version");
        int startIndex = javaVersion.indexOf('_');

        if (startIndex == -1) {
            return 0;
        }

        return Integer.parseInt(javaVersion.substring(startIndex + 1, javaVersion.length()));
    }

    public void applyChangesToWindowsServiceWrapper(File deployDir) throws DeploymentException {
        File wrapperDir = new File(deployDir, "../bin/wrapper");
        File wrapperEnvFile = new File(wrapperDir, "rhq-storage-wrapper.env");

        try {
            log.info("Applying configuration changes to " + wrapperEnvFile);

            PropertiesFileUpdate propertiesUpdater = new PropertiesFileUpdate(wrapperEnvFile.getAbsolutePath());
            Properties wrapperEnvProps = propertiesUpdater.loadExistingProperties();

            wrapperEnvProps.setProperty("set.heap_min", "-Xms" + deploymentOptions.getHeapSize());
            wrapperEnvProps.setProperty("set.heap_max", "-Xmx" + deploymentOptions.getHeapSize());
            wrapperEnvProps.setProperty("set.heap_new", "-Xmn" + deploymentOptions.getHeapNewSize());
            wrapperEnvProps.setProperty("set.thread_stack_size", "-Xss" + deploymentOptions.getStackSize());
            wrapperEnvProps.setProperty("set.jmx_port", deploymentOptions.getJmxPort().toString());
            // This is always on by default, just set it literally
            wrapperEnvProps.setProperty("set.heap_dump_on_OOMError", "-XX:+HeapDumpOnOutOfMemoryError");
            // This is always set to the bin directory initially
            wrapperEnvProps.setProperty("set.heap_dump_dir",
                    "-XX:HeapDumpPath=" + useForwardSlash(new File(deployDir, "bin").getAbsolutePath()));

            propertiesUpdater.update(wrapperEnvProps);
        } catch (IOException e) {
            log.error("An error occurred while updating " + wrapperEnvFile, e);
            throw new DeploymentException("An error occurred while updating " + wrapperEnvFile, e);
        }
    }

    /**
     * Ensure that the path uses only forward slash.
     * @param path
     * @return forward-slashed path, or null if path is null
     */
    private static String useForwardSlash(String path) {
        return (null != path) ? path.replace('\\', '/') : null;
    }

    public void updateFilePerms() {
        File deployDir = new File(deploymentOptions.getBasedir());
        File binDir = new File(deployDir, "bin");

        log.info("Updating file permissions in " + binDir);

        for (File f : binDir.listFiles()) {
            f.setExecutable(true);
        }
    }

    public void updateStorageAuthConf(Set<String> addresses) {
        File confDir = new File(deploymentOptions.getBasedir(), "conf");
        File authFile = new File(confDir, "rhq-storage-auth.conf");

        try {
            authFile.delete();
            StreamUtil.copy(new StringReader(StringUtil.collectionToString(addresses, "\n")),
                    new FileWriter(authFile), true);
        } catch (IOException e) {
            throw new RuntimeException("Failed to update " + authFile);
        }
    }

}