com.michelin.cio.hudson.plugins.qc.client.QualityCenterClientInstaller.java Source code

Java tutorial

Introduction

Here is the source code for com.michelin.cio.hudson.plugins.qc.client.QualityCenterClientInstaller.java

Source

/*
 * The MIT License
 *
 * Copyright (c) 2010, Manufacture Franaise des Pneumatiques Michelin, Thomas Maurel
 *
 * Permission is hereby granted, free of charge, to any person obtaining a copy
 * of this software and associated documentation files (the "Software"), to deal
 * in the Software without restriction, including without limitation the rights
 * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
 * copies of the Software, and to permit persons to whom the Software is
 * furnished to do so, subject to the following conditions:
 *
 * The above copyright notice and this permission notice shall be included in
 * all copies or substantial portions of the Software.
 *
 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
 * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
 * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
 * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
 * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
 * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
 * THE SOFTWARE.
 */

package com.michelin.cio.hudson.plugins.qc.client;

import com.michelin.cio.hudson.plugins.qc.Messages;
import com.michelin.cio.hudson.plugins.qc.QualityCenterUtils;
import hudson.AbortException;
import hudson.Extension;
import hudson.FilePath;
import hudson.Launcher;
import hudson.model.Hudson;
import hudson.model.Node;
import hudson.model.TaskListener;
import hudson.tools.ToolInstallation;
import hudson.tools.ToolInstaller;
import hudson.tools.ToolInstallerDescriptor;
import hudson.util.ArgumentListBuilder;
import hudson.util.FormValidation;
import java.io.FileInputStream;

import java.io.IOException;
import java.io.InputStream;
import java.io.InputStreamReader;
import java.io.OutputStreamWriter;
import java.io.PrintStream;
import java.net.URL;
import org.apache.commons.io.IOUtils;
import org.kohsuke.stapler.DataBoundConstructor;
import org.kohsuke.stapler.QueryParameter;

/**
 * @author Thomas Maurel
 */
public class QualityCenterClientInstaller extends ToolInstaller {

    private final String qcServerURL;
    private final String localPathToQCClient;

    public static final String INSTALLER_PATH_ON_SERVER = "PlugIns/ClientSideInstallation/";
    public static final String DLL_PATH_ON_NODE = "MERCURY INTERACTIVE\\Quality Center";
    public static final String INSTALLLER_FILE_NAME = "QCClient.msi";
    public static final String DLL_NAME = "OTAClient.dll";

    @DataBoundConstructor
    public QualityCenterClientInstaller(String qcServerURL, String localPathToQCClient) {
        super(null);
        this.qcServerURL = qcServerURL;
        this.localPathToQCClient = localPathToQCClient;
    }

    public String getLocalPathToQCClient() {
        return localPathToQCClient;
    }

    public String getQcServerURL() {
        return qcServerURL;
    }

    @Override
    public FilePath performInstallation(ToolInstallation tool, Node node, TaskListener log)
            throws IOException, InterruptedException {
        FilePath expectedLocation = preferredLocation(tool, node);
        PrintStream out = log.getLogger();
        FilePath qcFolder = expectedLocation.child(DLL_PATH_ON_NODE);

        // Check if it has been installed by Hudson or manually
        // Might be in the QC_HOME, or in QC_HOME\MERCURY INTERACTIVE\Quality Center
        if (expectedLocation.child(".installedByHudson").exists() || expectedLocation.child(DLL_NAME).exists()) {
            return expectedLocation;
        }

        if (qcFolder.child(".installedByHudson").exists() || qcFolder.child(DLL_NAME).exists()) {
            return qcFolder;
        }

        // Create the directory tree
        expectedLocation.mkdirs();
        FilePath file = expectedLocation.child(INSTALLLER_FILE_NAME);

        // If the installer is stored on the master, copy it from there
        if (localPathToQCClient != null & localPathToQCClient.length() > 0) {
            FilePath installerOnMaster = new FilePath(Hudson.MasterComputer.localChannel, localPathToQCClient);
            if (!installerOnMaster.exists()) {
                log.fatalError(Messages.QualityCenterClientInstaller_CannotFindInstaller());
                throw new AbortException();
            }

            if (installerOnMaster.isDirectory()) {
                log.fatalError(Messages.QualityCenterClientInstaller_ShouldBeAFile());
                throw new AbortException();
            }

            out.println(Messages.QualityCenterClientInstaller_CopyingFromMaster(localPathToQCClient));
            file.copyFrom(installerOnMaster);
        }
        // Else, download it from Quality Center Server
        else {
            String url;
            // Add a "/" at the end of the URL if it isnt already
            if (qcServerURL.lastIndexOf("/") == qcServerURL.length() - 1) {
                url = qcServerURL + INSTALLER_PATH_ON_SERVER + INSTALLLER_FILE_NAME;
            } else {
                url = qcServerURL + "/" + INSTALLER_PATH_ON_SERVER + INSTALLLER_FILE_NAME;
            }
            URL installURL = new URL(url);
            out.println(Messages.QualityCenterClientInstaller_Downloading(installURL));
            file.copyFrom(installURL);
        }

        // Perform installation
        install(node.createLauncher(log), log, expectedLocation.absolutize().getRemote(), file);

        // Successfully installed
        // Remove the installer
        file.delete();

        // Check if the DLL exists after installation
        if (!qcFolder.child(DLL_NAME).exists()) {
            log.fatalError(Messages.QualityCenterClientInstaller_CouldntFindDllAfterInstall(DLL_NAME));
            throw new AbortException();
        }

        qcFolder.child(".installedByHudson").touch(System.currentTimeMillis());

        return qcFolder;
    }

    public void install(Launcher launcher, TaskListener log, String expectedLocation, FilePath qcBundle)
            throws IOException, InterruptedException {
        PrintStream out = log.getLogger();
        String qcBundleName = qcBundle.getName();
        String qcBundlePath = qcBundle.absolutize().getRemote();

        out.println(Messages.QualityCenterClientInstaller_Installing(qcBundleName));
        String logFile = qcBundlePath + ".install.log";

        StringBuilder cmd = new StringBuilder();
        cmd.append('"').append(qcBundlePath).append('"');
        cmd.append(" /qn /norestart TARGETDIR=");
        cmd.append('"').append(expectedLocation).append('"');
        cmd.append(" /l ");
        cmd.append('"').append(logFile).append('"');

        // Run the install on the node
        // The result must be 0
        ArgumentListBuilder args = new ArgumentListBuilder().add("cmd.exe", "/C").addQuoted(cmd.toString());
        if (launcher.launch().cmds(args).stdout(out).pwd(expectedLocation).join() != 0) {
            log.fatalError(Messages.QualityCenterClientInstaller_AbortedInstall());
            // log file is in UTF-16
            InputStream is = new FileInputStream(logFile);
            InputStreamReader in = new InputStreamReader(is, "UTF-16");
            try {
                IOUtils.copy(in, new OutputStreamWriter(out));
            } finally {
                in.close();
                is.close();
            }
            throw new AbortException();
        }

        out.println(Messages.QualityCenterClientInstaller_InstallationSuccessfull());
    }

    @Extension
    public static final class DescriptorImpl extends ToolInstallerDescriptor<QualityCenterClientInstaller> {

        public String getDisplayName() {
            return Messages.QualityCenterClientInstaller_DescriptorImpl_DisplayName();
        }

        @Override
        public boolean isApplicable(Class<? extends ToolInstallation> toolType) {
            return toolType == QualityCenterClientInstallation.class;
        }

        public FormValidation doCheckQcServerURL(@QueryParameter String value) {
            // this can be used to check the existence of a file on the server, so needs to be protected
            Hudson.getInstance().checkPermission(Hudson.ADMINISTER);
            return QualityCenterUtils.checkQcServerURL(value, true);
        }

        public FormValidation doCheckLocalPathToQCClient(@QueryParameter String value) {
            // this can be used to check the existence of a file on the server, so needs to be protected
            Hudson.getInstance().checkPermission(Hudson.ADMINISTER);
            return QualityCenterUtils.checkLocalPathToInstaller(value, true);
        }

    }

}