1 /************************************************************** 2 * 3 * Licensed to the Apache Software Foundation (ASF) under one 4 * or more contributor license agreements. See the NOTICE file 5 * distributed with this work for additional information 6 * regarding copyright ownership. The ASF licenses this file 7 * to you under the Apache License, Version 2.0 (the 8 * "License"); you may not use this file except in compliance 9 * with the License. You may obtain a copy of the License at 10 * 11 * http://www.apache.org/licenses/LICENSE-2.0 12 * 13 * Unless required by applicable law or agreed to in writing, 14 * software distributed under the License is distributed on an 15 * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY 16 * KIND, either express or implied. See the License for the 17 * specific language governing permissions and limitations 18 * under the License. 19 * 20 *************************************************************/ 21 22 23 24 package org.openoffice.test; 25 26 import com.sun.star.bridge.UnoUrlResolver; 27 import com.sun.star.bridge.XUnoUrlResolver; 28 import com.sun.star.comp.helper.Bootstrap; 29 import com.sun.star.connection.NoConnectException; 30 import com.sun.star.frame.XDesktop; 31 import com.sun.star.lang.DisposedException; 32 import com.sun.star.lang.XMultiComponentFactory; 33 import com.sun.star.uno.UnoRuntime; 34 import com.sun.star.uno.XComponentContext; 35 import java.io.IOException; 36 import java.io.InputStream; 37 import java.io.PrintStream; 38 import java.util.Map; 39 import java.util.UUID; 40 import static org.junit.Assert.*; 41 42 /** Start up and shut down an OOo instance. 43 44 Details about the OOo instance are tunneled in via 45 org.openoffice.test.arg.... system properties. 46 */ 47 public final class OfficeConnection { 48 /** Start up an OOo instance. 49 */ setUp()50 public void setUp() throws Exception { 51 String sofficeArg = Argument.get("soffice"); 52 if (sofficeArg.startsWith("path:")) { 53 description = "pipe,name=oootest" + UUID.randomUUID(); 54 ProcessBuilder pb = new ProcessBuilder( 55 sofficeArg.substring("path:".length()), "-quickstart=no", 56 "-nofirststartwizard", "-norestore", 57 "-accept=" + description + ";urp", 58 "-env:UserInstallation=" + Argument.get("user"), 59 "-env:UNO_JAVA_JFW_ENV_JREHOME=true"); 60 String envArg = Argument.get("env"); 61 if (envArg != null) { 62 Map<String, String> env = pb.environment(); 63 int i = envArg.indexOf("="); 64 if (i == -1) { 65 env.remove(envArg); 66 } else { 67 env.put(envArg.substring(0, i), envArg.substring(i + 1)); 68 } 69 } 70 process = pb.start(); 71 outForward = new Forward(process.getInputStream(), System.out); 72 outForward.start(); 73 errForward = new Forward(process.getErrorStream(), System.err); 74 errForward.start(); 75 } else if (sofficeArg.startsWith("connect:")) { 76 description = sofficeArg.substring("connect:".length()); 77 } else { 78 fail( 79 "\"soffice\" argument \"" + sofficeArg + 80 " starts with neither \"path:\" nor \"connect:\""); 81 } 82 XUnoUrlResolver resolver = UnoUrlResolver.create( 83 Bootstrap.createInitialComponentContext(null)); 84 for (;;) { 85 try { 86 context = UnoRuntime.queryInterface( 87 XComponentContext.class, 88 resolver.resolve( 89 "uno:" + description + 90 ";urp;StarOffice.ComponentContext")); 91 break; 92 } catch (NoConnectException e) {} 93 if (process != null) { 94 assertNull(waitForProcess(process, 1000)); // 1 sec 95 } 96 } 97 } 98 99 /** Shut down the OOo instance. 100 */ tearDown()101 public void tearDown() 102 throws InterruptedException, com.sun.star.uno.Exception 103 { 104 boolean desktopTerminated = true; 105 if (process != null) { 106 if (context != null) { 107 XMultiComponentFactory factory = context.getServiceManager(); 108 assertNotNull(factory); 109 XDesktop desktop = UnoRuntime.queryInterface( 110 XDesktop.class, 111 factory.createInstanceWithContext( 112 "com.sun.star.frame.Desktop", context)); 113 context = null; 114 try { 115 desktopTerminated = desktop.terminate(); 116 } catch (DisposedException e) {} 117 // it appears that DisposedExceptions can already happen 118 // while receiving the response of the terminate call 119 desktop = null; 120 } else { 121 process.destroy(); 122 } 123 } 124 int code = 0; 125 if (process != null) { 126 code = process.waitFor(); 127 } 128 boolean outTerminated = outForward == null || outForward.terminated(); 129 boolean errTerminated = errForward == null || errForward.terminated(); 130 assertTrue(desktopTerminated); 131 assertEquals(0, code); 132 assertTrue(outTerminated); 133 assertTrue(errTerminated); 134 } 135 136 /** Obtain the component context of the running OOo instance. 137 */ getComponentContext()138 public XComponentContext getComponentContext() { 139 return context; 140 } 141 142 //TODO: get rid of this hack for legacy qa/unoapi tests getDescription()143 public String getDescription() { 144 return description; 145 } 146 waitForProcess(Process process, final long millis)147 private static Integer waitForProcess(Process process, final long millis) 148 throws InterruptedException 149 { 150 final Thread t1 = Thread.currentThread(); 151 Thread t2 = new Thread("waitForProcess") { 152 public void run() { 153 try { 154 Thread.currentThread().sleep(millis); 155 } catch (InterruptedException e) {} 156 t1.interrupt(); 157 } 158 }; 159 boolean old = Thread.interrupted(); 160 // clear interrupted status, get old status 161 t2.start(); 162 int n = 0; 163 boolean done = false; 164 try { 165 n = process.waitFor(); 166 done = true; 167 } catch (InterruptedException e) {} 168 t2.interrupt(); 169 try { 170 t2.join(); 171 } catch (InterruptedException e) { 172 t2.join(); 173 } 174 Thread.interrupted(); // clear interrupted status 175 if (old) { 176 t1.interrupt(); // reset old status 177 } 178 return done ? new Integer(n) : null; 179 } 180 181 private static final class Forward extends Thread { Forward(InputStream in, PrintStream out)182 public Forward(InputStream in, PrintStream out) { 183 super("process output forwarder"); 184 this.in = in; 185 this.out = out; 186 } 187 run()188 public void run() { 189 for (;;) { 190 byte[] buf = new byte[1024]; 191 int n; 192 try { 193 n = in.read(buf); 194 } catch (IOException e) { 195 throw new RuntimeException("wrapping", e); 196 } 197 if (n == -1) { 198 break; 199 } 200 out.write(buf, 0, n); 201 } 202 done = true; 203 } 204 terminated()205 public boolean terminated() throws InterruptedException { 206 join(); 207 return done; 208 } 209 210 private final InputStream in; 211 private final PrintStream out; 212 private boolean done = false; 213 } 214 215 private String description; 216 private Process process = null; 217 private Forward outForward = null; 218 private Forward errForward = null; 219 private XComponentContext context = null; 220 } 221