From 5ac92921b49b8ba9850e652767c1535b8a6ed1c4 Mon Sep 17 00:00:00 2001 From: Ilya Chekashkin Date: Mon, 10 Feb 2020 15:47:26 +0400 Subject: [PATCH] Set user directory for openoffice processes (#125) * Set user directory for the openOffice processes (-env:UserInstallation parameter) * YARG-34 Log information from LibreOffice output using slf4j-api --- .../impl/doc/connector/OOServer.java | 96 ++++++++++++++----- .../impl/doc/connector/OfficeConnection.java | 3 +- 2 files changed, 76 insertions(+), 23 deletions(-) diff --git a/core/modules/core/src/com/haulmont/yarg/formatters/impl/doc/connector/OOServer.java b/core/modules/core/src/com/haulmont/yarg/formatters/impl/doc/connector/OOServer.java index 3bf0f29a..55a952fe 100644 --- a/core/modules/core/src/com/haulmont/yarg/formatters/impl/doc/connector/OOServer.java +++ b/core/modules/core/src/com/haulmont/yarg/formatters/impl/doc/connector/OOServer.java @@ -16,8 +16,12 @@ package com.haulmont.yarg.formatters.impl.doc.connector; +import com.google.common.collect.Lists; import com.sun.star.comp.helper.BootstrapException; import com.sun.star.lib.util.NativeLibraryLoader; +import org.apache.commons.collections.CollectionUtils; +import org.apache.commons.io.FileUtils; +import org.apache.commons.lang.StringUtils; import org.slf4j.Logger; import org.slf4j.LoggerFactory; @@ -38,7 +42,7 @@ * http://udk.openoffice.org/source/browse/udk/javaunohelper/com/sun/star/comp/helper/Bootstrap.java?view=markup */ public class OOServer { - protected static final Logger log = LoggerFactory.getLogger(JavaProcessManager.class); + protected static final Logger log = LoggerFactory.getLogger(OOServer.class); /** * The OOo server process. */ @@ -57,10 +61,12 @@ public class OOServer { /** * The options for starting the OOo server. */ - private List oooOptions; + private List oooOptions; private ProcessManager processManager; + protected OfficeIntegration officeIntegration; + /** * Constructs an OOo server which uses the folder of the OOo installation * containing the soffice executable and a given list of options to start @@ -69,13 +75,15 @@ public class OOServer { * @param oooExecFolder The folder of the OOo installation containing the soffice executable * @param oooOptions The list of options */ - public OOServer(String oooExecFolder, List oooOptions, String host, int port, ProcessManager processManager) { + public OOServer(String oooExecFolder, List oooOptions, String host, int port, + ProcessManager processManager, OfficeIntegration officeIntegration) { this.oooProcess = null; this.oooExecFolder = oooExecFolder; this.host = host; this.port = port; this.oooOptions = oooOptions; this.processManager = processManager; + this.officeIntegration = officeIntegration; } /** @@ -91,7 +99,7 @@ public OOServer(String oooExecFolder, List oooOptions, String host, int port, Pr * the pipe name "oooPipe" the accept option looks like this: * - accept option : -accept=pipe,name=oooPipe;urp; */ - public void start() throws BootstrapException, IOException { + public synchronized void start() throws BootstrapException, IOException { // find office executable relative to this class's class loader String sOffice = System.getProperty("os.name").startsWith("Windows") ? "soffice.exe" : "soffice"; //accept option !Note! we are using old version notation (- instead of --) to support old version of office @@ -103,23 +111,30 @@ public void start() throws BootstrapException, IOException { if (fOffice == null) throw new BootstrapException("no office executable found!"); - // create call with arguments - int arguments = (oooOptions != null) ? oooOptions.size() + 1 : 1; - arguments++; - String[] oooCommand = new String[arguments]; - oooCommand[0] = fOffice.getPath(); + List argumentsList = Lists.newLinkedList(); + argumentsList.add(fOffice.getPath()); - for (int i = 0; i < oooOptions.size(); i++) { - oooCommand[i + 1] = (String) oooOptions.get(i); - } + if (CollectionUtils.isNotEmpty(oooOptions)) + argumentsList.addAll(oooOptions); - oooCommand[arguments - 1] = oooAcceptOption; + String instanceProfilePath = getInstanceProfilePath(); + if (StringUtils.isNotBlank(instanceProfilePath)) { + prepareInstanceProfileDir(); + argumentsList.add("-env:UserInstallation=" + toUrl(new File(instanceProfilePath))); + } + argumentsList.add(oooAcceptOption); // start office process - oooProcess = Runtime.getRuntime().exec(oooCommand); + oooProcess = Runtime.getRuntime().exec(argumentsList.toArray(new String[0])); + + pipe(oooProcess.getInputStream(), "OUT"); + pipe(oooProcess.getErrorStream(), "ERR"); + } - pipe(oooProcess.getInputStream(), System.out, "CO> "); - pipe(oooProcess.getErrorStream(), System.err, "CE> "); + public 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; } /** @@ -128,17 +143,18 @@ public void start() throws BootstrapException, IOException { * nothing. * If there has been a previous start, kill destroys the process. */ - public void kill() { + public synchronized void kill() { if (oooProcess != null) { - log.info("OOServer is killing office instance with port " + port); + log.info("OOServer is killing office instance with port {}", port); List pids = processManager.findPid(host, port); processManager.kill(oooProcess, pids); oooProcess = null; + deleteProfileDir(); } } - private static void pipe(final InputStream in, final PrintStream out, final String prefix) { - new Thread("Pipe: " + prefix) { + protected void pipe(final InputStream in, final String prefix) { + new Thread(String.format("OOServer: %s", prefix)) { @Override public void run() { BufferedReader r = new BufferedReader(new InputStreamReader(in)); @@ -148,10 +164,10 @@ public void run() { if (s == null) { break; } - out.println(prefix + s); + log.debug("{}: {}", prefix, s); } } catch (IOException e) { - e.printStackTrace(System.err); + log.debug("OOServer error:", e); } } }.start(); @@ -177,4 +193,40 @@ public static List getDefaultOOoOptions() { return options; } + + protected void prepareInstanceProfileDir() { + String instanceProfilePath = getInstanceProfilePath(); + if (StringUtils.isNotBlank(instanceProfilePath)) { + File instanceProfileDir = new File(instanceProfilePath); + if (instanceProfileDir.exists()) { + log.debug(String.format("OpenOffice server profile dir '%s' already exists; deleting", instanceProfileDir)); + deleteProfileDir(); + } + } + } + + protected void deleteProfileDir() { + String instanceProfilePath = getInstanceProfilePath(); + if (StringUtils.isNotBlank(instanceProfilePath)) { + File instanceProfileDir = new File(instanceProfilePath); + try { + FileUtils.deleteDirectory(instanceProfileDir); + } catch (IOException ioException) { + File oldProfileDir = new File(instanceProfileDir.getParentFile(), + instanceProfileDir.getName() + ".old." + System.currentTimeMillis()); + if (instanceProfileDir.renameTo(oldProfileDir)) { + log.warn("could not delete profileDir: " + ioException.getMessage() + "; renamed it to " + oldProfileDir); + } else { + log.error("could not delete profileDir: " + ioException.getMessage()); + } + } + } + } + + protected String getInstanceProfilePath() { + if (StringUtils.isBlank(officeIntegration.getTemporaryDirPath())) + return ""; + + return officeIntegration.getTemporaryDirPath() + String.format(".ooserver_%s_%s", host, port); + } } \ No newline at end of file diff --git a/core/modules/core/src/com/haulmont/yarg/formatters/impl/doc/connector/OfficeConnection.java b/core/modules/core/src/com/haulmont/yarg/formatters/impl/doc/connector/OfficeConnection.java index 70645646..c7703cd5 100644 --- a/core/modules/core/src/com/haulmont/yarg/formatters/impl/doc/connector/OfficeConnection.java +++ b/core/modules/core/src/com/haulmont/yarg/formatters/impl/doc/connector/OfficeConnection.java @@ -45,7 +45,8 @@ public class OfficeConnection { public OfficeConnection(String openOfficePath, Integer port, ProcessManager processManager, OfficeIntegration officeIntegration) { this.port = port; this.officeIntegration = officeIntegration; - this.oooServer = new OOServer(openOfficePath, OOServer.getDefaultOOoOptions(), "localhost", port, processManager); + this.oooServer = new OOServer(openOfficePath, OOServer.getDefaultOOoOptions(), + "localhost", port, processManager, officeIntegration); this.bsc = new BootstrapSocketConnector(oooServer); this.openOfficePath = openOfficePath; }