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: BasicHandler.java,v $
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 ************************************************************************/
33 import com
.sun
.star
.beans
.PropertyValue
;
34 import com
.sun
.star
.beans
.XPropertySet
;
35 import com
.sun
.star
.connection
.ConnectionSetupException
;
36 import com
.sun
.star
.container
.ContainerEvent
;
37 import com
.sun
.star
.container
.XContainer
;
38 import com
.sun
.star
.container
.XContainerListener
;
39 import com
.sun
.star
.container
.XNameContainer
;
40 import com
.sun
.star
.frame
.XComponentLoader
;
41 import com
.sun
.star
.frame
.XDesktop
;
42 import com
.sun
.star
.lang
.WrappedTargetException
;
43 import com
.sun
.star
.lang
.XComponent
;
44 import com
.sun
.star
.lang
.XMultiServiceFactory
;
45 import com
.sun
.star
.lang
.XServiceInfo
;
46 import com
.sun
.star
.lang
.XSingleServiceFactory
;
47 import com
.sun
.star
.lang
.XTypeProvider
;
48 import com
.sun
.star
.uno
.Type
;
49 import com
.sun
.star
.uno
.UnoRuntime
;
50 import com
.sun
.star
.util
.XChangesBatch
;
51 import java
.util
.Hashtable
;
52 import lib
.TestParameters
;
54 import share
.LogWriter
;
58 * This class is a java-part of BASIC-java interaction "driver"
59 * It is used to call Star-Basic's function from java using
60 * basic's part of "driver" where listeners are implemented.
61 * The instance of the BasicHandler should be added to the MSF that will be
62 * used for loading BASIC's part of "driver".<br>
63 * After opening basic's document it creates an instance of the
64 * HandlerContainer using BasicHandler. HandlerContainer is a UNO
65 * XContainer and XNameContainer.
66 * Only one instance of BasicHandler can be used at the moment.
67 * @see com.sun.star.lang.XServiceInfo
68 * @see com.sun.star.lang.XSingleServiceFactory
70 public class BasicHandler
implements XServiceInfo
, XSingleServiceFactory
{
72 * serviceName is the name of service that can be created in BASIC.
74 static final String serviceName
=
75 "com.sun.star.jsuite.basicrunner.BasicHandler";
78 * <code>container</code> is a SHARED variable (between BASIC and Java).
79 * It is used for interacting.
81 static private HandlerContainer container
= null;
84 * Contains a writer to log an information about the interface testing, to
85 * allows for tests to access it.
87 static private LogWriter log
;
90 * <code>oHandlerDoc</code> is a referrence to BASIC's document.
92 static private XComponent oHandlerDoc
= null;
95 * <code>xMSF</code> is a MultiServiceFactory currently used by
98 static private XMultiServiceFactory xMSF
= null;
101 * Interface being tested now.
103 static private BasicIfcTest TestedInterface
= null;
106 * Ab enhanced scheme of timeouts can be used with BASIC tests.
107 * A small timeout can be used zo wait for changes in the test status.
108 * <code>respFlag</code> is set to <code>true</code> when a BASIC test
109 * writes any log information.
111 static private boolean respFlag
= false;
114 * <code>iBasicTimeout</code> is the amount of milliseconds that
115 * the BasicHandler will wait for a response from tests
116 * (finish to execute a method or add log information)
117 * before it decides that SOffice is dead.
119 static private int iBasicTimeout
= 10000;
124 * Creates an instance of a HandlerContainer. This instance is used from
126 * @param tParam The test parameters.
128 public BasicHandler(TestParameters tParam
) {
129 if (tParam
.get("soapi.test.basic.debugFile") != null) {
130 iBasicTimeout
= 0; // Debug mode.
132 container
= new HandlerContainer(this);
136 * Set the tested interface and a log writer.
137 * @param ifc The test of an interface
138 * @param log A log writer.
140 public void setTestedInterface(BasicIfcTest ifc
, LogWriter log
) {
142 TestedInterface
= ifc
;
146 * Is called when BASIC signals that it has performed the test of a method.
147 * @param methodName The name of the method.
148 * @bResult The result of the test.
150 synchronized void methodTested(String methodName
, boolean bResult
) {
152 TestedInterface
.methodTested(methodName
, bResult
);
157 * Is called when BASIC sends a signal to write some log information.
158 * @param info The string to write.
160 synchronized public void Log(String info
) {
167 * Is called by BasicIfcTest to find out if this BasicHandler uses the
168 * correct MultiServiceFactory.
169 * @param xMSF The MultiServiceFactory
170 * @see com.sun.star.lang.XMultiServiceFactory
171 * @return True, if xMSF is equal to the MultiServiceFactory of this class.
173 public boolean isUptodate(XMultiServiceFactory xMSF
) {
174 return xMSF
.equals(this.xMSF
);
179 * Establishes a connection between BASIC and Java.
180 * If required, hte BASIC part of the "driver" is loaded.
181 * @param sBasicBridgeURL The URL of the basic bridge document
183 * @param tParam The test parameters.
184 * @param xMSF The MultiServiceFactory
185 * @param log The log writer.
186 * @see com.sun.star.lang.XMultiServiceFactory
187 * @throws ConnectionSetupException Exception is thrown, if no connection could be made.
189 public synchronized void Connect(String sBasicBridgeURL
,
190 TestParameters tParam
, XMultiServiceFactory xMSF
,
191 LogWriter log
) throws ConnectionSetupException
{
195 Object oInterface
= xMSF
.createInstance(
196 "com.sun.star.frame.Desktop");
197 XDesktop oDesktop
= (XDesktop
) UnoRuntime
.queryInterface(
198 XDesktop
.class, oInterface
);
199 XComponentLoader oCLoader
= (XComponentLoader
)
200 UnoRuntime
.queryInterface(
201 XComponentLoader
.class, oDesktop
);
203 // load BasicBridge with MarcoEceutionMode = Always-no warn
204 //PropertyValue[] DocArgs = null;
205 PropertyValue
[] DocArgs
= new PropertyValue
[1];
206 PropertyValue DocArg
= new PropertyValue();
207 DocArg
.Name
= "MacroExecutionMode";
208 DocArg
.Value
= new Short(
209 com
.sun
.star
.document
.MacroExecMode
.ALWAYS_EXECUTE_NO_WARN
);
212 // configure Office to allow to execute macos
213 PropertyValue
[] ProvArgs
= new PropertyValue
[1];
214 PropertyValue Arg
= new PropertyValue();
215 Arg
.Name
= "nodepath";
216 Arg
.Value
= "/org.openoffice.Office.Common/Security";
219 Object oProvider
= xMSF
.createInstance(
220 "com.sun.star.configuration.ConfigurationProvider");
222 XMultiServiceFactory oProviderMSF
= (XMultiServiceFactory
)
223 UnoRuntime
.queryInterface(
224 XMultiServiceFactory
.class, oProvider
);
226 Object oSecure
= oProviderMSF
.createInstanceWithArguments(
227 "com.sun.star.configuration.ConfigurationUpdateAccess",
230 XPropertySet oSecureProps
= (XPropertySet
)
231 UnoRuntime
.queryInterface(XPropertySet
.class, oSecure
);
233 Object oScripting
= oSecureProps
.getPropertyValue("Scripting");
234 XPropertySet oScriptingSettings
= (XPropertySet
)
235 UnoRuntime
.queryInterface(XPropertySet
.class, oScripting
);
237 oScriptingSettings
.setPropertyValue("Warning", Boolean
.FALSE
);
238 oScriptingSettings
.setPropertyValue("OfficeBasic", new Integer(2));
240 XChangesBatch oSecureChange
= (XChangesBatch
)
241 UnoRuntime
.queryInterface(XChangesBatch
.class, oSecure
);
242 oSecureChange
.commitChanges();
244 // As we want to have some information about a debugFile
245 // BEFORE connection is established
246 // we pass the information about it in frame name.
247 String sFrameName
= (String
)tParam
.get(
248 "soapi.test.basic.debugFile");
249 if (sFrameName
== null) sFrameName
= "BasicRunner";
251 oHandlerDoc
= oCLoader
.loadComponentFromURL(sBasicBridgeURL
,
252 sFrameName
, 40, DocArgs
);
256 wait(10000); // waiting for basic response for 10 seconds.
257 } while (respFlag
&& !container
.hasByName("BASIC_Done")) ;
259 if (!container
.hasByName("BASIC_Done")) {
260 throw new ConnectionSetupException("Connection timed out.");
262 } catch (Exception e
) {
263 System
.out
.println("Exception: " + e
.toString());
264 throw new ConnectionSetupException();
267 log
.println("Java-BASIC connection established!");
271 * Overloads perform(Strin fName, Object params) for convenience.
272 * @return A proprty value as result.
274 public synchronized PropertyValue perform(String fName)
275 throws BasicException {
276 return perform(fName, "");
280 * Perform a test of a method.
281 * @param fName The name of the method to test.
282 * @param params The test parameters.
283 * @return A proprty value as result of the test.
284 * @throws BasicException The method could not be executed.
286 public synchronized PropertyValue
perform(String fName
, Object params
)
287 throws BasicException
{
289 container
.callBasicFunction(fName
, params
);
293 // waiting for basic response for iBasicTimeout milliseconds.
295 } while(respFlag
&& !container
.hasByName("BASIC_Done"));
297 } catch (InterruptedException e
) {
298 System
.out
.println("The operation " + fName
+ " was interrupted.");
299 } catch (com
.sun
.star
.lang
.DisposedException de
) {
300 System
.out
.println("## Office is disposed");
303 if (!container
.hasByName("BASIC_Done")) {
304 System
.out
.println("Operation timed out.");
305 throw new BasicException(
306 "Operation timed out.");
309 Object res
= container
.getByName("BASIC_Done") ;
310 container
.removeByName("BASIC_Done");
312 if (!(res
instanceof PropertyValue
)) {
315 "BasicBridge returns null");
316 throw new BasicException(
317 "BasicBridge returns null");
320 "BasicBridge returns wrong type: " + res
.getClass());
321 throw new BasicException(
322 "BasicBridge returns wrong type: " + res
.getClass());
326 PropertyValue result
= (PropertyValue
) res
;
328 if ((result
.Value
instanceof String
) && (((String
)result
.Value
)).startsWith("Exception")) {
329 throw new BasicException((String
)result
.Value
);
336 * Returns true, if name is a supported service of this class.
337 * @param name The service name.
338 * @return True, if the service is supported.
340 public boolean supportsService(String name
) {
341 return serviceName
.equals(name
);
345 * Return all supported service names.
346 * @return All supported services.
348 public String
[] getSupportedServiceNames() {
349 return new String
[] {serviceName
};
353 * Get the implementation name.
354 * @return Implementation name.
356 public String
getImplementationName() {
357 return getClass().getName();
361 * Create an instance of HandlerContainer.
362 * Arguments are not supported here, so they will be ignored.
363 * @param args The arguments.
364 * @return The instance.
366 public Object
createInstanceWithArguments(Object
[] args
) {
371 * Create an instance of HandlerContainer.
372 * @return The instance.
374 public Object
createInstance() {
375 return createInstanceWithArguments(null);
379 * Dispose the BASIC document.
381 public synchronized void dispose() {
383 if (oHandlerDoc
!= null) {
384 //oHandlerDoc.dispose();
385 util
.DesktopTools
.closeDoc(oHandlerDoc
);
388 } catch (Exception e
) {
389 System
.out
.println("Exception: " + e
.toString());
396 * This class handles the communication between Java and BASIC.
397 * @see com.sun.star.container.XContainer
398 * @see com.sun.star.container.XNameContainer
399 * @see com.sun.star.lang.XTypeProvider
401 class HandlerContainer
implements XContainer
, XNameContainer
, XTypeProvider
{
403 /** Container for parameters.
405 Hashtable container
= new Hashtable(20);
407 * An array of listeners for container events.
408 * @see com.sun.star.container.XContainerListener
410 static XContainerListener
[] listener
= null;
412 /** The BasicHandler belonging to this handler. **/
413 BasicHandler parent
= null;
416 * Constructor with the parent BasicHandler.
417 * @param par The BasicHandler.
419 public HandlerContainer(BasicHandler par
) {
424 * Call a BASIC function, meaning a test method.
425 * @param fName The method name.
426 * @param args Arguments for the method.
428 public void callBasicFunction(String fName
, Object args
) {
429 // BASIC's listener should be called ONLY in this case.
430 if (container
.containsKey(fName
)) {
431 container
.remove(fName
);
433 container
.put(fName
, args
);
434 if (listener
!= null) {
435 ContainerEvent event
= new ContainerEvent();
436 event
.Element
= fName
;
437 for (int i
=0; i
<listener
.length
; i
++){
438 if (listener
[i
] != null) {
439 listener
[i
].elementInserted(event
);
446 * Insert an object into the container.
447 * @param name The key for the object.
448 * @param object The object to insert.
449 * @throws IllegalArgumentException Throws this exception when trying to insert null.
451 public void insertByName(String name
, Object object
) throws com
.sun
.star
.lang
.IllegalArgumentException
, com
.sun
.star
.container
.ElementExistException
, com
.sun
.star
.lang
.WrappedTargetException
{
453 // BASIC and Java can insert into the container.
454 if (container
.containsKey(name
)) {
455 container
.remove(name
);
457 container
.put(name
, object
);
459 PropertyValue result
= null ;
461 if (object
instanceof PropertyValue
) {
462 result
= (PropertyValue
)object
;
463 if (name
.equals("BASIC_Done")) {
464 synchronized (parent
) {
467 } else if (name
.equals("BASIC_MethodTested")) {
468 parent
.methodTested(result
.Name
,
469 ((Boolean
)result
.Value
).booleanValue());
471 } else if (name
.equals("BASIC_Log")) {
472 parent
.Log(object
.toString());
477 * Remove the object with this name from the container.
478 * @param name The key.
480 public void removeByName(String name
) {
481 container
.remove(name
) ;
485 * Unsupported method.
486 * @param name The name of the key.
487 * @param value The value.
488 * @throws WrappedTargetException Throws this exception when called falsely.
490 public void replaceByName(String name
, Object value
)
491 throws WrappedTargetException
{
492 throw new WrappedTargetException("Unsupported");
496 * Has a value for this key.
497 * @param name The name of a key.
498 * @return True, if name exists as key in the container.
500 public boolean hasByName(String name
) {
501 return container
.containsKey(name
);
505 * Get an object by its key.
506 * @param name The name of the key.
507 * @return The object of this key.
509 public Object
getByName(String name
) {
510 return container
.get(name
);
515 * @return All names of keys.
517 public String
[] getElementNames() {
518 String
[] res
= new String
[container
.size()];
519 return (String
[])container
.keySet().toArray(res
);
523 * Is the xcontainer empty?
524 * @return True, if the container has elements.
526 public boolean hasElements() {
527 return !container
.isEmpty();
531 * Get the type of this class.
532 * @return The type of this class.
534 public Type
getElementType() {
536 return new Type(String
.class);
537 } catch (Exception e
) {
543 * Get the implementation id of this class.
544 * @return A unique id for this class
545 * @see com.sun.star.lang.XTypeProvider
547 public byte[] getImplementationId() {
548 return toString().getBytes();
552 * Get all types of this class.
553 * @return All implemented UNO types.
555 public Type
[] getTypes() {
556 Class interfaces
[] = getClass().getInterfaces();
557 Type types
[] = new Type
[interfaces
.length
];
558 for(int i
= 0; i
< interfaces
.length
; ++ i
) {
559 types
[i
] = new Type(interfaces
[i
]);
566 * @param xListener The listener.
568 public void addContainerListener(XContainerListener xListener
){
570 if (listener
!= null)
571 length
= listener
.length
;
573 XContainerListener
[] mListener
=
574 new XContainerListener
[length
+1];
575 for (int i
=0; i
<length
-1; i
++) {
576 mListener
[i
] = listener
[i
];
577 // listener already added
578 if (((Object
)xListener
).equals(listener
[i
]))
581 mListener
[length
] = xListener
;
582 listener
= mListener
;
587 * @param xListener The listener.
589 public void removeContainerListener(XContainerListener xListener
){
590 if (listener
!= null && listener
.length
!= 0) {
591 int length
= listener
.length
;
592 XContainerListener
[] mListener
=
593 new XContainerListener
[length
-1];
594 boolean found
= false;
596 for (int i
=0; i
<length
-1; i
++) {
597 if (!((Object
)xListener
).equals(listener
[j
])) {
598 mListener
[i
] = listener
[j
];
607 if (((Object
)xListener
).equals(listener
[length
-1]))
608 listener
= mListener
;
611 listener
= mListener
;