/************************************************************************* * * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * Copyright 2000, 2010 Oracle and/or its affiliates. * * OpenOffice.org - a multi-platform office productivity suite * * This file is part of OpenOffice.org. * * OpenOffice.org is free software: you can redistribute it and/or modify * it under the terms of the GNU Lesser General Public License version 3 * only, as published by the Free Software Foundation. * * OpenOffice.org is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU Lesser General Public License version 3 for more details * (a copy is included in the LICENSE file that accompanied this code). * * You should have received a copy of the GNU Lesser General Public License * version 3 along with OpenOffice.org. If not, see * * for a copy of the LGPLv3 License. * ************************************************************************/ package basicrunner; import com.sun.star.beans.PropertyValue; import com.sun.star.beans.XPropertySet; import com.sun.star.connection.ConnectionSetupException; import com.sun.star.container.ContainerEvent; import com.sun.star.container.XContainer; import com.sun.star.container.XContainerListener; import com.sun.star.container.XNameContainer; import com.sun.star.frame.XComponentLoader; import com.sun.star.frame.XDesktop; import com.sun.star.lang.WrappedTargetException; import com.sun.star.lang.XComponent; import com.sun.star.lang.XMultiServiceFactory; import com.sun.star.lang.XServiceInfo; import com.sun.star.lang.XSingleServiceFactory; import com.sun.star.lang.XTypeProvider; import com.sun.star.uno.Type; import com.sun.star.uno.UnoRuntime; import com.sun.star.util.XChangesBatch; import java.util.Hashtable; import lib.TestParameters; import share.LogWriter; /** * This class is a java-part of BASIC-java interaction "driver" * It is used to call Star-Basic's function from java using * basic's part of "driver" where listeners are implemented. * The instance of the BasicHandler should be added to the MSF that will be * used for loading BASIC's part of "driver".
* After opening basic's document it creates an instance of the * HandlerContainer using BasicHandler. HandlerContainer is a UNO * XContainer and XNameContainer. * Only one instance of BasicHandler can be used at the moment. * @see com.sun.star.lang.XServiceInfo * @see com.sun.star.lang.XSingleServiceFactory */ public class BasicHandler implements XServiceInfo, XSingleServiceFactory { /** * serviceName is the name of service that can be created in BASIC. */ static final String serviceName = "com.sun.star.jsuite.basicrunner.BasicHandler"; /** * container is a SHARED variable (between BASIC and Java). * It is used for interacting. */ static private HandlerContainer container = null; /** * Contains a writer to log an information about the interface testing, to * allows for tests to access it. */ static private LogWriter log; /** * oHandlerDoc is a referrence to BASIC's document. */ static private XComponent oHandlerDoc = null; /** * xMSF is a MultiServiceFactory currently used by * BasicHandler. */ static private XMultiServiceFactory xMSF = null; /** * Interface being tested now. */ static private BasicIfcTest TestedInterface = null; /** * Ab enhanced scheme of timeouts can be used with BASIC tests. * A small timeout can be used zo wait for changes in the test status. * respFlag is set to true when a BASIC test * writes any log information. */ static private boolean respFlag = false; /** * iBasicTimeout is the amount of milliseconds that * the BasicHandler will wait for a response from tests * (finish to execute a method or add log information) * before it decides that SOffice is dead. */ static private int iBasicTimeout = 10000; /** * Creates an instance of a HandlerContainer. This instance is used from * BASIC. * @param tParam The test parameters. */ public BasicHandler(TestParameters tParam) { if (tParam.get("soapi.test.basic.debugFile") != null) { iBasicTimeout = 0; // Debug mode. } container = new HandlerContainer(this); } /** * Set the tested interface and a log writer. * @param ifc The test of an interface * @param log A log writer. */ public void setTestedInterface(BasicIfcTest ifc, LogWriter log) { this.log = log; TestedInterface = ifc; } /** * Is called when BASIC signals that it has performed the test of a method. * @param methodName The name of the method. * @bResult The result of the test. */ synchronized void methodTested(String methodName, boolean bResult) { respFlag = true; TestedInterface.methodTested(methodName, bResult); notify() ; } /** * Is called when BASIC sends a signal to write some log information. * @param info The string to write. */ synchronized public void Log(String info) { respFlag = true; log.println(info); notify() ; } /** * Is called by BasicIfcTest to find out if this BasicHandler uses the * correct MultiServiceFactory. * @param xMSF The MultiServiceFactory * @see com.sun.star.lang.XMultiServiceFactory * @return True, if xMSF is equal to the MultiServiceFactory of this class. */ public boolean isUptodate(XMultiServiceFactory xMSF) { return xMSF.equals(this.xMSF); } /** * Establishes a connection between BASIC and Java. * If required, hte BASIC part of the "driver" is loaded. * @param sBasicBridgeURL The URL of the basic bridge document * (BasicBridge.sxw) * @param tParam The test parameters. * @param xMSF The MultiServiceFactory * @param log The log writer. * @see com.sun.star.lang.XMultiServiceFactory * @throws ConnectionSetupException Exception is thrown, if no connection could be made. */ public synchronized void Connect(String sBasicBridgeURL, TestParameters tParam, XMultiServiceFactory xMSF, LogWriter log) throws ConnectionSetupException { this.log = log; try { this.xMSF = xMSF; Object oInterface = xMSF.createInstance( "com.sun.star.frame.Desktop"); XDesktop oDesktop = (XDesktop) UnoRuntime.queryInterface( XDesktop.class, oInterface); XComponentLoader oCLoader = (XComponentLoader) UnoRuntime.queryInterface( XComponentLoader.class, oDesktop); // load BasicBridge with MarcoEceutionMode = Always-no warn //PropertyValue[] DocArgs = null; PropertyValue[] DocArgs = new PropertyValue[1]; PropertyValue DocArg = new PropertyValue(); DocArg.Name = "MacroExecutionMode"; DocArg.Value = new Short( com.sun.star.document.MacroExecMode.ALWAYS_EXECUTE_NO_WARN); DocArgs[0] = DocArg; // configure Office to allow to execute macos PropertyValue [] ProvArgs = new PropertyValue [1]; PropertyValue Arg = new PropertyValue(); Arg.Name = "nodepath"; Arg.Value = "/org.openoffice.Office.Common/Security"; ProvArgs[0] = Arg; Object oProvider = xMSF.createInstance( "com.sun.star.configuration.ConfigurationProvider"); XMultiServiceFactory oProviderMSF = (XMultiServiceFactory) UnoRuntime.queryInterface( XMultiServiceFactory.class, oProvider); Object oSecure = oProviderMSF.createInstanceWithArguments( "com.sun.star.configuration.ConfigurationUpdateAccess", ProvArgs); XPropertySet oSecureProps = (XPropertySet) UnoRuntime.queryInterface(XPropertySet.class, oSecure); Object oScripting = oSecureProps.getPropertyValue("Scripting"); XPropertySet oScriptingSettings = (XPropertySet) UnoRuntime.queryInterface(XPropertySet.class, oScripting); oScriptingSettings.setPropertyValue("Warning", Boolean.FALSE); oScriptingSettings.setPropertyValue("OfficeBasic", new Integer(2)); XChangesBatch oSecureChange = (XChangesBatch) UnoRuntime.queryInterface(XChangesBatch.class, oSecure); oSecureChange.commitChanges(); // As we want to have some information about a debugFile // BEFORE connection is established // we pass the information about it in frame name. String sFrameName = (String)tParam.get( "soapi.test.basic.debugFile"); if (sFrameName == null) sFrameName = "BasicRunner"; oHandlerDoc = oCLoader.loadComponentFromURL(sBasicBridgeURL, sFrameName, 40, DocArgs); do { respFlag = false ; wait(10000); // waiting for basic response for 10 seconds. } while (respFlag && !container.hasByName("BASIC_Done")) ; if (!container.hasByName("BASIC_Done")) { throw new ConnectionSetupException("Connection timed out."); } } catch (Exception e) { System.out.println("Exception: " + e.toString()); throw new ConnectionSetupException(); } log.println("Java-BASIC connection established!"); } /** * Overloads perform(Strin fName, Object params) for convenience. * @return A proprty value as result. * public synchronized PropertyValue perform(String fName) throws BasicException { return perform(fName, ""); } */ /** * Perform a test of a method. * @param fName The name of the method to test. * @param params The test parameters. * @return A proprty value as result of the test. * @throws BasicException The method could not be executed. */ public synchronized PropertyValue perform(String fName, Object params) throws BasicException { try { container.callBasicFunction(fName, params); do { respFlag = false; // waiting for basic response for iBasicTimeout milliseconds. wait(iBasicTimeout); } while(respFlag && !container.hasByName("BASIC_Done")); } catch (InterruptedException e) { System.out.println("The operation " + fName + " was interrupted."); } catch (com.sun.star.lang.DisposedException de) { System.out.println("## Office is disposed"); } if (!container.hasByName("BASIC_Done")) { System.out.println("Operation timed out."); throw new BasicException( "Operation timed out."); } Object res = container.getByName("BASIC_Done") ; container.removeByName("BASIC_Done"); if (!(res instanceof PropertyValue)) { if (res == null) { System.out.println( "BasicBridge returns null"); throw new BasicException( "BasicBridge returns null"); } else { System.out.println( "BasicBridge returns wrong type: " + res.getClass()); throw new BasicException( "BasicBridge returns wrong type: " + res.getClass()); } } PropertyValue result = (PropertyValue) res ; if ((result.Value instanceof String) && (((String)result.Value)).startsWith("Exception")) { throw new BasicException((String)result.Value); } return result; } /** * Returns true, if name is a supported service of this class. * @param name The service name. * @return True, if the service is supported. */ public boolean supportsService(String name) { return serviceName.equals(name); } /** * Return all supported service names. * @return All supported services. */ public String[] getSupportedServiceNames() { return new String[] {serviceName}; } /** * Get the implementation name. * @return Implementation name. */ public String getImplementationName() { return getClass().getName(); } /** * Create an instance of HandlerContainer. * Arguments are not supported here, so they will be ignored. * @param args The arguments. * @return The instance. */ public Object createInstanceWithArguments(Object[] args) { return container; } /** * Create an instance of HandlerContainer. * @return The instance. */ public Object createInstance() { return createInstanceWithArguments(null); } /** * Dispose the BASIC document. */ public synchronized void dispose() { try { if (oHandlerDoc != null) { //oHandlerDoc.dispose(); util.DesktopTools.closeDoc(oHandlerDoc); wait(1000); } } catch (Exception e) { System.out.println("Exception: " + e.toString()); } } } /** * This class handles the communication between Java and BASIC. * @see com.sun.star.container.XContainer * @see com.sun.star.container.XNameContainer * @see com.sun.star.lang.XTypeProvider */ class HandlerContainer implements XContainer, XNameContainer, XTypeProvider{ /** Container for parameters. **/ Hashtable container = new Hashtable(20); /** * An array of listeners for container events. * @see com.sun.star.container.XContainerListener */ static XContainerListener[] listener = null; /** The BasicHandler belonging to this handler. **/ BasicHandler parent = null; /** * Constructor with the parent BasicHandler. * @param par The BasicHandler. */ public HandlerContainer(BasicHandler par) { parent = par; } /** * Call a BASIC function, meaning a test method. * @param fName The method name. * @param args Arguments for the method. */ public void callBasicFunction(String fName, Object args) { // BASIC's listener should be called ONLY in this case. if (container.containsKey(fName)) { container.remove(fName); } container.put(fName, args); if (listener != null) { ContainerEvent event = new ContainerEvent(); event.Element = fName; for (int i=0; i