Update git submodules
[LibreOffice.git] / unotest / source / java / org / openoffice / test / OfficeConnection.java
blob0801da6e03bdf6f9a73555523159f4d7813ddc48
1 /*
2 * This file is part of the LibreOffice project.
4 * This Source Code Form is subject to the terms of the Mozilla Public
5 * License, v. 2.0. If a copy of the MPL was not distributed with this
6 * file, You can obtain one at http://mozilla.org/MPL/2.0/.
8 * This file incorporates work covered by the following license notice:
10 * Licensed to the Apache Software Foundation (ASF) under one or more
11 * contributor license agreements. See the NOTICE file distributed
12 * with this work for additional information regarding copyright
13 * ownership. The ASF licenses this file to you under the Apache
14 * License, Version 2.0 (the "License"); you may not use this file
15 * except in compliance with the License. You may obtain a copy of
16 * the License at http://www.apache.org/licenses/LICENSE-2.0 .
19 package org.openoffice.test;
21 import com.sun.star.bridge.UnoUrlResolver;
22 import com.sun.star.bridge.XUnoUrlResolver;
23 import com.sun.star.comp.helper.Bootstrap;
24 import com.sun.star.connection.NoConnectException;
25 import com.sun.star.frame.XDesktop;
26 import com.sun.star.lang.DisposedException;
27 import com.sun.star.lang.XMultiComponentFactory;
28 import com.sun.star.uno.UnoRuntime;
29 import com.sun.star.uno.XComponentContext;
30 import java.io.File;
31 import java.io.IOException;
32 import java.io.InputStream;
33 import java.io.PrintStream;
34 import java.util.Map;
35 import java.util.UUID;
36 import static org.junit.Assert.*;
38 /** Start up and shut down an OOo instance.
40 Details about the OOo instance are tunneled in via
41 org.openoffice.test.arg... system properties.
45 public final class OfficeConnection {
46 /** Start up an OOo instance.
48 public void setUp() throws Exception {
49 String sofficeArg = Argument.get("soffice");
50 if (sofficeArg.startsWith("path:")) {
51 description = "pipe,name=oootest" + UUID.randomUUID();
52 ProcessBuilder pb = new ProcessBuilder(
53 sofficeArg.substring("path:".length()), "--quickstart=no",
54 "--norestore", "--nologo", "--headless",
55 "--accept=" + description + ";urp",
56 "-env:UserInstallation=" + Argument.get("user"),
57 "-env:UNO_JAVA_JFW_ENV_JREHOME=true");
58 String workdirArg = Argument.get("workdir");
59 if (workdirArg != null) {
60 pb.directory(new File(workdirArg));
62 String envArg = Argument.get("env");
63 if (envArg != null) {
64 Map<String, String> env = pb.environment();
65 int i = envArg.indexOf('=');
66 if (i == -1) {
67 env.remove(envArg);
68 } else {
69 env.put(envArg.substring(0, i), envArg.substring(i + 1));
72 process = pb.start();
73 outForward = new Forward(process.getInputStream(), System.out);
74 outForward.start();
75 errForward = new Forward(process.getErrorStream(), System.err);
76 errForward.start();
77 } else if (sofficeArg.startsWith("connect:")) {
78 description = sofficeArg.substring("connect:".length());
79 } else {
80 fail(
81 "\"soffice\" argument \"" + sofficeArg +
82 " starts with neither \"path:\" nor \"connect:\"");
84 XUnoUrlResolver resolver = UnoUrlResolver.create(
85 Bootstrap.createInitialComponentContext(null));
86 for (;;) {
87 try {
88 context = UnoRuntime.queryInterface(
89 XComponentContext.class,
90 resolver.resolve(
91 "uno:" + description +
92 ";urp;StarOffice.ComponentContext"));
93 break;
94 } catch (NoConnectException e) {}
95 if (process != null) {
96 assertNull(waitForProcess(process, 1000)); // 1 sec
101 /** Shut down the OOo instance.
103 public void tearDown()
104 throws InterruptedException, com.sun.star.uno.Exception
106 boolean cleanTermination = false;
107 int code = 0;
108 try {
109 if (process != null) {
110 if (context != null) {
111 XDesktop desktop = null;
112 try {
113 XMultiComponentFactory factory =
114 context.getServiceManager();
115 assertNotNull(factory);
116 desktop = UnoRuntime.queryInterface(XDesktop.class,
117 factory.createInstanceWithContext(
118 "com.sun.star.frame.Desktop", context));
119 } catch (DisposedException e) {
120 // it can happen that the Java bridge was disposed
121 // already, we want to ensure soffice.bin is killed
122 process.destroy();
124 context = null;
125 if (desktop != null) {
126 try {
127 boolean desktopTerminated = desktop.terminate();
128 if (!desktopTerminated) {
129 // in case terminate() fails we would wait
130 // forever for the process to die, so kill it
131 process.destroy();
133 assertTrue(desktopTerminated);
134 } catch (DisposedException e) {}
135 // it appears that DisposedExceptions can already happen
136 // while receiving the response of the terminate call
138 desktop = null;
139 } else {
140 process.destroy();
143 if (process != null) {
144 code = process.waitFor();
146 boolean outTerminated = outForward == null
147 || outForward.terminated();
148 boolean errTerminated = errForward == null
149 || errForward.terminated();
150 assertEquals(0, code);
151 cleanTermination = true;
152 assertTrue(outTerminated);
153 assertTrue(errTerminated);
154 } finally {
155 if (!cleanTermination) {
156 try {
157 String sofficeArg = Argument.get("soffice");
158 String workdir = Argument.get("workdir");
159 String postprocesscommand = Argument.get(
160 "postprocesscommand");
161 if (sofficeArg.startsWith("path:") && workdir != null
162 && postprocesscommand != null)
164 ProcessBuilder pb = new ProcessBuilder(
165 postprocesscommand,
166 sofficeArg.substring("path:".length()) + ".bin",
167 workdir, String.valueOf(code));
168 Process postprocess = pb.start();
169 Forward ppoutForward = new Forward(
170 postprocess.getInputStream(), System.out);
171 ppoutForward.start();
172 Forward pperrForward = new Forward(
173 postprocess.getErrorStream(), System.err);
174 pperrForward.start();
175 code = postprocess.waitFor();
176 if (code != 0) {
177 throw new PostprocessFailedException(code);
181 catch (IOException e) {
182 throw new PostprocessFailedException(e);
188 /** Obtain the component context of the running OOo instance.
190 public XComponentContext getComponentContext() {
191 return context;
194 //TODO: get rid of this hack for legacy qa/unoapi tests
195 public String getDescription() {
196 return description;
199 private static Integer waitForProcess(Process process, final int millis)
200 throws InterruptedException
202 final Thread t1 = Thread.currentThread();
203 Thread t2 = new Thread("waitForProcess") {
204 @Override
205 public void run() {
206 util.utils.pause(millis);
207 t1.interrupt();
210 boolean old = Thread.interrupted();
211 // clear interrupted status, get old status
212 t2.start();
213 int n = 0;
214 boolean done = false;
215 try {
216 n = process.waitFor();
217 done = true;
218 } catch (InterruptedException e) {}
219 t2.interrupt();
220 try {
221 t2.join();
222 } catch (InterruptedException e) {
223 t2.join();
225 Thread.interrupted(); // clear interrupted status
226 if (old) {
227 t1.interrupt(); // reset old status
229 return done ? Integer.valueOf(n) : null;
232 private static final class Forward extends Thread {
233 public Forward(InputStream in, PrintStream out) {
234 super("process output forwarder");
235 this.in = in;
236 this.out = out;
239 @Override
240 public void run() {
241 for (;;) {
242 byte[] buf = new byte[1024];
243 int n;
244 try {
245 n = in.read(buf);
246 } catch (IOException e) {
247 throw new RuntimeException("wrapping", e);
249 if (n == -1) {
250 break;
252 out.write(buf, 0, n);
254 done = true;
257 public boolean terminated() throws InterruptedException {
258 join();
259 return done;
262 private final InputStream in;
263 private final PrintStream out;
264 private boolean done = false;
267 private static final class PostprocessFailedException
268 extends RuntimeException
270 PostprocessFailedException(int exitCode) {
271 super("postprocessing failed with exit code " + exitCode);
274 PostprocessFailedException(IOException cause) {
275 super("postprocessing failed with IOException " + cause, cause);
279 private String description;
280 private Process process = null;
281 private Forward outForward = null;
282 private Forward errForward = null;
283 private XComponentContext context = null;
285 // vim:set et sw=4 sts=4: