Package net.sourceforge.cruisecontrol.sourcecontrols

Source Code of net.sourceforge.cruisecontrol.sourcecontrols.CMSynergy

/********************************************************************************
* CruiseControl, a Continuous Integration Toolkit
* Copyright (c) 2001, ThoughtWorks, Inc.
* 651 W Washington Ave. Suite 600
* Chicago, IL 60661 USA
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions
* are met:
*
*     + Redistributions of source code must retain the above copyright
*       notice, this list of conditions and the following disclaimer.
*
*     + Redistributions in binary form must reproduce the above
*       copyright notice, this list of conditions and the following
*       disclaimer in the documentation and/or other materials provided
*       with the distribution.
*
*     + Neither the name of ThoughtWorks, Inc., CruiseControl, nor the
*       names of its contributors may be used to endorse or promote
*       products derived from this software without specific prior
*       written permission.
*
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
* "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
* LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
* A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR
* CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
* EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
* PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
* PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
* LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
* NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
* SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
********************************************************************************/
package net.sourceforge.cruisecontrol.sourcecontrols;

import java.io.File;
import java.io.IOException;
import java.text.ParseException;
import java.text.SimpleDateFormat;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.Date;
import java.util.Hashtable;
import java.util.Iterator;
import java.util.List;
import java.util.Locale;
import java.util.Properties;

import net.sourceforge.cruisecontrol.CruiseControlException;
import net.sourceforge.cruisecontrol.SourceControl;
import net.sourceforge.cruisecontrol.util.ValidationHelper;
import net.sourceforge.cruisecontrol.util.ManagedCommandline;
import net.sourceforge.cruisecontrol.util.Util;

import org.apache.log4j.Logger;

/**
* Checks for modifications made to a Telelogic CM Synergy repository.
* It does this by examining a provided reference project, getting
* the tasks from all folders in that project, and checking the
* completion time of those tasks against the last build.
*
* @author <a href="mailto:rjmpsmith@gmail.com">Robert J. Smith</a>
*/
public class CMSynergy implements SourceControl {
   
    /**
     * A delimiter used for data values returned from a CM Synergy query
     */
    public static final String CCM_ATTR_DELIMITER = "@#@#@#@";

    /**
     * A delimiter used to mark the end of a multi-lined result from a query
     */
    public static final String CCM_END_OBJECT = "<<<#@#@#>>>";
   
    /**
     * The default CM Synergy command line client executable
     */
    public static final String CCM_EXE = "ccm";
   
    /**
     * The environment variable used by CM Synergy to determine
     * which backend ccmSession to use when issuing commands.
     */
    public static final String CCM_SESSION_VAR = "CCM_ADDR";
       
    /**
     * The default CM Synergy session map file
     */
    public static final String CCM_SESSION_FILE = System
            .getProperty("user.home")
            + File.separator + ".ccmsessionmap";

    /**
     * An instance of the logging class
     */
    private static final Logger LOG = Logger.getLogger(CMSynergy.class);

    /**
     * A collection of properties which will be passed to and set
     * within the builder.
     */
    private Hashtable properties = new Hashtable();

    /**
     * The name of the property which will be set and passed to the
     * builder if any object has changed since the last build.
     */
    private String property = "cc.ccm.haschanged";

    /**
     * The version number delimeter used by the database with which
     * this CM Synergy session is connected.
     */
    private String ccmDelimiter = "-";
   
    /**
     * The URL for your installation of Change Synergy
     */
    private String changeSynergyURL;
   
    /**
     * The CCM database with which we wish to connect
     */
    private String ccmDb;
   
    /**
     * The CM Synergy executable used for executing commands. If not set,
     * we will use the default value "ccm".
     */
    private String ccmExe;
   
    /**
     * The CM Synergy project spec (2 part name) of the project we will
     * use as a template to determine if any new tasks have been completed.
     */
    private String projectSpec;
   
    /**
     * The instance number of the project. This is almost always "1", but might
     * need to be overridden if you are using DCM?
     */
    private String projectInstance = "1";
   
    /**
     * If set to true, the contents of the folders contained within the
     * project's reconfigure properties will be updated before we query
     * to find new tasks.
     */
    private boolean updateFolders = true;
   
    /**
     * The file which contains the mapping between CM Synergy session names
     * and IDs.
     */
    private File sessionFile;
   
    /**
     * The name of the CM Synergy session to use.
     */
    private String sessionName;
   
    /**
     * The date format as returned by your installation of CM Synergy.
     */
    private String ccmDateFormat = "EEE MMM dd HH:mm:ss yyyy"; // Fri Dec  3 17:51:56 2004
   
    /**
     * If set to true, the project will be reconfigured when changes are
     * detected.
     */
    private boolean reconfigure = false;
   
    /**
     * Used in conjunction with reconfigure. If set to true, all subprojects
     * will be reconfigured when changes are detected.
     */
    private boolean recurse = true;
   
    /**
     * If set to true, the work area location will not be queried and passed
     * to the builder.
     */
    private boolean ignoreWorkarea = false;
   
    /**
     * The locale used for parsing dates.
     */
    private Locale locale;
   
    /**
     * The language used to set the locale for parsing CM Synergy dates.
     */
    private String language = "en";
   
    /**
     * A reusable commandline for issuing CM Synergy commands
     */
    private ManagedCommandline cmd;
   
    /**
     * The country used to set the locale for parsing CM Synergy dates.
     */
    private String country = "US";
   
    /**
     * The number of modified tasks found
     */
    private int numTasks;
   
    /**
     * The number of modified objects found
     */
    private int numObjects;
   
    /**
     * Sets the name of the CM Synergy executable to use when issuing
     * commands.
     *
     * @param ccmExe the name of the CM Synergy executable
     */
    public void setCcmExe(String ccmExe) {
        this.ccmExe = ccmExe;
    }
   
    /**
     * Sets the CM Synergy project spec to be used as a template for calculating
     * changes. The value set here can be accessed from within the build as the
     * property "cc.ccm.project".
     *
     * @param projectSpec
     *            The project spec (in 2 part name format).
     */
    public void setProject(String projectSpec) {
        this.projectSpec = projectSpec;
    }
   
    /**
     * Sets the project's instance value. This value will be used in any query
     * which involves the project. Defaults to "1". This default should work for
     * most people. You might, however, need to override this value when using
     * DCM?
     *
     * @param projectInstance The instance number of the project.
     */
    public void setInstance(String projectInstance) {
        this.projectInstance = projectInstance;
    }
   
    /**
     * Sets the URL for your installation of Change Synergy. This is used to
     * create active links from the modification report to the Change Requests
     * associated with the modified tasks. If not set, the links will not be
     * created. If you wish to use this feature, you must also set the ccmdb
     * attribute to the remote location of the Synergy database.
     *
     * @param url
     *            The URL of your ChangeSynergy installation
     */
    public void setChangeSynergyURL(String url) {
        this.changeSynergyURL = url;
    }

    /**
     * Sets the remote Synergy database with which to connect. This is only
     * needed if you wish to create active links from the build results page to
     * your installation of Change Synergy. If you set this attribute, you must
     * also set the changesynergyurl attribute.
     *
     * @param db
     *            The remote Synergy database with which to connect (e.g.
     *            /ccmdb/mydb).
     */
    public void setCcmDb(String db) {
        this.ccmDb = db;
    }
   
    /**
     * Sets the value of the updateFolders attribute. If set to true, the
     * contents of the folders contained within the project's reconfigure
     * properties will be updated before we query to find new tasks.
     *
     * @param updateFolders
     */
    public void setUpdateFolders(boolean updateFolders) {
        this.updateFolders = updateFolders;
    }
   
    /**
     * Sets the file which contains the mapping between CM Synergy session names
     * and IDs. This file should be in the standard properties file format. Each
     * line should map one name to a CM Synergy session ID (as returned by the
     * "ccm status" command).
     * <p>
     * example:
     * <br><br>
     * session1=localhost:65024:192.168.1.17
     *
     * @param sessionFile
     *            The session file
     */
    public void setSessionFile(String sessionFile) {
        this.sessionFile = new File(sessionFile);
    }
   
    /**
     * Sets the name of the CM Synergy session to use with this plugin. This
     * name should appear in the specified session file.
     *
     * @param sessionName
     *            The session name
     *
     * @see #setSessionFile(String)
     */
    public void setSessionName(String sessionName) {
        this.sessionName = sessionName;
    }
   
    /**
     * Sets the date format used by your installation of CM Synergy. The format
     * string should use the syntax described in <code>SimpleDateFormat</code>.
     * The default is "EEE MMM dd HH:mm:ss yyyy" The value set here can be
     * accessed from within the build as the property "cc.ccm.dateformat".
     *
     * @param format
     *            the date format
     */
    public void setCcmDateFormat(String format) {
        this.ccmDateFormat = format;
    }
   
    /**
     * Sets the value of the reconfigure attribute. If set to true, the project
     * will be reconfigured when changes are detected. Default value is false.
     *
     * @param reconfigure
     */
    public void setReconfigure (boolean reconfigure) {
        this.reconfigure = reconfigure;
    }
   
    /**
     * Sets the value of the recurse attribute. Used in conjuction with the
     * reconfigure attribute. If set to true, all subprojects will also be
     * reconfigured when changes are detected. Default is true.
     *
     * @param recurse
     */
    public void setRecurse (boolean recurse) {
        this.recurse = recurse;
    }
   
    /**
     * Sets the value of the ignoreWorkarea attribute. If set to true, we will
     * not attempt to determine the location of the project's workarea, nor
     * will we pass the cc.ccm.workarea attribute to the builders. Default
     * is false.
     *
     * @param ignoreWorkarea
     */
    public void setIgnoreWorkarea (boolean ignoreWorkarea) {
        this.ignoreWorkarea = ignoreWorkarea;
    }

    /**
     * Sets the language used to create the locale for parsing CM Synergy dates.
     * The format should follow the ISO standard as specified by
     * <code>java.util.Locale</code>. The default is "en" (English).
     *
     * @param language
     *            The language to use when creating the <code>Locale</code>
     */
    public void setLanguage(String language) {
        this.language = language;
    }
   
    /**
     * Sets the country used to create the locale for parsing CM Synergy dates.
     * The format should follow the ISO standard as specified by
     * <code>java.util.Locale</code>. The default is "US" (United States).
     *
     * @param country The ISO country code to use
     */
    public void setCountry (String country) {
        this.country = country;
    }
   
    /* (non-Javadoc)
     * @see net.sourceforge.cruisecontrol.SourceControl#getProperties()
     */
    public Hashtable getProperties() {
        return properties;
    }

    /* (non-Javadoc)
     * @see net.sourceforge.cruisecontrol.SourceControl#setProperty(java.lang.String)
     */
    public void setProperty(String property) {
        this.property = property;
    }

    /* (non-Javadoc)
     * @see net.sourceforge.cruisecontrol.SourceControl#validate()
     */
    public void validate() throws CruiseControlException {
        ValidationHelper.assertIsSet(projectSpec, "project", this.getClass());
    }
   
    /* (non-Javadoc)
     * @see net.sourceforge.cruisecontrol.SourceControl#getModifications(java.util.Date, java.util.Date)
     */
    public List getModifications(Date lastBuild, Date now) {
               
        // Create a Locale appropriate for this installation
        locale = new Locale(language, country);
        if (!locale.equals(Locale.US)) {
            LOG.info("Locale has been set to " + locale.toString());
        }

        // Attempt to get the database delimiter
        cmd = createCcmCommand(ccmExe, sessionName,
                sessionFile);
        cmd.createArgument().setValue("delimiter");
        try {
            cmd.execute();
            cmd.assertExitCode(0);
            this.ccmDelimiter = cmd.getStdoutAsString().trim();
        } catch (Exception e) {
            StringBuffer buff = new StringBuffer(
                    "Could not connect to provided CM Synergy session");
            LOG.error(buff.toString(), e);
            return null;
        }
       
        LOG.info("Checking for modifications between " + lastBuild.toString()
                + " and " + now.toString());
               
        // If we were asked to update the folders, do so
        if (updateFolders) {
            refreshReconfigureProperties();
        }

        // Create a list of modifications based upon tasks completed
        // since the last build.
        numObjects = 0;
        numTasks = 0;
        List modifications = getModifiedTasks(lastBuild);
       
        LOG.info("Found " + numObjects + " modified object(s) in " + numTasks
                + " new task(s).");
              
        // If we were asked to reconfigure the project, do so
        if (reconfigure && (numObjects > 0)) {
            reconfigureProject();
        }

        // Pass to the build any relevent properties
        properties.put("cc.ccm.project", projectSpec);
        properties.put("cc.ccm.dateformat", ccmDateFormat);
        String sessionID = cmd.getVariable(CCM_SESSION_VAR);
        if (sessionID != null) {
            properties.put("cc.ccm.session", sessionID);
        }
        if (numObjects > 0) {
            properties.put(property, "true");
        }
        if (!ignoreWorkarea) {
            properties.put("cc.ccm.workarea", getWorkarea());
        }
       
        return modifications;
    }

    /**
     * Update the folders within the given project's reconfigure
     * properties.
     */
    private void refreshReconfigureProperties() {
        // Construct the CM Synergy command
        cmd.clearArgs();
        cmd.createArgument().setValue("reconfigure_properties");
        cmd.createArgument().setValue("-refresh");
        cmd.createArgument().setValue(projectSpec);
        try {
            cmd.execute();
            cmd.assertExitCode(0);
        } catch (Exception e) {
            LOG.warn("Could not refresh reconfigure properties for project \""
                    + projectSpec + "\".", e);
        }
    }
   
    /**
     * Get a list of all tasks which are contained in all folders in the
     * reconfigure properties of the specified project and were completed after
     * the last build.
     *
     * @return A list of <code>CMSynergyModifications</code> which represent
     *         the new tasks
     */
    private List getModifiedTasks(Date lastBuild) {
               
        // The format used for converting Java dates into CM Synergy dates
        // Note that the format used to submit commands differs from the
        // format used in the results of that command!?!
        SimpleDateFormat toCcmDate = new SimpleDateFormat(
                "yyyy/MM/dd HH:mm:ss", locale);

        // Construct the CM Synergy command
        cmd.clearArgs();
        cmd.createArgument().setValue("query");
        cmd.createArgument().setValue("-u");
       
        // Set up the output format
        cmd.createArgument().setValue("-f");
        cmd.createArgument().setValue(
                "%displayname" + CCM_ATTR_DELIMITER +      // 0
                "%release" + CCM_ATTR_DELIMITER +          // 1
                "%owner" + CCM_ATTR_DELIMITER +            // 2
                "%completion_date" + CCM_ATTR_DELIMITER +  // 3
                "%task_synopsis" + CCM_END_OBJECT);        // 4
       
        // Construct the query string
        cmd.createArgument().setValue(
                "is_task_in_folder_of(is_folder_in_rp_of('"
                + projectSpec
                + ":project:"
                + projectInstance
                + "')) and completion_date>time('"
                + toCcmDate.format(lastBuild)
                + "')");
       
        // Execute the command
        try {
            cmd.execute();
        } catch (Exception e) {
            LOG.error("Could not query for new tasks. The modification list "
                    + "will be empty!", e);
        }

        //create a modification list with discovered tasks
        List modificationList = new ArrayList();
        Iterator tasks = format(cmd.getStdoutAsList()).iterator();
        while (tasks.hasNext()) {
            numTasks++;
            String[] attributes = tokeniseEntry((String) tasks.next(), 5);
            if (attributes == null) {
                LOG.warn("Could not determine attributes for at least one "
                        + "discovered task! The modification set is suspect.");
                continue;
            }
            CMSynergyModification mod = new CMSynergyModification();
            mod.taskNumber = attributes[0];
            mod.revision = attributes[1];
            mod.userName = attributes[2];
            mod.modifiedTime = getDateFromSynergy(attributes[3]);
            mod.comment = attributes[4];
           
            // Populate the included files by quering for objects in the task
            getModifiedObjects(mod);
           
            // Find any Change Requests with which the task is associated
            getAssociatedCRs(mod);

            // Add the modification to the list
            modificationList.add(mod);
        }
       
        return modificationList;
    }

    /**
     * Split the results of a CM Synergy query into individual tokens. This
     * method was added for compatibility with the 1.3 JRE.
     *
     * @param line
     *            The line to be tokenised.
     * @param maxTokens
     *            The maximum number of tokens in the line
     *
     * @return The tokens found
     */
    private String[] tokeniseEntry(String line, int maxTokens) {
        int minTokens = maxTokens - 1; // comment may be absent.
        String[] tokens = new String[maxTokens];
        Arrays.fill(tokens, "");
        int tokenIndex = 0;
        for (int oldIndex = 0, index = line.indexOf(CCM_ATTR_DELIMITER, 0); true; oldIndex = index
                + CCM_ATTR_DELIMITER.length(), index = line.indexOf(
                CCM_ATTR_DELIMITER, oldIndex), tokenIndex++) {
            if (tokenIndex > maxTokens) {
                LOG.debug("Too many tokens; skipping entry");
                return null;
            }
            if (index == -1) {
                tokens[tokenIndex] = line.substring(oldIndex);
                break;
            } else {
                tokens[tokenIndex] = line.substring(oldIndex, index);
            }
        }
        if (tokenIndex < minTokens) {
            LOG.debug("Not enough tokens; skipping entry");
            return null;
        }
        return tokens;
    }
   
   
    /**
     * Populate the object list of a Modification by quering for objects
     * associated with the task.
     */
    private void getModifiedObjects(CMSynergyModification mod) {   
        // Construct the CM Synergy command
        cmd.clearArgs();
        cmd.createArgument().setValue("task");
        cmd.createArgument().setValue("-show");
        cmd.createArgument().setValue("objects");
           
        // Set up the output format
        cmd.createArgument().setValue("-f");
        cmd.createArgument().setValue(
                "%name" + CCM_ATTR_DELIMITER +      // 0
                "%version" + CCM_ATTR_DELIMITER +   // 1
                "%type" + CCM_ATTR_DELIMITER +      // 2
                "%instance" + CCM_ATTR_DELIMITER +  // 3
                "%project" + CCM_ATTR_DELIMITER +   // 4
                "%comment" + CCM_END_OBJECT);       // 5
           
        // Construct the query string
        cmd.createArgument().setValue(mod.taskNumber);
       
        // Execute the command
        try {
            cmd.execute();
        } catch (Exception e) {
            LOG.warn("Could not query for objects in task \"" + mod.taskNumber
                    + "\". The modification list will be incomplete!", e);
        }
       
        // Populate the modification with the object data from the task
        Iterator objects = format(cmd.getStdoutAsList()).iterator();
        while (objects.hasNext()) {
            numObjects++;
            String object = (String) objects.next();
            String[] attributes = tokeniseEntry(object, 6);
            if (attributes == null) {
                LOG.warn("Could not determine attributes for object associated "
                        + "with task \"" + mod.revision + "\".");
                continue;
            }
            // Add each object to the CMSynergyModification
            mod.createModifiedObject(attributes[0], attributes[1],
                    attributes[2], attributes[3], attributes[4], attributes[5]);
        }  
    }

    /**
     * Queries the CM Synergy repository to find any Change Requests with which
     * a task is associated. If the Change Synergy URL and database were provided,
     * we will add HTML based links to those CRs.
     *
     * @param mod The modification object
     */
    private void getAssociatedCRs(CMSynergyModification mod) {
        // Construct the CM Synergy command
        cmd.clearArgs();
        cmd.createArgument().setValue("query");
        cmd.createArgument().setValue("-u");
       
        // Set up the output format
        cmd.createArgument().setValue("-f");
        cmd.createArgument().setValue("%displayname");
       
        // Construct the query string
        cmd.createArgument().setValue(
                "cvtype='problem' and has_associated_task('task"
                + mod.taskNumber
                + ccmDelimiter
                + "1:task:probtrac')");
       
        // Execute the command
        try {
            cmd.execute();
        } catch (Exception e) {
            LOG.warn("Could not query for associated CRs. The modification list "
                    + "may be incomplete!", e);
        }

        // Add the Change Request(s) to the modification
        List crList = cmd.getStdoutAsList();
        if (crList != null) {
            Iterator crs = crList.iterator();
            while (crs.hasNext()) {
                String crNum = ((String) crs.next()).trim();
                CMSynergyModification.ChangeRequest cr = mod.createChangeRequest(crNum);
                if (changeSynergyURL != null && ccmDb != null) {
                    StringBuffer href = new StringBuffer(changeSynergyURL);
                    href.append("/servlet/com.continuus.webpt.servlet.PTweb?");
                    href.append("ACTION_FLAG=frameset_form&#38;TEMPLATE_FLAG=ProblemReportView&#38;database=");
                    href.append(ccmDb);
                    href.append("&#38;role=User&#38;problem_number=");
                    href.append(crNum);
                    cr.href = href.toString();
                }
            }
        }              
    }
   
    /**
     * Determine the work area location for the specified project.
     *
     * @return The work area location
     */
    private String getWorkarea() {
        String defaultWorkarea = ".";
       
        // Get the literal workarea from Synergy
        cmd.clearArgs();
        cmd.createArgument().setValue("attribute");
        cmd.createArgument().setValue("-show");
        cmd.createArgument().setValue("wa_path");
        cmd.createArgument().setValue("-project");
        cmd.createArgument().setValue(projectSpec);
       
        try {
            cmd.execute();
            cmd.assertExitCode(0);
        } catch (Exception e) {
            LOG.warn("Could not determine the workarea location for project \""
                    + projectSpec + "\".", e);
            return defaultWorkarea;
        }
       
        // The command will return the literal work area, but what we are
        // really interested in is the top level directory within that work area.
        File workareaPath = new File(cmd.getStdoutAsString()
                .trim());
        if (!workareaPath.isDirectory()) {
            LOG.warn("The workarea reported by Synergy does not exist or is not accessible by this session - \""
                            + workareaPath.toString() + "\".");
            return defaultWorkarea;
        }
        String[] dirs = workareaPath.list();
        if (dirs.length != 1) {
            LOG.warn("The workarea reported by Synergy is invalid - \""
                            + workareaPath.toString() + "\".");
            return defaultWorkarea;
        }
       
        // Found it!
        return workareaPath.getAbsolutePath() + File.separator + dirs[0];
    }
   
    /**
     * Reconfigure the project
     */
    private void reconfigureProject() {
        LOG.info("Reconfiguring project " + projectSpec + ".");
       
        // Construct the CM Synergy command
        cmd.clearArgs();
        cmd.createArgument().setValue("reconfigure");
        if (recurse) {
            cmd.createArgument().setValue("-recurse");
        }
        cmd.createArgument().setValue("-project");
        cmd.createArgument().setValue(projectSpec);
       
        try {
            cmd.execute();
            cmd.assertExitCode(0);
        } catch (Exception e) {
            LOG.warn("Could not reconfigure project \""
                    + projectSpec + "\".", e);
        }
    }
   
    /**
     * Format the output of a CM Synergy query by removing
     * newlines introduced by comments.
     *
     * @param in The <code>List</code> to be formated
     * @return The formated <code>List</code>
     */
    private List format(List in) {
        // Concatenate output lines until we hit the end of object delimiter.
        List out = new ArrayList();
        Iterator it = in.iterator();
        StringBuffer buff = new StringBuffer();
        while (it.hasNext()) {
            buff.append((String) it.next());
            int index = buff.toString().lastIndexOf(CCM_END_OBJECT);
            if (index > -1) {
                buff.delete(index, buff.length());
                out.add(buff.toString());
                buff = new StringBuffer();
            }
        }  
        return out;
    }

    /**
     * Parse a CM Synergy date string into a Java <code>Date</code>. If the
     * string cannot be parsed, a warning is written to the log, and the current
     * date is returned.
     *
     * @param dateString
     *            the date string to parse
     * @return The date
     *
     * @see #setCcmDateFormat(String)
     */
    private Date getDateFromSynergy(String dateString) {
        SimpleDateFormat fromCcmDate = new SimpleDateFormat(ccmDateFormat,
                locale);
        Date date;
        try {
            date = fromCcmDate.parse(dateString);
        } catch (ParseException e) {
            LOG.warn("Could not parse CM Synergy date \"" + dateString
                    + "\" into Java Date using format \"" + ccmDateFormat
                    + "\".", e);
            date = new Date();
        }
        return date;
    }
   
    /**
     * Given a CM Synergy session name, looks up the corresponding session ID.
     *
     * @param sessionName
     *            The CM Synergy session name
     * @param sessionFile
     *            The session map file
     * @return The session ID.
     *
     * @throws CruiseControlException
     */
    public static String getSessionID(String sessionName, File sessionFile)
            throws CruiseControlException {

        // If no session file was provided, try to use the default
        if (sessionFile == null) {
            sessionFile = new File(CCM_SESSION_FILE);
        }
       
        // Load the persisted session information from file
        Properties sessionProperties = null;
        try {
            sessionProperties = Util.loadPropertiesFromFile(sessionFile);
        } catch (IOException e) {
            throw new CruiseControlException (e);
        }

        // Look up and return the full session ID
        return sessionProperties.getProperty(sessionName);
    }
   
    /**
     * Creates a <code>ManagedCommandline</code> configured to run CM Synergy
     * commands.
     *
     * @param ccmExe
     *            Full path of the CM Synergy command line client (or
     *            <code>null</code> to use the default).
     * @param sessionName
     *            The name of the session as stored in the map file (or
     *            <code>null</code> to use the default session).
     * @param sessionFile
     *            The CM Synergy session map file (or <code>null</code> to use
     *            the default).
     * @return A configured <code>ManagedCommandline</code>
     */
    public static ManagedCommandline createCcmCommand(String ccmExe,
            String sessionName, File sessionFile) {
       
        // If no executable name was provided, use the default
        if (ccmExe == null) {
            ccmExe = CCM_EXE;
        }
       
        // Attempt to get the appropriate CM Synergy session
        String sessionID = null;
        if (sessionName != null) {
            try {
                sessionID = getSessionID(sessionName, sessionFile);
                if (sessionID == null) {
                    LOG.error("Could not find a session ID for CM Synergy session named \""
                            + sessionName
                            + "\". Attempting to use the default (current) session.");
                }
            } catch (CruiseControlException e) {
                LOG.error("Failed to look up CM Synergy session named \""
                        + sessionName
                        + "\". Attempting to use the default (current) session.",
                        e);
            }
        }

        // Create a managed command line
        ManagedCommandline command = new ManagedCommandline(ccmExe);

        // If we were able to find a CM Synergy session ID, use it
        if (sessionID != null) {
            command.setVariable(CCM_SESSION_VAR, sessionID);
        }

        return command;
    }         
}
TOP

Related Classes of net.sourceforge.cruisecontrol.sourcecontrols.CMSynergy

TOP
Copyright © 2018 www.massapi.com. All rights reserved.
All source code are property of their respective owners. Java is a trademark of Sun Microsystems, Inc and owned by ORACLE Inc. Contact coftware#gmail.com.