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 .
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
;
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
;
45 * This class will connect the office and start it if possible
48 public class OfficeProvider
implements AppProvider
51 private boolean debug
= false;
54 * copy the user layer to a safe place, usually to $TMP/user_backup$USER
56 private void backupUserLayer(TestParameters param
, XMultiServiceFactory msf
)
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") +
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
));
78 deleteFilesAndDirector (new File(copyLayer
));
79 FileTools
.copyDirectory(new File(userLayer
), new File(copyLayer
), new String
[]
87 catch (com
.sun
.star
.container
.NoSuchElementException e
)
89 System
.out
.println("User Variable '$(user)' not defined.");
91 catch (java
.io
.IOException e
)
93 System
.out
.println("Couldn't backup user layer");
100 * This method can only be used, if the office was connected in the first
101 * place: getManager() was called first.
102 * @return return true if desktop is terminates, else false
104 public boolean disposeManager(lib
.TestParameters param
)
107 XMultiServiceFactory msf
= param
.getMSF();
115 XDesktop desk
= null;
119 desk
= UnoRuntime
.queryInterface(XDesktop
.class, msf
.createInstance("com.sun.star.frame.Desktop"));
121 catch (com
.sun
.star
.uno
.Exception ue
)
142 * Method to get the ServiceManager of an Office
144 public Object
getManager(lib
.TestParameters param
)
146 String errorMessage
= null;
147 boolean bAppExecutionHasWarning
= false;
148 debug
= param
.getBool(PropertyName
.DEBUG_IS_ACTIVE
);
150 String additionalArgs
= (String
) param
.get(
151 "AdditionalConnectionArguments");
153 if (additionalArgs
== null)
155 additionalArgs
= ";";
159 additionalArgs
= "," + additionalArgs
+ ";";
162 final String cncstr
= "uno:" + param
.get("ConnectionString") + ";urp" +
163 additionalArgs
+ "StarOffice.ServiceManager";
165 System
.out
.println("Connecting the Office with " + cncstr
);
167 XMultiServiceFactory msf
= connectOffice(cncstr
);
169 // if the office is running and the office crashes while testing it could
170 // be usesfull to restart the office if possible and continuing the tests.
171 // Example: The UNO-API-Tests in the projects will be executed by calling
172 // 'damke'. This connects to an existing office. If the office crashes
173 // it is useful to restart the office and continuing the tests.
174 if ((param
.getBool(util
.PropertyName
.AUTO_RESTART
)) && (msf
!= null))
176 makeAppExecCommand(msf
, param
);
182 Exception exConnectFailed
= null;
183 boolean isExecutable
= false;
184 boolean isAppKnown
= ((cncstr
.indexOf("host=localhost") > 0) || (cncstr
.indexOf("pipe,name=") > 0));
185 isAppKnown
&= ((String
) param
.get("AppExecutionCommand")).length() != 0;
189 dbg("Local Connection trying to start the Office");
191 //ensure that a pending officewatcher gets finished before a new
193 final OfficeWatcher ow_old
= (OfficeWatcher
) param
.get("Watcher");
197 ow_old
.finish
= true;
200 final String cmd
= (String
) param
.get("AppExecutionCommand");
201 dbg("AppExecutionCommand: " + cmd
);
202 // validate the AppExecutionCommand, but try it out anyway.
203 // keep the error message for later.
205 util
.utils
.validateAppExecutionCommand(cmd
, (String
) param
.get("OperatingSystem"));
206 if (errorMessage
.startsWith("Error"))
208 System
.out
.println(errorMessage
);
211 bAppExecutionHasWarning
= !errorMessage
.equals("OK");
213 final DynamicClassLoader dcl
= new DynamicClassLoader();
214 final LogWriter log
= (LogWriter
) dcl
.getInstance(
215 (String
) param
.get("LogWriter"));
218 final DescEntry Entry
= new DescEntry();
219 Entry
.entryName
= "office";
220 Entry
.longName
= "office";
221 Entry
.EntryType
= "placebo";
222 Entry
.isOptional
= false;
223 Entry
.isToTest
= false;
224 Entry
.SubEntryCount
= 0;
225 Entry
.hasErrorMsg
= false;
226 Entry
.State
= "non possible";
227 Entry
.UserDefinedParams
= param
;
229 log
.initialize(Entry
, debug
);
231 final ProcessHandler ph
= new ProcessHandler(cmd
, (PrintWriter
) log
);
232 isExecutable
= ph
.executeAsynchronously();
236 param
.put("AppProvider", ph
);
237 final OfficeWatcher ow
= new OfficeWatcher(param
);
238 param
.put("Watcher", ow
);
245 // wait up to 21 seconds to get an office connection
246 while ((k
< 42) && (msf
== null))
250 msf
= connect(cncstr
);
252 catch (com
.sun
.star
.uno
.Exception ue
)
254 exConnectFailed
= ue
;
255 exc
= ue
.getMessage();
257 catch (java
.lang
.Exception je
)
259 exConnectFailed
= je
;
260 exc
= je
.getMessage();
264 util
.utils
.pause(500 * k
);
271 System
.out
.println("Exception while connecting.\n" + exConnectFailed
);
274 System
.out
.println(exc
);
276 if (bAppExecutionHasWarning
)
278 System
.out
.println(errorMessage
);
281 else if (isExecutable
)
283 backupUserLayer(param
, msf
);
288 System
.out
.println("Could not connect an Office and cannot start one.\n".concat("please start an office with following parameter:\n").
289 concat("\nsoffice --accept=").concat((String
) param
.get("ConnectionString")).concat(";urp;\n"));
300 * @throws com.sun.star.uno.Exception
301 * @throws com.sun.star.uno.RuntimeException
302 * @throws com.sun.star.connection.NoConnectException
305 private XMultiServiceFactory
connect(String connectStr
)
306 throws com
.sun
.star
.uno
.Exception
,
307 com
.sun
.star
.uno
.RuntimeException
,
308 com
.sun
.star
.connection
.NoConnectException
,
312 // Get component context
313 final XComponentContext xcomponentcontext
= com
.sun
.star
.comp
.helper
.Bootstrap
.createInitialComponentContext(null);
315 // initial serviceManager
316 final XMultiComponentFactory xLocalServiceManager
= xcomponentcontext
.getServiceManager();
318 // create a connector, so that it can contact the office
319 final Object xUrlResolver
= xLocalServiceManager
.createInstanceWithContext("com.sun.star.bridge.UnoUrlResolver", xcomponentcontext
);
320 final XUnoUrlResolver urlResolver
= UnoRuntime
.queryInterface(XUnoUrlResolver
.class, xUrlResolver
);
322 final Object rInitialObject
= urlResolver
.resolve(connectStr
);
324 XMultiServiceFactory xMSF
= null;
326 if (rInitialObject
!= null)
331 xMSF
= UnoRuntime
.queryInterface(XMultiServiceFactory
.class, rInitialObject
);
339 * @param param The test parameters.
340 * @param closeIfPossible If true, close even if
341 * it was running before the test
343 public boolean closeExistingOffice(lib
.TestParameters param
, boolean closeIfPossible
)
346 XMultiServiceFactory msf
= param
.getMSF();
347 final boolean alreadyConnected
= (msf
!= null);
348 debug
= param
.getBool(PropertyName
.DEBUG_IS_ACTIVE
);
350 if (alreadyConnected
)
352 dbg("try to get ProcessHandler");
354 final ProcessHandler ph
= (ProcessHandler
) param
.get("AppProvider");
358 dbg("ProcessHandler != null");
360 disposeOffice(msf
, param
);
362 // dispose watcher in case it's still running.
363 dbg("try to get OfficeWatcher");
365 final OfficeWatcher ow
= (OfficeWatcher
) param
.get("Watcher");
367 if ((ow
!= null) && ow
.isAlive())
369 dbg("OfficeWatcher will be finished");
374 dbg("OfficeWatcher seems to be finished");
383 return disposeOffice(msf
, param
);
389 final String cncstr
= "uno:" + param
.get("ConnectionString") +
390 ";urp;StarOffice.ServiceManager";
391 dbg("try to connect office");
392 msf
= connectOffice(cncstr
);
396 return disposeOffice(msf
, param
);
399 dbg("closeExistingOffice finished");
403 private XMultiServiceFactory
connectOffice(String cncstr
)
405 XMultiServiceFactory msf
= null;
409 dbg("trying to connect to " + cncstr
);
413 msf
= connect(cncstr
);
415 catch (com
.sun
.star
.uno
.Exception ue
)
417 exc
= ue
.getMessage();
419 catch (java
.lang
.Exception je
)
421 exc
= je
.getMessage();
424 if (debug
&& exc
!= null && exc
.length() != 0)
426 dbg("Could not connect an Office. " + exc
);
432 private synchronized boolean disposeOffice(XMultiServiceFactory msf
,
433 TestParameters param
)
435 XDesktop desk
= null;
437 debug
= param
.getBool(PropertyName
.DEBUG_IS_ACTIVE
);
439 boolean result
= true;
444 // disable QuickStarter
447 Object quickStarter
= msf
.createInstance("com.sun.star.office.Quickstart");
448 XFastPropertySet fps
= UnoRuntime
.queryInterface(XFastPropertySet
.class, quickStarter
);
449 fps
.setFastPropertyValue(0, false);
451 catch (com
.sun
.star
.uno
.Exception ex
)
453 dbg("ERROR: Could not disable QuickStarter: " + ex
.toString());
458 desk
= UnoRuntime
.queryInterface(XDesktop
.class, msf
.createInstance("com.sun.star.frame.Desktop"));
463 final boolean allClosed
= closeAllWindows(desk
);
467 dbg("Couldn't close all office windows!");
470 dbg("Trying to terminate the desktop");
473 dbg("Desktop terminated");
477 final int closeTime
= param
.getInt(util
.PropertyName
.OFFICE_CLOSE_TIME_OUT
);
478 dbg("the Office has " + closeTime
/ 1000 + " seconds for closing...");
479 Thread
.sleep(closeTime
);
481 catch (InterruptedException e
)
486 catch (com
.sun
.star
.uno
.Exception ue
)
490 catch (com
.sun
.star
.lang
.DisposedException ue
)
496 final ProcessHandler ph
= (ProcessHandler
) param
.get("AppProvider");
500 // dispose watcher in case it's still running.
501 final OfficeWatcher ow
= (OfficeWatcher
) param
.get("Watcher");
503 if ((ow
!= null) && ow
.isAlive())
511 param
.remove("AppProvider");
512 param
.remove("ServiceFactory");
514 //copy user_backup into user layer
517 final String userLayer
= (String
) param
.get("userLayer");
518 final String copyLayer
= (String
) param
.get("copyLayer");
519 if (userLayer
!= null && copyLayer
!= null)
521 deleteFilesAndDirector(new File(userLayer
));
522 final File copyFile
= new File(copyLayer
);
523 dbg("copy '" + copyFile
+ "' -> '" + userLayer
+ "'");
524 FileTools
.copyDirectory(copyFile
, new File(userLayer
), new String
[]
528 dbg("copy '" + copyFile
+ "' -> '" + userLayer
+ "' finished");
530 // remove all user_backup folder in temp dir
531 // this is for the case the runner was killed and some old backup folder still stay in temp dir
537 System
.out
.println("Cannot copy layer: '" + copyLayer
+ "' back to user layer: '" + userLayer
+ "'");
540 catch (java
.io
.IOException e
)
542 dbg("Couldn't recover from backup\n" + e
.getMessage());
547 private boolean closeAllWindows(XDesktop desk
)
549 final XEnumerationAccess compEnumAccess
= desk
.getComponents();
550 final XEnumeration compEnum
= compEnumAccess
.createEnumeration();
555 while (compEnum
.hasMoreElements())
557 final XCloseable closer
= UnoRuntime
.queryInterface(XCloseable
.class, compEnum
.nextElement());
565 catch (com
.sun
.star
.util
.CloseVetoException cve
)
569 catch (com
.sun
.star
.container
.NoSuchElementException nsee
)
573 catch (com
.sun
.star
.lang
.WrappedTargetException wte
)
581 private static XStringSubstitution
createStringSubstitution(XMultiServiceFactory xMSF
)
583 Object xPathSubst
= null;
587 xPathSubst
= xMSF
.createInstance(
588 "com.sun.star.util.PathSubstitution");
590 catch (com
.sun
.star
.uno
.Exception e
)
595 if (xPathSubst
!= null)
597 return UnoRuntime
.queryInterface(XStringSubstitution
.class, xPathSubst
);
606 * converts directory without 'file:///' prefix.
607 * and System dependent file separator
609 private static String
getDirSys(String dir
)
613 final int idx
= dir
.indexOf("file://");
615 final int idx2
= dir
.indexOf("file:///");
617 // remove leading 'file://'
624 sysDir
= dir
.substring("file://".length());
627 sysDir
= sysDir
.replace("%20", " ");
629 // append '/' if not there (e.g. linux)
630 if (sysDir
.charAt(sysDir
.length() - 1) != '/')
635 // remove leading '/' and replace others with '\' on windows machines
636 final String sep
= System
.getProperty("file.separator");
638 if (sep
.equalsIgnoreCase("\\"))
642 sysDir
= sysDir
.substring(1);
647 sysDir
= "//" + sysDir
;
649 sysDir
= sysDir
.replace('/', '\\');
656 * If the office is connected but the <CODE>AppExecutionCommand</CODE> is not set,
657 * this function asks the office for its location and fill the
658 * <CODE>AppExecutionCommand</CODE> with valid contet.
659 * This function was only called if parameter <CODE>AutoRestart</CODE> is set.
660 * @param msf the <CODE>MultiServiceFactory</CODE>
661 * @param param the <CODE>TestParameters</CODE>
663 private void makeAppExecCommand(XMultiServiceFactory msf
, TestParameters param
)
665 debug
= param
.getBool(PropertyName
.DEBUG_IS_ACTIVE
);
667 // get existing AppExecutionCommand if available, else empty string
668 String command
= (String
) param
.get(util
.PropertyName
.APP_EXECUTION_COMMAND
);
670 String connectionString
;
671 if (param
.getBool(util
.PropertyName
.USE_PIPE_CONNECTION
))
673 // This is the default behaviour
674 connectionString
= (String
) param
.get(util
.PropertyName
.PIPE_CONNECTION_STRING
);
678 // is used if UsePipeConnection=false
679 connectionString
= (String
) param
.get(util
.PropertyName
.CONNECTION_STRING
);
682 String sysBinDir
= "";
686 sysBinDir
= utils
.getSystemURL(utils
.expandMacro(msf
, "$SYSBINDIR"));
688 catch (java
.lang
.Exception e
)
690 dbg("could not get system binary directory");
694 // does the existing command show to the connected office?
695 if (command
.indexOf(sysBinDir
) == -1)
697 command
= sysBinDir
+ System
.getProperty("file.separator") + "soffice" +
698 " --norestore --accept=" + connectionString
+ ";urp;";
701 dbg("update AppExecutionCommand: " + command
);
703 param
.put(util
.PropertyName
.APP_EXECUTION_COMMAND
, command
);
706 private void dbg(String message
)
710 System
.out
.println(utils
.getDateTime() + "OfficeProvider: " + message
);
715 private class OfficeWatcherPing
extends Thread
718 private final OfficeWatcher ow
;
719 private boolean bStop
= false;
721 public OfficeWatcherPing(OfficeWatcher ow
)
729 System
.out
.println(utils
.getDateTime() + "OfficeProvider:Owp: start ");
733 System
.out
.println(utils
.getDateTime() + "OfficeProvider:Owp: ping ");
735 System
.out
.println(utils
.getDateTime() + "OfficeProvider:Owp: sleep ");
736 util
.utils
.pause(1000);
746 System
.out
.println(utils
.getDateTime() + "OfficeProvider:Owp: stop ");
753 private void deleteFilesAndDirector(File file
)
758 File files
[] = f
.listFiles();
759 for(int i
= 0; i
< files
.length
; i
++)
761 deleteFilesAndDirector(files
[i
]);