All Downloads are FREE. Search and download functionalities are using the official Maven repository.

net.sf.okapi.steps.externalcommand.ExternalCommandStep Maven / Gradle / Ivy

There is a newer version: 1.46.0
Show newest version
/*===========================================================================
  Copyright (C) 2010 by the Okapi Framework contributors
-----------------------------------------------------------------------------
  Licensed under the Apache License, Version 2.0 (the "License");
  you may not use this file except in compliance with the License.
  You may obtain a copy of the License at

  http://www.apache.org/licenses/LICENSE-2.0

  Unless required by applicable law or agreed to in writing, software
  distributed under the License is distributed on an "AS IS" BASIS,
  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
  See the License for the specific language governing permissions and
  limitations under the License.
===========================================================================*/

package net.sf.okapi.steps.externalcommand;

import java.io.ByteArrayOutputStream;
import java.io.File;
import java.io.IOException;
import java.net.URI;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Locale;
import java.util.Map;

import net.sf.okapi.common.Event;
import net.sf.okapi.common.IParameters;
import net.sf.okapi.common.UsingParameters;
import net.sf.okapi.common.exceptions.OkapiException;
import net.sf.okapi.common.exceptions.OkapiIOException;
import net.sf.okapi.common.pipeline.BasePipelineStep;
import net.sf.okapi.common.pipeline.annotations.StepParameterMapping;
import net.sf.okapi.common.pipeline.annotations.StepParameterType;
import net.sf.okapi.common.resource.RawDocument;

import org.apache.commons.exec.CommandLine;
import org.apache.commons.exec.DefaultExecutor;
import org.apache.commons.exec.ExecuteException;
import org.apache.commons.exec.ExecuteWatchdog;
import org.apache.commons.exec.Executor;
import org.apache.commons.exec.PumpStreamHandler;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

/**
 * Run a Command line tool on {@link RawDocument} {@link Event}s. The step returns a RawDocument Event generated by the
 * external command. ${inputPath} and ${outputPath} variables must be defined in the command
 * line string. For example:
 * 
"sort ${inputPath} /O ${outputPath}"
* is a valid windows command which sorts lines on a file. * * @author HARGRAVEJE */ @UsingParameters(Parameters.class) public class ExternalCommandStep extends BasePipelineStep { private final Logger LOGGER = LoggerFactory.getLogger(getClass()); private static final String INPUT_FILE_VAR = "inputPath"; private static final String OUTPUT_FILE_VAR = "outputPath"; private boolean done = false; private Parameters parameters; private Executor executor; private ExecuteWatchdog watchdog; private URI outputURI; public ExternalCommandStep () { parameters = new Parameters(); } @StepParameterMapping(parameterType = StepParameterType.OUTPUT_URI) public void setOutputURI(URI outputURI) { this.outputURI = outputURI; } @Override public Parameters getParameters() { return parameters; } @Override public void setParameters(IParameters params) { this.parameters = (Parameters) params; } @Override public boolean isDone() { return done; } @Override public String getDescription() { return "Execute an external command line."; } @Override public String getName() { return "External Command"; } @Override protected Event handleStartBatch(Event event) { done = false; executor = new DefaultExecutor(); // set process timeout if value is greater than zero if (parameters.getTimeout() > 0) { // convert from seconds to milliseconds watchdog = new ExecuteWatchdog(parameters.getTimeout() * 1000L); executor.setWatchdog(watchdog); } return event; } @Override protected Event handleRawDocument(Event event) { int exitValue; Map subtitutions = new HashMap<>(); RawDocument rawDoc = event.getRawDocument(); // Set input path variable String inputPath = (new File(rawDoc.getInputURI()).getPath()); subtitutions.put(INPUT_FILE_VAR, inputPath); // Set output path variable String outputPath = inputPath + ".out"; // Default if ( isLastOutputStep() && outputURI != null && !outputURI.getPath().isEmpty() ) { outputPath = (new File(outputURI).getPath()); } subtitutions.put(OUTPUT_FILE_VAR, outputPath); // Set source-related variables subtitutions.put("srcLangName", rawDoc.getSourceLocale().toJavaLocale().getDisplayLanguage(Locale.ENGLISH)); subtitutions.put("srcLang", rawDoc.getSourceLocale().getLanguage()); subtitutions.put("srcBCP47", rawDoc.getSourceLocale().toBCP47()); // Set target-related variables subtitutions.put("trgLangName", rawDoc.getTargetLocale().toJavaLocale().getDisplayLanguage(Locale.ENGLISH)); subtitutions.put("trgLang", rawDoc.getTargetLocale().getLanguage()); subtitutions.put("trgBCP47", rawDoc.getTargetLocale().toBCP47()); ByteArrayOutputStream out = new ByteArrayOutputStream(); ByteArrayOutputStream err = new ByteArrayOutputStream(); PumpStreamHandler psh = new PumpStreamHandler(out, err); String[] parts = splitCommand(parameters.getCommand()); CommandLine cl = new CommandLine(parts[0]); cl.setSubstitutionMap(subtitutions); for (int i = 1; i < parts.length; i++) { cl.addArgument(parts[i], false); } try { psh.start(); LOGGER.info("External Command: {}", cl.toString()); exitValue = executor.execute(cl); } catch (ExecuteException e) { throw new OkapiException(e); } catch (IOException e) { throw new OkapiIOException(e); } if (watchdog != null && watchdog.killedProcess()) { throw new OkapiException("Command line process timed out: " + out.toString()); } if (executor.isFailure(exitValue)) { throw new OkapiException("Command line process failed: " + err.toString()); } try { psh.stop(); out.close(); } catch (IOException e) { throw new OkapiIOException("Error closing process output streamm.", e); } try { err.close(); } catch (IOException e) { throw new OkapiIOException("Error closing process error streamm", e); } // Create new event resource pointing to the output RawDocument outRawDoc = null; outRawDoc = new RawDocument((new File(outputPath)).toURI(), rawDoc.getEncoding(), rawDoc.getSourceLocale(), rawDoc.getTargetLocale()); event.setResource(outRawDoc); done = true; return event; } @Override protected Event handleEndBatch(Event event) { return event; } public static String[] splitCommand(String cmd) { cmd = cmd.trim(); if (cmd.length() == 0) return new String[] { "" }; StringBuilder arg = new StringBuilder(); List result = new ArrayList<>(); final char noQuote = '\0'; char currentQuote = noQuote; for (int i = 0; i < cmd.length(); i++) { char c = cmd.charAt(i); if (c == currentQuote) { currentQuote = noQuote; } else if (c == '"' && currentQuote == noQuote) { currentQuote = '"'; } else if (c == '\'' && currentQuote == noQuote) { currentQuote = '\''; } else if (c == '\\' && i + 1 < cmd.length()) { char next = cmd.charAt(i + 1); if ((currentQuote == noQuote && Character.isWhitespace(next)) || (currentQuote == '"' && next == '"')) { arg.append(next); i++; } else { arg.append(c); } } else { if (Character.isWhitespace(c) && currentQuote == noQuote) { if (arg.length() > 0) { result.add(arg.toString()); arg = new StringBuilder(); } else { // Discard } } else { arg.append(c); } } } // Catch last arg if (arg.length() > 0) { result.add(arg.toString()); } return result.toArray(new String[0]); } }




© 2015 - 2024 Weber Informatics LLC | Privacy Policy