Version 5.4.3.2, tag libreoffice-5.4.3.2
[LibreOffice.git] / qadevOOo / runner / helper / OfficeProvider.java
blob880565896443ac2ff633f156f23840e8fbbba8a4
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;
35 import lib.TestParameters;
37 import share.DescEntry;
38 import share.LogWriter;
40 import util.DynamicClassLoader;
41 import util.PropertyName;
42 import util.utils;
44 /**
45 * This class will connect the office and start it if possible
48 public class OfficeProvider implements AppProvider
51 private boolean debug = false;
53 /**
54 * copy the user layer to a safe place, usually to $TMP/user_backup$USER
56 private void backupUserLayer(TestParameters param, XMultiServiceFactory msf)
58 try
60 final XStringSubstitution sts = createStringSubstitution(msf);
61 debug = param.getBool(PropertyName.DEBUG_IS_ACTIVE);
63 String userLayer = sts.getSubstituteVariableValue("$(user)");
64 userLayer = getDirSys(userLayer);
65 param.put("userLayer", userLayer);
67 final String copyLayer = util.utils.getUsersTempDir() + System.getProperty("file.separator") +
68 "user_backup" +
69 System.getProperty("user.name");
70 param.put("copyLayer", copyLayer);
73 dbg(" copy '" + userLayer + "' ->" + copyLayer + "'");
74 // Slow machines the copy job could spend some time. To avoid activating of OfficeWatcher it must be pinged
75 OfficeWatcherPing owp = new OfficeWatcherPing((OfficeWatcher) param.get(PropertyName.OFFICE_WATCHER));
76 owp.start();
78 deleteFilesAndDirector (new File(copyLayer));
79 FileTools.copyDirectory(new File(userLayer), new File(copyLayer), new String[]
81 "temp"
82 });
84 owp.finish();
87 catch (com.sun.star.container.NoSuchElementException e)
89 System.out.println("User Variable '$(user)' not defined.");
91 catch (com.sun.star.uno.Exception e)
93 System.out.println("Couldn't backup user layer");
94 e.printStackTrace();
96 catch (java.io.IOException e)
98 System.out.println("Couldn't backup user layer");
99 e.printStackTrace();
104 * Dispose the office.
105 * This method can only be used, if the office was connected in the first
106 * place: getManager() was called first.
107 * @return return true if desktop is terminates, else false
109 public boolean disposeManager(lib.TestParameters param)
112 XMultiServiceFactory msf = param.getMSF();
114 if (msf == null)
116 return true;
118 else
120 XDesktop desk = null;
124 desk = UnoRuntime.queryInterface(XDesktop.class, msf.createInstance("com.sun.star.frame.Desktop"));
126 catch (com.sun.star.uno.Exception ue)
128 return false;
131 msf = null;
133 if (desk != null)
135 desk.terminate();
137 return true;
139 else
141 return false;
147 * Method to get the ServiceManager of an Office
149 public Object getManager(lib.TestParameters param)
151 String errorMessage = null;
152 boolean bAppExecutionHasWarning = false;
153 debug = param.getBool(PropertyName.DEBUG_IS_ACTIVE);
155 String additionalArgs = (String) param.get(
156 "AdditionalConnectionArguments");
158 if (additionalArgs == null)
160 additionalArgs = ";";
162 else
164 additionalArgs = "," + additionalArgs + ";";
167 final String cncstr = "uno:" + param.get("ConnectionString") + ";urp" +
168 additionalArgs + "StarOffice.ServiceManager";
170 System.out.println("Connecting the Office with " + cncstr);
172 XMultiServiceFactory msf = connectOffice(cncstr);
174 // if the office is running and the office crashes while testing it could
175 // be useful to restart the office if possible and continuing the tests.
176 // Example: the UNO-API-Tests in the projects will be executed by calling
177 // 'damke'. This connects to an existing office. If the office crashes
178 // it is useful to restart the office and continuing the tests.
179 if ((param.getBool(util.PropertyName.AUTO_RESTART)) && (msf != null))
181 makeAppExecCommand(msf, param);
184 if (msf == null)
186 String exc = "";
187 Exception exConnectFailed = null;
188 boolean isExecutable = false;
189 boolean isAppKnown = ((cncstr.indexOf("host=localhost") > 0) || (cncstr.indexOf("pipe,name=") > 0));
190 isAppKnown &= ((String) param.get("AppExecutionCommand")).length() != 0;
192 if (isAppKnown)
194 dbg("Local Connection trying to start the Office");
196 //ensure that a pending officewatcher gets finished before a new
197 //office is started
198 final OfficeWatcher ow_old = (OfficeWatcher) param.get("Watcher");
200 if (ow_old != null)
202 ow_old.finish = true;
205 final String cmd = (String) param.get("AppExecutionCommand");
206 dbg("AppExecutionCommand: " + cmd);
207 // validate the AppExecutionCommand, but try it out anyway.
208 // keep the error message for later.
209 errorMessage =
210 util.utils.validateAppExecutionCommand(cmd, (String) param.get("OperatingSystem"));
211 if (errorMessage.startsWith("Error"))
213 System.out.println(errorMessage);
214 return null;
216 bAppExecutionHasWarning = !errorMessage.equals("OK");
218 final DynamicClassLoader dcl = new DynamicClassLoader();
219 final LogWriter log = (LogWriter) dcl.getInstance(
220 (String) param.get("LogWriter"));
222 //create empty entry
223 final DescEntry Entry = new DescEntry();
224 Entry.entryName = "office";
225 Entry.longName = "office";
226 Entry.EntryType = "placebo";
227 Entry.isOptional = false;
228 Entry.isToTest = false;
229 Entry.SubEntryCount = 0;
230 Entry.hasErrorMsg = false;
231 Entry.State = "non possible";
232 Entry.UserDefinedParams = param;
234 log.initialize(Entry, debug);
236 final ProcessHandler ph = new ProcessHandler(cmd, (PrintWriter) log);
237 isExecutable = ph.executeAsynchronously();
239 if (isExecutable)
241 param.put("AppProvider", ph);
242 final OfficeWatcher ow = new OfficeWatcher(param);
243 param.put("Watcher", ow);
244 ow.start();
245 ow.ping();
248 int k = 0;
250 // wait up to 21 seconds to get an office connection
251 while ((k < 42) && (msf == null))
255 msf = connect(cncstr);
257 catch (com.sun.star.uno.Exception ue)
259 exConnectFailed = ue;
260 exc = ue.getMessage();
262 catch (java.lang.Exception je)
264 exConnectFailed = je;
265 exc = je.getMessage();
267 if (msf == null)
269 util.utils.pause(500 * k);
271 k++;
274 if (msf == null)
276 System.out.println("Exception while connecting.\n" + exConnectFailed);
277 if (exc != null)
279 System.out.println(exc);
281 if (bAppExecutionHasWarning)
283 System.out.println(errorMessage);
286 else if (isExecutable)
288 backupUserLayer(param, msf);
291 else
293 System.out.println("Could not connect an Office and cannot start one.\n".concat("please start an office with following parameter:\n").
294 concat("\nsoffice --accept=").concat((String) param.get("ConnectionString")).concat(";urp;\n"));
298 return msf;
302 * Connect an Office
303 * @param connectStr
304 * @return
305 * @throws com.sun.star.uno.Exception
306 * @throws com.sun.star.uno.RuntimeException
307 * @throws com.sun.star.connection.NoConnectException
308 * @throws Exception
310 private XMultiServiceFactory connect(String connectStr)
311 throws com.sun.star.uno.Exception,
312 com.sun.star.uno.RuntimeException,
313 com.sun.star.connection.NoConnectException,
314 Exception
317 // Get component context
318 final XComponentContext xcomponentcontext = com.sun.star.comp.helper.Bootstrap.createInitialComponentContext(null);
320 // initial serviceManager
321 final XMultiComponentFactory xLocalServiceManager = xcomponentcontext.getServiceManager();
323 // create a connector, so that it can contact the office
324 final Object xUrlResolver = xLocalServiceManager.createInstanceWithContext("com.sun.star.bridge.UnoUrlResolver", xcomponentcontext);
325 final XUnoUrlResolver urlResolver = UnoRuntime.queryInterface(XUnoUrlResolver.class, xUrlResolver);
327 final Object rInitialObject = urlResolver.resolve(connectStr);
329 XMultiServiceFactory xMSF = null;
331 if (rInitialObject != null)
333 // debug = true;
334 dbg("resolved url");
336 xMSF = UnoRuntime.queryInterface(XMultiServiceFactory.class, rInitialObject);
339 return xMSF;
343 * Close an office.
344 * @param param The test parameters.
345 * @param closeIfPossible If true, close even if
346 * it was running before the test
348 public boolean closeExistingOffice(lib.TestParameters param, boolean closeIfPossible)
351 XMultiServiceFactory msf = param.getMSF();
352 final boolean alreadyConnected = (msf != null);
353 debug = param.getBool(PropertyName.DEBUG_IS_ACTIVE);
355 if (alreadyConnected)
357 dbg("try to get ProcessHandler");
359 final ProcessHandler ph = (ProcessHandler) param.get("AppProvider");
361 if (ph != null)
363 dbg("ProcessHandler != null");
365 disposeOffice(msf, param);
367 // dispose watcher in case it's still running.
368 dbg("try to get OfficeWatcher");
370 final OfficeWatcher ow = (OfficeWatcher) param.get("Watcher");
372 if ((ow != null) && ow.isAlive())
374 dbg("OfficeWatcher will be finished");
375 ow.finish = true;
377 else
379 dbg("OfficeWatcher seems to be finished");
382 return true;
384 else
386 if (closeIfPossible)
388 return disposeOffice(msf, param);
392 else
394 final String cncstr = "uno:" + param.get("ConnectionString") +
395 ";urp;StarOffice.ServiceManager";
396 dbg("try to connect office");
397 msf = connectOffice(cncstr);
399 if (closeIfPossible)
401 return disposeOffice(msf, param);
404 dbg("closeExistingOffice finished");
405 return true;
408 private XMultiServiceFactory connectOffice(String cncstr)
410 XMultiServiceFactory msf = null;
411 String exc = "";
412 // debug = true;
414 dbg("trying to connect to " + cncstr);
418 msf = connect(cncstr);
420 catch (com.sun.star.uno.Exception ue)
422 exc = ue.getMessage();
424 catch (java.lang.Exception je)
426 exc = je.getMessage();
429 if (debug && exc != null && exc.length() != 0)
431 dbg("Could not connect an Office. " + exc);
434 return msf;
437 private boolean disposeOffice(XMultiServiceFactory msf,
438 TestParameters param)
440 XDesktop desk = null;
442 debug = param.getBool(PropertyName.DEBUG_IS_ACTIVE);
444 boolean result = true;
446 if (msf != null)
449 // disable QuickStarter
452 Object quickStarter = msf.createInstance("com.sun.star.office.Quickstart");
453 XFastPropertySet fps = UnoRuntime.queryInterface(XFastPropertySet.class, quickStarter);
454 fps.setFastPropertyValue(0, false);
456 catch (com.sun.star.uno.Exception ex)
458 dbg("ERROR: Could not disable QuickStarter: " + ex.toString());
463 desk = UnoRuntime.queryInterface(XDesktop.class, msf.createInstance("com.sun.star.frame.Desktop"));
464 msf = null;
466 if (desk != null)
468 final boolean allClosed = closeAllWindows(desk);
470 if (!allClosed)
472 dbg("Couldn't close all office windows!");
475 dbg("Trying to terminate the desktop");
477 desk.terminate();
478 dbg("Desktop terminated");
481 catch (com.sun.star.uno.Exception ue)
483 result = false;
485 catch (com.sun.star.lang.DisposedException ue)
487 result = false;
491 final ProcessHandler ph = (ProcessHandler) param.get("AppProvider");
493 if (ph != null)
495 // dispose watcher in case it's still running.
496 final OfficeWatcher ow = (OfficeWatcher) param.get("Watcher");
498 if ((ow != null) && ow.isAlive())
500 ow.finish = true;
503 ph.kill();
506 param.remove("AppProvider");
507 param.remove("ServiceFactory");
509 //copy user_backup into user layer
512 final String userLayer = (String) param.get("userLayer");
513 final String copyLayer = (String) param.get("copyLayer");
514 if (userLayer != null && copyLayer != null)
516 deleteFilesAndDirector(new File(userLayer));
517 final File copyFile = new File(copyLayer);
518 dbg("copy '" + copyFile + "' -> '" + userLayer + "'");
519 FileTools.copyDirectory(copyFile, new File(userLayer), new String[]
521 "temp"
523 dbg("copy '" + copyFile + "' -> '" + userLayer + "' finished");
525 // remove all user_backup folder in temp dir
526 // this is for the case the runner was killed and some old backup folder still stay in temp dir
530 else
532 System.out.println("Cannot copy layer: '" + copyLayer + "' back to user layer: '" + userLayer + "'");
535 catch (java.io.IOException e)
537 dbg("Couldn't recover from backup\n" + e.getMessage());
539 return result;
542 private boolean closeAllWindows(XDesktop desk)
544 final XEnumerationAccess compEnumAccess = desk.getComponents();
545 final XEnumeration compEnum = compEnumAccess.createEnumeration();
546 boolean res = true;
550 while (compEnum.hasMoreElements())
552 final XCloseable closer = UnoRuntime.queryInterface(XCloseable.class, compEnum.nextElement());
554 if (closer != null)
556 closer.close(true);
560 catch (com.sun.star.util.CloseVetoException cve)
562 res = false;
564 catch (com.sun.star.container.NoSuchElementException nsee)
566 res = false;
568 catch (com.sun.star.lang.WrappedTargetException wte)
570 res = false;
573 return res;
576 private static XStringSubstitution createStringSubstitution(XMultiServiceFactory xMSF) throws com.sun.star.uno.Exception
578 Object xPathSubst = xMSF.createInstance(
579 "com.sun.star.util.PathSubstitution");
580 return UnoRuntime.queryInterface(XStringSubstitution.class, xPathSubst);
584 * converts directory without 'file:///' prefix.
585 * and System dependent file separator
587 private static String getDirSys(String dir)
589 String sysDir = "";
591 final int idx = dir.indexOf("file://");
593 final int idx2 = dir.indexOf("file:///");
595 // remove leading 'file://'
596 if (idx < 0)
598 sysDir = dir;
600 else
602 sysDir = dir.substring("file://".length());
605 sysDir = sysDir.replace("%20", " ");
607 // append '/' if not there (e.g. linux)
608 if (sysDir.charAt(sysDir.length() - 1) != '/')
610 sysDir += "/";
613 // remove leading '/' and replace others with '\' on windows machines
614 final String sep = System.getProperty("file.separator");
616 if (sep.equalsIgnoreCase("\\"))
618 if (idx2 >= 0)
620 sysDir = sysDir.substring(1);
622 else
624 //network path
625 sysDir = "//" + sysDir;
627 sysDir = sysDir.replace('/', '\\');
630 return sysDir;
634 * If the office is connected but the <CODE>AppExecutionCommand</CODE> is not set,
635 * this function asks the office for its location and fill the
636 * <CODE>AppExecutionCommand</CODE> with valid content.
637 * This function was only called if parameter <CODE>AutoRestart</CODE> is set.
638 * @param msf the <CODE>MultiServiceFactory</CODE>
639 * @param param the <CODE>TestParameters</CODE>
641 private void makeAppExecCommand(XMultiServiceFactory msf, TestParameters param)
643 debug = param.getBool(PropertyName.DEBUG_IS_ACTIVE);
645 // get existing AppExecutionCommand if available, else empty string
646 String command = (String) param.get(util.PropertyName.APP_EXECUTION_COMMAND);
648 String connectionString;
649 if (param.getBool(util.PropertyName.USE_PIPE_CONNECTION))
651 // This is the default behaviour
652 connectionString = (String) param.get(util.PropertyName.PIPE_CONNECTION_STRING);
654 else
656 // is used if UsePipeConnection=false
657 connectionString = (String) param.get(util.PropertyName.CONNECTION_STRING);
660 String sysBinDir = "";
664 sysBinDir = utils.getSystemURL(utils.expandMacro(msf, "$SYSBINDIR"));
666 catch (java.lang.Exception e)
668 dbg("could not get system binary directory");
669 return;
672 // does the existing command show to the connected office?
673 if (command.indexOf(sysBinDir) == -1)
675 command = sysBinDir + System.getProperty("file.separator") + "soffice" +
676 " --norestore --accept=" + connectionString + ";urp;";
679 dbg("update AppExecutionCommand: " + command);
681 param.put(util.PropertyName.APP_EXECUTION_COMMAND, command);
684 private void dbg(String message)
686 if (debug)
688 System.out.println(utils.getDateTime() + "OfficeProvider: " + message);
693 private static class OfficeWatcherPing extends Thread
696 private final OfficeWatcher ow;
697 private boolean bStop = false;
699 public OfficeWatcherPing(OfficeWatcher ow)
701 this.ow = ow;
704 @Override
705 public void run()
707 System.out.println(utils.getDateTime() + "OfficeProvider:Owp: start ");
709 while (!bStop)
711 System.out.println(utils.getDateTime() + "OfficeProvider:Owp: ping ");
712 ow.ping();
713 System.out.println(utils.getDateTime() + "OfficeProvider:Owp: sleep ");
714 util.utils.pause(1000);
719 public void finish()
721 synchronized(this)
723 bStop = true;
724 System.out.println(utils.getDateTime() + "OfficeProvider:Owp: stop ");
726 notify();
731 private void deleteFilesAndDirector(File file)
733 File f = file;
734 if(f.isDirectory())
736 File files[] = f.listFiles();
737 int filesLength = files != null ? files.length : 0;
738 for(int i = 0; i < filesLength; ++i)
740 deleteFilesAndDirector(files[i]);
742 boolean bDeleteOk = f.delete();
743 if (!bDeleteOk) {
744 System.out.println("delete failed");
747 else if (f.isFile())
749 boolean bDeleteOk = f.delete();
750 if (!bDeleteOk) {
751 System.out.println("delete failed");