| /******************************************************************************* |
| * Copyright (c) 2008 IBM Corporation. |
| * All rights reserved. This program and the accompanying materials |
| * are made available under the terms of the Eclipse Public License v1.0 |
| * which accompanies this distribution, and is available at |
| * http://www.eclipse.org/legal/epl-v10.html |
| * |
| * Contributors: |
| * IBM Corporation - initial API and implementation |
| ******************************************************************************/ |
| package org.eclipse.ptp.rm.core.rtsystem; |
| |
| import java.io.IOException; |
| import java.text.MessageFormat; |
| import java.util.ArrayList; |
| import java.util.HashMap; |
| import java.util.Iterator; |
| import java.util.List; |
| import java.util.Map; |
| import java.util.Map.Entry; |
| import java.util.regex.Matcher; |
| import java.util.regex.Pattern; |
| |
| import org.eclipse.core.runtime.Assert; |
| import org.eclipse.core.runtime.CoreException; |
| import org.eclipse.core.runtime.IProgressMonitor; |
| import org.eclipse.core.runtime.IStatus; |
| import org.eclipse.core.runtime.Status; |
| import org.eclipse.core.runtime.jobs.Job; |
| import org.eclipse.osgi.util.NLS; |
| import org.eclipse.ptp.core.PTPCorePlugin; |
| import org.eclipse.ptp.core.attributes.ArrayAttribute; |
| import org.eclipse.ptp.core.attributes.AttributeManager; |
| import org.eclipse.ptp.core.attributes.BooleanAttribute; |
| import org.eclipse.ptp.core.attributes.EnumeratedAttribute; |
| import org.eclipse.ptp.core.attributes.IAttribute; |
| import org.eclipse.ptp.core.attributes.IAttributeDefinition; |
| import org.eclipse.ptp.core.attributes.IllegalValueException; |
| import org.eclipse.ptp.core.attributes.StringAttribute; |
| import org.eclipse.ptp.core.elements.IPJob; |
| import org.eclipse.ptp.core.elements.IPQueue; |
| import org.eclipse.ptp.core.elements.IResourceManager; |
| import org.eclipse.ptp.core.elements.attributes.JobAttributes; |
| import org.eclipse.ptp.remote.core.IRemoteProcess; |
| import org.eclipse.ptp.remote.core.IRemoteProcessBuilder; |
| import org.eclipse.ptp.rm.core.ToolsRMPlugin; |
| import org.eclipse.ptp.rm.core.messages.Messages; |
| import org.eclipse.ptp.rm.core.rmsystem.AbstractEffectiveToolRMConfiguration; |
| import org.eclipse.ptp.rm.core.utils.DebugUtil; |
| import org.eclipse.ptp.utils.core.linux.ArgumentParser; |
| |
| /** |
| * Implements a job that controls the parallel application launched with a command line tool. |
| * This class is different from {@link AbstractRemoteCommandJob} because it is not aimed towards parsing output of the |
| * tool called by command line, but to prepare a whole launch environment for the command line tool, also supporting |
| * semantics of the parallel application launcher. |
| * |
| * @author Daniel Felix Ferber |
| */ |
| public abstract class AbstractToolRuntimeSystemJob extends Job implements IToolRuntimeSystemJob { |
| |
| protected String jobID; |
| protected String queueID; |
| protected boolean debug = false; |
| protected IRemoteProcess process = null; |
| protected AttributeManager attrMgr; |
| protected AbstractToolRuntimeSystem rtSystem; |
| |
| protected boolean terminateJobFlag = false; |
| |
| public AbstractToolRuntimeSystemJob(String jobID, String queueID, String name, AbstractToolRuntimeSystem rtSystem, |
| AttributeManager attrMgr) { |
| super(name); |
| this.attrMgr = attrMgr; |
| this.rtSystem = rtSystem; |
| this.jobID = jobID; |
| this.queueID = queueID; |
| } |
| |
| @Override |
| public Object getAdapter(Class adapter) { |
| if (adapter == IToolRuntimeSystemJob.class) { |
| return this; |
| } |
| return super.getAdapter(adapter); |
| } |
| |
| public String getQueueID() { |
| return queueID; |
| } |
| |
| public String getJobID() { |
| return jobID; |
| } |
| |
| public AbstractToolRuntimeSystem getRtSystem() { |
| return rtSystem; |
| } |
| |
| public AttributeManager getAttrMgr() { |
| return attrMgr; |
| } |
| |
| public boolean isDebug() { |
| return debug; |
| } |
| |
| @Override |
| protected IStatus run(IProgressMonitor monitor) { |
| BooleanAttribute debugAttr = attrMgr.getAttribute(JobAttributes.getDebugFlagAttributeDefinition()); |
| if (debugAttr != null) { |
| debug = debugAttr.getValue().booleanValue(); |
| } |
| |
| changeJobState(JobAttributes.State.STARTED); |
| |
| if (DebugUtil.RTS_JOB_TRACING_MORE) { |
| System.out.println("Launch attributes:"); //$NON-NLS-1$ |
| String array[] = getAttrMgr().toStringArray(); |
| for (int i = 0; i < array.length; i++) { |
| System.out.println(array[i]); |
| } |
| } |
| |
| try { |
| DebugUtil.trace(DebugUtil.RTS_JOB_TRACING_MORE, "RTS job #{0}: handle prepare", jobID); //$NON-NLS-1$ |
| doPrepareExecution(monitor); |
| } catch (CoreException e) { |
| changeJobState(JobAttributes.State.ERROR); |
| return new Status(IStatus.ERROR, ToolsRMPlugin.getDefault().getBundle().getSymbolicName(), Messages.AbstractToolRuntimeSystemJob_Exception_PrepareExecution, e); |
| } |
| |
| if (monitor.isCanceled()) { |
| changeJobState(JobAttributes.State.TERMINATED); |
| return new Status(IStatus.OK, ToolsRMPlugin.getDefault().getBundle().getSymbolicName(), Messages.AbstractToolRuntimeSystemJob_UserCanceled); |
| } |
| |
| try { |
| /* |
| * Calculate command and environment. |
| */ |
| DebugUtil.trace(DebugUtil.RTS_JOB_TRACING_MORE, "About to run RTS job #{0}.", jobID); //$NON-NLS-1$ |
| List<String> command = null; |
| Map<String,String> environment = null; |
| String directory = null; |
| try { |
| AttributeManager baseSubstitutionAttributeManager = retrieveBaseSubstitutionAttributes(); |
| environment = retrieveEnvironment(baseSubstitutionAttributeManager); |
| directory = retrieveWorkingDirectory(baseSubstitutionAttributeManager); |
| |
| AttributeManager commandSubstitutionAttributeManager = retrieveCommandSubstitutionAttributes(baseSubstitutionAttributeManager, directory, environment); |
| if (isDebug()) { |
| command = retrieveCreateDebugCommand(commandSubstitutionAttributeManager); |
| } else { |
| command = retrieveCreateLaunchCommand(commandSubstitutionAttributeManager); |
| } |
| if (DebugUtil.RTS_JOB_TRACING) { |
| System.out.println("Available macros for environment and work directory:"); //$NON-NLS-1$ |
| for (IAttribute<?, ?, ?> attr : baseSubstitutionAttributeManager.getAttributes()) { |
| System.out.println(MessageFormat.format(" {0}={1}", attr.getDefinition().getId(), attr.getValueAsString())); //$NON-NLS-1$ |
| } |
| System.out.println("Available macros for command:"); //$NON-NLS-1$ |
| for (IAttribute<?, ?, ?> attr : commandSubstitutionAttributeManager.getAttributes()) { |
| System.out.println(MessageFormat.format(" {0}={1}", attr.getDefinition().getId(), attr.getValueAsString())); //$NON-NLS-1$ |
| } |
| System.out.println("Environment variables:"); //$NON-NLS-1$ |
| for (Entry<String, String> env : environment.entrySet()) { |
| System.out.println(MessageFormat.format(" export {0}={1}", env.getKey(), env.getValue())); //$NON-NLS-1$ |
| } |
| System.out.println(MessageFormat.format("Work directory: {0}", directory)); //$NON-NLS-1$ |
| ArgumentParser argumentParser = new ArgumentParser(command); |
| System.out.println(MessageFormat.format("Command: {0}", argumentParser.getCommandLine(false))); //$NON-NLS-1$ |
| } |
| } catch (CoreException e) { |
| changeJobState(JobAttributes.State.ERROR); |
| return new Status(IStatus.ERROR, ToolsRMPlugin.getDefault().getBundle().getSymbolicName(), Messages.AbstractToolRuntimeSystemJob_Exception_CreateCommand, e); |
| } |
| |
| try { |
| DebugUtil.trace(DebugUtil.RTS_JOB_TRACING_MORE, "RTS job #{0}: handle before execution", jobID); //$NON-NLS-1$ |
| doBeforeExecution(monitor); |
| } catch (CoreException e) { |
| changeJobState(JobAttributes.State.ERROR); |
| return new Status(IStatus.ERROR, ToolsRMPlugin.getDefault().getBundle().getSymbolicName(), Messages.AbstractToolRuntimeSystemJob_Exception_BeforeExecution, e); |
| } |
| |
| if (monitor.isCanceled()) { |
| changeJobState(JobAttributes.State.TERMINATED); |
| return new Status(IStatus.OK, ToolsRMPlugin.getDefault().getBundle().getSymbolicName(), Messages.AbstractToolRuntimeSystemJob_UserCanceled); |
| } |
| |
| /* |
| * Execute remote command for the job. |
| */ |
| try { |
| IRemoteProcessBuilder processBuilder = rtSystem.createProcessBuilder(command, directory); |
| processBuilder.environment().putAll(environment); |
| DebugUtil.trace(DebugUtil.RTS_JOB_TRACING_MORE, "RTS job #{0}: start", jobID); //$NON-NLS-1$ |
| process = processBuilder.start(); |
| } catch (IOException e) { |
| changeJobState(JobAttributes.State.ERROR); |
| return new Status(IStatus.ERROR, ToolsRMPlugin.getDefault().getBundle().getSymbolicName(), Messages.AbstractToolRuntimeSystemJob_Exception_ExecuteCommand, e); |
| } |
| |
| try { |
| DebugUtil.trace(DebugUtil.RTS_JOB_TRACING_MORE, "RTS job #{0}: handle start", jobID); //$NON-NLS-1$ |
| doExecutionStarted(monitor); |
| } catch (CoreException e) { |
| changeJobState(JobAttributes.State.ERROR); |
| return new Status(IStatus.ERROR, ToolsRMPlugin.getDefault().getBundle().getSymbolicName(), Messages.AbstractToolRuntimeSystemJob_Exception_ExecutionStarted, e); |
| } |
| |
| if (monitor.isCanceled()) { |
| changeJobState(JobAttributes.State.TERMINATED); |
| return new Status(IStatus.OK, ToolsRMPlugin.getDefault().getBundle().getSymbolicName(), Messages.AbstractToolRuntimeSystemJob_UserCanceled); |
| } |
| |
| changeJobState(JobAttributes.State.RUNNING); |
| |
| try { |
| DebugUtil.trace(DebugUtil.RTS_JOB_TRACING_MORE, "RTS job #{0}: wait to finish", jobID); //$NON-NLS-1$ |
| doWaitExecution(monitor); |
| } catch (CoreException e) { |
| changeJobState(JobAttributes.State.ERROR); |
| return new Status(IStatus.ERROR, ToolsRMPlugin.getDefault().getBundle().getSymbolicName(), Messages.AbstractToolRuntimeSystemJob_Exception_WaitExecution, e); |
| } |
| |
| if (monitor.isCanceled()) { |
| changeJobState(JobAttributes.State.TERMINATED); |
| return new Status(IStatus.OK, ToolsRMPlugin.getDefault().getBundle().getSymbolicName(), Messages.AbstractToolRuntimeSystemJob_UserCanceled); |
| } |
| |
| DebugUtil.trace(DebugUtil.RTS_JOB_TRACING, "RTS job #{0}: exit value {1}", jobID, process.exitValue()); //$NON-NLS-1$ |
| |
| |
| // try { |
| // DebugUtil.trace(DebugUtil.COMMAND_TRACING, "RTS job #{0}: wait to finish", jobID); //$NON-NLS-1$ |
| // process.waitFor(); |
| // } catch (InterruptedException e) { |
| // changeJobState(JobAttributes.State.ERROR); |
| // return new Status(IStatus.ERROR, Activator.getDefault().getBundle().getSymbolicName(), "Failed while terminating the command.", e); |
| // } |
| |
| try { |
| DebugUtil.trace(DebugUtil.RTS_JOB_TRACING_MORE, "RTS job #{0}: handle finish", jobID); //$NON-NLS-1$ |
| doExecutionFinished(monitor); |
| } catch (CoreException e) { |
| changeJobState(JobAttributes.State.ERROR); |
| return new Status(IStatus.ERROR, ToolsRMPlugin.getDefault().getBundle().getSymbolicName(), Messages.AbstractToolRuntimeSystemJob_Exception_ExecutionFinished, e); |
| } |
| |
| changeJobState(JobAttributes.State.TERMINATED); |
| |
| return new Status(IStatus.OK, ToolsRMPlugin.getDefault().getBundle().getSymbolicName(), NLS.bind(Messages.AbstractToolRuntimeSystemJob_Success, process.exitValue())); |
| |
| } finally { |
| DebugUtil.trace(DebugUtil.RTS_JOB_TRACING_MORE, "RTS job #{0}: cleanup", jobID); //$NON-NLS-1$ |
| final IResourceManager rm = PTPCorePlugin.getDefault().getUniverse().getResourceManager(rtSystem.getRmID()); |
| if (rm != null) { |
| final IPQueue queue = rm.getQueueById(getQueueID()); |
| if (queue != null) { |
| final IPJob ipJob = queue.getJobById(getJobID()); |
| if (ipJob != null) { |
| switch (ipJob.getState()) { |
| case TERMINATED: |
| case ERROR: |
| break; |
| case PENDING: |
| case RUNNING: |
| case STARTED: |
| case SUSPENDED: |
| case UNKNOWN: |
| changeJobState(JobAttributes.State.TERMINATED); |
| break; |
| } |
| } |
| } |
| } |
| doExecutionCleanUp(monitor); |
| } |
| } |
| |
| abstract protected void doPrepareExecution(IProgressMonitor monitor) throws CoreException; |
| |
| abstract protected void doExecutionCleanUp(IProgressMonitor monitor); |
| |
| abstract protected void doWaitExecution(IProgressMonitor monitor) throws CoreException; |
| |
| abstract protected void doExecutionFinished(IProgressMonitor monitor) throws CoreException; |
| |
| abstract protected void doExecutionStarted(IProgressMonitor monitor) throws CoreException; |
| |
| abstract protected void doBeforeExecution(IProgressMonitor monitor) throws CoreException; |
| |
| abstract protected void doTerminateJob(); |
| |
| /** |
| * Change the state of the job state. |
| * @param newState |
| */ |
| protected void changeJobState(JobAttributes.State newState) { |
| EnumeratedAttribute<JobAttributes.State> state = JobAttributes.getStateAttributeDefinition().create(newState); |
| AttributeManager attrManager = new AttributeManager(); |
| attrManager.addAttribute(state); |
| rtSystem.changeJob(jobID, attrManager); |
| } |
| |
| /** |
| * Retrieve the working directory for the launch. |
| * @param baseSubstitutionAttributeManager |
| * @return |
| */ |
| protected String retrieveWorkingDirectory(AttributeManager baseSubstitutionAttributeManager) { |
| /* |
| * TODO Return IPath instead of string |
| */ |
| String workdir = attrMgr.getAttribute(JobAttributes.getWorkingDirectoryAttributeDefinition()).getValue(); |
| String newWorkdir = replaceVariables(workdir, baseSubstitutionAttributeManager); |
| if (! workdir.equals(newWorkdir)) { |
| DebugUtil.trace(DebugUtil.RTS_JOB_TRACING_MORE, "Changed work directory from {0} to {1}", workdir, newWorkdir); //$NON-NLS-1$ |
| workdir = newWorkdir; |
| } |
| return workdir; |
| } |
| |
| /** |
| * Retrieve the environment variables. |
| * @param baseSubstitutionAttributeManager |
| */ |
| protected Map<String,String> retrieveEnvironment(AttributeManager baseSubstitutionAttributeManager) throws CoreException { |
| HashMap<String, String> environmentMap = new HashMap<String, String>(); |
| |
| /* |
| * First, get environment from the attribute manager. |
| */ |
| retrieveEnvironmentFromAttrMrg(environmentMap); |
| |
| /* |
| * Then, get extra environment variables that are specific for the tool. |
| */ |
| HashMap<String, String> extraEnvironmentMap = doRetrieveToolEnvironment(); |
| if (extraEnvironmentMap != null) { |
| environmentMap.putAll(extraEnvironmentMap); |
| } |
| |
| /* |
| * Do substitution on each environment variable. |
| */ |
| for (Iterator<Entry<String, String>> iterator = environmentMap.entrySet().iterator(); iterator.hasNext();) { |
| Entry<String, String> env = iterator.next(); |
| String value = env.getValue(); |
| String newValue = replaceVariables(value, baseSubstitutionAttributeManager); |
| if (! value.equals(newValue)) { |
| DebugUtil.trace(DebugUtil.RTS_JOB_TRACING_MORE, "Changed environment '{0}={1}' to '{0}={2}", env.getKey(), value, newValue); //$NON-NLS-1$ |
| env.setValue(newValue); |
| } |
| } |
| |
| return environmentMap; |
| } |
| |
| /** |
| * Retrieve additional environment variables that are specific for the tool. |
| */ |
| abstract protected HashMap<String, String> doRetrieveToolEnvironment() throws CoreException; |
| |
| private void retrieveEnvironmentFromAttrMrg( |
| HashMap<String, String> environmentMap) { |
| ArrayAttribute<String> environmentAttribute = getAttrMgr().getAttribute(JobAttributes.getEnvironmentAttributeDefinition()); |
| if (environmentAttribute != null) { |
| List<String> environment = environmentAttribute.getValue(); |
| for (String entry : environment) { |
| int i = entry.indexOf('='); |
| String key = entry.substring(0, i); |
| String value = entry.substring(i+1); |
| environmentMap.put(key, value); |
| } |
| } |
| } |
| |
| /** |
| * Retrieve attributes used to expand macros. |
| * @return |
| * @throws CoreException |
| */ |
| protected AttributeManager retrieveBaseSubstitutionAttributes() throws CoreException { |
| AttributeManager newAttributeManager = new AttributeManager(getAttrMgr().getAttributes()); |
| |
| /* |
| * First, add all default attributes that are default attributes for the launch. |
| * If they are not present in the launch attributes, then use default value. |
| */ |
| for (IAttributeDefinition<?, ?, ?> attributeDefinition : getDefaultSubstitutionAttributes()) { |
| IAttribute<?, ?, ?> attribute = newAttributeManager.getAttribute(attributeDefinition.getId()); |
| if (attribute == null) { |
| // Create one with default value. |
| try { |
| newAttributeManager.addAttribute(attributeDefinition.create()); |
| } catch (IllegalValueException e) { |
| throw new CoreException(new Status(IStatus.ERROR, ToolsRMPlugin.getDefault().getBundle().getSymbolicName(), NLS.bind(Messages.AbstractToolRuntimeSystemJob_Exception_DefaultAttributeValue, attributeDefinition.getName()), e)); |
| } |
| } |
| } |
| |
| /* |
| * Then, add attributes that are specific for the tool. |
| */ |
| IAttribute<?,?,?> extraAttributes[] = doRetrieveToolBaseSubstitutionAttributes(); |
| if (extraAttributes != null) { |
| newAttributeManager.addAttributes(extraAttributes); |
| } |
| |
| return newAttributeManager; |
| } |
| |
| /** |
| * Retrieve additional attributes to expand macros that are specific for the tool. |
| */ |
| abstract protected IAttribute<?, ?, ?>[] doRetrieveToolBaseSubstitutionAttributes() throws CoreException; |
| |
| /** |
| * A list of all attributes definitions from the launch configuration that can be used to expand macros. |
| * @return |
| */ |
| protected IAttributeDefinition<?, ?, ?>[] getDefaultSubstitutionAttributes() { |
| return new IAttributeDefinition[]{ |
| JobAttributes.getEnvironmentAttributeDefinition(), |
| JobAttributes.getExecutableNameAttributeDefinition(), |
| JobAttributes.getExecutablePathAttributeDefinition(), |
| JobAttributes.getJobIdAttributeDefinition(), |
| JobAttributes.getNumberOfProcessesAttributeDefinition(), |
| JobAttributes.getProgramArgumentsAttributeDefinition(), |
| JobAttributes.getQueueIdAttributeDefinition(), |
| JobAttributes.getSubIdAttributeDefinition(), |
| JobAttributes.getUserIdAttributeDefinition(), |
| JobAttributes.getWorkingDirectoryAttributeDefinition() |
| }; |
| } |
| |
| final protected AttributeManager retrieveCommandSubstitutionAttributes( |
| AttributeManager baseSubstitutionAttributeManager, |
| String directory, Map<String, String> environment) { |
| AttributeManager newAttributeManager = new AttributeManager(baseSubstitutionAttributeManager.getAttributes()); |
| |
| /* |
| * Add attributes that are specific for the tool. |
| */ |
| IAttribute<?,?,?> extraAttributes[] = doRetrieveToolCommandSubstitutionAttributes(baseSubstitutionAttributeManager, directory, environment); |
| if (extraAttributes != null) { |
| newAttributeManager.addAttributes(extraAttributes); |
| } |
| |
| return newAttributeManager; |
| } |
| |
| |
| abstract protected IAttribute<?, ?, ?>[] doRetrieveToolCommandSubstitutionAttributes( |
| AttributeManager baseSubstitutionAttributeManager, |
| String directory, Map<String, String> environment); |
| |
| protected List<String> retrieveCreateLaunchCommand(AttributeManager substitutionAttributeManager) throws CoreException { |
| /* |
| * Create launch command. If there is no launch command, simply launch the executable. |
| */ |
| AbstractEffectiveToolRMConfiguration effectiveConfiguration = getRtSystem().retrieveEffectiveToolRmConfiguration(); |
| List<String> command = new ArrayList<String>(); |
| if (! effectiveConfiguration.hasLaunchCmd()) { |
| // Fall back to calling the executable. |
| StringAttribute execPath = getAttrMgr().getAttribute(JobAttributes.getExecutablePathAttributeDefinition()); |
| ArrayAttribute<String> arguments = getAttrMgr().getAttribute(JobAttributes.getProgramArgumentsAttributeDefinition()); |
| command.add(execPath.getValue()); |
| command.addAll(arguments.getValue()); |
| } else { |
| // Use the tool to launch executable |
| String launchCommand = effectiveConfiguration.getLaunchCmd(); |
| Assert.isNotNull(launchCommand); |
| Assert.isTrue(launchCommand.trim().length() > 0); |
| launchCommand = replaceVariables(launchCommand, substitutionAttributeManager); |
| ArgumentParser argumentParser = new ArgumentParser(launchCommand); |
| command = argumentParser.getTokenList(); |
| } |
| return command; |
| } |
| |
| protected List<String> retrieveCreateDebugCommand(AttributeManager substitutionAttributeManager) throws CoreException { |
| /* |
| * Create debug command. If there is no debug command, simply launch the executable. |
| */ |
| AbstractEffectiveToolRMConfiguration effectiveConfiguration = getRtSystem().retrieveEffectiveToolRmConfiguration(); |
| List<String> command = new ArrayList<String>(); |
| if (! effectiveConfiguration.hasDebugCmd()) { |
| // Fall back to calling the executable. |
| StringAttribute execPath = getAttrMgr().getAttribute(JobAttributes.getExecutablePathAttributeDefinition()); |
| ArrayAttribute<String> arguments = getAttrMgr().getAttribute(JobAttributes.getProgramArgumentsAttributeDefinition()); |
| command.add(execPath.getValue()); |
| command.addAll(arguments.getValue()); |
| } else { |
| // Use the tool to launch executable |
| String debugCommand = effectiveConfiguration.getDebugCmd(); |
| Assert.isNotNull(debugCommand); |
| Assert.isTrue(debugCommand.trim().length() > 0); |
| debugCommand = replaceVariables(debugCommand, substitutionAttributeManager); |
| ArgumentParser argumentParser = new ArgumentParser(debugCommand); |
| command = argumentParser.getTokenList(); |
| } |
| return command; |
| } |
| |
| /* |
| * Pattern to fined variables according these rules: |
| * Starts with "${" and ends with "}" |
| * The content is a name and a set of parameters separated by ":" |
| * In the parameters, "\" may be used to quote following chars: '\', '}' and ':' |
| * |
| * TODO move this patter substitution code into the attribute manager |
| * TODO enable the attribute manager to do substitution -> have this feature available on entire PTP. |
| */ |
| static final Pattern variablePattern = Pattern.compile(("/$/{(/w+)("+"(?:(?:////)|(?:///})|[^/}])*"+")/}").replace('/','\\')); //$NON-NLS-1$ //$NON-NLS-2$ //$NON-NLS-3$ |
| static final Pattern parameterPattern = Pattern.compile(":((?:(?:////)|(?:///:)|(?:///})|[^:])*)".replace('/', '\\')); //$NON-NLS-1$ |
| |
| /** |
| * Performs substitution of variables using attributes from the attribute manager as variables. |
| * @param input the string with variables. |
| * @param substitutionAttributeManager |
| * @return The string after substitution of variables. |
| */ |
| protected String replaceVariables(String input, AttributeManager substitutionAttributeManager) { |
| StringBuffer output = new StringBuffer(); |
| Matcher matcher = variablePattern.matcher(input); |
| |
| int lastPos = 0; |
| while (matcher.find()) { |
| int startPos = matcher.start(); |
| int endPos = matcher.end(); |
| String name = matcher.group(1); |
| String parameterList = matcher.group(2); |
| String variable = matcher.group(); |
| output.append(input.substring(lastPos, startPos)); |
| |
| /* |
| * Resolve variable. |
| */ |
| String resolvedValue = null; |
| IAttribute<?,?,?> attribute = substitutionAttributeManager.getAttribute(name); |
| if (attribute != null) { |
| if (attribute instanceof ArrayAttribute<?>) { |
| /* |
| * Retrieve parameters or use defaults. |
| */ |
| String optStartStr = ""; //$NON-NLS-1$ |
| String optEndStr = ""; //$NON-NLS-1$ |
| String startStr = ""; //$NON-NLS-1$ |
| String endStr = ""; //$NON-NLS-1$ |
| String separatorStr = " "; //$NON-NLS-1$ |
| Matcher paramMatcher = parameterPattern.matcher(parameterList); |
| if (paramMatcher.find()) { |
| startStr = paramMatcher.group(1); |
| if (paramMatcher.find()) { |
| separatorStr = paramMatcher.group(1); |
| if (paramMatcher.find()) { |
| endStr = paramMatcher.group(1); |
| if (paramMatcher.find()) { |
| optStartStr = paramMatcher.group(1); |
| if (paramMatcher.find()) { |
| optEndStr = paramMatcher.group(1); |
| } |
| } |
| } |
| } |
| } |
| |
| /* |
| * Build content. |
| */ |
| ArrayAttribute<?> array_attr = (ArrayAttribute<?>) attribute; |
| StringBuffer buffer = new StringBuffer(); |
| boolean first = true; |
| List<?> array = array_attr.getValue(); |
| if (array.size() > 0) { |
| buffer.append(optStartStr); |
| } |
| buffer.append(startStr); |
| for (Object element : array) { |
| if (first) { |
| first = false; |
| } else { |
| buffer.append(separatorStr); |
| } |
| assert element != null; |
| buffer.append(element); |
| } |
| buffer.append(endStr); |
| if (array.size() > 0) { |
| buffer.append(optEndStr); |
| } |
| resolvedValue = buffer.toString(); |
| } else { |
| resolvedValue = attribute.getValueAsString(); |
| } |
| } |
| |
| /* |
| * If failed to resolve variable, keep it on the string. Else replace by its value. |
| */ |
| if (resolvedValue == null) { |
| output.append(variable); |
| } else { |
| // Recursive macro substitution |
| resolvedValue = replaceVariables(resolvedValue, substitutionAttributeManager); |
| output.append(resolvedValue); |
| } |
| lastPos = endPos; |
| } |
| output.append(input.substring(lastPos)); |
| String result = output.toString(); |
| return result; |
| } |
| |
| public void terminate() { |
| terminateJobFlag = true; |
| if (process != null) { |
| process.destroy(); |
| } |
| doTerminateJob(); |
| } |
| |
| @Override |
| protected void canceling() { |
| terminate(); |
| super.canceling(); |
| } |
| } |