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 (com
.sun
.star
.uno
.Exception e
)
93 System
.out
.println("Couldn't backup user layer");
96 catch (java
.io
.IOException e
)
98 System
.out
.println("Couldn't backup user layer");
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();
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
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
= ";";
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
);
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;
194 dbg("Local Connection trying to start the Office");
196 //ensure that a pending officewatcher gets finished before a new
198 final OfficeWatcher ow_old
= (OfficeWatcher
) param
.get("Watcher");
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.
210 util
.utils
.validateAppExecutionCommand(cmd
, (String
) param
.get("OperatingSystem"));
211 if (errorMessage
.startsWith("Error"))
213 System
.out
.println(errorMessage
);
216 bAppExecutionHasWarning
= !errorMessage
.equals("OK");
218 final DynamicClassLoader dcl
= new DynamicClassLoader();
219 final LogWriter log
= (LogWriter
) dcl
.getInstance(
220 (String
) param
.get("LogWriter"));
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();
241 param
.put("AppProvider", ph
);
242 final OfficeWatcher ow
= new OfficeWatcher(param
);
243 param
.put("Watcher", ow
);
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();
269 util
.utils
.pause(500 * k
);
276 System
.out
.println("Exception while connecting.\n" + exConnectFailed
);
279 System
.out
.println(exc
);
281 if (bAppExecutionHasWarning
)
283 System
.out
.println(errorMessage
);
286 else if (isExecutable
)
288 backupUserLayer(param
, msf
);
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"));
305 * @throws com.sun.star.uno.Exception
306 * @throws com.sun.star.uno.RuntimeException
307 * @throws com.sun.star.connection.NoConnectException
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
,
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)
336 xMSF
= UnoRuntime
.queryInterface(XMultiServiceFactory
.class, rInitialObject
);
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");
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");
379 dbg("OfficeWatcher seems to be finished");
388 return disposeOffice(msf
, param
);
394 final String cncstr
= "uno:" + param
.get("ConnectionString") +
395 ";urp;StarOffice.ServiceManager";
396 dbg("try to connect office");
397 msf
= connectOffice(cncstr
);
401 return disposeOffice(msf
, param
);
404 dbg("closeExistingOffice finished");
408 private XMultiServiceFactory
connectOffice(String cncstr
)
410 XMultiServiceFactory msf
= null;
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
);
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;
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"));
468 final boolean allClosed
= closeAllWindows(desk
);
472 dbg("Couldn't close all office windows!");
475 dbg("Trying to terminate the desktop");
478 dbg("Desktop terminated");
481 catch (com
.sun
.star
.uno
.Exception ue
)
485 catch (com
.sun
.star
.lang
.DisposedException ue
)
491 final ProcessHandler ph
= (ProcessHandler
) param
.get("AppProvider");
495 // dispose watcher in case it's still running.
496 final OfficeWatcher ow
= (OfficeWatcher
) param
.get("Watcher");
498 if ((ow
!= null) && ow
.isAlive())
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
[]
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
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());
542 private boolean closeAllWindows(XDesktop desk
)
544 final XEnumerationAccess compEnumAccess
= desk
.getComponents();
545 final XEnumeration compEnum
= compEnumAccess
.createEnumeration();
550 while (compEnum
.hasMoreElements())
552 final XCloseable closer
= UnoRuntime
.queryInterface(XCloseable
.class, compEnum
.nextElement());
560 catch (com
.sun
.star
.util
.CloseVetoException cve
)
564 catch (com
.sun
.star
.container
.NoSuchElementException nsee
)
568 catch (com
.sun
.star
.lang
.WrappedTargetException wte
)
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
)
591 final int idx
= dir
.indexOf("file://");
593 final int idx2
= dir
.indexOf("file:///");
595 // remove leading 'file://'
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) != '/')
613 // remove leading '/' and replace others with '\' on windows machines
614 final String sep
= System
.getProperty("file.separator");
616 if (sep
.equalsIgnoreCase("\\"))
620 sysDir
= sysDir
.substring(1);
625 sysDir
= "//" + sysDir
;
627 sysDir
= sysDir
.replace('/', '\\');
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
);
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");
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
)
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
)
707 System
.out
.println(utils
.getDateTime() + "OfficeProvider:Owp: start ");
711 System
.out
.println(utils
.getDateTime() + "OfficeProvider:Owp: ping ");
713 System
.out
.println(utils
.getDateTime() + "OfficeProvider:Owp: sleep ");
714 util
.utils
.pause(1000);
724 System
.out
.println(utils
.getDateTime() + "OfficeProvider:Owp: stop ");
731 private void deleteFilesAndDirector(File file
)
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();
744 System
.out
.println("delete failed");
749 boolean bDeleteOk
= f
.delete();
751 System
.out
.println("delete failed");