1 /*************************************************************************
3 * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
5 * Copyright 2000, 2010 Oracle and/or its affiliates.
7 * OpenOffice.org - a multi-platform office productivity suite
9 * This file is part of OpenOffice.org.
11 * OpenOffice.org is free software: you can redistribute it and/or modify
12 * it under the terms of the GNU Lesser General Public License version 3
13 * only, as published by the Free Software Foundation.
15 * OpenOffice.org is distributed in the hope that it will be useful,
16 * but WITHOUT ANY WARRANTY; without even the implied warranty of
17 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
18 * GNU Lesser General Public License version 3 for more details
19 * (a copy is included in the LICENSE file that accompanied this code).
21 * You should have received a copy of the GNU Lesser General Public License
22 * version 3 along with OpenOffice.org. If not, see
23 * <http://www.openoffice.org/license.html>
24 * for a copy of the LGPLv3 License.
26 ************************************************************************/
29 //import com.sun.star.bridge.UnoUrlResolver;
30 import com
.sun
.star
.beans
.XFastPropertySet
;
31 import com
.sun
.star
.bridge
.XUnoUrlResolver
;
32 import com
.sun
.star
.container
.XEnumeration
;
33 import com
.sun
.star
.container
.XEnumerationAccess
;
34 import com
.sun
.star
.frame
.XDesktop
;
35 import com
.sun
.star
.lang
.XMultiComponentFactory
;
36 import com
.sun
.star
.lang
.XMultiServiceFactory
;
37 import com
.sun
.star
.uno
.UnoRuntime
;
38 import com
.sun
.star
.uno
.XComponentContext
;
39 import com
.sun
.star
.util
.XCloseable
;
40 import com
.sun
.star
.util
.XStringSubstitution
;
43 import java
.io
.PrintWriter
;
44 import java
.util
.StringTokenizer
;
46 import lib
.TestParameters
;
48 import share
.DescEntry
;
49 import share
.LogWriter
;
51 import util
.DynamicClassLoader
;
52 import util
.PropertyName
;
56 * This class will connect the office and start it if possible
59 public class OfficeProvider
implements AppProvider
62 private static boolean debug
= false;
65 * copy the user layer to a safe place, usualy to $TMP/user_backup$USER
69 public void backupUserLayer(TestParameters param
, XMultiServiceFactory msf
)
73 final XStringSubstitution sts
= createStringSubstitution(msf
);
74 debug
= param
.getBool(PropertyName
.DEBUG_IS_ACTIVE
);
76 String userLayer
= sts
.getSubstituteVariableValue("$(user)");
77 userLayer
= getDirSys(userLayer
);
78 param
.put("userLayer", userLayer
);
80 final String copyLayer
= util
.utils
.getUsersTempDir() + System
.getProperty("file.separator") +
82 System
.getProperty("user.name");
83 param
.put("copyLayer", copyLayer
);
86 dbg(" copy '" + userLayer
+ "' ->" + copyLayer
+ "'");
87 // Slow machines the copy job could spend some time. To avoid activating of OfficeWatcher it must be pinged
88 OfficeWatcherPing owp
= new OfficeWatcherPing((OfficeWatcher
) param
.get(PropertyName
.OFFICE_WATCHER
));
91 deleteFilesAndDirector (new File(copyLayer
));
92 FileTools
.copyDirectory(new File(userLayer
), new File(copyLayer
), new String
[]
100 catch (com
.sun
.star
.container
.NoSuchElementException e
)
102 System
.out
.println("User Variable '$(user)' not defined.");
104 catch (java
.io
.IOException e
)
106 System
.out
.println("Couldn't backup user layer");
112 * Dispose the office.
113 * This method can only be used, if the office was connected in the first
114 * place: getManager() was called first.
116 * @return return true if desktop is terminates, else false
118 public boolean disposeManager(lib
.TestParameters param
)
121 XMultiServiceFactory msf
= (XMultiServiceFactory
) param
.getMSF();
129 XDesktop desk
= null;
133 desk
= UnoRuntime
.queryInterface(XDesktop
.class, msf
.createInstance("com.sun.star.frame.Desktop"));
135 catch (com
.sun
.star
.uno
.Exception ue
)
156 * Method to get the ServiceManager of an Office
160 public Object
getManager(lib
.TestParameters param
)
162 String errorMessage
= null;
163 boolean bAppExecutionHasWarning
= false;
164 debug
= param
.getBool(PropertyName
.DEBUG_IS_ACTIVE
);
166 String additionalArgs
= (String
) param
.get(
167 "AdditionalConnectionArguments");
169 if (additionalArgs
== null)
171 additionalArgs
= ";";
175 additionalArgs
= "," + additionalArgs
+ ";";
178 final String cncstr
= "uno:" + param
.get("ConnectionString") + ";urp" +
179 additionalArgs
+ "StarOffice.ServiceManager";
181 System
.out
.println("Connecting the Office with " + cncstr
);
183 XMultiServiceFactory msf
= connectOffice(cncstr
);
185 // if the office is running and the office crashes while testing it could
186 // be usesfull to restart the office if possible and continuing the tests.
187 // Example: The UNO-API-Tests in the projects will be executed by calling
188 // 'damke'. This connects to an existing office. If the office crashes
189 // it is usefull to restart the office and continuing the tests.
190 if ((param
.getBool(util
.PropertyName
.AUTO_RESTART
)) && (msf
!= null))
192 makeAppExecCommand(msf
, param
);
198 Exception exConnectFailed
= null;
199 boolean isExecutable
= false;
200 boolean isAppKnown
= ((cncstr
.indexOf("host=localhost") > 0) || (cncstr
.indexOf("pipe,name=") > 0));
201 isAppKnown
&= !((String
) param
.get("AppExecutionCommand")).equals("");
205 dbg("Local Connection trying to start the Office");
207 //ensure that a pending officewatcher gets finished before a new
209 final OfficeWatcher ow_old
= (OfficeWatcher
) param
.get("Watcher");
213 ow_old
.finish
= true;
216 final String cmd
= (String
) param
.get("AppExecutionCommand");
217 dbg("AppExecutionCommand: " + cmd
);
218 // validate the AppExecutionCommand, but try it out anyway.
219 // keep the error message for later.
221 util
.utils
.validateAppExecutionCommand(cmd
, (String
) param
.get("OperatingSystem"));
222 if (errorMessage
.startsWith("Error"))
224 System
.out
.println(errorMessage
);
227 bAppExecutionHasWarning
= !errorMessage
.equals("OK");
229 final DynamicClassLoader dcl
= new DynamicClassLoader();
230 final LogWriter log
= (LogWriter
) dcl
.getInstance(
231 (String
) param
.get("LogWriter"));
234 final DescEntry Entry
= new DescEntry();
235 Entry
.entryName
= "office";
236 Entry
.longName
= "office";
237 Entry
.EntryType
= "placebo";
238 Entry
.isOptional
= false;
239 Entry
.isToTest
= false;
240 Entry
.SubEntryCount
= 0;
241 Entry
.hasErrorMsg
= false;
242 Entry
.State
= "non possible";
243 Entry
.UserDefinedParams
= param
;
245 log
.initialize(Entry
, debug
);
247 final ProcessHandler ph
= new ProcessHandler(cmd
, (PrintWriter
) log
);
248 isExecutable
= ph
.executeAsynchronously();
252 param
.put("AppProvider", ph
);
253 final OfficeWatcher ow
= new OfficeWatcher(param
);
254 param
.put("Watcher", ow
);
261 // wait up to 21 seconds to get an office connection
262 while ((k
< 42) && (msf
== null))
266 msf
= connect(cncstr
);
268 catch (com
.sun
.star
.uno
.Exception ue
)
270 exConnectFailed
= ue
;
271 exc
= ue
.getMessage();
273 catch (java
.lang
.Exception je
)
275 exConnectFailed
= je
;
276 exc
= je
.getMessage();
282 Thread
.sleep(k
* 500);
284 catch (InterruptedException ex
)
293 System
.out
.println("Exception while connecting.\n" + exConnectFailed
);
296 System
.out
.println(exc
);
298 if (bAppExecutionHasWarning
)
300 System
.out
.println(errorMessage
);
303 else if (isExecutable
)
305 if (!param
.getBool(util
.PropertyName
.DONT_BACKUP_USERLAYER
))
307 backupUserLayer(param
, msf
);
313 System
.out
.println("Could not connect an Office and cannot start one.\n".concat("please start an office with following parameter:\n").
314 concat("\nsoffice --accept=").concat((String
) param
.get("ConnectionString")).concat(";urp;\n"));
315 if (bAppExecutionHasWarning
)
317 System
.out
.println(errorMessage
);
329 * @throws com.sun.star.uno.Exception
330 * @throws com.sun.star.uno.RuntimeException
331 * @throws com.sun.star.connection.NoConnectException
334 protected static XMultiServiceFactory
connect(String connectStr
)
335 throws com
.sun
.star
.uno
.Exception
,
336 com
.sun
.star
.uno
.RuntimeException
,
337 com
.sun
.star
.connection
.NoConnectException
,
341 // Get component context
342 final XComponentContext xcomponentcontext
= com
.sun
.star
.comp
.helper
.Bootstrap
.createInitialComponentContext(null);
344 // initial serviceManager
345 final XMultiComponentFactory xLocalServiceManager
= xcomponentcontext
.getServiceManager();
347 // create a connector, so that it can contact the office
348 // XUnoUrlResolver urlResolver = UnoUrlResolver.create(xcomponentcontext);
349 final Object xUrlResolver
= xLocalServiceManager
.createInstanceWithContext("com.sun.star.bridge.UnoUrlResolver", xcomponentcontext
);
350 final XUnoUrlResolver urlResolver
= UnoRuntime
.queryInterface(XUnoUrlResolver
.class, xUrlResolver
);
352 final Object rInitialObject
= urlResolver
.resolve(connectStr
);
354 XMultiServiceFactory xMSF
= null;
356 if (rInitialObject
!= null)
361 xMSF
= UnoRuntime
.queryInterface(XMultiServiceFactory
.class, rInitialObject
);
369 * @param param The test parameters.
370 * @param closeIfPossible If true, close even if
371 * it was running before the test
373 public boolean closeExistingOffice(lib
.TestParameters param
, boolean closeIfPossible
)
376 XMultiServiceFactory msf
= (XMultiServiceFactory
) param
.getMSF();
377 final boolean alreadyConnected
= (msf
!= null);
378 debug
= param
.getBool(PropertyName
.DEBUG_IS_ACTIVE
);
380 if (alreadyConnected
)
382 dbg("try to get ProcessHandler");
384 final ProcessHandler ph
= (ProcessHandler
) param
.get("AppProvider");
388 dbg("ProcessHandler != null");
390 disposeOffice(msf
, param
);
392 // dispose watcher in case it's still running.
393 dbg("try to get OfficeWatcher");
395 final OfficeWatcher ow
= (OfficeWatcher
) param
.get("Watcher");
397 if ((ow
!= null) && ow
.isAlive())
399 dbg("OfficeWatcher will be finished");
404 dbg("OfficeWatcher seems to be finished");
413 return disposeOffice(msf
, param
);
419 final String cncstr
= "uno:" + param
.get("ConnectionString") +
420 ";urp;StarOffice.ServiceManager";
421 dbg("try to connect office");
422 msf
= connectOffice(cncstr
);
426 return disposeOffice(msf
, param
);
429 dbg("closeExistingOffice finished");
433 private XMultiServiceFactory
connectOffice(String cncstr
)
435 XMultiServiceFactory msf
= null;
439 dbg("trying to connect to " + cncstr
);
443 msf
= connect(cncstr
);
445 catch (com
.sun
.star
.uno
.Exception ue
)
447 exc
= ue
.getMessage();
449 catch (java
.lang
.Exception je
)
451 exc
= je
.getMessage();
454 if (debug
&& exc
!= null && exc
.length() != 0)
460 dbg("Could not connect an Office. " + exc
);
466 private synchronized boolean disposeOffice(XMultiServiceFactory msf
,
467 TestParameters param
)
469 XDesktop desk
= null;
471 debug
= param
.getBool(PropertyName
.DEBUG_IS_ACTIVE
);
473 boolean result
= true;
478 // disable QuickStarter
481 Object quickStarter
= msf
.createInstance("com.sun.star.office.Quickstart");
482 XFastPropertySet fps
= UnoRuntime
.queryInterface(XFastPropertySet
.class, quickStarter
);
483 fps
.setFastPropertyValue(0, false);
485 catch (com
.sun
.star
.uno
.Exception ex
)
487 dbg("ERROR: Could not disable QuickStarter: " + ex
.toString());
492 desk
= UnoRuntime
.queryInterface(XDesktop
.class, msf
.createInstance("com.sun.star.frame.Desktop"));
497 final boolean allClosed
= closeAllWindows(desk
);
501 dbg("Couldn't close all office windows!");
504 dbg("Trying to terminate the desktop");
507 dbg("Desktop terminated");
511 final int closeTime
= param
.getInt(util
.PropertyName
.OFFICE_CLOSE_TIME_OUT
);
512 dbg("the Office has " + closeTime
/ 1000 + " seconds for closing...");
513 Thread
.sleep(closeTime
);
515 catch (java
.lang
.InterruptedException e
)
520 catch (com
.sun
.star
.uno
.Exception ue
)
524 catch (com
.sun
.star
.lang
.DisposedException ue
)
530 final String AppKillCommand
= (String
) param
.get(util
.PropertyName
.APP_KILL_COMMAND
);
531 if (AppKillCommand
!= null)
533 String sAppKillCommand
= StringHelper
.removeSurroundQuoteIfExists(AppKillCommand
);
534 final StringTokenizer aKillCommandToken
= new StringTokenizer(sAppKillCommand
, ";");
535 while (aKillCommandToken
.hasMoreTokens())
537 final String sKillCommand
= aKillCommandToken
.nextToken();
538 dbg("User defined an application to destroy the started process. Trying to execute: " + sKillCommand
);
540 final ProcessHandler pHdl
= new ProcessHandler(sKillCommand
, 1000); // 3000 seems to be too long
547 final ProcessHandler ph
= (ProcessHandler
) param
.get("AppProvider");
551 // dispose watcher in case it's still running.
552 final OfficeWatcher ow
= (OfficeWatcher
) param
.get("Watcher");
554 if ((ow
!= null) && ow
.isAlive())
562 param
.remove("AppProvider");
563 param
.remove("ServiceFactory");
565 if (!param
.getBool(util
.PropertyName
.DONT_BACKUP_USERLAYER
))
567 //copy user_backup into user layer
570 final String userLayer
= (String
) param
.get("userLayer");
571 final String copyLayer
= (String
) param
.get("copyLayer");
572 if (userLayer
!= null && copyLayer
!= null)
574 deleteFilesAndDirector(new File(userLayer
));
575 final File copyFile
= new File(copyLayer
);
576 dbg("copy '" + copyFile
+ "' -> '" + userLayer
+ "'");
577 FileTools
.copyDirectory(copyFile
, new File(userLayer
), new String
[]
581 dbg("copy '" + copyFile
+ "' -> '" + userLayer
+ "' finished");
583 // remove all user_backup folder in temp dir
584 // this is for the case the runner was killed and some old backup folder still stay in temp dir
590 System
.out
.println("Cannot copy layer: '" + copyLayer
+ "' back to user layer: '" + userLayer
+ "'");
593 catch (java
.io
.IOException e
)
595 dbg("Couldn't recover from backup\n" + e
.getMessage());
601 protected boolean closeAllWindows(XDesktop desk
)
603 final XEnumerationAccess compEnumAccess
= desk
.getComponents();
604 final XEnumeration compEnum
= compEnumAccess
.createEnumeration();
609 while (compEnum
.hasMoreElements())
611 final XCloseable closer
= UnoRuntime
.queryInterface(XCloseable
.class, compEnum
.nextElement());
619 catch (com
.sun
.star
.util
.CloseVetoException cve
)
623 catch (com
.sun
.star
.container
.NoSuchElementException nsee
)
627 catch (com
.sun
.star
.lang
.WrappedTargetException wte
)
635 public static XStringSubstitution
createStringSubstitution(XMultiServiceFactory xMSF
)
637 Object xPathSubst
= null;
641 xPathSubst
= xMSF
.createInstance(
642 "com.sun.star.util.PathSubstitution");
644 catch (com
.sun
.star
.uno
.Exception e
)
649 if (xPathSubst
!= null)
651 return UnoRuntime
.queryInterface(XStringSubstitution
.class, xPathSubst
);
660 * converts directory without 'file:///' prefix.
661 * and System dependend file separator
665 public static String
getDirSys(String dir
)
669 final int idx
= dir
.indexOf("file://");
671 final int idx2
= dir
.indexOf("file:///");
673 // remove leading 'file://'
680 sysDir
= dir
.substring("file://".length());
683 sysDir
= utils
.replaceAll13(sysDir
, "%20", " ");
685 // append '/' if not there (e.g. linux)
686 if (sysDir
.charAt(sysDir
.length() - 1) != '/')
691 // remove leading '/' and replace others with '\' on windows machines
692 final String sep
= System
.getProperty("file.separator");
694 if (sep
.equalsIgnoreCase("\\"))
698 sysDir
= sysDir
.substring(1);
703 sysDir
= "//" + sysDir
;
705 sysDir
= sysDir
.replace('/', '\\');
712 * If the office is connected but the <CODE>AppExecutionCommand</CODE> is not set,
713 * this function asks the office for its location and fill the
714 * <CODE>AppExecutionCommand</CODE> with valid contet.
715 * This function was only called if parameter <CODE>AutoRestart</CODE> is set.
716 * @param msf the <CODE>MultiServiceFactory</CODE>
717 * @param param the <CODE>TestParameters</CODE>
719 private static void makeAppExecCommand(XMultiServiceFactory msf
, TestParameters param
)
721 debug
= param
.getBool(PropertyName
.DEBUG_IS_ACTIVE
);
723 // get existing AppExecutionCommand if available, else empty string
724 String command
= (String
) param
.get(util
.PropertyName
.APP_EXECUTION_COMMAND
);
726 String connectionString
;
727 if (param
.getBool(util
.PropertyName
.USE_PIPE_CONNECTION
) == true)
729 // This is the default behaviour
730 connectionString
= (String
) param
.get(util
.PropertyName
.PIPE_CONNECTION_STRING
);
734 // is used if UsePipeConnection=false
735 connectionString
= (String
) param
.get(util
.PropertyName
.CONNECTION_STRING
);
738 String sysBinDir
= "";
742 sysBinDir
= utils
.getSystemURL(utils
.expandMacro(msf
, "$SYSBINDIR"));
744 catch (java
.lang
.Exception e
)
746 dbg("could not get system binary directory");
750 // does the existing command show to the connected office?
751 if (command
.indexOf(sysBinDir
) == -1)
753 command
= sysBinDir
+ System
.getProperty("file.separator") + "soffice" +
754 " --norestore --accept=" + connectionString
+ ";urp;";
757 dbg("update AppExecutionCommand: " + command
);
759 param
.put(util
.PropertyName
.APP_EXECUTION_COMMAND
, command
);
762 private static void dbg(String message
)
766 System
.out
.println(utils
.getDateTime() + "OfficeProvider: " + message
);
771 private class OfficeWatcherPing
extends Thread
774 private final OfficeWatcher ow
;
775 private boolean bStop
= false;
777 public OfficeWatcherPing(OfficeWatcher ow
)
785 System
.out
.println(utils
.getDateTime() + "OfficeProvider:Owp: start ");
789 System
.out
.println(utils
.getDateTime() + "OfficeProvider:Owp: ping ");
793 System
.out
.println(utils
.getDateTime() + "OfficeProvider:Owp: sleep ");
794 OfficeWatcherPing
.sleep(1000); // 5000
796 catch (InterruptedException ex
)
798 ex
.printStackTrace();
809 System
.out
.println(utils
.getDateTime() + "OfficeProvider:Owp: stop ");
816 private void deleteFilesAndDirector(File file
)
821 File files
[] = f
.listFiles();
822 for(int i
= 0; i
< files
.length
; i
++)
824 deleteFilesAndDirector(files
[i
]);