buildframework/helium/sf/java/synergy/src/com/nokia/helium/synergy/ant/taskdefs/AbstractScmBaseTask.java
/*
* Copyright (c) 2007-2008 Nokia Corporation and/or its subsidiary(-ies).
* All rights reserved.
* This component and the accompanying materials are made available
* under the terms of the License "Eclipse Public License v1.0"
* which accompanies this distribution, and is available
* at the URL "http://www.eclipse.org/legal/epl-v10.html".
*
* Initial Contributors:
* Nokia Corporation - initial contribution.
*
* Contributors:
*
* Description:
*
*/
package com.nokia.helium.synergy.ant.taskdefs;
import java.io.File;
import java.io.IOException;
import java.lang.reflect.Field;
import java.util.ArrayList;
import java.util.List;
import org.apache.tools.ant.BuildException;
import org.apache.tools.ant.Project;
import org.apache.tools.ant.Task;
import org.apache.tools.ant.taskdefs.Execute;
import org.apache.tools.ant.taskdefs.LogStreamHandler;
import org.apache.tools.ant.taskdefs.condition.Os;
import com.nokia.helium.core.FileUtils;
/**
* <code>AbstractScmBaseTask</code> is an abstract class for GSCM related tasks
* such as rebaseline and deconfigure.
*
* @ant.task category="SCM"
*
*/
public abstract class AbstractScmBaseTask extends Task {
// common attributes
private String database; // -d dbname = Database name (or database path)
private String password; // -U password = UNIX password
private String ccmProject; // -p projectname = Project name (incompatible
// with -B)
private Integer verbosity;
private StringBuffer commandString = new StringBuffer();
private List<SCMCommandArgument> commands = new ArrayList<SCMCommandArgument>();
/**
* Return the Synergy project name.
*
* @return the Synergy project name.
*/
public String getCcmProject() {
return ccmProject;
}
/**
* Set Synergy Project Name to be used.
*
* @param ccmProject
* is the Synergy project name to set
* @ant.required
*/
public void setCcmProject(String ccmProject) {
this.ccmProject = ccmProject;
log("Set ccmProject to " + ccmProject);
}
/**
* Return the database name.
*
* @return the database name.
*/
public String getDatabase() {
return database;
}
/**
* Set Synergy Database name to be used.
*
* @param database
* is the name of the Synergy database to set.
* @ant.required
*/
public void setDatabase(String database) {
this.database = database;
log("Set database to " + database);
}
/**
* Return the Synergy password.
*
* @return the Synergy password.
*/
public String getPassword() {
return password;
}
/**
* Set Synergy Password to be used.
*
* @param password
* is the password to set.
* @ant.required
*/
public void setPassword(String password) {
this.password = password;
log("Set password to ****** ");
}
/**
* Return the verbosity.
*
* @return the verbosity.
*/
public Integer getVerbosity() {
return verbosity;
}
/**
* Set verbosity level to be used. Verbosity level ( 0 - quiet, 1 - verbose,
* 2 - very verbose). Exception will be raised for any other value.
*
* @param verbosity
* is the verbosity level to set.
* @ant.not-required
*/
public void setVerbosity(Integer verbosity) {
this.verbosity = verbosity;
log("Set verbosity to " + verbosity);
}
/**
* Method executes the current task.
*
*/
@Override
public void execute() {
// Set execution script
String script = getExecutionScript();
String systemPath = System.getenv("PATH");
String[] pathDirs = systemPath.split(File.pathSeparator);
if (Os.isFamily(Os.FAMILY_WINDOWS)) {
// Under windows it is not in the path...
String[] customPathDirs = new String[pathDirs.length + 1];
System.arraycopy(pathDirs, 0, customPathDirs, 0, pathDirs.length);
customPathDirs[customPathDirs.length - 1] = "C:\\apps\\base-apps\\bin";
pathDirs = customPathDirs;
} else {
// Under Linux environment it is a perl script...
script = script + ".pl";
}
File scriptFile = FileUtils
.findExecutableOnPath(script, pathDirs);
if (scriptFile == null) {
throw new BuildException("Could not find " + script
+ " application in the path.");
}
appendToCommandLine(scriptFile.getAbsolutePath());
// Build command argument list
buildCommandList();
// handle the command arguments
handleCommandArguments();
// configure verbosity
configureVerbosity();
// Execute the command-line launching as a separate process
runCommand();
log("Completed successfully.");
}
/**
* Method appends the given prefix and the command to the command string if
* the input cmd string is not null.
*
* @param prefix
* is the prefix of the cmd string input.
* @param cmd
* is the cmd string to be appended to main command string.
*/
protected void appendToCommandLine(String prefix, Object cmd) {
if (cmd != null) {
commandString.append(prefix);
commandString.append(" ");
commandString.append(cmd);
commandString.append(" ");
}
}
/**
* Method appends the given prefix to the command string if the boolean
* value input is set true.
*
* @param prefix
* is the prefix to be appended to the command string.
* @param bool
* indicates whether to append the prefix or not.
*/
protected void appendToCommandLine(String prefix, Boolean bool) {
if (bool != null && bool) {
appendToCommandLine(prefix);
}
}
/**
* Method appends the given cmd to the command string.
*
* @param cmd
* is the command string to be appended.
*/
protected void appendToCommandLine(String cmd) {
commandString.append(cmd);
commandString.append(" ");
}
/**
* Add the given command argument to the command list.
*
* @param fieldName
* is the name of the task field.
* @param cmdArg
* is the command argument to be added to the command list.
* @param required
* indicates whether the command argument is mandatory or not.
* @param fieldValue
* is the value of the given field
*/
protected void addCommandArg(String fieldName, String cmdArg,
Boolean required, Object fieldValue) {
SCMCommandArgument cmdObj = new SCMCommandArgument(fieldName, cmdArg,
required, fieldValue);
commands.add(cmdObj);
}
/**
* Add the given command argument to the command list. By default, the input
* command argument will be optional.
*
* @param fieldName
* is the name of the task field.
* @param cmdArg
* is the command argument to be added to the command list.
* @param fieldValue
* is the value of the given field
*/
protected void addCommandArg(String fieldName, String cmdArg,
Object fieldValue) {
addCommandArg(fieldName, cmdArg, false, fieldValue);
}
/**
* Method validates the given arguments.
*/
protected abstract void validateArguments();
/**
* Get the name of the script to execute
*
* @return the script name to execute
*/
protected abstract String getExecutionScript();
/**
* Build a command list consisting of all the required and optional command
* arguments of the current task.
*/
protected abstract void buildCommandList();
/**
* Method returns the correct verbosity level for the input choice.
*
* @param choice
* is the verbosity choice set by user.
* @return the verbosity level to set.
*/
protected abstract String getVerbosity(int choice);
// ----------------------------------- PRIVATE METHODS
// --------------------------------------
/**
* Method returns the requested {@link Field} object from the input
* {@link Class}. If the requested field is not found in the given
* {@link Class} then all its super classes are searched recursively.
*
* @param clazz
* is the {@link Class} of which the field is requested.
* @param fieldName
* is the name of the requested field.
* @return the requested field.
*/
private Field getField(Class<?> clazz, String fieldName) {
Field field = null;
if (clazz != null) {
try {
field = clazz.getDeclaredField(fieldName);
} catch (NoSuchFieldException nsfe) {
field = getField(clazz.getSuperclass(), fieldName);
}
}
return field;
}
/**
* Method process the command arguments set in the command list.
*
* @throws Exception
* if any error occurs while processing the command arguments.
*/
private void handleCommandArguments() {
StringBuffer missingArgs = new StringBuffer();
Field field = null;
for (SCMCommandArgument cmdObj : commands) {
field = getField(getClass(), cmdObj.fieldName);
if (field != null) {
Object fieldValue = field.getType().cast(cmdObj.fieldValue);
check4MandatoryCmdArguments(cmdObj, fieldValue, missingArgs);
buildCommand(cmdObj, fieldValue);
}
}
// handle missing args if any
handleMissingArguments(missingArgs);
validateArguments();
}
/**
* Method checks for the mandatory command arguments.
*
* @param cmdObj
* is the {@link SCMCommandArgument} used in verification
* @param fieldValue
* is the field value to verify
* @param missingArgs
* contains the mandatory command arguments which are missing.
*/
private void check4MandatoryCmdArguments(SCMCommandArgument cmdObj,
Object fieldValue, StringBuffer missingArgs) {
if (cmdObj.required && fieldValue == null) {
missingArgs.append(cmdObj.fieldName);
missingArgs.append(" ");
}
}
/**
* Method is used to construct an executable command string.
*
* @param cmdObj
* is the {@link SCMCommandArgument}
* @param fieldValue
* is the fieldValue containing the actual command argument.
*/
private void buildCommand(SCMCommandArgument cmdObj, Object fieldValue) {
if (fieldValue instanceof Boolean) {
appendToCommandLine(cmdObj.commandArgument, (Boolean)fieldValue);
} else {
appendToCommandLine(cmdObj.commandArgument, fieldValue);
}
}
/**
* Method throws a {@link BuildException} if any mandatory command arguments
* are missing.
*
* @param missingArgs
* is the {@link StringBuffer} consisting of mandatory command
* arguments which are missing.
*/
private void handleMissingArguments(StringBuffer missingArgs) {
if (missingArgs.length() > 0) {
throw new BuildException("Error: mandatory attributes are not defined - "
+ missingArgs.toString());
}
}
/**
* Configure the verbosity set by the user.
*/
private void configureVerbosity() {
if (verbosity != null) {
appendToCommandLine(getVerbosity(verbosity));
}
}
/**
* Execute the specified command.
*
* @throws Exception
* if execution fails or any error occurs while execution of the
* command.
*/
private void runCommand() {
String[] cmdline = commandString.toString().split(" ");
/*
* Note: static method call to Execute.runCommand does not run the given
* script here due to the setting of vmLauncher which acutally
* tries executing the script using Runtime.getRuntime().exec() method
* and this method cannot run the script without reference to the cmd or
* shell. (Similar with ExecTask)
*
* So creating an instance of Execute class helps to disable the
* vmLauncher and an OS dependent shellLauncher will be available for
* the execution of the script.
*/
// Make sure we replace the password on the command line before printing.
log("Executing: " + commandString.toString().replace(" " + password + " ", " *** "));
Execute exe = new Execute(new LogStreamHandler(this, Project.MSG_INFO,
Project.MSG_ERR));
exe.setAntRun(getProject());
exe.setCommandline(cmdline);
exe.setVMLauncher(false);
try {
int retval = exe.execute();
if (Execute.isFailure(retval)) {
throw new BuildException("Error: Script execution failure.");
}
} catch (IOException th) {
th.printStackTrace();
throw new BuildException("Error: Script execution failure.");
}
}
// ************************************* PRIVATE CLASSES
// ***************************************
/**
* <code>SCMCommandArgument</code> is a private class and represents a
* normal java bean which is used to hold the information related to SCM
* command arguments.
*/
private class SCMCommandArgument {
private String fieldName;
private Object fieldValue;
private String commandArgument;
private Boolean required;
/**
* Create an instance of {@link SCMCommandArgument}.
*
* @param fieldName
* is the name of the task field
* @param commandArg
* is the SCM command argument
* @param reqd
* indicates the input command argument is mandatory or not.
*/
protected SCMCommandArgument(String fieldName, String commandArg,
Boolean reqd, Object fieldValue) {
this.fieldName = fieldName;
this.commandArgument = commandArg;
this.required = reqd;
this.fieldValue = fieldValue;
}
}
}