public void executeTask() throws Exception { final PooledOfficeManagerSettings settings = new PooledOfficeManagerSettings(CONNECTION_MODE); settings.setProcessManager(OfficeUtils.findBestProcessManager()); final PooledOfficeManager officeManager = new PooledOfficeManager(settings); ManagedOfficeProcess managedOfficeProcess = (ManagedOfficeProcess) FieldUtils.readDeclaredField(officeManager, "managedOfficeProcess", true); OfficeProcess process = (OfficeProcess) FieldUtils.readDeclaredField(managedOfficeProcess, "process", true); OfficeConnection connection = (OfficeConnection) FieldUtils.readDeclaredField(managedOfficeProcess, "connection", true); try { officeManager.start(); assertTrue(process.isRunning()); assertTrue(connection.isConnected()); MockOfficeTask task = new MockOfficeTask(); officeManager.execute(task); assertTrue(task.isCompleted()); } finally { officeManager.stop(); assertFalse(connection.isConnected()); assertFalse(process.isRunning()); assertEquals(process.getExitCode(0, 0), 0); } }
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 : "")); }
public void restartAfterCrash() throws Exception { final PooledOfficeManagerSettings settings = new PooledOfficeManagerSettings(CONNECTION_MODE); settings.setProcessManager(OfficeUtils.findBestProcessManager()); final PooledOfficeManager officeManager = new PooledOfficeManager(settings); ManagedOfficeProcess managedOfficeProcess = (ManagedOfficeProcess) FieldUtils.readDeclaredField(officeManager, "managedOfficeProcess", true); OfficeProcess process = (OfficeProcess) FieldUtils.readDeclaredField(managedOfficeProcess, "process", true); OfficeConnection connection = (OfficeConnection) FieldUtils.readDeclaredField(managedOfficeProcess, "connection", true); assertNotNull(connection); try { officeManager.start(); assertTrue(process.isRunning()); assertTrue(connection.isConnected()); new Thread() { public void run() { MockOfficeTask badTask = new MockOfficeTask(10 * 1000); try { officeManager.execute(badTask); fail("task should be cancelled"); // FIXME being in a separate thread the test won't actually fail } catch (OfficeException officeEx) { assertTrue(officeEx.getCause() instanceof CancellationException); } } }.start(); Thread.sleep(500); Process underlyingProcess = (Process) FieldUtils.readDeclaredField(process, "process", true); assertNotNull(underlyingProcess); logger.debug("Simulating the crash"); underlyingProcess.destroy(); // simulate crash Thread.sleep(RESTART_WAIT_TIME); assertTrue(process.isRunning()); assertTrue(connection.isConnected()); MockOfficeTask goodTask = new MockOfficeTask(); officeManager.execute(goodTask); assertTrue(goodTask.isCompleted()); } finally { officeManager.stop(); assertFalse(connection.isConnected()); assertFalse(process.isRunning()); assertEquals(process.getExitCode(0, 0), 0); } }
public void restartAfterTaskTimeout() throws Exception { final PooledOfficeManagerSettings settings = new PooledOfficeManagerSettings(CONNECTION_MODE); settings.setProcessManager(OfficeUtils.findBestProcessManager()); settings.setTaskExecutionTimeout(1500L); final PooledOfficeManager officeManager = new PooledOfficeManager(settings); ManagedOfficeProcess managedOfficeProcess = (ManagedOfficeProcess) FieldUtils.readDeclaredField(officeManager, "managedOfficeProcess", true); OfficeProcess process = (OfficeProcess) FieldUtils.readDeclaredField(managedOfficeProcess, "process", true); OfficeConnection connection = (OfficeConnection) FieldUtils.readDeclaredField(managedOfficeProcess, "connection", true); assertNotNull(connection); try { officeManager.start(); assertTrue(process.isRunning()); assertTrue(connection.isConnected()); MockOfficeTask task = new MockOfficeTask(2000); try { officeManager.execute(task); fail("task should be timed out"); } catch (OfficeException officeEx) { assertTrue(officeEx.getCause() instanceof TimeoutException); } Thread.sleep(RESTART_WAIT_TIME); assertTrue(process.isRunning()); assertTrue(connection.isConnected()); MockOfficeTask goodTask = new MockOfficeTask(); officeManager.execute(goodTask); assertTrue(goodTask.isCompleted()); } finally { officeManager.stop(); assertFalse(connection.isConnected()); assertFalse(process.isRunning()); assertEquals(process.getExitCode(0, 0), 0); } }
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(); final int numInstances = connectionProtocol == OfficeConnectionProtocol.PIPE ? pipeNames.length : portNumbers.length; final 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, manageExternalInstances); }
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 private boolean manageExternalInstances; public DefaultOfficeManagerConfiguration setOfficeHome(final String officeHome) throws NullPointerException, IllegalArgumentException { checkArgumentNotNull("officeHome", officeHome); return setOfficeHome(new File(officeHome)); } public DefaultOfficeManagerConfiguration setOfficeHome(final 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( final OfficeConnectionProtocol connectionProtocol) throws NullPointerException { checkArgumentNotNull("connectionProtocol", connectionProtocol); this.connectionProtocol = connectionProtocol; return this; } public DefaultOfficeManagerConfiguration setPortNumber(final int portNumber) { portNumbers = new int[] {portNumber}; return this; } public DefaultOfficeManagerConfiguration setPortNumbers(final 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(final String pipeName) throws NullPointerException { checkArgumentNotNull("pipeName", pipeName); pipeNames = new String[] {pipeName}; return this; } public DefaultOfficeManagerConfiguration setPipeNames(final 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(final String... runAsArgs) { this.runAsArgs = runAsArgs; return this; } public DefaultOfficeManagerConfiguration setTemplateProfileDir(final 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(final File workDir) { checkArgumentNotNull("workDir", workDir); this.workDir = workDir; return this; } public DefaultOfficeManagerConfiguration setTaskQueueTimeout(final long taskQueueTimeout) { this.taskQueueTimeout = taskQueueTimeout; return this; } public DefaultOfficeManagerConfiguration setTaskExecutionTimeout( final long taskExecutionTimeout) { this.taskExecutionTimeout = taskExecutionTimeout; return this; } public DefaultOfficeManagerConfiguration setMaxTasksPerProcess(final 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(final 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(final long retryTimeout) { this.retryTimeout = retryTimeout; return this; } public void setManageExternalInstances(final boolean value) { manageExternalInstances = value; } 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(); final int numInstances = connectionProtocol == OfficeConnectionProtocol.PIPE ? pipeNames.length : portNumbers.length; final 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, manageExternalInstances); } private ProcessManager findBestProcessManager() { if (isSigarAvailable()) return new SigarProcessManager(); else if (PlatformUtils.isLinux()) { final 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 (final ClassNotFoundException classNotFoundException) { return false; } } private void checkArgumentNotNull(final String argName, final Object argValue) throws NullPointerException { if (argValue == null) throw new NullPointerException(argName + " must not be null"); } private void checkArgument(final String argName, final boolean condition, final String message) throws IllegalArgumentException { if (!condition) throw new IllegalArgumentException(argName + " " + message); } private boolean isValidProfileDir(final File profileDir) { return new File(profileDir, "user").isDirectory(); } }