blob: 11b00234b7dc036945fe537a4ee50226dc5e26f6 [file] [log] [blame]
/*******************************************************************************
* Copyright (c) 2011 University of Illinois 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:
* Albert L. Rossi - design and implementation
******************************************************************************/
package org.eclipse.ptp.internal.rm.jaxb.control.core.runnable;
import java.io.File;
import java.io.FileWriter;
import java.io.IOException;
import java.util.List;
import java.util.UUID;
import org.eclipse.core.filesystem.EFS;
import org.eclipse.core.filesystem.IFileStore;
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.SubMonitor;
import org.eclipse.core.runtime.jobs.Job;
import org.eclipse.ptp.core.util.CoreExceptionUtils;
import org.eclipse.ptp.internal.rm.jaxb.control.core.JAXBControlConstants;
import org.eclipse.ptp.internal.rm.jaxb.control.core.JAXBControlCorePlugin;
import org.eclipse.ptp.internal.rm.jaxb.control.core.LaunchController;
import org.eclipse.ptp.internal.rm.jaxb.control.core.RemoteServicesDelegate;
import org.eclipse.ptp.internal.rm.jaxb.control.core.data.LineImpl;
import org.eclipse.ptp.internal.rm.jaxb.control.core.messages.Messages;
import org.eclipse.ptp.rm.jaxb.control.core.ILaunchController;
import org.eclipse.ptp.rm.jaxb.core.IVariableMap;
import org.eclipse.ptp.rm.jaxb.core.data.AttributeType;
import org.eclipse.ptp.rm.jaxb.core.data.LineType;
import org.eclipse.ptp.rm.jaxb.core.data.ManagedFileType;
import org.eclipse.ptp.rm.jaxb.core.data.ManagedFilesType;
import org.eclipse.remote.core.IRemoteConnection;
/**
* A managed file is a client-side file which needs to be moved to the resource to which the job will be submitted. This class wraps
* the Job runnable for staging these files. <br>
* <br>
* There are two possible operations, copy and delete. In the former case, all files in the list are copied serially to the target
* resource; in the latter, only those files with delete of the target marked as true are deleted.
*
* @author arossi
*
*/
public class ManagedFilesJob extends Job {
public enum Operation {
COPY, DELETE
};
private final String uuid;
private final ILaunchController control;
private final List<ManagedFileType> files;
private RemoteServicesDelegate delegate;
private IVariableMap rmVarMap;
private String stagingDir;
private boolean success;
private Operation operation;
/**
*
* @param uuid
* internal job identifier (the job has not yet been submitted)
* @param files
* JAXB data element
* @param control
* callback to resource manager control
* @throws CoreException
*/
public ManagedFilesJob(String uuid, ManagedFilesType files, ILaunchController control) throws CoreException {
super(Messages.ManagedFilesJob);
this.uuid = uuid;
this.control = control;
stagingDir = files.getFileStagingLocation();
this.files = files.getFile();
}
/**
* @return whether the staging succeeded
*/
public boolean getSuccess() {
return success;
}
/**
* Either copy or delete
*
* @param operation
*/
public void setOperation(Operation operation) {
this.operation = operation;
}
/**
* First checks to see if the file references in-memory content, and if so, writes out a temporary source file. It then copies
* the file and places a property in the environment mapping the name of the ManagedFile object against its target path.
*/
@Override
protected IStatus run(IProgressMonitor monitor) {
SubMonitor progress = SubMonitor.convert(monitor, 10);
try {
try {
delegate = RemoteServicesDelegate.getDelegate(control.getRemoteServicesId(), control.getConnectionName(),
progress.newChild(1));
IRemoteConnection conn = delegate.getRemoteConnection();
LaunchController.checkConnection(conn, progress.newChild(2));
} catch (Exception e) {
return CoreExceptionUtils.getErrorStatus(Messages.ManagedFilesJobError, e);
}
rmVarMap = control.getEnvironment();
success = false;
try {
if (operation == Operation.COPY) {
doCopy(progress.newChild(7));
} else if (operation == Operation.DELETE) {
doDelete(progress.newChild(7));
}
success = true;
return Status.OK_STATUS;
} catch (Exception e) {
return CoreExceptionUtils.getErrorStatus(Messages.ManagedFilesJobError, e);
}
} finally {
if (monitor != null) {
monitor.done();
}
}
}
/**
* Copy local data from the local host to the remote host.
*
* @param localPath
* source file
* @param remotePath
* target file
* @param monitor
* @throws CoreException
*/
private void copyFileToRemoteHost(String localPath, String remotePath, IProgressMonitor monitor) throws CoreException {
/*
* EFS.NONE means mkdir -p on the parent directory (EFS.SHALLOW is mkdir parent, UNDEFINED is no mkdir).
*/
RemoteServicesDelegate.copy(delegate.getLocalFileService(), localPath, delegate.getRemoteFileService(), remotePath,
EFS.NONE, monitor);
}
/**
* Executes copy operation.
*
* @param monitor
*/
private void doCopy(IProgressMonitor monitor) throws Exception {
stagingDir = rmVarMap.getString(uuid, stagingDir);
boolean localTarget = delegate.getLocalFileService() == delegate.getRemoteFileService();
SubMonitor progress = SubMonitor.convert(monitor, files.size() * 10);
/*
* for now we handle the files serially. NOTE: no support for Windows as target ...
*/
for (ManagedFileType file : files) {
File localFile = maybeWriteFile(file);
progress.worked(5);
String fileName = localFile.getName();
if (fileName == null || fileName.length() == 0) {
continue;
}
String pathSep = localTarget ? JAXBControlConstants.PATH_SEP : JAXBControlConstants.REMOTE_PATH_SEP;
String target = stagingDir + pathSep + fileName;
SubMonitor m = progress.newChild(5);
copyFileToRemoteHost(localFile.getAbsolutePath(), target, m);
if (file.isDeleteSourceAfterUse()) {
localFile.delete();
}
if (m.isCanceled()) {
break;
}
AttributeType a = new AttributeType();
a.setName(file.getName());
if (localTarget && !new File(target).isAbsolute()) {
a.setValue(new File(System.getProperty(JAXBControlConstants.JAVA_USER_HOME), target).getAbsolutePath());
} else {
a.setValue(target);
}
a.setVisible(false);
rmVarMap.put(a.getName(), a);
progress.worked(5);
}
}
/**
* Deletes files where delete target is indicated.
*
* @param monitor
*/
private void doDelete(IProgressMonitor monitor) {
SubMonitor progress = SubMonitor.convert(monitor, files.size() * 15);
/*
* for now we handle the files serially. NOTE: no support for Windows as target ...
*/
for (ManagedFileType file : files) {
if (!file.isDeleteTargetAfterUse()) {
progress.worked(15);
continue;
}
AttributeType a = rmVarMap.get(file.getName());
IFileStore store = delegate.getRemoteFileService().getResource(String.valueOf(a.getValue()));
try {
if (store.fetchInfo(EFS.NONE, progress.newChild(5)).exists()) {
store.delete(EFS.NONE, progress.newChild(10));
}
} catch (CoreException t) {
JAXBControlCorePlugin.log(t);
}
}
}
/**
* If there is already a path defined for this file, this is returned. Else a temporary source file is created to be deleted on
* completion. If the file contents is a reference to a string in the environment, the normal VariableResolver can be bypassed
* by setting <code>resolveContents</code> to false; this avoids recursive resolution which might falsely interpret shell
* symbols (${...}) as referring to the Eclipse default string resolver. Otherwise, the &lt;line&gt; arguments are processed as
* in the script.
*
* @param file
* JAXB data element
* @return the written or the pre-existent file
* @throws IOException
* @throws CoreException
*/
private File maybeWriteFile(ManagedFileType file) throws IOException, CoreException {
String path = file.getPath();
if (path != null) {
/*
* We need to dereference here; added 06/11/2011
*/
path = rmVarMap.getString(uuid, path);
return new File(path);
}
String name = rmVarMap.getString(uuid, file.getName());
if (file.isUniqueIdPrefix()) {
name = UUID.randomUUID() + name;
}
File sourceDir = new File(System.getProperty(JAXBControlConstants.JAVA_TMP_DIR));
File localFile = new File(sourceDir, name);
String contents = file.getContents();
List<LineType> lines = file.getLine();
FileWriter fw = null;
try {
if (!lines.isEmpty()) {
StringBuffer buffer = new StringBuffer();
String s = null;
for (LineType line : lines) {
s = new LineImpl(uuid, line, rmVarMap).getResolved();
if (!JAXBControlConstants.ZEROSTR.equals(s)) {
buffer.append(s).append(JAXBControlConstants.REMOTE_LINE_SEP);
}
}
contents = buffer.toString();
} else if (file.isResolveContents()) {
contents = rmVarMap.getString(uuid, contents);
} else {
/*
* magic to avoid attempted resolution of unknown shell variables
*/
int start = contents.indexOf(JAXBControlConstants.OPENVRM);
int end = contents.length();
if (start >= 0) {
start += JAXBControlConstants.OPENVRM.length();
end = contents.indexOf(JAXBControlConstants.PD);
if (end < 0) {
end = contents.indexOf(JAXBControlConstants.CLOSV);
}
String key = contents.substring(start, end);
contents = String.valueOf(rmVarMap.get(key).getValue());
}
}
fw = new FileWriter(localFile, false);
fw.write(contents);
fw.flush();
} finally {
try {
if (fw != null) {
fw.close();
}
} catch (IOException t) {
JAXBControlCorePlugin.log(t);
}
}
return localFile;
}
}