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 package org.openoffice.test; 23 24 import java.io.File; 25 import java.io.IOException; 26 import java.net.MalformedURLException; 27 import java.net.URL; 28 import java.text.SimpleDateFormat; 29 import java.util.ArrayList; 30 import java.util.Date; 31 import java.util.HashMap; 32 import java.util.Map.Entry; 33 import java.util.Properties; 34 import java.util.Set; 35 import java.util.UUID; 36 import java.util.logging.Logger; 37 38 import org.openoffice.test.common.FileUtil; 39 import org.openoffice.test.common.SystemUtil; 40 41 /** 42 * It represents one OpenOffice instance. 43 * By default, the instance will be started with automation and socket UNO connection enabled. 44 * 45 */ 46 public class OpenOffice { 47 48 private static Logger LOG = Logger.getLogger(OpenOffice.class.getName()); 49 50 private static final String[] DEFAULT_HOME = new String[] { 51 "C:/Program Files/OpenOffice.org 3", 52 "C:/Program Files (x86)/OpenOffice.org 3", 53 "/Applications/OpenOffice.org.app/Contents", 54 "/opt/openoffice.org3", 55 }; 56 57 private static final String USERHOME = System.getProperty("user.home"); 58 private static final String BIN = SystemUtil.isWindows() ? "program/soffice.exe" : SystemUtil.isMac() ? "MacOS/soffice": "program/soffice"; 59 private static final String SYSUSERCONFIG = SystemUtil.isWindows()? System.getenv("APPDATA") : SystemUtil.isMac() ? USERHOME + "/Library/Application Support" : USERHOME; 60 public static final String DEFAULT_UNO_URL = "socket,host=127.0.0.1,port=2002;urp"; 61 public static final int DEFAULT_AUTOMATION_PORT = 12479; 62 63 private static OpenOffice defaultInstance = null; 64 65 private File userInstallation = null; 66 67 private File defaultUserInstallation = null; 68 69 private File home = null; 70 71 private File bin = null; 72 73 private String binPath = null; 74 75 private ArrayList<String> args = new ArrayList<String>(); 76 77 private ArrayList<String> registryModifications = new ArrayList<String>(); 78 79 private int automationPort = 0; 80 81 private Process process = null; 82 83 private String unoUrl = null; 84 85 private Properties versionProps = null; 86 87 private String id = UUID.randomUUID().toString().replace("-", ""); 88 89 private String processPattern = SystemUtil.isMac() ? ".*soffice .*" + id + ".*" : ".*soffice\\.bin.*" + id + ".*|.*soffice\\.exe.*" + id + ".*-env.*"; 90 OpenOffice()91 public OpenOffice() { 92 this(null); 93 } 94 95 /** 96 * Construct Process with the home path of OpenOffice. 97 * 98 * @param appHome 99 */ OpenOffice(String appHome)100 public OpenOffice(String appHome) { 101 if (appHome == null) 102 appHome = System.getProperty("openoffice.home"); 103 if (appHome == null) 104 appHome = System.getenv("OPENOFFICE_HOME"); 105 if (appHome == null) { 106 // Search in the classpath 107 try { 108 URL url = getClass().getClassLoader().getResource(BIN); 109 File file = new File(url.toURI()); 110 if (file.exists()) 111 appHome = file.getParentFile().getParentFile().getAbsolutePath(); 112 } catch (Exception e) { 113 // ignore 114 } 115 } 116 117 if (appHome == null) { 118 for (int i = 0; i < DEFAULT_HOME.length; i++) 119 if (new File(DEFAULT_HOME[i]).exists()) 120 appHome = DEFAULT_HOME[i]; 121 } 122 123 home = new File(appHome); 124 bin = new File(appHome, BIN); 125 try { 126 binPath = bin.getCanonicalPath(); 127 } catch (IOException e1) { 128 } 129 File binParent = bin.getParentFile(); 130 File bootstrapFile = new File(binParent, "bootstraprc"); 131 if (!bootstrapFile.exists()) 132 bootstrapFile = new File(binParent, "bootstrap.ini"); 133 if (!bootstrapFile.exists()) 134 throw new Error("OpenOffice can not be found or it's broken. Testing can not be performed. " + 135 "Use system property openoffice.home to specify the correct location of OpenOffice."); 136 137 Properties props = FileUtil.loadProperties(bootstrapFile); 138 String defaultUserInstallationPath = props.getProperty("UserInstallation").replace("$ORIGIN", binParent.getAbsolutePath()).replace("$SYSUSERCONFIG", SYSUSERCONFIG); 139 defaultUserInstallation = new File(defaultUserInstallationPath); 140 141 File versionFile = new File(binParent, "versionrc"); 142 if (!versionFile.exists()) 143 versionFile = new File(binParent, "version.ini"); 144 versionProps = FileUtil.loadProperties(versionFile); 145 Set<Entry<Object, Object>> entries = versionProps.entrySet(); 146 for (Entry<Object, Object> e : entries) { 147 System.setProperty("info.app." + e.getKey(), (String)e.getValue()); 148 } 149 // 150 SimpleDateFormat dateFormat = new SimpleDateFormat("yyyy-MM-dd"); 151 System.setProperty("info.app.date", dateFormat.format(new Date(versionFile.lastModified()))); 152 addArgs("-" + id); 153 } 154 getDefault()155 public static OpenOffice getDefault() { 156 if (defaultInstance == null) { 157 defaultInstance = new OpenOffice(); 158 defaultInstance.setAutomationPort(DEFAULT_AUTOMATION_PORT); 159 defaultInstance.setUnoUrl(DEFAULT_UNO_URL); 160 defaultInstance.addArgs("-nofirststartwizard", "-norestore", "-quickstart=no"); 161 defaultInstance.addRegistryModifications("<item oor:path=\"/org.openoffice.Office.Common/Misc\"><prop oor:name=\"UseSystemFileDialog\" oor:op=\"fuse\"><value>false</value></prop></item>", 162 "<item oor:path=\"/org.openoffice.Office.Common/Security/Scripting\"><prop oor:name=\"MacroSecurityLevel\" oor:op=\"fuse\"><value>0</value></prop></item>"); 163 } 164 165 return defaultInstance; 166 } 167 restoreDefault()168 public static void restoreDefault() { 169 if (defaultInstance != null) { 170 171 } 172 } 173 getVersionProps()174 public Properties getVersionProps() { 175 return versionProps; 176 } 177 178 /** 179 * Set UserInstallation directory. When openoffice is launched, the argument 180 * "-env:UserInstallation" will be enabled. 181 * 182 * @param dir 183 * user installation directory. If null is given, the default 184 * will be used. 185 */ setUserInstallation(File dir)186 public void setUserInstallation(File dir) { 187 userInstallation = dir; 188 } 189 190 /** 191 * Get UserInstallation directory 192 * 193 * @return 194 */ getUserInstallation()195 public File getUserInstallation() { 196 return userInstallation == null ? defaultUserInstallation : userInstallation; 197 } 198 199 /** 200 * Get default UserInstallation directory 201 * 202 * @return 203 */ getDefaultUserInstallation()204 public File getDefaultUserInstallation() { 205 return defaultUserInstallation; 206 } 207 208 /** 209 * Clean the user installation 210 */ cleanUserInstallation()211 public void cleanUserInstallation() { 212 FileUtil.deleteFile(getUserInstallation()); 213 } 214 215 /** 216 * Get installation directory of OpenOffice. 217 * 218 * @return 219 */ getHome()220 public File getHome() { 221 return home; 222 } 223 224 /** 225 * Set other command line arguments 226 * 227 * @param args 228 */ addArgs(String... arguments)229 public void addArgs(String... arguments) { 230 for (String a : arguments) 231 args.add(a); 232 } 233 addRegistryModifications(String... items)234 public void addRegistryModifications(String... items) { 235 for (String i : items) 236 registryModifications.add(i); 237 } 238 getAutomationPort()239 public int getAutomationPort() { 240 return automationPort; 241 } 242 243 /** 244 * Set automation server listening port 245 * @param automationPort If 0, automation server will be disabled. 246 */ setAutomationPort(int automationPort)247 public void setAutomationPort(int automationPort) { 248 this.automationPort = automationPort; 249 } 250 getUnoUrl()251 public String getUnoUrl() { 252 return unoUrl; 253 } 254 255 /** 256 * Set UNO connection listening url 257 * @param unoUrl If null, UNO connection will be disabled. 258 */ setUnoUrl(String unoUrl)259 public void setUnoUrl(String unoUrl) { 260 this.unoUrl = unoUrl; 261 } 262 263 /** 264 * destroy OpenOffice 265 */ kill()266 public void kill() { 267 SystemUtil.killProcess(".*soffice.*" + id + ".*"); 268 SystemUtil.sleep(1); 269 process = null; 270 } 271 272 /** 273 * Kill all openoffice instances 274 */ killAll()275 public static void killAll() { 276 SystemUtil.killProcess(".*soffice.*"); 277 SystemUtil.sleep(1); 278 } 279 isRunning()280 public boolean isRunning() { 281 if (process == null) 282 return false; 283 284 try { 285 process.exitValue(); 286 } catch (Exception e1) { 287 return true; 288 } 289 290 return false; 291 } 292 293 /** 294 * Start OpenOffice 295 * 296 * @return return true when the process is created. 297 */ 298 @SuppressWarnings("all") start()299 public boolean start() { 300 if (isRunning()) 301 return false; 302 303 ArrayList<String> cmds = new ArrayList<String>(); 304 cmds.add(binPath); 305 if (automationPort > 0) { 306 cmds.add("-automationport=" + automationPort); 307 cmds.add("-enableautomation"); 308 } 309 310 if (unoUrl != null) 311 cmds.add("-accept=" + unoUrl); 312 313 if (userInstallation != null) { 314 try { 315 String url = userInstallation.toURL().toString(); 316 url = url.replace("file:/", "file:///"); 317 cmds.add("-env:UserInstallation=" + url); 318 } catch (MalformedURLException e) { 319 // ignore never to occur 320 } 321 } 322 323 if (args != null) 324 cmds.addAll(args); 325 326 if (registryModifications.size() > 0) { 327 File registry = new File(getUserInstallation(), "user/registrymodifications.xcu"); 328 String content = FileUtil.readFileAsString(registry); 329 String newContent = ""; 330 for (String item : registryModifications) { 331 if (!content.contains(item)) { 332 newContent += item; 333 } 334 } 335 content.replace("</oor:items>", ""); 336 if (content.length() == 0) 337 content += "<?xml version=\"1.0\" encoding=\"UTF-8\"?><oor:items xmlns:oor=\"http://openoffice.org/2001/registry\" xmlns:xs=\"http://www.w3.org/2001/XMLSchema\" xmlns:xsi=\"http://www.w3.org/2001/XMLSchema-instance\">"; 338 content += newContent + "</oor:items>"; 339 FileUtil.writeStringToFile(registry.getAbsolutePath(), content); 340 } 341 342 process = SystemUtil.backgroundExec(cmds.toArray(new String[]{}), null, null, null, null); 343 344 String cmdLine=""; 345 for (String s : cmds) 346 cmdLine += "\""+ s + "\" "; 347 348 LOG.info(cmdLine); 349 if (process == null) 350 throw new RuntimeException("OpenOffice can't be started!"); 351 return true; 352 } 353 getPerfData()354 public HashMap<String, Object> getPerfData() { 355 HashMap<String, Object> proccessInfo = SystemUtil.findProcess(processPattern); 356 String pid = (String) proccessInfo.get("pid"); 357 if (pid == null) 358 throw new RuntimeException("Can not find performance data"); 359 return SystemUtil.getProcessPerfData(pid); 360 } 361 } 362