org.jodconverter.local.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 - 2020 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.local.process;
import java.io.IOException;
import java.util.List;
import java.util.Objects;
import java.util.regex.Matcher;
import java.util.regex.Pattern;
import java.util.stream.Collectors;
import org.checkerframework.checker.nullness.qual.NonNull;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.jodconverter.core.util.StringUtils;
/**
* 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);
/** Initializes a new instance of the class. */
protected AbstractProcessManager() {
super();
}
private String buildOutput(final List lines) {
Objects.requireNonNull(lines, "lines must not be null");
// 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 @NonNull List<@NonNull String> execute(final @NonNull String[] cmdarray)
throws IOException {
final Process process = Runtime.getRuntime().exec(cmdarray);
final LinesPumpStreamHandler streamsHandler =
new LinesPumpStreamHandler(process.getInputStream(), process.getErrorStream());
streamsHandler.start();
try {
process.waitFor();
streamsHandler.stop();
} 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 = streamsHandler.getOutputPumper().getLines();
if (LOGGER.isTraceEnabled()) {
final String out = buildOutput(outLines);
final String err = buildOutput(streamsHandler.getErrorPumper().getLines());
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 @NonNull ProcessQuery query) throws IOException {
if (!canFindPid()) {
return PID_UNKNOWN;
}
final Pattern commandPattern =
Pattern.compile(
Pattern.quote(query.getCommand()) + ".*" + Pattern.quote(query.getArgument()));
final Pattern processLinePattern = getRunningProcessLinePattern();
final String[] currentProcessesCommand = getRunningProcessesCommand(query.getCommand());
if (LOGGER.isTraceEnabled()) {
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(),
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("CommandLine");
if (LOGGER.isTraceEnabled()) {
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);
}
}
}
LOGGER.debug("No matching command line found! Returning pid: NOT_FOUND");
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 @NonNull 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 @NonNull Pattern getRunningProcessLinePattern();
}