Version 6.4.0.0.beta1, tag libreoffice-6.4.0.0.beta1
[LibreOffice.git] / qadevOOo / runner / helper / OfficeProvider.java
blob01599cd3ff150d584e1bb309b6f36c4329e26f66
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 .
18 package helper;
20 import com.sun.star.beans.XFastPropertySet;
21 import com.sun.star.bridge.XUnoUrlResolver;
22 import com.sun.star.container.XEnumeration;
23 import com.sun.star.container.XEnumerationAccess;
24 import com.sun.star.frame.XDesktop;
25 import com.sun.star.lang.XMultiComponentFactory;
26 import com.sun.star.lang.XMultiServiceFactory;
27 import com.sun.star.uno.UnoRuntime;
28 import com.sun.star.uno.XComponentContext;
29 import com.sun.star.util.XCloseable;
30 import com.sun.star.util.XStringSubstitution;
32 import java.io.File;
33 import java.io.PrintWriter;
34 import java.io.UnsupportedEncodingException;
36 import lib.TestParameters;
38 import share.DescEntry;
39 import share.LogWriter;
41 import util.DynamicClassLoader;
42 import util.PropertyName;
43 import util.utils;
45 /**
46 * This class will connect the office and start it if possible
49 public class OfficeProvider implements AppProvider
52 private boolean debug = false;
54 /**
55 * copy the user layer to a safe place, usually to $TMP/user_backup$USER
57 private void backupUserLayer(TestParameters param, XMultiServiceFactory msf)
59 try
61 final XStringSubstitution sts = createStringSubstitution(msf);
62 debug = param.getBool(PropertyName.DEBUG_IS_ACTIVE);
64 String userLayer = sts.getSubstituteVariableValue("$(user)");
65 userLayer = getDirSys(userLayer);
66 param.put("userLayer", userLayer);
68 final String copyLayer = util.utils.getUsersTempDir() + System.getProperty("file.separator") +
69 "user_backup" +
70 System.getProperty("user.name");
71 param.put("copyLayer", copyLayer);
74 dbg(" copy '" + userLayer + "' ->" + copyLayer + "'");
75 // Slow machines the copy job could spend some time. To avoid activating of OfficeWatcher it must be pinged
76 OfficeWatcherPing owp = new OfficeWatcherPing((OfficeWatcher) param.get(PropertyName.OFFICE_WATCHER));
77 owp.start();
79 deleteFilesAndDirector (new File(copyLayer));
80 FileTools.copyDirectory(new File(userLayer), new File(copyLayer), new String[]
82 "temp"
83 });
85 owp.finish();
88 catch (com.sun.star.container.NoSuchElementException e)
90 System.out.println("User Variable '$(user)' not defined.");
92 catch (com.sun.star.uno.Exception e)
94 System.out.println("Couldn't backup user layer");
95 e.printStackTrace();
97 catch (java.io.IOException e)
99 System.out.println("Couldn't backup user layer");
100 e.printStackTrace();
105 * Dispose the office.
106 * This method can only be used, if the office was connected in the first
107 * place: getManager() was called first.
108 * @return return true if desktop is terminates, else false
110 public boolean disposeManager(lib.TestParameters param)
113 XMultiServiceFactory msf = param.getMSF();
115 if (msf == null)
117 return true;
119 else
121 XDesktop desk = null;
125 desk = UnoRuntime.queryInterface(XDesktop.class, msf.createInstance("com.sun.star.frame.Desktop"));
127 catch (com.sun.star.uno.Exception ue)
129 return false;
132 msf = null;
134 if (desk != null)
136 desk.terminate();
138 return true;
140 else
142 return false;
148 * Method to get the ServiceManager of an Office
150 public Object getManager(lib.TestParameters param) throws UnsupportedEncodingException
152 String errorMessage = null;
153 boolean bAppExecutionHasWarning = false;
154 debug = param.getBool(PropertyName.DEBUG_IS_ACTIVE);
156 String additionalArgs = (String) param.get(
157 "AdditionalConnectionArguments");
159 if (additionalArgs == null)
161 additionalArgs = ";";
163 else
165 additionalArgs = "," + additionalArgs + ";";
168 final String cncstr = "uno:" + param.get("ConnectionString") + ";urp" +
169 additionalArgs + "StarOffice.ServiceManager";
171 System.out.println("Connecting the Office with " + cncstr);
173 XMultiServiceFactory msf = connectOffice(cncstr);
175 // if the office is running and the office crashes while testing it could
176 // be useful to restart the office if possible and continuing the tests.
177 // Example: the UNO-API-Tests in the projects will be executed by calling
178 // 'damke'. This connects to an existing office. If the office crashes
179 // it is useful to restart the office and continuing the tests.
180 if ((param.getBool(util.PropertyName.AUTO_RESTART)) && (msf != null))
182 makeAppExecCommand(msf, param);
185 if (msf == null)
187 String exc = "";
188 Exception exConnectFailed = null;
189 boolean isExecutable = false;
190 boolean isAppKnown = ((cncstr.indexOf("host=localhost") > 0) || (cncstr.indexOf("pipe,name=") > 0));
191 isAppKnown &= ((String) param.get("AppExecutionCommand")).length() != 0;
193 if (isAppKnown)
195 dbg("Local Connection trying to start the Office");
197 //ensure that a pending officewatcher gets finished before a new
198 //office is started
199 final OfficeWatcher ow_old = (OfficeWatcher) param.get("Watcher");
201 if (ow_old != null)
203 ow_old.finish = true;
206 final String cmd = (String) param.get("AppExecutionCommand");
207 dbg("AppExecutionCommand: " + cmd);
208 // validate the AppExecutionCommand, but try it out anyway.
209 // keep the error message for later.
210 errorMessage =
211 util.utils.validateAppExecutionCommand(cmd, (String) param.get("OperatingSystem"));
212 if (errorMessage.startsWith("Error"))
214 System.out.println(errorMessage);
215 return null;
217 bAppExecutionHasWarning = !errorMessage.equals("OK");
219 final DynamicClassLoader dcl = new DynamicClassLoader();
220 final LogWriter log = (LogWriter) dcl.getInstance(
221 (String) param.get("LogWriter"));
223 //create empty entry
224 final DescEntry Entry = new DescEntry();
225 Entry.entryName = "office";
226 Entry.longName = "office";
227 Entry.EntryType = "placebo";
228 Entry.isOptional = false;
229 Entry.isToTest = false;
230 Entry.SubEntryCount = 0;
231 Entry.hasErrorMsg = false;
232 Entry.State = "non possible";
233 Entry.UserDefinedParams = param;
235 log.initialize(Entry, debug);
237 final ProcessHandler ph = new ProcessHandler(cmd, (PrintWriter) log);
238 isExecutable = ph.executeAsynchronously();
240 if (isExecutable)
242 param.put("AppProvider", ph);
243 final OfficeWatcher ow = new OfficeWatcher(param);
244 param.put("Watcher", ow);
245 ow.start();
246 ow.ping();
249 int k = 0;
251 // wait up to 21 seconds to get an office connection
252 while ((k < 42) && (msf == null))
256 msf = connect(cncstr);
258 catch (com.sun.star.uno.Exception ue)
260 exConnectFailed = ue;
261 exc = ue.getMessage();
263 catch (java.lang.Exception je)
265 exConnectFailed = je;
266 exc = je.getMessage();
268 if (msf == null)
270 util.utils.pause(500 * k);
272 k++;
275 if (msf == null)
277 System.out.println("Exception while connecting.\n" + exConnectFailed);
278 if (exc != null)
280 System.out.println(exc);
282 if (bAppExecutionHasWarning)
284 System.out.println(errorMessage);
287 else if (isExecutable)
289 backupUserLayer(param, msf);
292 else
294 System.out.println("Could not connect an Office and cannot start one.\n".concat("please start an office with following parameter:\n").
295 concat("\nsoffice --accept=").concat((String) param.get("ConnectionString")).concat(";urp;\n"));
299 return msf;
303 * Connect an Office
304 * @param connectStr
305 * @return
306 * @throws com.sun.star.uno.Exception
307 * @throws com.sun.star.uno.RuntimeException
308 * @throws com.sun.star.connection.NoConnectException
309 * @throws Exception
311 private XMultiServiceFactory connect(String connectStr)
312 throws com.sun.star.uno.Exception,
313 com.sun.star.uno.RuntimeException,
314 com.sun.star.connection.NoConnectException,
315 Exception
318 // Get component context
319 final XComponentContext xcomponentcontext = com.sun.star.comp.helper.Bootstrap.createInitialComponentContext(null);
321 // initial serviceManager
322 final XMultiComponentFactory xLocalServiceManager = xcomponentcontext.getServiceManager();
324 // create a connector, so that it can contact the office
325 final Object xUrlResolver = xLocalServiceManager.createInstanceWithContext("com.sun.star.bridge.UnoUrlResolver", xcomponentcontext);
326 final XUnoUrlResolver urlResolver = UnoRuntime.queryInterface(XUnoUrlResolver.class, xUrlResolver);
328 final Object rInitialObject = urlResolver.resolve(connectStr);
330 XMultiServiceFactory xMSF = null;
332 if (rInitialObject != null)
334 // debug = true;
335 dbg("resolved url");
337 xMSF = UnoRuntime.queryInterface(XMultiServiceFactory.class, rInitialObject);
340 return xMSF;
344 * Close an office.
345 * @param param The test parameters.
346 * @param closeIfPossible If true, close even if
347 * it was running before the test
349 public boolean closeExistingOffice(lib.TestParameters param, boolean closeIfPossible)
352 XMultiServiceFactory msf = param.getMSF();
353 final boolean alreadyConnected = (msf != null);
354 debug = param.getBool(PropertyName.DEBUG_IS_ACTIVE);
356 if (alreadyConnected)
358 dbg("try to get ProcessHandler");
360 final ProcessHandler ph = (ProcessHandler) param.get("AppProvider");
362 if (ph != null)
364 dbg("ProcessHandler != null");
366 disposeOffice(msf, param);
368 // dispose watcher in case it's still running.
369 dbg("try to get OfficeWatcher");
371 final OfficeWatcher ow = (OfficeWatcher) param.get("Watcher");
373 if ((ow != null) && ow.isAlive())
375 dbg("OfficeWatcher will be finished");
376 ow.finish = true;
378 else
380 dbg("OfficeWatcher seems to be finished");
383 return true;
385 else
387 if (closeIfPossible)
389 return disposeOffice(msf, param);
393 else
395 final String cncstr = "uno:" + param.get("ConnectionString") +
396 ";urp;StarOffice.ServiceManager";
397 dbg("try to connect office");
398 msf = connectOffice(cncstr);
400 if (closeIfPossible)
402 return disposeOffice(msf, param);
405 dbg("closeExistingOffice finished");
406 return true;
409 private XMultiServiceFactory connectOffice(String cncstr)
411 XMultiServiceFactory msf = null;
412 String exc = "";
413 // debug = true;
415 dbg("trying to connect to " + cncstr);
419 msf = connect(cncstr);
421 catch (com.sun.star.uno.Exception ue)
423 exc = ue.getMessage();
425 catch (java.lang.Exception je)
427 exc = je.getMessage();
430 if (debug && exc != null && exc.length() != 0)
432 dbg("Could not connect an Office. " + exc);
435 return msf;
438 private boolean disposeOffice(XMultiServiceFactory msf,
439 TestParameters param)
441 XDesktop desk = null;
443 debug = param.getBool(PropertyName.DEBUG_IS_ACTIVE);
445 boolean result = true;
447 if (msf != null)
450 // disable QuickStarter
453 Object quickStarter = msf.createInstance("com.sun.star.office.Quickstart");
454 XFastPropertySet fps = UnoRuntime.queryInterface(XFastPropertySet.class, quickStarter);
455 fps.setFastPropertyValue(0, false);
457 catch (com.sun.star.uno.Exception ex)
459 dbg("ERROR: Could not disable QuickStarter: " + ex.toString());
464 desk = UnoRuntime.queryInterface(XDesktop.class, msf.createInstance("com.sun.star.frame.Desktop"));
465 msf = null;
467 if (desk != null)
469 final boolean allClosed = closeAllWindows(desk);
471 if (!allClosed)
473 dbg("Couldn't close all office windows!");
476 dbg("Trying to terminate the desktop");
478 desk.terminate();
479 dbg("Desktop terminated");
482 catch (com.sun.star.uno.Exception ue)
484 result = false;
486 catch (com.sun.star.lang.DisposedException ue)
488 result = false;
492 final ProcessHandler ph = (ProcessHandler) param.get("AppProvider");
494 if (ph != null)
496 // dispose watcher in case it's still running.
497 final OfficeWatcher ow = (OfficeWatcher) param.get("Watcher");
499 if ((ow != null) && ow.isAlive())
501 ow.finish = true;
504 ph.kill();
507 param.remove("AppProvider");
508 param.remove("ServiceFactory");
510 //copy user_backup into user layer
513 final String userLayer = (String) param.get("userLayer");
514 final String copyLayer = (String) param.get("copyLayer");
515 if (userLayer != null && copyLayer != null)
517 deleteFilesAndDirector(new File(userLayer));
518 final File copyFile = new File(copyLayer);
519 dbg("copy '" + copyFile + "' -> '" + userLayer + "'");
520 FileTools.copyDirectory(copyFile, new File(userLayer), new String[]
522 "temp"
524 dbg("copy '" + copyFile + "' -> '" + userLayer + "' finished");
526 // remove all user_backup folder in temp dir
527 // this is for the case the runner was killed and some old backup folder still stay in temp dir
531 else
533 System.out.println("Cannot copy layer: '" + copyLayer + "' back to user layer: '" + userLayer + "'");
536 catch (java.io.IOException e)
538 dbg("Couldn't recover from backup\n" + e.getMessage());
540 return result;
543 private boolean closeAllWindows(XDesktop desk)
545 final XEnumerationAccess compEnumAccess = desk.getComponents();
546 final XEnumeration compEnum = compEnumAccess.createEnumeration();
547 boolean res = true;
551 while (compEnum.hasMoreElements())
553 final XCloseable closer = UnoRuntime.queryInterface(XCloseable.class, compEnum.nextElement());
555 if (closer != null)
557 closer.close(true);
561 catch (com.sun.star.util.CloseVetoException cve)
563 res = false;
565 catch (com.sun.star.container.NoSuchElementException nsee)
567 res = false;
569 catch (com.sun.star.lang.WrappedTargetException wte)
571 res = false;
574 return res;
577 private static XStringSubstitution createStringSubstitution(XMultiServiceFactory xMSF) throws com.sun.star.uno.Exception
579 Object xPathSubst = xMSF.createInstance(
580 "com.sun.star.util.PathSubstitution");
581 return UnoRuntime.queryInterface(XStringSubstitution.class, xPathSubst);
585 * converts directory without 'file:///' prefix.
586 * and System dependent file separator
588 private static String getDirSys(String dir)
590 String sysDir = "";
592 final int idx = dir.indexOf("file://");
594 final int idx2 = dir.indexOf("file:///");
596 // remove leading 'file://'
597 if (idx < 0)
599 sysDir = dir;
601 else
603 sysDir = dir.substring("file://".length());
606 sysDir = sysDir.replace("%20", " ");
608 // append '/' if not there (e.g. linux)
609 if (sysDir.charAt(sysDir.length() - 1) != '/')
611 sysDir += "/";
614 // remove leading '/' and replace others with '\' on windows machines
615 final String sep = System.getProperty("file.separator");
617 if (sep.equalsIgnoreCase("\\"))
619 if (idx2 >= 0)
621 sysDir = sysDir.substring(1);
623 else
625 //network path
626 sysDir = "//" + sysDir;
628 sysDir = sysDir.replace('/', '\\');
631 return sysDir;
635 * If the office is connected but the <CODE>AppExecutionCommand</CODE> is not set,
636 * this function asks the office for its location and fill the
637 * <CODE>AppExecutionCommand</CODE> with valid content.
638 * This function was only called if parameter <CODE>AutoRestart</CODE> is set.
639 * @param msf the <CODE>MultiServiceFactory</CODE>
640 * @param param the <CODE>TestParameters</CODE>
642 private void makeAppExecCommand(XMultiServiceFactory msf, TestParameters param)
644 debug = param.getBool(PropertyName.DEBUG_IS_ACTIVE);
646 // get existing AppExecutionCommand if available, else empty string
647 String command = (String) param.get(util.PropertyName.APP_EXECUTION_COMMAND);
649 String connectionString;
650 if (param.getBool(util.PropertyName.USE_PIPE_CONNECTION))
652 // This is the default behaviour
653 connectionString = (String) param.get(util.PropertyName.PIPE_CONNECTION_STRING);
655 else
657 // is used if UsePipeConnection=false
658 connectionString = (String) param.get(util.PropertyName.CONNECTION_STRING);
661 String sysBinDir = "";
665 sysBinDir = utils.getSystemURL(utils.expandMacro(msf, "$SYSBINDIR"));
667 catch (java.lang.Exception e)
669 dbg("could not get system binary directory");
670 return;
673 // does the existing command show to the connected office?
674 if (command.indexOf(sysBinDir) == -1)
676 command = sysBinDir + System.getProperty("file.separator") + "soffice" +
677 " --norestore --accept=" + connectionString + ";urp;";
680 dbg("update AppExecutionCommand: " + command);
682 param.put(util.PropertyName.APP_EXECUTION_COMMAND, command);
685 private void dbg(String message)
687 if (debug)
689 System.out.println(utils.getDateTime() + "OfficeProvider: " + message);
694 private static class OfficeWatcherPing extends Thread
697 private final OfficeWatcher ow;
698 private boolean bStop = false;
700 public OfficeWatcherPing(OfficeWatcher ow)
702 this.ow = ow;
705 @Override
706 public void run()
708 System.out.println(utils.getDateTime() + "OfficeProvider:Owp: start ");
710 while (!bStop)
712 System.out.println(utils.getDateTime() + "OfficeProvider:Owp: ping ");
713 ow.ping();
714 System.out.println(utils.getDateTime() + "OfficeProvider:Owp: sleep ");
715 util.utils.pause(1000);
720 public void finish()
722 synchronized(this)
724 bStop = true;
725 System.out.println(utils.getDateTime() + "OfficeProvider:Owp: stop ");
727 notify();
732 private void deleteFilesAndDirector(File file)
734 File f = file;
735 if(f.isDirectory())
737 File files[] = f.listFiles();
738 int filesLength = files != null ? files.length : 0;
739 for(int i = 0; i < filesLength; ++i)
741 deleteFilesAndDirector(files[i]);
743 boolean bDeleteOk = f.delete();
744 if (!bDeleteOk) {
745 System.out.println("delete failed");
748 else if (f.isFile())
750 boolean bDeleteOk = f.delete();
751 if (!bDeleteOk) {
752 System.out.println("delete failed");