package com.mozilla.grouperfish.batch.transforms; import java.io.File; import java.io.IOException; import java.io.InputStream; import org.slf4j.Logger; import org.slf4j.LoggerFactory; import com.mozilla.grouperfish.base.Assert; import com.mozilla.grouperfish.model.Fail; import com.mozilla.grouperfish.model.Task; import com.mozilla.grouperfish.services.api.FileSystem; import com.mozilla.grouperfish.services.api.FileSystem.FsError; /** * Transform based on launching a subprocess, with an executable * locally available on the grouperfish node. * Right now, this is the only transform we have. */ abstract class ExecutableTransform implements Transform { private static final Logger log = LoggerFactory.getLogger(ExecutableTransform.class); public static final String TRANSFORMS_DIRECTORY = "./transforms"; private final String name; private final FileSystem dataFs; private final File exe; private final File transformDir; public String name() { return name; } public FileSystem dataFs() { return dataFs; } public String toString() { return String.format( "{%s name=%s, transformDir=%s}", getClass().getSimpleName(), name, transformDir); } protected File executable() { return exe; } /** * Return the URL of the working directory to use, and make sure * that it actually exists and contains the required input data. */ protected abstract String taskDirectoryUri(final Task task) throws FsError; public ExecutableTransform(final String name, final FileSystem dataFs) { Assert.nonNull(name, dataFs); Assert.check(!name.isEmpty()); this.name = name; this.dataFs = dataFs; final String transformPath = String.format("%s/%s", TRANSFORMS_DIRECTORY, name); final String exePath = String.format("%s/%s", transformPath, name); transformDir = new File(transformPath); if (!transformDir.exists() || !transformDir.isDirectory()) Assert.unreachable( "Cannot find transform directory '%s'. (system working directory: '%s')", transformPath, System.getProperty("user.dir")); exe = new File(exePath); if (!exe.exists()) Assert.unreachable( "Cannot find executable '%s'. (system working directory: '%s')", exePath, System.getProperty("user.dir")); if (!exe.isFile() || !exe.canExecute()) Assert.unreachable("Cannot execute '%s'.", exe.getAbsolutePath()); } @Override public TransformResult run(final Task task) throws Fail, InterruptedException { Assert.nonNull(task); final String taskDirectoryUri; try { taskDirectoryUri = taskDirectoryUri(task); } catch (final FsError e) { throw Fail.hard(task, "Could not access task work directory!", e); } try { final ProcessBuilder pb = new ProcessBuilder(exe.getCanonicalPath(), taskDirectoryUri); pb.redirectErrorStream(true); pb.directory(transformDir); log.debug("{} Launching process: {}", task, pb.command()); final Process process = pb.start(); final boolean success = process.waitFor() == 0; return new TransformResult() { @Override public InputStream stderr() { return process.getInputStream(); } @Override public boolean success() { return success; } }; } catch (final IOException e) { throw Fail.hard(task, "IO problem during transform execution.", e); } } }