org.jodconverter.process.AbstractProcessManager Maven / Gradle / Ivy
Go to download
Show more of this group Show more artifacts with this name
Show all versions of jodconverter-local Show documentation
Show all versions of jodconverter-local Show documentation
Module required in order to process local conversions for the Java OpenDocument Converter (JODConverter) project.
/*
* Copyright 2004 - 2012 Mirko Nasato and contributors
* 2016 - 2018 Simon Braconnier and contributors
*
* This file is part of JODConverter - Java OpenDocument Converter.
*
* 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 org.jodconverter.process;
import java.io.BufferedReader;
import java.io.IOException;
import java.io.InputStream;
import java.io.InputStreamReader;
import java.util.ArrayList;
import java.util.List;
import java.util.regex.Matcher;
import java.util.regex.Pattern;
import java.util.stream.Collectors;
import org.apache.commons.lang3.StringUtils;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
/**
* Base class for all process manager implementations included in the standard JODConverter
* distribution.
*/
public abstract class AbstractProcessManager implements ProcessManager {
private static final Logger LOGGER = LoggerFactory.getLogger(AbstractProcessManager.class);
private static class StreamPumper extends Thread {
private final InputStream inputStream;
private final List outputLines;
/**
* Creates a new pumper for the specified input stream.
*
* @param inputStream The input stream to read from.
*/
public StreamPumper(final InputStream inputStream) {
super();
this.inputStream = inputStream;
this.outputLines = new ArrayList<>();
}
/**
* Gets the output lines from this input stream pumper.
*
* @return The command output lines.
*/
public List getOutputLines() {
return outputLines;
}
@Override
public void run() {
try (InputStreamReader inputStreamReader = new InputStreamReader(inputStream);
BufferedReader bufferedReader = new BufferedReader(inputStreamReader)) {
String line;
while ((line = bufferedReader.readLine()) != null) {
outputLines.add(line);
}
} catch (IOException ex) {
LOGGER.error("Unable to read from command input stream.", ex);
}
}
}
/** Initializes a new instance of the class. */
protected AbstractProcessManager() {
super();
}
private String buildOutput(final List lines) {
if (lines == null) {
return "";
}
// Ignore empty lines
return lines.stream().filter(StringUtils::isNotBlank).collect(Collectors.joining("\n"));
}
/**
* Executes the specified command and return the output.
*
* @param cmdarray An array containing the command to call and its arguments.
* @return The command execution output.
* @throws IOException If an I/O error occurs.
*/
protected List execute(final String[] cmdarray) throws IOException {
final Process process = Runtime.getRuntime().exec(cmdarray);
final StreamPumper outPumper = new StreamPumper(process.getInputStream());
final StreamPumper errPumper = new StreamPumper(process.getErrorStream());
outPumper.start();
errPumper.start();
try {
process.waitFor();
outPumper.join();
errPumper.join();
} catch (InterruptedException ex) {
// Log the interruption
LOGGER.warn(
"The current thread was interrupted while waiting for command execution output.", ex);
// Restore the interrupted status
Thread.currentThread().interrupt();
}
final List outLines = outPumper.getOutputLines();
if (LOGGER.isDebugEnabled()) {
final String out = buildOutput(outLines);
final String err = buildOutput(errPumper.getOutputLines());
if (!StringUtils.isBlank(out)) {
LOGGER.trace("Command Output: {}", out);
}
if (!StringUtils.isBlank(err)) {
LOGGER.trace("Command Error: {}", err);
}
}
return outLines;
}
@Override
public long findPid(final ProcessQuery query) throws IOException {
final Pattern commandPattern =
Pattern.compile(
Pattern.quote(query.getCommand()) + ".*" + Pattern.quote(query.getArgument()));
final Pattern processLinePattern = getRunningProcessLinePattern();
final String[] currentProcessesCommand = getRunningProcessesCommand(query.getCommand());
LOGGER.trace(
"Finding PID using\n"
+ "Command to get current running processes: {}\n"
+ "Regex used to match current running process lines: {}\n"
+ "Regex used to match running office process we are looking for: {}",
currentProcessesCommand,
processLinePattern.pattern(), // NOSONAR
commandPattern.pattern());
final List lines = execute(currentProcessesCommand);
for (final String line : lines) {
if (StringUtils.isBlank(line)) {
// Skip this one
continue;
}
LOGGER.trace(
"Checking if process line matches the process line regex\nProcess line: {}", line);
final Matcher lineMatcher = processLinePattern.matcher(line);
if (lineMatcher.matches()) {
final String pid = lineMatcher.group("Pid");
final String commandLine = lineMatcher.group("CommanLine");
LOGGER.trace(
"Line matches!\n"
+ "pid: {}; Command line: {}\n"
+ "Checking if this command line matches the office command line regex",
pid,
commandLine);
final Matcher commandMatcher = commandPattern.matcher(commandLine);
if (commandMatcher.find()) {
LOGGER.debug("Command line matches! Returning pid: {}", pid);
return Long.parseLong(pid);
}
}
}
return PID_NOT_FOUND;
}
/**
* Gets the command to be executed to get a snapshot of all the running processes identified by
* the specified argument (process).
*
* @param process The name of the process to query for.
* @return An array containing the command to call and its arguments.
*/
protected abstract String[] getRunningProcessesCommand(String process);
/**
* Gets the pattern to be used to match an output line containing the information about a running
* process. The output lines being tested against this pattern are the result of the execution of
* the command returned by the getRunningProcessesCommand function.
*
* @return The pattern.
* @see #getRunningProcessesCommand(String)
*/
protected abstract Pattern getRunningProcessLinePattern();
}