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.bridge.UnoUrlResolver;
21 import com
.sun
.star
.beans
.XFastPropertySet
;
22 import com
.sun
.star
.bridge
.XUnoUrlResolver
;
23 import com
.sun
.star
.container
.XEnumeration
;
24 import com
.sun
.star
.container
.XEnumerationAccess
;
25 import com
.sun
.star
.frame
.XDesktop
;
26 import com
.sun
.star
.lang
.XMultiComponentFactory
;
27 import com
.sun
.star
.lang
.XMultiServiceFactory
;
28 import com
.sun
.star
.uno
.UnoRuntime
;
29 import com
.sun
.star
.uno
.XComponentContext
;
30 import com
.sun
.star
.util
.XCloseable
;
31 import com
.sun
.star
.util
.XStringSubstitution
;
34 import java
.io
.PrintWriter
;
35 import java
.util
.StringTokenizer
;
37 import lib
.TestParameters
;
39 import share
.DescEntry
;
40 import share
.LogWriter
;
42 import util
.DynamicClassLoader
;
43 import util
.PropertyName
;
47 * This class will connect the office and start it if possible
50 public class OfficeProvider
implements AppProvider
53 private static boolean debug
= false;
56 * copy the user layer to a safe place, usualy to $TMP/user_backup$USER
60 public void backupUserLayer(TestParameters param
, XMultiServiceFactory msf
)
64 final XStringSubstitution sts
= createStringSubstitution(msf
);
65 debug
= param
.getBool(PropertyName
.DEBUG_IS_ACTIVE
);
67 String userLayer
= sts
.getSubstituteVariableValue("$(user)");
68 userLayer
= getDirSys(userLayer
);
69 param
.put("userLayer", userLayer
);
71 final String copyLayer
= util
.utils
.getUsersTempDir() + System
.getProperty("file.separator") +
73 System
.getProperty("user.name");
74 param
.put("copyLayer", copyLayer
);
77 dbg(" copy '" + userLayer
+ "' ->" + copyLayer
+ "'");
78 // Slow machines the copy job could spend some time. To avoid activating of OfficeWatcher it must be pinged
79 OfficeWatcherPing owp
= new OfficeWatcherPing((OfficeWatcher
) param
.get(PropertyName
.OFFICE_WATCHER
));
82 deleteFilesAndDirector (new File(copyLayer
));
83 FileTools
.copyDirectory(new File(userLayer
), new File(copyLayer
), new String
[]
91 catch (com
.sun
.star
.container
.NoSuchElementException e
)
93 System
.out
.println("User Variable '$(user)' not defined.");
95 catch (java
.io
.IOException e
)
97 System
.out
.println("Couldn't backup user layer");
103 * Dispose the office.
104 * This method can only be used, if the office was connected in the first
105 * 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
= (XMultiServiceFactory
) param
.getMSF();
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
)
147 * Method to get the ServiceManager of an Office
151 public Object
getManager(lib
.TestParameters param
)
153 String errorMessage
= null;
154 boolean bAppExecutionHasWarning
= false;
155 debug
= param
.getBool(PropertyName
.DEBUG_IS_ACTIVE
);
157 String additionalArgs
= (String
) param
.get(
158 "AdditionalConnectionArguments");
160 if (additionalArgs
== null)
162 additionalArgs
= ";";
166 additionalArgs
= "," + additionalArgs
+ ";";
169 final String cncstr
= "uno:" + param
.get("ConnectionString") + ";urp" +
170 additionalArgs
+ "StarOffice.ServiceManager";
172 System
.out
.println("Connecting the Office with " + cncstr
);
174 XMultiServiceFactory msf
= connectOffice(cncstr
);
176 // if the office is running and the office crashes while testing it could
177 // be usesfull to restart the office if possible and continuing the tests.
178 // Example: The UNO-API-Tests in the projects will be executed by calling
179 // 'damke'. This connects to an existing office. If the office crashes
180 // it is useful to restart the office and continuing the tests.
181 if ((param
.getBool(util
.PropertyName
.AUTO_RESTART
)) && (msf
!= null))
183 makeAppExecCommand(msf
, param
);
189 Exception exConnectFailed
= null;
190 boolean isExecutable
= false;
191 boolean isAppKnown
= ((cncstr
.indexOf("host=localhost") > 0) || (cncstr
.indexOf("pipe,name=") > 0));
192 isAppKnown
&= !((String
) param
.get("AppExecutionCommand")).equals("");
196 dbg("Local Connection trying to start the Office");
198 //ensure that a pending officewatcher gets finished before a new
200 final OfficeWatcher ow_old
= (OfficeWatcher
) param
.get("Watcher");
204 ow_old
.finish
= true;
207 final String cmd
= (String
) param
.get("AppExecutionCommand");
208 dbg("AppExecutionCommand: " + cmd
);
209 // validate the AppExecutionCommand, but try it out anyway.
210 // keep the error message for later.
212 util
.utils
.validateAppExecutionCommand(cmd
, (String
) param
.get("OperatingSystem"));
213 if (errorMessage
.startsWith("Error"))
215 System
.out
.println(errorMessage
);
218 bAppExecutionHasWarning
= !errorMessage
.equals("OK");
220 final DynamicClassLoader dcl
= new DynamicClassLoader();
221 final LogWriter log
= (LogWriter
) dcl
.getInstance(
222 (String
) param
.get("LogWriter"));
225 final DescEntry Entry
= new DescEntry();
226 Entry
.entryName
= "office";
227 Entry
.longName
= "office";
228 Entry
.EntryType
= "placebo";
229 Entry
.isOptional
= false;
230 Entry
.isToTest
= false;
231 Entry
.SubEntryCount
= 0;
232 Entry
.hasErrorMsg
= false;
233 Entry
.State
= "non possible";
234 Entry
.UserDefinedParams
= param
;
236 log
.initialize(Entry
, debug
);
238 final ProcessHandler ph
= new ProcessHandler(cmd
, (PrintWriter
) log
);
239 isExecutable
= ph
.executeAsynchronously();
243 param
.put("AppProvider", ph
);
244 final OfficeWatcher ow
= new OfficeWatcher(param
);
245 param
.put("Watcher", ow
);
252 // wait up to 21 seconds to get an office connection
253 while ((k
< 42) && (msf
== null))
257 msf
= connect(cncstr
);
259 catch (com
.sun
.star
.uno
.Exception ue
)
261 exConnectFailed
= ue
;
262 exc
= ue
.getMessage();
264 catch (java
.lang
.Exception je
)
266 exConnectFailed
= je
;
267 exc
= je
.getMessage();
273 Thread
.sleep(k
* 500);
275 catch (InterruptedException ex
)
284 System
.out
.println("Exception while connecting.\n" + exConnectFailed
);
287 System
.out
.println(exc
);
289 if (bAppExecutionHasWarning
)
291 System
.out
.println(errorMessage
);
294 else if (isExecutable
)
296 if (!param
.getBool(util
.PropertyName
.DONT_BACKUP_USERLAYER
))
298 backupUserLayer(param
, msf
);
304 System
.out
.println("Could not connect an Office and cannot start one.\n".concat("please start an office with following parameter:\n").
305 concat("\nsoffice --accept=").concat((String
) param
.get("ConnectionString")).concat(";urp;\n"));
306 if (bAppExecutionHasWarning
)
308 System
.out
.println(errorMessage
);
320 * @throws com.sun.star.uno.Exception
321 * @throws com.sun.star.uno.RuntimeException
322 * @throws com.sun.star.connection.NoConnectException
325 protected static XMultiServiceFactory
connect(String connectStr
)
326 throws com
.sun
.star
.uno
.Exception
,
327 com
.sun
.star
.uno
.RuntimeException
,
328 com
.sun
.star
.connection
.NoConnectException
,
332 // Get component context
333 final XComponentContext xcomponentcontext
= com
.sun
.star
.comp
.helper
.Bootstrap
.createInitialComponentContext(null);
335 // initial serviceManager
336 final XMultiComponentFactory xLocalServiceManager
= xcomponentcontext
.getServiceManager();
338 // create a connector, so that it can contact the office
339 // XUnoUrlResolver urlResolver = UnoUrlResolver.create(xcomponentcontext);
340 final Object xUrlResolver
= xLocalServiceManager
.createInstanceWithContext("com.sun.star.bridge.UnoUrlResolver", xcomponentcontext
);
341 final XUnoUrlResolver urlResolver
= UnoRuntime
.queryInterface(XUnoUrlResolver
.class, xUrlResolver
);
343 final Object rInitialObject
= urlResolver
.resolve(connectStr
);
345 XMultiServiceFactory xMSF
= null;
347 if (rInitialObject
!= null)
352 xMSF
= UnoRuntime
.queryInterface(XMultiServiceFactory
.class, rInitialObject
);
360 * @param param The test parameters.
361 * @param closeIfPossible If true, close even if
362 * it was running before the test
364 public boolean closeExistingOffice(lib
.TestParameters param
, boolean closeIfPossible
)
367 XMultiServiceFactory msf
= (XMultiServiceFactory
) param
.getMSF();
368 final boolean alreadyConnected
= (msf
!= null);
369 debug
= param
.getBool(PropertyName
.DEBUG_IS_ACTIVE
);
371 if (alreadyConnected
)
373 dbg("try to get ProcessHandler");
375 final ProcessHandler ph
= (ProcessHandler
) param
.get("AppProvider");
379 dbg("ProcessHandler != null");
381 disposeOffice(msf
, param
);
383 // dispose watcher in case it's still running.
384 dbg("try to get OfficeWatcher");
386 final OfficeWatcher ow
= (OfficeWatcher
) param
.get("Watcher");
388 if ((ow
!= null) && ow
.isAlive())
390 dbg("OfficeWatcher will be finished");
395 dbg("OfficeWatcher seems to be finished");
404 return disposeOffice(msf
, param
);
410 final String cncstr
= "uno:" + param
.get("ConnectionString") +
411 ";urp;StarOffice.ServiceManager";
412 dbg("try to connect office");
413 msf
= connectOffice(cncstr
);
417 return disposeOffice(msf
, param
);
420 dbg("closeExistingOffice finished");
424 private XMultiServiceFactory
connectOffice(String cncstr
)
426 XMultiServiceFactory msf
= null;
430 dbg("trying to connect to " + cncstr
);
434 msf
= connect(cncstr
);
436 catch (com
.sun
.star
.uno
.Exception ue
)
438 exc
= ue
.getMessage();
440 catch (java
.lang
.Exception je
)
442 exc
= je
.getMessage();
445 if (debug
&& exc
!= null && exc
.length() != 0)
447 dbg("Could not connect an Office. " + exc
);
453 private synchronized boolean disposeOffice(XMultiServiceFactory msf
,
454 TestParameters param
)
456 XDesktop desk
= null;
458 debug
= param
.getBool(PropertyName
.DEBUG_IS_ACTIVE
);
460 boolean result
= true;
465 // disable QuickStarter
468 Object quickStarter
= msf
.createInstance("com.sun.star.office.Quickstart");
469 XFastPropertySet fps
= UnoRuntime
.queryInterface(XFastPropertySet
.class, quickStarter
);
470 fps
.setFastPropertyValue(0, false);
472 catch (com
.sun
.star
.uno
.Exception ex
)
474 dbg("ERROR: Could not disable QuickStarter: " + ex
.toString());
479 desk
= UnoRuntime
.queryInterface(XDesktop
.class, msf
.createInstance("com.sun.star.frame.Desktop"));
484 final boolean allClosed
= closeAllWindows(desk
);
488 dbg("Couldn't close all office windows!");
491 dbg("Trying to terminate the desktop");
494 dbg("Desktop terminated");
498 final int closeTime
= param
.getInt(util
.PropertyName
.OFFICE_CLOSE_TIME_OUT
);
499 dbg("the Office has " + closeTime
/ 1000 + " seconds for closing...");
500 Thread
.sleep(closeTime
);
502 catch (java
.lang
.InterruptedException e
)
507 catch (com
.sun
.star
.uno
.Exception ue
)
511 catch (com
.sun
.star
.lang
.DisposedException ue
)
517 final String AppKillCommand
= (String
) param
.get(util
.PropertyName
.APP_KILL_COMMAND
);
518 if (AppKillCommand
!= null)
520 String sAppKillCommand
= StringHelper
.removeSurroundQuoteIfExists(AppKillCommand
);
521 final StringTokenizer aKillCommandToken
= new StringTokenizer(sAppKillCommand
, ";");
522 while (aKillCommandToken
.hasMoreTokens())
524 final String sKillCommand
= aKillCommandToken
.nextToken();
525 dbg("User defined an application to destroy the started process. Trying to execute: " + sKillCommand
);
527 final ProcessHandler pHdl
= new ProcessHandler(sKillCommand
, 1000); // 3000 seems to be too long
534 final ProcessHandler ph
= (ProcessHandler
) param
.get("AppProvider");
538 // dispose watcher in case it's still running.
539 final OfficeWatcher ow
= (OfficeWatcher
) param
.get("Watcher");
541 if ((ow
!= null) && ow
.isAlive())
549 param
.remove("AppProvider");
550 param
.remove("ServiceFactory");
552 if (!param
.getBool(util
.PropertyName
.DONT_BACKUP_USERLAYER
))
554 //copy user_backup into user layer
557 final String userLayer
= (String
) param
.get("userLayer");
558 final String copyLayer
= (String
) param
.get("copyLayer");
559 if (userLayer
!= null && copyLayer
!= null)
561 deleteFilesAndDirector(new File(userLayer
));
562 final File copyFile
= new File(copyLayer
);
563 dbg("copy '" + copyFile
+ "' -> '" + userLayer
+ "'");
564 FileTools
.copyDirectory(copyFile
, new File(userLayer
), new String
[]
568 dbg("copy '" + copyFile
+ "' -> '" + userLayer
+ "' finished");
570 // remove all user_backup folder in temp dir
571 // this is for the case the runner was killed and some old backup folder still stay in temp dir
577 System
.out
.println("Cannot copy layer: '" + copyLayer
+ "' back to user layer: '" + userLayer
+ "'");
580 catch (java
.io
.IOException e
)
582 dbg("Couldn't recover from backup\n" + e
.getMessage());
588 protected boolean closeAllWindows(XDesktop desk
)
590 final XEnumerationAccess compEnumAccess
= desk
.getComponents();
591 final XEnumeration compEnum
= compEnumAccess
.createEnumeration();
596 while (compEnum
.hasMoreElements())
598 final XCloseable closer
= UnoRuntime
.queryInterface(XCloseable
.class, compEnum
.nextElement());
606 catch (com
.sun
.star
.util
.CloseVetoException cve
)
610 catch (com
.sun
.star
.container
.NoSuchElementException nsee
)
614 catch (com
.sun
.star
.lang
.WrappedTargetException wte
)
622 public static XStringSubstitution
createStringSubstitution(XMultiServiceFactory xMSF
)
624 Object xPathSubst
= null;
628 xPathSubst
= xMSF
.createInstance(
629 "com.sun.star.util.PathSubstitution");
631 catch (com
.sun
.star
.uno
.Exception e
)
636 if (xPathSubst
!= null)
638 return UnoRuntime
.queryInterface(XStringSubstitution
.class, xPathSubst
);
647 * converts directory without 'file:///' prefix.
648 * and System dependend file separator
652 public static String
getDirSys(String dir
)
656 final int idx
= dir
.indexOf("file://");
658 final int idx2
= dir
.indexOf("file:///");
660 // remove leading 'file://'
667 sysDir
= dir
.substring("file://".length());
670 sysDir
= utils
.replaceAll13(sysDir
, "%20", " ");
672 // append '/' if not there (e.g. linux)
673 if (sysDir
.charAt(sysDir
.length() - 1) != '/')
678 // remove leading '/' and replace others with '\' on windows machines
679 final String sep
= System
.getProperty("file.separator");
681 if (sep
.equalsIgnoreCase("\\"))
685 sysDir
= sysDir
.substring(1);
690 sysDir
= "//" + sysDir
;
692 sysDir
= sysDir
.replace('/', '\\');
699 * If the office is connected but the <CODE>AppExecutionCommand</CODE> is not set,
700 * this function asks the office for its location and fill the
701 * <CODE>AppExecutionCommand</CODE> with valid contet.
702 * This function was only called if parameter <CODE>AutoRestart</CODE> is set.
703 * @param msf the <CODE>MultiServiceFactory</CODE>
704 * @param param the <CODE>TestParameters</CODE>
706 private static void makeAppExecCommand(XMultiServiceFactory msf
, TestParameters param
)
708 debug
= param
.getBool(PropertyName
.DEBUG_IS_ACTIVE
);
710 // get existing AppExecutionCommand if available, else empty string
711 String command
= (String
) param
.get(util
.PropertyName
.APP_EXECUTION_COMMAND
);
713 String connectionString
;
714 if (param
.getBool(util
.PropertyName
.USE_PIPE_CONNECTION
) == true)
716 // This is the default behaviour
717 connectionString
= (String
) param
.get(util
.PropertyName
.PIPE_CONNECTION_STRING
);
721 // is used if UsePipeConnection=false
722 connectionString
= (String
) param
.get(util
.PropertyName
.CONNECTION_STRING
);
725 String sysBinDir
= "";
729 sysBinDir
= utils
.getSystemURL(utils
.expandMacro(msf
, "$SYSBINDIR"));
731 catch (java
.lang
.Exception e
)
733 dbg("could not get system binary directory");
737 // does the existing command show to the connected office?
738 if (command
.indexOf(sysBinDir
) == -1)
740 command
= sysBinDir
+ System
.getProperty("file.separator") + "soffice" +
741 " --norestore --accept=" + connectionString
+ ";urp;";
744 dbg("update AppExecutionCommand: " + command
);
746 param
.put(util
.PropertyName
.APP_EXECUTION_COMMAND
, command
);
749 private static void dbg(String message
)
753 System
.out
.println(utils
.getDateTime() + "OfficeProvider: " + message
);
758 private class OfficeWatcherPing
extends Thread
761 private final OfficeWatcher ow
;
762 private boolean bStop
= false;
764 public OfficeWatcherPing(OfficeWatcher ow
)
772 System
.out
.println(utils
.getDateTime() + "OfficeProvider:Owp: start ");
776 System
.out
.println(utils
.getDateTime() + "OfficeProvider:Owp: ping ");
780 System
.out
.println(utils
.getDateTime() + "OfficeProvider:Owp: sleep ");
781 OfficeWatcherPing
.sleep(1000); // 5000
783 catch (InterruptedException ex
)
785 ex
.printStackTrace();
796 System
.out
.println(utils
.getDateTime() + "OfficeProvider:Owp: stop ");
803 private void deleteFilesAndDirector(File file
)
808 File files
[] = f
.listFiles();
809 for(int i
= 0; i
< files
.length
; i
++)
811 deleteFilesAndDirector(files
[i
]);