1 /*************************************************************************
3 * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
5 * Copyright 2008 by Sun Microsystems, Inc.
7 * OpenOffice.org - a multi-platform office productivity suite
9 * $RCSfile: OfficeProvider.java,v $
10 * $Revision: 1.22.2.5 $
12 * This file is part of OpenOffice.org.
14 * OpenOffice.org is free software: you can redistribute it and/or modify
15 * it under the terms of the GNU Lesser General Public License version 3
16 * only, as published by the Free Software Foundation.
18 * OpenOffice.org is distributed in the hope that it will be useful,
19 * but WITHOUT ANY WARRANTY; without even the implied warranty of
20 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
21 * GNU Lesser General Public License version 3 for more details
22 * (a copy is included in the LICENSE file that accompanied this code).
24 * You should have received a copy of the GNU Lesser General Public License
25 * version 3 along with OpenOffice.org. If not, see
26 * <http://www.openoffice.org/license.html>
27 * for a copy of the LGPLv3 License.
29 ************************************************************************/
32 //import com.sun.star.bridge.UnoUrlResolver;
33 import com
.sun
.star
.beans
.XFastPropertySet
;
34 import com
.sun
.star
.bridge
.XUnoUrlResolver
;
35 import com
.sun
.star
.container
.XEnumeration
;
36 import com
.sun
.star
.container
.XEnumerationAccess
;
37 import com
.sun
.star
.frame
.XDesktop
;
38 import com
.sun
.star
.lang
.XMultiComponentFactory
;
39 import com
.sun
.star
.lang
.XMultiServiceFactory
;
40 import com
.sun
.star
.uno
.UnoRuntime
;
41 import com
.sun
.star
.uno
.XComponentContext
;
42 import com
.sun
.star
.util
.XCloseable
;
43 import com
.sun
.star
.util
.XStringSubstitution
;
46 import java
.io
.PrintWriter
;
47 import java
.util
.StringTokenizer
;
49 import lib
.TestParameters
;
51 import share
.DescEntry
;
52 import share
.LogWriter
;
54 import util
.DynamicClassLoader
;
55 import util
.PropertyName
;
59 * This class will connect the office and start it if possible
62 public class OfficeProvider
implements AppProvider
65 protected static boolean debug
= false;
68 * copy the user layer to a safe place, usualy to $TMP/user_backup$USER
72 public void backupUserLayer(TestParameters param
, XMultiServiceFactory msf
)
76 final XStringSubstitution sts
= createStringSubstitution(msf
);
77 debug
= param
.getBool(PropertyName
.DEBUG_IS_ACTIVE
);
79 String userLayer
= sts
.getSubstituteVariableValue("$(user)");
80 userLayer
= getDirSys(userLayer
);
81 param
.put("userLayer", userLayer
);
83 final String copyLayer
= util
.utils
.getUsersTempDir() + System
.getProperty("file.separator") +
85 System
.getProperty("user.name");
86 param
.put("copyLayer", copyLayer
);
89 dbg(" copy '" + userLayer
+ "' ->" + copyLayer
+ "'");
90 // Slow machines the copy job could spend some time. To avoid activating of OfficeWatcher it must be pinged
91 OfficeWatcherPing owp
= new OfficeWatcherPing((OfficeWatcher
) param
.get(PropertyName
.OFFICE_WATCHER
));
94 deleteFilesAndDirector (new File(copyLayer
));
95 FileTools
.copyDirectory(new File(userLayer
), new File(copyLayer
), new String
[]
103 catch (com
.sun
.star
.container
.NoSuchElementException e
)
105 System
.out
.println("User Variable '$(user)' not defined.");
107 catch (java
.io
.IOException e
)
109 System
.out
.println("Couldn't backup user layer");
115 * Dispose the office.
116 * This method can only be used, if the office was connected in the first
117 * place: getManager() was called first.
119 * @return return true if desktop is terminates, else false
121 public boolean disposeManager(lib
.TestParameters param
)
124 XMultiServiceFactory msf
= (XMultiServiceFactory
) param
.getMSF();
132 XDesktop desk
= null;
136 desk
= (XDesktop
) UnoRuntime
.queryInterface(XDesktop
.class,
138 "com.sun.star.frame.Desktop"));
140 catch (com
.sun
.star
.uno
.Exception ue
)
161 * Method to get the ServiceManager of an Office
165 public Object
getManager(lib
.TestParameters param
)
167 String errorMessage
= null;
168 boolean bAppExecutionHasWarning
= false;
169 debug
= param
.getBool(PropertyName
.DEBUG_IS_ACTIVE
);
171 String additionalArgs
= (String
) param
.get(
172 "AdditionalConnectionArguments");
174 if (additionalArgs
== null)
176 additionalArgs
= ";";
180 additionalArgs
= "," + additionalArgs
+ ";";
183 final String cncstr
= "uno:" + param
.get("ConnectionString") + ";urp" +
184 additionalArgs
+ "StarOffice.ServiceManager";
186 System
.out
.println("Connecting the Office with " + cncstr
);
188 XMultiServiceFactory msf
= connectOffice(cncstr
);
190 // if the office is running and the office crashes while testing it could
191 // be usesfull to restart the office if possible and continuing the tests.
192 // Example: The UNO-API-Tests in the projects will be executed by calling
193 // 'damke'. This connects to an existing office. If the office crashes
194 // it is usefull to restart the office and continuing the tests.
195 if ((param
.getBool(util
.PropertyName
.AUTO_RESTART
)) && (msf
!= null))
197 makeAppExecCommand(msf
, param
);
203 Exception exConnectFailed
= null;
204 boolean isExecutable
= false;
205 boolean isAppKnown
= ((cncstr
.indexOf("host=localhost") > 0) || (cncstr
.indexOf("pipe,name=") > 0));
206 isAppKnown
&= !((String
) param
.get("AppExecutionCommand")).equals("");
210 dbg("Local Connection trying to start the Office");
212 //ensure that a pending officewatcher gets finished before a new
214 final OfficeWatcher ow_old
= (OfficeWatcher
) param
.get("Watcher");
218 ow_old
.finish
= true;
221 final String cmd
= (String
) param
.get("AppExecutionCommand");
222 dbg("AppExecutionCommand: " + cmd
);
223 // validate the AppExecutionCommand, but try it out anyway.
224 // keep the error message for later.
226 util
.utils
.validateAppExecutionCommand(cmd
, (String
) param
.get("OperatingSystem"));
227 if (errorMessage
.startsWith("Error"))
229 System
.out
.println(errorMessage
);
232 bAppExecutionHasWarning
= !errorMessage
.equals("OK");
234 final DynamicClassLoader dcl
= new DynamicClassLoader();
235 final LogWriter log
= (LogWriter
) dcl
.getInstance(
236 (String
) param
.get("LogWriter"));
239 final DescEntry Entry
= new DescEntry();
240 Entry
.entryName
= "office";
241 Entry
.longName
= "office";
242 Entry
.EntryType
= "placebo";
243 Entry
.isOptional
= false;
244 Entry
.isToTest
= false;
245 Entry
.SubEntryCount
= 0;
246 Entry
.hasErrorMsg
= false;
247 Entry
.State
= "non possible";
248 Entry
.UserDefinedParams
= param
;
250 log
.initialize(Entry
, debug
);
252 final ProcessHandler ph
= new ProcessHandler(cmd
, (PrintWriter
) log
);
253 isExecutable
= ph
.executeAsynchronously();
257 param
.put("AppProvider", ph
);
258 final OfficeWatcher ow
= new OfficeWatcher(param
);
259 param
.put("Watcher", ow
);
266 // wait up to 21 seconds to get an office connection
267 while ((k
< 42) && (msf
== null))
271 msf
= connect(cncstr
);
273 catch (com
.sun
.star
.uno
.Exception ue
)
275 exConnectFailed
= ue
;
276 exc
= ue
.getMessage();
278 catch (java
.lang
.Exception je
)
280 exConnectFailed
= je
;
281 exc
= je
.getMessage();
287 Thread
.sleep(k
* 500);
289 catch (InterruptedException ex
)
298 System
.out
.println("Exception while connecting.\n" + exConnectFailed
);
301 System
.out
.println(exc
);
303 if (bAppExecutionHasWarning
)
305 System
.out
.println(errorMessage
);
308 else if (isExecutable
)
310 if (!param
.getBool(util
.PropertyName
.DONT_BACKUP_USERLAYER
))
312 backupUserLayer(param
, msf
);
318 System
.out
.println("Could not connect an Office and cannot start one.\n".concat("please start an office with following parameter:\n").
319 concat("\nsoffice -accept=").concat((String
) param
.get("ConnectionString")).concat(";urp;\n"));
320 if (bAppExecutionHasWarning
)
322 System
.out
.println(errorMessage
);
334 * @throws com.sun.star.uno.Exception
335 * @throws com.sun.star.uno.RuntimeException
336 * @throws com.sun.star.connection.NoConnectException
339 protected static XMultiServiceFactory
connect(String connectStr
)
340 throws com
.sun
.star
.uno
.Exception
,
341 com
.sun
.star
.uno
.RuntimeException
,
342 com
.sun
.star
.connection
.NoConnectException
,
346 // Get component context
347 final XComponentContext xcomponentcontext
= com
.sun
.star
.comp
.helper
.Bootstrap
.createInitialComponentContext(
350 // initial serviceManager
351 final XMultiComponentFactory xLocalServiceManager
= xcomponentcontext
.getServiceManager();
353 // create a connector, so that it can contact the office
354 // XUnoUrlResolver urlResolver = UnoUrlResolver.create(xcomponentcontext);
355 final Object xUrlResolver
= xLocalServiceManager
.createInstanceWithContext(
356 "com.sun.star.bridge.UnoUrlResolver", xcomponentcontext
);
357 final XUnoUrlResolver urlResolver
= (XUnoUrlResolver
) UnoRuntime
.queryInterface(
358 XUnoUrlResolver
.class, xUrlResolver
);
360 final Object rInitialObject
= urlResolver
.resolve(connectStr
);
362 XMultiServiceFactory xMSF
= null;
364 if (rInitialObject
!= null)
369 xMSF
= (XMultiServiceFactory
) UnoRuntime
.queryInterface(
370 XMultiServiceFactory
.class, rInitialObject
);
378 * @param param The test parameters.
379 * @param closeIfPossible If true, close even if
380 * it was running before the test
382 public boolean closeExistingOffice(lib
.TestParameters param
, boolean closeIfPossible
)
385 XMultiServiceFactory msf
= (XMultiServiceFactory
) param
.getMSF();
386 final boolean alreadyConnected
= (msf
!= null);
387 debug
= param
.getBool(PropertyName
.DEBUG_IS_ACTIVE
);
389 if (alreadyConnected
)
391 dbg("try to get ProcessHandler");
393 final ProcessHandler ph
= (ProcessHandler
) param
.get("AppProvider");
397 dbg("ProcessHandler != null");
399 disposeOffice(msf
, param
);
401 // dispose watcher in case it's still running.
402 dbg("try to get OfficeWatcher");
404 final OfficeWatcher ow
= (OfficeWatcher
) param
.get("Watcher");
406 if ((ow
!= null) && ow
.isAlive())
408 dbg("OfficeWatcher will be finished");
413 dbg("OfficeWatcher seems to be finished");
422 return disposeOffice(msf
, param
);
428 final String cncstr
= "uno:" + param
.get("ConnectionString") +
429 ";urp;StarOffice.ServiceManager";
430 dbg("try to connect office");
431 msf
= connectOffice(cncstr
);
435 return disposeOffice(msf
, param
);
438 dbg("closeExistingOffice finished");
442 private XMultiServiceFactory
connectOffice(String cncstr
)
444 XMultiServiceFactory msf
= null;
448 dbg("trying to connect to " + cncstr
);
452 msf
= connect(cncstr
);
454 catch (com
.sun
.star
.uno
.Exception ue
)
456 exc
= ue
.getMessage();
458 catch (java
.lang
.Exception je
)
460 exc
= je
.getMessage();
463 if (debug
&& exc
!= null && exc
.length() != 0)
469 dbg("Could not connect an Office. " + exc
);
475 private synchronized boolean disposeOffice(XMultiServiceFactory msf
,
476 TestParameters param
)
478 XDesktop desk
= null;
480 debug
= param
.getBool(PropertyName
.DEBUG_IS_ACTIVE
);
482 boolean result
= true;
487 // disable QuickStarter
490 Object quickStarter
= msf
.createInstance("com.sun.star.office.Quickstart");
491 XFastPropertySet fps
= (XFastPropertySet
) UnoRuntime
.queryInterface(XFastPropertySet
.class, quickStarter
);
492 fps
.setFastPropertyValue(0, false);
494 catch (com
.sun
.star
.uno
.Exception ex
)
496 dbg("ERROR: Could not disable QuickStarter: " + ex
.toString());
501 desk
= (XDesktop
) UnoRuntime
.queryInterface(XDesktop
.class,
503 "com.sun.star.frame.Desktop"));
508 final boolean allClosed
= closeAllWindows(desk
);
512 dbg("Couldn't close all office windows!");
515 dbg("Trying to terminate the desktop");
518 dbg("Desktop terminated");
522 final int closeTime
= param
.getInt(util
.PropertyName
.OFFICE_CLOSE_TIME_OUT
);
523 dbg("the Office has " + closeTime
/ 1000 + " seconds for closing...");
524 Thread
.sleep(closeTime
);
526 catch (java
.lang
.InterruptedException e
)
531 catch (com
.sun
.star
.uno
.Exception ue
)
535 catch (com
.sun
.star
.lang
.DisposedException ue
)
541 final String AppKillCommand
= (String
) param
.get(util
.PropertyName
.APP_KILL_COMMAND
);
542 if (AppKillCommand
!= null)
544 String sAppKillCommand
= StringHelper
.removeSurroundQuoteIfExists(AppKillCommand
);
545 final StringTokenizer aKillCommandToken
= new StringTokenizer(sAppKillCommand
, ";");
546 while (aKillCommandToken
.hasMoreTokens())
548 final String sKillCommand
= aKillCommandToken
.nextToken();
549 dbg("User defined an application to destroy the started process. Trying to execute: " + sKillCommand
);
551 final ProcessHandler pHdl
= new ProcessHandler(sKillCommand
, 1000); // 3000 seems to be too long
558 final ProcessHandler ph
= (ProcessHandler
) param
.get("AppProvider");
562 // dispose watcher in case it's still running.
563 final OfficeWatcher ow
= (OfficeWatcher
) param
.get("Watcher");
565 if ((ow
!= null) && ow
.isAlive())
573 param
.remove("AppProvider");
574 param
.remove("ServiceFactory");
576 if (!param
.getBool(util
.PropertyName
.DONT_BACKUP_USERLAYER
))
578 //copy user_backup into user layer
581 final String userLayer
= (String
) param
.get("userLayer");
582 final String copyLayer
= (String
) param
.get("copyLayer");
583 if (userLayer
!= null && copyLayer
!= null)
585 deleteFilesAndDirector(new File(userLayer
));
586 final File copyFile
= new File(copyLayer
);
587 dbg("copy '" + copyFile
+ "' -> '" + userLayer
+ "'");
588 FileTools
.copyDirectory(copyFile
, new File(userLayer
), new String
[]
592 dbg("copy '" + copyFile
+ "' -> '" + userLayer
+ "' finished");
594 // remove all user_backup folder in temp dir
595 // this is for the case the runner was killed and some old backup folder still stay in temp dir
601 System
.out
.println("Cannot copy layer: '" + copyLayer
+ "' back to user layer: '" + userLayer
+ "'");
604 catch (java
.io
.IOException e
)
606 dbg("Couldn't recover from backup\n" + e
.getMessage());
612 protected boolean closeAllWindows(XDesktop desk
)
614 final XEnumerationAccess compEnumAccess
= desk
.getComponents();
615 final XEnumeration compEnum
= compEnumAccess
.createEnumeration();
620 while (compEnum
.hasMoreElements())
622 final XCloseable closer
= (XCloseable
) UnoRuntime
.queryInterface(
624 compEnum
.nextElement());
632 catch (com
.sun
.star
.util
.CloseVetoException cve
)
636 catch (com
.sun
.star
.container
.NoSuchElementException nsee
)
640 catch (com
.sun
.star
.lang
.WrappedTargetException wte
)
648 public static XStringSubstitution
createStringSubstitution(XMultiServiceFactory xMSF
)
650 Object xPathSubst
= null;
654 xPathSubst
= xMSF
.createInstance(
655 "com.sun.star.util.PathSubstitution");
657 catch (com
.sun
.star
.uno
.Exception e
)
662 if (xPathSubst
!= null)
664 return (XStringSubstitution
) UnoRuntime
.queryInterface(
665 XStringSubstitution
.class, xPathSubst
);
674 * converts directory without 'file:///' prefix.
675 * and System dependend file separator
679 public static String
getDirSys(String dir
)
683 final int idx
= dir
.indexOf("file://");
685 final int idx2
= dir
.indexOf("file:///");
687 // remove leading 'file://'
694 sysDir
= dir
.substring("file://".length());
697 sysDir
= utils
.replaceAll13(sysDir
, "%20", " ");
699 // append '/' if not there (e.g. linux)
700 if (sysDir
.charAt(sysDir
.length() - 1) != '/')
705 // remove leading '/' and replace others with '\' on windows machines
706 final String sep
= System
.getProperty("file.separator");
708 if (sep
.equalsIgnoreCase("\\"))
712 sysDir
= sysDir
.substring(1);
717 sysDir
= "//" + sysDir
;
719 sysDir
= sysDir
.replace('/', '\\');
726 * If the office is connected but the <CODE>AppExecutionCommand</CODE> is not set,
727 * this function asks the office for its location and fill the
728 * <CODE>AppExecutionCommand</CODE> with valid contet.
729 * This function was only called if parameter <CODE>AutoRestart</CODE> is set.
730 * @param msf the <CODE>MultiServiceFactory</CODE>
731 * @param param the <CODE>TestParameters</CODE>
733 private static void makeAppExecCommand(XMultiServiceFactory msf
, TestParameters param
)
735 debug
= param
.getBool(PropertyName
.DEBUG_IS_ACTIVE
);
737 // get existing AppExecutionCommand if available, else empty string
738 String command
= (String
) param
.get(util
.PropertyName
.APP_EXECUTION_COMMAND
);
740 String connectionString
;
741 if (param
.getBool(util
.PropertyName
.USE_PIPE_CONNECTION
) == true)
743 // This is the default behaviour
744 connectionString
= (String
) param
.get(util
.PropertyName
.PIPE_CONNECTION_STRING
);
748 // is used if UsePipeConnection=false
749 connectionString
= (String
) param
.get(util
.PropertyName
.CONNECTION_STRING
);
752 String sysBinDir
= "";
756 sysBinDir
= utils
.getSystemURL(utils
.expandMacro(msf
, "$SYSBINDIR"));
758 catch (java
.lang
.Exception e
)
760 dbg("could not get system binary directory");
764 // does the existing command show to the connected office?
765 if (command
.indexOf(sysBinDir
) == -1)
767 command
= sysBinDir
+ System
.getProperty("file.separator") + "soffice" +
768 " -norestore -accept=" + connectionString
+ ";urp;";
771 dbg("update AppExecutionCommand: " + command
);
773 param
.put(util
.PropertyName
.APP_EXECUTION_COMMAND
, command
);
776 private static void dbg(String message
)
780 System
.out
.println(utils
.getDateTime() + "OfficeProvider: " + message
);
785 private class OfficeWatcherPing
extends Thread
788 private final OfficeWatcher ow
;
789 private boolean bStop
= false;
791 public OfficeWatcherPing(OfficeWatcher ow
)
798 System
.out
.println(utils
.getDateTime() + "OfficeProvider:Owp: start ");
802 System
.out
.println(utils
.getDateTime() + "OfficeProvider:Owp: ping ");
806 System
.out
.println(utils
.getDateTime() + "OfficeProvider:Owp: sleep ");
807 OfficeWatcherPing
.sleep(1000); // 5000
809 catch (InterruptedException ex
)
811 ex
.printStackTrace();
822 System
.out
.println(utils
.getDateTime() + "OfficeProvider:Owp: stop ");
829 private void deleteFilesAndDirector(File file
)
834 File files
[] = f
.listFiles();
835 for(int i
= 0; i
< files
.length
; i
++)
837 deleteFilesAndDirector(files
[i
]);