mirror of
https://github.com/kekingcn/kkFileView.git
synced 2026-04-20 04:28:38 +00:00
调整项目模块,jodconverter-core重命名为office-plugin。jdocnverter-web重命名为server
This commit is contained in:
@@ -0,0 +1,223 @@
|
||||
//
|
||||
// JODConverter - Java OpenDocument Converter
|
||||
// Copyright 2004-2012 Mirko Nasato and contributors
|
||||
//
|
||||
// JODConverter is Open Source software, you can redistribute it and/or
|
||||
// modify it under either (at your option) of the following licenses
|
||||
//
|
||||
// 1. The GNU Lesser General Public License v3 (or later)
|
||||
// -> http://www.gnu.org/licenses/lgpl-3.0.txt
|
||||
// 2. The Apache License, Version 2.0
|
||||
// -> http://www.apache.org/licenses/LICENSE-2.0.txt
|
||||
//
|
||||
package org.artofsolving.jodconverter.office;
|
||||
|
||||
import java.io.File;
|
||||
|
||||
import org.artofsolving.jodconverter.process.ProcessManager;
|
||||
import org.artofsolving.jodconverter.process.PureJavaProcessManager;
|
||||
import org.artofsolving.jodconverter.process.LinuxProcessManager;
|
||||
import org.artofsolving.jodconverter.process.SigarProcessManager;
|
||||
import org.artofsolving.jodconverter.util.PlatformUtils;
|
||||
|
||||
public class DefaultOfficeManagerConfiguration {
|
||||
|
||||
public static final long DEFAULT_RETRY_TIMEOUT = 120000L;
|
||||
|
||||
private File officeHome = OfficeUtils.getDefaultOfficeHome();
|
||||
private OfficeConnectionProtocol connectionProtocol = OfficeConnectionProtocol.SOCKET;
|
||||
private int[] portNumbers = new int[] { 2002 };
|
||||
private String[] pipeNames = new String[] { "office" };
|
||||
private String[] runAsArgs = null;
|
||||
private File templateProfileDir = null;
|
||||
private File workDir = new File(System.getProperty("java.io.tmpdir"));
|
||||
private long taskQueueTimeout = 30000L; // 30 seconds
|
||||
private long taskExecutionTimeout = 120000L; // 2 minutes
|
||||
private int maxTasksPerProcess = 200;
|
||||
private long retryTimeout = DEFAULT_RETRY_TIMEOUT;
|
||||
|
||||
private ProcessManager processManager = null; // lazily initialised
|
||||
|
||||
public DefaultOfficeManagerConfiguration setOfficeHome(String officeHome) throws NullPointerException, IllegalArgumentException {
|
||||
checkArgumentNotNull("officeHome", officeHome);
|
||||
return setOfficeHome(new File(officeHome));
|
||||
}
|
||||
|
||||
public DefaultOfficeManagerConfiguration setOfficeHome(File officeHome) throws NullPointerException, IllegalArgumentException {
|
||||
checkArgumentNotNull("officeHome", officeHome);
|
||||
checkArgument("officeHome", officeHome.isDirectory(), "must exist and be a directory");
|
||||
this.officeHome = officeHome;
|
||||
return this;
|
||||
}
|
||||
|
||||
public DefaultOfficeManagerConfiguration setConnectionProtocol(OfficeConnectionProtocol connectionProtocol) throws NullPointerException {
|
||||
checkArgumentNotNull("connectionProtocol", connectionProtocol);
|
||||
this.connectionProtocol = connectionProtocol;
|
||||
return this;
|
||||
}
|
||||
|
||||
public DefaultOfficeManagerConfiguration setPortNumber(int portNumber) {
|
||||
this.portNumbers = new int[] { portNumber };
|
||||
return this;
|
||||
}
|
||||
|
||||
public DefaultOfficeManagerConfiguration setPortNumbers(int... portNumbers) throws NullPointerException, IllegalArgumentException {
|
||||
checkArgumentNotNull("portNumbers", portNumbers);
|
||||
checkArgument("portNumbers", portNumbers.length > 0, "must not be empty");
|
||||
this.portNumbers = portNumbers;
|
||||
return this;
|
||||
}
|
||||
|
||||
public DefaultOfficeManagerConfiguration setPipeName(String pipeName) throws NullPointerException {
|
||||
checkArgumentNotNull("pipeName", pipeName);
|
||||
this.pipeNames = new String[] { pipeName };
|
||||
return this;
|
||||
}
|
||||
|
||||
public DefaultOfficeManagerConfiguration setPipeNames(String... pipeNames) throws NullPointerException, IllegalArgumentException {
|
||||
checkArgumentNotNull("pipeNames", pipeNames);
|
||||
checkArgument("pipeNames", pipeNames.length > 0, "must not be empty");
|
||||
this.pipeNames = pipeNames;
|
||||
return this;
|
||||
}
|
||||
|
||||
public DefaultOfficeManagerConfiguration setRunAsArgs(String... runAsArgs) {
|
||||
this.runAsArgs = runAsArgs;
|
||||
return this;
|
||||
}
|
||||
|
||||
public DefaultOfficeManagerConfiguration setTemplateProfileDir(File templateProfileDir) throws IllegalArgumentException {
|
||||
if (templateProfileDir != null) {
|
||||
checkArgument("templateProfileDir", templateProfileDir.isDirectory(), "must exist and be a directory");
|
||||
}
|
||||
this.templateProfileDir = templateProfileDir;
|
||||
return this;
|
||||
}
|
||||
|
||||
/**
|
||||
* Sets the directory where temporary office profiles will be created.
|
||||
* <p>
|
||||
* Defaults to the system temporary directory as specified by the <code>java.io.tmpdir</code> system property.
|
||||
*
|
||||
* @param workDir
|
||||
* @return
|
||||
*/
|
||||
public DefaultOfficeManagerConfiguration setWorkDir(File workDir) {
|
||||
checkArgumentNotNull("workDir", workDir);
|
||||
this.workDir = workDir;
|
||||
return this;
|
||||
}
|
||||
|
||||
public DefaultOfficeManagerConfiguration setTaskQueueTimeout(long taskQueueTimeout) {
|
||||
this.taskQueueTimeout = taskQueueTimeout;
|
||||
return this;
|
||||
}
|
||||
|
||||
public DefaultOfficeManagerConfiguration setTaskExecutionTimeout(long taskExecutionTimeout) {
|
||||
this.taskExecutionTimeout = taskExecutionTimeout;
|
||||
return this;
|
||||
}
|
||||
|
||||
public DefaultOfficeManagerConfiguration setMaxTasksPerProcess(int maxTasksPerProcess) {
|
||||
this.maxTasksPerProcess = maxTasksPerProcess;
|
||||
return this;
|
||||
}
|
||||
|
||||
/**
|
||||
* Provide a specific {@link ProcessManager} implementation
|
||||
* <p>
|
||||
* The default is to use {@link SigarProcessManager} if sigar.jar is
|
||||
* available in the classpath, otherwise {@link LinuxProcessManager}
|
||||
* on Linux and {@link PureJavaProcessManager} on other platforms.
|
||||
*
|
||||
* @param processManager
|
||||
* @return
|
||||
* @throws NullPointerException
|
||||
*/
|
||||
public DefaultOfficeManagerConfiguration setProcessManager(ProcessManager processManager) throws NullPointerException {
|
||||
checkArgumentNotNull("processManager", processManager);
|
||||
this.processManager = processManager;
|
||||
return this;
|
||||
}
|
||||
|
||||
/**
|
||||
* Retry timeout set in milliseconds. Used for retrying office process calls.
|
||||
* If not set, it defaults to 2 minutes
|
||||
*
|
||||
* @param retryTimeout in milliseconds
|
||||
* @return
|
||||
*/
|
||||
public DefaultOfficeManagerConfiguration setRetryTimeout(long retryTimeout) {
|
||||
this.retryTimeout = retryTimeout;
|
||||
return this;
|
||||
}
|
||||
|
||||
public OfficeManager buildOfficeManager() throws IllegalStateException {
|
||||
if (officeHome == null) {
|
||||
throw new IllegalStateException("officeHome not set and could not be auto-detected");
|
||||
} else if (!officeHome.isDirectory()) {
|
||||
throw new IllegalStateException("officeHome doesn't exist or is not a directory: " + officeHome);
|
||||
} else if (!OfficeUtils.getOfficeExecutable(officeHome).isFile()) {
|
||||
throw new IllegalStateException("invalid officeHome: it doesn't contain soffice.bin: " + officeHome);
|
||||
}
|
||||
if (templateProfileDir != null && !isValidProfileDir(templateProfileDir)) {
|
||||
throw new IllegalStateException("templateProfileDir doesn't appear to contain a user profile: " + templateProfileDir);
|
||||
}
|
||||
if (!workDir.isDirectory()) {
|
||||
throw new IllegalStateException("workDir doesn't exist or is not a directory: " + workDir);
|
||||
}
|
||||
|
||||
if (processManager == null) {
|
||||
processManager = findBestProcessManager();
|
||||
}
|
||||
|
||||
int numInstances = connectionProtocol == OfficeConnectionProtocol.PIPE ? pipeNames.length : portNumbers.length;
|
||||
UnoUrl[] unoUrls = new UnoUrl[numInstances];
|
||||
for (int i = 0; i < numInstances; i++) {
|
||||
unoUrls[i] = (connectionProtocol == OfficeConnectionProtocol.PIPE) ? UnoUrl.pipe(pipeNames[i]) : UnoUrl.socket(portNumbers[i]);
|
||||
}
|
||||
return new ProcessPoolOfficeManager(officeHome, unoUrls, runAsArgs, templateProfileDir, workDir, retryTimeout, taskQueueTimeout, taskExecutionTimeout, maxTasksPerProcess, processManager);
|
||||
}
|
||||
|
||||
private ProcessManager findBestProcessManager() {
|
||||
if (isSigarAvailable()) {
|
||||
return new SigarProcessManager();
|
||||
} else if (PlatformUtils.isLinux()) {
|
||||
LinuxProcessManager processManager = new LinuxProcessManager();
|
||||
if (runAsArgs != null) {
|
||||
processManager.setRunAsArgs(runAsArgs);
|
||||
}
|
||||
return processManager;
|
||||
} else {
|
||||
// NOTE: UnixProcessManager can't be trusted to work on Solaris
|
||||
// because of the 80-char limit on ps output there
|
||||
return new PureJavaProcessManager();
|
||||
}
|
||||
}
|
||||
|
||||
private boolean isSigarAvailable() {
|
||||
try {
|
||||
Class.forName("org.hyperic.sigar.Sigar", false, getClass().getClassLoader());
|
||||
return true;
|
||||
} catch (ClassNotFoundException classNotFoundException) {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
private void checkArgumentNotNull(String argName, Object argValue) throws NullPointerException {
|
||||
if (argValue == null) {
|
||||
throw new NullPointerException(argName + " must not be null");
|
||||
}
|
||||
}
|
||||
|
||||
private void checkArgument(String argName, boolean condition, String message) throws IllegalArgumentException {
|
||||
if (!condition) {
|
||||
throw new IllegalArgumentException(argName + " " + message);
|
||||
}
|
||||
}
|
||||
|
||||
private boolean isValidProfileDir(File profileDir) {
|
||||
return new File(profileDir, "user").isDirectory();
|
||||
}
|
||||
|
||||
}
|
||||
@@ -0,0 +1,86 @@
|
||||
//
|
||||
// JODConverter - Java OpenDocument Converter
|
||||
// Copyright 2004-2012 Mirko Nasato and contributors
|
||||
//
|
||||
// JODConverter is Open Source software, you can redistribute it and/or
|
||||
// modify it under either (at your option) of the following licenses
|
||||
//
|
||||
// 1. The GNU Lesser General Public License v3 (or later)
|
||||
// -> http://www.gnu.org/licenses/lgpl-3.0.txt
|
||||
// 2. The Apache License, Version 2.0
|
||||
// -> http://www.apache.org/licenses/LICENSE-2.0.txt
|
||||
//
|
||||
package org.artofsolving.jodconverter.office;
|
||||
|
||||
import java.net.ConnectException;
|
||||
|
||||
/**
|
||||
* {@link OfficeManager} implementation that connects to an external Office process.
|
||||
* <p>
|
||||
* The external Office process needs to be started manually, e.g. from the command line with
|
||||
*
|
||||
* <pre>
|
||||
* soffice -accept="socket,host=127.0.0.1,port=2002;urp;"
|
||||
* </pre>
|
||||
* <p>
|
||||
* Since this implementation does not manage the Office process, it does not support auto-restarting the process if it exits unexpectedly.
|
||||
* <p>
|
||||
* It will however auto-reconnect to the external process if the latter is manually restarted.
|
||||
* <p>
|
||||
* This {@link OfficeManager} implementation basically provides the same behaviour as JODConverter 2.x, including using <em>synchronized</em> blocks for serialising office
|
||||
* operations.
|
||||
*/
|
||||
class ExternalOfficeManager implements OfficeManager {
|
||||
|
||||
private final OfficeConnection connection;
|
||||
private final boolean connectOnStart;
|
||||
|
||||
/**
|
||||
* @param unoUrl
|
||||
* @param connectOnStart
|
||||
* should a connection be attempted on {@link #start()}? Default is <em>true</em>. If <em>false</em>, a connection will only be attempted the first time an
|
||||
* {@link OfficeTask} is executed.
|
||||
*/
|
||||
public ExternalOfficeManager(UnoUrl unoUrl, boolean connectOnStart) {
|
||||
connection = new OfficeConnection(unoUrl);
|
||||
this.connectOnStart = connectOnStart;
|
||||
}
|
||||
|
||||
public void start() throws OfficeException {
|
||||
if (connectOnStart) {
|
||||
synchronized (connection) {
|
||||
connect();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public void stop() {
|
||||
synchronized (connection) {
|
||||
if (connection.isConnected()) {
|
||||
connection.disconnect();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public void execute(OfficeTask task) throws OfficeException {
|
||||
synchronized (connection) {
|
||||
if (!connection.isConnected()) {
|
||||
connect();
|
||||
}
|
||||
task.execute(connection);
|
||||
}
|
||||
}
|
||||
|
||||
private void connect() {
|
||||
try {
|
||||
connection.connect();
|
||||
} catch (ConnectException connectException) {
|
||||
throw new OfficeException("could not connect to external office process", connectException);
|
||||
}
|
||||
}
|
||||
|
||||
public boolean isRunning() {
|
||||
return connection.isConnected();
|
||||
}
|
||||
|
||||
}
|
||||
@@ -0,0 +1,47 @@
|
||||
//
|
||||
// JODConverter - Java OpenDocument Converter
|
||||
// Copyright 2004-2012 Mirko Nasato and contributors
|
||||
//
|
||||
// JODConverter is Open Source software, you can redistribute it and/or
|
||||
// modify it under either (at your option) of the following licenses
|
||||
//
|
||||
// 1. The GNU Lesser General Public License v3 (or later)
|
||||
// -> http://www.gnu.org/licenses/lgpl-3.0.txt
|
||||
// 2. The Apache License, Version 2.0
|
||||
// -> http://www.apache.org/licenses/LICENSE-2.0.txt
|
||||
//
|
||||
package org.artofsolving.jodconverter.office;
|
||||
|
||||
public class ExternalOfficeManagerConfiguration {
|
||||
|
||||
private OfficeConnectionProtocol connectionProtocol = OfficeConnectionProtocol.SOCKET;
|
||||
private int portNumber = 2002;
|
||||
private String pipeName = "office";
|
||||
private boolean connectOnStart = true;
|
||||
|
||||
public ExternalOfficeManagerConfiguration setConnectionProtocol(OfficeConnectionProtocol connectionProtocol) {
|
||||
this.connectionProtocol = connectionProtocol;
|
||||
return this;
|
||||
}
|
||||
|
||||
public ExternalOfficeManagerConfiguration setPortNumber(int portNumber) {
|
||||
this.portNumber = portNumber;
|
||||
return this;
|
||||
}
|
||||
|
||||
public ExternalOfficeManagerConfiguration setPipeName(String pipeName) {
|
||||
this.pipeName = pipeName;
|
||||
return this;
|
||||
}
|
||||
|
||||
public ExternalOfficeManagerConfiguration setConnectOnStart(boolean connectOnStart) {
|
||||
this.connectOnStart = connectOnStart;
|
||||
return this;
|
||||
}
|
||||
|
||||
public OfficeManager buildOfficeManager() {
|
||||
UnoUrl unoUrl = connectionProtocol == OfficeConnectionProtocol.SOCKET ? UnoUrl.socket(portNumber) : UnoUrl.pipe(pipeName);
|
||||
return new ExternalOfficeManager(unoUrl, connectOnStart);
|
||||
}
|
||||
|
||||
}
|
||||
@@ -0,0 +1,176 @@
|
||||
//
|
||||
// JODConverter - Java OpenDocument Converter
|
||||
// Copyright 2004-2012 Mirko Nasato and contributors
|
||||
//
|
||||
// JODConverter is Open Source software, you can redistribute it and/or
|
||||
// modify it under either (at your option) of the following licenses
|
||||
//
|
||||
// 1. The GNU Lesser General Public License v3 (or later)
|
||||
// -> http://www.gnu.org/licenses/lgpl-3.0.txt
|
||||
// 2. The Apache License, Version 2.0
|
||||
// -> http://www.apache.org/licenses/LICENSE-2.0.txt
|
||||
//
|
||||
package org.artofsolving.jodconverter.office;
|
||||
|
||||
import java.net.ConnectException;
|
||||
import java.util.concurrent.ExecutorService;
|
||||
import java.util.concurrent.Executors;
|
||||
import java.util.concurrent.Future;
|
||||
import java.util.logging.Level;
|
||||
import java.util.logging.Logger;
|
||||
|
||||
import com.sun.star.frame.XDesktop;
|
||||
import com.sun.star.lang.DisposedException;
|
||||
|
||||
class ManagedOfficeProcess {
|
||||
|
||||
private static final Integer EXIT_CODE_NEW_INSTALLATION = Integer.valueOf(81);
|
||||
|
||||
private final ManagedOfficeProcessSettings settings;
|
||||
|
||||
private final OfficeProcess process;
|
||||
private final OfficeConnection connection;
|
||||
|
||||
private ExecutorService executor = Executors.newSingleThreadExecutor(new NamedThreadFactory("OfficeProcessThread"));
|
||||
|
||||
private final Logger logger = Logger.getLogger(getClass().getName());
|
||||
|
||||
public ManagedOfficeProcess(ManagedOfficeProcessSettings settings) throws OfficeException {
|
||||
this.settings = settings;
|
||||
process = new OfficeProcess(settings.getOfficeHome(), settings.getUnoUrl(), settings.getRunAsArgs(), settings.getTemplateProfileDir(), settings.getWorkDir(), settings
|
||||
.getProcessManager());
|
||||
connection = new OfficeConnection(settings.getUnoUrl());
|
||||
}
|
||||
|
||||
public OfficeConnection getConnection() {
|
||||
return connection;
|
||||
}
|
||||
|
||||
public void startAndWait() throws OfficeException {
|
||||
Future<?> future = executor.submit(new Runnable() {
|
||||
public void run() {
|
||||
doStartProcessAndConnect();
|
||||
}
|
||||
});
|
||||
try {
|
||||
future.get();
|
||||
} catch (Exception exception) {
|
||||
throw new OfficeException("failed to start and connect", exception);
|
||||
}
|
||||
}
|
||||
|
||||
public void stopAndWait() throws OfficeException {
|
||||
Future<?> future = executor.submit(new Runnable() {
|
||||
public void run() {
|
||||
doStopProcess();
|
||||
}
|
||||
});
|
||||
try {
|
||||
future.get();
|
||||
} catch (Exception exception) {
|
||||
throw new OfficeException("failed to start and connect", exception);
|
||||
}
|
||||
}
|
||||
|
||||
public void restartAndWait() {
|
||||
Future<?> future = executor.submit(new Runnable() {
|
||||
public void run() {
|
||||
doStopProcess();
|
||||
doStartProcessAndConnect();
|
||||
}
|
||||
});
|
||||
try {
|
||||
future.get();
|
||||
} catch (Exception exception) {
|
||||
throw new OfficeException("failed to restart", exception);
|
||||
}
|
||||
}
|
||||
|
||||
public void restartDueToTaskTimeout() {
|
||||
executor.execute(new Runnable() {
|
||||
public void run() {
|
||||
doTerminateProcess();
|
||||
// will cause unexpected disconnection and subsequent restart
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
public void restartDueToLostConnection() {
|
||||
executor.execute(new Runnable() {
|
||||
public void run() {
|
||||
try {
|
||||
doEnsureProcessExited();
|
||||
doStartProcessAndConnect();
|
||||
} catch (OfficeException officeException) {
|
||||
logger.log(Level.SEVERE, "could not restart process", officeException);
|
||||
}
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
private void doStartProcessAndConnect() throws OfficeException {
|
||||
try {
|
||||
process.start();
|
||||
new Retryable() {
|
||||
protected void attempt() throws TemporaryException, Exception {
|
||||
try {
|
||||
connection.connect();
|
||||
} catch (ConnectException connectException) {
|
||||
Integer exitCode = process.getExitCode();
|
||||
if (exitCode == null) {
|
||||
// process is running; retry later
|
||||
throw new TemporaryException(connectException);
|
||||
} else if (exitCode.equals(EXIT_CODE_NEW_INSTALLATION)) {
|
||||
// restart and retry later
|
||||
// see http://code.google.com/p/jodconverter/issues/detail?id=84
|
||||
logger.log(Level.WARNING, "office process died with exit code 81; restarting it");
|
||||
process.start(true);
|
||||
throw new TemporaryException(connectException);
|
||||
} else {
|
||||
throw new OfficeException("office process died with exit code " + exitCode);
|
||||
}
|
||||
}
|
||||
}
|
||||
}.execute(settings.getRetryInterval(), settings.getRetryTimeout());
|
||||
} catch (Exception exception) {
|
||||
throw new OfficeException("could not establish connection", exception);
|
||||
}
|
||||
}
|
||||
|
||||
private void doStopProcess() {
|
||||
try {
|
||||
XDesktop desktop = OfficeUtils.cast(XDesktop.class, connection.getService(OfficeUtils.SERVICE_DESKTOP));
|
||||
desktop.terminate();
|
||||
} catch (DisposedException disposedException) {
|
||||
// expected
|
||||
} catch (Exception exception) {
|
||||
// in case we can't get hold of the desktop
|
||||
doTerminateProcess();
|
||||
}
|
||||
doEnsureProcessExited();
|
||||
}
|
||||
|
||||
private void doEnsureProcessExited() throws OfficeException {
|
||||
try {
|
||||
int exitCode = process.getExitCode(settings.getRetryInterval(), settings.getRetryTimeout());
|
||||
logger.info("process exited with code " + exitCode);
|
||||
} catch (RetryTimeoutException retryTimeoutException) {
|
||||
doTerminateProcess();
|
||||
}
|
||||
process.deleteProfileDir();
|
||||
}
|
||||
|
||||
private void doTerminateProcess() throws OfficeException {
|
||||
try {
|
||||
int exitCode = process.forciblyTerminate(settings.getRetryInterval(), settings.getRetryTimeout());
|
||||
logger.info("process forcibly terminated with code " + exitCode);
|
||||
} catch (Exception exception) {
|
||||
throw new OfficeException("could not terminate process", exception);
|
||||
}
|
||||
}
|
||||
|
||||
boolean isConnected() {
|
||||
return connection.isConnected();
|
||||
}
|
||||
|
||||
}
|
||||
@@ -0,0 +1,97 @@
|
||||
//
|
||||
// JODConverter - Java OpenDocument Converter
|
||||
// Copyright 2004-2012 Mirko Nasato and contributors
|
||||
//
|
||||
// JODConverter is Open Source software, you can redistribute it and/or
|
||||
// modify it under either (at your option) of the following licenses
|
||||
//
|
||||
// 1. The GNU Lesser General Public License v3 (or later)
|
||||
// -> http://www.gnu.org/licenses/lgpl-3.0.txt
|
||||
// 2. The Apache License, Version 2.0
|
||||
// -> http://www.apache.org/licenses/LICENSE-2.0.txt
|
||||
//
|
||||
package org.artofsolving.jodconverter.office;
|
||||
|
||||
import java.io.File;
|
||||
|
||||
import org.artofsolving.jodconverter.process.ProcessManager;
|
||||
import org.artofsolving.jodconverter.process.PureJavaProcessManager;
|
||||
|
||||
class ManagedOfficeProcessSettings {
|
||||
|
||||
public static final long DEFAULT_RETRY_INTERVAL = 250L;
|
||||
|
||||
private final UnoUrl unoUrl;
|
||||
private File officeHome = OfficeUtils.getDefaultOfficeHome();
|
||||
private String[] runAsArgs;
|
||||
private File templateProfileDir;
|
||||
private File workDir = new File(System.getProperty("java.io.tmpdir"));
|
||||
private ProcessManager processManager = new PureJavaProcessManager();
|
||||
private long retryTimeout = DefaultOfficeManagerConfiguration.DEFAULT_RETRY_TIMEOUT;
|
||||
private long retryInterval = DEFAULT_RETRY_INTERVAL;
|
||||
|
||||
public ManagedOfficeProcessSettings(UnoUrl unoUrl) {
|
||||
this.unoUrl = unoUrl;
|
||||
}
|
||||
|
||||
public UnoUrl getUnoUrl() {
|
||||
return unoUrl;
|
||||
}
|
||||
|
||||
public File getOfficeHome() {
|
||||
return officeHome;
|
||||
}
|
||||
|
||||
public void setOfficeHome(File officeHome) {
|
||||
this.officeHome = officeHome;
|
||||
}
|
||||
|
||||
public String[] getRunAsArgs() {
|
||||
return runAsArgs;
|
||||
}
|
||||
|
||||
public void setRunAsArgs(String[] runAsArgs) {
|
||||
this.runAsArgs = runAsArgs;
|
||||
}
|
||||
|
||||
public File getTemplateProfileDir() {
|
||||
return templateProfileDir;
|
||||
}
|
||||
|
||||
public void setTemplateProfileDir(File templateProfileDir) {
|
||||
this.templateProfileDir = templateProfileDir;
|
||||
}
|
||||
|
||||
public File getWorkDir() {
|
||||
return workDir;
|
||||
}
|
||||
|
||||
public void setWorkDir(File workDir) {
|
||||
this.workDir = workDir;
|
||||
}
|
||||
|
||||
public ProcessManager getProcessManager() {
|
||||
return processManager;
|
||||
}
|
||||
|
||||
public void setProcessManager(ProcessManager processManager) {
|
||||
this.processManager = processManager;
|
||||
}
|
||||
|
||||
public long getRetryTimeout() {
|
||||
return retryTimeout;
|
||||
}
|
||||
|
||||
public void setRetryTimeout(long retryTimeout) {
|
||||
this.retryTimeout = retryTimeout;
|
||||
}
|
||||
|
||||
public long getRetryInterval() {
|
||||
return retryInterval;
|
||||
}
|
||||
|
||||
public void setRetryInterval(long retryInterval) {
|
||||
this.retryInterval = retryInterval;
|
||||
}
|
||||
|
||||
}
|
||||
@@ -0,0 +1,43 @@
|
||||
//
|
||||
// JODConverter - Java OpenDocument Converter
|
||||
// Copyright 2004-2012 Mirko Nasato and contributors
|
||||
//
|
||||
// JODConverter is Open Source software, you can redistribute it and/or
|
||||
// modify it under either (at your option) of the following licenses
|
||||
//
|
||||
// 1. The GNU Lesser General Public License v3 (or later)
|
||||
// -> http://www.gnu.org/licenses/lgpl-3.0.txt
|
||||
// 2. The Apache License, Version 2.0
|
||||
// -> http://www.apache.org/licenses/LICENSE-2.0.txt
|
||||
//
|
||||
package org.artofsolving.jodconverter.office;
|
||||
|
||||
import java.util.concurrent.ThreadFactory;
|
||||
import java.util.concurrent.atomic.AtomicInteger;
|
||||
|
||||
/**
|
||||
* A {@link ThreadFactory} that allows for custom thread names
|
||||
*/
|
||||
class NamedThreadFactory implements ThreadFactory {
|
||||
|
||||
private static final AtomicInteger threadIndex = new AtomicInteger(0);
|
||||
|
||||
private final String baseName;
|
||||
private final boolean daemon;
|
||||
|
||||
public NamedThreadFactory(String baseName) {
|
||||
this(baseName, true);
|
||||
}
|
||||
|
||||
public NamedThreadFactory(String baseName, boolean daemon) {
|
||||
this.baseName = baseName;
|
||||
this.daemon = daemon;
|
||||
}
|
||||
|
||||
public Thread newThread(Runnable runnable) {
|
||||
Thread thread = new Thread(runnable, baseName + "-" + threadIndex.getAndIncrement());
|
||||
thread.setDaemon(daemon);
|
||||
return thread;
|
||||
}
|
||||
|
||||
}
|
||||
@@ -0,0 +1,117 @@
|
||||
//
|
||||
// JODConverter - Java OpenDocument Converter
|
||||
// Copyright 2004-2012 Mirko Nasato and contributors
|
||||
//
|
||||
// JODConverter is Open Source software, you can redistribute it and/or
|
||||
// modify it under either (at your option) of the following licenses
|
||||
//
|
||||
// 1. The GNU Lesser General Public License v3 (or later)
|
||||
// -> http://www.gnu.org/licenses/lgpl-3.0.txt
|
||||
// 2. The Apache License, Version 2.0
|
||||
// -> http://www.apache.org/licenses/LICENSE-2.0.txt
|
||||
//
|
||||
package org.artofsolving.jodconverter.office;
|
||||
|
||||
import java.net.ConnectException;
|
||||
import java.util.ArrayList;
|
||||
import java.util.List;
|
||||
import java.util.concurrent.atomic.AtomicInteger;
|
||||
import java.util.logging.Logger;
|
||||
|
||||
import com.sun.star.beans.XPropertySet;
|
||||
import com.sun.star.bridge.XBridge;
|
||||
import com.sun.star.bridge.XBridgeFactory;
|
||||
import com.sun.star.comp.helper.Bootstrap;
|
||||
import com.sun.star.connection.NoConnectException;
|
||||
import com.sun.star.connection.XConnection;
|
||||
import com.sun.star.connection.XConnector;
|
||||
import com.sun.star.lang.EventObject;
|
||||
import com.sun.star.lang.XComponent;
|
||||
import com.sun.star.lang.XEventListener;
|
||||
import com.sun.star.lang.XMultiComponentFactory;
|
||||
import com.sun.star.uno.XComponentContext;
|
||||
|
||||
class OfficeConnection implements OfficeContext {
|
||||
|
||||
private static AtomicInteger bridgeIndex = new AtomicInteger();
|
||||
|
||||
private final UnoUrl unoUrl;
|
||||
|
||||
private XComponent bridgeComponent;
|
||||
private XMultiComponentFactory serviceManager;
|
||||
private XComponentContext componentContext;
|
||||
|
||||
private final List<OfficeConnectionEventListener> connectionEventListeners = new ArrayList<OfficeConnectionEventListener>();
|
||||
|
||||
private volatile boolean connected = false;
|
||||
|
||||
private XEventListener bridgeListener = new XEventListener() {
|
||||
public void disposing(EventObject event) {
|
||||
if (connected) {
|
||||
connected = false;
|
||||
logger.info(String.format("disconnected: '%s'", unoUrl));
|
||||
OfficeConnectionEvent connectionEvent = new OfficeConnectionEvent(OfficeConnection.this);
|
||||
for (OfficeConnectionEventListener listener : connectionEventListeners) {
|
||||
listener.disconnected(connectionEvent);
|
||||
}
|
||||
}
|
||||
// else we tried to connect to a server that doesn't speak URP
|
||||
}
|
||||
};
|
||||
|
||||
private final Logger logger = Logger.getLogger(getClass().getName());
|
||||
|
||||
public OfficeConnection(UnoUrl unoUrl) {
|
||||
this.unoUrl = unoUrl;
|
||||
}
|
||||
|
||||
public void addConnectionEventListener(OfficeConnectionEventListener connectionEventListener) {
|
||||
connectionEventListeners.add(connectionEventListener);
|
||||
}
|
||||
|
||||
public void connect() throws ConnectException {
|
||||
logger.fine(String.format("connecting with connectString '%s'", unoUrl));
|
||||
try {
|
||||
XComponentContext localContext = Bootstrap.createInitialComponentContext(null);
|
||||
XMultiComponentFactory localServiceManager = localContext.getServiceManager();
|
||||
XConnector connector = OfficeUtils.cast(XConnector.class, localServiceManager.createInstanceWithContext("com.sun.star.connection.Connector", localContext));
|
||||
XConnection connection = connector.connect(unoUrl.getConnectString());
|
||||
XBridgeFactory bridgeFactory = OfficeUtils.cast(XBridgeFactory.class, localServiceManager.createInstanceWithContext("com.sun.star.bridge.BridgeFactory", localContext));
|
||||
String bridgeName = "jodconverter_" + bridgeIndex.getAndIncrement();
|
||||
XBridge bridge = bridgeFactory.createBridge(bridgeName, "urp", connection, null);
|
||||
bridgeComponent = OfficeUtils.cast(XComponent.class, bridge);
|
||||
bridgeComponent.addEventListener(bridgeListener);
|
||||
serviceManager = OfficeUtils.cast(XMultiComponentFactory.class, bridge.getInstance("StarOffice.ServiceManager"));
|
||||
XPropertySet properties = OfficeUtils.cast(XPropertySet.class, serviceManager);
|
||||
componentContext = OfficeUtils.cast(XComponentContext.class, properties.getPropertyValue("DefaultContext"));
|
||||
connected = true;
|
||||
logger.info(String.format("connected: '%s'", unoUrl));
|
||||
OfficeConnectionEvent connectionEvent = new OfficeConnectionEvent(this);
|
||||
for (OfficeConnectionEventListener listener : connectionEventListeners) {
|
||||
listener.connected(connectionEvent);
|
||||
}
|
||||
} catch (NoConnectException connectException) {
|
||||
throw new ConnectException(String.format("connection failed: '%s'; %s", unoUrl, connectException.getMessage()));
|
||||
} catch (Exception exception) {
|
||||
throw new OfficeException("connection failed: "+ unoUrl, exception);
|
||||
}
|
||||
}
|
||||
|
||||
public boolean isConnected() {
|
||||
return connected;
|
||||
}
|
||||
|
||||
public synchronized void disconnect() {
|
||||
logger.fine(String.format("disconnecting: '%s'", unoUrl));
|
||||
bridgeComponent.dispose();
|
||||
}
|
||||
|
||||
public Object getService(String serviceName) {
|
||||
try {
|
||||
return serviceManager.createInstanceWithContext(serviceName, componentContext);
|
||||
} catch (Exception exception) {
|
||||
throw new OfficeException(String.format("failed to obtain service '%s'", serviceName), exception);
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
@@ -0,0 +1,25 @@
|
||||
//
|
||||
// JODConverter - Java OpenDocument Converter
|
||||
// Copyright 2004-2012 Mirko Nasato and contributors
|
||||
//
|
||||
// JODConverter is Open Source software, you can redistribute it and/or
|
||||
// modify it under either (at your option) of the following licenses
|
||||
//
|
||||
// 1. The GNU Lesser General Public License v3 (or later)
|
||||
// -> http://www.gnu.org/licenses/lgpl-3.0.txt
|
||||
// 2. The Apache License, Version 2.0
|
||||
// -> http://www.apache.org/licenses/LICENSE-2.0.txt
|
||||
//
|
||||
package org.artofsolving.jodconverter.office;
|
||||
|
||||
import java.util.EventObject;
|
||||
|
||||
class OfficeConnectionEvent extends EventObject {
|
||||
|
||||
private static final long serialVersionUID = 2060652797570876077L;
|
||||
|
||||
public OfficeConnectionEvent(OfficeConnection source) {
|
||||
super(source);
|
||||
}
|
||||
|
||||
}
|
||||
@@ -0,0 +1,23 @@
|
||||
//
|
||||
// JODConverter - Java OpenDocument Converter
|
||||
// Copyright 2004-2012 Mirko Nasato and contributors
|
||||
//
|
||||
// JODConverter is Open Source software, you can redistribute it and/or
|
||||
// modify it under either (at your option) of the following licenses
|
||||
//
|
||||
// 1. The GNU Lesser General Public License v3 (or later)
|
||||
// -> http://www.gnu.org/licenses/lgpl-3.0.txt
|
||||
// 2. The Apache License, Version 2.0
|
||||
// -> http://www.apache.org/licenses/LICENSE-2.0.txt
|
||||
//
|
||||
package org.artofsolving.jodconverter.office;
|
||||
|
||||
import java.util.EventListener;
|
||||
|
||||
interface OfficeConnectionEventListener extends EventListener {
|
||||
|
||||
void connected(OfficeConnectionEvent event);
|
||||
|
||||
void disconnected(OfficeConnectionEvent event);
|
||||
|
||||
}
|
||||
@@ -0,0 +1,15 @@
|
||||
//
|
||||
// JODConverter - Java OpenDocument Converter
|
||||
// Copyright 2004-2012 Mirko Nasato and contributors
|
||||
//
|
||||
// JODConverter is Open Source software, you can redistribute it and/or
|
||||
// modify it under either (at your option) of the following licenses
|
||||
//
|
||||
// 1. The GNU Lesser General Public License v3 (or later)
|
||||
// -> http://www.gnu.org/licenses/lgpl-3.0.txt
|
||||
// 2. The Apache License, Version 2.0
|
||||
// -> http://www.apache.org/licenses/LICENSE-2.0.txt
|
||||
//
|
||||
package org.artofsolving.jodconverter.office;
|
||||
|
||||
public enum OfficeConnectionProtocol { PIPE, SOCKET }
|
||||
@@ -0,0 +1,19 @@
|
||||
//
|
||||
// JODConverter - Java OpenDocument Converter
|
||||
// Copyright 2004-2012 Mirko Nasato and contributors
|
||||
//
|
||||
// JODConverter is Open Source software, you can redistribute it and/or
|
||||
// modify it under either (at your option) of the following licenses
|
||||
//
|
||||
// 1. The GNU Lesser General Public License v3 (or later)
|
||||
// -> http://www.gnu.org/licenses/lgpl-3.0.txt
|
||||
// 2. The Apache License, Version 2.0
|
||||
// -> http://www.apache.org/licenses/LICENSE-2.0.txt
|
||||
//
|
||||
package org.artofsolving.jodconverter.office;
|
||||
|
||||
public interface OfficeContext {
|
||||
|
||||
Object getService(String serviceName);
|
||||
|
||||
}
|
||||
@@ -0,0 +1,26 @@
|
||||
//
|
||||
// JODConverter - Java OpenDocument Converter
|
||||
// Copyright 2004-2012 Mirko Nasato and contributors
|
||||
//
|
||||
// JODConverter is Open Source software, you can redistribute it and/or
|
||||
// modify it under either (at your option) of the following licenses
|
||||
//
|
||||
// 1. The GNU Lesser General Public License v3 (or later)
|
||||
// -> http://www.gnu.org/licenses/lgpl-3.0.txt
|
||||
// 2. The Apache License, Version 2.0
|
||||
// -> http://www.apache.org/licenses/LICENSE-2.0.txt
|
||||
//
|
||||
package org.artofsolving.jodconverter.office;
|
||||
|
||||
public class OfficeException extends RuntimeException {
|
||||
|
||||
private static final long serialVersionUID = 1L;
|
||||
|
||||
public OfficeException(String message) {
|
||||
super(message);
|
||||
}
|
||||
|
||||
public OfficeException(String message, Throwable cause) {
|
||||
super(message, cause);
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,30 @@
|
||||
//
|
||||
// JODConverter - Java OpenDocument Converter
|
||||
// Copyright 2004-2012 Mirko Nasato and contributors
|
||||
//
|
||||
// JODConverter is Open Source software, you can redistribute it and/or
|
||||
// modify it under either (at your option) of the following licenses
|
||||
//
|
||||
// 1. The GNU Lesser General Public License v3 (or later)
|
||||
// -> http://www.gnu.org/licenses/lgpl-3.0.txt
|
||||
// 2. The Apache License, Version 2.0
|
||||
// -> http://www.apache.org/licenses/LICENSE-2.0.txt
|
||||
//
|
||||
package org.artofsolving.jodconverter.office;
|
||||
|
||||
/**
|
||||
* An OfficeManager knows how to execute {@link OfficeTask}s.
|
||||
* <p>
|
||||
* An OfficeManager implementation will typically manage one or more
|
||||
* {@link OfficeConnection}s.
|
||||
*/
|
||||
public interface OfficeManager {
|
||||
|
||||
void execute(OfficeTask task) throws OfficeException;
|
||||
|
||||
void start() throws OfficeException;
|
||||
|
||||
void stop() throws OfficeException;
|
||||
|
||||
boolean isRunning();
|
||||
}
|
||||
@@ -0,0 +1,209 @@
|
||||
//
|
||||
// JODConverter - Java OpenDocument Converter
|
||||
// Copyright 2004-2012 Mirko Nasato and contributors
|
||||
//
|
||||
// JODConverter is Open Source software, you can redistribute it and/or
|
||||
// modify it under either (at your option) of the following licenses
|
||||
//
|
||||
// 1. The GNU Lesser General Public License v3 (or later)
|
||||
// -> http://www.gnu.org/licenses/lgpl-3.0.txt
|
||||
// 2. The Apache License, Version 2.0
|
||||
// -> http://www.apache.org/licenses/LICENSE-2.0.txt
|
||||
//
|
||||
package org.artofsolving.jodconverter.office;
|
||||
|
||||
import static org.artofsolving.jodconverter.process.ProcessManager.PID_NOT_FOUND;
|
||||
import static org.artofsolving.jodconverter.process.ProcessManager.PID_UNKNOWN;
|
||||
import java.io.File;
|
||||
import java.io.IOException;
|
||||
import java.util.ArrayList;
|
||||
import java.util.Arrays;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
import java.util.logging.Logger;
|
||||
|
||||
import org.apache.commons.io.FileUtils;
|
||||
import org.artofsolving.jodconverter.process.ProcessManager;
|
||||
import org.artofsolving.jodconverter.process.ProcessQuery;
|
||||
import org.artofsolving.jodconverter.util.PlatformUtils;
|
||||
|
||||
class OfficeProcess {
|
||||
|
||||
private final File officeHome;
|
||||
private final UnoUrl unoUrl;
|
||||
private final String[] runAsArgs;
|
||||
private final File templateProfileDir;
|
||||
private final File instanceProfileDir;
|
||||
private final ProcessManager processManager;
|
||||
|
||||
private Process process;
|
||||
private long pid = PID_UNKNOWN;
|
||||
|
||||
private final Logger logger = Logger.getLogger(getClass().getName());
|
||||
|
||||
public OfficeProcess(File officeHome, UnoUrl unoUrl, String[] runAsArgs, File templateProfileDir, File workDir, ProcessManager processManager) {
|
||||
this.officeHome = officeHome;
|
||||
this.unoUrl = unoUrl;
|
||||
this.runAsArgs = runAsArgs;
|
||||
this.templateProfileDir = templateProfileDir;
|
||||
this.instanceProfileDir = getInstanceProfileDir(workDir, unoUrl);
|
||||
this.processManager = processManager;
|
||||
}
|
||||
|
||||
public void start() throws IOException {
|
||||
start(false);
|
||||
}
|
||||
|
||||
public void start(boolean restart) throws IOException {
|
||||
ProcessQuery processQuery = new ProcessQuery("soffice.bin", unoUrl.getAcceptString());
|
||||
long existingPid = processManager.findPid(processQuery);
|
||||
if (!(existingPid == PID_NOT_FOUND || existingPid == PID_UNKNOWN)) {
|
||||
throw new IllegalStateException(String.format("a process with acceptString '%s' is already running; pid %d",
|
||||
unoUrl.getAcceptString(), existingPid));
|
||||
}
|
||||
if (!restart) {
|
||||
prepareInstanceProfileDir();
|
||||
}
|
||||
List<String> command = new ArrayList<String>();
|
||||
File executable = OfficeUtils.getOfficeExecutable(officeHome);
|
||||
if (runAsArgs != null) {
|
||||
command.addAll(Arrays.asList(runAsArgs));
|
||||
}
|
||||
command.add(executable.getAbsolutePath());
|
||||
command.add("-accept=" + unoUrl.getAcceptString() + ";urp;");
|
||||
command.add("-env:UserInstallation=" + OfficeUtils.toUrl(instanceProfileDir));
|
||||
command.add("-headless");
|
||||
command.add("-nocrashreport");
|
||||
command.add("-nodefault");
|
||||
command.add("-nofirststartwizard");
|
||||
command.add("-nolockcheck");
|
||||
command.add("-nologo");
|
||||
command.add("-norestore");
|
||||
ProcessBuilder processBuilder = new ProcessBuilder(command);
|
||||
if (PlatformUtils.isWindows()) {
|
||||
addBasisAndUrePaths(processBuilder);
|
||||
}
|
||||
logger.info(String.format("starting process with acceptString '%s' and profileDir '%s'", unoUrl, instanceProfileDir));
|
||||
process = processBuilder.start();
|
||||
pid = processManager.findPid(processQuery);
|
||||
if (pid == PID_NOT_FOUND) {
|
||||
throw new IllegalStateException(String.format("process with acceptString '%s' started but its pid could not be found",
|
||||
unoUrl.getAcceptString()));
|
||||
}
|
||||
logger.info("started process" + (pid != PID_UNKNOWN ? "; pid = " + pid : ""));
|
||||
}
|
||||
|
||||
private File getInstanceProfileDir(File workDir, UnoUrl unoUrl) {
|
||||
String dirName = ".jodconverter_" + unoUrl.getAcceptString().replace(',', '_').replace('=', '-');
|
||||
return new File(workDir, dirName);
|
||||
}
|
||||
|
||||
private void prepareInstanceProfileDir() throws OfficeException {
|
||||
if (instanceProfileDir.exists()) {
|
||||
logger.warning(String.format("profile dir '%s' already exists; deleting", instanceProfileDir));
|
||||
deleteProfileDir();
|
||||
}
|
||||
if (templateProfileDir != null) {
|
||||
try {
|
||||
FileUtils.copyDirectory(templateProfileDir, instanceProfileDir);
|
||||
} catch (IOException ioException) {
|
||||
throw new OfficeException("failed to create profileDir", ioException);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public void deleteProfileDir() {
|
||||
if (instanceProfileDir != null) {
|
||||
try {
|
||||
FileUtils.deleteDirectory(instanceProfileDir);
|
||||
} catch (IOException ioException) {
|
||||
File oldProfileDir = new File(instanceProfileDir.getParentFile(), instanceProfileDir.getName() + ".old." + System.currentTimeMillis());
|
||||
if (instanceProfileDir.renameTo(oldProfileDir)) {
|
||||
logger.warning("could not delete profileDir: " + ioException.getMessage() + "; renamed it to " + oldProfileDir);
|
||||
} else {
|
||||
logger.severe("could not delete profileDir: " + ioException.getMessage());
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private void addBasisAndUrePaths(ProcessBuilder processBuilder) throws IOException {
|
||||
// see http://wiki.services.openoffice.org/wiki/ODF_Toolkit/Efforts/Three-Layer_OOo
|
||||
File basisLink = new File(officeHome, "basis-link");
|
||||
if (!basisLink.isFile()) {
|
||||
logger.fine("no %OFFICE_HOME%/basis-link found; assuming it's OOo 2.x and we don't need to append URE and Basic paths");
|
||||
return;
|
||||
}
|
||||
String basisLinkText = FileUtils.readFileToString(basisLink).trim();
|
||||
File basisHome = new File(officeHome, basisLinkText);
|
||||
File basisProgram = new File(basisHome, "program");
|
||||
File ureLink = new File(basisHome, "ure-link");
|
||||
String ureLinkText = FileUtils.readFileToString(ureLink).trim();
|
||||
File ureHome = new File(basisHome, ureLinkText);
|
||||
File ureBin = new File(ureHome, "bin");
|
||||
Map<String,String> environment = processBuilder.environment();
|
||||
// Windows environment variables are case insensitive but Java maps are not :-/
|
||||
// so let's make sure we modify the existing key
|
||||
String pathKey = "PATH";
|
||||
for (String key : environment.keySet()) {
|
||||
if ("PATH".equalsIgnoreCase(key)) {
|
||||
pathKey = key;
|
||||
}
|
||||
}
|
||||
String path = environment.get(pathKey) + ";" + ureBin.getAbsolutePath() + ";" + basisProgram.getAbsolutePath();
|
||||
logger.fine(String.format("setting %s to \"%s\"", pathKey, path));
|
||||
environment.put(pathKey, path);
|
||||
}
|
||||
|
||||
public boolean isRunning() {
|
||||
if (process == null) {
|
||||
return false;
|
||||
}
|
||||
return getExitCode() == null;
|
||||
}
|
||||
|
||||
private class ExitCodeRetryable extends Retryable {
|
||||
|
||||
private int exitCode;
|
||||
|
||||
protected void attempt() throws TemporaryException, Exception {
|
||||
try {
|
||||
exitCode = process.exitValue();
|
||||
} catch (IllegalThreadStateException illegalThreadStateException) {
|
||||
throw new TemporaryException(illegalThreadStateException);
|
||||
}
|
||||
}
|
||||
|
||||
public int getExitCode() {
|
||||
return exitCode;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
public Integer getExitCode() {
|
||||
try {
|
||||
return process.exitValue();
|
||||
} catch (IllegalThreadStateException exception) {
|
||||
return null;
|
||||
}
|
||||
}
|
||||
|
||||
public int getExitCode(long retryInterval, long retryTimeout) throws RetryTimeoutException {
|
||||
try {
|
||||
ExitCodeRetryable retryable = new ExitCodeRetryable();
|
||||
retryable.execute(retryInterval, retryTimeout);
|
||||
return retryable.getExitCode();
|
||||
} catch (RetryTimeoutException retryTimeoutException) {
|
||||
throw retryTimeoutException;
|
||||
} catch (Exception exception) {
|
||||
throw new OfficeException("could not get process exit code", exception);
|
||||
}
|
||||
}
|
||||
|
||||
public int forciblyTerminate(long retryInterval, long retryTimeout) throws IOException, RetryTimeoutException {
|
||||
logger.info(String.format("trying to forcibly terminate process: '" + unoUrl + "'" + (pid != PID_UNKNOWN ? " (pid " + pid + ")" : "")));
|
||||
processManager.kill(process, pid);
|
||||
return getExitCode(retryInterval, retryTimeout);
|
||||
}
|
||||
|
||||
}
|
||||
@@ -0,0 +1,19 @@
|
||||
//
|
||||
// JODConverter - Java OpenDocument Converter
|
||||
// Copyright 2004-2012 Mirko Nasato and contributors
|
||||
//
|
||||
// JODConverter is Open Source software, you can redistribute it and/or
|
||||
// modify it under either (at your option) of the following licenses
|
||||
//
|
||||
// 1. The GNU Lesser General Public License v3 (or later)
|
||||
// -> http://www.gnu.org/licenses/lgpl-3.0.txt
|
||||
// 2. The Apache License, Version 2.0
|
||||
// -> http://www.apache.org/licenses/LICENSE-2.0.txt
|
||||
//
|
||||
package org.artofsolving.jodconverter.office;
|
||||
|
||||
public interface OfficeTask {
|
||||
|
||||
void execute(OfficeContext context) throws OfficeException;
|
||||
|
||||
}
|
||||
@@ -0,0 +1,161 @@
|
||||
//
|
||||
// JODConverter - Java OpenDocument Converter
|
||||
// Copyright 2004-2012 Mirko Nasato and contributors
|
||||
//
|
||||
// JODConverter is Open Source software, you can redistribute it and/or
|
||||
// modify it under either (at your option) of the following licenses
|
||||
//
|
||||
// 1. The GNU Lesser General Public License v3 (or later)
|
||||
// -> http://www.gnu.org/licenses/lgpl-3.0.txt
|
||||
// 2. The Apache License, Version 2.0
|
||||
// -> http://www.apache.org/licenses/LICENSE-2.0.txt
|
||||
//
|
||||
package org.artofsolving.jodconverter.office;
|
||||
|
||||
import java.io.BufferedReader;
|
||||
import java.io.File;
|
||||
import java.io.FileReader;
|
||||
import java.util.Iterator;
|
||||
import java.util.Map;
|
||||
import java.util.Properties;
|
||||
|
||||
import org.artofsolving.jodconverter.util.ConfigUtils;
|
||||
import org.artofsolving.jodconverter.util.PlatformUtils;
|
||||
|
||||
import com.sun.star.beans.PropertyValue;
|
||||
import com.sun.star.uno.UnoRuntime;
|
||||
|
||||
public class OfficeUtils {
|
||||
|
||||
public static final String SERVICE_DESKTOP = "com.sun.star.frame.Desktop";
|
||||
public static final String OFFICE_HOME_KEY = "office.home";
|
||||
public static final String DEFAULT_OFFICE_HOME_VALUE = "default";
|
||||
|
||||
private OfficeUtils() {
|
||||
throw new AssertionError("utility class must not be instantiated");
|
||||
}
|
||||
|
||||
public static <T> T cast(Class<T> type, Object object) {
|
||||
return (T) UnoRuntime.queryInterface(type, object);
|
||||
}
|
||||
|
||||
public static PropertyValue property(String name, Object value) {
|
||||
PropertyValue propertyValue = new PropertyValue();
|
||||
propertyValue.Name = name;
|
||||
propertyValue.Value = value;
|
||||
return propertyValue;
|
||||
}
|
||||
|
||||
@SuppressWarnings("unchecked")
|
||||
public static PropertyValue[] toUnoProperties(Map<String,?> properties) {
|
||||
PropertyValue[] propertyValues = new PropertyValue[properties.size()];
|
||||
int i = 0;
|
||||
for (Map.Entry<String,?> entry : properties.entrySet()) {
|
||||
Object value = entry.getValue();
|
||||
if (value instanceof Map) {
|
||||
Map<String,Object> subProperties = (Map<String,Object>) value;
|
||||
value = toUnoProperties(subProperties);
|
||||
}
|
||||
propertyValues[i++] = property(entry.getKey(), value);
|
||||
}
|
||||
return propertyValues;
|
||||
}
|
||||
|
||||
public static String toUrl(File file) {
|
||||
String path = file.toURI().getRawPath();
|
||||
String url = path.startsWith("//") ? "file:" + path : "file://" + path;
|
||||
return url.endsWith("/") ? url.substring(0, url.length() - 1) : url;
|
||||
}
|
||||
|
||||
public static File getDefaultOfficeHome() {
|
||||
Properties properties = new Properties();
|
||||
String customizedConfigPath = ConfigUtils.getCustomizedConfigPath();
|
||||
try {
|
||||
BufferedReader bufferedReader = new BufferedReader(new FileReader(customizedConfigPath));
|
||||
properties.load(bufferedReader);
|
||||
restorePropertiesFromEnvFormat(properties);
|
||||
} catch (Exception e) {}
|
||||
String officeHome = properties.getProperty(OFFICE_HOME_KEY);
|
||||
if (officeHome != null && !DEFAULT_OFFICE_HOME_VALUE.equals(officeHome)) {
|
||||
return new File(officeHome);
|
||||
}
|
||||
if (PlatformUtils.isWindows()) {
|
||||
// %ProgramFiles(x86)% on 64-bit machines; %ProgramFiles% on 32-bit ones
|
||||
String homePath = ConfigUtils.getHomePath();
|
||||
String programFiles = System.getenv("ProgramFiles(x86)");
|
||||
if (programFiles == null) {
|
||||
programFiles = System.getenv("ProgramFiles");
|
||||
}
|
||||
return findOfficeHome(
|
||||
programFiles + File.separator + "OpenOffice 4",
|
||||
programFiles + File.separator + "LibreOffice 4",
|
||||
homePath + File.separator + "office"
|
||||
);
|
||||
} else if (PlatformUtils.isMac()) {
|
||||
return findOfficeHome(
|
||||
"/Applications/OpenOffice.org.app/Contents",
|
||||
"/Applications/OpenOffice.app/Contents",
|
||||
"/Applications/LibreOffice.app/Contents"
|
||||
);
|
||||
} else {
|
||||
// Linux or other *nix variants
|
||||
return findOfficeHome(
|
||||
"/opt/openoffice.org3",
|
||||
"/opt/openoffice",
|
||||
"/opt/libreoffice",
|
||||
"/opt/openoffice4",
|
||||
"/usr/lib/openoffice",
|
||||
"/usr/lib/libreoffice"
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
private static File findOfficeHome(String... knownPaths) {
|
||||
for (String path : knownPaths) {
|
||||
File home = new File(path);
|
||||
if (getOfficeExecutable(home).isFile()) {
|
||||
return home;
|
||||
}
|
||||
}
|
||||
return null;
|
||||
}
|
||||
|
||||
public static File getOfficeExecutable(File officeHome) {
|
||||
if (PlatformUtils.isMac()) {
|
||||
return new File(officeHome, "MacOS/soffice");
|
||||
} else {
|
||||
return new File(officeHome, "program/soffice.bin");
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
|
||||
/**
|
||||
* SpringBoot application.properties 支持从环境变量获取值
|
||||
* @param properties
|
||||
*/
|
||||
public synchronized static void restorePropertiesFromEnvFormat(Properties properties) {
|
||||
Iterator<Map.Entry<Object, Object>> iterator = properties.entrySet().iterator();
|
||||
while (iterator.hasNext()) {
|
||||
Map.Entry<Object, Object> entry = iterator.next();
|
||||
String key = entry.getKey().toString();
|
||||
String value = entry.getValue().toString();
|
||||
if (value.trim().startsWith("${") && value.trim().endsWith("}")) {
|
||||
int beginIndex = value.indexOf(":");
|
||||
if (beginIndex < 0) {
|
||||
beginIndex = value.length() - 1;
|
||||
}
|
||||
int endIndex = value.length() - 1;
|
||||
String envKey = value.substring(2, beginIndex);
|
||||
String envValue = System.getenv(envKey);
|
||||
if (envValue == null || "".equals(envValue.trim())) {
|
||||
value = value.substring(beginIndex + 1, endIndex);
|
||||
} else {
|
||||
value = envValue;
|
||||
}
|
||||
properties.setProperty(key, value);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
@@ -0,0 +1,110 @@
|
||||
//
|
||||
//
|
||||
// JODConverter - Java OpenDocument Converter
|
||||
// Copyright 2004-2012 Mirko Nasato and contributors
|
||||
//
|
||||
// JODConverter is Open Source software, you can redistribute it and/or
|
||||
// modify it under either (at your option) of the following licenses
|
||||
//
|
||||
// 1. The GNU Lesser General Public License v3 (or later)
|
||||
// -> http://www.gnu.org/licenses/lgpl-3.0.txt
|
||||
// 2. The Apache License, Version 2.0
|
||||
// -> http://www.apache.org/licenses/LICENSE-2.0.txt
|
||||
//
|
||||
package org.artofsolving.jodconverter.office;
|
||||
|
||||
import java.util.concurrent.ExecutionException;
|
||||
import java.util.concurrent.Future;
|
||||
import java.util.concurrent.TimeUnit;
|
||||
import java.util.concurrent.TimeoutException;
|
||||
import java.util.logging.Logger;
|
||||
|
||||
class PooledOfficeManager implements OfficeManager {
|
||||
|
||||
private final PooledOfficeManagerSettings settings;
|
||||
private final ManagedOfficeProcess managedOfficeProcess;
|
||||
private final SuspendableThreadPoolExecutor taskExecutor;
|
||||
|
||||
private volatile boolean stopping = false;
|
||||
private int taskCount;
|
||||
private Future<?> currentTask;
|
||||
|
||||
private final Logger logger = Logger.getLogger(getClass().getName());
|
||||
|
||||
private OfficeConnectionEventListener connectionEventListener = new OfficeConnectionEventListener() {
|
||||
public void connected(OfficeConnectionEvent event) {
|
||||
taskCount = 0;
|
||||
taskExecutor.setAvailable(true);
|
||||
}
|
||||
public void disconnected(OfficeConnectionEvent event) {
|
||||
taskExecutor.setAvailable(false);
|
||||
if (stopping) {
|
||||
// expected
|
||||
stopping = false;
|
||||
} else {
|
||||
logger.warning("connection lost unexpectedly; attempting restart");
|
||||
if (currentTask != null) {
|
||||
currentTask.cancel(true);
|
||||
}
|
||||
managedOfficeProcess.restartDueToLostConnection();
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
public PooledOfficeManager(UnoUrl unoUrl) {
|
||||
this(new PooledOfficeManagerSettings(unoUrl));
|
||||
}
|
||||
|
||||
public PooledOfficeManager(PooledOfficeManagerSettings settings) {
|
||||
this.settings = settings;
|
||||
managedOfficeProcess = new ManagedOfficeProcess(settings);
|
||||
managedOfficeProcess.getConnection().addConnectionEventListener(connectionEventListener);
|
||||
taskExecutor = new SuspendableThreadPoolExecutor(new NamedThreadFactory("OfficeTaskThread"));
|
||||
}
|
||||
|
||||
public void execute(final OfficeTask task) throws OfficeException {
|
||||
Future<?> futureTask = taskExecutor.submit(new Runnable() {
|
||||
public void run() {
|
||||
if (settings.getMaxTasksPerProcess() > 0 && ++taskCount == settings.getMaxTasksPerProcess() + 1) {
|
||||
logger.info(String.format("reached limit of %d maxTasksPerProcess: restarting", settings.getMaxTasksPerProcess()));
|
||||
taskExecutor.setAvailable(false);
|
||||
stopping = true;
|
||||
managedOfficeProcess.restartAndWait();
|
||||
//FIXME taskCount will be 0 rather than 1 at this point
|
||||
}
|
||||
task.execute(managedOfficeProcess.getConnection());
|
||||
}
|
||||
});
|
||||
currentTask = futureTask;
|
||||
try {
|
||||
futureTask.get(settings.getTaskExecutionTimeout(), TimeUnit.MILLISECONDS);
|
||||
} catch (TimeoutException timeoutException) {
|
||||
managedOfficeProcess.restartDueToTaskTimeout();
|
||||
throw new OfficeException("task did not complete within timeout", timeoutException);
|
||||
} catch (ExecutionException executionException) {
|
||||
if (executionException.getCause() instanceof OfficeException) {
|
||||
throw (OfficeException) executionException.getCause();
|
||||
} else {
|
||||
throw new OfficeException("task failed", executionException.getCause());
|
||||
}
|
||||
} catch (Exception exception) {
|
||||
throw new OfficeException("task failed", exception);
|
||||
}
|
||||
}
|
||||
|
||||
public void start() throws OfficeException {
|
||||
managedOfficeProcess.startAndWait();
|
||||
}
|
||||
|
||||
public void stop() throws OfficeException {
|
||||
taskExecutor.setAvailable(false);
|
||||
stopping = true;
|
||||
taskExecutor.shutdownNow();
|
||||
managedOfficeProcess.stopAndWait();
|
||||
}
|
||||
|
||||
public boolean isRunning() {
|
||||
return managedOfficeProcess.isConnected();
|
||||
}
|
||||
|
||||
}
|
||||
@@ -0,0 +1,43 @@
|
||||
//
|
||||
// JODConverter - Java OpenDocument Converter
|
||||
// Copyright 2004-2012 Mirko Nasato and contributors
|
||||
//
|
||||
// JODConverter is Open Source software, you can redistribute it and/or
|
||||
// modify it under either (at your option) of the following licenses
|
||||
//
|
||||
// 1. The GNU Lesser General Public License v3 (or later)
|
||||
// -> http://www.gnu.org/licenses/lgpl-3.0.txt
|
||||
// 2. The Apache License, Version 2.0
|
||||
// -> http://www.apache.org/licenses/LICENSE-2.0.txt
|
||||
//
|
||||
package org.artofsolving.jodconverter.office;
|
||||
|
||||
class PooledOfficeManagerSettings extends ManagedOfficeProcessSettings {
|
||||
|
||||
public static final long DEFAULT_TASK_EXECUTION_TIMEOUT = 120000L;
|
||||
public static final int DEFAULT_MAX_TASKS_PER_PROCESS = 200;
|
||||
|
||||
private long taskExecutionTimeout = DEFAULT_TASK_EXECUTION_TIMEOUT;
|
||||
private int maxTasksPerProcess = DEFAULT_MAX_TASKS_PER_PROCESS;
|
||||
|
||||
public PooledOfficeManagerSettings(UnoUrl unoUrl) {
|
||||
super(unoUrl);
|
||||
}
|
||||
|
||||
public long getTaskExecutionTimeout() {
|
||||
return taskExecutionTimeout;
|
||||
}
|
||||
|
||||
public void setTaskExecutionTimeout(long taskExecutionTimeout) {
|
||||
this.taskExecutionTimeout = taskExecutionTimeout;
|
||||
}
|
||||
|
||||
public int getMaxTasksPerProcess() {
|
||||
return maxTasksPerProcess;
|
||||
}
|
||||
|
||||
public void setMaxTasksPerProcess(int maxTasksPerProcess) {
|
||||
this.maxTasksPerProcess = maxTasksPerProcess;
|
||||
}
|
||||
|
||||
}
|
||||
@@ -0,0 +1,110 @@
|
||||
//
|
||||
// JODConverter - Java OpenDocument Converter
|
||||
// Copyright 2004-2012 Mirko Nasato and contributors
|
||||
//
|
||||
// JODConverter is Open Source software, you can redistribute it and/or
|
||||
// modify it under either (at your option) of the following licenses
|
||||
//
|
||||
// 1. The GNU Lesser General Public License v3 (or later)
|
||||
// -> http://www.gnu.org/licenses/lgpl-3.0.txt
|
||||
// 2. The Apache License, Version 2.0
|
||||
// -> http://www.apache.org/licenses/LICENSE-2.0.txt
|
||||
//
|
||||
package org.artofsolving.jodconverter.office;
|
||||
|
||||
import java.io.File;
|
||||
import java.util.concurrent.ArrayBlockingQueue;
|
||||
import java.util.concurrent.BlockingQueue;
|
||||
import java.util.concurrent.TimeUnit;
|
||||
import java.util.logging.Logger;
|
||||
|
||||
import org.artofsolving.jodconverter.process.ProcessManager;
|
||||
|
||||
class ProcessPoolOfficeManager implements OfficeManager {
|
||||
|
||||
private final BlockingQueue<PooledOfficeManager> pool;
|
||||
private final PooledOfficeManager[] pooledManagers;
|
||||
private final long taskQueueTimeout;
|
||||
|
||||
private volatile boolean running = false;
|
||||
|
||||
private final Logger logger = Logger.getLogger(ProcessPoolOfficeManager.class.getName());
|
||||
|
||||
public ProcessPoolOfficeManager(File officeHome, UnoUrl[] unoUrls, String[] runAsArgs, File templateProfileDir, File workDir,
|
||||
long retryTimeout, long taskQueueTimeout, long taskExecutionTimeout, int maxTasksPerProcess,
|
||||
ProcessManager processManager) {
|
||||
this.taskQueueTimeout = taskQueueTimeout;
|
||||
pool = new ArrayBlockingQueue<PooledOfficeManager>(unoUrls.length);
|
||||
pooledManagers = new PooledOfficeManager[unoUrls.length];
|
||||
for (int i = 0; i < unoUrls.length; i++) {
|
||||
PooledOfficeManagerSettings settings = new PooledOfficeManagerSettings(unoUrls[i]);
|
||||
settings.setRunAsArgs(runAsArgs);
|
||||
settings.setTemplateProfileDir(templateProfileDir);
|
||||
settings.setWorkDir(workDir);
|
||||
settings.setOfficeHome(officeHome);
|
||||
settings.setRetryTimeout(retryTimeout);
|
||||
settings.setTaskExecutionTimeout(taskExecutionTimeout);
|
||||
settings.setMaxTasksPerProcess(maxTasksPerProcess);
|
||||
settings.setProcessManager(processManager);
|
||||
pooledManagers[i] = new PooledOfficeManager(settings);
|
||||
}
|
||||
logger.info("ProcessManager implementation is " + processManager.getClass().getSimpleName());
|
||||
}
|
||||
|
||||
public synchronized void start() throws OfficeException {
|
||||
for (int i = 0; i < pooledManagers.length; i++) {
|
||||
pooledManagers[i].start();
|
||||
releaseManager(pooledManagers[i]);
|
||||
}
|
||||
running = true;
|
||||
}
|
||||
|
||||
public void execute(OfficeTask task) throws IllegalStateException, OfficeException {
|
||||
if (!running) {
|
||||
throw new IllegalStateException("this OfficeManager is currently stopped");
|
||||
}
|
||||
PooledOfficeManager manager = null;
|
||||
try {
|
||||
manager = acquireManager();
|
||||
if (manager == null) {
|
||||
throw new OfficeException("no office manager available");
|
||||
}
|
||||
manager.execute(task);
|
||||
} finally {
|
||||
if (manager != null) {
|
||||
releaseManager(manager);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public synchronized void stop() throws OfficeException {
|
||||
running = false;
|
||||
logger.info("stopping");
|
||||
pool.clear();
|
||||
for (int i = 0; i < pooledManagers.length; i++) {
|
||||
pooledManagers[i].stop();
|
||||
}
|
||||
logger.info("stopped");
|
||||
}
|
||||
|
||||
private PooledOfficeManager acquireManager() {
|
||||
try {
|
||||
return pool.poll(taskQueueTimeout, TimeUnit.MILLISECONDS);
|
||||
} catch (InterruptedException interruptedException) {
|
||||
throw new OfficeException("interrupted", interruptedException);
|
||||
}
|
||||
}
|
||||
|
||||
private void releaseManager(PooledOfficeManager manager) {
|
||||
try {
|
||||
pool.put(manager);
|
||||
} catch (InterruptedException interruptedException) {
|
||||
throw new OfficeException("interrupted", interruptedException);
|
||||
}
|
||||
}
|
||||
|
||||
public boolean isRunning() {
|
||||
return running;
|
||||
}
|
||||
|
||||
}
|
||||
@@ -0,0 +1,23 @@
|
||||
//
|
||||
// JODConverter - Java OpenDocument Converter
|
||||
// Copyright 2004-2012 Mirko Nasato and contributors
|
||||
//
|
||||
// JODConverter is Open Source software, you can redistribute it and/or
|
||||
// modify it under either (at your option) of the following licenses
|
||||
//
|
||||
// 1. The GNU Lesser General Public License v3 (or later)
|
||||
// -> http://www.gnu.org/licenses/lgpl-3.0.txt
|
||||
// 2. The Apache License, Version 2.0
|
||||
// -> http://www.apache.org/licenses/LICENSE-2.0.txt
|
||||
//
|
||||
package org.artofsolving.jodconverter.office;
|
||||
|
||||
class RetryTimeoutException extends Exception {
|
||||
|
||||
private static final long serialVersionUID = -3704437769955257514L;
|
||||
|
||||
public RetryTimeoutException(Throwable cause) {
|
||||
super(cause);
|
||||
}
|
||||
|
||||
}
|
||||
@@ -0,0 +1,55 @@
|
||||
//
|
||||
// JODConverter - Java OpenDocument Converter
|
||||
// Copyright 2004-2012 Mirko Nasato and contributors
|
||||
//
|
||||
// JODConverter is Open Source software, you can redistribute it and/or
|
||||
// modify it under either (at your option) of the following licenses
|
||||
//
|
||||
// 1. The GNU Lesser General Public License v3 (or later)
|
||||
// -> http://www.gnu.org/licenses/lgpl-3.0.txt
|
||||
// 2. The Apache License, Version 2.0
|
||||
// -> http://www.apache.org/licenses/LICENSE-2.0.txt
|
||||
//
|
||||
package org.artofsolving.jodconverter.office;
|
||||
|
||||
abstract class Retryable {
|
||||
|
||||
/**
|
||||
* @throws TemporaryException for an error condition that can be temporary - i.e. retrying later could be successful
|
||||
* @throws Exception for all other error conditions
|
||||
*/
|
||||
protected abstract void attempt() throws TemporaryException, Exception;
|
||||
|
||||
public void execute(long interval, long timeout) throws RetryTimeoutException, Exception {
|
||||
execute(0L, interval, timeout);
|
||||
}
|
||||
|
||||
public void execute(long delay, long interval, long timeout) throws RetryTimeoutException, Exception {
|
||||
long start = System.currentTimeMillis();
|
||||
if (delay > 0L) {
|
||||
sleep(delay);
|
||||
}
|
||||
while (true) {
|
||||
try {
|
||||
attempt();
|
||||
return;
|
||||
} catch (TemporaryException temporaryException) {
|
||||
if (System.currentTimeMillis() - start < timeout) {
|
||||
sleep(interval);
|
||||
// continue
|
||||
} else {
|
||||
throw new RetryTimeoutException(temporaryException.getCause());
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private void sleep(long millis) {
|
||||
try {
|
||||
Thread.sleep(millis);
|
||||
} catch (InterruptedException interruptedException) {
|
||||
// continue
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
@@ -0,0 +1,59 @@
|
||||
//
|
||||
// JODConverter - Java OpenDocument Converter
|
||||
// Copyright 2004-2012 Mirko Nasato and contributors
|
||||
//
|
||||
// JODConverter is Open Source software, you can redistribute it and/or
|
||||
// modify it under either (at your option) of the following licenses
|
||||
//
|
||||
// 1. The GNU Lesser General Public License v3 (or later)
|
||||
// -> http://www.gnu.org/licenses/lgpl-3.0.txt
|
||||
// 2. The Apache License, Version 2.0
|
||||
// -> http://www.apache.org/licenses/LICENSE-2.0.txt
|
||||
//
|
||||
package org.artofsolving.jodconverter.office;
|
||||
|
||||
import java.util.concurrent.LinkedBlockingQueue;
|
||||
import java.util.concurrent.ThreadFactory;
|
||||
import java.util.concurrent.ThreadPoolExecutor;
|
||||
import java.util.concurrent.TimeUnit;
|
||||
import java.util.concurrent.locks.Condition;
|
||||
import java.util.concurrent.locks.ReentrantLock;
|
||||
|
||||
class SuspendableThreadPoolExecutor extends ThreadPoolExecutor {
|
||||
|
||||
private boolean available = false;
|
||||
private ReentrantLock suspendLock = new ReentrantLock();
|
||||
private Condition availableCondition = suspendLock.newCondition();
|
||||
|
||||
public SuspendableThreadPoolExecutor(ThreadFactory threadFactory) {
|
||||
super(1, 1, 0L, TimeUnit.MILLISECONDS, new LinkedBlockingQueue<Runnable>(), threadFactory);
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void beforeExecute(Thread thread, Runnable task) {
|
||||
super.beforeExecute(thread, task);
|
||||
suspendLock.lock();
|
||||
try {
|
||||
while (!available) {
|
||||
availableCondition.await();
|
||||
}
|
||||
} catch (InterruptedException interruptedException) {
|
||||
thread.interrupt();
|
||||
} finally {
|
||||
suspendLock.unlock();
|
||||
}
|
||||
}
|
||||
|
||||
public void setAvailable(boolean available) {
|
||||
suspendLock.lock();
|
||||
try {
|
||||
this.available = available;
|
||||
if (available) {
|
||||
availableCondition.signalAll();
|
||||
}
|
||||
} finally {
|
||||
suspendLock.unlock();
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
@@ -0,0 +1,32 @@
|
||||
//
|
||||
// JODConverter - Java OpenDocument Converter
|
||||
// Copyright 2004-2012 Mirko Nasato and contributors
|
||||
//
|
||||
// JODConverter is Open Source software, you can redistribute it and/or
|
||||
// modify it under either (at your option) of the following licenses
|
||||
//
|
||||
// 1. The GNU Lesser General Public License v3 (or later)
|
||||
// -> http://www.gnu.org/licenses/lgpl-3.0.txt
|
||||
// 2. The Apache License, Version 2.0
|
||||
// -> http://www.apache.org/licenses/LICENSE-2.0.txt
|
||||
//
|
||||
package org.artofsolving.jodconverter.office;
|
||||
|
||||
import java.math.BigDecimal;
|
||||
|
||||
/**
|
||||
* Represents an error condition that can be temporary, i.e. that could go
|
||||
* away by simply retrying the same operation after an interval.
|
||||
*/
|
||||
class TemporaryException extends Exception {
|
||||
|
||||
private static final long serialVersionUID = 7237380113208327295L;
|
||||
|
||||
public TemporaryException(Throwable cause) {
|
||||
super(cause);
|
||||
}
|
||||
|
||||
public static void main(String[] args) {
|
||||
System.out.println(new BigDecimal("7412611111110.99"));
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,62 @@
|
||||
//
|
||||
// JODConverter - Java OpenDocument Converter
|
||||
// Copyright 2004-2012 Mirko Nasato and contributors
|
||||
//
|
||||
// JODConverter is Open Source software, you can redistribute it and/or
|
||||
// modify it under either (at your option) of the following licenses
|
||||
//
|
||||
// 1. The GNU Lesser General Public License v3 (or later)
|
||||
// -> http://www.gnu.org/licenses/lgpl-3.0.txt
|
||||
// 2. The Apache License, Version 2.0
|
||||
// -> http://www.apache.org/licenses/LICENSE-2.0.txt
|
||||
//
|
||||
package org.artofsolving.jodconverter.office;
|
||||
|
||||
/**
|
||||
* Encapsulates the UNO Interprocess Connection type and parameters.
|
||||
* <p>
|
||||
* OpenOffice.org supports two connection types: TCP sockets and named pipes.
|
||||
* Named pipes are marginally faster and do not take up a TCP port, but they
|
||||
* require native libraries, which means setting <em>java.library.path</em>
|
||||
* when starting Java. E.g. on Linux
|
||||
* <pre>
|
||||
* java -Djava.library.path=/opt/openoffice.org/ure/lib ...
|
||||
* </pre>
|
||||
* <p>
|
||||
* See <a href="http://wiki.services.openoffice.org/wiki/Documentation/DevGuide/ProUNO/Opening_a_Connection">Opening a Connection</a>
|
||||
* in the OpenOffice.org Developer's Guide for more details.
|
||||
*/
|
||||
class UnoUrl {
|
||||
|
||||
private final String acceptString;
|
||||
private final String connectString;
|
||||
|
||||
private UnoUrl(String acceptString, String connectString) {
|
||||
this.acceptString = acceptString;
|
||||
this.connectString = connectString;
|
||||
}
|
||||
|
||||
public static UnoUrl socket(int port) {
|
||||
String socketString = "socket,host=127.0.0.1,port=" + port;
|
||||
return new UnoUrl(socketString, socketString + ",tcpNoDelay=1");
|
||||
}
|
||||
|
||||
public static UnoUrl pipe(String pipeName) {
|
||||
String pipeString = "pipe,name=" + pipeName;
|
||||
return new UnoUrl(pipeString, pipeString);
|
||||
}
|
||||
|
||||
public String getAcceptString() {
|
||||
return acceptString;
|
||||
}
|
||||
|
||||
public String getConnectString() {
|
||||
return connectString;
|
||||
}
|
||||
|
||||
@Override
|
||||
public String toString() {
|
||||
return connectString;
|
||||
}
|
||||
|
||||
}
|
||||
Reference in New Issue
Block a user