summaryrefslogtreecommitdiffstats
path: root/qadevOOo/runner/helper/OfficeProvider.java
diff options
context:
space:
mode:
authorDaniel Baumann <daniel.baumann@progress-linux.org>2024-04-07 09:06:44 +0000
committerDaniel Baumann <daniel.baumann@progress-linux.org>2024-04-07 09:06:44 +0000
commited5640d8b587fbcfed7dd7967f3de04b37a76f26 (patch)
tree7a5f7c6c9d02226d7471cb3cc8fbbf631b415303 /qadevOOo/runner/helper/OfficeProvider.java
parentInitial commit. (diff)
downloadlibreoffice-ed5640d8b587fbcfed7dd7967f3de04b37a76f26.tar.xz
libreoffice-ed5640d8b587fbcfed7dd7967f3de04b37a76f26.zip
Adding upstream version 4:7.4.7.upstream/4%7.4.7upstream
Signed-off-by: Daniel Baumann <daniel.baumann@progress-linux.org>
Diffstat (limited to 'qadevOOo/runner/helper/OfficeProvider.java')
-rw-r--r--qadevOOo/runner/helper/OfficeProvider.java755
1 files changed, 755 insertions, 0 deletions
diff --git a/qadevOOo/runner/helper/OfficeProvider.java b/qadevOOo/runner/helper/OfficeProvider.java
new file mode 100644
index 000000000..48c0910f6
--- /dev/null
+++ b/qadevOOo/runner/helper/OfficeProvider.java
@@ -0,0 +1,755 @@
+/*
+ * This file is part of the LibreOffice project.
+ *
+ * This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/.
+ *
+ * This file incorporates work covered by the following license notice:
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed
+ * with this work for additional information regarding copyright
+ * ownership. The ASF licenses this file to you under the Apache
+ * License, Version 2.0 (the "License"); you may not use this file
+ * except in compliance with the License. You may obtain a copy of
+ * the License at http://www.apache.org/licenses/LICENSE-2.0 .
+ */
+package helper;
+
+import com.sun.star.beans.XFastPropertySet;
+import com.sun.star.bridge.XUnoUrlResolver;
+import com.sun.star.container.XEnumeration;
+import com.sun.star.container.XEnumerationAccess;
+import com.sun.star.frame.XDesktop;
+import com.sun.star.lang.XMultiComponentFactory;
+import com.sun.star.lang.XMultiServiceFactory;
+import com.sun.star.uno.UnoRuntime;
+import com.sun.star.uno.XComponentContext;
+import com.sun.star.util.XCloseable;
+import com.sun.star.util.XStringSubstitution;
+
+import java.io.File;
+import java.io.PrintWriter;
+import java.io.UnsupportedEncodingException;
+
+import lib.TestParameters;
+
+import share.DescEntry;
+import share.LogWriter;
+
+import util.DynamicClassLoader;
+import util.PropertyName;
+import util.utils;
+
+/**
+ * This class will connect the office and start it if possible
+ *
+ */
+public class OfficeProvider implements AppProvider
+{
+
+ private boolean debug = false;
+
+ /**
+ * copy the user layer to a safe place, usually to $TMP/user_backup$USER
+ */
+ private void backupUserLayer(TestParameters param, XMultiServiceFactory msf)
+ {
+ try
+ {
+ final XStringSubstitution sts = createStringSubstitution(msf);
+ debug = param.getBool(PropertyName.DEBUG_IS_ACTIVE);
+
+ String userLayer = sts.getSubstituteVariableValue("$(user)");
+ userLayer = getDirSys(userLayer);
+ param.put("userLayer", userLayer);
+
+ final String copyLayer = util.utils.getUsersTempDir() + System.getProperty("file.separator") +
+ "user_backup" +
+ System.getProperty("user.name");
+ param.put("copyLayer", copyLayer);
+
+
+ dbg(" copy '" + userLayer + "' ->" + copyLayer + "'");
+ // Slow machines the copy job could spend some time. To avoid activating of OfficeWatcher it must be pinged
+ OfficeWatcherPing owp = new OfficeWatcherPing((OfficeWatcher) param.get(PropertyName.OFFICE_WATCHER));
+ owp.start();
+
+ deleteFilesAndDirector (new File(copyLayer));
+ FileTools.copyDirectory(new File(userLayer), new File(copyLayer), new String[]
+ {
+ "temp"
+ });
+
+ owp.finish();
+
+ }
+ catch (com.sun.star.container.NoSuchElementException e)
+ {
+ System.out.println("User Variable '$(user)' not defined.");
+ }
+ catch (com.sun.star.uno.Exception e)
+ {
+ System.out.println("Couldn't backup user layer");
+ e.printStackTrace();
+ }
+ catch (java.io.IOException e)
+ {
+ System.out.println("Couldn't backup user layer");
+ e.printStackTrace();
+ }
+ }
+
+ /**
+ * Dispose the office.
+ * This method can only be used, if the office was connected in the first
+ * place: getManager() was called first.
+ * @return return true if desktop is terminates, else false
+ */
+ public boolean disposeManager(lib.TestParameters param)
+ {
+
+ XMultiServiceFactory msf = param.getMSF();
+
+ if (msf == null)
+ {
+ return true;
+ }
+ else
+ {
+ XDesktop desk = null;
+
+ try
+ {
+ desk = UnoRuntime.queryInterface(XDesktop.class, msf.createInstance("com.sun.star.frame.Desktop"));
+ }
+ catch (com.sun.star.uno.Exception ue)
+ {
+ return false;
+ }
+
+ msf = null;
+
+ if (desk != null)
+ {
+ desk.terminate();
+
+ return true;
+ }
+ else
+ {
+ return false;
+ }
+ }
+ }
+
+ /**
+ * Method to get the ServiceManager of an Office
+ */
+ public Object getManager(lib.TestParameters param) throws UnsupportedEncodingException
+ {
+ String errorMessage = null;
+ boolean bAppExecutionHasWarning = false;
+ debug = param.getBool(PropertyName.DEBUG_IS_ACTIVE);
+
+ String additionalArgs = (String) param.get(
+ "AdditionalConnectionArguments");
+
+ if (additionalArgs == null)
+ {
+ additionalArgs = ";";
+ }
+ else
+ {
+ additionalArgs = "," + additionalArgs + ";";
+ }
+
+ final String cncstr = "uno:" + param.get("ConnectionString") + ";urp" +
+ additionalArgs + "StarOffice.ServiceManager";
+
+ System.out.println("Connecting the Office with " + cncstr);
+
+ XMultiServiceFactory msf = connectOffice(cncstr);
+
+ // if the office is running and the office crashes while testing it could
+ // be useful to restart the office if possible and continue the tests.
+ // Example: the UNO-API-Tests in the projects will be executed by calling
+ // 'dmake'.
+ if ((param.getBool(util.PropertyName.AUTO_RESTART)) && (msf != null))
+ {
+ makeAppExecCommand(msf, param);
+ }
+
+ if (msf == null)
+ {
+ String exc = "";
+ Exception exConnectFailed = null;
+ boolean isExecutable = false;
+ boolean isAppKnown = ((cncstr.indexOf("host=localhost") > 0) || (cncstr.indexOf("pipe,name=") > 0));
+ isAppKnown &= ((String) param.get("AppExecutionCommand")).length() != 0;
+
+ if (isAppKnown)
+ {
+ dbg("Local Connection trying to start the Office");
+
+ //ensure that a pending officewatcher gets finished before a new
+ //office is started
+ final OfficeWatcher ow_old = (OfficeWatcher) param.get("Watcher");
+
+ if (ow_old != null)
+ {
+ ow_old.finish = true;
+ }
+
+ final String cmd = (String) param.get("AppExecutionCommand");
+ dbg("AppExecutionCommand: " + cmd);
+ // validate the AppExecutionCommand, but try it out anyway.
+ // keep the error message for later.
+ errorMessage =
+ util.utils.validateAppExecutionCommand(cmd, (String) param.get("OperatingSystem"));
+ if (errorMessage.startsWith("Error"))
+ {
+ System.out.println(errorMessage);
+ return null;
+ }
+ bAppExecutionHasWarning = !errorMessage.equals("OK");
+
+ final DynamicClassLoader dcl = new DynamicClassLoader();
+ final LogWriter log = (LogWriter) dcl.getInstance(
+ (String) param.get("LogWriter"));
+
+ //create empty entry
+ final DescEntry Entry = new DescEntry();
+ Entry.entryName = "office";
+ Entry.longName = "office";
+ Entry.EntryType = "placebo";
+ Entry.isOptional = false;
+ Entry.isToTest = false;
+ Entry.SubEntryCount = 0;
+ Entry.hasErrorMsg = false;
+ Entry.State = "non possible";
+ Entry.UserDefinedParams = param;
+
+ log.initialize(Entry, debug);
+
+ final ProcessHandler ph = new ProcessHandler(cmd, (PrintWriter) log);
+ isExecutable = ph.executeAsynchronously();
+
+ if (isExecutable)
+ {
+ param.put("AppProvider", ph);
+ final OfficeWatcher ow = new OfficeWatcher(param);
+ param.put("Watcher", ow);
+ ow.start();
+ ow.ping();
+ }
+
+ int k = 0;
+
+ // wait up to 21 seconds to get an office connection
+ while ((k < 42) && (msf == null))
+ {
+ try
+ {
+ msf = connect(cncstr);
+ }
+ catch (com.sun.star.uno.Exception ue)
+ {
+ exConnectFailed = ue;
+ exc = ue.getMessage();
+ }
+ catch (java.lang.Exception je)
+ {
+ exConnectFailed = je;
+ exc = je.getMessage();
+ }
+ if (msf == null)
+ {
+ util.utils.pause(500 * k);
+ }
+ k++;
+ }
+
+ if (msf == null)
+ {
+ System.out.println("Exception while connecting.\n" + exConnectFailed);
+ if (exc != null)
+ {
+ System.out.println(exc);
+ }
+ if (bAppExecutionHasWarning)
+ {
+ System.out.println(errorMessage);
+ }
+ }
+ else if (isExecutable)
+ {
+ backupUserLayer(param, msf);
+ }
+ }
+ else
+ {
+ System.out.println("Could not connect an Office and cannot start one.\n".concat("please start an office with following parameter:\n").
+ concat("\nsoffice --accept=").concat((String) param.get("ConnectionString")).concat(";urp;\n"));
+ }
+ }
+
+ return msf;
+ }
+
+ /**
+ * Connect an Office
+ * @param connectStr
+ * @return
+ * @throws com.sun.star.uno.Exception
+ * @throws com.sun.star.uno.RuntimeException
+ * @throws com.sun.star.connection.NoConnectException
+ * @throws Exception
+ */
+ private XMultiServiceFactory connect(String connectStr)
+ throws com.sun.star.uno.Exception,
+ com.sun.star.uno.RuntimeException,
+ com.sun.star.connection.NoConnectException,
+ Exception
+ {
+
+ // Get component context
+ final XComponentContext xcomponentcontext = com.sun.star.comp.helper.Bootstrap.createInitialComponentContext(null);
+
+ // initial serviceManager
+ final XMultiComponentFactory xLocalServiceManager = xcomponentcontext.getServiceManager();
+
+ // create a connector, so that it can contact the office
+ final Object xUrlResolver = xLocalServiceManager.createInstanceWithContext("com.sun.star.bridge.UnoUrlResolver", xcomponentcontext);
+ final XUnoUrlResolver urlResolver = UnoRuntime.queryInterface(XUnoUrlResolver.class, xUrlResolver);
+
+ final Object rInitialObject = urlResolver.resolve(connectStr);
+
+ XMultiServiceFactory xMSF = null;
+
+ if (rInitialObject != null)
+ {
+ // debug = true;
+ dbg("resolved url");
+
+ xMSF = UnoRuntime.queryInterface(XMultiServiceFactory.class, rInitialObject);
+ }
+
+ return xMSF;
+ }
+
+ /**
+ * Close an office.
+ * @param param The test parameters.
+ * @param closeIfPossible If true, close even if
+ * it was running before the test
+ */
+ public boolean closeExistingOffice(lib.TestParameters param, boolean closeIfPossible)
+ {
+
+ XMultiServiceFactory msf = param.getMSF();
+ final boolean alreadyConnected = (msf != null);
+ debug = param.getBool(PropertyName.DEBUG_IS_ACTIVE);
+
+ if (alreadyConnected)
+ {
+ dbg("try to get ProcessHandler");
+
+ final ProcessHandler ph = (ProcessHandler) param.get("AppProvider");
+
+ if (ph != null)
+ {
+ dbg("ProcessHandler != null");
+
+ disposeOffice(msf, param);
+
+ // dispose watcher in case it's still running.
+ dbg("try to get OfficeWatcher");
+
+ final OfficeWatcher ow = (OfficeWatcher) param.get("Watcher");
+
+ if ((ow != null) && ow.isAlive())
+ {
+ dbg("OfficeWatcher will be finished");
+ ow.finish = true;
+ }
+ else
+ {
+ dbg("OfficeWatcher seems to be finished");
+ }
+
+ return true;
+ }
+ else
+ {
+ if (closeIfPossible)
+ {
+ return disposeOffice(msf, param);
+ }
+ }
+ }
+ else
+ {
+ final String cncstr = "uno:" + param.get("ConnectionString") +
+ ";urp;StarOffice.ServiceManager";
+ dbg("try to connect office");
+ msf = connectOffice(cncstr);
+
+ if (closeIfPossible)
+ {
+ return disposeOffice(msf, param);
+ }
+ }
+ dbg("closeExistingOffice finished");
+ return true;
+ }
+
+ private XMultiServiceFactory connectOffice(String cncstr)
+ {
+ XMultiServiceFactory msf = null;
+ String exc = "";
+ // debug = true;
+
+ dbg("trying to connect to " + cncstr);
+
+ try
+ {
+ msf = connect(cncstr);
+ }
+ catch (com.sun.star.uno.Exception ue)
+ {
+ exc = ue.getMessage();
+ }
+ catch (java.lang.Exception je)
+ {
+ exc = je.getMessage();
+ }
+
+ if (debug && exc != null && exc.length() != 0)
+ {
+ dbg("Could not connect an Office. " + exc);
+ }
+
+ return msf;
+ }
+
+ private boolean disposeOffice(XMultiServiceFactory msf,
+ TestParameters param)
+ {
+ XDesktop desk = null;
+
+ debug = param.getBool(PropertyName.DEBUG_IS_ACTIVE);
+
+ boolean result = true;
+
+ if (msf != null)
+ {
+
+ // disable QuickStarter
+ try
+ {
+ Object quickStarter = msf.createInstance("com.sun.star.office.Quickstart");
+ XFastPropertySet fps = UnoRuntime.queryInterface(XFastPropertySet.class, quickStarter);
+ fps.setFastPropertyValue(0, false);
+ }
+ catch (com.sun.star.uno.Exception ex)
+ {
+ dbg("ERROR: Could not disable QuickStarter: " + ex.toString());
+ }
+
+ try
+ {
+ desk = UnoRuntime.queryInterface(XDesktop.class, msf.createInstance("com.sun.star.frame.Desktop"));
+ msf = null;
+
+ if (desk != null)
+ {
+ final boolean allClosed = closeAllWindows(desk);
+
+ if (!allClosed)
+ {
+ dbg("Couldn't close all office windows!");
+ }
+
+ dbg("Trying to terminate the desktop");
+
+ desk.terminate();
+ dbg("Desktop terminated");
+ }
+ }
+ catch (com.sun.star.uno.Exception ue)
+ {
+ result = false;
+ }
+ catch (com.sun.star.lang.DisposedException ue)
+ {
+ result = false;
+ }
+ }
+
+ final ProcessHandler ph = (ProcessHandler) param.get("AppProvider");
+
+ if (ph != null)
+ {
+ // dispose watcher in case it's still running.
+ final OfficeWatcher ow = (OfficeWatcher) param.get("Watcher");
+
+ if ((ow != null) && ow.isAlive())
+ {
+ ow.finish = true;
+ }
+
+ ph.kill();
+ }
+
+ param.remove("AppProvider");
+ param.remove("ServiceFactory");
+
+ //copy user_backup into user layer
+ try
+ {
+ final String userLayer = (String) param.get("userLayer");
+ final String copyLayer = (String) param.get("copyLayer");
+ if (userLayer != null && copyLayer != null)
+ {
+ deleteFilesAndDirector(new File(userLayer));
+ final File copyFile = new File(copyLayer);
+ dbg("copy '" + copyFile + "' -> '" + userLayer + "'");
+ FileTools.copyDirectory(copyFile, new File(userLayer), new String[]
+ {
+ "temp"
+ });
+ dbg("copy '" + copyFile + "' -> '" + userLayer + "' finished");
+
+ // remove all user_backup folder in temp dir
+ // this is for the case the runner was killed and some old backup folder still stay in temp dir
+
+
+ }
+ else
+ {
+ System.out.println("Cannot copy layer: '" + copyLayer + "' back to user layer: '" + userLayer + "'");
+ }
+ }
+ catch (java.io.IOException e)
+ {
+ dbg("Couldn't recover from backup\n" + e.getMessage());
+ }
+ return result;
+ }
+
+ private boolean closeAllWindows(XDesktop desk)
+ {
+ final XEnumerationAccess compEnumAccess = desk.getComponents();
+ final XEnumeration compEnum = compEnumAccess.createEnumeration();
+ boolean res = true;
+
+ try
+ {
+ while (compEnum.hasMoreElements())
+ {
+ final XCloseable closer = UnoRuntime.queryInterface(XCloseable.class, compEnum.nextElement());
+
+ if (closer != null)
+ {
+ closer.close(true);
+ }
+ }
+ }
+ catch (com.sun.star.util.CloseVetoException cve)
+ {
+ res = false;
+ }
+ catch (com.sun.star.container.NoSuchElementException nsee)
+ {
+ res = false;
+ }
+ catch (com.sun.star.lang.WrappedTargetException wte)
+ {
+ res = false;
+ }
+
+ return res;
+ }
+
+ private static XStringSubstitution createStringSubstitution(XMultiServiceFactory xMSF) throws com.sun.star.uno.Exception
+ {
+ Object xPathSubst = xMSF.createInstance(
+ "com.sun.star.util.PathSubstitution");
+ return UnoRuntime.queryInterface(XStringSubstitution.class, xPathSubst);
+ }
+
+ /**
+ * converts directory without 'file:///' prefix.
+ * and System dependent file separator
+ */
+ private static String getDirSys(String dir)
+ {
+ String sysDir = "";
+
+ final int idx = dir.indexOf("file://");
+
+ final int idx2 = dir.indexOf("file:///");
+
+ // remove leading 'file://'
+ if (idx < 0)
+ {
+ sysDir = dir;
+ }
+ else
+ {
+ sysDir = dir.substring("file://".length());
+ }
+
+ sysDir = sysDir.replace("%20", " ");
+
+ // append '/' if not there (e.g. linux)
+ if (sysDir.charAt(sysDir.length() - 1) != '/')
+ {
+ sysDir += "/";
+ }
+
+ // remove leading '/' and replace others with '\' on windows machines
+ final String sep = System.getProperty("file.separator");
+
+ if (sep.equalsIgnoreCase("\\"))
+ {
+ if (idx2 >= 0)
+ {
+ sysDir = sysDir.substring(1);
+ }
+ else
+ {
+ //network path
+ sysDir = "//" + sysDir;
+ }
+ sysDir = sysDir.replace('/', '\\');
+ }
+
+ return sysDir;
+ }
+
+ /**
+ * If the office is connected but the <CODE>AppExecutionCommand</CODE> is not set,
+ * this function asks the office for its location and fill the
+ * <CODE>AppExecutionCommand</CODE> with valid content.
+ * This function was only called if parameter <CODE>AutoRestart</CODE> is set.
+ * @param msf the <CODE>MultiServiceFactory</CODE>
+ * @param param the <CODE>TestParameters</CODE>
+ */
+ private void makeAppExecCommand(XMultiServiceFactory msf, TestParameters param)
+ {
+ debug = param.getBool(PropertyName.DEBUG_IS_ACTIVE);
+
+ // get existing AppExecutionCommand if available, else empty string
+ String command = (String) param.get(util.PropertyName.APP_EXECUTION_COMMAND);
+
+ String connectionString;
+ if (param.getBool(util.PropertyName.USE_PIPE_CONNECTION))
+ {
+ // This is the default behaviour
+ connectionString = (String) param.get(util.PropertyName.PIPE_CONNECTION_STRING);
+ }
+ else
+ {
+ // is used if UsePipeConnection=false
+ connectionString = (String) param.get(util.PropertyName.CONNECTION_STRING);
+ }
+
+ String sysBinDir = "";
+
+ try
+ {
+ sysBinDir = utils.getSystemURL(utils.expandMacro(msf, "$SYSBINDIR"));
+ }
+ catch (java.lang.Exception e)
+ {
+ dbg("could not get system binary directory");
+ return;
+ }
+
+ // does the existing command show to the connected office?
+ if (command.indexOf(sysBinDir) == -1)
+ {
+ command = sysBinDir + System.getProperty("file.separator") + "soffice" +
+ " --norestore --accept=" + connectionString + ";urp;";
+ }
+
+ dbg("update AppExecutionCommand: " + command);
+
+ param.put(util.PropertyName.APP_EXECUTION_COMMAND, command);
+ }
+
+ private void dbg(String message)
+ {
+ if (debug)
+ {
+ System.out.println(utils.getDateTime() + "OfficeProvider: " + message);
+ }
+
+ }
+
+ private static class OfficeWatcherPing extends Thread
+ {
+
+ private final OfficeWatcher ow;
+ private boolean bStop = false;
+
+ public OfficeWatcherPing(OfficeWatcher ow)
+ {
+ this.ow = ow;
+ }
+
+ @Override
+ public void run()
+ {
+ System.out.println(utils.getDateTime() + "OfficeProvider:Owp: start ");
+
+ while (!bStop)
+ {
+ System.out.println(utils.getDateTime() + "OfficeProvider:Owp: ping ");
+ ow.ping();
+ System.out.println(utils.getDateTime() + "OfficeProvider:Owp: sleep ");
+ util.utils.pause(1000);
+ }
+
+ }
+
+ public void finish()
+ {
+ synchronized(this)
+ {
+ bStop = true;
+ System.out.println(utils.getDateTime() + "OfficeProvider:Owp: stop ");
+
+ notify();
+ }
+ }
+ }
+
+ private void deleteFilesAndDirector(File file)
+ {
+ File f = file;
+ if(f.isDirectory())
+ {
+ File files[] = f.listFiles();
+ int filesLength = files != null ? files.length : 0;
+ for(int i = 0; i < filesLength; ++i)
+ {
+ deleteFilesAndDirector(files[i]);
+ }
+ boolean bDeleteOk = f.delete();
+ if (!bDeleteOk) {
+ System.out.println("delete failed");
+ }
+ }
+ else if (f.isFile())
+ {
+ boolean bDeleteOk = f.delete();
+ if (!bDeleteOk) {
+ System.out.println("delete failed");
+ }
+ }
+ }
+}