summaryrefslogtreecommitdiffstats
path: root/ridljar/com
diff options
context:
space:
mode:
Diffstat (limited to '')
-rw-r--r--ridljar/com/sun/star/comp/bridgefactory/BridgeFactory.java212
-rw-r--r--ridljar/com/sun/star/comp/connections/Acceptor.java153
-rw-r--r--ridljar/com/sun/star/comp/connections/Connector.java130
-rw-r--r--ridljar/com/sun/star/comp/connections/ConstantInstanceProvider.java118
-rw-r--r--ridljar/com/sun/star/comp/connections/Implementation.java95
-rw-r--r--ridljar/com/sun/star/comp/connections/PipedConnection.java259
-rw-r--r--ridljar/com/sun/star/comp/helper/Bootstrap.java492
-rw-r--r--ridljar/com/sun/star/comp/helper/BootstrapException.java82
-rw-r--r--ridljar/com/sun/star/comp/helper/ComponentContext.java308
-rw-r--r--ridljar/com/sun/star/comp/helper/ComponentContextEntry.java64
-rw-r--r--ridljar/com/sun/star/comp/helper/SharedLibraryLoader.java175
-rw-r--r--ridljar/com/sun/star/comp/loader/FactoryHelper.java502
-rw-r--r--ridljar/com/sun/star/comp/loader/JavaLoader.java439
-rw-r--r--ridljar/com/sun/star/comp/loader/JavaLoaderFactory.java90
-rw-r--r--ridljar/com/sun/star/comp/loader/RegistrationClassFinder.java69
-rw-r--r--ridljar/com/sun/star/comp/servicemanager/ServiceManager.java662
-rw-r--r--ridljar/com/sun/star/comp/urlresolver/UrlResolver.java147
-rw-r--r--ridljar/com/sun/star/lib/connections/pipe/PipeConnection.java213
-rw-r--r--ridljar/com/sun/star/lib/connections/pipe/pipeAcceptor.java123
-rw-r--r--ridljar/com/sun/star/lib/connections/pipe/pipeConnector.java120
-rw-r--r--ridljar/com/sun/star/lib/connections/socket/ConnectionDescriptor.java98
-rw-r--r--ridljar/com/sun/star/lib/connections/socket/SocketConnection.java235
-rw-r--r--ridljar/com/sun/star/lib/connections/socket/socketAcceptor.java202
-rw-r--r--ridljar/com/sun/star/lib/connections/socket/socketConnector.java174
-rw-r--r--ridljar/com/sun/star/lib/connections/websocket/ConnectionDescriptor.java60
-rw-r--r--ridljar/com/sun/star/lib/connections/websocket/WebsocketConnection.java326
-rw-r--r--ridljar/com/sun/star/lib/connections/websocket/websocketConnector.java137
-rw-r--r--ridljar/com/sun/star/lib/uno/Proxy.java34
-rw-r--r--ridljar/com/sun/star/lib/uno/adapter/ByteArrayToXInputStreamAdapter.java117
-rw-r--r--ridljar/com/sun/star/lib/uno/adapter/InputStreamToXInputStreamAdapter.java157
-rw-r--r--ridljar/com/sun/star/lib/uno/adapter/OutputStreamToXOutputStreamAdapter.java80
-rw-r--r--ridljar/com/sun/star/lib/uno/adapter/XInputStreamToInputStreamAdapter.java218
-rw-r--r--ridljar/com/sun/star/lib/uno/adapter/XOutputStreamToByteArrayAdapter.java94
-rw-r--r--ridljar/com/sun/star/lib/uno/adapter/XOutputStreamToOutputStreamAdapter.java117
-rw-r--r--ridljar/com/sun/star/lib/uno/bridges/java_remote/BridgedObject.java43
-rw-r--r--ridljar/com/sun/star/lib/uno/bridges/java_remote/ProxyFactory.java198
-rw-r--r--ridljar/com/sun/star/lib/uno/bridges/java_remote/RequestHandler.java35
-rw-r--r--ridljar/com/sun/star/lib/uno/bridges/java_remote/XConnectionInputStream_Adapter.java76
-rw-r--r--ridljar/com/sun/star/lib/uno/bridges/java_remote/XConnectionOutputStream_Adapter.java89
-rw-r--r--ridljar/com/sun/star/lib/uno/bridges/java_remote/java_remote_bridge.java700
-rw-r--r--ridljar/com/sun/star/lib/uno/environments/java/java_environment.java312
-rw-r--r--ridljar/com/sun/star/lib/uno/environments/remote/IProtocol.java93
-rw-r--r--ridljar/com/sun/star/lib/uno/environments/remote/IReceiver.java40
-rw-r--r--ridljar/com/sun/star/lib/uno/environments/remote/IThreadPool.java115
-rw-r--r--ridljar/com/sun/star/lib/uno/environments/remote/JavaThreadPool.java124
-rw-r--r--ridljar/com/sun/star/lib/uno/environments/remote/JavaThreadPoolFactory.java87
-rw-r--r--ridljar/com/sun/star/lib/uno/environments/remote/Job.java163
-rw-r--r--ridljar/com/sun/star/lib/uno/environments/remote/JobQueue.java373
-rw-r--r--ridljar/com/sun/star/lib/uno/environments/remote/Message.java189
-rw-r--r--ridljar/com/sun/star/lib/uno/environments/remote/NativeThreadPool.java94
-rw-r--r--ridljar/com/sun/star/lib/uno/environments/remote/ThreadId.java109
-rw-r--r--ridljar/com/sun/star/lib/uno/environments/remote/ThreadPoolManager.java74
-rw-r--r--ridljar/com/sun/star/lib/uno/environments/remote/remote_environment.java66
-rw-r--r--ridljar/com/sun/star/lib/uno/helper/ComponentBase.java136
-rw-r--r--ridljar/com/sun/star/lib/uno/helper/Factory.java291
-rw-r--r--ridljar/com/sun/star/lib/uno/helper/InterfaceContainer.java864
-rw-r--r--ridljar/com/sun/star/lib/uno/helper/MultiTypeInterfaceContainer.java155
-rw-r--r--ridljar/com/sun/star/lib/uno/helper/PropertySet.java1103
-rw-r--r--ridljar/com/sun/star/lib/uno/helper/PropertySetMixin.java1111
-rw-r--r--ridljar/com/sun/star/lib/uno/helper/UnoUrl.java401
-rw-r--r--ridljar/com/sun/star/lib/uno/helper/WeakAdapter.java94
-rw-r--r--ridljar/com/sun/star/lib/uno/helper/WeakBase.java101
-rw-r--r--ridljar/com/sun/star/lib/uno/protocols/urp/Cache.java114
-rw-r--r--ridljar/com/sun/star/lib/uno/protocols/urp/Marshal.java355
-rw-r--r--ridljar/com/sun/star/lib/uno/protocols/urp/PendingRequests.java65
-rw-r--r--ridljar/com/sun/star/lib/uno/protocols/urp/Unmarshal.java476
-rw-r--r--ridljar/com/sun/star/lib/uno/protocols/urp/UrpMessage.java48
-rw-r--r--ridljar/com/sun/star/lib/uno/protocols/urp/urp.java760
-rw-r--r--ridljar/com/sun/star/lib/uno/typedesc/FieldDescription.java78
-rw-r--r--ridljar/com/sun/star/lib/uno/typedesc/MemberDescriptionHelper.java54
-rw-r--r--ridljar/com/sun/star/lib/uno/typedesc/MethodDescription.java131
-rw-r--r--ridljar/com/sun/star/lib/uno/typedesc/TypeDescription.java819
-rw-r--r--ridljar/com/sun/star/lib/uno/typeinfo/AttributeTypeInfo.java86
-rw-r--r--ridljar/com/sun/star/lib/uno/typeinfo/ConstantTypeInfo.java32
-rw-r--r--ridljar/com/sun/star/lib/uno/typeinfo/MemberTypeInfo.java96
-rw-r--r--ridljar/com/sun/star/lib/uno/typeinfo/MethodTypeInfo.java89
-rw-r--r--ridljar/com/sun/star/lib/uno/typeinfo/ParameterTypeInfo.java105
-rw-r--r--ridljar/com/sun/star/lib/uno/typeinfo/TypeInfo.java76
-rw-r--r--ridljar/com/sun/star/lib/util/AsynchronousFinalizer.java117
-rw-r--r--ridljar/com/sun/star/lib/util/DisposeListener.java34
-rw-r--r--ridljar/com/sun/star/lib/util/DisposeNotifier.java44
-rw-r--r--ridljar/com/sun/star/lib/util/NativeLibraryLoader.java132
-rw-r--r--ridljar/com/sun/star/lib/util/StringHelper.java46
-rw-r--r--ridljar/com/sun/star/lib/util/UrlToFileMapper.java94
-rw-r--r--ridljar/com/sun/star/lib/util/WeakMap.java323
-rw-r--r--ridljar/com/sun/star/uno/Any.java151
-rw-r--r--ridljar/com/sun/star/uno/AnyConverter.java668
-rw-r--r--ridljar/com/sun/star/uno/Ascii.java43
-rw-r--r--ridljar/com/sun/star/uno/AsciiString.java44
-rw-r--r--ridljar/com/sun/star/uno/Enum.java50
-rw-r--r--ridljar/com/sun/star/uno/IBridge.java94
-rw-r--r--ridljar/com/sun/star/uno/IEnvironment.java144
-rw-r--r--ridljar/com/sun/star/uno/IMapping.java41
-rw-r--r--ridljar/com/sun/star/uno/IQueryInterface.java60
-rw-r--r--ridljar/com/sun/star/uno/MappingException.java65
-rw-r--r--ridljar/com/sun/star/uno/Type.java699
-rw-r--r--ridljar/com/sun/star/uno/UnoRuntime.java726
-rw-r--r--ridljar/com/sun/star/uno/WeakReference.java154
98 files changed, 20851 insertions, 0 deletions
diff --git a/ridljar/com/sun/star/comp/bridgefactory/BridgeFactory.java b/ridljar/com/sun/star/comp/bridgefactory/BridgeFactory.java
new file mode 100644
index 0000000000..031e60d3f1
--- /dev/null
+++ b/ridljar/com/sun/star/comp/bridgefactory/BridgeFactory.java
@@ -0,0 +1,212 @@
+/* -*- Mode: Java; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
+/*
+ * 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 com.sun.star.comp.bridgefactory;
+
+import java.math.BigInteger;
+import java.util.ArrayList;
+
+import com.sun.star.bridge.BridgeExistsException;
+import com.sun.star.bridge.XBridge;
+import com.sun.star.bridge.XBridgeFactory;
+import com.sun.star.bridge.XInstanceProvider;
+import com.sun.star.comp.loader.FactoryHelper;
+import com.sun.star.connection.XConnection;
+import com.sun.star.lang.XMultiServiceFactory;
+import com.sun.star.lang.XSingleServiceFactory;
+import com.sun.star.registry.XRegistryKey;
+import com.sun.star.uno.IBridge;
+import com.sun.star.uno.UnoRuntime;
+
+
+/**
+ * The BridgeFactory class implements the <code>XBridgeFactory</code> Interface.
+ *
+ * <p>It wraps the <code>UnoRuntime#getBridgeByName</code>method and delivers a
+ * XBridge component.</p>
+ *
+ * <p>This component is only usable for remote bridges.</p>
+ *
+ * @see com.sun.star.uno.UnoRuntime
+ * @since UDK1.0
+ */
+public class BridgeFactory implements XBridgeFactory/*, XEventListener*/ {
+ private static final boolean DEBUG = false;
+
+ /**
+ * The name of the service, the <code>JavaLoader</code> accesses this through
+ * reflection.
+ */
+ public static final String __serviceName = "com.sun.star.bridge.BridgeFactory";
+
+ /**
+ * Gives a factory for creating the service.
+ *
+ * <p>This method is called by the <code>JavaLoader</code>.</p>
+ *
+ * @param implName the name of the implementation for which a service is desired.
+ * @param multiFactory the service manager to be uses if needed.
+ * @param regKey the registryKey.
+ * @return returns a <code>XSingleServiceFactory</code> for creating the component.
+ *
+ * @see com.sun.star.comp.loader.JavaLoader
+ */
+ public static XSingleServiceFactory __getServiceFactory(String implName,
+ XMultiServiceFactory multiFactory,
+ XRegistryKey regKey)
+ {
+ XSingleServiceFactory xSingleServiceFactory = null;
+
+ if (implName.equals(BridgeFactory.class.getName()) )
+ xSingleServiceFactory = FactoryHelper.getServiceFactory(BridgeFactory.class,
+ multiFactory,
+ regKey);
+
+ return xSingleServiceFactory;
+ }
+
+ /**
+ * Creates a remote bridge and memorizes it under <code>sName</code>.
+ *
+ * @param sName the name to memorize the bridge.
+ * @param sProtocol the protocol the bridge should use.
+ * @param anInstanceProvider the instance provider.
+ * @return the bridge.
+ *
+ * @see com.sun.star.bridge.XBridgeFactory
+ */
+ public XBridge createBridge(String sName, String sProtocol, XConnection aConnection, XInstanceProvider anInstanceProvider) throws
+ BridgeExistsException,
+ com.sun.star.lang.IllegalArgumentException,
+ com.sun.star.uno.RuntimeException
+ {
+ boolean hasName = sName.length() != 0;
+ Object context = hasName ? sName : new UniqueToken();
+ // UnoRuntime.getBridgeByName internally uses context.toString() to
+ // distinguish bridges, so the result of
+ // new UniqueToken().toString() might clash with an explicit
+ // sName.toString(), but the UnoRuntime bridge management is
+ // obsolete anyway and should be removed
+
+ // do not create a new bridge, if one already exists
+ if (hasName) {
+ IBridge iBridges[] = UnoRuntime.getBridges();
+ for(int i = 0; i < iBridges.length; ++ i) {
+ XBridge xBridge = UnoRuntime.queryInterface(XBridge.class, iBridges[i]);
+
+ if(xBridge != null && xBridge.getName().equals(sName)) {
+ throw new BridgeExistsException(sName + " already exists");
+ }
+ }
+ }
+
+ XBridge xBridge;
+
+ try {
+ IBridge iBridge = UnoRuntime.getBridgeByName("java", context, "remote", context, hasName ? new Object[]{sProtocol, aConnection, anInstanceProvider, sName} : new Object[]{sProtocol, aConnection, anInstanceProvider});
+
+ xBridge = UnoRuntime.queryInterface(XBridge.class, iBridge);
+ }
+ catch (Exception e) {
+ throw new com.sun.star.lang.IllegalArgumentException(e, e.getMessage());
+ }
+
+ if(DEBUG) System.err.println("##### " + getClass().getName() + ".createBridge:" + sName + " " + sProtocol + " " + aConnection + " " + anInstanceProvider + " " + xBridge);
+
+ return xBridge;
+ }
+
+ /**
+ * Gets a remote bridge which must already exist.
+ *
+ * @param sName the name of the bridge.
+ * @return the bridge.
+ * @see com.sun.star.bridge.XBridgeFactory
+ */
+ public XBridge getBridge(String sName) throws com.sun.star.uno.RuntimeException {
+ XBridge xBridge = null;
+
+ IBridge iBridges[] = UnoRuntime.getBridges();
+ for(int i = 0; i < iBridges.length; ++ i) {
+ xBridge = UnoRuntime.queryInterface(XBridge.class, iBridges[i]);
+
+ if(xBridge != null) {
+ if(xBridge.getName().equals(sName))
+ break;
+
+ else
+ xBridge = null;
+ }
+ }
+
+
+ if(DEBUG) System.err.println("##### " + getClass().getName() + ".getBridge:" + sName + " " + xBridge);
+
+ return xBridge;
+ }
+
+ /**
+ * Gives all created bridges.
+ *
+ * @return the bridges.
+ * @see com.sun.star.bridge.XBridgeFactory
+ */
+ public synchronized XBridge[] getExistingBridges() throws com.sun.star.uno.RuntimeException {
+ ArrayList<XBridge> vector = new ArrayList<XBridge>();
+
+ IBridge iBridges[] = UnoRuntime.getBridges();
+ for(int i = 0; i < iBridges.length; ++ i) {
+ XBridge xBridge = UnoRuntime.queryInterface(XBridge.class, iBridges[i]);
+
+ if(xBridge != null)
+ vector.add(xBridge);
+ }
+
+ XBridge xBridges[]= new XBridge[vector.size()];
+ for(int i = 0; i < vector.size(); ++ i)
+ xBridges[i] = vector.get(i);
+
+ return xBridges;
+ }
+
+ private static final class UniqueToken {
+ public UniqueToken() {
+ synchronized (UniqueToken.class) {
+ token = counter.toString();
+ counter = counter.add(BigInteger.ONE);
+ }
+ }
+
+ /**
+ * Returns a string representation of the object.
+ *
+ * @return a string representation of the object.
+ * @see java.lang.Object#toString
+ */
+ @Override
+ public String toString() {
+ return token;
+ }
+
+ private final String token;
+ private static BigInteger counter = BigInteger.ZERO;
+ }
+}
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/ridljar/com/sun/star/comp/connections/Acceptor.java b/ridljar/com/sun/star/comp/connections/Acceptor.java
new file mode 100644
index 0000000000..996eaeb858
--- /dev/null
+++ b/ridljar/com/sun/star/comp/connections/Acceptor.java
@@ -0,0 +1,153 @@
+/* -*- Mode: Java; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
+/*
+ * 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 com.sun.star.comp.connections;
+
+import com.sun.star.comp.loader.FactoryHelper;
+import com.sun.star.connection.AlreadyAcceptingException;
+import com.sun.star.connection.ConnectionSetupException;
+import com.sun.star.connection.XAcceptor;
+import com.sun.star.connection.XConnection;
+import com.sun.star.lang.XMultiServiceFactory;
+import com.sun.star.lang.XSingleServiceFactory;
+import com.sun.star.registry.XRegistryKey;
+
+/**
+ * A component that implements the <code>XAcceptor</code> interface.
+ *
+ * <p>The <code>Acceptor</code> is a general component, that uses less general
+ * components (like <code>com.sun.star.connection.socketAcceptor</code>) to
+ * implement its functionality.</p>
+ *
+ * @see com.sun.star.connection.XAcceptor
+ * @see com.sun.star.connection.XConnection
+ * @see com.sun.star.connection.XConnector
+ * @see com.sun.star.comp.loader.JavaLoader
+ *
+ * @since UDK 1.0
+ */
+public final class Acceptor implements XAcceptor {
+ /**
+ * The name of the service.
+ *
+ * <p>The <code>JavaLoader</code> accesses this through reflection.</p>
+ *
+ * @see com.sun.star.comp.loader.JavaLoader
+ */
+ public static final String __serviceName
+ = "com.sun.star.connection.Acceptor";
+
+ /**
+ * Returns a factory for creating the service.
+ *
+ * <p>This method is called by the <code>JavaLoader</code>.</p>
+ *
+ * @param implName the name of the implementation for which a service is
+ * requested.
+ * @param multiFactory the service manager to be used (if needed).
+ * @param regKey the registry key.
+ * @return an <code>XSingleServiceFactory</code> for creating the component.
+ *
+ * @see com.sun.star.comp.loader.JavaLoader
+ */
+ public static XSingleServiceFactory __getServiceFactory(
+ String implName, XMultiServiceFactory multiFactory, XRegistryKey regKey)
+ {
+ return implName.equals(Acceptor.class.getName())
+ ? FactoryHelper.getServiceFactory(Acceptor.class, __serviceName,
+ multiFactory, regKey)
+ : null;
+ }
+
+ /**
+ * Constructs a new <code>Acceptor</code> that uses the given service
+ * factory to create a specific <code>XAcceptor</code>.
+ *
+ * @param serviceFactory the service factory to use.
+ */
+ public Acceptor(XMultiServiceFactory serviceFactory) {
+ this.serviceFactory = serviceFactory;
+ }
+
+ /**
+ * Accepts a connection request via the given connection type.
+ *
+ * <p>This call blocks until a connection has been established.</p>
+ *
+ * <p>The connection description has the following format:
+ * <code><var>type</var></code><!--
+ * -->*(<code><var>key</var>=<var>value</var></code>).
+ * The specific <code>XAcceptor</code> implementation is instantiated
+ * through the service factory as
+ * <code>com.sun.star.connection.<var>type</var>Acceptor</code> (with
+ * <code><var>type</var></code> in lower case).</p>
+ *
+ * @param connectionDescription the description of the connection.
+ * @return an <code>XConnection</code> to the client.
+ *
+ * @see com.sun.star.connection.XConnection
+ * @see com.sun.star.connection.XConnector
+ */
+ public XConnection accept(String connectionDescription) throws
+ AlreadyAcceptingException, ConnectionSetupException,
+ com.sun.star.lang.IllegalArgumentException
+ {
+ if (DEBUG) {
+ System.err.println("##### " + getClass().getName() + ".accept("
+ + connectionDescription + ")");
+ }
+ XAcceptor acc;
+ synchronized (this) {
+ if (acceptor == null) {
+ acceptor = (XAcceptor) Implementation.getConnectionService(
+ serviceFactory, connectionDescription, XAcceptor.class,
+ "Acceptor");
+ acceptingDescription = connectionDescription;
+ } else if (!connectionDescription.equals(acceptingDescription)) {
+ throw new AlreadyAcceptingException(acceptingDescription
+ + " vs. "
+ + connectionDescription);
+ }
+ acc = acceptor;
+ }
+ return acc.accept(connectionDescription);
+ }
+
+ /**
+ *
+ * @see com.sun.star.connection.XAcceptor#stopAccepting
+ */
+ public void stopAccepting() {
+ XAcceptor acc;
+ synchronized (this) {
+ acc = acceptor;
+ }
+ acc.stopAccepting();
+ }
+
+ private static final boolean DEBUG = false;
+
+ private final XMultiServiceFactory serviceFactory;
+
+ private XAcceptor acceptor = null;
+ private String acceptingDescription;
+}
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
+
diff --git a/ridljar/com/sun/star/comp/connections/Connector.java b/ridljar/com/sun/star/comp/connections/Connector.java
new file mode 100644
index 0000000000..6ffab9eea8
--- /dev/null
+++ b/ridljar/com/sun/star/comp/connections/Connector.java
@@ -0,0 +1,130 @@
+/* -*- Mode: Java; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
+/*
+ * 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 com.sun.star.comp.connections;
+
+import com.sun.star.comp.loader.FactoryHelper;
+import com.sun.star.connection.ConnectionSetupException;
+import com.sun.star.connection.NoConnectException;
+import com.sun.star.connection.XConnection;
+import com.sun.star.connection.XConnector;
+import com.sun.star.lang.XMultiServiceFactory;
+import com.sun.star.lang.XSingleServiceFactory;
+import com.sun.star.registry.XRegistryKey;
+
+/**
+ * A component that implements the <code>XConnector</code> interface.
+ *
+ * <p>The <code>Connector</code> is a general component, that uses less general
+ * components (like <code>com.sun.star.connection.socketConnector</code>) to
+ * implement its functionality.</p>
+ *
+ * @see com.sun.star.connection.XAcceptor
+ * @see com.sun.star.connection.XConnection
+ * @see com.sun.star.connection.XConnector
+ * @see com.sun.star.comp.loader.JavaLoader
+ *
+ * @since UDK 1.0
+ */
+public class Connector implements XConnector {
+ /**
+ * The name of the service.
+ *
+ * <p>The <code>JavaLoader</code> accesses this through reflection.</p>
+ *
+ * @see com.sun.star.comp.loader.JavaLoader
+ */
+ public static final String __serviceName
+ = "com.sun.star.connection.Connector";
+
+ /**
+ * Returns a factory for creating the service.
+ *
+ * <p>This method is called by the <code>JavaLoader</code>.</p>
+ *
+ * @param implName the name of the implementation for which a service is
+ * requested.
+ * @param multiFactory the service manager to be used (if needed).
+ * @param regKey the registry key.
+ * @return an <code>XSingleServiceFactory</code> for creating the component.
+ *
+ * @see com.sun.star.comp.loader.JavaLoader
+ */
+ public static XSingleServiceFactory __getServiceFactory(
+ String implName, XMultiServiceFactory multiFactory, XRegistryKey regKey)
+ {
+ return implName.equals(Connector.class.getName())
+ ? FactoryHelper.getServiceFactory(Connector.class, __serviceName,
+ multiFactory, regKey)
+ : null;
+ }
+
+ /**
+ * Constructs a new <code>Connector</code> that uses the given service
+ * factory to create a specific <code>XConnector</code>.
+ *
+ * @param serviceFactory the service factory to use.
+ */
+ public Connector(XMultiServiceFactory serviceFactory) {
+ this.serviceFactory = serviceFactory;
+ }
+
+ /**
+ * Connects via the given connection type to a waiting server.
+ *
+ * <p>The connection description has the following format:
+ * <code><var>type</var></code><!--
+ * -->*(<code><var>key</var>=<var>value</var></code>).
+ * The specific <code>XConnector</code> implementation is instantiated
+ * through the service factory as
+ * <code>com.sun.star.connection.<var>type</var>Connector</code> (with
+ * <code><var>type</var></code> in lower case).</p>
+ *
+ * @param connectionDescription the description of the connection.
+ * @return an <code>XConnection</code> to the server.
+ *
+ * @see com.sun.star.connection.XAcceptor
+ * @see com.sun.star.connection.XConnection
+ */
+ public synchronized XConnection connect(String connectionDescription)
+ throws NoConnectException, ConnectionSetupException
+ {
+ if (DEBUG) {
+ System.err.println("##### " + getClass().getName() + ".connect("
+ + connectionDescription + ")");
+ }
+ if (connected) {
+ throw new ConnectionSetupException("already connected");
+ }
+ XConnection con
+ = ((XConnector) Implementation.getConnectionService(
+ serviceFactory, connectionDescription, XConnector.class,
+ "Connector")).connect(connectionDescription);
+ connected = true;
+ return con;
+ }
+
+ private static final boolean DEBUG = false;
+
+ private final XMultiServiceFactory serviceFactory;
+
+ private boolean connected = false;
+}
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/ridljar/com/sun/star/comp/connections/ConstantInstanceProvider.java b/ridljar/com/sun/star/comp/connections/ConstantInstanceProvider.java
new file mode 100644
index 0000000000..6c2fcb2d85
--- /dev/null
+++ b/ridljar/com/sun/star/comp/connections/ConstantInstanceProvider.java
@@ -0,0 +1,118 @@
+/* -*- Mode: Java; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
+/*
+ * 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 com.sun.star.comp.connections;
+
+import com.sun.star.bridge.XInstanceProvider;
+
+import com.sun.star.lang.XMultiServiceFactory;
+import com.sun.star.lang.XSingleServiceFactory;
+
+import com.sun.star.registry.XRegistryKey;
+
+import com.sun.star.comp.loader.FactoryHelper;
+
+
+/**
+ * The <code>ConstantInstanceProvider</code> is a component
+ * that implements the <code>XInstanceProvider</code> Interface.
+ *
+ * @see com.sun.star.bridge.XBridge
+ * @see com.sun.star.bridge.XBridgeFactory
+ * @see com.sun.star.bridge.XInstanceProvider
+ * @see com.sun.star.comp.loader.JavaLoader
+ * @since UDK1.0
+ */
+public class ConstantInstanceProvider implements XInstanceProvider {
+ /**
+ * When set to true, enables various debugging output.
+ */
+ public static final boolean DEBUG = false;
+
+ /**
+ * The name of the service, the <code>JavaLoader</code> accesses this through
+ * reflection.
+ */
+ private static final String __serviceName = "com.sun.star.comp.connection.InstanceProvider";
+
+ /**
+ * Gives a factory for creating the service.
+ * <p>This method is called by the <code>JavaLoader</code>.</p>
+ *
+ * @param implName the name of the implementation for which a service is desired.
+ * @param multiFactory the service manager to be uses if needed.
+ * @param regKey the registryKey.
+ * @return returns a <code>XSingleServiceFactory</code> for creating the component.
+ *
+ * @see com.sun.star.comp.loader.JavaLoader
+ */
+ public static XSingleServiceFactory __getServiceFactory(String implName,
+ XMultiServiceFactory multiFactory,
+ XRegistryKey regKey)
+ {
+ XSingleServiceFactory xSingleServiceFactory = null;
+
+ if (implName.equals(ConstantInstanceProvider.class.getName()) )
+ xSingleServiceFactory = FactoryHelper.getServiceFactory(ConstantInstanceProvider.class,
+ __serviceName,
+ multiFactory,
+ regKey);
+
+ return xSingleServiceFactory;
+ }
+
+ protected XMultiServiceFactory _serviceManager;
+ protected String _serviceName;
+ protected Object _instance;
+
+
+ public void setInstance(String serviceName) throws com.sun.star.uno.Exception {
+ _instance = _serviceManager.createInstance(serviceName);
+ _serviceName = serviceName;
+ }
+
+ /**
+ * Constructs a new <code>ConstantInstanceProvider</code>.
+ * <p>Uses the provided ServiceManager as the provided instance.</p>
+ *
+ * @param serviceManager the provided service manager
+ */
+ public ConstantInstanceProvider(XMultiServiceFactory serviceManager) {
+ _serviceManager = serviceManager;
+
+ _serviceName = "SERVICEMANAGER";
+ _instance = serviceManager;
+ }
+
+ /**
+ * Gives an object for the passed instance name.
+ *
+ * @return the desired instance
+ * @param sInstanceName the name of the desired instance
+ */
+ public Object getInstance(String sInstanceName) throws com.sun.star.container.NoSuchElementException, com.sun.star.uno.RuntimeException {
+ Object result = sInstanceName.equals(_serviceName) ? _instance : null;
+
+ if(DEBUG) System.err.println("##### " + getClass().getName() + ".getInstance(" + sInstanceName + "):" + result);
+
+ return result;
+ }
+}
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/ridljar/com/sun/star/comp/connections/Implementation.java b/ridljar/com/sun/star/comp/connections/Implementation.java
new file mode 100644
index 0000000000..94cabe253a
--- /dev/null
+++ b/ridljar/com/sun/star/comp/connections/Implementation.java
@@ -0,0 +1,95 @@
+/* -*- Mode: Java; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
+/*
+ * 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 com.sun.star.comp.connections;
+
+import com.sun.star.connection.ConnectionSetupException;
+import com.sun.star.lang.XMultiServiceFactory;
+import com.sun.star.uno.UnoRuntime;
+
+/**
+ * Helper class for <code>Acceptor</code> and <code>Connector</code>.
+ */
+final class Implementation {
+ /**
+ * Instantiate a service for a given connection type.
+ *
+ * @param factory the service factory used to instantiate the requested
+ * service.
+ * @param description has the following format:
+ * <code><var>type</var></code><!--
+ * -->*(<code><var>key</var>=<var>value</var></code>).
+ * The specific service implementation is instantiated through the
+ * service factory as
+ * <code>com.sun.star.connection.<var>type</var>service<var></var><!--
+ * --></code>
+ * (with <code><var>type</var></code> in lower case, and
+ * <code><var>service</var></code> either <code>Acceptor</code> or
+ * <code>Connector</code>).
+ * @param serviceClass the IDL interface type for which to query the
+ * requested service.
+ * @param serviceType must be either <code>Acceptor</code> or
+ * <code>Connector</code>.
+ * @return an instance of the requested service. Never returns
+ * <code>null</code>.
+ * @throws ConnectionSetupException if the requested service can not be
+ * found, or cannot be instantiated.
+ */
+ public static Object getConnectionService(XMultiServiceFactory factory,
+ String description,
+ Class<?> serviceClass,
+ String serviceType)
+ throws ConnectionSetupException
+ {
+ int i = description.indexOf(',');
+ String type
+ = (i < 0 ? description : description.substring(0, i)).toLowerCase();
+ Object service = null;
+ try {
+ service = UnoRuntime.queryInterface(
+ serviceClass,
+ factory.createInstance("com.sun.star.connection." + type
+ + serviceType));
+ } catch (RuntimeException e) {
+ throw e;
+ } catch (com.sun.star.uno.Exception e) {
+ }
+ if (service == null) {
+ // As a fallback, also try to instantiate the service from the
+ // com.sun.star.lib.connections package structure:
+ try {
+ service
+ = Class.forName("com.sun.star.lib.connections." + type
+ + "." + type + serviceType).newInstance();
+ } catch (ClassNotFoundException e) {
+ } catch (IllegalAccessException e) {
+ } catch (InstantiationException e) {
+ }
+ }
+ if (service == null) {
+ throw new ConnectionSetupException("no " + serviceType + " for "
+ + type);
+ }
+ return service;
+ }
+
+ private Implementation() {} // do not instantiate
+}
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/ridljar/com/sun/star/comp/connections/PipedConnection.java b/ridljar/com/sun/star/comp/connections/PipedConnection.java
new file mode 100644
index 0000000000..631cfae40e
--- /dev/null
+++ b/ridljar/com/sun/star/comp/connections/PipedConnection.java
@@ -0,0 +1,259 @@
+/* -*- Mode: Java; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
+/*
+ * 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 com.sun.star.comp.connections;
+
+
+import com.sun.star.comp.loader.FactoryHelper;
+import com.sun.star.connection.XConnection;
+import com.sun.star.lang.XMultiServiceFactory;
+import com.sun.star.lang.XSingleServiceFactory;
+import com.sun.star.registry.XRegistryKey;
+
+/**
+ * The <code>PipedConnection</code> is a component that implements the
+ * <code>XConnection</code> Interface.
+ * <p>It is useful for <code>Thread</code> communication in one Process.</p>
+ *
+ * @see com.sun.star.connection.XConnection
+ * @see com.sun.star.comp.loader.JavaLoader
+ * @since UDK1.0
+ */
+public class PipedConnection implements XConnection {
+ /**
+ * When set to true, enables various debugging output.
+ */
+ public static final boolean DEBUG = false;
+
+ /**
+ * The name of the service, the <code>JavaLoader</code> accesses this through
+ * reflection.
+ */
+ private static final String __serviceName = "com.sun.star.connection.PipedConnection";
+
+ /**
+ * Gives a factory for creating the service.
+ * <p>This method is called by the <code>JavaLoader</code>.</p>
+ *
+ * @param implName the name of the implementation for which a service is desired.
+ * @param multiFactory the service manager to be uses if needed.
+ * @param regKey the registryKey.
+ * @return returns a <code>XSingleServiceFactory</code> for creating the component.
+ *
+ * @see com.sun.star.comp.loader.JavaLoader
+ */
+ public static XSingleServiceFactory __getServiceFactory(String implName,
+ XMultiServiceFactory multiFactory,
+ XRegistryKey regKey)
+ {
+ XSingleServiceFactory xSingleServiceFactory = null;
+
+ if (implName.equals(PipedConnection.class.getName()) )
+ xSingleServiceFactory = FactoryHelper.getServiceFactory(PipedConnection.class,
+ __serviceName,
+ multiFactory,
+ regKey);
+
+ return xSingleServiceFactory;
+ }
+
+ /**
+ * The amount of time in milliseconds, to wait to see check the buffers.
+ */
+ protected static final int __waitTime = 10000;
+
+ protected byte _buffer[] = new byte[4096];
+ protected int _in,
+ _out;
+ protected boolean _closed;
+ protected PipedConnection _otherSide;
+
+ /**
+ * Constructs a new <code>PipedConnection</code>, sees if there is another
+ * side, which it should be connected to.
+ *
+ * @param args Another side could be in index 0.
+ */
+ public PipedConnection(Object args[]) throws com.sun.star.uno.RuntimeException {
+ if (DEBUG) System.err.println("##### " + getClass().getName() + " - instantiated");
+
+ _otherSide = (args.length == 1) ? (PipedConnection)args[0] : null;
+ if(_otherSide != null) {
+ if(_otherSide == this)
+ throw new RuntimeException("can not connect to myself");
+
+ _otherSide._otherSide = this;
+ }
+ }
+
+ /**
+ * This is a private method, used to communicate internal in the pipe.
+ */
+ private synchronized void receive(byte aData[]) throws com.sun.star.io.IOException {
+ int bytesWritten = 0;
+
+ if(DEBUG) System.err.println("##### PipedConnection.receive - bytes:" + aData.length + " at:" + _out);
+
+ while(bytesWritten < aData.length) {
+ // wait until it is not full anymore
+ while(_out == (_in - 1) || (_in == 0 && _out == _buffer.length - 1)) {
+ try {
+ notify(); // the buffer is full, signal it
+
+ wait(__waitTime);
+ }
+ catch(InterruptedException interruptedException) {
+ throw new com.sun.star.io.IOException(interruptedException);
+ }
+ }
+
+ if(_closed) throw new com.sun.star.io.IOException("connection has been closed");
+
+ int bytes ;
+
+ if(_out < _in) {
+ bytes = Math.min(aData.length - bytesWritten, _in - _out - 1);
+
+ System.arraycopy(aData, bytesWritten, _buffer, _out, bytes);
+ }
+ else {
+ if(_in > 0){
+ bytes = Math.min(aData.length - bytesWritten, _buffer.length - _out);
+ }
+ else {
+ bytes = Math.min(aData.length - bytesWritten, _buffer.length - _out - 1);
+ }
+
+ System.arraycopy(aData, bytesWritten, _buffer, _out, bytes);
+ }
+
+ bytesWritten += bytes;
+ _out += bytes;
+ if(_out >= _buffer.length)
+ _out = 0;
+ }
+ }
+
+ /**
+ * Read the required number of bytes.
+ *
+ * @param aReadBytes the out parameter, where the bytes have to be placed.
+ * @param nBytesToRead the number of bytes to read.
+ * @return the number of bytes read.
+ *
+ * @see com.sun.star.connection.XConnection#read
+ */
+ public synchronized int read(/*OUT*/byte[][] aReadBytes, int nBytesToRead) throws com.sun.star.io.IOException, com.sun.star.uno.RuntimeException {
+ aReadBytes[0] = new byte[nBytesToRead];
+
+ if(DEBUG) System.err.println("##### PipedConnection.read - bytes:" + nBytesToRead + " at:" + _in);
+
+ // loop while not all bytes read or when closed but there is still data
+ while(nBytesToRead > 0 && (_in != _out || !_closed)) {
+ while(_in == _out && !_closed) {
+ try {
+ notify(); // the buffer is empty, signal it
+
+ wait(__waitTime); // we wait for data or for the pipe to be closed
+ }
+ catch(InterruptedException interruptedException) {
+ throw new com.sun.star.io.IOException(interruptedException);
+ }
+ }
+
+ if(_in < _out) {
+ int bytes = Math.min(nBytesToRead, _out - _in);
+
+ System.arraycopy(_buffer, _in, aReadBytes[0], aReadBytes[0].length - nBytesToRead, bytes);
+
+ nBytesToRead -= bytes;
+ _in += bytes;
+ }
+ else if(_in > _out) {
+ int bytes = Math.min(nBytesToRead, _buffer.length - _in);
+
+ System.arraycopy(_buffer, _in, aReadBytes[0], aReadBytes[0].length - nBytesToRead, bytes);
+
+ nBytesToRead -= bytes;
+ _in += bytes;
+ if(_in >= _buffer.length)
+ _in = 0;
+ }
+ }
+
+ if(nBytesToRead > 0) { // not all bytes read
+ byte tmp[] = new byte[aReadBytes[0].length - nBytesToRead];
+ System.arraycopy(aReadBytes[0], 0, tmp, 0, tmp.length);
+
+ aReadBytes[0] = tmp;
+ }
+
+ return aReadBytes[0].length;
+ }
+
+ /**
+ * Write bytes.
+ *
+ * @param aData the bytes to write.
+ * @see com.sun.star.connection.XConnection#write
+ */
+ public void write(byte aData[]) throws com.sun.star.io.IOException, com.sun.star.uno.RuntimeException {
+ _otherSide.receive(aData);
+ }
+
+ /**
+ * Flushes the buffer, notifies if necessary the other side that new data has
+ * arrived.
+ *
+ * @see com.sun.star.connection.XConnection#flush
+ */
+ public void flush() throws com.sun.star.io.IOException, com.sun.star.uno.RuntimeException {
+ synchronized(_otherSide) {
+ _otherSide.notify();
+ }
+ }
+
+ /**
+ * Closes the pipe.
+ *
+ * @see com.sun.star.connection.XConnection#close()
+ */
+ public synchronized void close() throws com.sun.star.io.IOException, com.sun.star.uno.RuntimeException {
+ if(!_closed) {
+ _closed = true;
+
+ _otherSide.close();
+
+ notify();
+ }
+ }
+
+ /**
+ * Gives a description of this pipe.
+ *
+ * @return the description.
+ * @see com.sun.star.connection.XConnection#getDescription
+ */
+ public String getDescription() throws com.sun.star.uno.RuntimeException {
+ return getClass().getName();
+ }
+
+}
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/ridljar/com/sun/star/comp/helper/Bootstrap.java b/ridljar/com/sun/star/comp/helper/Bootstrap.java
new file mode 100644
index 0000000000..6b371f5032
--- /dev/null
+++ b/ridljar/com/sun/star/comp/helper/Bootstrap.java
@@ -0,0 +1,492 @@
+// -*- Mode: Java; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*-
+
+/*
+ * 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 com.sun.star.comp.helper;
+
+import com.sun.star.bridge.UnoUrlResolver;
+import com.sun.star.bridge.XUnoUrlResolver;
+import com.sun.star.comp.loader.JavaLoader;
+import com.sun.star.comp.servicemanager.ServiceManager;
+import com.sun.star.container.XSet;
+import com.sun.star.lang.XInitialization;
+import com.sun.star.lang.XMultiServiceFactory;
+import com.sun.star.lang.XMultiComponentFactory;
+import com.sun.star.lib.util.NativeLibraryLoader;
+import com.sun.star.loader.XImplementationLoader;
+import com.sun.star.uno.UnoRuntime;
+import com.sun.star.uno.XComponentContext;
+import com.sun.star.beans.XPropertySet;
+
+import java.io.BufferedReader;
+import java.io.File;
+import java.io.InputStream;
+import java.io.InputStreamReader;
+import java.io.PrintStream;
+import java.io.UnsupportedEncodingException;
+import java.util.HashMap;
+import java.util.Hashtable;
+import java.util.Map;
+import java.util.Random;
+
+/** Bootstrap offers functionality to obtain a context or simply
+ a service manager.
+ The service manager can create a few basic services, whose implementations are:
+ <ul>
+ <li>com.sun.star.comp.loader.JavaLoader</li>
+ <li>com.sun.star.comp.urlresolver.UrlResolver</li>
+ <li>com.sun.star.comp.bridgefactory.BridgeFactory</li>
+ <li>com.sun.star.comp.connections.Connector</li>
+ <li>com.sun.star.comp.connections.Acceptor</li>
+ <li>com.sun.star.comp.servicemanager.ServiceManager</li>
+ </ul>
+
+ Other services can be inserted into the service manager by
+ using its XSet interface:
+ <pre>
+ XSet xSet = UnoRuntime.queryInterface( XSet.class, aMultiComponentFactory );
+ // insert the service manager
+ xSet.insert( aSingleComponentFactory );
+ </pre>
+*/
+public class Bootstrap {
+
+ private static void insertBasicFactories(
+ XSet xSet, XImplementationLoader xImpLoader )
+ throws Exception
+ {
+ // insert the factory of the loader
+ xSet.insert( xImpLoader.activate(
+ "com.sun.star.comp.loader.JavaLoader", null, null, null ) );
+
+ // insert the factory of the URLResolver
+ xSet.insert( xImpLoader.activate(
+ "com.sun.star.comp.urlresolver.UrlResolver", null, null, null ) );
+
+ // insert the bridgefactory
+ xSet.insert( xImpLoader.activate(
+ "com.sun.star.comp.bridgefactory.BridgeFactory", null, null, null ) );
+
+ // insert the connector
+ xSet.insert( xImpLoader.activate(
+ "com.sun.star.comp.connections.Connector", null, null, null ) );
+
+ // insert the acceptor
+ xSet.insert( xImpLoader.activate(
+ "com.sun.star.comp.connections.Acceptor", null, null, null ) );
+ }
+
+ /**
+ * Returns an array of default commandline options to start bootstrapped
+ * instance of soffice with. You may use it in connection with bootstrap
+ * method for example like this:
+ * <pre>
+ * List list = Arrays.asList( Bootstrap.getDefaultOptions() );
+ * list.remove("--nologo");
+ * list.remove("--nodefault");
+ * list.add("--invisible");
+ *
+ * Bootstrap.bootstrap( list.toArray( new String[list.size()] );
+ * </pre>
+ *
+ * @return an array of default commandline options
+ * @see #bootstrap( String[] )
+ * @since LibreOffice 5.1
+ */
+ public static final String[] getDefaultOptions()
+ {
+ return new String[]
+ {
+ "--nologo",
+ "--nodefault",
+ "--norestore",
+ "--nolockcheck"
+ };
+ }
+
+ /**
+ backwards compatibility stub.
+ @param context_entries the hash table contains mappings of entry names (type string) to
+ context entries (type class ComponentContextEntry).
+ @throws Exception if things go awry.
+ @return a new context.
+ */
+ public static XComponentContext createInitialComponentContext( Hashtable<String, Object> context_entries )
+ throws Exception
+ {
+ return createInitialComponentContext((Map<String, Object>) context_entries);
+ }
+ /** Bootstraps an initial component context with service manager and basic
+ jurt components inserted.
+ @param context_entries the hash table contains mappings of entry names (type string) to
+ context entries (type class ComponentContextEntry).
+ @throws Exception if things go awry.
+ @return a new context.
+ */
+ public static XComponentContext createInitialComponentContext( Map<String, Object> context_entries )
+ throws Exception
+ {
+ ServiceManager xSMgr = new ServiceManager();
+
+ XImplementationLoader xImpLoader = UnoRuntime.queryInterface(
+ XImplementationLoader.class, new JavaLoader() );
+ XInitialization xInit = UnoRuntime.queryInterface(
+ XInitialization.class, xImpLoader );
+ Object[] args = new Object [] { xSMgr };
+ xInit.initialize( args );
+
+ // initial component context
+ if (context_entries == null)
+ context_entries = new HashMap<String,Object>( 1 );
+ // add smgr
+ context_entries.put(
+ "/singletons/com.sun.star.lang.theServiceManager",
+ new ComponentContextEntry( null, xSMgr ) );
+ // ... xxx todo: add standard entries
+ XComponentContext xContext = new ComponentContext( context_entries, null );
+
+ xSMgr.setDefaultContext(xContext);
+
+ XSet xSet = UnoRuntime.queryInterface( XSet.class, xSMgr );
+ // insert basic jurt factories
+ insertBasicFactories( xSet, xImpLoader );
+
+ return xContext;
+ }
+
+ /**
+ * Bootstraps a servicemanager with the jurt base components registered.
+ *
+ * See also UNOIDL <code>com.sun.star.lang.ServiceManager</code>.
+ *
+ * @throws Exception if things go awry.
+ * @return a freshly bootstrapped service manager
+ */
+ public static XMultiServiceFactory createSimpleServiceManager() throws Exception
+ {
+ return UnoRuntime.queryInterface(
+ XMultiServiceFactory.class, createInitialComponentContext( (Map<String, Object>) null ).getServiceManager() );
+ }
+
+
+ /** Bootstraps the initial component context from a native UNO installation.
+
+ @throws Exception if things go awry.
+ @return a freshly bootstrapped component context.
+
+ See also
+ <code>cppuhelper/defaultBootstrap_InitialComponentContext()</code>.
+ */
+ public static final XComponentContext defaultBootstrap_InitialComponentContext()
+ throws Exception
+ {
+ return defaultBootstrap_InitialComponentContext( (String) null, (Map<String,String>) null );
+ }
+ /**
+ * Backwards compatibility stub.
+ *
+ * @param ini_file
+ * ini_file (may be null: uno.rc besides cppuhelper lib)
+ * @param bootstrap_parameters
+ * bootstrap parameters (maybe null)
+ *
+ * @throws Exception if things go awry.
+ * @return a freshly bootstrapped component context.
+ */
+ public static final XComponentContext defaultBootstrap_InitialComponentContext(
+ String ini_file, Hashtable<String,String> bootstrap_parameters )
+ throws Exception
+ {
+ return defaultBootstrap_InitialComponentContext(ini_file, (Map<String,String>) bootstrap_parameters);
+
+ }
+ /** Bootstraps the initial component context from a native UNO installation.
+
+ See also
+ <code>cppuhelper/defaultBootstrap_InitialComponentContext()</code>.
+
+ @param ini_file
+ ini_file (may be null: uno.rc besides cppuhelper lib)
+ @param bootstrap_parameters
+ bootstrap parameters (maybe null)
+
+ @throws Exception if things go awry.
+ @return a freshly bootstrapped component context.
+ */
+ public static final XComponentContext defaultBootstrap_InitialComponentContext(
+ String ini_file, Map<String,String> bootstrap_parameters )
+ throws Exception
+ {
+ // jni convenience: easier to iterate over array than calling Hashtable
+ String pairs [] = null;
+ if (null != bootstrap_parameters)
+ {
+ pairs = new String [ 2 * bootstrap_parameters.size() ];
+ int n = 0;
+ for (Map.Entry<String, String> bootstrap_parameter : bootstrap_parameters.entrySet()) {
+ pairs[ n++ ] = bootstrap_parameter.getKey();
+ pairs[ n++ ] = bootstrap_parameter.getValue();
+ }
+ }
+
+ if (! m_loaded_juh)
+ {
+ if ("The Android Project".equals(System.getProperty("java.vendor")))
+ {
+ // Find out if we are configured with DISABLE_DYNLOADING or
+ // not. Try to load the lo-bootstrap shared library which
+ // won't exist in the DISABLE_DYNLOADING case. (And which will
+ // be already loaded otherwise, so nothing unexpected happens
+ // that case.) Yeah, this would be simpler if I just could be
+ // bothered to keep a separate branch for DISABLE_DYNLOADING
+ // on Android, merging in master periodically, until I know
+ // for sure whether it is what I want, or not.
+
+ boolean disable_dynloading = false;
+ try {
+ System.loadLibrary( "lo-bootstrap" );
+ } catch ( UnsatisfiedLinkError e ) {
+ disable_dynloading = true;
+ }
+
+ if (!disable_dynloading)
+ {
+ NativeLibraryLoader.loadLibrary( Bootstrap.class.getClassLoader(), "juh" );
+ }
+ }
+ else
+ {
+ NativeLibraryLoader.loadLibrary( Bootstrap.class.getClassLoader(), "juh" );
+ }
+ m_loaded_juh = true;
+ }
+ return UnoRuntime.queryInterface(
+ XComponentContext.class,
+ cppuhelper_bootstrap(
+ ini_file, pairs, Bootstrap.class.getClassLoader() ) );
+ }
+
+ private static boolean m_loaded_juh = false;
+ private static native Object cppuhelper_bootstrap(
+ String ini_file, String bootstrap_parameters [], ClassLoader loader )
+ throws Exception;
+
+ /**
+ * Bootstraps the component context from a UNO installation.
+ *
+ * @throws BootstrapException if things go awry.
+ *
+ * @return a bootstrapped component context.
+ *
+ * @since UDK 3.1.0
+ */
+ public static final XComponentContext bootstrap()
+ throws BootstrapException {
+
+ String[] defaultArgArray = getDefaultOptions();
+ return bootstrap( defaultArgArray );
+ }
+
+ /**
+ * Bootstraps the component context from a UNO installation.
+ *
+ * @param argArray
+ * an array of strings - commandline options to start instance of
+ * soffice with
+ * @see #getDefaultOptions()
+ *
+ * @throws BootstrapException if things go awry.
+ *
+ * @return a bootstrapped component context.
+ *
+ * @since LibreOffice 5.1
+ */
+ public static final XComponentContext bootstrap( String[] argArray )
+ throws BootstrapException {
+
+ XComponentContext xContext = null;
+
+ try {
+ // create default local component context
+ XComponentContext xLocalContext =
+ createInitialComponentContext( (Map<String, Object>) null );
+ if ( xLocalContext == null )
+ throw new BootstrapException( "no local component context!" );
+
+ // find office executable relative to this class's class loader
+ String sOffice =
+ System.getProperty( "os.name" ).startsWith( "Windows" ) ?
+ "soffice.exe" : "soffice";
+ File fOffice = NativeLibraryLoader.getResource(
+ Bootstrap.class.getClassLoader(), sOffice );
+ if ( fOffice == null )
+ throw new BootstrapException( "no office executable found!" );
+
+ // create random pipe name
+ String sPipeName = "uno" +
+ Long.toString(randomPipeName.nextLong() & 0x7fffffffffffffffL);
+
+ // create call with arguments
+ String[] cmdArray = new String[ argArray.length + 2 ];
+ cmdArray[0] = fOffice.getPath();
+ cmdArray[1] = ( "--accept=pipe,name=" + sPipeName + ";urp;" );
+
+ System.arraycopy( argArray, 0, cmdArray, 2, argArray.length );
+
+ // start office process
+ Process p = Runtime.getRuntime().exec( cmdArray );
+ pipe( p.getInputStream(), System.out, "CO> " );
+ pipe( p.getErrorStream(), System.err, "CE> " );
+
+ // initial service manager
+ XMultiComponentFactory xLocalServiceManager =
+ xLocalContext.getServiceManager();
+ if ( xLocalServiceManager == null )
+ throw new BootstrapException( "no initial service manager!" );
+
+ // create a URL resolver
+ XUnoUrlResolver xUrlResolver =
+ UnoUrlResolver.create( xLocalContext );
+
+ // connection string
+ String sConnect = "uno:pipe,name=" + sPipeName +
+ ";urp;StarOffice.ComponentContext";
+
+ // wait until office is started
+ for (int i = 0;; ++i) {
+ try {
+ // try to connect to office
+ Object context = xUrlResolver.resolve( sConnect );
+ xContext = UnoRuntime.queryInterface(
+ XComponentContext.class, context);
+ if ( xContext == null )
+ throw new BootstrapException( "no component context!" );
+ break;
+ } catch ( com.sun.star.connection.NoConnectException ex ) {
+ // Wait 500 ms, then try to connect again, but do not wait
+ // longer than 5 min (= 600 * 500 ms) total:
+ if (i == 600) {
+ throw new BootstrapException(ex);
+ }
+ Thread.sleep( 500 );
+ }
+ }
+ } catch ( BootstrapException e ) {
+ throw e;
+ } catch ( java.lang.RuntimeException e ) {
+ throw e;
+ } catch ( java.lang.Exception e ) {
+ throw new BootstrapException( e );
+ }
+
+ return xContext;
+ }
+
+ /**
+ * Bootstraps the component context from a websocket location.
+ *
+ * @param url
+ * the ws:// or wss:// url of the websocket server
+ *
+ * @throws BootstrapException if things go awry.
+ *
+ * @return a bootstrapped component context.
+ *
+ * @since LibreOffice 24.2
+ */
+ public static final XComponentContext bootstrapWebsocketConnection( String url )
+ throws BootstrapException {
+
+ XComponentContext xContext = null;
+
+ try {
+ // create default local component context
+ XComponentContext xLocalContext =
+ createInitialComponentContext( (Map<String, Object>) null );
+ if ( xLocalContext == null )
+ throw new BootstrapException( "no local component context!" );
+
+ // initial service manager
+ XMultiComponentFactory xLocalServiceManager =
+ xLocalContext.getServiceManager();
+ if ( xLocalServiceManager == null )
+ throw new BootstrapException( "no initial service manager!" );
+
+ // create a URL resolver
+ XUnoUrlResolver xUrlResolver =
+ UnoUrlResolver.create( xLocalContext );
+
+ // connection string
+ String sConnect = "uno:websocket"
+ + ",url=" + url
+ + ";urp;StarOffice.ComponentContext";
+
+ try {
+ // try to connect to office
+ Object xOfficeServiceManager = xUrlResolver.resolve(sConnect);
+
+ xContext = UnoRuntime.queryInterface(XComponentContext.class, xOfficeServiceManager);
+
+ if ( xContext == null )
+ throw new BootstrapException( "no component context!" );
+ } catch ( com.sun.star.connection.NoConnectException ex ) {
+ throw new BootstrapException(ex);
+ }
+ } catch ( BootstrapException e ) {
+ throw e;
+ } catch ( java.lang.RuntimeException e ) {
+ throw e;
+ } catch ( java.lang.Exception e ) {
+ throw new BootstrapException( e );
+ }
+
+ return xContext;
+ }
+
+
+ private static final Random randomPipeName = new Random();
+
+ private static void pipe(
+ final InputStream in, final PrintStream out, final String prefix ) {
+
+ new Thread( "Pipe: " + prefix) {
+ @Override
+ public void run() {
+ try {
+ BufferedReader r = new BufferedReader(
+ new InputStreamReader(in, "UTF-8") );
+
+ for ( ; ; ) {
+ String s = r.readLine();
+ if ( s == null ) {
+ break;
+ }
+ out.println( prefix + s );
+ }
+ } catch ( UnsupportedEncodingException e ) {
+ e.printStackTrace( System.err );
+ } catch ( java.io.IOException e ) {
+ e.printStackTrace( System.err );
+ }
+ }
+ }.start();
+ }
+}
+
+// vim:set shiftwidth=4 softtabstop=4 expandtab:
diff --git a/ridljar/com/sun/star/comp/helper/BootstrapException.java b/ridljar/com/sun/star/comp/helper/BootstrapException.java
new file mode 100644
index 0000000000..11911bbc07
--- /dev/null
+++ b/ridljar/com/sun/star/comp/helper/BootstrapException.java
@@ -0,0 +1,82 @@
+/*
+ * 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 com.sun.star.comp.helper;
+
+/**
+ * BootstrapException is a checked exception that wraps an exception
+ * thrown by the original target.
+ *
+ * @since UDK 3.1.0
+ */
+public class BootstrapException extends java.lang.Exception {
+
+ /**
+ * This field holds the target exception.
+ */
+ private Exception m_target = null;
+
+ /**
+ * Constructs a <code>BootstrapException</code> with <code>null</code> as
+ * the target exception.
+ */
+ public BootstrapException() {
+ super();
+ }
+
+ /**
+ * Constructs a <code>BootstrapException</code> with the specified
+ * detail message.
+ *
+ * @param message the detail message
+ */
+ public BootstrapException( String message ) {
+ super( message );
+ }
+
+ /**
+ * Constructs a <code>BootstrapException</code> with the specified
+ * detail message and a target exception.
+ *
+ * @param message the detail message
+ * @param target the target exception
+ */
+ public BootstrapException( String message, Exception target ) {
+ super( message );
+ m_target = target;
+ }
+
+ /**
+ * Constructs a <code>BootstrapException</code> with a target exception.
+ *
+ * @param target the target exception
+ */
+ public BootstrapException( Exception target ) {
+ super();
+ m_target = target;
+ }
+
+ /**
+ * Get the thrown target exception.
+ *
+ * @return the target exception
+ */
+ public Exception getTargetException() {
+ return m_target;
+ }
+}
diff --git a/ridljar/com/sun/star/comp/helper/ComponentContext.java b/ridljar/com/sun/star/comp/helper/ComponentContext.java
new file mode 100644
index 0000000000..34649d5633
--- /dev/null
+++ b/ridljar/com/sun/star/comp/helper/ComponentContext.java
@@ -0,0 +1,308 @@
+/*
+ * 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 com.sun.star.comp.helper;
+
+import com.sun.star.uno.UnoRuntime;
+import com.sun.star.uno.Any;
+
+import com.sun.star.uno.DeploymentException;
+import com.sun.star.uno.XComponentContext;
+import com.sun.star.lang.XMultiComponentFactory;
+import com.sun.star.lang.XSingleComponentFactory;
+import com.sun.star.lang.XComponent;
+import com.sun.star.lang.XEventListener;
+import com.sun.star.lang.EventObject;
+
+import java.util.ArrayList;
+import java.util.Hashtable;
+import java.util.Map;
+
+
+
+class Disposer implements XEventListener
+{
+ private final XComponent m_xComp;
+
+
+ Disposer( XComponent xComp )
+ {
+ m_xComp = xComp;
+ }
+
+ public void disposing( EventObject Source )
+ {
+ m_xComp.dispose();
+ }
+}
+
+/** Component context implementation.
+*/
+public class ComponentContext implements XComponentContext, XComponent
+{
+ private static final boolean DEBUG = false;
+ private static final String SMGR_NAME = "/singletons/com.sun.star.lang.theServiceManager";
+ private static final String TDMGR_NAME = "/singletons/com.sun.star.reflection.theTypeDescriptionManager";
+
+ private Map<String,Object> m_table;
+ private XComponentContext m_xDelegate;
+
+ private XMultiComponentFactory m_xSMgr;
+ private boolean m_bDisposeSMgr;
+
+ private ArrayList<XEventListener> m_eventListener;
+
+ public ComponentContext( Hashtable<String,Object> table, XComponentContext xDelegate )
+ {
+ this((Map<String,Object>) table, xDelegate);
+ }
+
+ /** Ctor to create a component context passing a hashtable for values and a delegator
+ reference. Entries of the passed hashtable are either direct values or
+ ComponentContextEntry objects.
+
+ @param table
+ entries
+ @param xDelegate
+ if values are not found, request is delegated to this object
+ */
+ public ComponentContext( Map<String,Object> table, XComponentContext xDelegate )
+ {
+ m_eventListener = new ArrayList<XEventListener>();
+ m_table = table;
+ m_xDelegate = xDelegate;
+ m_xSMgr = null;
+ m_bDisposeSMgr = false;
+
+ Object o = table.get( SMGR_NAME );
+ if (o != null)
+ {
+ if (o instanceof ComponentContextEntry)
+ {
+ o = ((ComponentContextEntry)o).m_value;
+ }
+ m_xSMgr = UnoRuntime.queryInterface(
+ XMultiComponentFactory.class, o );
+ }
+ if (m_xSMgr != null)
+ {
+ m_bDisposeSMgr = true;
+ }
+ else if (m_xDelegate != null)
+ {
+ m_xSMgr = m_xDelegate.getServiceManager();
+ }
+
+ // listen for delegate
+ XComponent xComp = UnoRuntime.queryInterface(
+ XComponent.class, m_xDelegate );
+ if (xComp != null)
+ {
+ xComp.addEventListener( new Disposer( this ) );
+ }
+ }
+
+ // XComponentContext impl
+
+ public Object getValueByName( String rName )
+ {
+ Object o = m_table.get( rName );
+ if (o == null)
+ {
+ if (m_xDelegate != null)
+ {
+ return m_xDelegate.getValueByName( rName );
+ }
+ else
+ {
+ return Any.VOID;
+ }
+ }
+
+ if (!(o instanceof ComponentContextEntry))
+ {
+ // direct value in map
+ return o;
+ }
+
+ ComponentContextEntry entry = (ComponentContextEntry)o;
+ if (entry.m_lateInit == null)
+ {
+ return entry.m_value;
+ }
+
+ Object xInstance = null;
+ try
+ {
+ String serviceName = (String)entry.m_lateInit;
+ if (serviceName != null)
+ {
+ if (m_xSMgr != null)
+ {
+ xInstance = m_xSMgr.createInstanceWithContext( serviceName, this );
+ }
+ else
+ {
+ if (DEBUG)
+ System.err.println( "### no service manager instance for late init of singleton instance \"" + rName + "\"!" );
+ }
+ }
+ else
+ {
+ XSingleComponentFactory xCompFac = UnoRuntime.queryInterface( XSingleComponentFactory.class, entry.m_lateInit );
+ if (xCompFac != null)
+ {
+ xInstance = xCompFac.createInstanceWithContext( this );
+ }
+ else
+ {
+ if (DEBUG)
+ System.err.println( "### neither service name nor service factory given for late init of singleton instance \"" + rName + "\"!" );
+ }
+ }
+ }
+ catch (com.sun.star.uno.Exception exc)
+ {
+ if (DEBUG)
+ System.err.println( "### exception occurred on late init of singleton instance \"" + rName + "\": " + exc.getMessage() );
+ }
+
+ if (xInstance != null)
+ {
+ synchronized (entry)
+ {
+ if (entry.m_lateInit != null)
+ {
+ entry.m_value = xInstance;
+ entry.m_lateInit = null;
+ }
+ else // inited in the meantime
+ {
+ // dispose fresh service instance
+ XComponent xComp = UnoRuntime.queryInterface(
+ XComponent.class, xInstance );
+ if (xComp != null)
+ {
+ xComp.dispose();
+ }
+ }
+ }
+ }
+ else
+ {
+ if (DEBUG)
+ System.err.println( "### failed late init of singleton instance \"" + rName + "\"!" );
+ }
+ return entry.m_value;
+ }
+
+ public XMultiComponentFactory getServiceManager()
+ {
+ if (m_xSMgr == null)
+ {
+ throw new DeploymentException(
+ "null component context service manager" );
+ }
+ return m_xSMgr;
+ }
+
+ // XComponent impl
+
+ public void dispose()
+ {
+ if (DEBUG)
+ System.err.print( "> disposing context " + this );
+
+ // fire events
+ EventObject evt = new EventObject( this );
+ for (XEventListener listener : m_eventListener)
+ {
+ listener.disposing( evt );
+ }
+ m_eventListener.clear();
+
+ XComponent tdmgr = null;
+ // dispose values, then service manager, then typedescription manager
+ for (Map.Entry<String, Object> entry : m_table.entrySet())
+ {
+ String name = entry.getKey();
+ if (! name.equals( SMGR_NAME ))
+ {
+ Object o = entry.getValue();
+ if (o instanceof ComponentContextEntry)
+ {
+ o = ((ComponentContextEntry)o).m_value;
+ }
+
+ XComponent xComp = UnoRuntime.queryInterface( XComponent.class, o );
+ if (xComp != null)
+ {
+ if (name.equals( TDMGR_NAME ))
+ {
+ tdmgr = xComp;
+ }
+ else
+ {
+ xComp.dispose();
+ }
+ }
+ }
+ }
+ m_table.clear();
+
+ // smgr
+ if (m_bDisposeSMgr)
+ {
+ XComponent xComp = UnoRuntime.queryInterface(
+ XComponent.class, m_xSMgr );
+ if (xComp != null)
+ {
+ xComp.dispose();
+ }
+ }
+ m_xSMgr = null;
+
+ // tdmgr
+ if (tdmgr != null)
+ {
+ tdmgr.dispose();
+ }
+
+ if (DEBUG)
+ System.err.println( "... finished" );
+ }
+
+ public void addEventListener( XEventListener xListener )
+ {
+ if (xListener == null)
+ throw new com.sun.star.uno.RuntimeException( "Listener must not be null" );
+ if (m_eventListener.contains( xListener ))
+ throw new com.sun.star.uno.RuntimeException( "Listener already registered." );
+
+ m_eventListener.add( xListener );
+ }
+
+ public void removeEventListener( XEventListener xListener )
+ {
+ if (xListener == null)
+ throw new com.sun.star.uno.RuntimeException( "Listener must not be null" );
+ if (! m_eventListener.contains( xListener ))
+ throw new com.sun.star.uno.RuntimeException( "Listener is not registered." );
+
+ m_eventListener.remove( xListener );
+ }
+}
diff --git a/ridljar/com/sun/star/comp/helper/ComponentContextEntry.java b/ridljar/com/sun/star/comp/helper/ComponentContextEntry.java
new file mode 100644
index 0000000000..aa402d29c6
--- /dev/null
+++ b/ridljar/com/sun/star/comp/helper/ComponentContextEntry.java
@@ -0,0 +1,64 @@
+/*
+ * 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 com.sun.star.comp.helper;
+
+/** Component context entry for constructing ComponentContext objects.
+ <p>
+ A ComponentContextEntry is separated into a late-init and direct-value
+ purpose.
+ The first one is commonly used for singleton objects of the component
+ context, that are raised on first-time retrieval of the key.
+ You have to pass a com.sun.star.lang.XSingleComponentFactory
+ or string (=&gt; service name) object for this.
+ </p>
+*/
+public class ComponentContextEntry
+{
+ /** if late init of service instance, set service name (String) or
+ component factory (XSingleComponentFactory), null otherwise
+ */
+ public Object m_lateInit;
+ /** set entry value
+ */
+ public Object m_value;
+
+ /** Creating a late-init singleton entry component context entry.
+ The second parameter will be ignored and overwritten during
+ instantiation of the singleton instance.
+
+ @param lateInit
+ object factory or service string
+ @param value
+ pass null (dummy separating from second constructor signature)
+ */
+ public ComponentContextEntry( Object lateInit, Object value )
+ {
+ this.m_lateInit = lateInit;
+ this.m_value = value;
+ }
+ /** Creating a direct value component context entry.
+
+ @param value
+ pass null
+ */
+ public ComponentContextEntry( Object value )
+ {
+ this.m_lateInit = null;
+ this.m_value = value;
+ }
+}
diff --git a/ridljar/com/sun/star/comp/helper/SharedLibraryLoader.java b/ridljar/com/sun/star/comp/helper/SharedLibraryLoader.java
new file mode 100644
index 0000000000..035644efa0
--- /dev/null
+++ b/ridljar/com/sun/star/comp/helper/SharedLibraryLoader.java
@@ -0,0 +1,175 @@
+// -*- Mode: Java; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*-
+/*
+ * 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 com.sun.star.comp.helper;
+
+import com.sun.star.uno.UnoRuntime;
+import com.sun.star.lang.XMultiServiceFactory;
+import com.sun.star.lang.XSingleServiceFactory;
+import com.sun.star.registry.XRegistryKey;
+
+/**
+ * @deprecated use class Bootstrap bootstrapping a native UNO installation
+ * and use the shared library loader service.
+ *
+ * The <code>SharedLibraryLoader</code> class provides the functionality of the <code>com.sun.star.loader.SharedLibrary</code>
+ * service.
+ *
+ * See also UNOIDL <code>com.sun.star.lang.ServiceManager</code>.
+ *
+ * @see com.sun.star.loader.SharedLibrary
+ */
+@Deprecated
+public class SharedLibraryLoader {
+ /**
+ * The default library which contains the SharedLibraryLoader component
+ */
+ public static final String DEFAULT_LIBRARY = "shlibloader.uno";
+
+ /**
+ * The default implementation name
+ */
+ public static final String DEFAULT_IMPLEMENTATION = "com.sun.star.comp.stoc.DLLComponentLoader";
+
+ static {
+ if ("The Android Project".equals(System.getProperty("java.vendor"))) {
+ // See corresponding code in
+ // javaunohelper/com/sun/star/comp/helper/Bootstrap.java for more
+ // comments.
+
+ boolean disable_dynloading = false;
+ try {
+ System.loadLibrary("lo-bootstrap");
+ } catch (UnsatisfiedLinkError e) {
+ disable_dynloading = true;
+ }
+
+ if (!disable_dynloading)
+ System.loadLibrary("juh");
+ } else
+ System.loadLibrary("juh");
+ }
+
+ private static native boolean component_writeInfo(
+ String libName, XMultiServiceFactory smgr, XRegistryKey regKey,
+ ClassLoader loader );
+
+ private static native Object component_getFactory(
+ String libName, String implName, XMultiServiceFactory smgr,
+ XRegistryKey regKey, ClassLoader loader );
+
+ /**
+ * Supplies the ServiceFactory of the default SharedLibraryLoader.
+ * The defaults are "shlibloader.uno"
+ * for the library and "com.sun.star.comp.stoc.DLLComponentLoader"
+ * for the component name.
+ *
+ * See also UNOIDL <code>com.sun.star.lang.ServiceManager</code> and
+ * <code>com.sun.star.registry.RegistryKey</code>.
+ *
+ * @return the factory for the "com.sun.star.comp.stoc.DLLComponentLoader" component.
+ * @param smgr the ServiceManager
+ * @param regKey the root registry key
+ * @see com.sun.star.loader.SharedLibrary
+ */
+ public static XSingleServiceFactory getServiceFactory(
+ XMultiServiceFactory smgr,
+ XRegistryKey regKey )
+ {
+ return UnoRuntime.queryInterface(
+ XSingleServiceFactory.class,
+ component_getFactory(
+ DEFAULT_LIBRARY, DEFAULT_IMPLEMENTATION, smgr, regKey,
+ SharedLibraryLoader.class.getClassLoader() ) );
+ }
+
+ /**
+ * Loads and returns a specific factory for a given library and implementation name.
+ *
+ * See also UNOIDL <code>com.sun.star.lang.ServiceManager</code> and
+ * <code>com.sun.star.registry.RegistryKey</code>.
+ *
+ * @return the factory of the component
+ * @param libName the name of the shared library
+ * @param impName the implementation name of the component
+ * @param smgr the ServiceManager
+ * @param regKey the root registry key
+ * @see com.sun.star.loader.SharedLibrary
+ */
+ public static XSingleServiceFactory getServiceFactory(
+ String libName,
+ String impName,
+ XMultiServiceFactory smgr,
+ XRegistryKey regKey )
+ {
+ return UnoRuntime.queryInterface(
+ XSingleServiceFactory.class,
+ component_getFactory(
+ libName, impName, smgr, regKey,
+ SharedLibraryLoader.class.getClassLoader() ) );
+ }
+
+ /**
+ * Registers the SharedLibraryLoader under a RegistryKey.
+ *
+ * See also UNOIDL <code>com.sun.star.lang.ServiceManager</code> and
+ * <code>com.sun.star.registry.RegistryKey</code>.
+ *
+ * @return true if the registration was successful - otherwise false
+ * @param smgr the ServiceManager
+ * @param regKey the root key under that the component should be registered
+ * @see com.sun.star.loader.SharedLibrary
+ */
+ public static boolean writeRegistryServiceInfo(
+ com.sun.star.lang.XMultiServiceFactory smgr,
+ com.sun.star.registry.XRegistryKey regKey )
+ {
+ return component_writeInfo(
+ DEFAULT_LIBRARY, smgr, regKey,
+ SharedLibraryLoader.class.getClassLoader() );
+ }
+
+ /**
+ * Registers the SharedLibraryLoader under a RegistryKey.
+ *
+ * See also UNOIDL <code>com.sun.star.lang.ServiceManager</code> and
+ * <code>com.sun.star.registry.RegistryKey</code>.
+ *
+ * @return true if the registration was successful - otherwise false
+ * @param libName name of the shared library
+ * @param smgr the ServiceManager
+ * @param regKey the root key under that the component should be registered
+ * @throws com.sun.star.registry.InvalidRegistryException
+ * if the registry is not valid.
+ *
+ * @see com.sun.star.loader.SharedLibrary
+ */
+ public static boolean writeRegistryServiceInfo(
+ String libName,
+ com.sun.star.lang.XMultiServiceFactory smgr,
+ com.sun.star.registry.XRegistryKey regKey )
+
+ throws com.sun.star.registry.InvalidRegistryException,
+ com.sun.star.uno.RuntimeException
+ {
+ return component_writeInfo(
+ libName, smgr, regKey, SharedLibraryLoader.class.getClassLoader() );
+ }
+}
+
+// vim:set shiftwidth=4 softtabstop=4 expandtab:
diff --git a/ridljar/com/sun/star/comp/loader/FactoryHelper.java b/ridljar/com/sun/star/comp/loader/FactoryHelper.java
new file mode 100644
index 0000000000..fe56f594f2
--- /dev/null
+++ b/ridljar/com/sun/star/comp/loader/FactoryHelper.java
@@ -0,0 +1,502 @@
+/* -*- Mode: Java; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
+/*
+ * 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 com.sun.star.comp.loader;
+
+import java.lang.reflect.Constructor;
+import java.lang.reflect.Field;
+import java.lang.reflect.InvocationTargetException;
+
+import com.sun.star.uno.XComponentContext;
+import com.sun.star.lang.XInitialization;
+import com.sun.star.lang.XMultiServiceFactory;
+import com.sun.star.lang.XServiceInfo;
+import com.sun.star.lang.XSingleServiceFactory;
+import com.sun.star.lang.XSingleComponentFactory;
+import com.sun.star.lang.XTypeProvider;
+import com.sun.star.registry.XRegistryKey;
+import com.sun.star.uno.UnoRuntime;
+import com.sun.star.uno.Type;
+
+
+/**
+ * The purpose of this class to help component implementation.
+ *
+ * <p>This class has default implementations for <code>getServiceFactory</code>
+ * and <code>writeRegistryServiceInfo</code>.</p>
+ *
+ * @see com.sun.star.lang.XMultiServiceFactory
+ * @see com.sun.star.lang.XServiceInfo
+ * @see com.sun.star.lang.XSingleServiceFactory
+ * @see com.sun.star.registry.XRegistryKey
+ * @since UDK1.0
+ */
+public class FactoryHelper {
+
+ private static final boolean DEBUG = false;
+ // the factory
+ protected static class Factory
+ implements XSingleServiceFactory, XSingleComponentFactory, XServiceInfo,
+ XTypeProvider {
+
+ protected XMultiServiceFactory _xMultiServiceFactory;
+ protected XRegistryKey _xRegistryKey;
+ protected int _nCode;
+ protected Constructor<?> _constructor;
+ protected String _implName;
+ protected String _serviceName;
+
+ protected Factory(Class<?> implClass,
+ String serviceName,
+ XMultiServiceFactory xMultiServiceFactory,
+ XRegistryKey xRegistryKey)
+ {
+ _xMultiServiceFactory = xMultiServiceFactory;
+ _xRegistryKey = xRegistryKey;
+ _implName = implClass.getName();
+ _serviceName = serviceName;
+
+ Constructor<?> constructors[] = implClass.getConstructors();
+ for(int i = 0; i < constructors.length && _constructor == null; ++i) {
+ Class<?> parameters[] = constructors[i].getParameterTypes();
+
+ if(parameters.length == 3
+ && parameters[0].equals(XComponentContext.class)
+ && parameters[1].equals(XRegistryKey.class)
+ && parameters[2].equals(Object[].class)) {
+ _nCode = 0;
+ _constructor = constructors[i];
+ }
+ else if(parameters.length == 2
+ && parameters[0].equals(XComponentContext.class)
+ && parameters[1].equals(XRegistryKey.class)) {
+ _nCode = 1;
+ _constructor = constructors[i];
+ }
+ else if(parameters.length == 2
+ && parameters[0].equals(XComponentContext.class)
+ && parameters[1].equals(Object[].class)) {
+ _nCode = 2;
+ _constructor = constructors[i];
+ }
+ else if(parameters.length == 1
+ && parameters[0].equals(XComponentContext.class)) {
+ _nCode = 3;
+ _constructor = constructors[i];
+ }
+ // depr
+ else if(parameters.length == 3
+ && parameters[0].equals(XMultiServiceFactory.class)
+ && parameters[1].equals(XRegistryKey.class)
+ && parameters[2].equals(Object[].class)) {
+ _nCode = 4;
+ _constructor = constructors[i];
+ }
+ else if(parameters.length == 2
+ && parameters[0].equals(XMultiServiceFactory.class)
+ && parameters[1].equals(XRegistryKey.class)) {
+ _nCode = 5;
+ _constructor = constructors[i];
+ }
+ else if(parameters.length == 2
+ && parameters[0].equals(XMultiServiceFactory.class)
+ && parameters[1].equals(Object[].class)) {
+ _nCode = 6;
+ _constructor = constructors[i];
+ }
+ else if(parameters.length == 1
+ && parameters[0].equals(XMultiServiceFactory.class)) {
+ _nCode = 7;
+ _constructor = constructors[i];
+ }
+ else if(parameters.length == 1
+ && parameters[0].equals(Object[].class)) {
+ _nCode = 8;
+ _constructor = constructors[i];
+ }
+ else if(parameters.length == 0) {
+ _nCode = 9;
+ _constructor = constructors[i];
+ }
+ }
+
+ if(_constructor == null) // have not found a usable constructor
+ throw new com.sun.star.uno.RuntimeException(getClass().getName() + " can not find a usable constructor");
+ }
+
+ private final XMultiServiceFactory getSMgr( XComponentContext xContext )
+ {
+ if (xContext != null)
+ {
+ return UnoRuntime.queryInterface(
+ XMultiServiceFactory.class, xContext.getServiceManager() );
+ }
+ else
+ {
+ return _xMultiServiceFactory;
+ }
+ }
+
+ // XComponentContext impl
+
+ public Object createInstanceWithContext(
+ XComponentContext xContext )
+ throws com.sun.star.uno.Exception
+ {
+ Object args[];
+ switch (_nCode)
+ {
+ case 0:
+ args = new Object [] { xContext, _xRegistryKey, new Object[ 0 ] };
+ break;
+ case 1:
+ args = new Object [] { xContext, _xRegistryKey };
+ break;
+ case 2:
+ args = new Object [] { xContext, new Object[ 0 ] };
+ break;
+ case 3:
+ args = new Object [] { xContext };
+ break;
+ case 4:
+ args = new Object [] { getSMgr( xContext ), _xRegistryKey, new Object[ 0 ] };
+ break;
+ case 5:
+ args = new Object [] { getSMgr( xContext ), _xRegistryKey };
+ break;
+ case 6:
+ args = new Object [] { getSMgr( xContext ), new Object[ 0 ] };
+ break;
+ case 7:
+ args = new Object [] { getSMgr( xContext ) };
+ break;
+ case 8:
+ args = new Object [] { new Object[ 0 ] };
+ break;
+ default:
+ args = new Object [ 0 ];
+ break;
+ }
+
+ try {
+ return _constructor.newInstance( args );
+ } catch (InvocationTargetException invocationTargetException) {
+ Throwable targetException = invocationTargetException.getCause();
+
+ if (targetException instanceof java.lang.RuntimeException)
+ throw (java.lang.RuntimeException)targetException;
+ else if (targetException instanceof com.sun.star.uno.Exception)
+ throw (com.sun.star.uno.Exception)targetException;
+ else if (targetException instanceof com.sun.star.uno.RuntimeException)
+ throw (com.sun.star.uno.RuntimeException)targetException;
+ else
+ throw new com.sun.star.uno.Exception( targetException );
+ } catch (IllegalAccessException illegalAccessException) {
+ throw new com.sun.star.uno.Exception( illegalAccessException );
+ } catch (InstantiationException instantiationException) {
+ throw new com.sun.star.uno.Exception( instantiationException );
+ }
+ }
+
+ public Object createInstanceWithArgumentsAndContext(
+ Object rArguments[], XComponentContext xContext )
+ throws com.sun.star.uno.Exception
+ {
+ Object args[];
+
+ boolean bInitCall = true;
+ switch (_nCode)
+ {
+ case 0:
+ args = new Object [] { xContext, _xRegistryKey, rArguments };
+ bInitCall = false;
+ break;
+ case 1:
+ args = new Object [] { xContext, _xRegistryKey };
+ break;
+ case 2:
+ args = new Object [] { xContext, rArguments };
+ bInitCall = false;
+ break;
+ case 3:
+ args = new Object [] { xContext };
+ break;
+ case 4:
+ args = new Object [] { getSMgr( xContext ), _xRegistryKey, rArguments };
+ bInitCall = false;
+ break;
+ case 5:
+ args = new Object [] { getSMgr( xContext ), _xRegistryKey };
+ break;
+ case 6:
+ args = new Object [] { getSMgr( xContext ), rArguments };
+ bInitCall = false;
+ break;
+ case 7:
+ args = new Object [] { getSMgr( xContext ) };
+ break;
+ case 8:
+ args = new Object [] { rArguments };
+ bInitCall = false;
+ break;
+ default:
+ args = new Object [ 0 ];
+ break;
+ }
+
+ try {
+ Object instance = _constructor.newInstance( args );
+ if (bInitCall)
+ {
+ XInitialization xInitialization = UnoRuntime.queryInterface(
+ XInitialization.class, instance );
+ if (xInitialization != null)
+ {
+ xInitialization.initialize( rArguments );
+ }
+ }
+ return instance;
+ } catch (InvocationTargetException invocationTargetException) {
+ Throwable targetException = invocationTargetException.getCause();
+
+ if (targetException instanceof java.lang.RuntimeException)
+ throw (java.lang.RuntimeException)targetException;
+ else if (targetException instanceof com.sun.star.uno.Exception)
+ throw (com.sun.star.uno.Exception)targetException;
+ else if (targetException instanceof com.sun.star.uno.RuntimeException)
+ throw (com.sun.star.uno.RuntimeException)targetException;
+ else
+ throw new com.sun.star.uno.Exception( targetException );
+ } catch (IllegalAccessException illegalAccessException) {
+ throw new com.sun.star.uno.Exception( illegalAccessException );
+ } catch (InstantiationException instantiationException) {
+ throw new com.sun.star.uno.Exception( instantiationException );
+ }
+ }
+
+ /**
+ * Creates an instance of the desired service.
+ *
+ * @return returns an instance of the desired service.
+ * @see com.sun.star.lang.XSingleServiceFactory
+ */
+ public Object createInstance()
+ throws com.sun.star.uno.Exception,
+ com.sun.star.uno.RuntimeException
+ {
+ return createInstanceWithContext( null );
+ }
+
+ /**
+ * Creates an instance of the desired service.
+ *
+ * @param args the args given to the constructor of the service.
+ * @return returns an instance of the desired service.
+ *
+ * @see com.sun.star.lang.XSingleServiceFactory
+ */
+ public Object createInstanceWithArguments(Object[] args)
+ throws com.sun.star.uno.Exception,
+ com.sun.star.uno.RuntimeException
+ {
+ return createInstanceWithArgumentsAndContext( args, null );
+ }
+
+ /**
+ * Gives the supported services.
+ *
+ * @return returns an array of supported services.
+ * @see com.sun.star.lang.XServiceInfo
+ */
+ public String[] getSupportedServiceNames() throws com.sun.star.uno.RuntimeException {
+ return new String[]{_serviceName};
+ }
+
+ /**
+ * Gives the implementation name.
+ *
+ * @return returns the implementation name.
+ * @see com.sun.star.lang.XServiceInfo
+ */
+ public String getImplementationName() throws com.sun.star.uno.RuntimeException {
+ return _implName;
+ }
+
+ /**
+ * Indicates if the given service is supported.
+ *
+ * @return returns true if the given service is supported.
+ * @see com.sun.star.lang.XServiceInfo
+ */
+ public boolean supportsService(String serviceName) throws com.sun.star.uno.RuntimeException {
+ String services[] = getSupportedServiceNames();
+
+ boolean found = false;
+
+ for(int i = 0; i < services.length && !found; ++i)
+ found = services[i].equals(serviceName);
+
+ return found;
+ }
+
+ //XTypeProvider
+ public byte[] getImplementationId()
+ {
+ return new byte[0];
+ }
+ //XTypeProvider
+ public com.sun.star.uno.Type[] getTypes()
+ {
+ Type[] t = new Type[] {
+ new Type(XSingleServiceFactory.class),
+ new Type(XSingleComponentFactory.class),
+ new Type(XServiceInfo.class),
+ new Type(XTypeProvider.class)
+ };
+ return t;
+ }
+
+ }
+
+ /**
+ * Creates a factory for the given class.
+ *
+ * @param implClass the implementing class.
+ * @param multiFactory the given multi service factory (service manager).
+ * @param regKey the given registry key.
+ * @return returns a factory.
+ *
+ * @see com.sun.star.lang.XServiceInfo
+ * @deprecated as of UDK 1.0
+ */
+ @Deprecated
+ public static XSingleServiceFactory getServiceFactory(Class<?> implClass,
+ XMultiServiceFactory multiFactory,
+ XRegistryKey regKey)
+ {
+ XSingleServiceFactory xSingleServiceFactory = null;
+
+ try {
+ Field serviceName ;
+
+ try {
+ serviceName = implClass.getField("__serviceName");
+ } catch(NoSuchFieldException noSuchFieldExceptio) {
+ serviceName = implClass.getField("serviceName"); // old style
+ }
+
+ xSingleServiceFactory = new Factory(implClass, (String)serviceName.get(null), multiFactory, regKey);
+ } catch(NoSuchFieldException noSuchFieldException) {
+ System.err.println("##### FactoryHelper.getServiceFactory - exception:" + noSuchFieldException);
+ } catch(IllegalAccessException illegalAccessException) {
+ System.err.println("##### FactoryHelper.getServiceFactory - exception:" + illegalAccessException);
+ }
+
+ return xSingleServiceFactory;
+ }
+
+ /**
+ * Creates a factory for the given class.
+ *
+ * @param implClass the implementing class.
+ * @param serviceName the service name of the implementing class.
+ * @param multiFactory the given multi service factory (service manager).
+ * @param regKey the given registry key.
+ *
+ * @return returns a factory.
+ * @see com.sun.star.lang.XServiceInfo
+ */
+ public static XSingleServiceFactory getServiceFactory(Class<?> implClass,
+ String serviceName,
+ XMultiServiceFactory multiFactory,
+ XRegistryKey regKey)
+ {
+ return new Factory(implClass, serviceName, multiFactory, regKey);
+ }
+
+ /**
+ * Creates a factory for the given class.
+ *
+ * @param implClass the implementing class.
+ * @return returns a factory object.
+ */
+ public static Object createComponentFactory( Class<?> implClass, String serviceName )
+ {
+ return new Factory( implClass, serviceName, null, null );
+ }
+
+ /**
+ * Writes the registration data into the registry key.
+ *
+ * @param implName the name of the implementing class.
+ * @param serviceName the service name.
+ * @param regKey the given registry key.
+ * @return success.
+ *
+ * @see com.sun.star.lang.XServiceInfo
+ */
+ public static boolean writeRegistryServiceInfo(String implName, String serviceName, XRegistryKey regKey) {
+ boolean result = false;
+
+ try {
+ XRegistryKey newKey = regKey.createKey("/" + implName + "/UNO/SERVICES");
+
+ newKey.createKey(serviceName);
+
+ result = true;
+ }
+ catch (Exception ex) {
+ System.err.println(">>>Connection_Impl.writeRegistryServiceInfo " + ex);
+ }
+
+ return result;
+ }
+
+ /**
+ * Writes the registration data into the registry key.
+ *
+ * <p>Several services are supported.</p>
+ *
+ * @param impl_name name of implementation.
+ * @param supported_services supported services of implementation.
+ * @param xKey registry key to write to.
+ * @return success.
+ */
+ public static boolean writeRegistryServiceInfo(
+ String impl_name, String supported_services [], XRegistryKey xKey )
+ {
+ try {
+ XRegistryKey xNewKey = xKey.createKey( "/" + impl_name + "/UNO/SERVICES" );
+ for ( int nPos = 0; nPos < supported_services.length; ++nPos ) {
+ xNewKey.createKey( supported_services[ nPos ] );
+ }
+ return true;
+ } catch (com.sun.star.registry.InvalidRegistryException exc) {
+ if (DEBUG) {
+ System.err.println(
+ "##### " + Factory.class.getName() + ".writeRegistryServiceInfo -- exc: " +
+ exc.toString() );
+ }
+ }
+ return false;
+ }
+
+}
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/ridljar/com/sun/star/comp/loader/JavaLoader.java b/ridljar/com/sun/star/comp/loader/JavaLoader.java
new file mode 100644
index 0000000000..42dee0da5c
--- /dev/null
+++ b/ridljar/com/sun/star/comp/loader/JavaLoader.java
@@ -0,0 +1,439 @@
+/* -*- Mode: Java; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
+/*
+ * 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 com.sun.star.comp.loader;
+
+import java.lang.reflect.Method;
+import java.lang.reflect.InvocationTargetException;
+import java.net.URLDecoder;
+
+import com.sun.star.loader.CannotActivateFactoryException;
+import com.sun.star.loader.XImplementationLoader;
+
+import com.sun.star.registry.CannotRegisterImplementationException;
+import com.sun.star.registry.XRegistryKey;
+
+import com.sun.star.lang.XSingleComponentFactory;
+import com.sun.star.lang.XSingleServiceFactory;
+import com.sun.star.lang.XMultiServiceFactory;
+import com.sun.star.lang.XServiceInfo;
+import com.sun.star.lang.XInitialization;
+
+import com.sun.star.uno.XComponentContext;
+import com.sun.star.beans.XPropertySet;
+import com.sun.star.util.XMacroExpander;
+
+import com.sun.star.uno.Type;
+import com.sun.star.uno.UnoRuntime;
+
+import com.sun.star.lib.util.StringHelper;
+
+import com.sun.star.uno.AnyConverter;
+
+
+/**
+ * The <code>JavaLoader</code> class provides the functionality of the
+ * <code>com.sun.star.loader.Java</code> service.
+ *
+ * <p>Therefore the <code>JavaLoader</code> activates external UNO components
+ * which are implemented in Java.</p>
+ *
+ * <p>The loader is used by the <code>ServiceManager</code>.</p>
+ *
+ * @see com.sun.star.loader.XImplementationLoader
+ * @see com.sun.star.loader.Java
+ * @see com.sun.star.comp.servicemanager.ServiceManager
+ * @since UDK1.0
+ */
+public class JavaLoader implements XImplementationLoader,
+ XServiceInfo,
+ XInitialization
+{
+ private static final boolean DEBUG = false;
+
+ private static final void DEBUG(String dbg) {
+ if (DEBUG) System.err.println( dbg );
+ }
+
+ private static String[] supportedServices = {
+ "com.sun.star.loader.Java"
+ };
+
+ protected XMultiServiceFactory multiServiceFactory = null;
+
+ private XMacroExpander m_xMacroExpander = null;
+ private static final String EXPAND_PROTOCOL_PREFIX = "vnd.sun.star.expand:";
+
+ /**
+ * Expands macrofied url using the macro expander singleton.
+ */
+ private String expand_url( String url ) throws RuntimeException
+ {
+ if (url == null || !url.startsWith( EXPAND_PROTOCOL_PREFIX )) {
+ return url;
+ }
+ try {
+ if (m_xMacroExpander == null) {
+ XPropertySet xProps =
+ UnoRuntime.queryInterface(
+ XPropertySet.class, multiServiceFactory );
+ if (xProps == null) {
+ throw new com.sun.star.uno.RuntimeException(
+ "service manager does not support XPropertySet!",
+ this );
+ }
+ XComponentContext xContext = (XComponentContext)
+ AnyConverter.toObject(
+ new Type( XComponentContext.class ),
+ xProps.getPropertyValue( "DefaultContext" ) );
+ m_xMacroExpander = (XMacroExpander)AnyConverter.toObject(
+ new Type( XMacroExpander.class ),
+ xContext.getValueByName(
+ "/singletons/com.sun.star.util.theMacroExpander" )
+ );
+ }
+ // decode uric class chars
+ String macro = URLDecoder.decode(
+ StringHelper.replace(
+ url.substring( EXPAND_PROTOCOL_PREFIX.length() ),
+ '+', "%2B" ), "UTF-8" );
+ // expand macro string
+ String ret = m_xMacroExpander.expandMacros( macro );
+ if (DEBUG) {
+ System.err.println(
+ "JavaLoader.expand_url(): " + url + " => " +
+ macro + " => " + ret );
+ }
+ return ret;
+ } catch (com.sun.star.uno.Exception exc) {
+ throw new com.sun.star.uno.RuntimeException(exc,
+ exc.getMessage(), this );
+ } catch (java.lang.Exception exc) {
+ throw new com.sun.star.uno.RuntimeException(exc,
+ exc.getMessage(), this );
+ }
+ }
+
+ /**
+ * Default constructor.
+ *
+ * <p>Creates a new instance of the <code>JavaLoader</code> class.</p>
+ */
+ public JavaLoader() {}
+
+ /**
+ * Creates a new <code>JavaLoader</code> object.
+ *
+ * <p>The specified <code>com.sun.star.lang.XMultiServiceFactory</code> is
+ * the <code>ServiceManager</code> service which can be delivered to all
+ * components the <code>JavaLoader</code> is loading.</p>
+ *
+ * <p>To set the <code>MultiServiceFactory</code> you can use the
+ * <code>com.sun.star.lang.XInitialization</code> interface, either.</p>
+ *
+ * @param factory the <code>ServiceManager</code>.
+ * @see com.sun.star.comp.servicemanager.ServiceManager
+ * @see com.sun.star.lang.XInitialization
+ */
+ public JavaLoader(XMultiServiceFactory factory) {
+ multiServiceFactory = factory;
+ }
+
+ /**
+ * Unlike the original intention, the method could be called every time a
+ * new <code>com.sun.star.lang.XMultiServiceFactory</code> should be set at
+ * the loader.
+ *
+ * @param args - the first parameter (args[0]) specifies the <code>ServiceManager</code>.
+ * @see com.sun.star.lang.XInitialization
+ * @see com.sun.star.comp.servicemanager.ServiceManager
+ */
+ public void initialize( java.lang.Object[] args )
+ throws com.sun.star.uno.Exception,
+ com.sun.star.uno.RuntimeException
+ {
+ if (args.length == 0)
+ throw new com.sun.star.lang.IllegalArgumentException("No arguments specified");
+
+ try {
+ multiServiceFactory = (XMultiServiceFactory) AnyConverter.toObject(
+ new Type(XMultiServiceFactory.class), args[0]);
+ } catch (ClassCastException castEx) {
+ throw new com.sun.star.lang.IllegalArgumentException(castEx,
+ "The argument must be an instance of XMultiServiceFactory");
+ }
+ }
+
+ /**
+ * Supplies the implementation name of the component.
+ *
+ * @return the implementation name - here the class name.
+ * @see com.sun.star.lang.XServiceInfo
+ */
+ public String getImplementationName()
+ throws com.sun.star.uno.RuntimeException
+ {
+ return getClass().getName();
+ }
+
+ /**
+ * Verifies if a given service is supported by the component.
+ *
+ * @param serviceName the name of the service that should be checked.
+ * @return true,if service is supported - otherwise false.
+ *
+ * @see com.sun.star.lang.XServiceInfo
+ */
+ public boolean supportsService(String serviceName)
+ throws com.sun.star.uno.RuntimeException
+ {
+ for (String supportedService : supportedServices) {
+ if (supportedService.equals(serviceName)) {
+ return true;
+ }
+ }
+ return false;
+ }
+
+ /**
+ * Supplies a list of all service names supported by the component.
+ *
+ * @return a String array with all supported services.
+ * @see com.sun.star.lang.XServiceInfo
+ */
+ public String[] getSupportedServiceNames()
+ throws com.sun.star.uno.RuntimeException
+ {
+ return supportedServices;
+ }
+
+ /**
+ * Provides a components factory.
+ *
+ * <p>The <code>JavaLoader</code> tries to load the class first. If a
+ * location URL is given the RegistrationClassFinder is used to load the
+ * class. Otherwise the class is loaded through the Class.forName method.</p>
+ *
+ * <p>To get the factory the inspects the class for the optional static member
+ * functions __getServiceFactory resp. getServiceFactory (DEPRECATED).</p>
+ *
+ * @param implementationName the implementation (class) name of the component.
+ * @param implementationLoaderUrl the URL of the implementation loader. Not used.
+ * @param locationUrl points to an archive (JAR file) which contains a component.
+ * @param xKey registry key.
+ * @return the factory for the component (@see com.sun.star.lang.XSingleServiceFactory)
+ *
+ * @see com.sun.star.loader.XImplementationLoader
+ * @see com.sun.star.comp.loader.RegistrationClassFinder
+ */
+ public java.lang.Object activate( String implementationName,
+ String implementationLoaderUrl,
+ String locationUrl,
+ XRegistryKey xKey )
+ throws CannotActivateFactoryException,
+ com.sun.star.uno.RuntimeException
+ {
+ locationUrl = expand_url( locationUrl );
+
+ Object returnObject = null;
+ Class<?> clazz ;
+
+ DEBUG("try to get factory for " + implementationName);
+
+ // First we must get the class of the implementation
+ // 1. If a location URL is given it is assumed that this points to a JAR file.
+ // The components class name is stored in the manifest file.
+ // 2. If only the implementation name is given, the class is loaded with the
+ // Class.forName() method. This is a hack to load bootstrap components.
+ // Normally a string must no be null.
+ try {
+ if ( locationUrl != null ) {
+ clazz = RegistrationClassFinder.find( locationUrl );
+ if (clazz == null) {
+ throw new CannotActivateFactoryException(
+ "Cannot activate jar " + locationUrl);
+ }
+ } else {
+ clazz = Class.forName( implementationName );
+ if (clazz == null) {
+ throw new CannotActivateFactoryException(
+ "Cannot find class " + implementationName);
+ }
+ }
+ } catch (java.net.MalformedURLException e) {
+ throw new CannotActivateFactoryException(e, "Can not activate factory because " + e);
+ } catch (java.io.IOException e) {
+ throw new CannotActivateFactoryException(e, "Can not activate factory because " + e);
+ } catch (java.lang.ClassNotFoundException e) {
+ throw new CannotActivateFactoryException(e, "Can not activate factory because " + e);
+ }
+
+ Class<?>[] paramTypes = {String.class, XMultiServiceFactory.class, XRegistryKey.class};
+ Object[] params = { implementationName, multiServiceFactory, xKey };
+
+ // try to get factory from implementation class
+ // latest style: use the public static method __getComponentFactory
+ // - new style: use the public static method __getServiceFactory
+ // - old style: use the public static method getServiceFactory ( DEPRECATED )
+
+ Method compfac_method = null;
+ try {
+ compfac_method = clazz.getMethod(
+ "__getComponentFactory", new Class [] { String.class } );
+ } catch ( NoSuchMethodException noSuchMethodEx) {
+ } catch ( SecurityException secEx) {
+ }
+
+ Method method = null;
+ if (null == compfac_method) {
+ try {
+ method = clazz.getMethod("__getServiceFactory", paramTypes);
+ } catch ( NoSuchMethodException noSuchMethodEx) {
+ } catch ( SecurityException secEx) {
+ }
+ }
+
+ try {
+ if (null != compfac_method) {
+ Object ret = compfac_method.invoke( clazz, new Object [] { implementationName } );
+ if (!(ret instanceof XSingleComponentFactory))
+ throw new CannotActivateFactoryException(
+ "No factory object for " + implementationName );
+
+ return ret;
+ }
+ else {
+ if ( method == null )
+ method = clazz.getMethod("getServiceFactory", paramTypes);
+
+ Object oRet = method.invoke(clazz, params);
+
+ if ( (oRet != null) && (oRet instanceof XSingleServiceFactory) )
+ returnObject = oRet;
+ }
+ } catch ( NoSuchMethodException e) {
+ throw new CannotActivateFactoryException(e, "Can not activate the factory for "
+ + implementationName);
+ } catch ( SecurityException e) {
+ throw new CannotActivateFactoryException(e, "Can not activate the factory for "
+ + implementationName);
+ } catch ( IllegalAccessException e ) {
+ throw new CannotActivateFactoryException(e, "Can not activate the factory for "
+ + implementationName);
+ }
+ catch ( IllegalArgumentException e ) {
+ throw new CannotActivateFactoryException(e, "Can not activate the factory for "
+ + implementationName);
+ } catch ( InvocationTargetException e ) {
+ throw new CannotActivateFactoryException(e, "Can not activate the factory for "
+ + implementationName);
+ }
+
+ return returnObject;
+ }
+
+ /**
+ * Registers the component in a registry under a given root key.
+ *
+ * <p>If the component supports the optional
+ * methods __writeRegistryServiceInfo, writeRegistryServiceInfo (DEPRECATED),
+ * the call is delegated to that method. Otherwise a default registration
+ * will be accomplished.</p>
+ *
+ * @param regKey the root key under that the component should be registered.
+ * @param implementationLoaderUrl specifies the loader, the component is loaded by.
+ * @param locationUrl points to an archive (JAR file) which contains a component.
+ * @return true if registration is successfully - otherwise false.
+ */
+ public boolean writeRegistryInfo( XRegistryKey regKey,
+ String implementationLoaderUrl,
+ String locationUrl )
+ throws CannotRegisterImplementationException,
+ com.sun.star.uno.RuntimeException
+ {
+ locationUrl = expand_url( locationUrl );
+
+ boolean success = false;
+
+ try {
+
+ Class<?> clazz = RegistrationClassFinder.find(locationUrl);
+ if (null == clazz)
+ throw new CannotRegisterImplementationException(
+ "Cannot determine registration class!" );
+
+ Class<?>[] paramTypes = { XRegistryKey.class };
+ Object[] params = { regKey };
+
+ Method method = clazz.getMethod("__writeRegistryServiceInfo", paramTypes);
+ Object oRet = method.invoke(clazz, params);
+
+ if ( (oRet != null) && (oRet instanceof Boolean) )
+ success = ((Boolean) oRet).booleanValue();
+ } catch (Exception e) {
+ throw new CannotRegisterImplementationException(e, e.toString());
+ }
+
+ return success;
+ }
+
+ /**
+ * Supplies the factory for the <code>JavaLoader</code>.
+ *
+ * @param implName the name of the desired component.
+ * @param multiFactory the <code>ServiceManager</code> is delivered to the factory.
+ * @param regKey not used - can be null.
+ * @return the factory for the <code>JavaLoader</code>.
+ */
+ public static XSingleServiceFactory getServiceFactory( String implName,
+ XMultiServiceFactory multiFactory,
+ XRegistryKey regKey)
+ {
+ if ( implName.equals(JavaLoader.class.getName()) )
+ return new JavaLoaderFactory( multiFactory );
+
+ return null;
+ }
+
+ /**
+ * Registers the <code>JavaLoader</code> at the registry.
+ *
+ * @param regKey root key under which the <code>JavaLoader</code> should be registered.
+ * @return true if registration succeeded - otherwise false.
+ */
+ public static boolean writeRegistryServiceInfo(XRegistryKey regKey) {
+ boolean result = false;
+
+ try {
+ XRegistryKey newKey = regKey.createKey("/" + JavaLoader.class.getName() + "/UNO/SERVICE");
+
+ for (String supportedService : supportedServices) {
+ newKey.createKey(supportedService);
+ }
+
+ result = true;
+ } catch (Exception ex) {
+ if (DEBUG) System.err.println(">>>JavaLoader.writeRegistryServiceInfo " + ex);
+ }
+
+ return result;
+ }
+}
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/ridljar/com/sun/star/comp/loader/JavaLoaderFactory.java b/ridljar/com/sun/star/comp/loader/JavaLoaderFactory.java
new file mode 100644
index 0000000000..edf4f7a3a4
--- /dev/null
+++ b/ridljar/com/sun/star/comp/loader/JavaLoaderFactory.java
@@ -0,0 +1,90 @@
+/* -*- Mode: Java; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
+/*
+ * 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 com.sun.star.comp.loader;
+
+import com.sun.star.lang.XSingleServiceFactory;
+import com.sun.star.lang.XMultiServiceFactory;
+import com.sun.star.lang.XServiceInfo;
+
+
+public class JavaLoaderFactory implements XSingleServiceFactory, XServiceInfo {
+
+ private static String[] supportedServices = {
+ "com.sun.star.loader.Java",
+ "com.sun.star.loader.Java2"
+ };
+
+ protected XMultiServiceFactory multiServiceFactory = null;
+
+ public JavaLoaderFactory(XMultiServiceFactory factory) {
+ multiServiceFactory = factory;
+ }
+
+ public java.lang.Object createInstance()
+ throws com.sun.star.uno.Exception,
+ com.sun.star.uno.RuntimeException
+ {
+ return new JavaLoader(multiServiceFactory);
+ }
+
+ public java.lang.Object createInstanceWithArguments( java.lang.Object[] args )
+ throws com.sun.star.uno.Exception,
+ com.sun.star.uno.RuntimeException
+ {
+ JavaLoader loader = new JavaLoader();
+ loader.initialize(args);
+
+ return loader;
+ }
+
+ /**
+ * Implements the XServiceInfo interface.
+ */
+ public String getImplementationName()
+ throws com.sun.star.uno.RuntimeException
+ {
+ return JavaLoader.class.getName();
+ }
+
+ /**
+ * Implements the XServiceInfo interface.
+ */
+ public boolean supportsService(String serviceName)
+ throws com.sun.star.uno.RuntimeException
+ {
+ for (String supportedService : supportedServices) {
+ if (supportedService.equals(serviceName)) {
+ return true;
+ }
+ }
+ return false;
+ }
+
+ /**
+ * Implements the XServiceInfo interface.
+ */
+ public String[] getSupportedServiceNames()
+ throws com.sun.star.uno.RuntimeException
+ {
+ return supportedServices;
+ }
+}
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/ridljar/com/sun/star/comp/loader/RegistrationClassFinder.java b/ridljar/com/sun/star/comp/loader/RegistrationClassFinder.java
new file mode 100644
index 0000000000..e7679da167
--- /dev/null
+++ b/ridljar/com/sun/star/comp/loader/RegistrationClassFinder.java
@@ -0,0 +1,69 @@
+/* -*- Mode: Java; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
+/*
+ * 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 com.sun.star.comp.loader;
+
+import com.sun.star.lib.unoloader.UnoClassLoader;
+import com.sun.star.lib.util.WeakMap;
+import java.io.IOException;
+import java.net.URL;
+import java.net.URLClassLoader;
+import java.util.jar.Attributes;
+
+final class RegistrationClassFinder {
+ public static Class<?> find(String locationUrl)
+ throws ClassNotFoundException, IOException
+ {
+ synchronized (map) {
+ Class<?> c = (Class<?>) WeakMap.getValue(map.get(locationUrl));
+ if (c != null) {
+ return c;
+ }
+ }
+ URL url = new URL(locationUrl);
+ Attributes attr = UnoClassLoader.getJarMainAttributes(url);
+ String name = attr == null
+ ? null : attr.getValue("RegistrationClassName");
+ if (name == null) {
+ return null;
+ }
+ ClassLoader cl1 = RegistrationClassFinder.class.getClassLoader();
+ ClassLoader cl2;
+ if (cl1 instanceof UnoClassLoader) {
+ cl2 = ((UnoClassLoader) cl1).getClassLoader(url, attr);
+ } else {
+ cl2 = URLClassLoader.newInstance(new URL[] { url }, cl1);
+ }
+ Class<?> c = cl2.loadClass(name);
+ synchronized (map) {
+ Class<?> c2 = (Class<?>) WeakMap.getValue(map.get(locationUrl));
+ if (c2 != null) {
+ return c2;
+ }
+ map.put(locationUrl, c);
+ }
+ return c;
+ }
+
+ private RegistrationClassFinder() {} // do not instantiate
+
+ private static final WeakMap map = new WeakMap();
+}
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/ridljar/com/sun/star/comp/servicemanager/ServiceManager.java b/ridljar/com/sun/star/comp/servicemanager/ServiceManager.java
new file mode 100644
index 0000000000..574983f1e2
--- /dev/null
+++ b/ridljar/com/sun/star/comp/servicemanager/ServiceManager.java
@@ -0,0 +1,662 @@
+/* -*- Mode: Java; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
+/*
+ * 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 com.sun.star.comp.servicemanager;
+
+import java.util.ArrayList;
+import java.util.Collections;
+
+import com.sun.star.container.XContentEnumerationAccess;
+import com.sun.star.container.XEnumeration;
+import com.sun.star.container.XSet;
+import com.sun.star.lang.XComponent;
+import com.sun.star.lang.XEventListener;
+import com.sun.star.lang.XMultiComponentFactory;
+import com.sun.star.lang.XMultiServiceFactory;
+import com.sun.star.lang.XServiceInfo;
+import com.sun.star.lang.XSingleComponentFactory;
+import com.sun.star.lang.XSingleServiceFactory;
+import com.sun.star.uno.UnoRuntime;
+import com.sun.star.uno.XComponentContext;
+
+/**
+ * The <code>ServiceManager</code> class is an implementation of the
+ * <code>ServiceManager</code>the central class needed for implementing or using
+ * UNO components in Java.
+ *
+ * <p>The Methods <code>queryInterface</code> and <code>isSame</code> delegate
+ * calls to the implementing objects and are used instead of casts and identity
+ * comparisons.</p>
+ *
+ * @see com.sun.star.lang.XMultiServiceFactory
+ * @see com.sun.star.container.XSet
+ * @see com.sun.star.container.XContentEnumerationAccess
+ * @see com.sun.star.lang.XComponent
+ * @see com.sun.star.lang.XServiceInfo
+ * @since UDK1.0
+ */
+public class ServiceManager implements XMultiServiceFactory,
+ XMultiComponentFactory,
+ XSet,
+ XContentEnumerationAccess,
+ XComponent,
+ XServiceInfo
+{
+ private static final boolean DEBUG = false;
+
+ private static final void DEBUG (String dbg) {
+ if (DEBUG) System.err.println( dbg );
+ }
+
+ private static com.sun.star.uno.Type UNO_TYPE = null;
+
+ static String[] supportedServiceNames = {
+ "com.sun.star.lang.MultiServiceFactory",
+ "com.sun.star.lang.ServiceManager"
+ };
+
+ ArrayList<XEventListener> eventListener;
+ java.util.HashMap<String, Object> factoriesByImplNames;
+ java.util.HashMap<String, ArrayList<Object>> factoriesByServiceNames; // keys:
+
+ private com.sun.star.uno.XComponentContext m_xDefaultContext;
+
+ /**
+ * Creates a new instance of the <code>ServiceManager</code>.
+ */
+ public ServiceManager() {
+ eventListener = new ArrayList<XEventListener>();
+ factoriesByImplNames = new java.util.HashMap<String, Object>();
+ factoriesByServiceNames = new java.util.HashMap<String, ArrayList<Object>>();
+ m_xDefaultContext = null;
+ }
+
+ public void setDefaultContext(XComponentContext context) {
+ m_xDefaultContext = context;
+ }
+
+ /**
+ * Creates a new instance of a specified service.
+ *
+ * <p>Therefore the associated factory of the service is looked up and used
+ * to instantiate a new component. </p>
+ *
+ * @param serviceSpecifier indicates the service or component name.
+ * @return newly created component.
+ *
+ * @see com.sun.star.lang.XMultiServiceFactory
+ */
+ public java.lang.Object createInstance( String serviceSpecifier )
+ throws com.sun.star.uno.Exception,
+ com.sun.star.uno.RuntimeException
+ {
+ return createInstanceWithContext( serviceSpecifier, m_xDefaultContext );
+ }
+
+ /**
+ * Creates a new instance of a specified service with the given parameters.
+ *
+ * <p>Therefore the associated factory of the service is looked up and used
+ * to instantiate a new component.</p>
+ *
+ * @return newly created component.
+ * @param serviceSpecifier indicates the service or component name.
+ * @see com.sun.star.lang.XMultiServiceFactory
+ */
+ public java.lang.Object createInstanceWithArguments(
+ String serviceSpecifier, Object[] args )
+ throws com.sun.star.uno.Exception, com.sun.star.uno.RuntimeException
+ {
+ if (DEBUG) {
+ System.err.println("createInstanceWithArguments:" );
+
+ for (Object arg : args) {
+ System.err.print(" " + arg);
+ }
+
+ System.err.println();
+ }
+
+ return createInstanceWithArgumentsAndContext( serviceSpecifier, args, m_xDefaultContext );
+ }
+
+ /**
+ * Look up the factory for a given service or implementation name.
+ *
+ * <p>First the requested service name is search in the list of available
+ * services. If it can not be found the name is looked up in the implementation
+ * list.</p>
+ *
+ * @param serviceName indicates the service or implementation name.
+ * @return the factory of the service / implementation.
+ *
+ * @see com.sun.star.lang.XMultiServiceFactory
+ */
+ private Object queryServiceFactory(String serviceName)
+ throws com.sun.star.uno.Exception,
+ com.sun.star.uno.RuntimeException
+ {
+ DEBUG("queryServiceFactory for name " + serviceName );
+ Object factory = null;
+
+ if ( factoriesByServiceNames.containsKey( serviceName ) ) {
+ ArrayList<Object> availableFact = factoriesByServiceNames.get( serviceName );
+
+ DEBUG("");
+ DEBUG("available factories for " + serviceName +" "+ availableFact);
+ DEBUG("");
+
+ if ( !availableFact.isEmpty() )
+ factory = availableFact.get(availableFact.size()-1);
+
+ } else // not found in list of services - now try the implementations
+ factory = factoriesByImplNames.get( serviceName ); // return null if none is available
+
+ if (DEBUG) {
+ if (factory == null) System.err.println("service not registered");
+ else
+ System.err.println("service found:" + factory + " " + UnoRuntime.queryInterface(XSingleServiceFactory.class, factory));
+ }
+
+ if (factory == null)
+ throw new com.sun.star.uno.Exception("Query for service factory for " + serviceName + " failed.");
+
+ return factory;
+ }
+
+ /**
+ * Supplies a list of all available services names.
+ *
+ * @return list of Strings of all service names.
+ * @see com.sun.star.container.XContentEnumerationAccess
+ */
+ public String[] getAvailableServiceNames()
+ throws com.sun.star.uno.RuntimeException
+ {
+ try{
+ return factoriesByServiceNames.keySet().toArray(
+ new String[ factoriesByServiceNames.size() ] );
+ } catch(Exception ex) {
+ throw new com.sun.star.uno.RuntimeException(ex);
+ }
+ }
+
+ // XMultiComponentFactory implementation
+
+ /** Create a service instance with given context.
+ *
+ * @param rServiceSpecifier service name.
+ * @param xContext context.
+ * @return service instance.
+ */
+ public java.lang.Object createInstanceWithContext(
+ String rServiceSpecifier,
+ com.sun.star.uno.XComponentContext xContext )
+ throws com.sun.star.uno.Exception
+ {
+ Object fac = queryServiceFactory( rServiceSpecifier );
+ if (fac != null)
+ {
+ XSingleComponentFactory xCompFac = UnoRuntime.queryInterface(
+ XSingleComponentFactory.class, fac );
+ if (xCompFac != null)
+ {
+ return xCompFac.createInstanceWithContext( xContext );
+ }
+ else
+ {
+ XSingleServiceFactory xServiceFac = UnoRuntime.queryInterface(
+ XSingleServiceFactory.class, fac );
+ if (xServiceFac != null)
+ {
+ if (DEBUG)
+ System.err.println( "### ignoring context raising service \"" + rServiceSpecifier + "\"!" );
+ return xServiceFac.createInstance();
+ }
+ else
+ {
+ throw new com.sun.star.uno.Exception(
+ "retrieved service factory object for \"" + rServiceSpecifier +
+ "\" does not export XSingleComponentFactory nor XSingleServiceFactory!" );
+ }
+ }
+ }
+ return null;
+ }
+ /**
+ * Create a service instance with given context and arguments.
+ *
+ * @param rServiceSpecifier service name.
+ * @param rArguments arguments.
+ * @param xContext context.
+ * @return service instance.
+ */
+ public java.lang.Object createInstanceWithArgumentsAndContext(
+ String rServiceSpecifier,
+ java.lang.Object[] rArguments,
+ com.sun.star.uno.XComponentContext xContext )
+ throws com.sun.star.uno.Exception
+ {
+ Object fac = queryServiceFactory( rServiceSpecifier );
+ if (fac != null)
+ {
+ XSingleComponentFactory xCompFac = UnoRuntime.queryInterface(
+ XSingleComponentFactory.class, fac );
+ if (xCompFac != null)
+ {
+ return xCompFac.createInstanceWithArgumentsAndContext( rArguments, xContext );
+ }
+ else
+ {
+ XSingleServiceFactory xServiceFac = UnoRuntime.queryInterface(
+ XSingleServiceFactory.class, fac );
+ if (xServiceFac != null)
+ {
+ if (DEBUG)
+ System.err.println( "### ignoring context raising service \"" + rServiceSpecifier + "\"!" );
+ return xServiceFac.createInstanceWithArguments( rArguments );
+ }
+ else
+ {
+ throw new com.sun.star.uno.Exception(
+ "retrieved service factory object for \"" + rServiceSpecifier +
+ "\" does not export XSingleComponentFactory nor XSingleServiceFactory!" );
+ }
+ }
+ }
+ return null;
+ }
+
+ /**
+ * Removes all listeners from the <code>ServiceManager</code> and clears the
+ * list of the services.
+ *
+ * @see com.sun.star.lang.XComponent
+ */
+ public void dispose()
+ throws com.sun.star.uno.RuntimeException
+ {
+ if (eventListener != null) {
+ for (XEventListener listener : eventListener) {
+ listener.disposing(new com.sun.star.lang.EventObject(this));
+ }
+ eventListener.clear();
+ }
+
+ factoriesByServiceNames.clear();
+ factoriesByImplNames.clear();
+ }
+
+ /**
+ * Adds a new <code>EventListener</code>.
+ *
+ * <p>The listener is notified when a service is added (removed) to (from)
+ * the <code>ServiceManager</code>.</p>
+ *
+ * <p>If the listener is already registered a
+ * <code>com.sun.star.uno.RuntimeException</code> will be thrown.</p>
+ *
+ * @param xListener the new listener which should been added.
+ * @see com.sun.star.lang.XComponent
+ */
+ public void addEventListener( XEventListener xListener )
+ throws com.sun.star.uno.RuntimeException
+ {
+ if (xListener == null)
+ throw new com.sun.star.uno.RuntimeException("Listener must not be null");
+
+ if ( eventListener.contains(xListener) )
+ throw new com.sun.star.uno.RuntimeException("Listener already registered.");
+
+ eventListener.add(xListener);
+ }
+
+ /**
+ * Removes a <code>EventListener</code> from the <code>ServiceManager</code>.
+ *
+ * <p>If the listener is not registered a <code>com.sun.star.uno.RuntimeException</code>
+ * will be thrown.</p>
+ *
+ * @param xListener the new listener which should been removed.
+ * @see com.sun.star.lang.XComponent
+ */
+ public void removeEventListener( XEventListener xListener )
+ throws com.sun.star.uno.RuntimeException
+ {
+ if (xListener == null)
+ throw new com.sun.star.uno.RuntimeException("Listener must not be null");
+
+ if ( !eventListener.contains(xListener) )
+ throw new com.sun.star.uno.RuntimeException("Listener is not registered.");
+
+ eventListener.remove(xListener);
+ }
+
+ /**
+ * Checks if a component is registered at the <code>ServiceManager</code>.
+ *
+ * <p>The given object argument must provide a <code>XServiceInfo</code>
+ * interface.</p>
+ *
+ * @param object object which provides a <code>XServiceInfo</code> interface.
+ * @return true if the component is registered otherwise false.
+ *
+ * @see com.sun.star.container.XSet
+ * @see com.sun.star.lang.XServiceInfo
+ */
+ public boolean has( Object object )
+ throws com.sun.star.uno.RuntimeException
+ {
+ if (object == null)
+ throw new com.sun.star.uno.RuntimeException("The parameter must not been null");
+
+ XServiceInfo xServiceInfo = UnoRuntime.queryInterface(XServiceInfo.class, object);
+
+ return xServiceInfo != null && UnoRuntime.areSame(factoriesByImplNames.get(xServiceInfo.getImplementationName()), object);
+ }
+
+ /**
+ * Adds a <code>SingleServiceFactory</code> to the <code>ServiceManager</code>.
+ *
+ * @param object factory which should be added.
+ * @see com.sun.star.container.XSet
+ * @see com.sun.star.lang.XSingleServiceFactory
+ */
+ public void insert( Object object )
+ throws com.sun.star.lang.IllegalArgumentException,
+ com.sun.star.container.ElementExistException,
+ com.sun.star.uno.RuntimeException
+ {
+ if (object == null) throw new com.sun.star.lang.IllegalArgumentException();
+
+ XServiceInfo xServiceInfo =
+ UnoRuntime.queryInterface(XServiceInfo.class, object);
+
+ if (xServiceInfo == null)
+ throw new com.sun.star.lang.IllegalArgumentException(
+ "The given object does not implement the XServiceInfo interface."
+ );
+
+ if ( factoriesByImplNames.containsKey( xServiceInfo.getImplementationName() ) ) {
+ throw new com.sun.star.container.ElementExistException(
+ xServiceInfo.getImplementationName() + " already registered"
+ );
+ }
+
+ DEBUG("add factory " + object.toString() + " for " + xServiceInfo.getImplementationName());
+ factoriesByImplNames.put( xServiceInfo.getImplementationName(), object );
+
+
+ String[] serviceNames = xServiceInfo.getSupportedServiceNames();
+ ArrayList<Object> vec ;
+
+ for (String serviceName : serviceNames) {
+ if (!factoriesByServiceNames.containsKey(serviceName)) {
+ DEBUG("> no registered services found under " + serviceName + ": adding...");
+ factoriesByServiceNames.put(serviceName, new ArrayList<Object>());
+ }
+ vec = factoriesByServiceNames.get(serviceName);
+ if (vec.contains( object )) {
+ System.err.println("The implementation " + xServiceInfo.getImplementationName() +
+ " already registered for the service " + serviceName + " - ignoring!");
+ } else {
+ vec.add(object);
+ }
+ }
+ }
+
+ /**
+ * Removes a <code>SingleServiceFactory</code> from the <code>ServiceManager</code>.
+ *
+ * @param object factory which should be removed.
+ * @see com.sun.star.container.XSet
+ * @see com.sun.star.lang.XSingleServiceFactory
+ */
+ public void remove( Object object )
+ throws com.sun.star.lang.IllegalArgumentException,
+ com.sun.star.container.NoSuchElementException,
+ com.sun.star.uno.RuntimeException
+ {
+ if (object == null)
+ throw new com.sun.star.lang.IllegalArgumentException(
+ "The given object must not be null."
+ );
+
+ XServiceInfo xServiceInfo =
+ UnoRuntime.queryInterface(XServiceInfo.class, object);
+
+ if (xServiceInfo == null)
+ throw new com.sun.star.lang.IllegalArgumentException(
+ "The given object does not implement the XServiceInfo interface."
+ );
+
+ XSingleServiceFactory xSingleServiceFactory =
+ UnoRuntime.queryInterface(XSingleServiceFactory.class, object);
+
+ if (xSingleServiceFactory == null)
+ throw new com.sun.star.lang.IllegalArgumentException(
+ "The given object does not implement the XSingleServiceFactory interface."
+ );
+
+ if ( factoriesByImplNames.remove( xServiceInfo.getImplementationName() ) == null )
+ throw new com.sun.star.container.NoSuchElementException(
+ xServiceInfo.getImplementationName() +
+ " is not registered as an implementation."
+ );
+
+ String[] serviceNames = xServiceInfo.getSupportedServiceNames();
+
+ for (String serviceName : serviceNames) {
+ if (factoriesByServiceNames.containsKey(serviceName)) {
+ ArrayList<Object> vec = factoriesByServiceNames.get(serviceName);
+ if (!vec.remove(object)) {
+ System.err.println("The implementation " + xServiceInfo.getImplementationName() +
+ " is not registered for the service " + serviceName + " - ignoring!");
+ }
+ // remove the vector if no implementations available for the service
+ if (vec.isEmpty()) {
+ factoriesByServiceNames.remove(serviceName);
+ }
+ }
+ }
+ }
+
+ /**
+ * Provides an enumeration of all registered services.
+ *
+ * @return an enumeration of all available services.
+ * @see com.sun.star.container.XEnumerationAccess
+ */
+ public XEnumeration createEnumeration()
+ throws com.sun.star.uno.RuntimeException
+ {
+ return new ServiceEnumerationImpl( factoriesByImplNames.values().iterator() );
+ }
+
+ /**
+ * Provides the UNO type of the <code>ServiceManager</code>
+ *
+ * @return the UNO type of the <code>ServiceManager</code>.
+ * @see com.sun.star.container.XElementAccess
+ * @see com.sun.star.uno.TypeClass
+ */
+ public com.sun.star.uno.Type getElementType()
+ throws com.sun.star.uno.RuntimeException
+ {
+ if ( UNO_TYPE == null )
+ UNO_TYPE = new com.sun.star.uno.Type(ServiceManager.class);
+
+ return UNO_TYPE;
+ }
+
+ /**
+ * Checks if the any components are registered.
+ *
+ * @return true - if the list of the registered components is not empty - otherwise false.
+ * @see com.sun.star.container.XElementAccess
+ */
+ public boolean hasElements() {
+ return ! factoriesByImplNames.isEmpty();
+ }
+
+ /**
+ * Provides an enumeration of all factories for a specified service.
+ *
+ * @param serviceName name of the requested service.
+ * @return an enumeration for service name.
+ * @see com.sun.star.container.XContentEnumerationAccess
+ */
+ public XEnumeration createContentEnumeration( String serviceName )
+ throws com.sun.star.uno.RuntimeException
+ {
+ XEnumeration enumer ;
+
+ ArrayList<Object> serviceList = factoriesByServiceNames.get(serviceName);
+
+ if (serviceList != null)
+ enumer = new ServiceEnumerationImpl( serviceList.iterator() );
+ else
+ enumer = new ServiceEnumerationImpl();
+
+ return enumer;
+ }
+
+ /**
+ * Returns the implementation name of the <code>ServiceManager</code> component.
+ *
+ * @return the class name of the <code>ServiceManager</code>.
+ * @see com.sun.star.lang.XServiceInfo
+ */
+ public String getImplementationName()
+ throws com.sun.star.uno.RuntimeException
+ {
+ return getClass().getName();
+ }
+
+ /**
+ * Checks if the <code>ServiceManager</code> supports a service.
+ *
+ * @param serviceName service name which should be checked.
+ * @return true if the service is supported - otherwise false.
+ *
+ * @see com.sun.star.lang.XServiceInfo
+ */
+ public boolean supportsService( String serviceName )
+ throws com.sun.star.uno.RuntimeException
+ {
+ for (String supportedServiceName : supportedServiceNames) {
+ if (supportedServiceName.equals(serviceName)) {
+ return true;
+ }
+ }
+
+ return getImplementationName().equals(serviceName);
+ }
+
+ /**
+ * Supplies list of all supported services.
+ *
+ * @return a list of all supported service names.
+ * @see com.sun.star.lang.XServiceInfo
+ */
+ public String[] getSupportedServiceNames()
+ throws com.sun.star.uno.RuntimeException
+ {
+ return supportedServiceNames;
+ }
+
+ /**
+ * The <code>ServiceEnumerationImpl</code> class provides an
+ * implementation of the @see com.sun.star.container.XEnumeration interface.
+ *
+ * <p>It is an inner wrapper for a java.util.Enumeration object.</p>
+ *
+ * @see com.sun.star.lang.XSingleServiceFactory
+ * @see com.sun.star.lang.XServiceInfo
+ * @since UDK1.0
+ */
+ static class ServiceEnumerationImpl implements XEnumeration {
+ java.util.Iterator<Object> enumeration = null;
+
+ /**
+ * Constructs a new empty instance.
+ */
+ public ServiceEnumerationImpl() {
+ }
+
+ /**
+ * Constructs a new instance with a given enumeration.
+ *
+ * @param enumer is the enumeration which should been wrapped.
+ * @see com.sun.star.container.XEnumeration
+ */
+ public ServiceEnumerationImpl(java.util.Enumeration<Object> enumer) {
+ enumeration = Collections.list(enumer).iterator();
+ }
+
+ /**
+ * Constructs a new instance with a given enumeration.
+ *
+ * @param enumer is the enumeration which should been wrapped.
+ * @see com.sun.star.container.XEnumeration
+ */
+ public ServiceEnumerationImpl(java.util.Iterator<Object> enumer) {
+ enumeration = enumer;
+ }
+
+ /**
+ * Checks if the enumeration contains more elements.
+ *
+ * @return true if more elements are available - otherwise false.
+ * @see com.sun.star.container.XEnumeration
+ */
+ public boolean hasMoreElements()
+ throws com.sun.star.uno.RuntimeException
+ {
+ return enumeration != null && enumeration.hasNext();
+
+ }
+
+ /**
+ * Returns the next element of the enumeration.
+ *
+ * <p>If no further elements available a com.sun.star.container.NoSuchElementException
+ * exception will be thrown.</p>
+ *
+ * @return the next element.
+ * @see com.sun.star.container.XEnumeration
+ */
+ public Object nextElement()
+ throws com.sun.star.container.NoSuchElementException,
+ com.sun.star.lang.WrappedTargetException,
+ com.sun.star.uno.RuntimeException
+ {
+ if (enumeration == null)
+ throw new com.sun.star.container.NoSuchElementException();
+
+ try {
+ return enumeration.next();
+ } catch (java.util.NoSuchElementException e) {
+ throw new com.sun.star.container.NoSuchElementException(e, e.toString());
+ }
+ }
+ }
+}
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/ridljar/com/sun/star/comp/urlresolver/UrlResolver.java b/ridljar/com/sun/star/comp/urlresolver/UrlResolver.java
new file mode 100644
index 0000000000..7585dabf6d
--- /dev/null
+++ b/ridljar/com/sun/star/comp/urlresolver/UrlResolver.java
@@ -0,0 +1,147 @@
+/* -*- Mode: Java; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
+/*
+ * 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 com.sun.star.comp.urlresolver;
+
+
+import com.sun.star.bridge.XBridge;
+import com.sun.star.bridge.XBridgeFactory;
+import com.sun.star.bridge.XUnoUrlResolver;
+
+import com.sun.star.comp.loader.FactoryHelper;
+
+import com.sun.star.connection.ConnectionSetupException;
+import com.sun.star.connection.NoConnectException;
+import com.sun.star.connection.XConnection;
+import com.sun.star.connection.XConnector;
+
+import com.sun.star.lang.IllegalArgumentException;
+import com.sun.star.lang.XMultiServiceFactory;
+import com.sun.star.lang.XSingleServiceFactory;
+
+import com.sun.star.registry.XRegistryKey;
+
+import com.sun.star.uno.UnoRuntime;
+
+
+/**
+ * This component gives a factory for an <code>UnoUrlResolver</code> service.
+ *
+ * @see com.sun.star.bridge.XBridgeFactory
+ * @see com.sun.star.connection.Connector
+ * @since UDK1.0
+ */
+public class UrlResolver {
+ public static class _UrlResolver implements XUnoUrlResolver {
+ private static final String __serviceName = "com.sun.star.bridge.UnoUrlResolver";
+
+ private final XMultiServiceFactory _xMultiServiceFactory;
+
+ public _UrlResolver(XMultiServiceFactory xMultiServiceFactory) {
+ _xMultiServiceFactory = xMultiServiceFactory;
+ }
+
+ public Object resolve(/*IN*/String dcp) throws NoConnectException, ConnectionSetupException, IllegalArgumentException, com.sun.star.uno.RuntimeException {
+ String conDcp ;
+ String protDcp ;
+ String rootOid ;
+
+ if(dcp.indexOf(';') == -1) {// use old style
+ conDcp = dcp;
+ protDcp = "iiop";
+ rootOid = "classic_uno";
+ }
+ else { // new style
+ int index = dcp.indexOf(':');
+ dcp = dcp.substring(index + 1).trim();
+
+ index = dcp.indexOf(';');
+ conDcp = dcp.substring(0, index).trim();
+ dcp = dcp.substring(index + 1).trim();
+
+ index = dcp.indexOf(';');
+ protDcp = dcp.substring(0, index).trim();
+ dcp = dcp.substring(index + 1).trim();
+
+ rootOid = dcp.trim().trim();
+ }
+
+ Object rootObject ;
+ XBridgeFactory xBridgeFactory ;
+ try {
+ xBridgeFactory = UnoRuntime.queryInterface(XBridgeFactory.class,
+ _xMultiServiceFactory.createInstance("com.sun.star.bridge.BridgeFactory"));
+ } catch (com.sun.star.uno.Exception e) {
+ throw new com.sun.star.uno.RuntimeException(e);
+ }
+ XBridge xBridge = xBridgeFactory.getBridge(conDcp + ";" + protDcp);
+
+ if(xBridge == null) {
+ Object connector ;
+ try {
+ connector = _xMultiServiceFactory.createInstance("com.sun.star.connection.Connector");
+ } catch (com.sun.star.uno.Exception e) {
+ throw new com.sun.star.uno.RuntimeException(e);
+ }
+
+ XConnector connector_xConnector = UnoRuntime.queryInterface(XConnector.class, connector);
+
+ // connect to the server
+ XConnection xConnection = connector_xConnector.connect(conDcp);
+ try {
+ xBridge = xBridgeFactory.createBridge(conDcp + ";" + protDcp, protDcp, xConnection, null);
+ } catch (com.sun.star.bridge.BridgeExistsException e) {
+ throw new com.sun.star.uno.RuntimeException(e);
+ }
+ }
+ rootObject = xBridge.getInstance(rootOid);
+ return rootObject;
+ }
+ }
+
+
+ /**
+ * Gives a factory for creating the service.
+ *
+ * <p>This method is called by the <code>JavaLoader</code>.</p>
+ *
+ * @param implName the name of the implementation for which a service is desired.
+ * @param multiFactory the service manager to be uses if needed.
+ * @param regKey the registryKey.
+ * @return returns a <code>XSingleServiceFactory</code> for creating the component.
+ *
+ * @see com.sun.star.comp.loader.JavaLoader
+ */
+ public static XSingleServiceFactory __getServiceFactory(String implName,
+ XMultiServiceFactory multiFactory,
+ XRegistryKey regKey)
+ {
+ XSingleServiceFactory xSingleServiceFactory = null;
+
+ if (implName.equals(UrlResolver.class.getName()) )
+ xSingleServiceFactory = FactoryHelper.getServiceFactory(_UrlResolver.class,
+ _UrlResolver.__serviceName,
+ multiFactory,
+ regKey);
+
+ return xSingleServiceFactory;
+ }
+}
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/ridljar/com/sun/star/lib/connections/pipe/PipeConnection.java b/ridljar/com/sun/star/lib/connections/pipe/PipeConnection.java
new file mode 100644
index 0000000000..b3a686f179
--- /dev/null
+++ b/ridljar/com/sun/star/lib/connections/pipe/PipeConnection.java
@@ -0,0 +1,213 @@
+/* -*- Mode: Java; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
+/*
+ * 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 com.sun.star.lib.connections.pipe;
+
+import java.io.IOException;
+import java.util.ArrayList;
+import java.util.StringTokenizer;
+
+import com.sun.star.connection.XConnection;
+import com.sun.star.connection.XConnectionBroadcaster;
+import com.sun.star.io.XStreamListener;
+import com.sun.star.lib.util.NativeLibraryLoader;
+
+/**
+ * The PipeConnection implements the <code>XConnection</code> interface
+ * and is uses by the <code>PipeConnector</code> and the <code>PipeAcceptor</code>.
+ * This class is not part of the provided <code>api</code>.
+ *
+ * The native implementation is in jurt/source/pipe/com_sun_star_lib_connections_pipe_PipeConnection.c
+ *
+ * @see com.sun.star.lib.connections.pipe.pipeAcceptor
+ * @see com.sun.star.lib.connections.pipe.pipeConnector
+ * @see com.sun.star.connection.XConnection
+ * @since UDK1.0
+ */
+public class PipeConnection implements XConnection, XConnectionBroadcaster {
+ /**
+ * When set to true, enables various debugging output.
+ */
+ public static final boolean DEBUG = false;
+
+ static {
+ // load shared library for JNI code
+ NativeLibraryLoader.loadLibrary(PipeConnection.class.getClassLoader(), "jpipe");
+ }
+
+ protected String _aDescription;
+ protected long _nPipeHandle;
+ protected ArrayList<XStreamListener> _aListeners;
+ protected boolean _bFirstRead;
+
+ /**
+ * Constructs a new <code>PipeConnection</code>.
+ *
+ * @param description the description of the connection.
+ */
+ public PipeConnection(String description)
+ throws IOException
+ {
+ if (DEBUG) System.err.println("##### " + getClass().getName() + " - instantiated " + description );
+
+ _aListeners = new ArrayList<XStreamListener>();
+ _bFirstRead = true;
+
+ // get pipe name from pipe descriptor
+ String aPipeName ;
+ StringTokenizer aTokenizer = new StringTokenizer( description, "," );
+ if ( aTokenizer.hasMoreTokens() ) {
+ String aConnType = aTokenizer.nextToken();
+ if ( !aConnType.equals( "pipe" ) )
+ throw new RuntimeException( "invalid pipe descriptor: does not start with 'pipe,'" );
+
+ String aPipeNameParam = aTokenizer.nextToken();
+ if ( !aPipeNameParam.substring( 0, 5 ).equals( "name=" ) )
+ throw new RuntimeException( "invalid pipe descriptor: no 'name=' parameter found" );
+ aPipeName = aPipeNameParam.substring( 5 );
+ }
+ else
+ throw new RuntimeException( "invalid or empty pipe descriptor" );
+
+ // create the pipe
+ try {
+ createJNI( aPipeName );
+ } catch ( java.lang.Exception ex1 ) {
+ IOException ex2 = new IOException();
+ ex2.initCause(ex1);
+ throw ex2;
+ }
+ }
+
+ public void addStreamListener(XStreamListener aListener ) throws com.sun.star.uno.RuntimeException {
+ _aListeners.add(aListener);
+ }
+
+ public void removeStreamListener(XStreamListener aListener ) throws com.sun.star.uno.RuntimeException {
+ _aListeners.remove(aListener);
+ }
+
+ private void notifyListeners_open() {
+ for (XStreamListener xStreamListener : _aListeners) {
+ xStreamListener.started();
+ }
+ }
+
+ private void notifyListeners_close() {
+ for (XStreamListener xStreamListener : _aListeners) {
+ xStreamListener.closed();
+ }
+ }
+
+ private void notifyListeners_error(com.sun.star.uno.Exception exception) {
+ for (XStreamListener xStreamListener : _aListeners) {
+ xStreamListener.error(exception);
+ }
+ }
+
+ // JNI implementation to create the pipe
+ private native int createJNI( String name )
+ throws com.sun.star.io.IOException, com.sun.star.uno.RuntimeException;
+
+ // JNI implementation to read from the pipe
+ private native int readJNI(/*OUT*/byte[][] bytes, int nBytesToRead)
+ throws com.sun.star.io.IOException, com.sun.star.uno.RuntimeException;
+
+ // JNI implementation to write to the pipe
+ private native void writeJNI(byte aData[])
+ throws com.sun.star.io.IOException, com.sun.star.uno.RuntimeException;
+
+ // JNI implementation to flush the pipe
+ private native void flushJNI()
+ throws com.sun.star.io.IOException, com.sun.star.uno.RuntimeException;
+
+ // JNI implementation to close the pipe
+ private native void closeJNI()
+ throws com.sun.star.io.IOException, com.sun.star.uno.RuntimeException;
+
+ /**
+ * Read the required number of bytes.
+ *
+ * @param bytes the outparameter, where the bytes have to be placed.
+ * @param nBytesToRead the number of bytes to read.
+ * @return the number of bytes read.
+ *
+ * @see com.sun.star.connection.XConnection#read
+ */
+ public int read(/*OUT*/byte[][] bytes, int nBytesToRead)
+ throws com.sun.star.io.IOException, com.sun.star.uno.RuntimeException
+ {
+ if(_bFirstRead) {
+ _bFirstRead = false;
+
+ notifyListeners_open();
+ }
+
+ return readJNI( bytes, nBytesToRead );
+ }
+
+ /**
+ * Write bytes.
+ *
+ * @param aData the bytes to write.
+ * @see com.sun.star.connection.XConnection#write
+ */
+ public void write(byte aData[])
+ throws com.sun.star.io.IOException, com.sun.star.uno.RuntimeException
+ {
+ writeJNI( aData );
+ }
+
+ /**
+ * Flushes the buffer.
+ *
+ * @see com.sun.star.connection.XConnection#flush
+ */
+ public void flush()
+ throws com.sun.star.io.IOException, com.sun.star.uno.RuntimeException
+ {
+ flushJNI();
+ }
+
+ /**
+ * Closes the connection.
+ *
+ * @see com.sun.star.connection.XConnection#close
+ */
+ public void close()
+ throws com.sun.star.io.IOException, com.sun.star.uno.RuntimeException
+ {
+ if (DEBUG) System.out.print( "PipeConnection::close() " );
+ closeJNI();
+ notifyListeners_close();
+ if (DEBUG) System.out.println( "done" );
+ }
+
+ /**
+ * Gives a description of the connection.
+ *
+ * @return the description.
+ * @see com.sun.star.connection.XConnection#getDescription
+ */
+ public String getDescription() throws com.sun.star.uno.RuntimeException {
+ return _aDescription;
+ }
+
+}
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/ridljar/com/sun/star/lib/connections/pipe/pipeAcceptor.java b/ridljar/com/sun/star/lib/connections/pipe/pipeAcceptor.java
new file mode 100644
index 0000000000..983eb32659
--- /dev/null
+++ b/ridljar/com/sun/star/lib/connections/pipe/pipeAcceptor.java
@@ -0,0 +1,123 @@
+/* -*- Mode: Java; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
+/*
+ * 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 com.sun.star.lib.connections.pipe;
+
+import com.sun.star.comp.loader.FactoryHelper;
+import com.sun.star.connection.AlreadyAcceptingException;
+import com.sun.star.connection.ConnectionSetupException;
+import com.sun.star.connection.XAcceptor;
+import com.sun.star.connection.XConnection;
+import com.sun.star.lang.XMultiServiceFactory;
+import com.sun.star.lang.XSingleServiceFactory;
+import com.sun.star.registry.XRegistryKey;
+
+/**
+ * A component that implements the <code>XAcceptor</code> interface.
+ *
+ * <p>The <code>pipeAcceptor</code> is a specialized component that uses TCP
+ * pipes for communication. The <code>pipeAcceptor</code> is generally used
+ * by the <code>com.sun.star.connection.Acceptor</code> service.</p>
+ *
+ * @see com.sun.star.connection.XAcceptor
+ * @see com.sun.star.connection.XConnection
+ * @see com.sun.star.connection.XConnector
+ * @see com.sun.star.comp.loader.JavaLoader
+ *
+ * @since UDK 1.0
+ */
+public final class pipeAcceptor implements XAcceptor {
+ /**
+ * The name of the service.
+ *
+ * <p>The <code>JavaLoader</code> accesses this through reflection.</p>
+ *
+ * @see com.sun.star.comp.loader.JavaLoader
+ */
+ public static final String __serviceName
+ = "com.sun.star.connection.pipeAcceptor";
+
+ /**
+ * Returns a factory for creating the service.
+ *
+ * <p>This method is called by the <code>JavaLoader</code>.</p>
+ *
+ * @param implName the name of the implementation for which a service is
+ * requested.
+ * @param multiFactory the service manager to be used (if needed).
+ * @param regKey the registry key.
+ * @return an <code>XSingleServiceFactory</code> for creating the component.
+ *
+ * @see com.sun.star.comp.loader.JavaLoader
+ */
+ public static XSingleServiceFactory __getServiceFactory(
+ String implName, XMultiServiceFactory multiFactory, XRegistryKey regKey)
+ {
+ return implName.equals(pipeAcceptor.class.getName())
+ ? FactoryHelper.getServiceFactory(
+ pipeAcceptor.class, __serviceName, multiFactory, regKey)
+ : null;
+ }
+
+ /**
+ * Accepts a connection request via the described pipe.
+ *
+ * <p>This call blocks until a connection has been established.</p>
+ *
+ * <p>The connection description has the following format:
+ * <code><var>type</var></code><!--
+ * -->*(<code><var>key</var>=<var>value</var></code>),
+ * where <code><var>type</var></code> should be <code>pipe</code>
+ * (ignoring case). Supported keys (ignoring case) currently are</p>
+ * <dl>
+ * <dt><code>host</code>
+ * <dd>The name or address of the accepting interface (defaults to
+ * <code>0</code>, meaning any interface).
+ * <dt><code>port</code>
+ * <dd>The TCP port number to accept on (defaults to <code>6001</code>).
+ * <dt><code>backlog</code>
+ * <dd>The maximum length of the acceptor's queue (defaults to
+ * <code>50</code>).
+ * <dt><code>tcpnodelay</code>
+ * <dd>A flag (<code>0</code>/<code>1</code>) enabling or disabling Nagle's
+ * algorithm on the resulting connection.
+ * </dl>
+ *
+ * @param connectionDescription the description of the connection.
+ * @return an <code>XConnection</code> to the client.
+ *
+ * @see com.sun.star.connection.XConnection
+ * @see com.sun.star.connection.XConnector
+ */
+ public XConnection accept(String connectionDescription) throws
+ AlreadyAcceptingException, ConnectionSetupException,
+ com.sun.star.lang.IllegalArgumentException
+ {
+ throw new java.lang.NoSuchMethodError( "pipeAcceptor not fully implemented yet" );
+ }
+
+ /**
+ *
+ * @see com.sun.star.connection.XAcceptor#stopAccepting
+ */
+ public void stopAccepting() {
+ }
+}
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/ridljar/com/sun/star/lib/connections/pipe/pipeConnector.java b/ridljar/com/sun/star/lib/connections/pipe/pipeConnector.java
new file mode 100644
index 0000000000..192d350071
--- /dev/null
+++ b/ridljar/com/sun/star/lib/connections/pipe/pipeConnector.java
@@ -0,0 +1,120 @@
+/* -*- Mode: Java; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
+/*
+ * 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 com.sun.star.lib.connections.pipe;
+
+import com.sun.star.comp.loader.FactoryHelper;
+import com.sun.star.connection.ConnectionSetupException;
+import com.sun.star.connection.NoConnectException;
+import com.sun.star.connection.XConnection;
+import com.sun.star.connection.XConnector;
+import com.sun.star.lang.XMultiServiceFactory;
+import com.sun.star.lang.XSingleServiceFactory;
+import com.sun.star.registry.XRegistryKey;
+
+/**
+ * A component that implements the <code>XConnector</code> interface.
+ *
+ * <p>The <code>pipeConnector</code> is a specialized component that uses TCP
+ * pipes for communication. The <code>pipeConnector</code> is generally
+ * used by the <code>com.sun.star.connection.Connector</code> service.</p>
+ *
+ * @see com.sun.star.connection.XAcceptor
+ * @see com.sun.star.connection.XConnection
+ * @see com.sun.star.connection.XConnector
+ * @see com.sun.star.comp.loader.JavaLoader
+ *
+ * @since UDK 1.0
+ */
+public final class pipeConnector implements XConnector {
+ /**
+ * The name of the service.
+ *
+ * <p>The <code>JavaLoader</code> accesses this through reflection.</p>
+ *
+ * @see com.sun.star.comp.loader.JavaLoader
+ */
+ public static final String __serviceName = "com.sun.star.connection.pipeConnector";
+
+ /**
+ * Returns a factory for creating the service.
+ *
+ * <p>This method is called by the <code>JavaLoader</code>.</p>
+ *
+ * @param implName the name of the implementation for which a service is
+ * requested.
+ * @param multiFactory the service manager to be used (if needed).
+ * @param regKey the registry key.
+ * @return an <code>XSingleServiceFactory</code> for creating the component.
+ *
+ * @see com.sun.star.comp.loader.JavaLoader
+ */
+ public static XSingleServiceFactory __getServiceFactory(
+ String implName, XMultiServiceFactory multiFactory, XRegistryKey regKey)
+ {
+ return implName.equals(pipeConnector.class.getName())
+ ? FactoryHelper.getServiceFactory(pipeConnector.class,
+ __serviceName, multiFactory,
+ regKey)
+ : null;
+ }
+
+ /**
+ * Connects via the described pipe to a waiting server.
+ *
+ * <p>The connection description has the following format:
+ * <code><var>type</var></code><!--
+ * -->*(<code><var>key</var>=<var>value</var></code>),
+ * where <code><var>type</var></code> should be <code>pipe</code>
+ * (ignoring case). Supported keys (ignoring case) currently are</p>
+ * <dl>
+ * <dt><code>host</code>
+ * <dd>The name or address of the server. Must be present.
+ * <dt><code>port</code>
+ * <dd>The TCP port number of the server (defaults to <code>6001</code>).
+ * <dt><code>tcpnodelay</code>
+ * <dd>A flag (<code>0</code>/<code>1</code>) enabling or disabling Nagle's
+ * algorithm on the resulting connection.
+ * </dl>
+ *
+ * @param connectionDescription the description of the connection.
+ * @return an <code>XConnection</code> to the server.
+ *
+ * @see com.sun.star.connection.XAcceptor
+ * @see com.sun.star.connection.XConnection
+ */
+ public synchronized XConnection connect(String connectionDescription)
+ throws NoConnectException, ConnectionSetupException
+ {
+ if (bConnected)
+ throw new ConnectionSetupException("already connected");
+
+ try {
+ XConnection xConn = new PipeConnection( connectionDescription );
+ bConnected = true;
+ return xConn;
+ } catch ( java.io.IOException e ) {
+ throw new NoConnectException(e);
+ }
+ }
+
+ private boolean bConnected = false;
+}
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/ridljar/com/sun/star/lib/connections/socket/ConnectionDescriptor.java b/ridljar/com/sun/star/lib/connections/socket/ConnectionDescriptor.java
new file mode 100644
index 0000000000..5a88d41baf
--- /dev/null
+++ b/ridljar/com/sun/star/lib/connections/socket/ConnectionDescriptor.java
@@ -0,0 +1,98 @@
+/* -*- Mode: Java; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
+/*
+ * 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 com.sun.star.lib.connections.socket;
+
+/**
+ * Helper class for <code>socketAcceptor</code> and <code>socketConnector</code>.
+ *
+ * <p>FIXME: Once those classes have been moved from <code>jurt</code> to
+ * <code>javaunohelper</code>, they should use
+ * <code>com.sun.star.lib.uno.helper.UnoUrl</code> either instead of this class
+ * or underneath this class.</p>
+ */
+final class ConnectionDescriptor {
+ public ConnectionDescriptor(String description)
+ throws com.sun.star.lang.IllegalArgumentException {
+ for (int i = description.indexOf(','); i >= 0;) {
+ int j = description.indexOf(',', i + 1);
+ int k = j < 0 ? description.length() : j;
+ int l = description.indexOf('=', i + 1);
+ if (l < 0 || l >= k) {
+ throw new com.sun.star.lang.IllegalArgumentException(
+ "parameter lacks '='");
+ }
+ String key = description.substring(i + 1, l);
+ String value = description.substring(l + 1, k);
+ if (key.equalsIgnoreCase("host")) {
+ host = value;
+ } else if (key.equalsIgnoreCase("port")) {
+ try {
+ port = Integer.parseInt(value);
+ } catch (NumberFormatException e) {
+ throw new com.sun.star.lang.IllegalArgumentException(e);
+ }
+ if (port < 0 || port > 65535) {
+ throw new com.sun.star.lang.IllegalArgumentException(
+ "port parameter must have value between 0 and 65535,"
+ + " inclusive");
+ }
+ } else if (key.equalsIgnoreCase("backlog")) {
+ try {
+ backlog = Integer.parseInt(value);
+ } catch (NumberFormatException e) {
+ throw new com.sun.star.lang.IllegalArgumentException(e);
+ }
+ } else if (key.equalsIgnoreCase("tcpnodelay")) {
+ if (value.equals("0")) {
+ tcpNoDelay = Boolean.FALSE;
+ } else if (value.equals("1")) {
+ tcpNoDelay = Boolean.TRUE;
+ } else {
+ throw new com.sun.star.lang.IllegalArgumentException(
+ "tcpnodelay parameter must have 0/1 value");
+ }
+ }
+ i = j;
+ }
+ }
+
+ public String getHost() {
+ return host;
+ }
+
+ public int getPort() {
+ return port;
+ }
+
+ public int getBacklog() {
+ return backlog;
+ }
+
+ public Boolean getTcpNoDelay() {
+ return tcpNoDelay;
+ }
+
+ private String host = null;
+ private int port = 6001;
+ private int backlog = 50;
+ private Boolean tcpNoDelay = null;
+}
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/ridljar/com/sun/star/lib/connections/socket/SocketConnection.java b/ridljar/com/sun/star/lib/connections/socket/SocketConnection.java
new file mode 100644
index 0000000000..a906496f2c
--- /dev/null
+++ b/ridljar/com/sun/star/lib/connections/socket/SocketConnection.java
@@ -0,0 +1,235 @@
+/* -*- Mode: Java; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
+/*
+ * 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 com.sun.star.lib.connections.socket;
+
+
+import java.io.BufferedInputStream;
+import java.io.BufferedOutputStream;
+import java.io.IOException;
+import java.io.InputStream;
+import java.io.OutputStream;
+
+import java.net.Socket;
+
+import java.util.ArrayList;
+import java.util.Arrays;
+
+import com.sun.star.connection.XConnection;
+import com.sun.star.connection.XConnectionBroadcaster;
+import com.sun.star.io.XStreamListener;
+
+/**
+ * The SocketConnection implements the <code>XConnection</code> interface
+ * and is uses by the <code>SocketConnector</code> and the <code>SocketAcceptor</code>.
+ *
+ * <p>This class is not part of the provided <code>api</code>.</p>
+ *
+ * @see com.sun.star.lib.connections.socket.socketAcceptor
+ * @see com.sun.star.lib.connections.socket.socketConnector
+ * @see com.sun.star.connection.XConnection
+ * @since UDK1.0
+ */
+public class SocketConnection implements XConnection, XConnectionBroadcaster {
+ /**
+ * When set to true, enables various debugging output.
+ */
+ public static final boolean DEBUG = false;
+
+ protected String _description;
+ protected Socket _socket;
+ protected InputStream _inputStream;
+ protected OutputStream _outputStream;
+ protected ArrayList<XStreamListener> _listeners;
+ protected boolean _firstRead;
+
+ /**
+ * Constructs a new <code>SocketConnection</code>.
+ *
+ * @param description the description of the connection.
+ * @param socket the socket of the connection.
+ */
+ public SocketConnection(String description, Socket socket) throws IOException {
+ if (DEBUG) System.err.println("##### " + getClass().getName() + " - instantiated " + description + " " + socket);
+
+ _description = description
+ + ",localHost=" + socket.getLocalAddress().getHostName()
+ + ",localPort=" + socket.getLocalPort()
+ + ",peerHost=" + socket.getInetAddress().getHostName()
+ + ",peerPort=" + socket.getPort();
+
+ _socket = socket;
+ _inputStream = new BufferedInputStream(socket.getInputStream());
+ _outputStream = new BufferedOutputStream(socket.getOutputStream());
+
+ _listeners = new ArrayList<XStreamListener>();
+ _firstRead = true;
+ }
+
+ public void addStreamListener(XStreamListener aListener )
+ throws com.sun.star.uno.RuntimeException {
+ _listeners.add(aListener);
+ }
+
+ public void removeStreamListener(XStreamListener aListener )
+ throws com.sun.star.uno.RuntimeException {
+ _listeners.remove(aListener);
+ }
+
+ private void notifyListeners_open() {
+ for (XStreamListener xStreamListener : _listeners) {
+ xStreamListener.started();
+ }
+ }
+
+ private void notifyListeners_close() {
+ for (XStreamListener xStreamListener : _listeners) {
+ xStreamListener.closed();
+ }
+ }
+
+ private void notifyListeners_error(com.sun.star.uno.Exception exception) {
+ for (XStreamListener xStreamListener : _listeners) {
+ xStreamListener.error(exception);
+ }
+ }
+
+ /**
+ * Read the required number of bytes.
+ *
+ * @param bytes the outparameter, where the bytes have to be placed.
+ * @param nBytesToRead the number of bytes to read.
+ * @return the number of bytes read.
+ *
+ * @see com.sun.star.connection.XConnection#read
+ */
+ public int read(/*OUT*/byte[][] bytes, int nBytesToRead)
+ throws com.sun.star.io.IOException, com.sun.star.uno.RuntimeException {
+ if(_firstRead) {
+ _firstRead = false;
+
+ notifyListeners_open();
+ }
+
+ String errMessage = null;
+
+ int read_bytes = 0;
+ bytes[0] = new byte[nBytesToRead];
+
+ try {
+ int count ;
+
+ do {
+ count = _inputStream.read(bytes[0], read_bytes, nBytesToRead - read_bytes);
+ if(count == -1)
+ errMessage = "EOF reached - " + getDescription();
+
+ read_bytes += count;
+ }
+ while(read_bytes >= 0 && read_bytes < nBytesToRead && count >= 0);
+ } catch(IOException ioException) {
+ if(DEBUG) {
+ System.err.println("##### " + getClass().getName() + ".read - exception occurred:" + ioException);
+ ioException.printStackTrace();
+ }
+
+ errMessage = ioException.toString();
+ }
+
+ if(errMessage != null) {
+ com.sun.star.io.IOException unoIOException = new com.sun.star.io.IOException(errMessage);
+ notifyListeners_error(unoIOException);
+
+ throw unoIOException;
+ }
+
+ if (DEBUG) System.err.println("##### " + getClass().getName() + " - read byte:" + read_bytes + " " + Arrays.toString(bytes[0]));
+
+ return read_bytes;
+ }
+
+ /**
+ * Write bytes.
+ *
+ * @param aData the bytes to write.
+ * @see com.sun.star.connection.XConnection#write
+ */
+ public void write(byte aData[]) throws com.sun.star.io.IOException,
+ com.sun.star.uno.RuntimeException {
+ try {
+ _outputStream.write(aData);
+ } catch(IOException ioException) {
+ com.sun.star.io.IOException unoIOException = new com.sun.star.io.IOException(ioException);
+ notifyListeners_error(unoIOException);
+
+ throw unoIOException;
+ }
+
+ if (DEBUG) System.err.println("##### " + getClass().getName() + " - written bytes:" + Arrays.toString(aData) + " " + aData.length);
+ }
+
+ /**
+ * Flushes the buffer.
+ *
+ * @see com.sun.star.connection.XConnection#flush
+ */
+ public void flush() throws com.sun.star.io.IOException,
+ com.sun.star.uno.RuntimeException {
+ try {
+ _outputStream.flush();
+ } catch(IOException ioException) {
+ com.sun.star.io.IOException unoIOException = new com.sun.star.io.IOException(ioException);
+ notifyListeners_error(unoIOException);
+
+ throw unoIOException;
+ }
+ }
+
+ /**
+ * Closes the connection.
+ *
+ * @see com.sun.star.connection.XConnection#close
+ */
+ public void close() throws com.sun.star.io.IOException,
+ com.sun.star.uno.RuntimeException {
+ try {
+ _socket.close();
+ } catch(IOException ioException) {
+ com.sun.star.io.IOException unoIOException = new com.sun.star.io.IOException(ioException);
+ notifyListeners_error(unoIOException);
+
+ throw unoIOException;
+ }
+ if (DEBUG) System.err.println("##### " + getClass().getName() + " - socket closed");
+
+ notifyListeners_close();
+ }
+
+ /**
+ * Gives a description of the connection.
+ *
+ * @return the description.
+ * @see com.sun.star.connection.XConnection#getDescription
+ */
+ public String getDescription() throws com.sun.star.uno.RuntimeException {
+ return _description;
+ }
+
+}
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/ridljar/com/sun/star/lib/connections/socket/socketAcceptor.java b/ridljar/com/sun/star/lib/connections/socket/socketAcceptor.java
new file mode 100644
index 0000000000..4000a1d0a4
--- /dev/null
+++ b/ridljar/com/sun/star/lib/connections/socket/socketAcceptor.java
@@ -0,0 +1,202 @@
+/* -*- Mode: Java; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
+/*
+ * 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 com.sun.star.lib.connections.socket;
+
+import com.sun.star.comp.loader.FactoryHelper;
+import com.sun.star.connection.AlreadyAcceptingException;
+import com.sun.star.connection.ConnectionSetupException;
+import com.sun.star.connection.XAcceptor;
+import com.sun.star.connection.XConnection;
+import com.sun.star.lang.XMultiServiceFactory;
+import com.sun.star.lang.XSingleServiceFactory;
+import com.sun.star.registry.XRegistryKey;
+
+import java.io.IOException;
+import java.net.*;
+
+/**
+ * A component that implements the <code>XAcceptor</code> interface.
+ *
+ * <p>The <code>socketAcceptor</code> is a specialized component that uses TCP
+ * sockets for communication. The <code>socketAcceptor</code> is generally used
+ * by the <code>com.sun.star.connection.Acceptor</code> service.</p>
+ *
+ * @see com.sun.star.connection.XAcceptor
+ * @see com.sun.star.connection.XConnection2
+ * @see com.sun.star.connection.XConnector
+ * @see com.sun.star.comp.loader.JavaLoader
+ *
+ * @since UDK 1.0
+ */
+public final class socketAcceptor implements XAcceptor {
+ /**
+ * The name of the service.
+ *
+ * <p>The <code>JavaLoader</code> accesses this through reflection.</p>
+ *
+ * @see com.sun.star.comp.loader.JavaLoader
+ */
+ public static final String __serviceName
+ = "com.sun.star.connection.socketAcceptor";
+
+ /**
+ * Returns a factory for creating the service.
+ *
+ * <p>This method is called by the <code>JavaLoader</code>.</p>
+ *
+ * @param implName the name of the implementation for which a service is
+ * requested.
+ * @param multiFactory the service manager to be used (if needed).
+ * @param regKey the registry key.
+ * @return an <code>XSingleServiceFactory</code> for creating the component.
+ *
+ * @see com.sun.star.comp.loader.JavaLoader
+ */
+ public static XSingleServiceFactory __getServiceFactory(
+ String implName, XMultiServiceFactory multiFactory, XRegistryKey regKey)
+ {
+ return implName.equals(socketAcceptor.class.getName())
+ ? FactoryHelper.getServiceFactory(socketAcceptor.class,
+ __serviceName, multiFactory,
+ regKey)
+ : null;
+ }
+
+ /**
+ * Accepts a connection request via the described socket.
+ *
+ * <p>This call blocks until a connection has been established.</p>
+ *
+ * <p>The connection description has the following format:
+ * <code><var>type</var></code><!--
+ * -->*(<code><var>key</var>=<var>value</var></code>),
+ * where <code><var>type</var></code> should be <code>socket</code>
+ * (ignoring case). Supported keys (ignoring case) currently are</p>
+ * <dl>
+ * <dt><code>host</code>
+ * <dd>The name or address of the accepting interface (defaults to
+ * <code>0</code>, meaning any interface).
+ * <dt><code>port</code>
+ * <dd>The TCP port number to accept on (defaults to <code>6001</code>).
+ * <dt><code>backlog</code>
+ * <dd>The maximum length of the acceptor's queue (defaults to
+ * <code>50</code>).
+ * <dt><code>tcpnodelay</code>
+ * <dd>A flag (<code>0</code>/<code>1</code>) enabling or disabling Nagle's
+ * algorithm on the resulting connection.
+ * </dl>
+ *
+ * @param connectionDescription the description of the connection.
+ * @return an <code>XConnection</code> to the client.
+ *
+ * @see com.sun.star.connection.XConnection
+ * @see com.sun.star.connection.XConnector
+ */
+ public XConnection accept(String connectionDescription) throws
+ AlreadyAcceptingException, ConnectionSetupException,
+ com.sun.star.lang.IllegalArgumentException
+ {
+ ServerSocket serv;
+ synchronized (this) {
+ if (server == null) {
+ ConnectionDescriptor desc
+ = new ConnectionDescriptor(connectionDescription);
+ String host = desc.getHost();
+ if (host.equals("0")) {
+ host = null;
+ }
+ if (DEBUG) {
+ System.err.println("##### " + getClass().getName()
+ + ".accept: creating ServerSocket "
+ + desc.getPort() + ", "
+ + desc.getBacklog() + ", " + host);
+ }
+ try {
+ server = new ServerSocket(desc.getPort(), desc.getBacklog(),
+ host == null ? null
+ : InetAddress.getByName(host));
+ } catch (IOException e) {
+ throw new ConnectionSetupException(e);
+ }
+ acceptingDescription = connectionDescription;
+ tcpNoDelay = desc.getTcpNoDelay();
+ } else if (!connectionDescription.equals(acceptingDescription)) {
+ throw new AlreadyAcceptingException(acceptingDescription
+ + " vs. "
+ + connectionDescription);
+ }
+ serv = server;
+ }
+ Socket socket = null;
+ try {
+ socket = serv.accept();
+ if (DEBUG) {
+ System.err.println("##### " + getClass().getName()
+ + ".accept: accepted " + socket);
+ }
+ // we enable tcpNoDelay for loopback connections because
+ // it can make a significant speed difference on linux boxes.
+ if (tcpNoDelay != null) {
+ socket.setTcpNoDelay(tcpNoDelay.booleanValue());
+ }
+ else {
+ InetSocketAddress address = (InetSocketAddress)socket.getRemoteSocketAddress();
+ if (address != null && address.getAddress().isLoopbackAddress()) {
+ socket.setTcpNoDelay(true);
+ }
+ }
+ return new SocketConnection(acceptingDescription, socket);
+ }
+ catch(IOException e) {
+ if (socket != null) {
+ try {
+ socket.close();
+ } catch(IOException ioException) {
+ }
+ }
+ throw new ConnectionSetupException(e);
+ }
+ }
+
+ /**
+ *
+ * @see com.sun.star.connection.XAcceptor#stopAccepting
+ */
+ public void stopAccepting() {
+ ServerSocket serv;
+ synchronized (this) {
+ serv = server;
+ }
+ try {
+ serv.close();
+ }
+ catch (IOException e) {
+ throw new com.sun.star.uno.RuntimeException(e);
+ }
+ }
+
+ private static final boolean DEBUG = false;
+
+ private ServerSocket server = null;
+ private String acceptingDescription;
+ private Boolean tcpNoDelay;
+}
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/ridljar/com/sun/star/lib/connections/socket/socketConnector.java b/ridljar/com/sun/star/lib/connections/socket/socketConnector.java
new file mode 100644
index 0000000000..c9a15d1f5d
--- /dev/null
+++ b/ridljar/com/sun/star/lib/connections/socket/socketConnector.java
@@ -0,0 +1,174 @@
+/* -*- Mode: Java; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
+/*
+ * 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 com.sun.star.lib.connections.socket;
+
+import com.sun.star.comp.loader.FactoryHelper;
+import com.sun.star.connection.ConnectionSetupException;
+import com.sun.star.connection.NoConnectException;
+import com.sun.star.connection.XConnection;
+import com.sun.star.connection.XConnector;
+import com.sun.star.lang.XMultiServiceFactory;
+import com.sun.star.lang.XSingleServiceFactory;
+import com.sun.star.registry.XRegistryKey;
+
+import java.io.IOException;
+import java.net.InetAddress;
+import java.net.Socket;
+import java.net.UnknownHostException;
+
+/**
+ * A component that implements the <code>XConnector</code> interface.
+ *
+ * <p>The <code>socketConnector</code> is a specialized component that uses TCP
+ * sockets for communication. The <code>socketConnector</code> is generally
+ * used by the <code>com.sun.star.connection.Connector</code> service.</p>
+ *
+ * @see com.sun.star.connection.XAcceptor
+ * @see com.sun.star.connection.XConnection
+ * @see com.sun.star.connection.XConnector
+ * @see com.sun.star.comp.loader.JavaLoader
+ *
+ * @since UDK 1.0
+ */
+public final class socketConnector implements XConnector {
+ /**
+ * The name of the service.
+ *
+ * <p>The <code>JavaLoader</code> accesses this through reflection.</p>
+ *
+ * @see com.sun.star.comp.loader.JavaLoader
+ */
+ public static final String __serviceName
+ = "com.sun.star.connection.socketConnector";
+
+ /**
+ * Returns a factory for creating the service.
+ *
+ * <p>This method is called by the <code>JavaLoader</code>.</p>
+ *
+ * @param implName the name of the implementation for which a service is
+ * requested.
+ * @param multiFactory the service manager to be used (if needed).
+ * @param regKey the registry key.
+ * @return an <code>XSingleServiceFactory</code> for creating the component.
+ *
+ * @see com.sun.star.comp.loader.JavaLoader
+ */
+ public static XSingleServiceFactory __getServiceFactory(
+ String implName, XMultiServiceFactory multiFactory, XRegistryKey regKey)
+ {
+ return implName.equals(socketConnector.class.getName())
+ ? FactoryHelper.getServiceFactory(socketConnector.class,
+ __serviceName, multiFactory,
+ regKey)
+ : null;
+ }
+
+ /**
+ * Connects via the described socket to a waiting server.
+ *
+ * <p>The connection description has the following format:
+ * <code><var>type</var></code><!--
+ * -->*(<code><var>key</var>=<var>value</var></code>),
+ * where <code><var>type</var></code> should be <code>socket</code>
+ * (ignoring case). Supported keys (ignoring case) currently are</p>
+ * <dl>
+ * <dt><code>host</code>
+ * <dd>The name or address of the server. Must be present.
+ * <dt><code>port</code>
+ * <dd>The TCP port number of the server (defaults to <code>6001</code>).
+ * <dt><code>tcpnodelay</code>
+ * <dd>A flag (<code>0</code>/<code>1</code>) enabling or disabling Nagle's
+ * algorithm on the resulting connection.
+ * </dl>
+ *
+ * @param connectionDescription the description of the connection.
+ * @return an <code>XConnection</code> to the server.
+ *
+ * @see com.sun.star.connection.XAcceptor
+ * @see com.sun.star.connection.XConnection
+ */
+ public synchronized XConnection connect(String connectionDescription)
+ throws NoConnectException, ConnectionSetupException
+ {
+ if (connected)
+ throw new ConnectionSetupException("already connected");
+
+ ConnectionDescriptor desc;
+ try {
+ desc = new ConnectionDescriptor(connectionDescription);
+ } catch (com.sun.star.lang.IllegalArgumentException e) {
+ throw new ConnectionSetupException(e);
+ }
+
+ if (desc.getHost() == null)
+ throw new ConnectionSetupException("host parameter missing");
+ // Try all (IPv4 and IPv6) addresses, in case this client is on a
+ // dual-stack host and the server process is an IPv4-only process, also
+ // on a dual-stack host (see Stevens, Fenner, Rudoff: "Unix Network
+ // Programming, Volume 1: The Sockets Networking API, 3rd Edition",
+ // p. 359):
+ InetAddress[] adr;
+ try {
+ adr = InetAddress.getAllByName(desc.getHost());
+ } catch (UnknownHostException e) {
+ throw new ConnectionSetupException(e);
+ }
+ Socket socket = null;
+ boolean isLoopbackAddress = false;
+ for (int i = 0; i < adr.length; ++i) {
+ try {
+ isLoopbackAddress = adr[i].isLoopbackAddress();
+ socket = new Socket(adr[i], desc.getPort());
+ break;
+ } catch (IOException e) {
+ if (i == adr.length - 1)
+ throw new NoConnectException(e);
+ }
+ }
+
+ if (socket == null)
+ throw new ConnectionSetupException("no socket");
+
+ XConnection con;
+ try {
+ // we enable tcpNoDelay for loopback connections because
+ // it can make a significant speed difference on linux boxes.
+ if (desc.getTcpNoDelay() != null)
+ socket.setTcpNoDelay(desc.getTcpNoDelay().booleanValue());
+ else if (isLoopbackAddress)
+ socket.setTcpNoDelay(true);
+
+ con = new SocketConnection(connectionDescription, socket);
+ } catch (IOException e) {
+ try {
+ socket.close();
+ } catch(IOException ioException) {
+ }
+ throw new NoConnectException(e);
+ }
+ connected = true;
+ return con;
+ }
+
+ private boolean connected = false;
+}
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/ridljar/com/sun/star/lib/connections/websocket/ConnectionDescriptor.java b/ridljar/com/sun/star/lib/connections/websocket/ConnectionDescriptor.java
new file mode 100644
index 0000000000..439a525517
--- /dev/null
+++ b/ridljar/com/sun/star/lib/connections/websocket/ConnectionDescriptor.java
@@ -0,0 +1,60 @@
+/* -*- Mode: Java; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
+/*
+ * 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 com.sun.star.lib.connections.websocket;
+
+import java.util.Arrays;
+import java.util.Iterator;
+
+/**
+ * Helper class for <code>websocketConnector</code>.
+ */
+final class ConnectionDescriptor {
+ public ConnectionDescriptor(String description)
+ throws com.sun.star.lang.IllegalArgumentException {
+ Iterator<String> descriptionParts = Arrays.stream(description.split(",")).iterator();
+ descriptionParts
+ .next(); // skip over the first part as it's the protocol not a real parameter
+ while (descriptionParts.hasNext())
+ {
+ String parameter = descriptionParts.next();
+ String[] pair = parameter.split("=", 2);
+
+ if (pair.length != 2)
+ {
+ throw new com.sun.star.lang.IllegalArgumentException(
+ String.format("parameter %s lacks '='", parameter));
+ }
+
+ String key = pair[0];
+ String value = pair[1];
+ if (key.equalsIgnoreCase("url")) {
+ url = value;
+ }
+ }
+ }
+
+ public String getURL() {
+ return url;
+ }
+
+ private String url = null;
+}
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/ridljar/com/sun/star/lib/connections/websocket/WebsocketConnection.java b/ridljar/com/sun/star/lib/connections/websocket/WebsocketConnection.java
new file mode 100644
index 0000000000..87a8604c7b
--- /dev/null
+++ b/ridljar/com/sun/star/lib/connections/websocket/WebsocketConnection.java
@@ -0,0 +1,326 @@
+/* -*- Mode: Java; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
+/*
+ * 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 com.sun.star.lib.connections.websocket;
+
+
+import java.io.BufferedInputStream;
+import java.io.ByteArrayOutputStream;
+import java.io.IOException;
+import java.io.InputStream;
+import java.io.OutputStream;
+import java.io.PipedInputStream;
+import java.io.PipedOutputStream;
+import java.net.ProtocolException;
+import java.net.Socket;
+import java.net.URI;
+import java.net.URISyntaxException;
+import java.nio.charset.StandardCharsets;
+import java.nio.ByteBuffer;
+import java.util.ArrayList;
+import java.util.Arrays;
+
+import javax.swing.text.html.HTMLDocument.Iterator;
+
+import com.sun.star.connection.XConnection;
+import com.sun.star.connection.XConnectionBroadcaster;
+import com.sun.star.io.XStreamListener;
+import org.java_websocket.client.WebSocketClient;
+import org.java_websocket.handshake.ServerHandshake;
+
+/**
+ * The WebsocketConnection implements the <code>XConnection</code> interface
+ * and is uses by the <code>WebsocketConnector</code>.
+ *
+ * <p>This class is not part of the provided <code>api</code>.</p>
+ *
+ * @see com.sun.star.lib.connections.socket.socketAcceptor
+ * @see com.sun.star.lib.connections.socket.socketConnector
+ * @see com.sun.star.connection.XConnection
+ */
+public class WebsocketConnection extends WebSocketClient implements XConnection, XConnectionBroadcaster {
+ /**
+ * When set to true, enables various debugging output.
+ */
+ public static final boolean DEBUG = false;
+ static final byte[] outgoingPrefix = { 'u', 'r', 'p', ' ' };
+
+ protected String _description;
+ protected InputStream _inputStream;
+ protected OutputStream _inputStreamWriter;
+ protected ByteArrayOutputStream _outputStream;
+
+ protected ArrayList<XStreamListener> _listeners;
+
+ /**
+ * Constructs a new <code>WebsocketConnection</code>.
+ *
+ * @param description the description of the connection.
+ * @param desc the websocket ConnectionDescriptor containing information such as the websocket URL
+ */
+ public WebsocketConnection(String description, ConnectionDescriptor desc) throws IOException, URISyntaxException, InterruptedException {
+ super(new URI(desc.getURL()));
+
+ if (DEBUG) System.err.println("##### " + getClass().getName() + " - instantiated " + description + " " + desc);
+
+ _description = description;
+
+ PipedOutputStream inputStreamWriter = new PipedOutputStream();
+ PipedInputStream inputPipe = new PipedInputStream(inputStreamWriter);
+
+ _inputStream = new BufferedInputStream(inputPipe);
+ _inputStreamWriter = inputStreamWriter;
+ _outputStream = new ByteArrayOutputStream();
+
+ _listeners = new ArrayList<XStreamListener>();
+
+ connectBlocking();
+ }
+
+ public void addStreamListener(XStreamListener aListener )
+ throws com.sun.star.uno.RuntimeException {
+ _listeners.add(aListener);
+ }
+
+ public void removeStreamListener(XStreamListener aListener )
+ throws com.sun.star.uno.RuntimeException {
+ _listeners.remove(aListener);
+ }
+
+ private void notifyListeners_open() {
+ for (XStreamListener xStreamListener : _listeners) {
+ xStreamListener.started();
+ }
+ }
+
+ private void notifyListeners_close() {
+ for (XStreamListener xStreamListener : _listeners) {
+ xStreamListener.closed();
+ }
+ }
+
+ private void notifyListeners_error(com.sun.star.uno.Exception exception) {
+ for (XStreamListener xStreamListener : _listeners) {
+ xStreamListener.error(exception);
+ }
+ }
+
+ /**
+ * Read the required number of bytes.
+ *
+ * @param bytes the outparameter, where the bytes have to be placed.
+ * @param nBytesToRead the number of bytes to read.
+ * @return the number of bytes read.
+ *
+ * @see com.sun.star.connection.XConnection#read
+ */
+ public int read(/*OUT*/byte[][] bytes, int nBytesToRead)
+ throws com.sun.star.io.IOException, com.sun.star.uno.RuntimeException {
+
+ String errMessage = null;
+
+ int read_bytes = 0;
+ bytes[0] = new byte[nBytesToRead];
+
+ try {
+ _inputStreamWriter.flush();
+
+ int count ;
+
+ do {
+ count = _inputStream.read(bytes[0], read_bytes, nBytesToRead - read_bytes);
+ if(count == -1)
+ errMessage = "EOF reached - " + getDescription();
+
+ read_bytes += count;
+ }
+ while(read_bytes >= 0 && read_bytes < nBytesToRead && count >= 0);
+ } catch(IOException ioException) {
+ if(DEBUG) {
+ System.err.println("##### " + getClass().getName() + ".read - exception occurred:" + ioException);
+ ioException.printStackTrace();
+ }
+
+ errMessage = ioException.toString();
+ }
+
+ if(errMessage != null) {
+ com.sun.star.io.IOException unoIOException = new com.sun.star.io.IOException(errMessage);
+ notifyListeners_error(unoIOException);
+
+ throw unoIOException;
+ }
+
+ if (DEBUG) System.err.println(String.format("##### %s - read %s bytes of %s requested", getClass().getName(), Integer.toString(read_bytes), Integer.toString(nBytesToRead)));
+
+ return read_bytes;
+ }
+
+ /**
+ * Write bytes.
+ *
+ * @param aData the bytes to write.
+ * @see com.sun.star.connection.XConnection#write
+ */
+ public void write(byte aData[]) throws com.sun.star.io.IOException,
+ com.sun.star.uno.RuntimeException {
+ try {
+ _outputStream.write(aData);
+ } catch(IOException ioException) {
+ com.sun.star.io.IOException unoIOException = new com.sun.star.io.IOException(ioException);
+ notifyListeners_error(unoIOException);
+
+ throw unoIOException;
+ }
+
+ if (DEBUG) System.err.println(String.format("##### %s - wrote %s bytes", getClass().getName(), Integer.toString(aData.length)));
+ }
+
+ /**
+ * Sends the data over the websocket to whatever is on the other side.
+ *
+ * **NOTE**: unlike with genuine streams, without flushing the data is
+ * never sent
+ *
+ * @see com.sun.star.connection.XConnection#flush
+ */
+ public void flush() throws com.sun.star.io.IOException,
+ com.sun.star.uno.RuntimeException {
+
+ byte[] accumulatedBytes = _outputStream.toByteArray();
+ _outputStream.reset();
+
+ byte[] outputBytes = new byte[accumulatedBytes.length + outgoingPrefix.length];
+ System.arraycopy(outgoingPrefix, 0, outputBytes, 0, outgoingPrefix.length);
+ System.arraycopy(accumulatedBytes, 0, outputBytes, outgoingPrefix.length, accumulatedBytes.length);
+ send(outputBytes);
+
+ if (DEBUG)
+ System.err.println(String.format("##### %s - flushed", getClass().getName()));
+ }
+
+ /**
+ * Closes the connection.
+ *
+ * @see com.sun.star.connection.XConnection#close
+ */
+ public void close() throws com.sun.star.uno.RuntimeException {
+ if (DEBUG) System.err.println("##### " + getClass().getName() + " - socket closed");
+ super.close();
+ }
+
+ /**
+ * Gives a description of the connection.
+ *
+ * @return the description.
+ * @see com.sun.star.connection.XConnection#getDescription
+ */
+ public String getDescription() throws com.sun.star.uno.RuntimeException {
+ return _description;
+ }
+
+ @Override
+ public void onOpen(ServerHandshake handshakedata) {
+ notifyListeners_open();
+ }
+
+ @Override
+ public void onClose(int code, String reason, boolean remote) {
+ notifyListeners_close();
+ }
+
+ @Override
+ public void onMessage(String message) {
+ String[] messageParts = message.split(": ", 2);
+ if (messageParts.length != 2)
+ {
+ notifyListeners_error(new com.sun.star.uno.Exception(new ProtocolException(String.format("Received URP/WS message (%s) without a type specifier. Messages must be proceeded by 'urp: '", message))));
+ return;
+ }
+
+ String messageType = messageParts[0];
+
+ if (!messageType.equals("urp"))
+ {
+ if (DEBUG) System.err.println(String.format("##### %s - received %s message but that is not URP", getClass().getName(), messageType));
+ return;
+ }
+
+ byte[] messageBytes = messageParts[1].getBytes(StandardCharsets.UTF_8);
+
+ try {
+ _inputStreamWriter.write(messageBytes);
+ _inputStreamWriter.flush();
+ } catch (IOException e) {
+ notifyListeners_error(new com.sun.star.uno.Exception(e));
+ return;
+ }
+
+ if (DEBUG) System.err.println(String.format("##### %s - received %s chars", getClass().getName(), Integer.toString(messageBytes.length)));
+ }
+
+ @Override
+ public void onMessage(ByteBuffer message) {
+ byte[] prefixedMessageBytes = message.array();
+
+ StringBuffer messageTypeBuf = new StringBuffer();
+ boolean hasType = false;
+ int i;
+ for (i = 0; i < prefixedMessageBytes.length - 1; i++) {
+ if (prefixedMessageBytes[i] == ':' && prefixedMessageBytes[i+1] == ' ') {
+ hasType = true;
+ break; // The type ends with ": ", so if we find this sequence we found the end of our type
+ }
+ messageTypeBuf.append((char)prefixedMessageBytes[i]);
+ }
+
+ if(!hasType) {
+ notifyListeners_error(new com.sun.star.uno.Exception(new ProtocolException(String.format("Received URP/WS message (%s) without a type specifier. Binary messages must be proceeded by 'urp: '", message))));
+ return;
+ }
+
+ String messageType = messageTypeBuf.toString();
+
+ int messageStartIndex = i + 2;
+
+ if (!messageType.equals("urp")) {
+ if (DEBUG) System.err.println(String.format("##### %s - received %s binary message but that is not URP", getClass().getName(), messageType));
+ return;
+ }
+
+ byte[] messageBytes = Arrays.copyOfRange(prefixedMessageBytes, messageStartIndex, prefixedMessageBytes.length);
+
+ try {
+ _inputStreamWriter.write(messageBytes);
+ _inputStreamWriter.flush();
+ } catch (IOException e) {
+ notifyListeners_error(new com.sun.star.uno.Exception(e));
+ return;
+ }
+
+ if (DEBUG) System.err.println(String.format("##### %s - received %s bytes", getClass().getName(), Integer.toString(prefixedMessageBytes.length)));
+ }
+
+ @Override
+ public void onError(Exception ex) {
+ notifyListeners_error(new com.sun.star.uno.Exception(ex));
+ }
+
+}
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/ridljar/com/sun/star/lib/connections/websocket/websocketConnector.java b/ridljar/com/sun/star/lib/connections/websocket/websocketConnector.java
new file mode 100644
index 0000000000..a40bb0093c
--- /dev/null
+++ b/ridljar/com/sun/star/lib/connections/websocket/websocketConnector.java
@@ -0,0 +1,137 @@
+/* -*- Mode: Java; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
+/*
+ * 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 com.sun.star.lib.connections.websocket;
+
+import com.sun.star.comp.loader.FactoryHelper;
+import com.sun.star.connection.ConnectionSetupException;
+import com.sun.star.connection.NoConnectException;
+import com.sun.star.connection.XConnection;
+import com.sun.star.connection.XConnector;
+import com.sun.star.lang.XMultiServiceFactory;
+import com.sun.star.lang.XSingleServiceFactory;
+import com.sun.star.registry.XRegistryKey;
+
+import java.io.IOException;
+import java.net.InetAddress;
+import java.net.Socket;
+import java.net.URISyntaxException;
+import java.net.UnknownHostException;
+
+/**
+ * A component that implements the <code>XConnector</code> interface.
+ *
+ * <p>The <code>websocketConnector</code> is a specialized component that uses
+ * websockets for communication. The <code>websocketConnector</code> is generally
+ * used by the <code>com.sun.star.connection.Connector</code> service.</p>
+ *
+ * @see com.sun.star.connection.XAcceptor
+ * @see com.sun.star.connection.XConnection
+ * @see com.sun.star.connection.XConnector
+ * @see com.sun.star.comp.loader.JavaLoader
+ */
+public final class websocketConnector implements XConnector {
+ /**
+ * The name of the service.
+ *
+ * <p>The <code>JavaLoader</code> accesses this through reflection.</p>
+ *
+ * @see com.sun.star.comp.loader.JavaLoader
+ */
+ public static final String __serviceName
+ = "com.sun.star.connection.websocketConnector";
+
+ /**
+ * Returns a factory for creating the service.
+ *
+ * <p>This method is called by the <code>JavaLoader</code>.</p>
+ *
+ * @param implName the name of the implementation for which a service is
+ * requested.
+ * @param multiFactory the service manager to be used (if needed).
+ * @param regKey the registry key.
+ * @return an <code>XSingleServiceFactory</code> for creating the component.
+ *
+ * @see com.sun.star.comp.loader.JavaLoader
+ */
+ public static XSingleServiceFactory __getServiceFactory(
+ String implName, XMultiServiceFactory multiFactory, XRegistryKey regKey)
+ {
+ return implName.equals(websocketConnector.class.getName())
+ ? FactoryHelper.getServiceFactory(websocketConnector.class,
+ __serviceName, multiFactory,
+ regKey)
+ : null;
+ }
+
+ /**
+ * Connects via the described websocket to a waiting server.
+ *
+ * <p>The connection description has the following format:
+ * <code><var>type</var></code><!--
+ * -->*(<code><var>key</var>=<var>value</var></code>),
+ * where <code><var>type</var></code> should be <code>websocket</code>
+ * (ignoring case). Supported keys (ignoring case) currently are</p>
+ * <dl>
+ * <dt><code>url</code>
+ * <dd>The URL the websocket server is listening on, starting with
+ * either ws:// or wss://
+ * </dl>
+ *
+ * @param connectionDescription the description of the connection.
+ * @return an <code>XConnection</code> to the server.
+ *
+ * @see com.sun.star.connection.XAcceptor
+ * @see com.sun.star.connection.XConnection
+ */
+ public synchronized XConnection connect(String connectionDescription)
+ throws NoConnectException, ConnectionSetupException
+ {
+ if (connected)
+ throw new ConnectionSetupException("Already connected to the socket");
+
+ ConnectionDescriptor desc;
+ try {
+ desc = new ConnectionDescriptor(connectionDescription);
+ } catch (com.sun.star.lang.IllegalArgumentException e) {
+ throw new ConnectionSetupException(e);
+ }
+
+ WebsocketConnection websocket = null;
+ try {
+ websocket = new WebsocketConnection(connectionDescription, desc);
+ connected = websocket.isOpen();
+ } catch (IOException e) {
+ throw new ConnectionSetupException(e);
+ } catch (URISyntaxException e) {
+ throw new ConnectionSetupException(e);
+ } catch (InterruptedException e) {
+ throw new ConnectionSetupException(e);
+ }
+
+ if (websocket == null || !connected)
+ throw new ConnectionSetupException("Could not connect to the server. Is it up?");
+
+ return websocket;
+ }
+
+ private boolean connected = false;
+}
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/ridljar/com/sun/star/lib/uno/Proxy.java b/ridljar/com/sun/star/lib/uno/Proxy.java
new file mode 100644
index 0000000000..7d3612758f
--- /dev/null
+++ b/ridljar/com/sun/star/lib/uno/Proxy.java
@@ -0,0 +1,34 @@
+/* -*- Mode: Java; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
+/*
+ * 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 com.sun.star.lib.uno;
+
+/**
+ * Marker interface implemented by proxies for UNO objects.
+ *
+ * <p>Currently, this interface is used internally by
+ * <code>com.sun.star.lib.uno.environments.java.java_environment</code> to
+ * distinguish between proxies and local objects. Any proxy object that shall
+ * be registered at the <code>java_environment</code> must implement this marker
+ * interface.</p>
+ */
+public interface Proxy {
+}
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/ridljar/com/sun/star/lib/uno/adapter/ByteArrayToXInputStreamAdapter.java b/ridljar/com/sun/star/lib/uno/adapter/ByteArrayToXInputStreamAdapter.java
new file mode 100644
index 0000000000..2d3e9a8480
--- /dev/null
+++ b/ridljar/com/sun/star/lib/uno/adapter/ByteArrayToXInputStreamAdapter.java
@@ -0,0 +1,117 @@
+/*
+ * 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 com.sun.star.lib.uno.adapter;
+
+import com.sun.star.io.XInputStream;
+import com.sun.star.io.XSeekable;
+import com.sun.star.lib.uno.helper.ComponentBase;
+
+public final class ByteArrayToXInputStreamAdapter
+ extends ComponentBase
+ implements XInputStream, XSeekable
+{
+
+ byte[] m_bytes;
+ int m_length;
+ int m_pos;
+
+ boolean m_open;
+
+ /** Creates a new instance of ByteArrayXInputStram */
+ public ByteArrayToXInputStreamAdapter(byte[] bytes) {
+ init(bytes);
+ }
+
+ public void init(byte[] bytes) {
+ m_bytes = bytes;
+ m_length = bytes.length;
+ m_pos = 0;
+ m_open = true;
+ }
+
+ private void _check() throws com.sun.star.io.NotConnectedException, com.sun.star.io.IOException {
+ if (m_bytes == null) {
+ throw new com.sun.star.io.NotConnectedException("no bytes");
+ }
+ if(!m_open) {
+ throw new com.sun.star.io.IOException("input closed");
+ }
+ }
+
+ public int available() throws com.sun.star.io.NotConnectedException, com.sun.star.io.IOException {
+ _check();
+ long a = m_length - m_pos;
+ if (a != (int)a)
+ throw new com.sun.star.io.IOException("integer overflow");
+ else {
+ return (int)a;
+ }
+ }
+
+ public void closeInput() throws com.sun.star.io.NotConnectedException, com.sun.star.io.IOException {
+ _check();
+ m_open = false;
+ }
+
+ public int readBytes(byte[][] values, int param) throws com.sun.star.io.NotConnectedException, com.sun.star.io.BufferSizeExceededException, com.sun.star.io.IOException {
+ _check();
+ try {
+ int remain = (m_length - m_pos);
+ if (param > remain) param = remain;
+ /* ARGH!!! */
+ if (values[0] == null){
+ values[0] = new byte[param];
+ }
+ System.arraycopy(m_bytes, m_pos, values[0], 0, param);
+ m_pos += param;
+ return param;
+ } catch (ArrayIndexOutOfBoundsException ex) {
+ throw new com.sun.star.io.BufferSizeExceededException(ex, "buffer overflow");
+ } catch (Exception ex) {
+ throw new com.sun.star.io.IOException(ex, "error accessing buffer");
+ }
+ }
+
+ public int readSomeBytes(byte[][] values, int param) throws com.sun.star.io.NotConnectedException, com.sun.star.io.BufferSizeExceededException, com.sun.star.io.IOException {
+ return readBytes(values, param);
+ }
+
+ public void skipBytes(int param) throws com.sun.star.io.NotConnectedException, com.sun.star.io.BufferSizeExceededException, com.sun.star.io.IOException {
+ _check();
+ if (param > (m_length - m_pos))
+ throw new com.sun.star.io.BufferSizeExceededException("buffer overflow");
+ m_pos += param;
+ }
+
+ public long getLength() throws com.sun.star.io.IOException {
+ if (m_bytes != null) return m_length;
+ else throw new com.sun.star.io.IOException("no bytes");
+ }
+
+ public long getPosition() throws com.sun.star.io.IOException {
+ if (m_bytes != null) return m_pos;
+ else throw new com.sun.star.io.IOException("no bytes");
+ }
+
+ public void seek(long param) throws com.sun.star.lang.IllegalArgumentException, com.sun.star.io.IOException {
+ if (m_bytes != null){
+ if (param < 0 || param > m_length) throw new com.sun.star.lang.IllegalArgumentException("invalid seek position");
+ else m_pos = (int)param;
+ }else throw new com.sun.star.io.IOException("no bytes");
+ }
+}
diff --git a/ridljar/com/sun/star/lib/uno/adapter/InputStreamToXInputStreamAdapter.java b/ridljar/com/sun/star/lib/uno/adapter/InputStreamToXInputStreamAdapter.java
new file mode 100644
index 0000000000..dd634e7713
--- /dev/null
+++ b/ridljar/com/sun/star/lib/uno/adapter/InputStreamToXInputStreamAdapter.java
@@ -0,0 +1,157 @@
+/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4; fill-column: 100 -*- */
+/*
+ * 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 com.sun.star.lib.uno.adapter;
+
+import java.io.IOException;
+
+import com.sun.star.io.XInputStream;
+
+import java.io.InputStream;
+
+/** The <code>InputStreamToInputXStreamAdapter</code> wraps the
+ Java <code>InputStream</code> object into a
+ UNO <code>XInputStream</code> object.
+ This allows users to access an <code>InputStream</code>
+ as if it were an <code>XInputStream</code>.
+ */
+public final class InputStreamToXInputStreamAdapter implements XInputStream {
+
+ /**
+ * Internal store to the InputStream
+ */
+ private final InputStream iIn;
+
+ /**
+ * Constructor.
+ *
+ * @param in The <code>XInputStream</code> to be
+ * accessed as an <code>InputStream</code>.
+ */
+ public InputStreamToXInputStreamAdapter (InputStream in)
+ {
+ iIn = in;
+ }
+
+ public int available() throws
+ com.sun.star.io.IOException
+ {
+
+ int bytesAvail;
+
+ try {
+ bytesAvail = iIn.available();
+ } catch (IOException e) {
+ throw new com.sun.star.io.IOException(e);
+ }
+
+ return bytesAvail;
+ }
+
+ public void closeInput() throws
+ com.sun.star.io.IOException
+ {
+ try {
+ iIn.close();
+ } catch (IOException e) {
+ throw new com.sun.star.io.IOException(e);
+ }
+ }
+
+ public int readBytes(byte[][] b, int len) throws
+ com.sun.star.io.IOException
+ {
+ try {
+ long bytesRead;
+ int totalBytesRead = 0;
+ if (b[0] == null || b[0].length < len) {
+ b[0] = new byte[len];
+ }
+
+ // Casting bytesRead to an int is okay, since the user can
+ // only pass in an integer length to read, so the bytesRead
+ // must <= len.
+ while ((len > 0) && ((bytesRead = iIn.read(b[0], totalBytesRead, len)) > 0)) {
+ totalBytesRead += (int)bytesRead;
+ len -= (int)bytesRead;
+ }
+ if (totalBytesRead < b[0].length) {
+ byte[] out = new byte[totalBytesRead];
+ System.arraycopy(b[0], 0, out, 0, totalBytesRead);
+ b[0] = out;
+ }
+ return totalBytesRead;
+ } catch (IOException e) {
+ throw new com.sun.star.io.IOException("reader error", e);
+ }
+ }
+
+ public int readSomeBytes(byte[][] b, int len) throws
+ com.sun.star.io.IOException
+ {
+ try {
+ long bytesRead;
+ if (b[0] == null || b[0].length < len) {
+ b[0] = new byte[len];
+ }
+ if (len >iIn.available()) {
+ bytesRead = iIn.read(b[0], 0, iIn.available());
+ }
+ else{
+ bytesRead = iIn.read(b[0], 0, len);
+ }
+
+ // Casting bytesRead to an int is okay, since the user can
+ // only pass in an integer length to read, so the bytesRead
+ // must <= len.
+ if (bytesRead < b[0].length) {
+ int outSize = bytesRead > 0 ? (int)bytesRead : 0;
+ byte[] out = new byte[outSize];
+ System.arraycopy(b[0], 0, out, 0, outSize);
+ b[0] = out;
+ }
+ if (bytesRead <= 0) {
+ return 0;
+ }
+ return ((int)bytesRead);
+ } catch (IOException e) {
+ throw new com.sun.star.io.IOException("reader error", e);
+ }
+ }
+
+ public void skipBytes(int n) throws
+ com.sun.star.io.IOException
+ {
+ try {
+ iIn.available();
+ } catch (IOException e) {
+ throw new com.sun.star.io.IOException(e);
+ }
+
+ do {
+ try {
+ n -= iIn.skip(n);
+ } catch (IOException e) {
+ throw new com.sun.star.io.IOException(e);
+ }
+ } while (n > 0);
+ }
+}
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab cinoptions=b1,g0,N-s cinkeys+=0=break: */
diff --git a/ridljar/com/sun/star/lib/uno/adapter/OutputStreamToXOutputStreamAdapter.java b/ridljar/com/sun/star/lib/uno/adapter/OutputStreamToXOutputStreamAdapter.java
new file mode 100644
index 0000000000..2842e3df05
--- /dev/null
+++ b/ridljar/com/sun/star/lib/uno/adapter/OutputStreamToXOutputStreamAdapter.java
@@ -0,0 +1,80 @@
+/*
+ * 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 com.sun.star.lib.uno.adapter;
+
+import java.io.IOException;
+
+import com.sun.star.io.XOutputStream;
+
+import java.io.OutputStream;
+
+/** The <code>OutputStreamToXOutputStreamAdapter</code> wraps
+ a UNO <code>XOutputStream</code> into a Java <code>OutputStream</code>
+ object in a Java. This allows users to access an <code>OutputStream</code>
+ as if it were an <code>XOutputStream</code>.
+ */
+public final class OutputStreamToXOutputStreamAdapter implements XOutputStream {
+
+ /**
+ * Internal handle to the OutputStream
+ */
+ OutputStream iOut;
+
+ /**
+ * Constructor.
+ *
+ * @param out The <code>XOutputStream</code> to be
+ * accessed as an <code>OutputStream</code>.
+ */
+ public OutputStreamToXOutputStreamAdapter(OutputStream out) {
+ iOut = out;
+ }
+
+ public void closeOutput() throws
+ com.sun.star.io.IOException
+ {
+ try {
+ iOut.close();
+ } catch (IOException e) {
+ throw new com.sun.star.io.IOException(e);
+ }
+ }
+
+ public void flush() throws
+ com.sun.star.io.IOException
+ {
+ try {
+ iOut.flush();
+ } catch (IOException e) {
+ throw new com.sun.star.io.IOException(e);
+ }
+ }
+
+ public void writeBytes(byte[] b) throws
+ com.sun.star.io.IOException
+ {
+
+ try {
+ iOut.write(b);
+ } catch (IOException e) {
+ throw new com.sun.star.io.IOException(e);
+ }
+ }
+
+}
diff --git a/ridljar/com/sun/star/lib/uno/adapter/XInputStreamToInputStreamAdapter.java b/ridljar/com/sun/star/lib/uno/adapter/XInputStreamToInputStreamAdapter.java
new file mode 100644
index 0000000000..25f1798fba
--- /dev/null
+++ b/ridljar/com/sun/star/lib/uno/adapter/XInputStreamToInputStreamAdapter.java
@@ -0,0 +1,218 @@
+/*
+ * 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 com.sun.star.lib.uno.adapter;
+
+import java.io.IOException;
+
+import com.sun.star.io.XInputStream;
+
+import java.io.InputStream;
+
+/**
+ * The <code>XInputStreamToInputStreamAdapter</code> wraps
+ * the UNO <code>XInputStream</code> object in a Java
+ * <code>InputStream</code>. This allows users to access
+ * an <code>XInputStream</code> as if it were an
+ * <code>InputStream</code>.
+ */
+public final class XInputStreamToInputStreamAdapter extends InputStream {
+
+ /**
+ * Internal handle to the XInputStream
+ */
+ private final XInputStream xin;
+
+ /**
+ * Constructor.
+ *
+ * @param in The <code>XInputStream</code> to be
+ * accessed as an <code>InputStream</code>.
+ */
+ public XInputStreamToInputStreamAdapter (XInputStream in) {
+ xin = in;
+ }
+
+ @Override
+ public int available() throws IOException {
+
+ int bytesAvail;
+
+ try {
+ bytesAvail = xin.available();
+ } catch (Exception e) {
+ IOException newEx = new IOException(e.getMessage());
+ newEx.initCause(e);
+ throw newEx;
+ }
+
+ return bytesAvail;
+ }
+
+ @Override
+ public void close() throws IOException {
+ try {
+ xin.closeInput();
+ } catch (Exception e) {
+ IOException newEx = new IOException(e.getMessage());
+ newEx.initCause(e);
+ throw newEx;
+ }
+ }
+
+ @Override
+ public int read () throws IOException {
+ byte [][] tmp = new byte [1][1];
+ try {
+ long bytesRead = xin.readBytes(tmp, 1);
+
+ if (bytesRead <= 0) {
+ return (-1);
+ } else {
+ int tmpInt = tmp[0][0];
+ if (tmpInt< 0 ){
+ tmpInt = 256 +tmpInt;
+ }
+ return tmpInt;
+ }
+
+ } catch (Exception e) {
+ IOException newEx = new IOException(e.getMessage());
+ newEx.initCause(e);
+ throw newEx;
+ }
+ }
+
+ @Override
+ public int read (byte[] b) throws IOException {
+
+ byte [][] tmp = new byte [1][b.length];
+ int bytesRead;
+
+ try {
+ bytesRead = xin.readBytes(tmp, b.length);
+ if (bytesRead <= 0) {
+ return -1;
+ } else if (bytesRead < b.length) {
+ System.arraycopy(tmp[0], 0, b, 0, bytesRead);
+ } else {
+ System.arraycopy(tmp[0], 0, b, 0, b.length);
+ }
+ } catch (Exception e) {
+ IOException newEx = new IOException(e.getMessage());
+ newEx.initCause(e);
+ throw newEx;
+ }
+
+ return bytesRead;
+ }
+
+ @Override
+ public int read(byte[] b, int off, int len) throws IOException {
+ byte [][] tmp = new byte [1][b.length];
+ try {
+ long bytesRead;
+ int av = xin.available();
+ if ( av != 0 && len > av) {
+ bytesRead = xin.readBytes(tmp, av);
+ }
+ else{
+ bytesRead = xin.readBytes(tmp,len);
+ }
+ // Casting bytesRead to an int is okay, since the user can
+ // only pass in an integer length to read, so the bytesRead
+ // must <= len.
+
+ if (bytesRead <= 0) {
+ return -1;
+ } else if (bytesRead < len) {
+ System.arraycopy(tmp[0], 0, b, off, (int)bytesRead);
+ } else {
+ System.arraycopy(tmp[0], 0, b, off, len);
+ }
+
+ return ((int)bytesRead);
+ } catch (Exception e) {
+ IOException newEx = new IOException(e.getMessage());
+ newEx.initCause(e);
+ throw newEx;
+ }
+ }
+
+ @Override
+ public long skip(long n) throws IOException {
+
+ int avail;
+ long tmpLongVal = n;
+ int tmpIntVal;
+
+ try {
+ avail = xin.available();
+ } catch (Exception e) {
+ IOException newEx = new IOException(e.getMessage());
+ newEx.initCause(e);
+ throw newEx;
+ }
+
+ do {
+ if (tmpLongVal >= Integer.MAX_VALUE) {
+ tmpIntVal = Integer.MAX_VALUE;
+ } else {
+ // Casting is safe here.
+ tmpIntVal = (int)tmpLongVal;
+ }
+ tmpLongVal -= tmpIntVal;
+
+ try {
+ xin.skipBytes(tmpIntVal);
+ } catch (Exception e) {
+ IOException newEx = new IOException(e.getMessage());
+ newEx.initCause(e);
+ throw newEx;
+ }
+ } while (tmpLongVal > 0);
+
+ if ( avail != 0 && avail < n) {
+ return avail;
+ } else {
+ return n;
+ }
+ }
+
+ /**
+ * Tests if this input stream supports the mark and reset methods.
+ * The markSupported method of
+ * <code>XInputStreamToInputStreamAdapter</code> returns false.
+ *
+ * @return false
+ */
+ @Override
+ public boolean markSupported() {
+ return false;
+ }
+
+ @Override
+ public synchronized void mark(int readlimit) {
+ // Not supported.
+ }
+
+ @Override
+ public synchronized void reset() throws IOException {
+ // Not supported.
+ }
+}
+
diff --git a/ridljar/com/sun/star/lib/uno/adapter/XOutputStreamToByteArrayAdapter.java b/ridljar/com/sun/star/lib/uno/adapter/XOutputStreamToByteArrayAdapter.java
new file mode 100644
index 0000000000..48871277a7
--- /dev/null
+++ b/ridljar/com/sun/star/lib/uno/adapter/XOutputStreamToByteArrayAdapter.java
@@ -0,0 +1,94 @@
+/*
+ * 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 com.sun.star.lib.uno.adapter;
+
+import com.sun.star.io.*;
+import com.sun.star.lib.uno.helper.ComponentBase;
+
+public final class XOutputStreamToByteArrayAdapter
+ extends ComponentBase
+ implements XOutputStream
+{
+ private static final int initialSize = 100240; // 10 kb
+ private int size = 0;
+ private int position = 0;
+ private boolean externalBuffer = false;
+ private byte[] buffer;
+
+ /** Creates a new instance of ByteArrayXOutputStream */
+ public XOutputStreamToByteArrayAdapter() {
+ this(null);
+ }
+
+ public XOutputStreamToByteArrayAdapter(byte[] aBuffer) {
+ if (aBuffer != null) {
+ externalBuffer = true;
+ buffer = aBuffer;
+ size = buffer.length;
+ } else {
+ size = initialSize;
+ buffer = new byte[size];
+ }
+ }
+
+ public byte[] getBuffer() {
+ return buffer;
+ }
+
+ public void closeOutput()
+ throws com.sun.star.io.NotConnectedException,
+ com.sun.star.io.BufferSizeExceededException,
+ com.sun.star.io.IOException
+ {
+ // trim buffer
+ if ( buffer.length > position && !externalBuffer )
+ {
+ byte[] newBuffer = new byte[position];
+ System.arraycopy(buffer, 0, newBuffer, 0, position);
+ buffer = newBuffer;
+ }
+ }
+
+ public void flush()
+ throws com.sun.star.io.NotConnectedException,
+ com.sun.star.io.BufferSizeExceededException,
+ com.sun.star.io.IOException
+ {
+ }
+
+ public void writeBytes(byte[] values)
+ throws com.sun.star.io.NotConnectedException,
+ com.sun.star.io.BufferSizeExceededException,
+ com.sun.star.io.IOException
+ {
+ if ( values.length > size-position )
+ {
+ if ( externalBuffer )
+ throw new BufferSizeExceededException("out of buffer space, cannot grow external buffer");
+ while ( values.length > size-position ) {
+ size *= 2;
+ }
+ byte[] newBuffer = new byte[size];
+ System.arraycopy(buffer, 0, newBuffer, 0, position);
+ buffer = newBuffer;
+ }
+ System.arraycopy(values, 0, buffer, position, values.length);
+ position += values.length;
+ }
+
+}
diff --git a/ridljar/com/sun/star/lib/uno/adapter/XOutputStreamToOutputStreamAdapter.java b/ridljar/com/sun/star/lib/uno/adapter/XOutputStreamToOutputStreamAdapter.java
new file mode 100644
index 0000000000..8104cf42fa
--- /dev/null
+++ b/ridljar/com/sun/star/lib/uno/adapter/XOutputStreamToOutputStreamAdapter.java
@@ -0,0 +1,117 @@
+/*
+ * 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 com.sun.star.lib.uno.adapter;
+
+import java.io.IOException;
+
+import com.sun.star.io.XOutputStream;
+
+import java.io.OutputStream;
+
+/**
+ * The <code>XOutputStreamToOutputStreamAdapter</code> wraps
+ * the UNO <code>XOutputStream</code> object in a Java
+ * <code>OutputStream</code>. This allows users to access
+ * an <code>XOutputStream</code> as if it were an
+ * <code>OutputStream</code>.
+ */
+public final class XOutputStreamToOutputStreamAdapter extends OutputStream {
+
+ /**
+ * Internal handle to the XInputStream
+ */
+ XOutputStream xout;
+
+ /**
+ * Constructor.
+ *
+ * @param out The <code>XOutputStream</code> to be
+ * accessed as an <code>OutputStream</code>.
+ */
+ public XOutputStreamToOutputStreamAdapter(XOutputStream out) {
+ xout = out;
+ }
+
+ @Override
+ public void close() throws IOException {
+ try {
+ xout.closeOutput();
+ } catch (Exception e) {
+ IOException newEx = new IOException(e.getMessage());
+ newEx.initCause(e);
+ throw newEx;
+ }
+ }
+
+ @Override
+ public void flush() throws IOException {
+ try {
+ xout.flush();
+ } catch (Exception e) {
+ IOException newEx = new IOException(e.getMessage());
+ newEx.initCause(e);
+ throw newEx;
+ }
+ }
+
+ @Override
+ public void write(byte[] b) throws IOException {
+
+ try {
+ xout.writeBytes(b);
+ } catch (Exception e) {
+ IOException newEx = new IOException(e.getMessage());
+ newEx.initCause(e);
+ throw newEx;
+ }
+ }
+
+ @Override
+ public void write(byte[] b, int off, int len) throws IOException {
+
+ byte[] tmp = new byte[len];
+
+ // Copy the input array into a temp array, and write it out.
+
+ System.arraycopy(b, off, tmp, 0, len);
+
+ try {
+ xout.writeBytes(tmp);
+ } catch (Exception e) {
+ IOException newEx = new IOException(e.getMessage());
+ newEx.initCause(e);
+ throw newEx;
+ }
+ }
+
+ @Override
+ public void write(int b) throws IOException {
+
+ byte [] oneByte = new byte [1];
+ oneByte[0] = (byte) b;
+
+ try {
+ xout.writeBytes(oneByte);
+ } catch (Exception e) {
+ IOException newEx = new IOException(e.getMessage());
+ newEx.initCause(e);
+ throw newEx;
+ }
+ }
+}
diff --git a/ridljar/com/sun/star/lib/uno/bridges/java_remote/BridgedObject.java b/ridljar/com/sun/star/lib/uno/bridges/java_remote/BridgedObject.java
new file mode 100644
index 0000000000..0a724f0593
--- /dev/null
+++ b/ridljar/com/sun/star/lib/uno/bridges/java_remote/BridgedObject.java
@@ -0,0 +1,43 @@
+/* -*- Mode: Java; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
+/*
+ * 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 com.sun.star.lib.uno.bridges.java_remote;
+
+import com.sun.star.bridge.XBridge;
+
+/**
+ * A back door to access the bridge associated with a bridged object.
+ */
+public final class BridgedObject {
+ /**
+ * Obtains the bridge associated with a bridged object.
+ *
+ * @param obj a reference to a (Java representation of a) UNO object;
+ * must not be null.
+ * @return the bridge associated with the given object, if it is indeed
+ * bridged; otherwise, null is returned.
+ */
+ public static XBridge getBridge(Object obj) {
+ return ProxyFactory.getBridge(obj);
+ }
+
+ private BridgedObject() {} // do not instantiate
+}
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/ridljar/com/sun/star/lib/uno/bridges/java_remote/ProxyFactory.java b/ridljar/com/sun/star/lib/uno/bridges/java_remote/ProxyFactory.java
new file mode 100644
index 0000000000..1b38489835
--- /dev/null
+++ b/ridljar/com/sun/star/lib/uno/bridges/java_remote/ProxyFactory.java
@@ -0,0 +1,198 @@
+/* -*- Mode: Java; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
+/*
+ * 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 com.sun.star.lib.uno.bridges.java_remote;
+
+import com.sun.star.bridge.XBridge;
+import com.sun.star.lib.util.AsynchronousFinalizer;
+import com.sun.star.uno.IQueryInterface;
+import com.sun.star.uno.Type;
+import com.sun.star.uno.UnoRuntime;
+
+import java.lang.reflect.InvocationHandler;
+import java.lang.reflect.Method;
+import java.lang.reflect.Proxy;
+
+/**
+ * A factory for proxies specific to the <code>java_remote_bridge</code>.
+ *
+ * <p>Eventually, this class should be united with all other proxy classes
+ * specific to certain bridges (for example, the JNI bridge), resulting in a
+ * generic proxy class.</p>
+ */
+final class ProxyFactory {
+ public ProxyFactory(RequestHandler requestHandler, XBridge bridge) {
+ this.requestHandler = requestHandler;
+ this.bridge = bridge;
+ }
+
+ public Object create(String oid, Type type) {
+ return Proxy.newProxyInstance(
+ getClass().getClassLoader(),
+ new Class[] { com.sun.star.lib.uno.Proxy.class,
+ IQueryInterface.class, type.getZClass() },
+ new Handler(oid, type));
+ }
+
+ public boolean isProxy(Object obj) {
+ if (Proxy.isProxyClass(obj.getClass())) {
+ InvocationHandler h = Proxy.getInvocationHandler(obj);
+ return h instanceof Handler && ((Handler) h).matches(this);
+ } else {
+ return false;
+ }
+ }
+
+ public void dispose() throws InterruptedException {
+ asynchronousFinalizer.drain();
+ }
+
+ public static XBridge getBridge(Object obj) {
+ if (Proxy.isProxyClass(obj.getClass())) {
+ InvocationHandler h = Proxy.getInvocationHandler(obj);
+ if (h instanceof Handler) {
+ return ((Handler) h).getBridge();
+ }
+ }
+ return null;
+ }
+
+ static int getDebugCount() {
+ synchronized (debugCountLock) {
+ return debugCount;
+ }
+ }
+
+ private static void incrementDebugCount() {
+ synchronized (debugCountLock) {
+ ++debugCount;
+ }
+ }
+
+ private static void decrementDebugCount() {
+ synchronized (debugCountLock) {
+ --debugCount;
+ }
+ }
+
+ private final class Handler implements InvocationHandler {
+ public Handler(String oid, Type type) {
+ this.oid = oid;
+ this.type = type;
+ incrementDebugCount();
+ }
+
+ public boolean matches(ProxyFactory factory) {
+ return ProxyFactory.this == factory;
+ }
+
+ public XBridge getBridge() {
+ return bridge;
+ }
+
+ public Object invoke(Object proxy, Method method, Object[] args)
+ throws Throwable
+ {
+ if (method.equals(METHOD_EQUALS) || method.equals(METHOD_IS_SAME)) {
+ return Boolean.valueOf(args[0] != null
+ && oid.equals(UnoRuntime.generateOid(args[0])));
+ } else if (method.equals(METHOD_HASH_CODE)) {
+ return Integer.valueOf(oid.hashCode());
+ } else if (method.equals(METHOD_TO_STRING)) {
+ return "[Proxy:" + System.identityHashCode(proxy) + "," + oid
+ + "," + type + "]";
+ } else if (method.equals(METHOD_QUERY_INTERFACE)) {
+ // See the comment in java_remote_bridge.mapInterfaceTo for one
+ // reason why this implementation must not satisfy a request for
+ // a super-interface with a proxy itself:
+ return args[0].equals(type) ? proxy
+ : request("queryInterface", args);
+ } else if (method.equals(METHOD_GET_OID)) {
+ return oid;
+ } else {
+ return request(method.getName(), args);
+ }
+ }
+
+ @Override
+ protected void finalize() {
+ decrementDebugCount();
+ asynchronousFinalizer.add(new AsynchronousFinalizer.Job() {
+ public void run() throws Throwable {
+ request("release", null);
+ }
+ });
+ }
+
+ private Object request(String operation, Object[] args) throws Throwable
+ {
+ Object res = requestHandler.sendRequest(oid, type, operation, args);
+ // Avoid early finalization of this object, while an invoke ->
+ // request call is still ongoing; as finalize also calls request,
+ // this should fulfil the condition from The Java Language
+ // Specification, 3rd ed., that "if an object's finalizer can result
+ // in synchronization on that object, then that object must be alive
+ // and considered reachable whenever a lock is held on it:"
+ synchronized (this) {
+ ++dummy;
+ }
+ return res;
+ }
+
+ private final String oid;
+ private final Type type;
+ @SuppressWarnings("unused")
+ private int dummy = 0;
+ }
+
+ private static final Method METHOD_EQUALS;
+ private static final Method METHOD_HASH_CODE;
+ private static final Method METHOD_TO_STRING;
+ private static final Method METHOD_QUERY_INTERFACE;
+ private static final Method METHOD_IS_SAME;
+ private static final Method METHOD_GET_OID;
+ static {
+ try {
+ METHOD_EQUALS = Object.class.getMethod(
+ "equals", new Class[] { Object.class });
+ METHOD_HASH_CODE = Object.class.getMethod(
+ "hashCode", (Class[]) null);
+ METHOD_TO_STRING = Object.class.getMethod(
+ "toString", (Class[]) null);
+ METHOD_QUERY_INTERFACE = IQueryInterface.class.getMethod(
+ "queryInterface", new Class[] { Type.class });
+ METHOD_IS_SAME = IQueryInterface.class.getMethod(
+ "isSame", new Class[] { Object.class });
+ METHOD_GET_OID = IQueryInterface.class.getMethod(
+ "getOid", (Class[]) null);
+ } catch (NoSuchMethodException e) {
+ throw new ExceptionInInitializerError(e);
+ }
+ }
+
+ private static final Object debugCountLock = new Object();
+ private static int debugCount = 0;
+
+ private final RequestHandler requestHandler;
+ private final XBridge bridge;
+ private final AsynchronousFinalizer asynchronousFinalizer =
+ new AsynchronousFinalizer();
+}
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/ridljar/com/sun/star/lib/uno/bridges/java_remote/RequestHandler.java b/ridljar/com/sun/star/lib/uno/bridges/java_remote/RequestHandler.java
new file mode 100644
index 0000000000..d5246bf26c
--- /dev/null
+++ b/ridljar/com/sun/star/lib/uno/bridges/java_remote/RequestHandler.java
@@ -0,0 +1,35 @@
+/* -*- Mode: Java; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
+/*
+ * 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 com.sun.star.lib.uno.bridges.java_remote;
+
+import com.sun.star.uno.Type;
+
+/**
+ * The link between the proxies generated by <code>ProxyFactory</code> (which
+ * receive requests in the form of method calls) and
+ * <code>java_remote_bridge</code> (which passes those requests on to the remote
+ * side).
+ */
+interface RequestHandler {
+ Object sendRequest(String oid, Type type, String operation, Object[] args)
+ throws Throwable;
+}
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/ridljar/com/sun/star/lib/uno/bridges/java_remote/XConnectionInputStream_Adapter.java b/ridljar/com/sun/star/lib/uno/bridges/java_remote/XConnectionInputStream_Adapter.java
new file mode 100644
index 0000000000..8d660e88ca
--- /dev/null
+++ b/ridljar/com/sun/star/lib/uno/bridges/java_remote/XConnectionInputStream_Adapter.java
@@ -0,0 +1,76 @@
+/* -*- Mode: Java; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
+/*
+ * 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 com.sun.star.lib.uno.bridges.java_remote;
+
+
+import java.io.IOException;
+import java.io.InputStream;
+
+import com.sun.star.connection.XConnection;
+
+
+class XConnectionInputStream_Adapter extends InputStream {
+ private static final boolean DEBUG = false;
+
+ protected XConnection _xConnection;
+ protected byte _bytes[][] = new byte[1][];
+
+ XConnectionInputStream_Adapter(XConnection xConnection) {
+ if(xConnection == null) throw new NullPointerException("the XConnection must not be null");
+
+ if(DEBUG) System.err.println("#### " + getClass().getName() + " - instantiated ");
+
+ _xConnection = xConnection;
+ }
+
+ @Override
+ public int read() throws IOException {
+ int len;
+
+ try {
+ len = _xConnection.read(_bytes, 1);
+ } catch(com.sun.star.io.IOException ioException) {
+ IOException ex = new IOException(ioException.getMessage());
+ ex.initCause(ioException);
+ throw ex;
+ }
+
+ if(DEBUG) System.err.println("#### " + getClass().getName() + " - one byte read:" + _bytes[0][0]);
+
+ return len == 0 ? -1 : _bytes[0][0] & 0xff;
+ }
+
+ @Override
+ public int read(byte[] b, int off, int len) throws IOException {
+ try {
+ len = _xConnection.read(_bytes, len - off);
+ } catch(com.sun.star.io.IOException ioException) {
+ IOException ex = new IOException(ioException.getMessage());
+ ex.initCause(ioException);
+ throw ex;
+ }
+
+ System.arraycopy(_bytes[0], 0, b, off, len);
+
+ return len == 0 ? -1 : len;
+ }
+}
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/ridljar/com/sun/star/lib/uno/bridges/java_remote/XConnectionOutputStream_Adapter.java b/ridljar/com/sun/star/lib/uno/bridges/java_remote/XConnectionOutputStream_Adapter.java
new file mode 100644
index 0000000000..ac198f8fdd
--- /dev/null
+++ b/ridljar/com/sun/star/lib/uno/bridges/java_remote/XConnectionOutputStream_Adapter.java
@@ -0,0 +1,89 @@
+/* -*- Mode: Java; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
+/*
+ * 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 com.sun.star.lib.uno.bridges.java_remote;
+
+
+import java.io.IOException;
+import java.io.OutputStream;
+
+import com.sun.star.connection.XConnection;
+
+
+class XConnectionOutputStream_Adapter extends OutputStream {
+ private static final boolean DEBUG = false;
+
+ protected XConnection _xConnection;
+ protected byte _bytes[] = new byte[1];
+
+ XConnectionOutputStream_Adapter(XConnection xConnection) {
+ if(DEBUG) System.err.println("#### " + this.getClass() + " - instantiated ");
+
+ _xConnection = xConnection;
+ }
+
+ @Override
+ public void write(int b) throws IOException {
+ _bytes[0] = (byte)b;
+
+ try {
+ _xConnection.write(_bytes);
+ } catch(com.sun.star.io.IOException ioException) {
+ IOException ex = new IOException(ioException.getMessage());
+ ex.initCause(ioException);
+ throw ex;
+ }
+
+ if(DEBUG) System.err.println("#### " + this.getClass() + " - one byte written:" + _bytes[0]);
+ }
+
+ @Override
+ public void write(byte[] b, int off, int len) throws IOException {
+ byte bytes[] ;
+
+ if(off == 0 && len == b.length) {
+ bytes = b;
+ } else {
+ bytes = new byte[len];
+
+ System.arraycopy(b, off, bytes, 0, len);
+ }
+
+ try {
+ _xConnection.write(bytes);
+ } catch(com.sun.star.io.IOException ioException) {
+ IOException ex = new IOException(ioException.getMessage());
+ ex.initCause(ioException);
+ throw ex;
+ }
+ }
+
+ @Override
+ public void flush() throws IOException {
+ try {
+ _xConnection.flush();
+ } catch(com.sun.star.io.IOException ioException) {
+ IOException ex = new IOException(ioException.getMessage());
+ ex.initCause(ioException);
+ throw ex;
+ }
+ }
+}
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/ridljar/com/sun/star/lib/uno/bridges/java_remote/java_remote_bridge.java b/ridljar/com/sun/star/lib/uno/bridges/java_remote/java_remote_bridge.java
new file mode 100644
index 0000000000..392e031e30
--- /dev/null
+++ b/ridljar/com/sun/star/lib/uno/bridges/java_remote/java_remote_bridge.java
@@ -0,0 +1,700 @@
+/* -*- Mode: Java; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
+/*
+ * 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 com.sun.star.lib.uno.bridges.java_remote;
+
+
+import java.io.IOException;
+import java.io.InputStream;
+import java.io.OutputStream;
+import java.util.ArrayList;
+import java.util.HashMap;
+import java.util.Iterator;
+import java.util.LinkedList;
+import java.util.Map;
+import java.util.concurrent.atomic.AtomicInteger;
+
+import com.sun.star.bridge.XBridge;
+import com.sun.star.bridge.XInstanceProvider;
+import com.sun.star.connection.XConnection;
+import com.sun.star.lang.DisposedException;
+import com.sun.star.lang.EventObject;
+import com.sun.star.lang.XComponent;
+import com.sun.star.lang.XEventListener;
+import com.sun.star.lib.uno.environments.java.java_environment;
+import com.sun.star.lib.uno.environments.remote.IProtocol;
+import com.sun.star.lib.uno.environments.remote.IReceiver;
+import com.sun.star.lib.uno.environments.remote.IThreadPool;
+import com.sun.star.lib.uno.environments.remote.Job;
+import com.sun.star.lib.uno.environments.remote.Message;
+import com.sun.star.lib.uno.environments.remote.ThreadId;
+import com.sun.star.lib.uno.environments.remote.ThreadPoolManager;
+import com.sun.star.lib.uno.typedesc.MethodDescription;
+import com.sun.star.lib.uno.typedesc.TypeDescription;
+import com.sun.star.lib.util.DisposeListener;
+import com.sun.star.lib.util.DisposeNotifier;
+import com.sun.star.uno.Any;
+import com.sun.star.uno.IBridge;
+import com.sun.star.uno.IEnvironment;
+import com.sun.star.uno.Type;
+import com.sun.star.uno.TypeClass;
+import com.sun.star.uno.UnoRuntime;
+import com.sun.star.uno.XInterface;
+
+/**
+ * This class implements a remote bridge.
+ *
+ * <p>Therefore various interfaces are implemented.</p>
+ *
+ * <p>The protocol to used is passed by name, the bridge
+ * then looks for it under <code>com.sun.star.lib.uno.protocols</code>.</p>
+ *
+ * @since UDK1.0
+ */
+public class java_remote_bridge
+ implements IBridge, IReceiver, RequestHandler, XBridge, XComponent,
+ DisposeNotifier
+{
+ /**
+ * When set to true, enables various debugging output.
+ */
+ private static final boolean DEBUG = false;
+
+ private final class MessageDispatcher extends Thread {
+ public MessageDispatcher() {
+ super("MessageDispatcher");
+ }
+
+ @Override
+ public void run() {
+ try {
+ for (;;) {
+ synchronized (this) {
+ if (terminate) {
+ break;
+ }
+ }
+ Message msg = _iProtocol.readMessage();
+ Object obj = null;
+ if (msg.isRequest()) {
+ String oid = msg.getObjectId();
+ Type type = new Type(msg.getType());
+ int fid = msg.getMethod().getIndex();
+ if (fid == MethodDescription.ID_RELEASE) {
+ _java_environment.revokeInterface(oid, type);
+ remRefHolder(type, oid);
+ if (msg.isSynchronous()) {
+ sendReply(false, msg.getThreadId(), null);
+ }
+ continue;
+ }
+ obj = _java_environment.getRegisteredInterface(
+ oid, type);
+ if (obj == null
+ && fid == MethodDescription.ID_QUERY_INTERFACE)
+ {
+ if (_xInstanceProvider == null) {
+ sendReply(
+ true, msg.getThreadId(),
+ new com.sun.star.uno.RuntimeException(
+ "unknown OID " + oid));
+ continue;
+ } else {
+ UnoRuntime.setCurrentContext(
+ msg.getCurrentContext());
+ try {
+ obj = _xInstanceProvider.getInstance(oid);
+ } catch (com.sun.star.uno.RuntimeException e) {
+ sendReply(true, msg.getThreadId(), e);
+ continue;
+ } catch (Exception e) {
+ sendReply(
+ true, msg.getThreadId(),
+ new com.sun.star.uno.RuntimeException(
+ e.toString()));
+ continue;
+ } finally {
+ UnoRuntime.setCurrentContext(null);
+ }
+ }
+ }
+ }
+ _iThreadPool.putJob(
+ new Job(obj, java_remote_bridge.this, msg));
+ }
+ } catch (Throwable e) {
+ dispose(e);
+ }
+ }
+
+ public synchronized void terminate() {
+ terminate = true;
+ }
+
+ private boolean terminate = false;
+ }
+
+ protected XConnection _xConnection;
+
+ protected XInstanceProvider _xInstanceProvider;
+
+ protected String _name = "remote";
+ private final String protocol;
+ protected IProtocol _iProtocol;
+ protected IEnvironment _java_environment;
+ protected MessageDispatcher _messageDispatcher;
+ protected final AtomicInteger _life_count = new AtomicInteger(); // determines if this bridge is alive, which is controlled by acquire and release calls
+
+ private final ArrayList<XEventListener> _listeners = new ArrayList<XEventListener>();
+
+ protected IThreadPool _iThreadPool;
+
+ // Variable disposed must only be used while synchronized on this object:
+ private boolean disposed = false;
+
+ /**
+ * This method is for testing only.
+ */
+ int getLifeCount() {
+ return _life_count.get();
+ }
+
+ /**
+ * This method is for testing only.
+ */
+ IProtocol getProtocol() {
+ return _iProtocol;
+ }
+
+ /**
+ * The ref holder stuff strongly holds objects mapped out via this bridge
+ * (the java_environment only holds them weakly).
+ *
+ * <p>When this bridge is disposed, all remaining ref holder entries are
+ * released.</p>
+ */
+ private static final class RefHolder {
+ public RefHolder(Type type, Object object) {
+ this.type = type;
+ this.object = object;
+ }
+
+ public Type getType() {
+ return type;
+ }
+
+ public void acquire() {
+ ++count;
+ }
+
+ public boolean release() {
+ return --count == 0;
+ }
+
+ private final Type type;
+ @SuppressWarnings("unused")
+ private final Object object;
+ private int count = 1;
+ }
+
+ private final HashMap<String, LinkedList<RefHolder>> refHolders = new HashMap<String, LinkedList<RefHolder>>();
+ // from OID (String) to LinkedList of RefHolder
+
+ private boolean hasRefHolder(String oid, Type type) {
+ synchronized (refHolders) {
+ LinkedList<RefHolder> l = refHolders.get(oid);
+ if (l != null) {
+ for (RefHolder rh : l) {
+ if (type.isSupertypeOf(rh.getType())) {
+ return true;
+ }
+ }
+ }
+ }
+ return false;
+ }
+
+ final void addRefHolder(Object obj, Type type, String oid) {
+ synchronized (refHolders) {
+ LinkedList<RefHolder> l = refHolders.get(oid);
+ if (l == null) {
+ l = new LinkedList<RefHolder>();
+ refHolders.put(oid, l);
+ }
+ boolean found = false;
+ for (Iterator<RefHolder> i = l.iterator(); !found && i.hasNext();) {
+ RefHolder rh = i.next();
+ if (rh.getType().equals(type)) {
+ found = true;
+ rh.acquire();
+ }
+ }
+ if (!found) {
+ l.add(new RefHolder(type, obj));
+ }
+ }
+ acquire();
+ }
+
+ final void remRefHolder(Type type, String oid) {
+ synchronized (refHolders) {
+ LinkedList<RefHolder> l = refHolders.get(oid);
+ if (l == null) {
+ return;
+ }
+ for (RefHolder rh : l) {
+ if (rh.getType().equals(type)) {
+ try {
+ if (rh.release()) {
+ l.remove(rh);
+ if (l.isEmpty()) {
+ refHolders.remove(oid);
+ }
+ }
+ } finally {
+ release();
+ }
+ break;
+ }
+ }
+ }
+ }
+
+ final void freeHolders() {
+ synchronized (refHolders) {
+ for (Iterator<Map.Entry<String,LinkedList<RefHolder>>> i1 = refHolders.entrySet().iterator(); i1.hasNext();)
+ {
+ Map.Entry<String,LinkedList<RefHolder>> e = i1.next();
+ String oid = e.getKey();
+ LinkedList<RefHolder> l = e.getValue();
+ for (Iterator<RefHolder> i2 = l.iterator(); i2.hasNext();) {
+ RefHolder rh = i2.next();
+ for (boolean done = false; !done;) {
+ done = rh.release();
+ _java_environment.revokeInterface(oid, rh.getType());
+ release();
+ }
+ }
+ }
+ refHolders.clear();
+ }
+ }
+
+ public java_remote_bridge(
+ IEnvironment java_environment, IEnvironment remote_environment,
+ Object[] args)
+ throws Exception
+ {
+ _java_environment = java_environment;
+ String proto = (String) args[0];
+ _xConnection = (XConnection) args[1];
+ _xInstanceProvider = (XInstanceProvider) args[2];
+ if (args.length > 3) {
+ _name = (String) args[3];
+ }
+ String attr;
+ int i = proto.indexOf(',');
+ if (i >= 0) {
+ protocol = proto.substring(0, i);
+ attr = proto.substring(i + 1);
+ } else {
+ protocol = proto;
+ attr = null;
+ }
+ _iProtocol = (IProtocol) Class.forName(
+ "com.sun.star.lib.uno.protocols." + protocol + "." + protocol).
+ getConstructor(
+ new Class[] {
+ IBridge.class, String.class, InputStream.class,
+ OutputStream.class }).
+ newInstance(
+ new Object[] {
+ this, attr,
+ new XConnectionInputStream_Adapter(_xConnection),
+ new XConnectionOutputStream_Adapter(_xConnection) });
+ proxyFactory = new ProxyFactory(this, this);
+ _iThreadPool = ThreadPoolManager.create();
+ _messageDispatcher = new MessageDispatcher();
+ _messageDispatcher.start();
+ _iProtocol.init();
+ }
+
+ private void notifyListeners() {
+ EventObject eventObject = new EventObject(this);
+
+ Iterator<XEventListener> elements = _listeners.iterator();
+ while(elements.hasNext()) {
+ XEventListener xEventListener = elements.next();
+
+ try {
+ xEventListener.disposing(eventObject);
+ }
+ catch(com.sun.star.uno.RuntimeException runtimeException) {
+ // we are here not interested in any exceptions
+ }
+ }
+ }
+
+ /**
+ * Constructs a new bridge.
+ * <p> This method is not part of the provided <code>api</code>
+ * and should only be used by the UNO runtime.</p>
+ *
+ * @param args the custom parameters: arg[0] == protocol_name,
+ * arg[1] == xConnection, arg[2] == xInstanceProvider.
+ *
+ * @deprecated as of UDK 1.0
+ */
+ @Deprecated
+ public java_remote_bridge(Object args[]) throws Exception {
+ this(UnoRuntime.getEnvironment("java", null), UnoRuntime.getEnvironment("remote", null), args);
+ }
+
+ /**
+ *
+ * @see com.sun.star.uno.IBridge#mapInterfaceTo
+ */
+ public Object mapInterfaceTo(Object object, Type type) {
+ checkDisposed();
+ if (object == null) {
+ return null;
+ } else {
+ String[] oid = new String[1];
+ object = _java_environment.registerInterface(object, oid, type);
+ if (!proxyFactory.isProxy(object)) {
+ // This branch must be taken iff object either is no proxy at
+ // all or a proxy from some other bridge. There are objects
+ // that behave like objects for this bridge but that are not
+ // detected as such by proxyFactory.isProxy. The only known
+ // case of such objects is com.sun.star.comp.beans.Wrapper,
+ // which implements com.sun.star.lib.uno.Proxy and effectively
+ // is a second proxy around a proxy that can be from this
+ // bridge. For that case, there is no problem, however: Since
+ // the proxies generated by ProxyFactory send each
+ // queryInterface to the original object (i.e., they do not
+ // short-circuit requests for a super-interface to themselves),
+ // there will always be an appropriate ProxyFactory-proxy
+ // registered at the _java_environment, so that the object
+ // returned by _java_environment.registerInterface will never be
+ // a com.sun.star.comp.beans.Wrapper.
+ addRefHolder(object, type, oid[0]);
+ }
+ return oid[0];
+ }
+ }
+
+ /**
+ * Maps an object from destination environment to the source environment.
+ *
+ * @param oId the object to map.
+ * @param type the interface under which is to be mapped.
+ * @return the object in the source environment.
+ *
+ * @see com.sun.star.uno.IBridge#mapInterfaceFrom
+ */
+ public Object mapInterfaceFrom(Object oId, Type type) {
+ checkDisposed();
+ // TODO What happens if an exception is thrown after the call to
+ // acquire, but before it is guaranteed that a pairing release will be
+ // called eventually?
+ acquire();
+ String oid = (String) oId;
+ Object object = _java_environment.getRegisteredInterface(oid, type);
+ if (object == null) {
+ object = _java_environment.registerInterface(
+ proxyFactory.create(oid, type), new String[] { oid }, type);
+ // the proxy sends a release when finalized
+ } else if (!hasRefHolder(oid, type)) {
+ sendInternalRequest(oid, type, "release", null);
+ }
+ return object;
+ }
+
+ /**
+ * Gives the source environment.
+ *
+ * @return the source environment of this bridge.
+ * @see com.sun.star.uno.IBridge#getSourceEnvironment
+ */
+ public IEnvironment getSourceEnvironment() {
+ return _java_environment;
+ }
+
+ /**
+ * Gives the destination environment.
+ *
+ * @return the destination environment of this bridge.
+ * @see com.sun.star.uno.IBridge#getTargetEnvironment
+ */
+ public IEnvironment getTargetEnvironment() {
+ return null;
+ }
+
+ /**
+ * Increases the life count.
+ *
+ * @see com.sun.star.uno.IBridge#acquire
+ */
+ public void acquire() {
+ if(DEBUG) {
+ int x = _life_count.incrementAndGet();
+ System.err.println("##### " + getClass().getName() + ".acquire:" + x);
+ } else {
+ _life_count.incrementAndGet();
+ }
+ }
+
+ /**
+ * Decreases the life count.
+ *
+ * <p>If the life count drops to zero, the bridge disposes itself.</p>
+ *
+ * @see com.sun.star.uno.IBridge#release
+ */
+ public void release() {
+ int x = _life_count.decrementAndGet();
+ if (x <= 0) {
+ dispose(new Throwable("end of life"));
+ }
+ }
+
+ public void dispose() {
+ dispose(new Throwable("user dispose"));
+ }
+
+ private void dispose(Throwable throwable) {
+ synchronized (this) {
+ if (disposed) {
+ return;
+ }
+ disposed = true;
+ }
+
+ notifyListeners();
+ for (Iterator<DisposeListener> i = disposeListeners.iterator(); i.hasNext();) {
+ i.next().notifyDispose(this);
+ }
+
+ _iProtocol.terminate();
+
+ try {
+ _messageDispatcher.terminate();
+
+ try {
+ _xConnection.close();
+ } catch (com.sun.star.io.IOException e) {
+ System.err.println(
+ getClass().getName() + ".dispose - IOException:" + e);
+ }
+
+ if (Thread.currentThread() != _messageDispatcher
+ && _messageDispatcher.isAlive())
+ {
+ _messageDispatcher.join(1000);
+ if (_messageDispatcher.isAlive()) {
+ _messageDispatcher.interrupt();
+ _messageDispatcher.join();
+ }
+ }
+
+ // interrupt all jobs queued by this bridge
+ _iThreadPool.dispose(throwable);
+
+ // release all out-mapped objects and all in-mapped proxies:
+ freeHolders();
+ // assert _java_environment instanceof java_environment;
+ ((java_environment) _java_environment).revokeAllProxies();
+
+ proxyFactory.dispose();
+
+ if (DEBUG) {
+ if (_life_count.get() != 0) {
+ System.err.println(getClass().getName()
+ + ".dispose - life count (proxies left):"
+ + _life_count);
+ }
+ _java_environment.list();
+ }
+
+ // clear members
+ _xConnection = null;
+ _java_environment = null;
+ _messageDispatcher = null;
+ } catch (InterruptedException e) {
+ System.err.println(getClass().getName()
+ + ".dispose - InterruptedException:" + e);
+ }
+ }
+
+ /**
+ *
+ * @see com.sun.star.bridge.XBridge#getInstance
+ */
+ public Object getInstance(String instanceName) {
+ Type t = new Type(XInterface.class);
+ return sendInternalRequest(
+ instanceName, t, "queryInterface", new Object[] { t });
+ }
+
+ /**
+ * Gives the name of this bridge.
+ *
+ * @return the name of this bridge.
+ * @see com.sun.star.bridge.XBridge#getName
+ */
+ public String getName() {
+ return _name;
+ }
+
+ /**
+ * Gives a description of the connection type and protocol used.
+ *
+ * @return connection type and protocol.
+ * @see com.sun.star.bridge.XBridge#getDescription
+ */
+ public String getDescription() {
+ return protocol + "," + _xConnection.getDescription();
+ }
+
+ public void sendReply(boolean exception, ThreadId threadId, Object result) {
+ if (DEBUG) {
+ System.err.println("##### " + getClass().getName() + ".sendReply: "
+ + exception + " " + result);
+ }
+
+ checkDisposed();
+
+ try {
+ _iProtocol.writeReply(exception, threadId, result);
+ } catch (IOException e) {
+ dispose(e);
+ throw (DisposedException)
+ (new DisposedException("unexpected " + e).initCause(e));
+ } catch (RuntimeException e) {
+ dispose(e);
+ throw e;
+ } catch (Error e) {
+ dispose(e);
+ throw e;
+ }
+ }
+
+ public Object sendRequest(
+ String oid, Type type, String operation, Object[] params)
+ throws Throwable
+ {
+ Object result = null;
+
+ checkDisposed();
+
+ ThreadId threadId = _iThreadPool.getThreadId();
+ Object handle = _iThreadPool.attach(threadId);
+ try {
+ boolean sync;
+ try {
+ sync = _iProtocol.writeRequest(
+ oid, TypeDescription.getTypeDescription(type), operation,
+ threadId, params);
+ } catch (IOException e) {
+ dispose(e);
+ throw (DisposedException)
+ new DisposedException(e.toString()).initCause(e);
+ }
+ if (sync && Thread.currentThread() != _messageDispatcher) {
+ result = _iThreadPool.enter(handle, threadId);
+ }
+ } finally {
+ _iThreadPool.detach(handle, threadId);
+ if(operation.equals("release"))
+ release(); // kill this bridge, if this was the last proxy
+ }
+
+ if(DEBUG) System.err.println("##### " + getClass().getName() + ".sendRequest left:" + result);
+
+ // On the wire (at least in URP), the result of queryInterface is
+ // transported as an ANY, but in Java it shall be transported as a
+ // direct reference to the UNO object (represented as a Java Object),
+ // never boxed in a com.sun.star.uno.Any:
+ if (operation.equals("queryInterface") && result instanceof Any) {
+ Any a = (Any) result;
+ if (a.getType().getTypeClass() == TypeClass.INTERFACE) {
+ result = a.getObject();
+ } else {
+ result = null; // should never happen
+ }
+ }
+
+ return result;
+ }
+
+ private Object sendInternalRequest(
+ String oid, Type type, String operation, Object[] arguments)
+ {
+ try {
+ return sendRequest(oid, type, operation, arguments);
+ } catch (Error e) {
+ throw e;
+ } catch (RuntimeException e) {
+ throw e;
+ } catch (Throwable e) {
+ throw new RuntimeException("Unexpected " + e);
+ }
+ }
+
+ /**
+ * Methods XComponent.
+ */
+ public void addEventListener(XEventListener xEventListener) {
+ _listeners.add(xEventListener);
+ }
+
+ public void removeEventListener(XEventListener xEventListener) {
+ _listeners.remove(xEventListener);
+ }
+
+ /**
+ *
+ * @see DisposeNotifier#addDisposeListener
+ */
+ public void addDisposeListener(DisposeListener listener) {
+ synchronized (this) {
+ if (!disposed) {
+ disposeListeners.add(listener);
+ return;
+ }
+ }
+ listener.notifyDispose(this);
+ }
+
+ /**
+ * This function must only be called while synchronized on this object.
+ */
+ private synchronized void checkDisposed() {
+ if (disposed) {
+ throw new DisposedException("java_remote_bridge " + this
+ + " is disposed");
+ }
+ }
+
+ private final ProxyFactory proxyFactory;
+
+ // Access to disposeListeners must be synchronized on <CODE>this</CODE>:
+ private final ArrayList<DisposeListener> disposeListeners = new ArrayList<DisposeListener>();
+}
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/ridljar/com/sun/star/lib/uno/environments/java/java_environment.java b/ridljar/com/sun/star/lib/uno/environments/java/java_environment.java
new file mode 100644
index 0000000000..89e4b10880
--- /dev/null
+++ b/ridljar/com/sun/star/lib/uno/environments/java/java_environment.java
@@ -0,0 +1,312 @@
+/* -*- Mode: Java; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
+/*
+ * 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 com.sun.star.lib.uno.environments.java;
+
+import com.sun.star.uno.IEnvironment;
+import com.sun.star.uno.Type;
+import com.sun.star.uno.UnoRuntime;
+import java.lang.ref.ReferenceQueue;
+import java.lang.ref.WeakReference;
+import java.util.HashMap;
+import java.util.Iterator;
+
+/**
+ * The java_environment is the environment where objects and
+ * interfaces are registered, which are mapped out of java or
+ * into java.
+ *
+ * <p>The java_environment implements the <code>IEnvironment</code> interface
+ * defined in the uno runtime.</p>
+ *
+ * @see com.sun.star.uno.UnoRuntime
+ * @see com.sun.star.uno.IEnvironment
+ * @since UDK1.0
+ */
+public final class java_environment implements IEnvironment {
+ public java_environment(Object context) {
+ this.context = context;
+ }
+
+ /**
+ *
+ * @see com.sun.star.uno.IEnvironment#getContext
+ */
+ public Object getContext() {
+ return context;
+ }
+
+ /**
+ *
+ * @see com.sun.star.uno.IEnvironment#getName
+ */
+ public String getName() {
+ return "java";
+ }
+
+ /**
+ *
+ * @see com.sun.star.uno.IEnvironment#registerInterface
+ */
+ public Object registerInterface(Object object, String[] oid, Type type) {
+ if (oid[0] == null) {
+ oid[0] = UnoRuntime.generateOid(object);
+ }
+ return (isProxy(object) ? proxies : localObjects).register(
+ object, oid[0], type);
+ }
+
+ /**
+ * You have to revoke ANY interface that has been registered via this
+ * method.
+ *
+ * @param oid object id of interface to be revoked.
+ * @param type the type description of the interface.
+ * @see com.sun.star.uno.IEnvironment#revokeInterface
+ */
+ public void revokeInterface(String oid, Type type) {
+ if (!proxies.revoke(oid, type)) {
+ localObjects.revoke(oid, type);
+ }
+ }
+
+ /**
+ * Retrieves an interface identified by its object id and type from this
+ * environment.
+ *
+ * @param oid object id of interface to be retrieved.
+ * @param type the type description of the interface to be retrieved.
+ * @see com.sun.star.uno.IEnvironment#getRegisteredInterface
+ */
+ public Object getRegisteredInterface(String oid, Type type) {
+ Object o = proxies.get(oid, type);
+ if (o == null) {
+ o = localObjects.get(oid, type);
+ }
+ return o;
+ }
+
+ /**
+ * Retrieves the object identifier for a registered interface from this
+ * environment.
+ *
+ * @param object a registered interface.
+ * @see com.sun.star.uno.IEnvironment#getRegisteredObjectIdentifier
+ */
+ public String getRegisteredObjectIdentifier(Object object) {
+ return UnoRuntime.generateOid(object);
+ }
+
+ /**
+ *
+ * @see com.sun.star.uno.IEnvironment#list
+ */
+ public void list() {
+// TODO???
+ }
+
+ /**
+ * Revokes all registered proxy interfaces.
+ *
+ * <p>This method should be part of <code>IEnvironment</code>. It is called
+ * from <code>com.sun.star.lib.uno.bridges.java_remote.<!--
+ * -->java_remote_bridge.dispose</code>.</p>
+ */
+ public void revokeAllProxies() {
+ proxies.clear();
+ }
+
+ // TODO What's this??? java.lang.Object#equals requires reflexivity...
+ //
+ // Maybe this was hacked in so that different bridges use different
+ // instances of java_environment. That is desirable for the following
+ // reason: An OID is bridged in over bridge A, a proxy is created on the
+ // Java side, and recorded in the java_environment. The same OID is then
+ // bridged in over another bridge B. If there were only one
+ // java_environment shared by both bridges, the proxy from bridge A would be
+ // reused. If now bridge A is taken down programmatically (e.g., because
+ // some controlling code somehow deduced that no objects are mapped over
+ // that bridge any longer), but the proxy is still used by bridge B, using
+ // the proxy would now result in errors. The explicit API to control
+ // bridges forbids to transparently share proxies between bridges, and using
+ // different java_environment instances for different bridges is the way to
+ // enforce this.
+ @Override
+ public boolean equals(Object obj) {
+ return false;
+ }
+
+ private static final class Registry {
+ public synchronized Object register(
+ Object object, String oid, Type type)
+ {
+ cleanUp();
+ Level1Entry l1 = level1map.get(oid);
+ if (l1 != null) {
+ Level2Entry l2 = l1.level2map.get(type);
+ if (l2 != null) {
+ Object o = l2.get();
+ if (o != null) {
+ l2.acquire();
+ return o;
+ }
+ }
+ }
+ // TODO If a holder references an unreachable object, but still has
+ // a positive count, it is replaced with a new holder (referencing a
+ // reachable object, and with a count of 1). Any later calls to
+ // revoke that should decrement the count of the previous holder
+ // would now decrement the count of the new holder, removing it
+ // prematurely. This is a design flaw that will be fixed when
+ // IEnvironment.revokeInterface is changed to no longer use
+ // counting. (And this problem is harmless, as currently a holder
+ // either references a strongly held object and uses register/revoke
+ // to control it, or references a weakly held proxy and never
+ // revokes it.)
+ if (l1 == null) {
+ l1 = new Level1Entry();
+ level1map.put(oid, l1);
+ }
+ l1.level2map.put(type, new Level2Entry(oid, type, object, queue));
+ return object;
+ }
+
+ public synchronized boolean revoke(String oid, Type type) {
+ Level1Entry l1 = level1map.get(oid);
+ Level2Entry l2 = null;
+ if (l1 != null) {
+ l2 = l1.level2map.get(type);
+ if (l2 != null && l2.release()) {
+ removeLevel2Entry(l1, oid, type);
+ }
+ }
+ cleanUp();
+ return l2 != null;
+ }
+
+ public synchronized Object get(String oid, Type type) {
+ Level1Entry l1 = level1map.get(oid);
+ return l1 == null ? null : l1.find(type);
+ }
+
+ public synchronized void clear() {
+ level1map.clear();
+ cleanUp();
+ }
+
+ // must only be called while synchronized on this Registry:
+ private void cleanUp() {
+ for (;;) {
+ Object tmp = queue.poll();
+ Level2Entry l2 = (Level2Entry) tmp;
+ if (l2 == null) {
+ break;
+ }
+ // It is possible that a Level2Entry e1 for the OID/type pair
+ // (o,t) becomes weakly reachable, then another Level2Entry e2
+ // is registered for the same pair (o,t) (a new Level2Entry is
+ // created since now e1.get() == null), and only then e1 is
+ // enqueued. To not erroneously remove the new e2 in that case,
+ // check whether the map still contains e1:
+ Level1Entry l1 = level1map.get(l2.oid);
+ if (l1 != null && l1.level2map.get(l2.type) == l2) {
+ removeLevel2Entry(l1, l2.oid, l2.type);
+ }
+ }
+ }
+
+ // must only be called while synchronized on this Registry:
+ private void removeLevel2Entry(Level1Entry l1, String oid, Type type) {
+ l1.level2map.remove(type);
+ if (l1.level2map.isEmpty()) {
+ level1map.remove(oid);
+ }
+ }
+
+ private static final class Level1Entry {
+ // must only be called while synchronized on enclosing Registry:
+ public Object find(Type type) {
+ // First, look for an exactly matching entry; then, look for an
+ // arbitrary entry for a subtype of the request type:
+ Level2Entry l2 = level2map.get(type);
+ if (l2 != null) {
+ Object o = l2.get();
+ if (o != null) {
+ return o;
+ }
+ }
+ for (Iterator<Level2Entry> i = level2map.values().iterator();
+ i.hasNext();)
+ {
+ l2 = i.next();
+ if (type.isSupertypeOf(l2.type)) {
+ Object o = l2.get();
+ if (o != null) {
+ return o;
+ }
+ }
+ }
+ return null;
+ }
+
+ public final HashMap<Type, Level2Entry> level2map =
+ new HashMap<Type, Level2Entry>();
+ }
+
+ private static final class Level2Entry extends WeakReference<Object> {
+ public Level2Entry(
+ String oid, Type type, Object object, ReferenceQueue<Object> queue)
+ {
+ super(object, queue);
+ this.oid = oid;
+ this.type = type;
+ }
+
+ // must only be called while synchronized on enclosing Registry:
+ public void acquire() {
+ ++count;
+ }
+
+ // must only be called while synchronized on enclosing Registry:
+ public boolean release() {
+ return --count == 0;
+ }
+
+ public final String oid;
+ public final Type type;
+
+ private int count = 1;
+ }
+
+ private final HashMap<String, Level1Entry> level1map =
+ new HashMap<String, Level1Entry>();
+ private final ReferenceQueue<Object> queue = new ReferenceQueue<Object>();
+ }
+
+ private boolean isProxy(Object object) {
+ return object instanceof com.sun.star.lib.uno.Proxy;
+ }
+
+ private static final Registry localObjects = new Registry();
+
+ private final Object context;
+ private final Registry proxies = new Registry();
+}
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/ridljar/com/sun/star/lib/uno/environments/remote/IProtocol.java b/ridljar/com/sun/star/lib/uno/environments/remote/IProtocol.java
new file mode 100644
index 0000000000..c2ecbf9a09
--- /dev/null
+++ b/ridljar/com/sun/star/lib/uno/environments/remote/IProtocol.java
@@ -0,0 +1,93 @@
+/* -*- Mode: Java; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
+/*
+ * 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 com.sun.star.lib.uno.environments.remote;
+
+import com.sun.star.lib.uno.typedesc.TypeDescription;
+import java.io.IOException;
+
+/**
+ * An abstraction of remote bridge protocols.
+ *
+ * <p>A class implementing a given protocol <var>prot</var> must be named
+ * <code>com.sun.star.lib.uno.protocols.<var>prot</var>.<var>prot</var></code>
+ * and must have a public constructor that takes four arguments: The first
+ * argument of type <code>com.sun.star.uno.IBridge</code> must not be null. The
+ * second argument of type <code>String</code> represents any attributes; it may
+ * be null if there are no attributes. The third argument of type
+ * <code>java.io.InputStream</code> must not be null. The fourth argument of
+ * type <code>java.io.OutputStream</code> must not be null.</p>
+ */
+public interface IProtocol {
+ /**
+ * Initializes the connection.
+ *
+ * <p>This method must be called exactly once, after the
+ * <code>readMessage</code> loop has already been established.</p>
+ */
+ void init() throws IOException;
+
+ void terminate();
+
+ /**
+ * Reads a request or reply message.
+ *
+ * <p>Access to this method from multiple threads must be properly
+ * synchronized.</p>
+ *
+ * @return a non-null message; if the input stream is exhausted, a
+ * <code>java.io.IOException</code> is thrown instead.
+ */
+ Message readMessage() throws IOException;
+
+ /**
+ * Writes a request message.
+ *
+ * @param oid a non-null OID.
+ * @param type a non-null UNO type.
+ * @param function a non-null function (the name of a UNO interface method
+ * or attribute compatible with the given <code>type</code>, or either
+ * <code>"queryInterface"</code> or <code>"release"</code>).
+ * @param tid a non-null TID.
+ * @param arguments a list of UNO arguments compatible with the given
+ * <code>type</code> and <code>function</code>; may be null to represent
+ * an empty list.
+ * @return <code>true</code> if the request message is sent as a synchronous
+ * request.
+ */
+ boolean writeRequest(
+ String oid, TypeDescription type, String function, ThreadId tid,
+ Object[] arguments)
+ throws IOException;
+
+ /**
+ * Writes a reply message.
+ *
+ * @param exception <code>true</code> if the reply corresponds to a raised
+ * exception.
+ * @param tid a non-null TID.
+ * @param result if <code>exception</code> is <code>true</code>, a non-null
+ * UNO exception; otherwise, a UNO return value, which may be null to
+ * represent a <code>VOID</code> return value.
+ */
+ void writeReply(boolean exception, ThreadId tid, Object result)
+ throws IOException;
+}
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/ridljar/com/sun/star/lib/uno/environments/remote/IReceiver.java b/ridljar/com/sun/star/lib/uno/environments/remote/IReceiver.java
new file mode 100644
index 0000000000..e39ae3d4d5
--- /dev/null
+++ b/ridljar/com/sun/star/lib/uno/environments/remote/IReceiver.java
@@ -0,0 +1,40 @@
+/* -*- Mode: Java; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
+/*
+ * 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 com.sun.star.lib.uno.environments.remote;
+
+/**
+ * An abstraction for giving back a reply for a request.
+ *
+ * @see com.sun.star.uno.IQueryInterface
+ */
+public interface IReceiver {
+ /**
+ * Send back a reply for a request.
+ *
+ * @param exception <CODE>true</CODE> if an exception (instead of a normal
+ * result) is sent back.
+ * @param threadId the thread ID of the request.
+ * @param result the result of executing the request, or an exception thrown
+ * while executing the request.
+ */
+ void sendReply(boolean exception, ThreadId threadId, Object result);
+}
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/ridljar/com/sun/star/lib/uno/environments/remote/IThreadPool.java b/ridljar/com/sun/star/lib/uno/environments/remote/IThreadPool.java
new file mode 100644
index 0000000000..1de31ad04c
--- /dev/null
+++ b/ridljar/com/sun/star/lib/uno/environments/remote/IThreadPool.java
@@ -0,0 +1,115 @@
+/* -*- Mode: Java; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
+/*
+ * 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 com.sun.star.lib.uno.environments.remote;
+
+/**
+ * This interface is an abstraction of the various threadpool implementations.
+ *
+ * @see com.sun.star.lib.uno.environments.remote.ThreadPoolManager
+ * @since UDK1.0
+ */
+public interface IThreadPool {
+ /**
+ * Retrieves the global threadId for the current thread.
+ *
+ * @return the thread id.
+ */
+ ThreadId getThreadId();
+
+ /**
+ * Attaches this thread to the thread pool.
+ *
+ * @see #enter
+ */
+ void attach();
+
+ /**
+ * As above, but hands in an already existing instance of the threadid of
+ * the current thread.
+ *
+ * <p>The function exists for performance.</p>
+ *
+ * @return Returns a handle which can be used in enter and detach calls.
+ * @see #attach
+ */
+ Object attach( ThreadId id );
+
+ /**
+ * Detaches this thread from the thread pool.
+ * @see #enter
+ */
+ void detach();
+
+ /**
+ * As above, but hands in an already existing instance of the threadid of
+ * the current thread and a handle returned by attach.
+ *
+ * <p>The function exists for performance.</p>
+ *
+ * @see #attach()
+ * @see #detach()
+ */
+ void detach( Object handle, ThreadId id );
+
+ /**
+ * Lets this thread enter the thread pool.
+ *
+ * <p>This thread then executes all jobs put via <code>putJob</code> until
+ * a reply job arrives.</p>
+ *
+ * @see #putJob
+ */
+ Object enter() throws Throwable;
+
+ /**
+ * As above but hands in an already existing instance of the threadid of
+ * the current thread and a handle returned by attach.
+ *
+ * <p>This thread then executes all jobs put via <code>putJob</code> until
+ * a reply job arrives.</p>
+ *
+ * @see #putJob
+ */
+ Object enter( Object handle, ThreadId id ) throws Throwable;
+
+ /**
+ * Queues a job into the jobQueue of the thread belonging to the jobs
+ * threadId.
+ *
+ * @param job the job
+ */
+ void putJob(Job job);
+
+ /**
+ * Disposes this thread pool, thus releasing all threads by throwing a
+ * <code>DisposedException</code> with the given <code>Throwable</code> cause.
+ *
+ * @param throwable the cause
+ */
+ void dispose(Throwable throwable);
+
+
+ /**
+ * Destroys the thread pool and tries to join all created threads immediately.
+ */
+ void destroy();
+}
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/ridljar/com/sun/star/lib/uno/environments/remote/JavaThreadPool.java b/ridljar/com/sun/star/lib/uno/environments/remote/JavaThreadPool.java
new file mode 100644
index 0000000000..332306be0e
--- /dev/null
+++ b/ridljar/com/sun/star/lib/uno/environments/remote/JavaThreadPool.java
@@ -0,0 +1,124 @@
+/* -*- Mode: Java; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
+/*
+ * 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 com.sun.star.lib.uno.environments.remote;
+
+/**
+ * This class implements a java thread pool.
+ *
+ * @see com.sun.star.uno.UnoRuntime
+ * @see com.sun.star.lib.uno.environments.remote.NativeThreadPool
+ * @see com.sun.star.lib.uno.environments.remote.IThreadPool
+ * @see com.sun.star.lib.uno.environments.remote.Job
+ * @see com.sun.star.lib.uno.environments.remote.JobQueue
+ * @since UDK1.0
+ */
+public class JavaThreadPool implements IThreadPool {
+ /**
+ * When set to true, enables various debugging output.
+ */
+ private static final boolean DEBUG = false;
+
+ JavaThreadPoolFactory _javaThreadPoolFactory;
+
+ JavaThreadPool(JavaThreadPoolFactory javaThreadPoolFactory) {
+ _javaThreadPoolFactory = javaThreadPoolFactory;
+ }
+
+ public ThreadId getThreadId() {
+ return JavaThreadPoolFactory.getThreadId();
+ }
+
+ public Object attach( ThreadId threadId )
+ {
+ if(DEBUG) System.err.println("##### " + getClass().getName() + ".attach - id:" + threadId);
+ JobQueue jobQueue = _javaThreadPoolFactory.getJobQueue(threadId);
+ if(jobQueue == null)
+ jobQueue = new JobQueue(_javaThreadPoolFactory, threadId, false);
+
+ // acquiring the jobQueue registers it at the ThreadPoolFactory
+ jobQueue.acquire();
+ return jobQueue;
+ }
+
+ public void attach() {
+ attach( getThreadId() );
+ }
+
+ public void detach( Object handle, ThreadId id )
+ {
+ ((JobQueue)handle).release();
+ }
+
+ public void detach() {
+ ThreadId threadId = getThreadId();
+ detach(_javaThreadPoolFactory.getJobQueue(threadId), threadId );
+ }
+
+
+ public Object enter( ) throws Throwable {
+ ThreadId threadId = getThreadId();
+ return enter( _javaThreadPoolFactory.getJobQueue( threadId ), threadId );
+ }
+
+ public Object enter( Object handle, ThreadId threadId ) throws Throwable {
+ return ((JobQueue)handle).enter(this);
+ }
+
+ public void putJob(Job job) {
+ if (!job.isRequest() || job.isSynchronous()) {
+ JobQueue jobQueue = _javaThreadPoolFactory.getJobQueue(job.getThreadId());
+
+ // this has not be synchronized, cause
+ // sync jobs can only come over one bridge
+ // (cause the thread blocks on other side)
+ if(jobQueue == null)
+ jobQueue = new JobQueue(_javaThreadPoolFactory, job.getThreadId(), true);
+
+ // put job acquires the queue and registers it at the ThreadPoolFactory
+ jobQueue.putJob(job, this);
+ }
+ else {
+ // this has to be synchronized, cause
+ // async jobs of the same thread can come
+ // over different bridges
+ synchronized(_javaThreadPoolFactory) {
+ JobQueue async_jobQueue = _javaThreadPoolFactory.getAsyncJobQueue(job.getThreadId());
+
+ // ensure there is jobQueue
+ if(async_jobQueue == null) // so, there is really no async queue
+ async_jobQueue = new JobQueue(_javaThreadPoolFactory, job.getThreadId());
+
+ // put job acquires the queue and registers it at the ThreadPoolFactory
+ async_jobQueue.putJob(job, this);
+ }
+ }
+ }
+
+ public void dispose(Throwable throwable) {
+ if(DEBUG) System.err.println("##### " + getClass().getName() + ".dispose:" + throwable);
+
+ _javaThreadPoolFactory.dispose(this, throwable);
+ }
+
+ public void destroy() {
+ }
+}
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/ridljar/com/sun/star/lib/uno/environments/remote/JavaThreadPoolFactory.java b/ridljar/com/sun/star/lib/uno/environments/remote/JavaThreadPoolFactory.java
new file mode 100644
index 0000000000..181a3e17e4
--- /dev/null
+++ b/ridljar/com/sun/star/lib/uno/environments/remote/JavaThreadPoolFactory.java
@@ -0,0 +1,87 @@
+/* -*- Mode: Java; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
+/*
+ * 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 com.sun.star.lib.uno.environments.remote;
+
+import java.util.Collection;
+import java.util.HashMap;
+import java.util.WeakHashMap;
+
+final class JavaThreadPoolFactory {
+
+ public IThreadPool createThreadPool() {
+ return new JavaThreadPool(this);
+ }
+
+ public void addJobQueue(JobQueue jobQueue) {
+ synchronized (jobQueues) {
+ jobQueues.put(jobQueue.getThreadId(), jobQueue);
+ }
+ }
+
+ public void removeJobQueue(JobQueue jobQueue) {
+ synchronized (jobQueues) {
+ jobQueues.remove(jobQueue.getThreadId());
+ }
+ }
+
+ public JobQueue getJobQueue(ThreadId threadId) {
+ synchronized (jobQueues) {
+ return jobQueues.get(threadId);
+ }
+ }
+
+ public JobQueue getAsyncJobQueue(ThreadId threadId) {
+ JobQueue q = getJobQueue(threadId);
+ return q == null ? null : q._async_jobQueue;
+ }
+
+ public void dispose(Object disposeId, Throwable throwable) {
+ JobQueue[] qs;
+ synchronized (jobQueues) {
+ Collection<JobQueue> c = jobQueues.values();
+ qs = c.toArray(new JobQueue[c.size()]);
+ }
+ for (int i = 0; i < qs.length; ++i) {
+ qs[i].dispose(disposeId, throwable);
+ }
+ }
+
+ public static ThreadId getThreadId() {
+ Thread t = Thread.currentThread();
+ if (t instanceof JobQueue.JobDispatcher) {
+ return ((JobQueue.JobDispatcher) t).getThreadId();
+ } else {
+ ThreadId id;
+ synchronized (threadIdMap) {
+ id = threadIdMap.get(t);
+ if (id == null) {
+ id = ThreadId.createFresh();
+ threadIdMap.put(t, id);
+ }
+ }
+ return id;
+ }
+ }
+
+ private static final WeakHashMap<Thread, ThreadId> threadIdMap = new WeakHashMap<Thread, ThreadId>();
+ private final HashMap<ThreadId, JobQueue> jobQueues = new HashMap<ThreadId, JobQueue>();
+}
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/ridljar/com/sun/star/lib/uno/environments/remote/Job.java b/ridljar/com/sun/star/lib/uno/environments/remote/Job.java
new file mode 100644
index 0000000000..8ec4492c4c
--- /dev/null
+++ b/ridljar/com/sun/star/lib/uno/environments/remote/Job.java
@@ -0,0 +1,163 @@
+/* -*- Mode: Java; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
+/*
+ * 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 com.sun.star.lib.uno.environments.remote;
+
+
+import java.io.PrintWriter;
+import java.io.StringWriter;
+
+import java.lang.reflect.InvocationTargetException;
+
+import com.sun.star.lib.uno.typedesc.MethodDescription;
+import com.sun.star.uno.Any;
+import com.sun.star.uno.Type;
+import com.sun.star.uno.UnoRuntime;
+import com.sun.star.uno.XCurrentContext;
+
+/**
+ * The Job is an abstraction for tasks which have to be done
+ * remotely because of a method invocation.
+ *
+ * @see com.sun.star.lib.uno.environments.remote.ThreadId
+ * @see com.sun.star.lib.uno.environments.remote.IReceiver
+ * @since UDK1.0
+ */
+public class Job {
+ protected IReceiver _iReceiver;
+ protected Message _iMessage;
+ Object _disposeId;
+
+ protected Object _object;
+
+ public Job(Object object, IReceiver iReceiver, Message iMessage) {
+ _object = object;
+ _iReceiver = iReceiver;
+ _iMessage = iMessage;
+ }
+
+ /**
+ * Dispatches a <code>queryInterface</code> call.
+ *
+ * @return the result of the call (should be an <code>Any</code>).
+ */
+ protected Object dispatch_queryInterface(Type type) {
+ Class<?> zInterface = type.getTypeDescription().getZClass();
+
+ Object result = null;
+
+ Object face = UnoRuntime.queryInterface(zInterface, _object);
+ // the hell knows why, but empty interfaces a given back as void anys
+ if(face != null)
+ result = new Any(type, face);
+ return result;
+ }
+
+ /**
+ * Execute the job.
+ *
+ * @return the result of the message.
+ */
+ public Object execute() throws Throwable {
+ if (_iMessage.isRequest()) {
+ Object result = null;
+ Throwable exception = null;
+ MethodDescription md = _iMessage.getMethod();
+ Object[] args = _iMessage.getArguments();
+ XCurrentContext oldCC = UnoRuntime.getCurrentContext();
+ UnoRuntime.setCurrentContext(_iMessage.getCurrentContext());
+ try {
+ result = md.getIndex() == MethodDescription.ID_QUERY_INTERFACE
+ ? dispatch_queryInterface((Type) args[0])
+ : md.getMethod().invoke(_object, args);
+ } catch (InvocationTargetException e) {
+ exception = e.getCause();
+ if (exception == null) {
+ exception = e;
+ }
+ } catch (Exception e) {
+ exception = e;
+ } finally {
+ UnoRuntime.setCurrentContext(oldCC);
+ }
+ if (_iMessage.isSynchronous()) {
+ if (exception == null) {
+ _iReceiver.sendReply(
+ false, _iMessage.getThreadId(), result);
+ } else {
+ // Here we have to be aware of non-UNO exceptions, because
+ // they may kill a remote side which does not know anything
+ // about their types:
+ if (!(exception instanceof com.sun.star.uno.Exception)
+ && !(exception instanceof
+ com.sun.star.uno.RuntimeException))
+ {
+ StringWriter writer = new StringWriter();
+ exception.printStackTrace(new PrintWriter(writer));
+ exception = new com.sun.star.uno.RuntimeException(
+ "Java exception: <" + writer + ">", null);
+ }
+ _iReceiver.sendReply(
+ true, _iMessage.getThreadId(), exception);
+ }
+ }
+ return null;
+ } else if (_iMessage.isAbnormalTermination()) {
+ throw remoteUnoRequestRaisedException(_iMessage.getResult());
+ } else {
+ return _iMessage.getResult();
+ }
+ }
+
+ public ThreadId getThreadId() {
+ return _iMessage.getThreadId();
+ }
+
+ public boolean isRequest() {
+ return _iMessage.isRequest();
+ }
+
+ public boolean isSynchronous() {
+ return _iMessage.isSynchronous();
+ }
+
+ public void dispose() {
+// _oId = null;
+// _iReceiver = null;
+// _threadId = null;
+// _object = null;
+// _operation = null;
+// _param = null;
+// _exception = null;
+// _zInterface = null;
+// _disposeId = null;
+ }
+
+ /**
+ * The name of this method is chosen to generate a somewhat self-explanatory
+ * stack trace.
+ */
+ private Exception remoteUnoRequestRaisedException(Object exception) {
+ Exception e = (Exception) exception;
+ e.fillInStackTrace();
+ return e;
+ }
+}
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/ridljar/com/sun/star/lib/uno/environments/remote/JobQueue.java b/ridljar/com/sun/star/lib/uno/environments/remote/JobQueue.java
new file mode 100644
index 0000000000..b71525ba5d
--- /dev/null
+++ b/ridljar/com/sun/star/lib/uno/environments/remote/JobQueue.java
@@ -0,0 +1,373 @@
+/* -*- Mode: Java; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
+/*
+ * 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 com.sun.star.lib.uno.environments.remote;
+
+import java.util.ArrayList;
+
+import com.sun.star.lang.DisposedException;
+
+/**
+ * The <code>JobQueue</code> implements a queue for jobs.
+ *
+ * <p>For every jobs thread id exists a job queue which is registered
+ * at the <code>ThreadPool</code>.</p>
+ *
+ * <p>A JobQueue is split into a sync job queue and an async job queue.
+ * The sync job queue is the registered queue, it delegates async jobs
+ * (put by <code>putjob</code>) into the async queue, which is only
+ * known by the sync queue.</p>
+ *
+ * @see com.sun.star.lib.uno.environments.remote.IThreadPool
+ * @see com.sun.star.lib.uno.environments.remote.Job
+ * @see com.sun.star.lib.uno.environments.remote.ThreadId
+ * @since UDK1.0
+ */
+public class JobQueue {
+ /**
+ * When set to true, enables various debugging output.
+ */
+ private static final boolean DEBUG = false;
+
+ final ArrayList<Job> jobList = new ArrayList<Job>();
+
+ private ThreadId _threadId; // the thread id of the queue
+ protected int _ref_count = 0; // the stack deepness
+ private boolean _createThread; // create a worker thread, if needed
+ private boolean _createThread_now; // create a worker thread, if needed
+ private Thread _worker_thread; // the thread that does the jobs
+
+ private Object _disposeId; // the active dispose id
+ private Object _doDispose = null;
+ private Throwable _throwable;
+
+ JobQueue _async_jobQueue; // chaining job queues for asyncs
+ protected JobQueue _sync_jobQueue; // chaining job queues for syncs
+
+ private boolean _active = false;
+
+ private JavaThreadPoolFactory _javaThreadPoolFactory;
+
+ /**
+ * A thread for dispatching jobs.
+ */
+ class JobDispatcher extends Thread {
+ Object _disposeId;
+
+ JobDispatcher(Object disposeId) {
+ super("JobDispatcher");
+
+ if(DEBUG) System.err.println("JobQueue$JobDispatcher.<init>:" + _threadId);
+
+ _disposeId = disposeId;
+ }
+
+ ThreadId getThreadId() {
+ return _threadId;
+ }
+
+ @Override
+ public void run() {
+ if(DEBUG) System.err.println("ThreadPool$JobDispatcher.run: " + Thread.currentThread());
+
+ try {
+ enter(2000, _disposeId);
+ } catch(Throwable throwable) {
+ synchronized (JobQueue.this) {
+ if(!jobList.isEmpty() || _active) { // there was a job in progress, so give a stack
+ System.err.println(getClass().getName() + " - exception occurred:" + throwable);
+ throwable.printStackTrace(System.err);
+ }
+ }
+ }
+ finally {
+ release();
+ }
+
+ if(DEBUG) System.err.println("##### " + getClass().getName() + ".run - exit:" + _threadId);
+ }
+ }
+
+
+ /**
+ * Constructs an async job queue with the given thread id which belongs to
+ * the given sync job queue.
+ *
+ * @param threadId the thread id.
+ * @see com.sun.star.lib.uno.environments.remote.ThreadId
+ */
+ JobQueue(JavaThreadPoolFactory javaThreadPoolFactory, ThreadId threadId) {
+ _javaThreadPoolFactory = javaThreadPoolFactory;
+ _threadId = ThreadId.createFresh();
+
+ _sync_jobQueue = javaThreadPoolFactory.getJobQueue(threadId);
+ if(_sync_jobQueue == null) {
+ _sync_jobQueue = new JobQueue(javaThreadPoolFactory, threadId, true);
+ _sync_jobQueue.acquire();
+ }
+
+ _sync_jobQueue._async_jobQueue = this;
+
+ _createThread = true;
+ _createThread_now = true;
+
+ acquire();
+
+ if(DEBUG) System.err.println("##### " + getClass().getName() + " - init:" + _threadId);
+ }
+
+ /**
+ * Constructs a sync job queue with the given thread id and the given thread.
+ *
+ * @param threadId the thread id.
+ * @param createThread if true, the queue creates a worker thread if needed.
+ * @see com.sun.star.lib.uno.environments.remote.ThreadId
+ */
+ JobQueue(JavaThreadPoolFactory javaThreadPoolFactory, ThreadId threadId, boolean createThread){
+ _javaThreadPoolFactory = javaThreadPoolFactory;
+ _threadId = threadId;
+ _createThread = createThread;
+ _createThread_now = createThread;
+
+ if(DEBUG) System.err.println("##### " + getClass().getName() + " - init:" + _threadId + " " + createThread);
+ }
+
+ /**
+ * Gives the thread id of this queue.
+ *
+ * @return the thread id.
+ * @see com.sun.star.lib.uno.environments.remote.ThreadId
+ */
+ ThreadId getThreadId() {
+ return _threadId;
+ }
+
+ synchronized void acquire() {
+ // add only synchronous queues .
+ if(_ref_count <= 0 && _sync_jobQueue == null )
+ _javaThreadPoolFactory.addJobQueue(this);
+
+ ++ _ref_count;
+ }
+
+ synchronized void release() {
+ -- _ref_count;
+
+ if(_ref_count <= 0) {
+ // only synchronous queues needs to be removed .
+ if( _sync_jobQueue == null )
+ _javaThreadPoolFactory.removeJobQueue(this);
+
+
+ if(_sync_jobQueue != null) {
+ _sync_jobQueue._async_jobQueue = null;
+ _sync_jobQueue.release();
+ }
+ }
+ }
+
+ /**
+ * Removes a job from the queue.
+ *
+ * @param waitTime the maximum amount of time to wait for a job.
+ * @return a job or null if timed out.
+ */
+ private Job removeJob(int waitTime) {
+ if(DEBUG) System.err.println("##### " + getClass().getName() + ".removeJob:" + jobList + " " + _threadId);
+
+ Job job = null;
+ synchronized (this) {
+ // wait max. waitTime time for a job to enter the queue
+ boolean waited = false;
+ while(jobList.isEmpty() && (waitTime == 0 || !waited)) {
+ if(_doDispose == _disposeId) {
+ _doDispose = null;
+ throw (DisposedException)
+ new DisposedException().initCause(_throwable);
+ }
+
+ // notify sync queues
+ notifyAll();
+
+ try {
+ // wait for new job
+ wait(waitTime);
+ } catch(InterruptedException interruptedException) {
+ throw new com.sun.star.uno.RuntimeException(getClass().getName() + ".removeJob - unexpected:" + interruptedException);
+ }
+
+ // signal that we have already waited once
+ waited = true;
+ }
+
+
+ if(!jobList.isEmpty()) {
+ job = jobList.remove(0);
+ _active = true;
+ }
+ }
+
+ // always wait for asynchron jobqueue to be finished !
+ if(job != null && _async_jobQueue != null) {
+ synchronized(_async_jobQueue) {
+ // wait for async queue to be empty and last job to be done
+ while(_async_jobQueue._active || !_async_jobQueue.jobList.isEmpty()) {
+ if(DEBUG) System.err.println("waiting for async:" + _async_jobQueue.jobList + " " + _async_jobQueue._worker_thread);
+
+ if(_doDispose == _disposeId) {
+ _doDispose = null;
+ throw (DisposedException)
+ new DisposedException().initCause(_throwable);
+ }
+
+ try {
+ _async_jobQueue.wait();
+ } catch(InterruptedException interruptedException) {
+ throw new com.sun.star.uno.RuntimeException(getClass().getName() + ".removeJob - unexpected:" + interruptedException);
+ }
+ }
+ }
+ }
+
+ return job;
+ }
+
+ /**
+ * Puts a job into the queue.
+ *
+ * @param job the job.
+ * @param disposeId a dispose id.
+ */
+ synchronized void putJob(Job job, Object disposeId) {
+ if(DEBUG) System.err.println("##### " + getClass().getName() + ".putJob todoes: " + " job:" + job);
+
+ jobList.add(job);
+
+ if(_worker_thread == null && _createThread && _createThread_now) { // if there is no thread, which dispatches and if shall create one, create one
+
+ acquire();
+
+ _createThread_now = false;
+ new JobDispatcher(disposeId).start();
+ }
+
+ // always notify possible waiters
+ notifyAll();
+ }
+
+ /**
+ * Enters the job queue.
+ *
+ * @param disposeId a dispose id.
+ * @return the result of the final job (reply).
+ */
+ Object enter(Object disposeId) throws Throwable {
+ return enter(0, disposeId); // wait infinitely
+ }
+
+ /**
+ * Enters the job queue.
+ *
+ * @param waitTime the maximum amount of time to wait for a job (0 means wait infinitely).
+ * @param disposeId a dispose id.
+ * @return the result of the final job (reply).
+ */
+ Object enter(int waitTime, Object disposeId) throws Throwable {
+ if(DEBUG) System.err.println("#####" + getClass().getName() + ".enter: " + _threadId);
+
+ boolean quit = false;
+
+ Object hold_disposeId = _disposeId;
+ _disposeId = disposeId;
+
+ Object result = null;
+
+ Thread hold_worker_thread = _worker_thread;
+ _worker_thread = Thread.currentThread();
+
+ while(!quit) {
+ Job job = null;
+
+ try {
+ job = removeJob(waitTime);
+
+ if(job != null) {
+ try {
+ result = job.execute();
+ }
+ finally {
+ _active = false;
+ }
+
+ if (!job.isRequest()) {
+ job.dispose();
+
+ quit = true;
+ }
+
+ job = null;
+ }
+ else
+ quit = true;
+
+
+ }
+ finally { // ensure that this queue becomes disposed, if necessary
+ if(DEBUG) System.err.println("##### " + getClass().getName() + ".enter leaving: " + _threadId + " " + _worker_thread + " " + hold_worker_thread + " " + result);
+
+ synchronized(this) {
+ if(job != null || (quit && jobList.isEmpty())) {
+ _worker_thread = hold_worker_thread;
+
+ _createThread_now = true;
+
+ _disposeId = hold_disposeId;
+
+ if(_sync_jobQueue != null)
+ notifyAll(); // notify waiters (e.g. this is an asyncQueue and there is a sync waiting)
+ }
+ else
+ quit = false;
+
+ }
+ }
+ }
+
+ return result;
+ }
+
+ /**
+ * If the given disposeId is registered, interrupts the worker thread.
+ *
+ * @param disposeId the dispose id.
+ */
+ synchronized void dispose(Object disposeId, Throwable throwable) {
+ if(_sync_jobQueue == null) { // dispose only sync queues
+ _doDispose = disposeId;
+ _throwable = throwable;
+
+ // get thread out of wait and let it throw the throwable
+ if(DEBUG) System.err.println(getClass().getName() + ".dispose - notifying thread");
+
+ notifyAll();
+ }
+ }
+}
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/ridljar/com/sun/star/lib/uno/environments/remote/Message.java b/ridljar/com/sun/star/lib/uno/environments/remote/Message.java
new file mode 100644
index 0000000000..b34295ae33
--- /dev/null
+++ b/ridljar/com/sun/star/lib/uno/environments/remote/Message.java
@@ -0,0 +1,189 @@
+/* -*- Mode: Java; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
+/*
+ * 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 com.sun.star.lib.uno.environments.remote;
+
+import com.sun.star.lib.uno.typedesc.MethodDescription;
+import com.sun.star.lib.uno.typedesc.TypeDescription;
+import com.sun.star.uno.XCurrentContext;
+
+/**
+ * A remote request or reply message.
+ */
+public class Message {
+ public Message(
+ ThreadId threadId, boolean request, String objectId,
+ TypeDescription type, MethodDescription method, boolean synchronous,
+ XCurrentContext currentContext, boolean abnormalTermination,
+ Object result, Object[] arguments)
+ {
+ this.threadId = threadId;
+ this.request = request;
+ this.objectId = objectId;
+ this.type = type;
+ this.method = method;
+ this.synchronous = synchronous;
+ this.currentContext = currentContext;
+ this.abnormalTermination = abnormalTermination;
+ this.result = result;
+ this.arguments = arguments;
+ }
+
+ /**
+ * Returns the thread ID of the message.
+ *
+ * <p>Valid for all kinds of messages.</p>
+ *
+ * @return the (non-<code>null</code>) thread ID.
+ */
+ public final ThreadId getThreadId() {
+ return threadId;
+ }
+
+ /**
+ * Returns whether the message is a request or a reply.
+ *
+ * <p>Valid for all kinds of messages.</p>
+ *
+ * @return <code>true</code> for a request, <code>false</code> for a reply.
+ */
+ public final boolean isRequest() {
+ return request;
+ }
+
+ /**
+ * Returns the object ID of a request message.
+ *
+ * <p>Valid only for request messages.</p>
+ *
+ * @return the (non-<code>null</code>) object ID for a request,
+ * <code>null</code> for a reply.
+ */
+ public final String getObjectId() {
+ return objectId;
+ }
+
+ /**
+ * Returns the type of a request message.
+ *
+ * <p>Valid only for request messages.</p>
+ *
+ * @return the (non-<code>null</code>) type for a request, <code>null</code>
+ * for a reply.
+ */
+ public final TypeDescription getType() {
+ return type;
+ }
+
+ /**
+ * Returns the method description of a request message.
+ *
+ * <p>Valid only for request messages. The returned
+ * <code>MethodDescription</code> is consistent with the type of the
+ * message.</p>
+ *
+ * @return the (non-<code>null</code>) method description for a request,
+ * <code>null</code> for a reply.
+ */
+ public final MethodDescription getMethod() {
+ return method;
+ }
+
+ /**
+ * Returns whether the request message is synchronous.
+ *
+ * <p>Valid only for request messages.</p>
+ *
+ * @return <code>true</code> for a synchronous request, <code>false</code>
+ * for an asynchronous request or a reply.
+ */
+ public final boolean isSynchronous() {
+ return synchronous;
+ }
+
+ /**
+ * Returns the current context of a request message.
+ *
+ * <p>Valid only for request messages.</p>
+ *
+ * @return the current context (which may be <code>null</code>) for a
+ * request, <code>null</code> for a reply.
+ */
+ public XCurrentContext getCurrentContext() {
+ return currentContext;
+ }
+
+ /**
+ * Returns whether the reply message represents abnormal termination.
+ *
+ * <p>Valid only for reply messages.</p>
+ *
+ * @return <code>true</code> for a reply that represents abnormal
+ * termination, <code>false</code> for a reply that represents normal
+ * termination or a request.
+ */
+ public final boolean isAbnormalTermination() {
+ return abnormalTermination;
+ }
+
+ /**
+ * Returns the result of a reply message.
+ *
+ * <p>Valid only for reply messages.</p>
+ *
+ * @return any (possibly <code>null</code>) return value for a reply that
+ * represents normal termination, the (non-<code>null</code>) exception for
+ * a reply that represents abnormal termination, <code>null</code> for a
+ * request.
+ */
+ public final Object getResult() {
+ return result;
+ }
+
+ /**
+ * Returns the arguments of a message.
+ *
+ * <p>Valid only for request messages and reply messages that represent
+ * normal termination. Any returned array must not be modified.</p>
+ *
+ * @return the in and in&ndash; {
+ * }out arguments for a request (possibly
+ * <code>null</code> for a parameterless function), the out and in&ndash; {
+ * }out
+ * arguments for a reply that represents normal termination (possibly
+ * <code>null</code> for a parameterless function), <code>null</code> for a
+ * reply that represents abnormal termination.
+ */
+ public final Object[] getArguments() {
+ return arguments;
+ }
+
+ private final ThreadId threadId;
+ private final boolean request;
+ private final String objectId;
+ private final TypeDescription type;
+ private final MethodDescription method;
+ private final boolean synchronous;
+ private final XCurrentContext currentContext;
+ private final boolean abnormalTermination;
+ private final Object result;
+ private final Object[] arguments;
+}
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/ridljar/com/sun/star/lib/uno/environments/remote/NativeThreadPool.java b/ridljar/com/sun/star/lib/uno/environments/remote/NativeThreadPool.java
new file mode 100644
index 0000000000..f77bbb466d
--- /dev/null
+++ b/ridljar/com/sun/star/lib/uno/environments/remote/NativeThreadPool.java
@@ -0,0 +1,94 @@
+/* -*- Mode: Java; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
+/*
+ * 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 com.sun.star.lib.uno.environments.remote;
+
+final class NativeThreadPool implements IThreadPool {
+ public NativeThreadPool() {
+ pool = create();
+ }
+
+ public ThreadId getThreadId() {
+ return new ThreadId(threadId());
+ }
+
+ public void attach() {
+ attach(pool);
+ }
+
+ public Object attach(ThreadId id) {
+ attach();
+ return null;
+ }
+
+ public void detach() {
+ detach(pool);
+ }
+
+ public void detach(Object handle, ThreadId id) {
+ detach();
+ }
+
+ public Object enter() throws Throwable {
+ Job job = enter(pool);
+ if (job == null) {
+ throw dispose;
+ }
+ return job.execute();
+ }
+
+ public Object enter(Object handle, ThreadId id) throws Throwable {
+ return enter();
+ }
+
+ public void putJob(Job job) {
+ putJob(
+ pool, job.getThreadId().getBytes(), job, job.isRequest(),
+ job.isRequest() && !job.isSynchronous());
+ }
+
+ public void dispose(Throwable throwable) {
+ dispose = throwable;
+ dispose(pool);
+ }
+
+ public void destroy() {
+ destroy(pool);
+ }
+
+ // The native implementation is in
+ // bridges/source/jni_uno/nativethreadpool.cxx:
+ static {
+ System.loadLibrary("java_uno");
+ }
+ private static native byte[] threadId();
+ private static native long create();
+ private static native void attach(long pool);
+ private static native Job enter(long pool);
+ private static native void detach(long pool);
+ private static native void putJob(
+ long pool, byte[] threadId, Job job, boolean request, boolean oneWay);
+ private static native void dispose(long pool);
+ private static native void destroy(long pool);
+
+ private final long pool;
+ private volatile Throwable dispose;
+}
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/ridljar/com/sun/star/lib/uno/environments/remote/ThreadId.java b/ridljar/com/sun/star/lib/uno/environments/remote/ThreadId.java
new file mode 100644
index 0000000000..f8dacc78cc
--- /dev/null
+++ b/ridljar/com/sun/star/lib/uno/environments/remote/ThreadId.java
@@ -0,0 +1,109 @@
+/* -*- Mode: Java; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
+/*
+ * 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 com.sun.star.lib.uno.environments.remote;
+
+import java.io.UnsupportedEncodingException;
+import java.util.Arrays;
+import java.util.concurrent.atomic.AtomicLong;
+
+import com.sun.star.uno.UnoRuntime;
+
+public final class ThreadId {
+ public static ThreadId createFresh() {
+ long c = count.getAndIncrement();
+ try {
+ return new ThreadId((PREFIX + c).getBytes("UTF-8"));
+ } catch (UnsupportedEncodingException e) {
+ throw new RuntimeException("this cannot happen: " + e);
+ }
+ }
+
+ public ThreadId(byte[] id) {
+ this.id = id;
+ }
+
+ /**
+ * Indicates whether some other object is equal to this one.
+ *
+ * @param obj the reference object with which to compare.
+ * @return <code>true</code> if this object is the same as the obj argument;
+ * <code>false</code> otherwise.
+ *
+ * @see java.lang.Object#equals
+ */
+ @Override
+ public boolean equals(Object obj) {
+ return obj instanceof ThreadId
+ && Arrays.equals(id, ((ThreadId) obj).id);
+ }
+
+ /**
+ * Returns a hash code value for the object.
+ *
+ * @return a hash code value for this object.
+ * @see java.lang.Object#hashCode
+ */
+ @Override
+ public int hashCode() {
+ int h = hash;
+ if (h == 0) {
+ // Same algorithm as java.util.List.hashCode (also see Java 1.5
+ // java.util.Arrays.hashCode(byte[])):
+ h = 1;
+ for (int i = 0; i < id.length; ++i) {
+ h = 31 * h + id[i];
+ }
+ hash = h;
+ }
+ return h;
+ }
+
+ /**
+ * Returns a string representation of the object.
+ *
+ * @return a string representation of the object.
+ * @see java.lang.Object#toString
+ */
+ @Override
+ public String toString() {
+ StringBuffer b = new StringBuffer("[ThreadId:");
+ for (int i = 0; i < id.length; ++i) {
+ String n = Integer.toHexString(id[i] & 0xFF);
+ if (n.length() == 1) {
+ b.append('0');
+ }
+ b.append(n);
+ }
+ b.append(']');
+ return b.toString();
+ }
+
+ public byte[] getBytes() {
+ return id;
+ }
+
+ private static final String PREFIX = "java:" + UnoRuntime.getUniqueKey() + ":";
+ private static final AtomicLong count = new AtomicLong(0);
+
+ private final byte[] id;
+ private int hash = 0;
+}
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/ridljar/com/sun/star/lib/uno/environments/remote/ThreadPoolManager.java b/ridljar/com/sun/star/lib/uno/environments/remote/ThreadPoolManager.java
new file mode 100644
index 0000000000..2014f51674
--- /dev/null
+++ b/ridljar/com/sun/star/lib/uno/environments/remote/ThreadPoolManager.java
@@ -0,0 +1,74 @@
+/* -*- Mode: Java; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
+/*
+ * 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 com.sun.star.lib.uno.environments.remote;
+
+/**
+ * Manages the UNO thread pool factory.
+ *
+ * <P>The thread pool factory is a process-wide resource. It is important that
+ * all UNO environments within a process share the same thread pool mechanisms:
+ * if a synchronous UNO call is bridged out from one local UNO environment over
+ * one remote bridge, and recursively calls back into another local UNO
+ * environment over another remote bridge, the code in the second environment
+ * should be executed in the thread that did the original call from the first
+ * environment.</P>
+ *
+ * <P>There are both a Java and a native thread pool factory. A pure Java
+ * process will always use the Java thread pool factory. A mixed process uses
+ * the system property <CODE>org.openoffice.native</CODE> (to be set by the
+ * native code that starts the JVM) to determine which implementation
+ * to use.</P>
+ */
+public final class ThreadPoolManager {
+ /**
+ * Creates a thread pool instance.
+ *
+ * @return a new thread pool instance; will never be <CODE>null</CODE>.
+ */
+ public static synchronized IThreadPool create() {
+ if (useNative) {
+ return new NativeThreadPool();
+ } else {
+ if (javaFactory == null) {
+ javaFactory = new JavaThreadPoolFactory();
+ }
+ return javaFactory.createThreadPool();
+ }
+ }
+
+ /**
+ * Leads to using the native thread pool factory, unless a Java thread pool
+ * has already been created.
+ *
+ * @return <CODE>false</CODE> if a Java thread pool has already been created.
+ */
+ public static synchronized boolean useNative() {
+ useNative = javaFactory == null;
+ return useNative;
+ }
+
+ private static boolean useNative
+ = System.getProperty("org.openoffice.native") != null;
+ private static JavaThreadPoolFactory javaFactory = null;
+
+ private ThreadPoolManager() {} // do not instantiate
+}
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/ridljar/com/sun/star/lib/uno/environments/remote/remote_environment.java b/ridljar/com/sun/star/lib/uno/environments/remote/remote_environment.java
new file mode 100644
index 0000000000..09259c8cb0
--- /dev/null
+++ b/ridljar/com/sun/star/lib/uno/environments/remote/remote_environment.java
@@ -0,0 +1,66 @@
+/* -*- Mode: Java; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
+/*
+ * 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 com.sun.star.lib.uno.environments.remote;
+
+import com.sun.star.uno.IEnvironment;
+import com.sun.star.uno.Type;
+
+public final class remote_environment implements IEnvironment {
+ public remote_environment(Object context) {
+ this.context = context;
+ }
+
+ public Object getContext() {
+ return context;
+ }
+
+ public String getName() {
+ return "remote";
+ }
+
+ public Object registerInterface(Object object, String[] oid, Type type) {
+ throw new UnsupportedOperationException(
+ "java_remote environment is not functional");
+ }
+
+ public void revokeInterface(String oid, Type type) {
+ throw new UnsupportedOperationException(
+ "java_remote environment is not functional");
+ }
+
+ public Object getRegisteredInterface(String oid, Type type) {
+ throw new UnsupportedOperationException(
+ "java_remote environment is not functional");
+ }
+
+ public String getRegisteredObjectIdentifier(Object object) {
+ throw new UnsupportedOperationException(
+ "java_remote environment is not functional");
+ }
+
+ public void list() {
+ throw new UnsupportedOperationException(
+ "java_remote environment is not functional");
+ }
+
+ private final Object context;
+}
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/ridljar/com/sun/star/lib/uno/helper/ComponentBase.java b/ridljar/com/sun/star/lib/uno/helper/ComponentBase.java
new file mode 100644
index 0000000000..d886ef7020
--- /dev/null
+++ b/ridljar/com/sun/star/lib/uno/helper/ComponentBase.java
@@ -0,0 +1,136 @@
+/*
+ * 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 com.sun.star.lib.uno.helper;
+import com.sun.star.lang.XComponent;
+import com.sun.star.lang.XEventListener;
+import com.sun.star.lang.EventObject;
+import com.sun.star.uno.Type;
+
+/** This class can be used as the base class for UNO components. In addition to the functionality ,which
+ * is inherited from WeakBase, it implements com.sun.star.lang.XComponent.
+ */
+public class ComponentBase extends WeakBase implements XComponent
+{
+ private static final boolean DEBUG= false;
+ protected MultiTypeInterfaceContainer listenerContainer;
+ protected boolean bInDispose= false;
+ protected boolean bDisposed= false;
+ static final Type EVT_LISTENER_TYPE= new Type(XEventListener.class);
+
+
+ /** Creates a new instance of CompBase */
+ public ComponentBase()
+ {
+ super();
+ listenerContainer= new MultiTypeInterfaceContainer();
+ }
+
+ /** Override to perform extra clean-up work. Provided for subclasses. It is
+ called during dispose()
+ */
+ protected void preDisposing()
+ {
+ }
+ /** Override to become notified right before the disposing action is performed.
+ */
+ protected void postDisposing()
+ {
+ }
+
+
+ /** Method of XComponent. It is called by the owning client when the component is not needed
+ * anymore. The registered listeners are notified that this method has been called.
+ */
+ public void dispose()
+ {
+ // Determine in a thread-safe way if this is the first call to this method.
+ // Only then we proceed with the notification of event listeners.
+ // It is an error to call this method more than once.
+ boolean bDoDispose= false;
+ synchronized (this)
+ {
+ if ( ! bInDispose && ! bDisposed)
+ {
+ bDoDispose= true;
+ bInDispose= true;
+ }
+ }
+ // The notification occurs in an unsynchronized block in order to avoid
+ // deadlocks if one of the listeners calls back in a different thread on
+ // a synchronized method which uses the same object.
+ if (bDoDispose)
+ {
+ try
+ {
+ preDisposing();
+ listenerContainer.disposeAndClear(new EventObject(this));
+ //notify subclasses that disposing is in progress
+ postDisposing();
+ }
+ finally
+ {
+ // finally makes sure that the flags are set even if a RuntimeException is thrown.
+ // That ensures that this function is only called once.
+ synchronized (this)
+ {
+ bDisposed= true;
+ bInDispose= false;
+ }
+ }
+ }
+ else
+ {
+ // in a multithreaded environment, it can't be avoided, that dispose is called twice.
+ // However this condition is traced, because it MAY indicate an error.
+ if (DEBUG)
+ System.out.println("OComponentHelper::dispose() - dispose called twice" );
+ }
+ }
+
+ /** Method of XComponent.
+ */
+ public void removeEventListener(XEventListener xEventListener)
+ {
+ listenerContainer.removeInterface( EVT_LISTENER_TYPE, xEventListener);
+ }
+
+ public void addEventListener(XEventListener listener)
+ {
+ boolean bDoDispose= false;
+ synchronized (this)
+ {
+ if (bDisposed || bInDispose)
+ bDoDispose= true;
+ else
+ listenerContainer.addInterface(EVT_LISTENER_TYPE, listener);
+ }
+ if (bDoDispose )
+ {
+ listener.disposing( new EventObject(this));
+ }
+ }
+
+ @Override
+ protected void finalize() throws Throwable
+ {
+ if ( ! bInDispose && ! bDisposed)
+ dispose();
+ super.finalize();
+ }
+}
diff --git a/ridljar/com/sun/star/lib/uno/helper/Factory.java b/ridljar/com/sun/star/lib/uno/helper/Factory.java
new file mode 100644
index 0000000000..056d9549d5
--- /dev/null
+++ b/ridljar/com/sun/star/lib/uno/helper/Factory.java
@@ -0,0 +1,291 @@
+/*
+ * 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 com.sun.star.lib.uno.helper;
+
+import com.sun.star.uno.XComponentContext;
+import com.sun.star.lang.XSingleComponentFactory;
+import com.sun.star.lang.XServiceInfo;
+import com.sun.star.lang.XInitialization;
+import com.sun.star.registry.XRegistryKey;
+import com.sun.star.uno.UnoRuntime;
+
+
+/** Factory helper class supporting com.sun.star.lang.XServiceInfo and
+ com.sun.star.lang.XSingleComponentFactory.
+
+ <p>
+ Note: This factory implementation does not support lang.XSingleServiceFactory.
+ </p>
+*/
+public class Factory
+ extends ComponentBase
+ implements XSingleComponentFactory, XServiceInfo
+{
+ private static final boolean DEBUG = false;
+
+ /** Creates an object factory supporting interfaces
+ com.sun.star.lang.XSingleComponentFactory and
+ com.sun.star.lang.XServiceInfo
+
+ @param impl_class
+ implementation class
+ @param impl_name
+ implementation name
+ @param supported_services
+ services implemented
+ @return
+ object factory
+
+ @since UDK 3.2.13
+ */
+ public static XSingleComponentFactory createComponentFactory(
+ Class impl_class, String impl_name, String supported_services [] )
+ throws com.sun.star.uno.RuntimeException
+ {
+ return new Factory( impl_class, impl_name, supported_services );
+ }
+
+ /** Creates an object factory supporting interfaces
+ com.sun.star.lang.XSingleComponentFactory and
+ com.sun.star.lang.XServiceInfo
+
+ The implementation name is the name of the implementation class.
+
+ @param impl_class
+ implementation class
+ @param supported_services
+ services implemented
+ @return
+ object factory
+ */
+ public static XSingleComponentFactory createComponentFactory(
+ Class impl_class, String supported_services [] )
+ throws com.sun.star.uno.RuntimeException
+ {
+ return createComponentFactory(
+ impl_class, impl_class.getName(), supported_services );
+ }
+ /** Writes component's implementation info to given registry key.
+
+ @param impl_name
+ name of implementation
+ @param supported_services
+ supported services of implementation
+ @param xKey
+ registry key to write to
+ @return
+ success
+ */
+ public static boolean writeRegistryServiceInfo(
+ String impl_name, String supported_services [], XRegistryKey xKey )
+ {
+ try
+ {
+ XRegistryKey xNewKey = xKey.createKey( "/" + impl_name + "/UNO/SERVICES" );
+ for ( int nPos = 0; nPos < supported_services.length; ++nPos )
+ {
+ xNewKey.createKey( supported_services[ nPos ] );
+ }
+ return true;
+ }
+ catch (com.sun.star.registry.InvalidRegistryException exc)
+ {
+ if (DEBUG)
+ {
+ System.err.println(
+ "##### " + Factory.class.getName() + ".writeRegistryServiceInfo -- exc: " +
+ exc.toString() );
+ }
+ }
+ return false;
+ }
+
+
+ private final String m_impl_name;
+ private final String [] m_supported_services;
+ private final Class<?> m_impl_class;
+ private final java.lang.reflect.Method m_method;
+ private final java.lang.reflect.Constructor m_ctor;
+
+ private Factory(
+ Class impl_class, String impl_name, String supported_services [] )
+ throws com.sun.star.uno.DeploymentException
+ {
+ m_impl_name = impl_name;
+ m_supported_services = supported_services;
+ m_impl_class = impl_class;
+
+ Class params [] = new Class [] { XComponentContext.class };
+
+ if (!java.lang.reflect.Modifier.isPublic( impl_class.getModifiers() ))
+ {
+ throw new com.sun.star.uno.DeploymentException("class " + impl_class + " is not public");
+ }
+
+ java.lang.reflect.Method tmpMethod = null;
+ try
+ {
+ // seeking for "public static Object __create( XComponentContext )"
+ tmpMethod = m_impl_class.getMethod( "__create", params );
+ int mod = tmpMethod.getModifiers();
+ if (!tmpMethod.getReturnType().equals( Object.class ) ||
+ !java.lang.reflect.Modifier.isStatic( mod ) ||
+ !java.lang.reflect.Modifier.isPublic( mod ))
+ {
+ tmpMethod = null;
+ }
+ }
+ catch (Exception exc)
+ {
+ }
+ m_method = tmpMethod;
+
+
+ java.lang.reflect.Constructor tmpCtor = null;
+ if (null == m_method)
+ {
+ try
+ {
+ // ctor with context
+ tmpCtor = m_impl_class.getConstructor( params );
+ }
+ catch (Exception exc)
+ {
+ }
+ if (tmpCtor != null)
+ {
+ if (!java.lang.reflect.Modifier.isPublic( tmpCtor.getModifiers() ))
+ {
+ throw new com.sun.star.uno.DeploymentException("constructor with XComponentContext param for class " + impl_class + " is not public");
+ }
+ }
+ else
+ {
+ // else take default ctor
+ java.lang.reflect.Constructor defaultCtor;
+ try
+ {
+ defaultCtor = m_impl_class.getConstructor(new Class[0]);
+ }
+ catch (Exception exc2)
+ {
+ throw new com.sun.star.uno.DeploymentException(exc2, "class " + impl_class + " has no means of creating it, cannot find a __create method or a useful constructor.");
+ }
+ if (!java.lang.reflect.Modifier.isPublic( defaultCtor.getModifiers() ))
+ {
+ throw new com.sun.star.uno.DeploymentException("default constructor for class " + impl_class + " is not public");
+ }
+ }
+ }
+ m_ctor = tmpCtor;
+ }
+
+
+ private Object instantiate( XComponentContext xContext )
+ throws com.sun.star.uno.Exception
+ {
+ try
+ {
+ if (DEBUG)
+ System.out.print( "instantiating " + m_impl_class.toString() + " using " );
+ if (null != m_method)
+ {
+ if (DEBUG)
+ System.out.println( "__create( XComponentContext )..." );
+ return m_method.invoke( null, new Object [] { xContext } );
+ }
+ if (null != m_ctor)
+ {
+ if (DEBUG)
+ System.out.println( "ctor( XComponentContext )..." );
+ return m_ctor.newInstance( new Object [] { xContext } );
+ }
+ if (DEBUG)
+ System.out.println( "default ctor..." );
+ return m_impl_class.newInstance(); // default ctor
+ }
+ catch (java.lang.reflect.InvocationTargetException exc)
+ {
+ Throwable targetException = exc.getTargetException();
+ if (targetException instanceof java.lang.RuntimeException)
+ throw (java.lang.RuntimeException)targetException;
+ else if (targetException instanceof com.sun.star.uno.RuntimeException)
+ throw (com.sun.star.uno.RuntimeException)targetException;
+ else if (targetException instanceof com.sun.star.uno.Exception)
+ throw (com.sun.star.uno.Exception)targetException;
+ else
+ throw new com.sun.star.uno.Exception(targetException, targetException.getMessage(), this);
+ }
+ catch (IllegalAccessException exc)
+ {
+ throw new com.sun.star.uno.RuntimeException( exc, exc.getMessage(), this);
+ }
+ catch (InstantiationException exc)
+ {
+ throw new com.sun.star.uno.RuntimeException( exc, exc.getMessage(), this);
+ }
+ }
+ // XSingleComponentFactory impl
+
+ public final Object createInstanceWithContext(
+ XComponentContext xContext )
+ throws com.sun.star.uno.Exception
+ {
+ return instantiate( xContext );
+ }
+
+ public final Object createInstanceWithArgumentsAndContext(
+ Object arguments [], XComponentContext xContext )
+ throws com.sun.star.uno.Exception
+ {
+ Object inst = instantiate( xContext );
+ XInitialization xInit = UnoRuntime.queryInterface(
+ XInitialization.class, inst );
+ if (null == xInit)
+ {
+ throw new com.sun.star.lang.IllegalArgumentException(
+ "cannot pass arguments to component; no XInitialization implemented!", this,
+ (short)0 );
+ }
+ xInit.initialize( arguments );
+ return inst;
+ }
+
+ // XServiceInfo impl
+
+ public final String getImplementationName()
+ {
+ return m_impl_name;
+ }
+
+ public final boolean supportsService( String service_name )
+ {
+ for ( int nPos = 0; nPos < m_supported_services.length; ++nPos )
+ {
+ if (m_supported_services[ nPos ].equals( service_name ))
+ return true;
+ }
+ return false;
+ }
+
+ public final String [] getSupportedServiceNames()
+ {
+ return m_supported_services;
+ }
+}
+
diff --git a/ridljar/com/sun/star/lib/uno/helper/InterfaceContainer.java b/ridljar/com/sun/star/lib/uno/helper/InterfaceContainer.java
new file mode 100644
index 0000000000..e858ced81f
--- /dev/null
+++ b/ridljar/com/sun/star/lib/uno/helper/InterfaceContainer.java
@@ -0,0 +1,864 @@
+/*
+ * 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 com.sun.star.lib.uno.helper;
+
+import java.util.Iterator;
+import java.util.ListIterator;
+import java.util.Collection;
+
+import com.sun.star.lang.EventObject;
+import com.sun.star.lang.XEventListener;
+import com.sun.star.uno.UnoRuntime;
+
+/**
+ * This class is a container for interfaces.
+ *
+ * It is intended to be used as storage for UNO interface of a specific type.
+ * The client has to ensure that the container contains only elements of the same
+ * type. If one needs to store different types, then one uses OMultiTypeInterfaceContainer.
+ * When the client calls disposeAndClear, the contained objects are queried for
+ * com.sun.star.lang.XEventListener and disposing is called. Afterwards
+ * the list cannot be used anymore.
+ *
+ * This list does not allow null values.
+ * All methods are thread-safe. The same holds true for
+ * iterators, issued by this class. Several iterators can exist at the same time and can also
+ * be modified (java.util.ListIterator.add, java.util.ListIterator.remove etc.). To make this work,
+ * the InterfaceContainer provides the iterators with copies of the list's data.
+ * The add and remove calls on the iterator modify the data in the iterator's list as well as
+ * in InterfaceContainer. Modification on InterfaceContainer, however, are not
+ * synchronized with existing iterators. For example
+ * <pre>
+ * InterfaceContainer cont= new InterfaceContainer();
+ * ListIterator it= cont.listIterator();
+ *
+ * cont.add( someInterface);
+ * // one cannot obtain someInterface through iterator it,
+ * // instead get a new iterator
+ * it= cont.listIterator();
+ * // it now keeps a fresh copy of cont and hence contains someInterface
+ *
+ * // Adding an interface on the iterator will cause the interface also to be added
+ * // to InterfaceContainer
+ * it.add( someOtherInterface);
+ * // someOtherInterface is now in it and cont
+ * ListIterator it2= cont.listIterator();
+ * //someOtherInterface can also be obtained by all newly created iterators, e.g. it2.
+ * </pre>
+ *
+ * The add and remove methods of an iterator work on a particular location within a list,
+ * dependent on what the value of the iterator's cursor is. After the call the value at the
+ * appropriate position has been modified. Since the iterator received a copy of InterfaceContainer's
+ * data, InterfaceContainer may have been modified (by List methods or through other iterators).
+ * Therefore both data sets may not contain the same elements anymore. Consequently, a List method
+ * that modifies data, does not modify InterfaceContainer's data at a certain index
+ * (according to the iterators cursor). Instead, new elements are added at the end of list. When
+ * Iterator.remove is called, then the first occurrence of that element in InterfaceContainer
+ * is removed.
+ * ListIterator.set is not supported.
+ *
+ * A lot of methods resemble those of the to java.util.List interface, although
+ * this class does not implement it. However, the list iterators returned, for example by
+ * the listIterator method implement the java.util.ListIterator interface.
+ * Implementing the List interface would mean to support all none - optional methods as
+ * prescribed by the interface declaration. Among those is the subList method which returns
+ * a range of values of the list's data wrapped in a List implementation. Changes to the sub
+ * list have to cause changes in the main list. This is a problem, since this class is to be
+ * used in a multi-threaded environment. The sub list could work on a copy as the iterators
+ * do, but all the functions which work on a given index could not be properly supported.
+ * Unfortunately, the List interface documentation states that all optional methods implemented
+ * by the list have to be implemented in the sub list. That would mean to do without all those
+ * critical methods, although they might work well in the "main list" (as opposed to sub list).
+ */
+public class InterfaceContainer implements Cloneable
+{
+ static final boolean DEBUG= false;
+ /**
+ * The array buffer into which the elements of the ArrayList are stored.
+ * The capacity of the ArrayList is the length of this array buffer.
+ */
+ Object elementData[];
+
+ /**
+ * The size of the ArrayList (the number of elements it contains).
+ */
+ private int size;
+
+
+ /** Creates a new instance of InterfaceContainer */
+ public InterfaceContainer()
+ {
+ this(10);
+ }
+ /**
+ * Constructs an empty list with the specified initial capacity.
+ *
+ * @param initialCapacity the initial capacity of the list.
+ * @exception IllegalArgumentException if the specified initial capacity
+ * is negative
+ */
+ public InterfaceContainer(int initialCapacity)
+ {
+ if (initialCapacity < 0)
+ throw new java.lang.IllegalArgumentException("Illegal Capacity: "+
+ initialCapacity);
+ this.elementData = new Object[initialCapacity];
+ }
+
+ private InterfaceContainer(Object[] data) {
+ elementData = data;
+ size = elementData == null ? 0 : elementData.length;
+ }
+
+ /**
+ * Trims the capacity of this <code>ArrayList</code> instance to be the
+ * list's current size. An application can use this operation to minimize
+ * the storage of an <code>ArrayList</code> instance.
+ */
+ synchronized public void trimToSize()
+ {
+ int oldCapacity = elementData.length;
+ if (size < oldCapacity)
+ {
+ Object oldData[] = elementData;
+ elementData = new Object[size];
+ System.arraycopy(oldData, 0, elementData, 0, size);
+ }
+ }
+
+ /**
+ * Increases the capacity of this <code>ArrayList</code> instance, if
+ * necessary, to ensure that it can hold at least the number of elements
+ * specified by the minimum capacity argument.
+ *
+ * @param minCapacity the desired minimum capacity.
+ */
+ synchronized public void ensureCapacity(int minCapacity)
+ {
+ int oldCapacity = elementData.length;
+ if (minCapacity > oldCapacity)
+ {
+ Object oldData[] = elementData;
+ int newCapacity = (oldCapacity * 3)/2 + 1;
+ if (newCapacity < minCapacity)
+ newCapacity = minCapacity;
+ elementData = new Object[newCapacity];
+ System.arraycopy(oldData, 0, elementData, 0, size);
+ }
+ }
+
+ /**
+ * Appends the specified element to the end of this list.
+ *
+ * @param o element to be appended to this list.
+ * @return <code>true</code> (as per the general contract of Collection.add).
+ */
+ synchronized public boolean add(Object o)
+ {
+ boolean ret= false;
+ if (elementData != null && o != null)
+ {
+ ensureCapacity(size + 1); // Increments modCount!!
+ elementData[size++] = o;
+ ret= true;
+ }
+ return ret;
+ }
+
+ /**
+ * Inserts the specified element at the specified position in this
+ * list. Shifts the element currently at that position (if any) and
+ * any subsequent elements to the right (adds one to their indices).
+ *
+ * @param index index at which the specified element is to be inserted.
+ * @param element element to be inserted.
+ * @throws IndexOutOfBoundsException if index is out of range
+ * <code>(index &lt; 0 || index &gt; size())</code>.
+ */
+ synchronized public void add(int index, Object element)
+ {
+ if (elementData != null && element != null)
+ {
+ if (index > size || index < 0)
+ throw new IndexOutOfBoundsException(
+ "Index: "+index+", Size: "+size);
+
+ ensureCapacity(size+1);
+ System.arraycopy(elementData, index, elementData, index + 1,
+ size - index);
+ elementData[index] = element;
+ size++;
+ }
+ }
+
+
+ /**
+ * Appends all of the elements in the specified Collection to the end of
+ * this list, in the order that they are returned by the
+ * specified Collection's Iterator. The behavior of this operation is
+ * undefined if the specified Collection is modified while the operation
+ * is in progress. (This implies that the behavior of this call is
+ * undefined if the specified Collection is this list, and this
+ * list is nonempty.)
+ *
+ * @param c the elements to be inserted into this list.
+ * @throws IndexOutOfBoundsException if index out of range <code>(index
+ * &lt; 0 || index &gt; size())</code>.
+ * @return true if an element was inserted.
+ */
+ synchronized public boolean addAll(Collection c)
+ {
+ int numNew = c.size();
+ ensureCapacity(size + numNew);
+
+ Iterator e = c.iterator();
+ for (int i=0; i<numNew; i++)
+ {
+ Object o= e.next();
+ if (o != null)
+ elementData[size++] = o;
+ }
+ return numNew != 0;
+ }
+ /**
+ * Inserts all of the elements in the specified Collection into this
+ * list, starting at the specified position. Shifts the element
+ * currently at that position (if any) and any subsequent elements to
+ * the right (increases their indices). The new elements will appear
+ * in the list in the order that they are returned by the
+ * specified Collection's iterator.
+ *
+ * @param index index at which to insert first element
+ * from the specified collection.
+ * @param c elements to be inserted into this list.
+ * @throws IndexOutOfBoundsException if index out of range <code>(index
+ * &lt; 0 || index &gt; size())</code>.
+ * @return true if an element was inserted.
+ */
+ synchronized public boolean addAll(int index, Collection c)
+ {
+ boolean ret= false;
+ if (elementData != null)
+ {
+ if (index > size || index < 0)
+ throw new IndexOutOfBoundsException(
+ "Index: "+index+", Size: "+size);
+ // only add the non-null elements
+ int sizeCol= c.size();
+ Object[] arColl= new Object[sizeCol];
+ Iterator icol= c.iterator();
+ int curIndex= 0;
+ for (int i=0; i < sizeCol; i++)
+ {
+ Object o= icol.next();
+ if (o != null)
+ arColl[curIndex++]= o;
+ }
+ int numNew = curIndex;
+ ensureCapacity(size + numNew); // Increments modCount!!
+
+ int numMoved = size - index;
+ if (numMoved > 0)
+ System.arraycopy(elementData, index, elementData, index + numNew,
+ numMoved);
+
+ for (int i=0; i<numNew; i++)
+ {
+ elementData[index++]= arColl[i];
+ }
+ size += numNew;
+ ret= numNew != 0;
+ }
+ return ret;
+ }
+
+ /**
+ * Removes all of the elements from this list. The list will
+ * be empty after this call returns.
+ */
+ synchronized public void clear()
+ {
+ if (elementData != null)
+ {
+ // Let gc do its work
+ for (int i = 0; i < size; i++)
+ elementData[i] = null;
+
+ size = 0;
+ }
+ }
+ /**
+ * Returns <code>true</code> if this list contains the specified element.
+ *
+ * @param elem element whose presence in this List is to be tested.
+ * @return <code>true</code> if this list contains the specified element.
+ */
+ synchronized public boolean contains(Object elem)
+ {
+ return indexOf(elem) >= 0;
+ }
+
+ synchronized public boolean containsAll(Collection collection)
+ {
+ boolean retVal= true;
+ if (elementData != null && collection != null)
+ {
+ Iterator it= collection.iterator();
+ while (it.hasNext())
+ {
+ Object obj= it.next();
+ if (!contains(obj))
+ {
+ retVal= false;
+ break;
+ }
+ }
+ }
+ return retVal;
+ }
+ /**
+ * Returns the element at the specified position in this list.
+ *
+ * @param index index of element to return.
+ * @return the element at the specified position in this list.
+ * @throws IndexOutOfBoundsException if index is out of range <code>(index
+ * &lt; 0 || index &gt;= size())</code>.
+ */
+ synchronized public Object get(int index)
+ {
+ if (elementData != null)
+ {
+ RangeCheck(index);
+ return elementData[index];
+ }
+ return null;
+ }
+
+ /**
+ * Searches for the first occurrence of the given argument, testing
+ * for equality using the <code>equals</code> method.
+ *
+ * @param elem an object.
+ * @return the index of the first occurrence of the argument in this
+ * list; returns <code>-1</code> if the object is not found.
+ * @see Object#equals(Object)
+ */
+ synchronized public int indexOf(Object elem)
+ {
+ if (elementData == null || elem == null) {
+ return -1;
+ }
+
+ int index= -1;
+
+ for (int i = 0; i < size; i++)
+ {
+ if (elem == elementData[i])
+ {
+ index= i;
+ break;
+ }
+ }
+
+ if (index == -1)
+ {
+ for (int i = 0; i < size; i++)
+ {
+ if (UnoRuntime.areSame(elem, elementData[i]))
+ {
+ index= i;
+ break;
+ }
+ }
+ }
+ return index;
+ }
+ /**
+ * Tests if this list has no elements.
+ *
+ * @return <code>true</code> if this list has no elements;
+ * <code>false</code> otherwise.
+ */
+ synchronized public boolean isEmpty()
+ {
+ return size == 0;
+ }
+
+ synchronized public Iterator iterator()
+ {
+ if (elementData != null)
+ {
+ InterfaceContainer aCopy= (InterfaceContainer) clone();
+ return new Itr(aCopy);
+ }
+ return null;
+ }
+ /**
+ * Returns the index of the last occurrence of the specified object in
+ * this list.
+ *
+ * @param elem the desired element.
+ * @return the index of the last occurrence of the specified object in
+ * this list; returns -1 if the object is not found.
+ */
+ synchronized public int lastIndexOf(Object elem)
+ {
+ if (elementData == null || elem == null) {
+ return -1;
+ }
+
+ int index= -1;
+
+ for (int i = size-1; i >= 0; i--)
+ {
+ if (elem == elementData[i])
+ {
+ index= i;
+ break;
+ }
+ }
+ if (index == -1)
+ {
+ for (int i = size-1; i >= 0; i--)
+ {
+ if (UnoRuntime.areSame(elem, elementData[i]))
+ {
+ index= i;
+ break;
+ }
+ }
+ }
+ return index;
+ }
+
+ /**
+ * Returns a shallow copy of this <code>ArrayList</code> instance. The contained
+ * references are copied but the objects not.
+ *
+ * @return a clone of this <code>List</code> instance.
+ */
+ @Override
+ synchronized public Object clone()
+ {
+ Object[] data;
+ if (elementData == null) {
+ data = null;
+ } else {
+ data = new Object[size];
+ System.arraycopy(elementData, 0, data, 0, size);
+ }
+ return new InterfaceContainer(data);
+ }
+ synchronized public ListIterator listIterator()
+ {
+ return listIterator(0);
+ }
+
+ /** The iterator keeps a copy of the list. Changes to InterfaceContainer do not
+ * affect the data of the iterator. Conversely, changes to the iterator are effect
+ * InterfaceContainer.
+ * @param index the starting offset into the list.
+ * @return a new iterator.
+ */
+ synchronized public ListIterator listIterator(int index)
+ {
+ if (elementData != null)
+ {
+ InterfaceContainer aCopy= (InterfaceContainer) clone();
+ return new LstItr(aCopy, index);
+ }
+ return null;
+ }
+ /**
+ * Removes the element at the specified position in this list.
+ * Shifts any subsequent elements to the left (subtracts one from their
+ * indices).
+ *
+ * @param index the index of the element to removed.
+ * @return the element that was removed from the list.
+ * @throws IndexOutOfBoundsException if index out of range <code>(index
+ * &lt; 0 || index &gt;= size())</code>.
+ */
+ synchronized public Object remove(int index)
+ {
+ Object ret= null;
+ if (elementData != null)
+ {
+ RangeCheck(index);
+ ret= elementData[index];
+
+ int numMoved = size - index - 1;
+ if (numMoved > 0)
+ System.arraycopy(elementData, index+1, elementData, index,
+ numMoved);
+ elementData[--size] = null; // Let gc do its work
+ }
+ return ret;
+ }
+
+
+ /** Parameter obj may... or may not. What did the original author want
+ * to tell us here?
+ * @param obj the object to be removed.
+ * @return true if obj was successfully removed from the list.
+ */
+ synchronized public boolean remove(Object obj)
+ {
+ boolean ret= false;
+ if (elementData != null && obj != null)
+ {
+ int index= indexOf(obj);
+ if (index != -1)
+ {
+ ret= true;
+ remove(index);
+ }
+ }
+ return ret;
+ }
+
+ synchronized public boolean removeAll(Collection collection)
+ {
+ boolean retVal= false;
+ if (elementData != null && collection != null)
+ {
+ Iterator it= collection.iterator();
+ while (it.hasNext())
+ {
+ Object obj= it.next();
+ boolean bMod= remove( obj);
+ if (bMod)
+ retVal= true;
+ }
+ }
+ return retVal;
+ }
+
+ synchronized public boolean retainAll(Collection collection)
+ {
+ if (elementData == null || collection == null) {
+ return false;
+ }
+
+ boolean retVal= false;
+ // iterate over data
+ Object[] arRetained= new Object[size];
+ int indexRetained= 0;
+ for(int i= 0; i < size; i++)
+ {
+ Object curElem= elementData[i];
+ // try to find the element in collection
+ Iterator itColl= collection.iterator();
+ boolean bExists= false;
+ while (itColl.hasNext())
+ {
+ if (curElem == itColl.next())
+ {
+ // current element is in collection
+ bExists= true;
+ break;
+ }
+ }
+ if (!bExists)
+ {
+ itColl= collection.iterator();
+ while (itColl.hasNext())
+ {
+ Object o= itColl.next();
+ if (o != null && UnoRuntime.areSame(o, curElem))
+ {
+ bExists= true;
+ break;
+ }
+ }
+ }
+ if (bExists)
+ arRetained[indexRetained++]= curElem;
+ }
+ retVal= size != indexRetained;
+ if (indexRetained > 0)
+ {
+ elementData= arRetained;
+ size= indexRetained;
+ }
+ return retVal;
+ }
+
+
+ /** Not supported.
+ * @param index index of element to replace.
+ * @param element element to be stored at the specified position.
+ * @return the element previously at the specified position.
+ * @throws IndexOutOfBoundsException if index out of range
+ * <code>(index &lt; 0 || index &gt;= size())</code>.
+ */
+ synchronized public Object set(int index, Object element)
+ {
+ Object ret= null;
+ if (elementData != null && element != null)
+ {
+ RangeCheck(index);
+ ret = elementData[index];
+ elementData[index] = element;
+ }
+ return ret;
+ }
+
+ /**
+ * Returns the number of elements in this list.
+ *
+ * @return the number of elements in this list.
+ */
+ synchronized public int size()
+ {
+ if (elementData != null)
+ return size;
+ return 0;
+ }
+
+
+ /**
+ * Returns an array containing all of the elements in this list
+ * in the correct order.
+ *
+ * @return an array containing all of the elements in this list
+ * in the correct order.
+ */
+ synchronized public Object[] toArray()
+ {
+ if (elementData != null)
+ {
+ Object[] result = new Object[size];
+ System.arraycopy(elementData, 0, result, 0, size);
+ return result;
+ }
+ return null;
+ }
+
+ /**
+ * Returns an array containing all of the elements in this list in the
+ * correct order. The runtime type of the returned array is that of the
+ * specified array. If the list fits in the specified array, it is
+ * returned therein. Otherwise, a new array is allocated with the runtime
+ * type of the specified array and the size of this list.<p>
+ *
+ * If the list fits in the specified array with room to spare (i.e., the
+ * array has more elements than the list), the element in the array
+ * immediately following the end of the collection is set to
+ * <code>null</code>. This is useful in determining the length of the list
+ * <i>only</i> if the caller knows that the list does not contain any
+ * <code>null</code> elements.
+ *
+ * @param a the array into which the elements of the list are to
+ * be stored, if it is big enough; otherwise, a new array of the
+ * same runtime type is allocated for this purpose.
+ * @return an array containing the elements of the list.
+ * @throws ArrayStoreException if the runtime type of a is not a supertype
+ * of the runtime type of every element in this list.
+ */
+ synchronized public Object[] toArray(Object a[])
+ {
+ if (a.length < size)
+ a = (Object[])java.lang.reflect.Array.newInstance(
+ a.getClass().getComponentType(), size);
+ if (elementData != null)
+ System.arraycopy(elementData, 0, a, 0, size);
+
+ if (a.length > size)
+ a[size] = null;
+
+ return a;
+ }
+
+ /**
+ * Check if the given index is in range. If not, throw an appropriate
+ * runtime exception.
+ */
+ private void RangeCheck(int index)
+ {
+ if (index >= size || index < 0)
+ throw new IndexOutOfBoundsException(
+ "Index: "+index+", Size: "+size);
+ }
+
+ public void disposeAndClear(EventObject evt)
+ {
+ Iterator aIt;
+ synchronized (this)
+ {
+ aIt= iterator();
+ // Release containers if new entries occur in disposing;
+ // set the member to null, the iterator delete the values
+ clear();
+ elementData= null;
+ size= 0;
+ }
+ if (aIt != null)
+ {
+ while( aIt.hasNext() )
+ {
+ try
+ {
+ Object o= aIt.next();
+ XEventListener evtListener= UnoRuntime.queryInterface(
+ XEventListener.class, o);
+ if( evtListener != null )
+ evtListener.disposing( evt );
+ }
+ catch ( RuntimeException e)
+ {
+ // be robust, if e.g. a remote bridge has disposed already.
+ // there is no way, to delegate the error to the caller :o(.
+ }
+ }
+ }
+ }
+
+
+ private class Itr implements Iterator
+ {
+ InterfaceContainer dataIt;
+ /**
+ * Index of element to be returned by subsequent call to next.
+ */
+ int cursor= 0;
+ /**
+ * Index of element returned by most recent call to next or
+ * previous. Reset to -1 if this element is deleted by a call
+ * to remove.
+ */
+ int lastRet = -1;
+
+ /** The object that has been returned by most recent call to next
+ * or previous. Reset to null if this element is deleted by a call
+ * to remove.
+ */
+ Object lastRetObj= null;
+
+ Itr(InterfaceContainer _data)
+ {
+ dataIt= _data;
+ }
+
+ synchronized public boolean hasNext()
+ {
+ return cursor !=dataIt.size();
+ }
+
+ public synchronized Object next()
+ {
+ try
+ {
+ Object next = dataIt.get(cursor);
+ lastRet = cursor++;
+ lastRetObj= next;
+ return next;
+ }
+ catch(java.lang.IndexOutOfBoundsException e)
+ {
+ java.util.NoSuchElementException ex2 = new java.util.NoSuchElementException();
+ ex2.initCause(e);
+ throw ex2;
+ }
+ }
+
+ /** Removes the interface from the list, that has been last returned by a
+ * call to next(). This is done according to the specification of the interface
+ * method. The element is also removed from InterfaceContainer but independent
+ * of the location. If the element is multiple times in InterfaceContainer then
+ * it is up to the java.util.ArrayList implementation what element is removed.
+ */
+ public synchronized void remove()
+ {
+ if (lastRet == -1)
+ throw new IllegalStateException();
+ // Remove the entry from InterfaceContainer.
+ InterfaceContainer.this.remove(lastRetObj);
+ dataIt.remove(lastRet);
+
+ if (lastRet < cursor)
+ cursor--;
+ lastRet = -1;
+ lastRetObj= null;
+ }
+ }
+
+ private class LstItr extends Itr implements ListIterator
+ {
+
+ LstItr(InterfaceContainer _data, int _index)
+ {
+ super(_data);
+ cursor= _index;
+ }
+
+ /** Inserts an element to the iterators list according to the specification
+ * of this interface method. The element is also added to InterfaceContainer
+ * but its location within the list cannot be guaranteed.
+ */
+ public synchronized void add(Object o)
+ {
+ InterfaceContainer.this.add(o);
+ dataIt.add(cursor++, o);
+ lastRet = -1;
+ lastRetObj= null;
+ }
+
+ synchronized public boolean hasPrevious()
+ {
+ return cursor != 0;
+ }
+
+ synchronized public int nextIndex()
+ {
+ return cursor;
+ }
+
+ public synchronized Object previous()
+ {
+ try
+ {
+ Object previous = dataIt.get(--cursor);
+ lastRet = cursor;
+ lastRetObj= previous;
+ return previous;
+ } catch(IndexOutOfBoundsException e)
+ {
+ java.util.NoSuchElementException ex2 = new java.util.NoSuchElementException();
+ ex2.initCause(e);
+ throw ex2;
+ }
+ }
+
+ synchronized public int previousIndex()
+ {
+ return cursor-1;
+ }
+
+ /** This is not possible since several iterators can modify InterfaceContainer
+ */
+ public synchronized void set(Object o)
+ {
+ throw new UnsupportedOperationException();
+ }
+
+
+ } // class LstItr
+}
+
diff --git a/ridljar/com/sun/star/lib/uno/helper/MultiTypeInterfaceContainer.java b/ridljar/com/sun/star/lib/uno/helper/MultiTypeInterfaceContainer.java
new file mode 100644
index 0000000000..9b061f81c2
--- /dev/null
+++ b/ridljar/com/sun/star/lib/uno/helper/MultiTypeInterfaceContainer.java
@@ -0,0 +1,155 @@
+/*
+ * 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 com.sun.star.lib.uno.helper;
+import com.sun.star.uno.Type;
+import com.sun.star.lang.EventObject;
+import java.util.HashMap;
+import java.util.Map;
+import java.util.Iterator;
+
+public class MultiTypeInterfaceContainer
+{
+
+ private final Map<Object,InterfaceContainer> map= new HashMap<Object,InterfaceContainer>();
+
+ /** only returns types which have at least one value in InterfaceContainer
+ * return value can contain an element null, if someone called
+ * addInterface (null, interf)
+ * @return an array of types in this container.
+ */
+ synchronized public Type[] getContainedTypes()
+ {
+ int size;
+ Type[] retVal= null;
+
+ if ( (size=map.size()) > 0)
+ {
+ Type [] arTypes= new Type[size];
+
+ int countTypes= 0;
+ for (Map.Entry<Object,InterfaceContainer> entry : map.entrySet())
+ {
+ InterfaceContainer cont= entry.getValue();
+ if (cont != null && cont.size() > 0)
+ {
+ Object key = entry.getKey();
+ if (key == null)
+ arTypes[countTypes++]= new Type();
+ else if (key instanceof Type)
+ arTypes[countTypes++]= (Type) key;
+ else if (key instanceof Class)
+ arTypes[countTypes++]= new Type((Class) key);
+ else
+ arTypes[countTypes++]= new Type(key.getClass());
+ }
+ }
+
+ if (countTypes != size)
+ {
+ retVal= new Type[countTypes];
+ System.arraycopy(arTypes, 0, retVal, 0, countTypes);
+ }
+ else
+ retVal= arTypes;
+ }
+ if (retVal == null)
+ retVal= new Type[0];
+ return retVal;
+ }
+
+ /** param key can be null
+ * @param key the object for which the container should be retrieved.
+ * @return the container that contains the object key, if any.
+ */
+ synchronized public InterfaceContainer getContainer(Object key)
+ {
+ InterfaceContainer retVal= null;
+ for (Map.Entry<Object,InterfaceContainer> entry : map.entrySet())
+ {
+ Object obj= entry.getKey();
+ if (obj == null && key == null)
+ {
+ retVal= map.get(null);
+ break;
+ }
+ else if( obj != null && obj.equals(key))
+ {
+ retVal= entry.getValue();
+ break;
+ }
+ }
+ return retVal;
+ }
+
+
+ synchronized public int addInterface(Object ckey, Object iface)
+ {
+ //If the key is a Type then it does not matter if the objects are different
+ // if they represent the same type. This is because Types overrides hashCode and
+ // equals. For example:
+ // Type a= new Type(XInterface.class);
+ // Type b= new Type(XInterface.class);
+ // Although a != b , the map interprets both as being the same.
+ InterfaceContainer cont= map.get(ckey);
+ if (cont != null)
+ {
+ cont.add(iface);
+ }
+ else
+ {
+ cont= new InterfaceContainer();
+ cont.add(iface);
+ map.put(ckey, cont);
+ }
+ return cont.size();
+ }
+
+
+ synchronized public int removeInterface(Object key, Object iface)
+ {
+ int retVal= 0;
+ InterfaceContainer cont= map.get(key);
+ if (cont != null)
+ {
+ cont.remove(iface);
+ retVal= cont.size();
+ }
+ return retVal;
+ }
+
+ public void disposeAndClear(EventObject evt)
+ {
+ Iterator<InterfaceContainer> it= null;
+ synchronized(this)
+ {
+ it= map.values().iterator();
+ }
+ while (it.hasNext() ) {
+ it.next().disposeAndClear(evt);
+ }
+ }
+
+ synchronized public void clear()
+ {
+ Iterator<InterfaceContainer> it= map.values().iterator();
+ while (it.hasNext()) {
+ it.next().clear();
+ }
+ }
+}
diff --git a/ridljar/com/sun/star/lib/uno/helper/PropertySet.java b/ridljar/com/sun/star/lib/uno/helper/PropertySet.java
new file mode 100644
index 0000000000..dec51b9b08
--- /dev/null
+++ b/ridljar/com/sun/star/lib/uno/helper/PropertySet.java
@@ -0,0 +1,1103 @@
+/*
+ * 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 com.sun.star.lib.uno.helper;
+
+import com.sun.star.uno.Type;
+import com.sun.star.lang.EventObject;
+import com.sun.star.lang.WrappedTargetException;
+import com.sun.star.uno.TypeClass;
+import com.sun.star.uno.AnyConverter;
+import com.sun.star.uno.XInterface;
+import com.sun.star.uno.Any;
+import com.sun.star.uno.UnoRuntime;
+import com.sun.star.beans.XPropertyChangeListener;
+import com.sun.star.beans.XVetoableChangeListener;
+import com.sun.star.beans.PropertyChangeEvent;
+import com.sun.star.beans.XPropertySet;
+import com.sun.star.beans.Property;
+import com.sun.star.beans.PropertyAttribute;
+import com.sun.star.beans.UnknownPropertyException;
+import com.sun.star.beans.XPropertiesChangeListener;
+import com.sun.star.beans.XPropertySetInfo;
+import com.sun.star.beans.XFastPropertySet;
+import com.sun.star.beans.PropertyVetoException;
+import com.sun.star.beans.XMultiPropertySet;
+import java.util.Iterator;
+import java.util.Collection;
+import java.util.HashMap;
+import java.lang.reflect.Field;
+import com.sun.star.lang.DisposedException;
+
+
+/** This class is an implementation of the interfaces com.sun.star.beans.XPropertySet,
+ * com.sun.star.beans.XFastPropertySet and com.sun.star.beans.XMultiPropertySet. This
+ * class has to be inherited to be used. The values of properties are stored in member
+ * variables of the inheriting class. By overriding the methods
+ * {@link #convertPropertyValue convertPropertyValue},
+ * {@link #setPropertyValueNoBroadcast setPropertyValueNoBroadcast} and
+ * {@link #getPropertyValue(Property)} one can determine how
+ * property values are stored.
+ * When using the supplied implementations of this class then the member variables which
+ * hold property values have to be declared in the class which inherits last in the inheriting
+ * chain and they have to be public<p>
+ * Properties have to be registered by one of the registerProperty methods. They take among other
+ * arguments an Object named <em>id</em> which has to be a String that represents the name of
+ * the member variable. The registering has to occur in the constructor of the inheriting class.
+ * It is no allowed to add or change properties later on.<p>
+ * Example:
+ * <pre>
+ * public class Foo extends PropertySet
+ * {
+ * protected int intProp;
+ *
+ * public Foo()
+ * {
+ * registerProperty("PropertyA", 0, new Type(int.class), (short)0, "intProp");
+ * }
+ * }
+ *
+ * </pre>
+ */
+public class PropertySet extends ComponentBase implements XPropertySet, XFastPropertySet,
+XMultiPropertySet
+{
+ private HashMap<String,Property> _nameToPropertyMap;
+ private HashMap<Integer,Property> _handleToPropertyMap;
+ private HashMap<Property,Object> _propertyToIdMap;
+ private Property[] arProperties;
+
+ private int lastHandle= 1;
+
+ protected XPropertySetInfo propertySetInfo;
+ protected MultiTypeInterfaceContainer aBoundLC= new MultiTypeInterfaceContainer();
+ protected MultiTypeInterfaceContainer aVetoableLC= new MultiTypeInterfaceContainer();
+ public PropertySet()
+ {
+ super();
+ initMappings();
+ }
+
+ /** Registers a property with this helper class and associates the argument <em>id</em> with it.
+ * <em>id</em> is used to identify the storage of the property value. How property values are stored
+ * and retrieved is determined by the methods {@link #convertPropertyValue convertPropertyValue},
+ * {@link #setPropertyValueNoBroadcast setPropertyValueNoBroadcast} and {@link #getPropertyValue(Property) getPropertyValue}
+ * These methods expect <em>id</em> to be a String which represents the name of a member variable
+ * which holds the property value.
+ * Only properties which are registered can be accessed. Registration has to occur during
+ * initialization of the inheriting class (i.e. within the constructor).
+ * @param prop The property to be registered.
+ * @param id Identifies the properties storage.
+ * @see #getPropertyId
+ */
+ protected void registerProperty(Property prop, Object id)
+ {
+ putProperty(prop);
+ assignPropertyId(prop, id);
+ }
+
+ /** Registers a property with this helper class and associates the argument id with it.
+ * It does the same as {@link #registerProperty(Property, Object)}. The first four
+ * arguments are used to construct a Property object.
+ * Registration has to occur during
+ * initialization of the inheriting class (i.e. within the constructor)
+ * @param name The property's name (Property.Name).
+ * @param handle The property's handle (Property.Handle).
+ * @param type The property's type (Property.Type).
+ * @param attributes The property's attributes (Property.Attributes).
+ * @param id Identifies the property's storage.
+ */
+ protected void registerProperty(String name, int handle, Type type, short attributes, Object id)
+ {
+ Property p= new Property(name, handle, type, attributes);
+ registerProperty(p, id);
+ }
+
+ /** Registers a property with this class and associates the argument id with it.
+ * It does the same as {@link #registerProperty(Property, Object)}. The first three
+ * arguments are used to construct a Property object. The value for the Property.Handle
+ * is generated and does not have to be specified here. Use this method for registering
+ * a property if you do not care about the Property's handles.
+ * Registration has to occur during
+ * initialization of the inheriting class (i.e. within the constructor).
+ * @param name The property's name (Property.Name).
+ * @param type The property's type (Property.Type).
+ * @param attributes The property's attributes (Property.Attributes).
+ * @param id Identifies the property's storage.
+ */
+ protected void registerProperty(String name, Type type, short attributes, Object id)
+ {
+ Property p= new Property(name, lastHandle++, type, attributes);
+ registerProperty(p, id);
+ }
+
+ /** Registers a property with this class. This method expects that property values
+ * are stored in member variables as is the case if the methods convertPropertyValue,
+ * setPropertyValueNoBroadcast and getPropertyValue(Property) are not overridden.
+ * It is presumed that the type of the member variable
+ * corresponds Property.Type. For example, if the TypeClass of Property.Type is to be
+ * a TypeClass.SHORT then the member must be a short or java.lang.Short.
+ * The handle for the property is generated.<br>
+ * If there is no member with the specified name or if the member has an incompatible type
+ * then a com.sun.star.uno.RuntimeException is thrown.
+ * @param propertyName The name of the property.
+ * @param memberName The name of the member variable that holds the value of the property.
+ * @param attributes The property attributes.
+ */
+ protected void registerProperty(String propertyName, String memberName, short attributes)
+ {
+ Field propField= null;
+ try
+ {
+ propField= getClass().getDeclaredField(memberName);
+ }
+ catch (NoSuchFieldException e)
+ {
+ throw new com.sun.star.uno.RuntimeException(e, "there is no member variable: " + memberName);
+ }
+ Class cl= propField.getType();
+ Type t= new Type(cl);
+ if (t.getTypeClass() != TypeClass.UNKNOWN)
+ {
+ Property p= new Property(propertyName, lastHandle++, t, attributes);
+ registerProperty(p,memberName);
+ }
+ else
+ throw new com.sun.star.uno.RuntimeException("the member has an unknown type: " + memberName);
+ }
+
+ /** Registers a property with this class.
+ * It is presumed that the name of property is equal to the name of the member variable
+ * that holds the property value.
+ * @param propertyName The name of the property and the member variable that holds the property's value.
+ * @param attributes The property attributes.
+ * @see #registerProperty(String, String, short)
+ */
+ protected void registerProperty(String propertyName, short attributes)
+ {
+ registerProperty(propertyName, propertyName, attributes);
+ }
+
+
+
+ /** Returns the Property object for a given property name or null if that property does
+ * not exists (i.e. it has not been registered). Override this method
+ * if you want to implement your own mapping from property names to Property objects.
+ * Then you also have to override {@link #initMappings}, {@link #getProperties()} and
+ * {@link #putProperty(Property)}.
+ * @param propertyName The name of the property (Property.Name)
+ * @return The Property object with the name <em>propertyName</em>.
+ */
+ protected Property getProperty(String propertyName)
+ {
+ return _nameToPropertyMap.get(propertyName);
+ }
+
+ /** Returns the Property object with a handle (Property.Handle) as specified by the argument
+ * <em>nHandle</em>. The method returns null if there is no such property (i.e. it has not
+ * been registered). Override this method if you want to implement your own mapping from handles
+ * to Property objects. Then you also have to override {@link #initMappings}, {@link #putProperty(Property)}.
+ * @param nHandle The handle of the property (Property.Handle).
+ * @return The Property object with the handle <em>nHandle</em>
+ */
+ protected Property getPropertyByHandle(int nHandle)
+ {
+ return _handleToPropertyMap.get(Integer.valueOf(nHandle));
+ }
+
+ /** Returns an array of all Property objects or an array of length null if there
+ * are no properties. Override this method if you want to implement your own mapping from names
+ * to Property objects. Then you also have to override {@link #initMappings}, {@link #getProperty(String)} and
+ * {@link #putProperty}.
+ * @return Array of all Property objects.
+ */
+ protected Property[] getProperties()
+ {
+ if (arProperties == null)
+ {
+ Collection<Property> values= _nameToPropertyMap.values();
+ arProperties= values.toArray(new Property[_nameToPropertyMap.size()]);
+ }
+ return arProperties;
+ }
+
+ /** Stores a Property object so that it can be retrieved subsequently by
+ * {@link #getProperty(String)},{@link #getProperties()},{@link #getPropertyByHandle(int)}.
+ * Override this method if you want to implement your own mapping from handles
+ * to Property objects and names to Property objects. Then you also need to override {@link #initMappings},
+ * {@link #getProperty(String)},{@link #getProperties()},{@link #getPropertyByHandle(int)}.
+ * @param prop The Property object that is to be stored.
+ */
+ protected void putProperty(Property prop)
+ {
+ _nameToPropertyMap.put(prop.Name, prop);
+ if (prop.Handle != -1)
+ _handleToPropertyMap.put(Integer.valueOf(prop.Handle), prop);
+ }
+
+ /** Assigns an identifier object to a Property object so that the identifier
+ * can be obtained by {@link #getPropertyId getPropertyId} later on. The identifier
+ * is used to specify a certain storage for the property's value. If you do not
+ * override {@link #setPropertyValueNoBroadcast setPropertyValueNoBroadcast} or {@link #getPropertyValue(Property)}
+ * then the argument <em>id</em> has to be a String that equals the name of
+ * the member variable that holds the Property's value.
+ * Override this method if you want to implement your own mapping from Property objects to ids or
+ * if you need ids of a type other than String.
+ * Then you also need to override {@link #initMappings initMappings} and {@link #getPropertyId getPropertyId}.
+ * @param prop The Property object that is being assigned an id.
+ * @param id The object which identifies the storage used for the property's value.
+ * @see #registerProperty(Property, Object)
+ */
+ protected void assignPropertyId(Property prop, Object id)
+ {
+ if (id instanceof String && ((String) id).length() != 0)
+ _propertyToIdMap.put(prop, id);
+ }
+
+ /** Returns the identifier object for a certain Property. The object must have been
+ * previously assigned to the Property object by {@link #assignPropertyId assignPropertyId}.
+ * Override this method if you want to implement your own mapping from Property objects to ids.
+ * Then you also need to override {@link #initMappings initMappings} and {@link #assignPropertyId assignPropertyId}.
+ * @param prop The property for which the id is to be retrieved.
+ * @return The id object that identifies the storage used for the property's value.
+ * @see #registerProperty(Property, Object)
+ */
+ protected Object getPropertyId(Property prop)
+ {
+ return _propertyToIdMap.get(prop);
+ }
+
+ /** Initializes data structures used for mappings of property names to property object,
+ * property handles to property objects and property objects to id objects.
+ * Override this method if you want to implement your own mappings. Then you also need to
+ * override {@link #putProperty putProperty},{@link #getProperty getProperty}, {@link #getPropertyByHandle},
+ * {@link #assignPropertyId assignPropertyId} and {@link #getPropertyId getPropertyId}.
+ */
+ protected void initMappings()
+ {
+ _nameToPropertyMap= new HashMap<String,Property>();
+ _handleToPropertyMap= new HashMap<Integer,Property>();
+ _propertyToIdMap= new HashMap<Property,Object>();
+ }
+
+ /** Makes sure that listeners which are kept in aBoundLC (XPropertyChangeListener) and aVetoableLC
+ * (XVetoableChangeListener) receive a disposing call. Also those listeners are released.
+ */
+ @Override
+ protected void postDisposing()
+ {
+ // Create an event with this as sender
+ EventObject aEvt= new EventObject(this);
+
+ // inform all listeners to release this object
+ aBoundLC.disposeAndClear(aEvt);
+ aVetoableLC.disposeAndClear(aEvt);
+ }
+
+ //XPropertySet ----------------------------------------------------
+ synchronized public void addPropertyChangeListener(String str, XPropertyChangeListener xPropertyChangeListener)
+ throws UnknownPropertyException, WrappedTargetException
+ {
+ // only add listeners if you are not disposed
+ if (! bInDispose && ! bDisposed)
+ {
+ if (str.length() > 0)
+ {
+ Property prop= getProperty(str);
+ if (prop == null)
+ throw new UnknownPropertyException("Property " + str + " is unknown");
+
+ // Add listener for a certain property
+ if ((prop.Attributes & PropertyAttribute.BOUND) > 0)
+ aBoundLC.addInterface(str, xPropertyChangeListener);
+ else
+ //ignore silently
+ return;
+ }
+ else
+ // Add listener for all properties
+ listenerContainer.addInterface(XPropertyChangeListener.class, xPropertyChangeListener);
+ }
+ }
+ //XPropertySet ----------------------------------------------------
+ synchronized public void addVetoableChangeListener(String str, com.sun.star.beans.XVetoableChangeListener xVetoableChangeListener) throws com.sun.star.beans.UnknownPropertyException, com.sun.star.lang.WrappedTargetException
+ {
+ // only add listeners if you are not disposed
+ if (! bInDispose && ! bDisposed)
+ {
+ if (str.length() > 0)
+ {
+ Property prop= getProperty(str);
+ if (prop == null)
+ throw new UnknownPropertyException("Property " + str + " is unknown");
+
+ // Add listener for a certain property
+ if ((prop.Attributes & PropertyAttribute.CONSTRAINED) > 0)
+ aVetoableLC.addInterface(str, xVetoableChangeListener);
+ else
+ //ignore silently
+ return;
+ }
+ else
+ // Add listener for all properties
+ listenerContainer.addInterface(XVetoableChangeListener.class, xVetoableChangeListener);
+ }
+ }
+ //XPropertySet ----------------------------------------------------
+ public synchronized com.sun.star.beans.XPropertySetInfo getPropertySetInfo()
+ {
+ if (propertySetInfo == null)
+ propertySetInfo= new PropertySetInfo();
+ return propertySetInfo;
+ }
+ //XPropertySet ----------------------------------------------------
+ public Object getPropertyValue(String name) throws UnknownPropertyException, WrappedTargetException
+ {
+ Object ret= null;
+ if (bInDispose || bDisposed)
+ throw new com.sun.star.lang.DisposedException("The component has been disposed already");
+
+ Property prop= getProperty(name);
+ if (prop == null)
+ throw new UnknownPropertyException("The property " + name + " is unknown");
+
+ synchronized (this)
+ {
+ ret= getPropertyValue(prop);
+ }
+ // null must not be returned. Either a void any is returned or an any containing
+ // an interface type and a null reference.
+ if (ret == null)
+ {
+ if (prop.Type.getTypeClass() == TypeClass.INTERFACE)
+ ret= new Any(prop.Type, null);
+ else
+ ret= new Any(new Type(void.class), null);
+ }
+ return ret;
+ }
+
+ //XPropertySet ----------------------------------------------------
+ synchronized public void removePropertyChangeListener(String propName, XPropertyChangeListener listener) throws UnknownPropertyException, WrappedTargetException
+ { // all listeners are automatically released in a dispose call
+ if (!bInDispose && !bDisposed)
+ {
+ if (propName.length() > 0)
+ {
+ Property prop = getProperty(propName);
+ if (prop == null)
+ throw new UnknownPropertyException("Property " + propName + " is unknown");
+ aBoundLC.removeInterface(propName, listener);
+ }
+ else
+ listenerContainer.removeInterface(XPropertyChangeListener.class, listener);
+ }
+ }
+
+ //XPropertySet ----------------------------------------------------
+ synchronized public void removeVetoableChangeListener(String propName, XVetoableChangeListener listener) throws UnknownPropertyException, WrappedTargetException
+ {// all listeners are automatically released in a dispose call
+ if (!bInDispose && !bDisposed)
+ {
+ if (propName.length() > 0)
+ {
+ Property prop = getProperty(propName);
+ if (prop == null)
+ throw new UnknownPropertyException("Property " + propName + " is unknown");
+ aVetoableLC.removeInterface(propName, listener);
+ }
+ else
+ listenerContainer.removeInterface(XVetoableChangeListener.class, listener);
+ }
+ }
+
+ //XPropertySet ----------------------------------------------------
+ /** Sets the value of a property.
+ * The idl description for this interfaces, stipulates that the argument value is an Any. Since a java.lang.Object
+ * reference has the same meaning as an Any this function accepts
+ * java anys (com.sun.star.uno.Any) and all other appropriate objects as arguments. The value argument can be one
+ * of these:
+ * <ul>
+ * <li>java.lang.Boolean</li>
+ * <li>java.lang.Character</li>
+ * <li>java.lang.Byte</li>
+ * <li>java.lang.Short</li>
+ * <li>java.lang.Integer</li>
+ * <li>java.lang.Long</li>
+ * <li>java.lang.Float</li>
+ * <li>java.lang.Double</li>
+ * <li>String</li>
+ * <li>com.sun.star.uno.Type</li>
+ * <li><em>objects which implement UNO interfaces</em></li>
+ * <li><em>arrays which contain elements of the types above</em></li>
+ * <li>com.sun.star.uno.Any containing an instance of one of the above types</li>
+ * </ul>
+ *
+ * Properties can have the attribute com.sun.star.beans.PropertyAttribute.MAYBEVOID, which means that the value
+ * (not the type) can be void. In order to assign a void value to a property one can either pass an Any which
+ * contains a null reference or pass null directly. In both cases the null reference is only accepted if
+ * the PropertyAttribute.MAYBEVOID attribute is set for the property.
+ *
+ * Properties which have the attribute MAYBEVOID set (Property.Attributes) can have a void value. The following
+ * considerations presume that the Property has that attribute set. Further, when mentioning an Any's value we
+ * actually refer to the object returned by Any.getObject.
+ * If the argument <em>value</em> is null, or it is an Any whose value is null (but with a valid Type)
+ * then the member variable used for storing the property's value is set to null.
+ * Therefore those properties can only be stored in objects
+ * and primitive types are not allowed (one can use the wrapper classes instead,e.g. java.lang.Byte) .
+ * If a property's value is kept in a member variable of type Any and that reference is still null
+ * then when setPropertyValue is called with
+ * <em>value</em> = null then the member variable is assigned an Any with type void and a null value.
+ * Or if the argument is an Any with a null value then it is assigned to the member variable.
+ * Further, if the variable already
+ * references an Any and setPropertyValue is called with <em>value</em> = null, then the variable is assigned
+ * a new Any with the same type as the previously referenced Any and with a null value.
+ * @param name The name of the property.
+ * @param value The new value of the property.
+ * * */
+ public void setPropertyValue(String name, Object value) throws UnknownPropertyException,
+ PropertyVetoException, com.sun.star.lang.IllegalArgumentException, WrappedTargetException
+ {
+ Property prop= getProperty(name);
+ if (prop == null)
+ throw new UnknownPropertyException("Property " + name + " is unknown");
+ setPropertyValue(prop, value);
+ }
+
+ /** Sets the value of a property. It checks if the property's attributes (READONLY,MAYBEVOID), allow that the
+ * new value can be set. It also causes the notification of listeners.
+ * @param prop The property whose value is to be set.
+ * @param value The new value for the property.
+ *
+ * @throws UnknownPropertyException
+ * See com.sun.star.beans.XPropertySet
+ * @throws PropertyVetoException
+ * See com.sun.star.beans.XPropertySet
+ * @throws WrappedTargetException
+ * See com.sun.star.beans.XPropertySet
+ */
+ protected void setPropertyValue(Property prop, Object value) throws UnknownPropertyException,
+ PropertyVetoException, com.sun.star.lang.IllegalArgumentException, WrappedTargetException
+ {
+ if ((prop.Attributes & PropertyAttribute.READONLY) == PropertyAttribute.READONLY)
+ throw new com.sun.star.beans.PropertyVetoException();
+ // The value may be null only if MAYBEVOID attribute is set
+ boolean bVoidValue;
+ if (value instanceof Any)
+ bVoidValue= ((Any) value).getObject() == null;
+ else
+ bVoidValue= value == null;
+ if (bVoidValue && (prop.Attributes & PropertyAttribute.MAYBEVOID) == 0)
+ throw new com.sun.star.lang.IllegalArgumentException("The property must have a value; the MAYBEVOID attribute is not set!");
+ if (bInDispose || bDisposed)
+ throw new DisposedException("Component is already disposed");
+
+ //Check if the argument is allowed
+ boolean bValueOk;
+ if (value instanceof Any)
+ bValueOk= checkType(((Any) value).getObject());
+ else
+ bValueOk= checkType(value);
+ if (! bValueOk)
+ throw new com.sun.star.lang.IllegalArgumentException("No valid UNO type");
+
+
+ boolean bConversionOk= false;
+ Object[] outConvertedVal= new Object[1];
+ Object[] outOldValue= new Object[1];
+ synchronized (this)
+ {
+ bConversionOk= convertPropertyValue(prop, outConvertedVal, outOldValue, value);
+ }
+
+ //The next step following the conversion is to set the new value of the property. Prior to this
+ // the XVetoableChangeListener s have to be notified.
+ if (bConversionOk)
+ {
+ // If the property is CONSTRAINED, then we must notify XVetoableChangeListener. The listener can throw a com.sun.star.lang.beans.PropertyVetoException which
+ // will cause this method to return (the exception is not caught here).
+ fire( new Property[]{prop}, outConvertedVal, outOldValue, true);
+
+ synchronized (this)
+ {
+ setPropertyValueNoBroadcast(prop, outConvertedVal[0]);
+ }
+ // fire a change event (XPropertyChangeListener, PropertyAttribute.BOUND
+ fire( new Property[]{prop}, outConvertedVal, outOldValue, false);
+ }
+ }
+
+ /** Converts a value in a way so that it is appropriate for storing as a property value, that is
+ * {@link #setPropertyValueNoBroadcast setPropertyValueNoBroadcast} can process the value without any further
+ * conversion. This implementation presumes that
+ * the values are stored in member variables of the furthest inheriting class. For example,
+ * class A inherits this class then members of class A
+ * can hold property values. If there is a class B which inherits A then only members of B can hold
+ * property values. The variables must be public. A property must have been registered (e.g. by
+ * {@link #registerProperty(Property, Object)} in order for this method to work. The identifier argument (type Object)
+ * used in the registerProperty methods must
+ * be a String, which is, the name of the member variable that holds the property value.
+ * If one opts to store values differently then one may override
+ * this method, as well as {@link #setPropertyValueNoBroadcast setPropertyValueNoBroadcast} and
+ * {@link #getPropertyValue(Property) getPropertyValue(Property)}.
+ * This method is always called as a result of a call to one of the setter methods, such as
+ * {@link #setPropertyValue(String,Object) XPropertySet.setPropertyValue},
+ * {@link #setFastPropertyValue XFastPropertySet.setFastPropertyValue}
+ * and {@link #setPropertyValues XMultiPropertySet.setPropertyValues}.
+ * If this method fails, that is, it returns false or throws an exception, then no listeners are notified and the
+ * property value, that was intended to be changed, remains untouched.
+ *
+ * This method does not have to deal with property attributes, such as
+ * PropertyAttribute.READONLY or PropertyAttribute.MAYBEVOID. The processing of these attributes occurs
+ * in the calling methods.
+ *
+ * Only if this method returns successfully further processing, such
+ * as listener notification and finally the modification of the property's value, will occur.
+ *
+ * The actual modification of a property's value is done by {@link #setPropertyValueNoBroadcast setPropertyValueNoBroadcast}
+ * which is called subsequent to convertPropertyValue.
+ *<p>
+ * This method converts values by help of the com.sun.star.uno.AnyConverter which only does a few widening
+ * conversions on integer types and floating point types. For example, there is the property PropA with a Type equivalent
+ * to int.class and the
+ * value of the property is to be stored in a member variable of type int with name intProp. Then setPropertyValue is
+ * called:
+ * <pre>
+ * set.setPropertyValue( "PropA", Byte.valueOf( (byte)111));
+ * </pre>
+ * At some point setPropertyValue will call convertPropertyValue and pass in the Byte object. Since we allow
+ * that Byte values can be used with the property and know that the value is to be stored in intProp (type int)
+ * we convert the Byte object into an Integer object which is then returned in the out-parameter <em>newVal</em>. This
+ * conversion is actually performed by the AnyConverter. Later
+ * the setPropertyValueNoBroadcast is called with that Integer object and the int value can be easily extracted
+ * from the object and be assigned to the member intProp.
+ * <p>
+ * The method handles Any arguments the same as Object arguments. That is, the <em>setVal</em> argument can
+ * be a java.lang.Boolean or a com.sun.star.uno.Any containing a java.lang.Boolean. Likewise, a member
+ * containing a property value can be a com.sun.star.uno.Any or a java.lang.Object.
+ * Then, no conversion is necessary, since they can hold all possible values. However, if
+ * the member is an Object and <em>setVal</em> is an Any then the object contained in the any is assigned to
+ * the member. The extra type information which exists as Type object in the Any will get lost. If this is not
+ * intended then use an Any variable rather than an Object.
+ *
+ * If a member is an Object or Any and the argument <em>setVal</em> is an Object, other than String or array,
+ * then it is presumed to be a UNO object and queried for XInterface. If successful, the out-param <em>newVal</em>
+ * returns the XInterface.
+ *
+ * If a member is a UNO interface, then <em>setVal</em> is queried for this interface and the result is returned.
+ * If <em>setVal</em> is null then <em>newVal</em> will be null too after return.
+ * <p>
+ * If a property value is stored using a primitive type the out-parameters
+ * <em>curVal</em> and <em>newVal</em> contain the respective wrapper class (e.g.java.lang.Byte, etc.).
+ * curVal is used in calls to the XVetoableChangeListener and XPropertyChangeListener.
+ *
+ * @param property - in-param property for which the data is to be converted.
+ * @param newVal - out-param which contains the converted value on return.
+ * @param curVal - out-param the current value of the property. It is used in calls to the
+ * XVetoableChangeListener and XPropertyChangeListener.
+ * @param setVal - in-param. The value that is to be converted so that it matches Property and the internally used
+ * dataformat for that property.
+ * @return true - Conversion was successful. <em>newVal</em> contains a valid value for the property. false -
+ * conversion failed for some reason.
+ *
+ * @throws UnknownPropertyException
+ * See com.sun.star.beans.XPropertySet
+ * @throws com.sun.star.lang.IllegalArgumentException The value provided is unfit for the property.
+ * @throws com.sun.star.lang.WrappedTargetException - An exception occurred during the conversion, that is to be made known
+ * to the caller.
+ */
+ protected boolean convertPropertyValue(Property property, Object[] newVal, Object[]curVal, Object setVal)
+ throws com.sun.star.lang.IllegalArgumentException, WrappedTargetException, UnknownPropertyException
+ {
+ boolean ret= true;
+ try
+ {
+ // get the member name
+ String sMember= (String) getPropertyId(property);
+ if (sMember != null)
+ {
+ // use reflection to obtain the field that holds the property value
+ // Class.getDeclaredFields does not return inherited fields. One could use Class.getFields to
+ // also get inherited fields, but only those which are public.
+ Field propField= getClass().getDeclaredField(sMember);
+ if (propField != null)
+ {
+ curVal[0]= propField.get(this);
+ Class memberClass= propField.getType();
+
+ // MAYBEVOID: if setVal == null or it is an Any and getObject returns null, then a void value is to be set
+ // This works only if there are no primitive types. For those we use the respective wrapper classes.
+ // In this implementation, a null reference means void value.
+ boolean bVoidValue= false;
+ boolean bAnyVal= setVal instanceof Any;
+ if (bAnyVal)
+ bVoidValue= ((Any) setVal).getObject() == null;
+ else
+ bVoidValue= setVal == null;
+ if (bVoidValue && memberClass.isPrimitive())
+ throw new com.sun.star.lang.IllegalArgumentException("The implementation does not support the MAYBEVOID attribute for this property");
+
+ Object convObj= null;
+ //The member that keeps the value of the Property is an Any. It can contain all possible
+ //types, therefore a conversion is not necessary.
+ if (memberClass.equals(Any.class))
+ {
+ if (bAnyVal)
+ //parameter setVal is also an Any and can be used without further processing
+ convObj= setVal;
+ else
+ {
+ // Parameter setVal is not an Any. We need to construct an Any that contains
+ // the argument setVal.
+ // If setVal is an interface implementation then, we cannot construct the
+ // Any with setVal.getClass(), because the Any.Type._typeClass would be TypeClass.UNKNOWN.
+ // We try to get an XInterface of setVal and set an XInterface type.
+ if (setVal instanceof XInterface)
+ {
+ XInterface xint= UnoRuntime.queryInterface(XInterface.class, setVal);
+ if (xint != null)
+ convObj= new Any(new Type(XInterface.class), xint);
+ }
+ // The member is an any, and the past in argument was null reference (MAYBEVOID is set)
+ else if (setVal == null)
+ {
+ // if the any member is still null we create a void any
+ if (curVal[0] == null)
+ convObj= new Any(new Type(), null);
+ else
+ {
+ //otherwise we create an Any with the same type as a value of null;
+ convObj= new Any( ((Any)curVal[0]).getType(), null);
+ }
+ }
+ else
+ convObj= new Any(new Type(setVal.getClass()), setVal);
+ }
+ }
+ else
+ convObj= convert(memberClass, setVal);
+ newVal[0]= convObj;
+ }
+ }
+ else
+ throw new UnknownPropertyException("Property " + property.Name + " is unknown");
+ }
+ catch (java.lang.NoSuchFieldException e)
+ {
+ throw new WrappedTargetException(e, "Field does not exist", this, e);
+ }
+ catch (java.lang.IllegalAccessException e)
+ {
+ throw new WrappedTargetException(e, "", this ,e);
+ }
+ return ret;
+ }
+
+ private boolean checkType(Object obj)
+ {
+ return obj == null
+ || obj instanceof Boolean
+ || obj instanceof Character
+ || obj instanceof Number
+ || obj instanceof String
+ || obj instanceof XInterface
+ || obj instanceof Type
+ || obj instanceof com.sun.star.uno.Enum
+ || obj.getClass().isArray();
+ }
+
+ // Param object can be an Any or other object. If obj is null then the return value is null
+ private Object convert( Class cl, Object obj) throws com.sun.star.lang.IllegalArgumentException
+ {
+ Object retVal= null;
+ //The member that keeps the value of the Property is an Object.Objects are similar to Anys in that they can
+ // hold all types.
+ if (obj == null || (obj instanceof Any && ((Any) obj).getObject() == null))
+ {}
+ else if(cl.equals(Object.class))
+ {
+ if (obj instanceof Any)
+ obj= ((Any) obj).getObject();
+ retVal= obj;
+ }
+ else if(cl.equals(boolean.class))
+ retVal= Boolean.valueOf(AnyConverter.toBoolean(obj));
+ else if (cl.equals(char.class))
+ retVal= Character.valueOf(AnyConverter.toChar(obj));
+ else if (cl.equals(byte.class))
+ retVal= Byte.valueOf(AnyConverter.toByte(obj));
+ else if (cl.equals(short.class))
+ retVal= Short.valueOf(AnyConverter.toShort(obj));
+ else if (cl.equals(int.class))
+ retVal= Integer.valueOf(AnyConverter.toInt(obj));
+ else if (cl.equals(long.class))
+ retVal= Long.valueOf(AnyConverter.toLong(obj));
+ else if (cl.equals(float.class))
+ retVal= Float.valueOf(AnyConverter.toFloat(obj));
+ else if (cl.equals(double.class))
+ retVal= Double.valueOf(AnyConverter.toDouble(obj));
+ else if (cl.equals(String.class))
+ retVal= AnyConverter.toString(obj);
+ else if (cl.isArray())
+ retVal= AnyConverter.toArray(obj);
+ else if (cl.equals(Type.class))
+ retVal= AnyConverter.toType(obj);
+ else if (cl.equals(Boolean.class))
+ retVal= Boolean.valueOf(AnyConverter.toBoolean(obj));
+ else if (cl.equals(Character.class))
+ retVal= Character.valueOf(AnyConverter.toChar(obj));
+ else if (cl.equals(Byte.class))
+ retVal= Byte.valueOf(AnyConverter.toByte(obj));
+ else if (cl.equals(Short.class))
+ retVal= Short.valueOf(AnyConverter.toShort(obj));
+ else if (cl.equals(Integer.class))
+ retVal= Integer.valueOf(AnyConverter.toInt(obj));
+ else if (cl.equals(Long.class))
+ retVal= Long.valueOf(AnyConverter.toLong(obj));
+ else if (cl.equals(Float.class))
+ retVal= Float.valueOf(AnyConverter.toFloat(obj));
+ else if (cl.equals(Double.class))
+ retVal= Double.valueOf(AnyConverter.toDouble(obj));
+ else if (XInterface.class.isAssignableFrom(cl))
+ retVal= AnyConverter.toObject(new Type(cl), obj);
+ else if (com.sun.star.uno.Enum.class.isAssignableFrom(cl))
+ retVal= AnyConverter.toObject(new Type(cl), obj);
+ else
+ throw new com.sun.star.lang.IllegalArgumentException("Could not convert the argument");
+ return retVal;
+ }
+
+ /** Sets the value of a property. In this implementation property values are stored in member variables
+ * (see {@link #convertPropertyValue convertPropertyValue} Notification of property listeners
+ * does not occur in this method. By overriding this method one can take full control about how property values
+ * are stored. But then, the {@link #convertPropertyValue convertPropertyValue} and
+ * {@link #getPropertyValue(Property)} must be overridden too.
+ *
+ * A Property with the MAYBEVOID attribute set, is stored as null value. Therefore the member variable must be
+ * an Object in order to make use of the property attribute. An exception is Any. The Any variable can be initially null, but
+ * once it is set the reference will not become null again. If the value is to be set to
+ * void then a new Any will be stored
+ * with a valid type but without a value (i.e. Any.getObject returns null).
+ * If a property has the READONLY attribute set, and one of the setter methods, such as setPropertyValue, has been
+ * called, then this method is not going to be called.
+ * @param property the property for which the new value is set
+ * @param newVal the new value for the property.
+ * @throws com.sun.star.lang.WrappedTargetException An exception, which has to be made known to the caller,
+ * occurred during the setting of the value.
+ */
+ protected void setPropertyValueNoBroadcast(Property property, Object newVal)
+ throws WrappedTargetException
+ {
+ try
+ {
+ // get the member name
+ String sMember= (String) getPropertyId(property);
+ if (sMember != null)
+ {
+ // use reflection to obtain the field that holds the property value
+ // Class.getDeclaredFields does not return inherited fields. One could use Class.getFields to
+ // also get inherited fields, but only those which are public.
+ Field propField= getClass().getDeclaredField(sMember);
+ if (propField != null)
+ propField.set(this, newVal);
+ }
+ }
+ catch(java.lang.Exception e)
+ {
+ throw new WrappedTargetException(e, "PropertySet.setPropertyValueNoBroadcast", this, e);
+ }
+ }
+ /** Retrieves the value of a property. This implementation presumes that the values are stored in member variables
+ * of the furthest inheriting class (see {@link #convertPropertyValue convertPropertyValue}) and that the
+ * variables are public. The property must have
+ * been registered, for example by {@link #registerProperty(Property, Object)}. The identifier Object argument
+ * must have been a String which was the name of the member variable holding the property value.
+ * When properties are to be stored differently one has to override this method as well as
+ * {@link #convertPropertyValue} and {@link #setPropertyValueNoBroadcast}. <br>
+ * If a value is stored in a variable of a primitive type then this method returns an instance of the respective
+ * wrapper class (e.g. java.lang.Boolean).
+ * @param property The property for which the value is to be retrieved.
+ * @return The value of the property.
+ */
+ protected Object getPropertyValue(Property property)
+ {
+ Object ret= null;
+ try
+ {
+ // get the member name
+ String sMember= (String) getPropertyId(property);
+ if (sMember != null)
+ {
+ // use reflection to obtain the field that holds the property value
+ // Class.getDeclaredFields does not return inherited fields. One could use Class.getFields to
+ // also get inherited fields, but only those which are public.
+ Field propField= getClass().getDeclaredField(sMember);
+ if (propField != null)
+ ret= propField.get(this);
+ }
+ }
+ catch(java.lang.NoSuchFieldException e)
+ {
+ throw new java.lang.RuntimeException(e);
+ }
+ catch(java.lang.IllegalAccessException e)
+ {
+ throw new java.lang.RuntimeException(e);
+ }
+ return ret;
+ }
+
+ /**
+ * This method fires events to XPropertyChangeListener,XVetoableChangeListener and
+ * XPropertiesChangeListener event sinks.
+ * To distinguish what listeners are to be called the argument <em>bVetoable</em> is to be set to true if
+ * a XVetoableChangeListener is meant. For XPropertyChangeListener and XPropertiesChangeListener
+ * it is to be set to false.
+ *
+ * @param properties Properties which will be or have been affected.
+ * @param newValues the new values of the properties.
+ * @param oldValues the old values of the properties.
+ * @param bVetoable true means fire to VetoableChangeListener, false means fire to
+ * XPropertyChangedListener and XMultiPropertyChangedListener.
+ *
+ * @throws PropertyVetoException
+ * if a vetoable listener throws it.
+ */
+ protected void fire(
+ Property[] properties,
+ Object[] newValues,
+ Object[] oldValues,
+ boolean bVetoable ) throws PropertyVetoException
+ {
+ // Only fire, if one or more properties changed
+ int nNumProps= properties.length;
+ if (nNumProps > 0)
+ {
+ PropertyChangeEvent[] arEvts= new PropertyChangeEvent[nNumProps];
+ int nAffectedProps= 0;
+ // Loop over all changed properties to fill the event struct
+ for (int i= 0; i < nNumProps; i++)
+ {
+ if ((bVetoable && (properties[i].Attributes & PropertyAttribute.CONSTRAINED) > 0)
+ || (!bVetoable && (properties[i].Attributes & PropertyAttribute.BOUND) > 0))
+ {
+ arEvts[i]= new PropertyChangeEvent(this, properties[i].Name, false,
+ properties[i].Handle, oldValues[i], newValues[i]);
+ nAffectedProps++;
+ }
+ }
+ // fire the events for all changed properties
+ for (int i= 0; i < nAffectedProps; i++)
+ {
+ // get the listener container for the property name
+ InterfaceContainer lc;
+ if (bVetoable)
+ lc= aVetoableLC.getContainer(arEvts[i].PropertyName);
+ else
+ lc= aBoundLC.getContainer(arEvts[i].PropertyName);
+ Iterator it = lc != null ? lc.iterator() : null;
+ if (it != null)
+ {
+ while( it.hasNext())
+ {
+ Object listener= it.next();
+ if (bVetoable)
+ ((XVetoableChangeListener) listener).vetoableChange(arEvts[i]);
+ else
+ ((XPropertyChangeListener) listener).propertyChange(arEvts[i]);
+ }
+ }
+ // broadcast to all listeners with "" property name
+ if(bVetoable)
+ lc= listenerContainer.getContainer(XVetoableChangeListener.class);
+ else
+ lc= listenerContainer.getContainer(XPropertyChangeListener.class);
+ it = lc != null ? lc.iterator() : null;
+ if (it != null)
+ {
+ while(it.hasNext() )
+ {
+ Object listener= it.next();
+ if( bVetoable ) // fire change Events?
+ ((XVetoableChangeListener) listener).vetoableChange(arEvts[i]);
+ else
+ ((XPropertyChangeListener) listener).propertyChange(arEvts[i]);
+ }
+ }
+ }
+ // fire at XPropertiesChangeListeners
+ // if nAffectedProps == 0 then there are no BOUND properties
+ if (!bVetoable && nAffectedProps > 0)
+ {
+
+ PropertyChangeEvent[] arReduced= new PropertyChangeEvent[nAffectedProps];
+ System.arraycopy(arEvts, 0, arReduced, 0, nAffectedProps);
+ InterfaceContainer lc= listenerContainer.getContainer(XPropertiesChangeListener.class);
+ Iterator it = lc != null ? lc.iterator() : null;
+ if (it != null)
+ {
+ while (it.hasNext())
+ {
+ XPropertiesChangeListener listener = (XPropertiesChangeListener) it.next();
+ // fire the whole event sequence to the XPropertiesChangeListener's
+ listener.propertiesChange( arEvts );
+ }
+ }
+ }
+ }
+ }
+ // XFastPropertySet--------------------------------------------------------------------------------
+ public void setFastPropertyValue(int nHandle, Object aValue ) throws UnknownPropertyException,
+ PropertyVetoException, com.sun.star.lang.IllegalArgumentException, WrappedTargetException
+ {
+ Property prop= getPropertyByHandle(nHandle);
+ if (prop == null)
+ throw new UnknownPropertyException(" The property with handle : " + nHandle +" is unknown");
+ setPropertyValue(prop, aValue);
+ }
+
+ // XFastPropertySet --------------------------------------------------------------------------------
+ public Object getFastPropertyValue(int nHandle ) throws UnknownPropertyException,
+ WrappedTargetException
+ {
+ Property prop= getPropertyByHandle(nHandle);
+ if (prop == null)
+ throw new UnknownPropertyException("The property with handle : " + nHandle + " is unknown");
+ return getPropertyValue(prop);
+ }
+
+ // XMultiPropertySet -----------------------------------------------------------------------------------
+ public void addPropertiesChangeListener(String[] propNames, XPropertiesChangeListener listener)
+ {
+ listenerContainer.addInterface(XPropertiesChangeListener.class, listener);
+ }
+
+ // XMultiPropertySet -----------------------------------------------------------------------------------
+ public void firePropertiesChangeEvent(String[] propNames, XPropertiesChangeListener listener)
+ {
+ // Build the events.
+ PropertyChangeEvent[] arEvents= new PropertyChangeEvent[propNames.length];
+ int eventCount= 0;
+ // get a snapshot of the current property values
+ synchronized (this)
+ {
+ for (int i= 0; i < propNames.length; i++)
+ {
+ Property prop= getProperty(propNames[i]);
+ if (prop != null)
+ {
+ Object value= null;
+ try
+ {
+ value= getPropertyValue(prop);
+ }
+ catch(Exception e)
+ {
+ continue;
+ }
+ arEvents[eventCount]= new PropertyChangeEvent(this, prop.Name,
+ false, prop.Handle, value, value);
+ eventCount++;
+ }
+ }
+ }
+
+ // fire events from unsynchronized section so as to prevent deadlocks
+ if (eventCount > 0)
+ {
+ // Reallocate the array of the events if necessary
+ if (arEvents.length != eventCount)
+ {
+ PropertyChangeEvent[] arPropsTmp= new PropertyChangeEvent[eventCount];
+ System.arraycopy(arEvents, 0, arPropsTmp, 0, eventCount);
+ arEvents= arPropsTmp;
+ }
+ listener.propertiesChange(arEvents);
+ }
+ }
+ // XMultiPropertySet -----------------------------------------------------------------------------------
+ /** If a value for a property could not be retrieved then the respective element in the returned
+ * array has the value null.
+ */
+ public Object[] getPropertyValues(String[] propNames)
+ {
+ Object[] arValues= new Object[propNames.length];
+ synchronized (this)
+ {
+ for (int i= 0; i < propNames.length; i++)
+ {
+ Object value= null;
+ try
+ {
+ value= getPropertyValue(propNames[i]);
+ }
+ catch (Exception e)
+ {
+ }
+ arValues[i]= value;
+ }
+ }
+ return arValues;
+ }
+ // XMultiPropertySet -----------------------------------------------------------------------------------
+ public void removePropertiesChangeListener(XPropertiesChangeListener xPropertiesChangeListener)
+ {
+ listenerContainer.removeInterface(XPropertiesChangeListener.class, xPropertiesChangeListener);
+ }
+ // XMultiPropertySet -----------------------------------------------------------------------------------
+ /** If the array of property names contains an unknown property then it will be ignored.
+ */
+ public void setPropertyValues(String[] propNames, Object[] values) throws PropertyVetoException, com.sun.star.lang.IllegalArgumentException, com.sun.star.lang.WrappedTargetException
+ {
+ for (int i= 0; i < propNames.length; i++)
+ {
+ try
+ {
+ setPropertyValue(propNames[i], values[i]);
+ }
+ catch (UnknownPropertyException e)
+ {
+ continue;
+ }
+
+ }
+ }
+
+ private class PropertySetInfo implements XPropertySetInfo
+ {
+ public com.sun.star.beans.Property[] getProperties()
+ {
+ return PropertySet.this.getProperties();
+ }
+
+ public com.sun.star.beans.Property getPropertyByName(String name) throws UnknownPropertyException
+ {
+ return getProperty(name);
+ }
+
+ public boolean hasPropertyByName(String name)
+ {
+ return getProperty(name) != null;
+ }
+
+ }
+}
+
+
+
+
+
diff --git a/ridljar/com/sun/star/lib/uno/helper/PropertySetMixin.java b/ridljar/com/sun/star/lib/uno/helper/PropertySetMixin.java
new file mode 100644
index 0000000000..0c050d6769
--- /dev/null
+++ b/ridljar/com/sun/star/lib/uno/helper/PropertySetMixin.java
@@ -0,0 +1,1111 @@
+/*
+ * 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 com.sun.star.lib.uno.helper;
+
+import com.sun.star.beans.Property;
+import com.sun.star.beans.PropertyAttribute;
+import com.sun.star.beans.PropertyChangeEvent;
+import com.sun.star.beans.PropertyState;
+import com.sun.star.beans.PropertyValue;
+import com.sun.star.beans.PropertyVetoException;
+import com.sun.star.beans.UnknownPropertyException;
+import com.sun.star.beans.XPropertyChangeListener;
+import com.sun.star.beans.XPropertySetInfo;
+import com.sun.star.beans.XVetoableChangeListener;
+import com.sun.star.container.NoSuchElementException;
+import com.sun.star.container.XHierarchicalNameAccess;
+import com.sun.star.lang.DisposedException;
+import com.sun.star.lang.EventObject;
+import com.sun.star.lang.WrappedTargetException;
+import com.sun.star.lang.WrappedTargetRuntimeException;
+import com.sun.star.reflection.XCompoundTypeDescription;
+import com.sun.star.reflection.XIdlClass;
+import com.sun.star.reflection.XIdlField2;
+import com.sun.star.reflection.XIndirectTypeDescription;
+import com.sun.star.reflection.XInterfaceAttributeTypeDescription2;
+import com.sun.star.reflection.XInterfaceMemberTypeDescription;
+import com.sun.star.reflection.XInterfaceTypeDescription2;
+import com.sun.star.reflection.XStructTypeDescription;
+import com.sun.star.reflection.XTypeDescription;
+import com.sun.star.reflection.theCoreReflection;
+import com.sun.star.uno.Any;
+import com.sun.star.uno.AnyConverter;
+import com.sun.star.uno.Type;
+import com.sun.star.uno.TypeClass;
+import com.sun.star.uno.UnoRuntime;
+import com.sun.star.uno.XComponentContext;
+import com.sun.star.uno.XInterface;
+import java.util.ArrayList;
+import java.util.HashMap;
+import java.util.HashSet;
+import java.util.Iterator;
+import java.util.Map;
+
+/**
+ A helper mixin to implement certain UNO interfaces related to property set
+ handling on top of the attributes of a given UNO interface type.
+
+ <p>A client will mix in this class by keeping a reference to an instance of
+ this class, and forwarding all methods of (a subset of the interfaces)
+ <code>com.sun.star.beans.XPropertySet</code>,
+ <code>com.sun.star.beans.XFastPropertySet</code>, and
+ <code>com.sun.star.beans.XPropertyAccess</code> to it.</p>
+
+ <p>Client code should not use the monitors associated with instances of this
+ class, as they are used for internal purposes.</p>
+
+ @since UDK 3.2
+*/
+public final class PropertySetMixin {
+ /**
+ The constructor.
+
+ @param context the component context used by this instance; must not be
+ null, and must supply the
+ <code>com.sun.star.reflection.theCoreReflection</code> and
+ <code>com.sun.star.reflection.theTypeDescriptionManager</code> singletons
+
+ @param object the client UNO object into which this instance is mixed in;
+ must not be null, and must support the given <code>type</code>
+
+ @param type the UNO interface type whose attributes are mapped to
+ properties; must not be null, and must represent a UNO interface type
+
+ @param absentOptional a list of optional properties that are not present,
+ and should thus not be visible via
+ <code>com.sun.star.beans.XPropertySet.getPropertySetInfo</code>,
+ <code>com.sun.star.beans.XPropertySet.addPropertyChangeListener</code>,
+ <code>com.sun.star.beans.XPropertySet.removePropertyChangeListener<!--
+ --></code>,
+ <code>com.sun.star.beans.XPropertySet.addVetoableChangeListener</code>,
+ and <code>com.sun.star.beans.XPropertySet.<!--
+ -->removeVetoableChangeListener</code>; null is treated the same as an
+ empty list; if non-null, the given array must not be modified after it is
+ passed to this constructor. For consistency reasons, the given
+ <code>absentOptional</code> should only contain the names of attributes
+ that represent optional properties that are not present (that is, the
+ attribute getters and setters always throw a
+ <code>com.sun.star.beans.UnknownPropertyException</code>), and should
+ contain each such name only once. If an optional property is not present
+ (that is, the corresponding attribute getter and setter always throw a
+ <code>com.sun.star.beans.UnknownPropertyException</code>) but is not
+ contained in the given <code>absentOptional</code>, then it will be
+ visible via
+ <code>com.sun.star.beans.XPropertySet.getPropertySetInfo</code> as a
+ <code>com.sun.star.beans.Property</code> with a set
+ <code>com.sun.star.beans.PropertyAttribute.OPTIONAL</code>. If the given
+ <code>object</code> does not implement
+ <code>com.sun.star.beans.XPropertySet</code>, then the given
+ <code>absentOptional</code> is effectively ignored and can be null or
+ empty.
+ */
+ public PropertySetMixin(
+ XComponentContext context, XInterface object, Type type,
+ String[] absentOptional)
+ {
+ this.context = context;
+ this.object = object;
+ this.type = type;
+ this.absentOptional = absentOptional;
+ idlClass = getReflection(type.getTypeName());
+ XTypeDescription ifc;
+ try {
+ XHierarchicalNameAccess xhna = UnoRuntime.queryInterface(
+ XHierarchicalNameAccess.class,
+ context.getValueByName(
+ "/singletons/com.sun.star.reflection."
+ + "theTypeDescriptionManager"));
+ ifc = UnoRuntime.queryInterface(
+ XTypeDescription.class,
+ xhna.getByHierarchicalName(type.getTypeName()));
+ } catch (NoSuchElementException e) {
+ throw new RuntimeException(e);
+ }
+ HashMap<String,PropertyData> map = new HashMap<String,PropertyData>();
+ ArrayList<String> handleNames = new ArrayList<String>();
+ initProperties(ifc, map, handleNames, new HashSet<String>());
+ properties = map;
+ handleMap = handleNames.toArray(new String[handleNames.size()]);
+ }
+
+ /**
+ A method used by clients when implementing UNO interface type attribute
+ setter functions.
+
+ <p>First, this method checks whether this instance has already been
+ disposed (see {@link #dispose}), and throws a
+ <code>com.sun.star.beans.DisposedException</code> if applicable. For a
+ constrained attribute (whose setter can explicitly raise
+ <code>com.sun.star.beans.PropertyVetoException</code>), this method
+ notifies any <code>com.sun.star.beans.XVetoableChangeListener</code>s.
+ For a bound attribute, this method modifies the passed-in
+ <code>bound</code> so that it can afterwards be used to notify any
+ <code>com.sun.star.beans.XPropertyChangeListener</code>s. This method
+ should be called before storing the new attribute value, and
+ <code>bound.notifyListeners()</code> should be called exactly once after
+ storing the new attribute value (in case the attribute is bound;
+ otherwise, calling <code>bound.notifyListeners()</code> is ignored).
+ Furthermore, <code>bound.notifyListeners()</code> and this method have to
+ be called from the same thread.</p>
+
+ @param propertyName the name of the property (which is the same as the
+ name of the attribute that is going to be set)
+
+ @param oldValue the property value corresponding to the old attribute
+ value. This is only used as
+ <code>com.sun.star.beans.PropertyChangeEvent.OldValue</code>, which is
+ rather useless, anyway (see &ldquo;Using the Observer Pattern&rdquo; in
+ <a href="http://tools.openoffice.org/CodingGuidelines.sxw">
+ <cite>OpenOffice.org Coding Guidelines</cite></a>). If the attribute
+ that is going to be set is neither bound nor constrained, or if
+ <code>com.sun.star.beans.PropertyChangeEvent.OldValue</code> should not
+ be set, {@link Any#VOID} can be used instead.
+
+ @param newValue the property value corresponding to the new
+ attribute value. This is only used as
+ <code>com.sun.star.beans.PropertyChangeEvent.NewValue</code>, which is
+ rather useless, anyway (see &ldquo;Using the Observer Pattern&rdquo; in
+ <a href="http://tools.openoffice.org/CodingGuidelines.sxw">
+ <cite>OpenOffice.org Coding Guidelines</cite></a>), <em>unless</em> the
+ attribute that is going to be set is constrained. If the attribute
+ that is going to be set is neither bound nor constrained, or if it is
+ only bound but
+ <code>com.sun.star.beans.PropertyChangeEvent.NewValue</code> should not
+ be set, {@link Any#VOID} can be used instead.
+
+ @param bound a reference to a fresh {@link BoundListeners} instance
+ (which has not been passed to this method before, and on which
+ {@link BoundListeners#notifyListeners} has not yet been called); may only
+ be null if the attribute that is going to be set is not bound
+
+ @throws PropertyVetoException if a vetoable listener throws it.
+ */
+ public void prepareSet(
+ String propertyName, Object oldValue, Object newValue,
+ BoundListeners bound)
+ throws PropertyVetoException
+ {
+ // assert properties.get(propertyName) != null;
+ Property p = properties.get(propertyName).property;
+ ArrayList<XVetoableChangeListener> specificVeto = null;
+ ArrayList<XVetoableChangeListener> unspecificVeto = null;
+ synchronized (this) {
+ if (disposed) {
+ throw new DisposedException("disposed", object);
+ }
+ if ((p.Attributes & PropertyAttribute.CONSTRAINED) != 0) {
+ ArrayList<XVetoableChangeListener> o = vetoListeners.get(propertyName);
+ if (o != null) {
+ specificVeto = new ArrayList<XVetoableChangeListener>(o);
+ }
+ o = vetoListeners.get("");
+ if (o != null) {
+ unspecificVeto = new ArrayList<XVetoableChangeListener>(o);
+ }
+ }
+ if ((p.Attributes & PropertyAttribute.BOUND) != 0) {
+ // assert bound != null;
+ ArrayList<XPropertyChangeListener> o = boundListeners.get(propertyName);
+ if (o != null) {
+ bound.specificListeners = new ArrayList<XPropertyChangeListener>(o);
+ }
+ o = boundListeners.get("");
+ if (o != null) {
+ bound.unspecificListeners = new ArrayList<XPropertyChangeListener>(o);
+ }
+ }
+ }
+ if ((p.Attributes & PropertyAttribute.CONSTRAINED) != 0) {
+ PropertyChangeEvent event = new PropertyChangeEvent(
+ object, propertyName, false, p.Handle, oldValue, newValue);
+ if (specificVeto != null) {
+ for (Iterator<XVetoableChangeListener> i = specificVeto.iterator(); i.hasNext();) {
+ try {
+ i.next().vetoableChange(event);
+ } catch (DisposedException e) {}
+ }
+ }
+ if (unspecificVeto != null) {
+ for (Iterator<XVetoableChangeListener> i = unspecificVeto.iterator(); i.hasNext();) {
+ try {
+ i.next().vetoableChange(event);
+ } catch (DisposedException e) {}
+ }
+ }
+ }
+ if ((p.Attributes & PropertyAttribute.BOUND) != 0) {
+ // assert bound != null;
+ bound.event = new PropertyChangeEvent(
+ object, propertyName, false, p.Handle, oldValue, newValue);
+ }
+ }
+
+ /**
+ A simplified version of {@link #prepareSet(String, Object, Object,
+ PropertySetMixin.BoundListeners)}.
+
+ <p>This method is useful for attributes that are not constrained.</p>
+
+ @param propertyName the name of the property (which is the same as the
+ name of the attribute that is going to be set)
+
+ @param bound a reference to a fresh {@link BoundListeners} instance
+ (which has not been passed to this method before, and on which
+ {@link BoundListeners#notifyListeners} has not yet been called); may only
+ be null if the attribute that is going to be set is not bound
+ */
+ public void prepareSet(String propertyName, BoundListeners bound) {
+ try {
+ prepareSet(propertyName, Any.VOID, Any.VOID, bound);
+ } catch (PropertyVetoException e) {
+ throw new RuntimeException("unexpected " + e);
+ }
+ }
+
+ /**
+ Marks this instance as being disposed.
+
+ <p>See <code>com.sun.star.lang.XComponent</code> for the general concept
+ of disposing UNO objects. On the first call to this method, all
+ registered listeners
+ (<code>com.sun.star.beans.XPropertyChangeListener</code>s and
+ <code>com.sun.star.beans.XVetoableChangeListener</code>s) are notified of
+ the disposing source. Any subsequent calls to this method are
+ ignored.</p>
+ */
+ public void dispose() {
+ HashMap<String,ArrayList<XPropertyChangeListener>> bound;
+ HashMap<String,ArrayList<XVetoableChangeListener>> veto;
+ synchronized (this) {
+ bound = boundListeners;
+ boundListeners = null;
+ veto = vetoListeners;
+ vetoListeners = null;
+ disposed = true;
+ }
+ EventObject event = new EventObject(object);
+ if (bound != null) {
+ for (Iterator<ArrayList<XPropertyChangeListener>> i = bound.values().iterator(); i.hasNext();) {
+ for (Iterator<XPropertyChangeListener> j = i.next().iterator(); j.hasNext();)
+ {
+ j.next().disposing(event);
+ }
+ }
+ }
+ if (veto != null) {
+ for (Iterator<ArrayList<XVetoableChangeListener>> i = veto.values().iterator(); i.hasNext();) {
+ for (Iterator<XVetoableChangeListener> j = i.next().iterator(); j.hasNext();)
+ {
+ j.next().disposing(event);
+ }
+ }
+ }
+ }
+
+ /**
+ Implements
+ <code>com.sun.star.beans.XPropertySet.getPropertySetInfo</code>.
+ @return See com.sun.star.beans.XPropertySet
+ */
+ public XPropertySetInfo getPropertySetInfo() {
+ return new Info(properties);
+ }
+
+ /**
+ Implements <code>com.sun.star.beans.XPropertySet.setPropertyValue</code>.
+ @param propertyName
+ See com.sun.star.beans.XPropertySet
+ @param value
+ See com.sun.star.beans.XPropertySet
+ @throws UnknownPropertyException
+ See com.sun.star.beans.XPropertySet
+ @throws PropertyVetoException
+ See com.sun.star.beans.XPropertySet
+ @throws WrappedTargetException
+ See com.sun.star.beans.XPropertySet
+ */
+ public void setPropertyValue(String propertyName, Object value)
+ throws UnknownPropertyException, PropertyVetoException,
+ com.sun.star.lang.IllegalArgumentException, WrappedTargetException
+ {
+ setProperty(propertyName, value, false, false, (short) 1);
+ }
+
+ /**
+ Implements <code>com.sun.star.beans.XPropertySet.getPropertyValue</code>.
+ @param propertyName
+ See com.sun.star.beans.XPropertySet
+ @throws UnknownPropertyException
+ See com.sun.star.beans.XPropertySet
+ @throws WrappedTargetException
+ See com.sun.star.beans.XPropertySet
+ @return
+ See com.sun.star.beans.XPropertySet
+ */
+ public Object getPropertyValue(String propertyName)
+ throws UnknownPropertyException, WrappedTargetException
+ {
+ return getProperty(propertyName, null);
+ }
+
+ /**
+ Implements
+ <code>com.sun.star.beans.XPropertySet.addPropertyChangeListener</code>.
+
+ <p>If a listener is added more than once, it will receive all relevant
+ notifications multiple times.</p>
+
+ @param propertyName
+ See com.sun.star.beans.XPropertySet
+ @param listener
+ See com.sun.star.beans.XPropertySet
+ @throws UnknownPropertyException
+ See com.sun.star.beans.XPropertySet
+ @throws WrappedTargetException
+ See com.sun.star.beans.XPropertySet
+ */
+ public void addPropertyChangeListener(
+ String propertyName, XPropertyChangeListener listener)
+ throws UnknownPropertyException, WrappedTargetException
+ {
+ // assert listener != null;
+ checkUnknown(propertyName);
+ boolean disp;
+ synchronized (this) {
+ disp = disposed;
+ if (!disp) {
+ ArrayList<XPropertyChangeListener> v = boundListeners.get(propertyName);
+ if (v == null) {
+ v = new ArrayList<XPropertyChangeListener>();
+ boundListeners.put(propertyName, v);
+ }
+ v.add(listener);
+ }
+ }
+ if (disp) {
+ listener.disposing(new EventObject(object));
+ }
+ }
+
+ /**
+ Implements <code>
+ com.sun.star.beans.XPropertySet.removePropertyChangeListener</code>.
+
+ @param propertyName
+ See com.sun.star.beans.XPropertySet
+ @param listener
+ See com.sun.star.beans.XPropertySet
+ @throws UnknownPropertyException
+ See com.sun.star.beans.XPropertySet
+ @throws WrappedTargetException
+ See com.sun.star.beans.XPropertySet
+ */
+ public void removePropertyChangeListener(
+ String propertyName, XPropertyChangeListener listener)
+ throws UnknownPropertyException, WrappedTargetException
+ {
+ // assert listener != null;
+ checkUnknown(propertyName);
+ synchronized (this) {
+ if (boundListeners != null) {
+ ArrayList<XPropertyChangeListener> v = boundListeners.get(propertyName);
+ if (v != null) {
+ v.remove(listener);
+ }
+ }
+ }
+ }
+
+ /**
+ Implements
+ <code>com.sun.star.beans.XPropertySet.addVetoableChangeListener</code>.
+
+ <p>If a listener is added more than once, it will receive all relevant
+ notifications multiple times.</p>
+
+ @param propertyName
+ See com.sun.star.beans.XPropertySet
+ @param listener
+ See com.sun.star.beans.XPropertySet
+ @throws UnknownPropertyException
+ See com.sun.star.beans.XPropertySet
+ @throws WrappedTargetException
+ See com.sun.star.beans.XPropertySet
+ */
+ public void addVetoableChangeListener(
+ String propertyName, XVetoableChangeListener listener)
+ throws UnknownPropertyException, WrappedTargetException
+ {
+ // assert listener != null;
+ checkUnknown(propertyName);
+ boolean disp;
+ synchronized (this) {
+ disp = disposed;
+ if (!disp) {
+ ArrayList<XVetoableChangeListener> v = vetoListeners.get(propertyName);
+ if (v == null) {
+ v = new ArrayList<XVetoableChangeListener>();
+ vetoListeners.put(propertyName, v);
+ }
+ v.add(listener);
+ }
+ }
+ if (disp) {
+ listener.disposing(new EventObject(object));
+ }
+ }
+
+ /**
+ Implements <code>
+ com.sun.star.beans.XPropertySet.removeVetoableChangeListener</code>.
+
+ @param propertyName
+ See com.sun.star.beans.XPropertySet
+ @param listener
+ See com.sun.star.beans.XPropertySet
+ @throws UnknownPropertyException
+ See com.sun.star.beans.XPropertySet
+ @throws WrappedTargetException
+ See com.sun.star.beans.XPropertySet
+ */
+ public void removeVetoableChangeListener(
+ String propertyName, XVetoableChangeListener listener)
+ throws UnknownPropertyException, WrappedTargetException
+ {
+ // assert listener != null;
+ checkUnknown(propertyName);
+ synchronized (this) {
+ if (vetoListeners != null) {
+ ArrayList<XVetoableChangeListener> v = vetoListeners.get(propertyName);
+ if (v != null) {
+ v.remove(listener);
+ }
+ }
+ }
+ }
+
+ /**
+ Implements
+ <code>com.sun.star.beans.XFastPropertySet.setFastPropertyValue</code>.
+
+ @param handle
+ See com.sun.star.beans.XFastPropertySet
+ @param value
+ See com.sun.star.beans.XFastPropertySet
+ @throws UnknownPropertyException
+ See com.sun.star.beans.XFastPropertySet
+ @throws PropertyVetoException
+ See com.sun.star.beans.XFastPropertySet
+ @throws WrappedTargetException
+ See com.sun.star.beans.XFastPropertySet
+ */
+ public void setFastPropertyValue(int handle, Object value)
+ throws UnknownPropertyException, PropertyVetoException,
+ com.sun.star.lang.IllegalArgumentException, WrappedTargetException
+ {
+ setProperty(translateHandle(handle), value, false, false, (short) 1);
+ }
+
+ /**
+ Implements
+ <code>com.sun.star.beans.XFastPropertySet.getFastPropertyValue</code>.
+
+ @param handle
+ See com.sun.star.beans.XFastPropertySet
+ @throws UnknownPropertyException
+ See com.sun.star.beans.XFastPropertySet
+ @throws WrappedTargetException
+ See com.sun.star.beans.XFastPropertySet
+ @return
+ See com.sun.star.beans.XFastPropertySet
+ */
+ public Object getFastPropertyValue(int handle)
+ throws UnknownPropertyException, WrappedTargetException
+ {
+ return getProperty(translateHandle(handle), null);
+ }
+
+ /**
+ Implements
+ <code>com.sun.star.beans.XPropertyAccess.getPropertyValues</code>.
+
+ @return
+ See com.sun.star.beans.XPropertyAccess
+ */
+ public PropertyValue[] getPropertyValues() {
+ PropertyValue[] s = new PropertyValue[handleMap.length];
+ int n = 0;
+ for (int i = 0; i < handleMap.length; ++i) {
+ PropertyState[] state = new PropertyState[1];
+ Object value;
+ try {
+ value = getProperty(handleMap[i], state);
+ } catch (UnknownPropertyException e) {
+ continue;
+ } catch (WrappedTargetException e) {
+ throw new WrappedTargetRuntimeException(e.getCause(),
+ e.getMessage(), object, e.TargetException);
+ }
+ s[n++] = new PropertyValue(handleMap[i], i, value, state[0]);
+ }
+ if (n < handleMap.length) {
+ PropertyValue[] s2 = new PropertyValue[n];
+ System.arraycopy(s, 0, s2, 0, n);
+ s = s2;
+ }
+ return s;
+ }
+
+ /**
+ Implements
+ <code>com.sun.star.beans.XPropertyAccess.setPropertyValues</code>.
+
+ @param props
+ See com.sun.star.beans.XPropertyAccess
+ @throws UnknownPropertyException
+ See com.sun.star.beans.XPropertyAccess
+ @throws PropertyVetoException
+ See com.sun.star.beans.XPropertyAccess
+ @throws WrappedTargetException
+ See com.sun.star.beans.XPropertyAccess
+ */
+ public void setPropertyValues(PropertyValue[] props)
+ throws UnknownPropertyException, PropertyVetoException,
+ com.sun.star.lang.IllegalArgumentException, WrappedTargetException
+ {
+ for (int i = 0; i < props.length; ++i) {
+ if (props[i].Handle != -1
+ && !props[i].Name.equals(translateHandle(props[i].Handle)))
+ {
+ throw new UnknownPropertyException(
+ ("name " + props[i].Name + " does not match handle "
+ + props[i].Handle),
+ object);
+ }
+ setProperty(
+ props[i].Name, props[i].Value,
+ props[i].State == PropertyState.AMBIGUOUS_VALUE,
+ props[i].State == PropertyState.DEFAULT_VALUE, (short) 0);
+ }
+ }
+
+ /**
+ A class used by clients of {@link PropertySetMixin} when implementing UNO
+ interface type attribute setter functions.
+
+ @see #prepareSet(String, Object, Object, PropertySetMixin.BoundListeners)
+ */
+ public static final class BoundListeners {
+
+ /**
+ Notifies any
+ <code>com.sun.star.beans.XPropertyChangeListener</code>s.
+
+ @see #prepareSet(String, Object, Object,
+ PropertySetMixin.BoundListeners)
+ */
+ public void notifyListeners() {
+ if (specificListeners != null) {
+ for (Iterator<XPropertyChangeListener> i = specificListeners.iterator(); i.hasNext();) {
+ try {
+ i.next().propertyChange(event);
+ } catch (DisposedException e) {}
+ }
+ }
+ if (unspecificListeners != null) {
+ for (Iterator<XPropertyChangeListener> i = unspecificListeners.iterator(); i.hasNext();)
+ {
+ try {
+ i.next().propertyChange(event);
+ } catch (DisposedException e) {}
+ }
+ }
+ }
+
+ private ArrayList<XPropertyChangeListener> specificListeners = null;
+ private ArrayList<XPropertyChangeListener> unspecificListeners = null;
+ private PropertyChangeEvent event = null;
+ }
+
+ private XIdlClass getReflection(String typeName) {
+ return theCoreReflection.get(context).forName(typeName);
+ }
+
+ private void initProperties(
+ XTypeDescription type, HashMap<String,PropertyData> map, ArrayList<String> handleNames, HashSet<String> seen)
+ {
+ XInterfaceTypeDescription2 ifc = UnoRuntime.queryInterface(
+ XInterfaceTypeDescription2.class, resolveTypedefs(type));
+ if (!seen.add(ifc.getName())) {
+ return;
+ }
+ XTypeDescription[] bases = ifc.getBaseTypes();
+ for (int i = 0; i < bases.length; ++i) {
+ initProperties(bases[i], map, handleNames, seen);
+ }
+ XInterfaceMemberTypeDescription[] members = ifc.getMembers();
+ for (int i = 0; i < members.length; ++i) {
+ if (members[i].getTypeClass() == TypeClass.INTERFACE_ATTRIBUTE)
+ {
+ XInterfaceAttributeTypeDescription2 attr =
+ UnoRuntime.queryInterface(
+ XInterfaceAttributeTypeDescription2.class,
+ members[i]);
+ short attrAttribs = 0;
+ if (attr.isBound()) {
+ attrAttribs |= PropertyAttribute.BOUND;
+ }
+ boolean setUnknown = false;
+ if (attr.isReadOnly()) {
+ attrAttribs |= PropertyAttribute.READONLY;
+ setUnknown = true;
+ }
+ XCompoundTypeDescription[] excs = attr.getGetExceptions();
+ boolean getUnknown = false;
+ //XXX Special interpretation of getter/setter exceptions
+ // only works if the specified exceptions are of the exact
+ // type, not of a supertype:
+ for (int j = 0; j < excs.length; ++j) {
+ if (excs[j].getName().equals(
+ "com.sun.star.beans.UnknownPropertyException"))
+ {
+ getUnknown = true;
+ break;
+ }
+ }
+ excs = attr.getSetExceptions();
+ for (int j = 0; j < excs.length; ++j) {
+ if (excs[j].getName().equals(
+ "com.sun.star.beans.UnknownPropertyException"))
+ {
+ setUnknown = true;
+ } else if (excs[j].getName().equals(
+ "com.sun.star.beans."
+ + "PropertyVetoException"))
+ {
+ attrAttribs |= PropertyAttribute.CONSTRAINED;
+ }
+ }
+ if (getUnknown && setUnknown) {
+ attrAttribs |= PropertyAttribute.OPTIONAL;
+ }
+ XTypeDescription t = attr.getType();
+ for (;;) {
+ t = resolveTypedefs(t);
+ short n;
+ if (t.getName().startsWith(
+ "com.sun.star.beans.Ambiguous<"))
+ {
+ n = PropertyAttribute.MAYBEAMBIGUOUS;
+ } else if (t.getName().startsWith(
+ "com.sun.star.beans.Defaulted<"))
+ {
+ n = PropertyAttribute.MAYBEDEFAULT;
+ } else if (t.getName().startsWith(
+ "com.sun.star.beans.Optional<"))
+ {
+ n = PropertyAttribute.MAYBEVOID;
+ } else {
+ break;
+ }
+ attrAttribs |= n;
+ t = UnoRuntime.queryInterface(XStructTypeDescription.class, t).getTypeArguments()[0];
+ }
+ String name = members[i].getMemberName();
+ boolean present = true;
+ if (absentOptional != null) {
+ for (int j = 0; j < absentOptional.length; ++j) {
+ if (name.equals(absentOptional[j])) {
+ present = false;
+ break;
+ }
+ }
+ }
+ if (map.put(
+ name,
+ new PropertyData(
+ new Property(
+ name, handleNames.size(),
+ new Type(t.getName(), t.getTypeClass()),
+ attrAttribs),
+ present))
+ != null)
+ {
+ throw new RuntimeException(
+ "inconsistent UNO type registry");
+ }
+ handleNames.add(name);
+ }
+ }
+ }
+
+ private String translateHandle(int handle) throws UnknownPropertyException {
+ if (handle < 0 || handle >= handleMap.length) {
+ throw new UnknownPropertyException("bad handle " + handle, object);
+ }
+ return handleMap[handle];
+ }
+
+ private void setProperty(
+ String name, Object value, boolean isAmbiguous, boolean isDefaulted,
+ short illegalArgumentPosition)
+ throws UnknownPropertyException, PropertyVetoException,
+ com.sun.star.lang.IllegalArgumentException, WrappedTargetException
+ {
+ PropertyData p = properties.get(name);
+ if (p == null) {
+ throw new UnknownPropertyException(name, object);
+ }
+ if ((isAmbiguous
+ && (p.property.Attributes & PropertyAttribute.MAYBEAMBIGUOUS) == 0)
+ || (isDefaulted
+ && ((p.property.Attributes & PropertyAttribute.MAYBEDEFAULT)
+ == 0)))
+ {
+ throw new com.sun.star.lang.IllegalArgumentException(
+ ("flagging as ambiguous/defaulted non-ambiguous/defaulted"
+ + " property " + name),
+ object, illegalArgumentPosition);
+
+ }
+ XIdlField2 f = UnoRuntime.queryInterface(
+ XIdlField2.class, idlClass.getField(name));
+ Object[] o = new Object[] {
+ new Any(type, UnoRuntime.queryInterface(type, object)) };
+ Object v = wrapValue(
+ value,
+ UnoRuntime.queryInterface(
+ XIdlField2.class, idlClass.getField(name)).getType(),
+ (p.property.Attributes & PropertyAttribute.MAYBEAMBIGUOUS) != 0,
+ isAmbiguous,
+ (p.property.Attributes & PropertyAttribute.MAYBEDEFAULT) != 0,
+ isDefaulted,
+ (p.property.Attributes & PropertyAttribute.MAYBEVOID) != 0);
+ try {
+ f.set(o, v);
+ } catch (com.sun.star.lang.IllegalArgumentException e) {
+ if (e.ArgumentPosition == 1) {
+ throw new com.sun.star.lang.IllegalArgumentException(e,
+ e.getMessage(), object, illegalArgumentPosition);
+ } else {
+ throw new RuntimeException(e);
+ }
+ } catch (com.sun.star.lang.IllegalAccessException e) {
+ //TODO Clarify whether PropertyVetoException is the correct
+ // exception to throw when trying to set a read-only property:
+ throw new PropertyVetoException(e,
+ "cannot set read-only property " + name, object);
+ } catch (WrappedTargetRuntimeException e) {
+ //FIXME A WrappedTargetRuntimeException from XIdlField2.get is not
+ // guaranteed to originate directly within XIdlField2.get (and thus
+ // have the expected semantics); it might also be passed through
+ // from lower layers.
+ if (new Type(UnknownPropertyException.class).isSupertypeOf(
+ AnyConverter.getType(e.TargetException))
+ && (p.property.Attributes & PropertyAttribute.OPTIONAL) != 0)
+ {
+ throw new UnknownPropertyException(e, name, object);
+ } else if (new Type(PropertyVetoException.class).isSupertypeOf(
+ AnyConverter.getType(e.TargetException))
+ && ((p.property.Attributes
+ & PropertyAttribute.CONSTRAINED)
+ != 0))
+ {
+ throw new PropertyVetoException(e, name, object);
+ } else {
+ throw new WrappedTargetException(e.getCause(),
+ e.getMessage(), object, e.TargetException);
+ }
+ }
+ }
+
+ Object getProperty(String name, PropertyState[] state)
+ throws UnknownPropertyException, WrappedTargetException
+ {
+ PropertyData p = properties.get(name);
+ if (p == null) {
+ throw new UnknownPropertyException(name, object);
+ }
+ XIdlField2 field = UnoRuntime.queryInterface(
+ XIdlField2.class, idlClass.getField(name));
+ Object value;
+ try {
+ value = field.get(
+ new Any(type, UnoRuntime.queryInterface(type, object)));
+ } catch (com.sun.star.lang.IllegalArgumentException e) {
+ throw new RuntimeException(e);
+ } catch (WrappedTargetRuntimeException e) {
+ //FIXME A WrappedTargetRuntimeException from XIdlField2.get is not
+ // guaranteed to originate directly within XIdlField2.get (and thus
+ // have the expected semantics); it might also be passed through
+ // from lower layers.
+ if (new Type(UnknownPropertyException.class).isSupertypeOf(
+ AnyConverter.getType(e.TargetException))
+ && (p.property.Attributes & PropertyAttribute.OPTIONAL) != 0)
+ {
+ throw new UnknownPropertyException(e, name, object);
+ } else {
+ throw new WrappedTargetException(e.getCause(),
+ e.getMessage(), object, e.TargetException);
+ }
+ }
+ boolean undoAmbiguous
+ = (p.property.Attributes & PropertyAttribute.MAYBEAMBIGUOUS) != 0;
+ boolean undoDefaulted
+ = (p.property.Attributes & PropertyAttribute.MAYBEDEFAULT) != 0;
+ boolean undoOptional
+ = (p.property.Attributes & PropertyAttribute.MAYBEVOID) != 0;
+ boolean isAmbiguous = false;
+ boolean isDefaulted = false;
+ while (undoAmbiguous || undoDefaulted || undoOptional) {
+ String typeName = AnyConverter.getType(value).getTypeName();
+ if (undoAmbiguous
+ && typeName.startsWith("com.sun.star.beans.Ambiguous<"))
+ {
+ XIdlClass ambiguous = getReflection(typeName);
+ try {
+ isAmbiguous = AnyConverter.toBoolean(
+ UnoRuntime.queryInterface(
+ XIdlField2.class,
+ ambiguous.getField("IsAmbiguous")).get(value));
+ value = UnoRuntime.queryInterface(
+ XIdlField2.class,
+ ambiguous.getField("Value")).get(value);
+ } catch (com.sun.star.lang.IllegalArgumentException e) {
+ throw new RuntimeException(e);
+ }
+ undoAmbiguous = false;
+ } else if (undoDefaulted
+ && typeName.startsWith("com.sun.star.beans.Defaulted<"))
+ {
+ XIdlClass defaulted = getReflection(typeName);
+ try {
+ isDefaulted = AnyConverter.toBoolean(
+ UnoRuntime.queryInterface(
+ XIdlField2.class,
+ defaulted.getField("IsDefaulted")).get(value));
+ value = UnoRuntime.queryInterface(
+ XIdlField2.class,
+ defaulted.getField("Value")).get(value);
+ } catch (com.sun.star.lang.IllegalArgumentException e) {
+ throw new RuntimeException(e);
+ }
+ undoDefaulted = false;
+ } else if (undoOptional
+ && typeName.startsWith("com.sun.star.beans.Optional<"))
+ {
+ XIdlClass optional = getReflection(typeName);
+ try {
+ boolean present = AnyConverter.toBoolean(
+ UnoRuntime.queryInterface(
+ XIdlField2.class,
+ optional.getField("IsPresent")).get(value));
+ if (!present) {
+ value = Any.VOID;
+ break;
+ }
+ value = UnoRuntime.queryInterface(
+ XIdlField2.class,
+ optional.getField("Value")).get(value);
+ } catch (com.sun.star.lang.IllegalArgumentException e) {
+ throw new RuntimeException(e);
+ }
+ undoOptional = false;
+ } else {
+ throw new RuntimeException(
+ "unexpected type of attribute " + name);
+ }
+ }
+ if (state != null) {
+ //XXX If isAmbiguous && isDefaulted, arbitrarily choose
+ // AMBIGUOUS_VALUE over DEFAULT_VALUE:
+ state[0] = isAmbiguous
+ ? PropertyState.AMBIGUOUS_VALUE
+ : isDefaulted
+ ? PropertyState.DEFAULT_VALUE : PropertyState.DIRECT_VALUE;
+ }
+ return value;
+ }
+
+ private Object wrapValue(
+ Object value, XIdlClass type, boolean wrapAmbiguous,
+ boolean isAmbiguous, boolean wrapDefaulted, boolean isDefaulted,
+ boolean wrapOptional)
+ {
+ if (wrapAmbiguous
+ && type.getName().startsWith("com.sun.star.beans.Ambiguous<"))
+ {
+ Object[] strct = new Object[1];
+ type.createObject(strct);
+ try {
+ XIdlField2 field = UnoRuntime.queryInterface(
+ XIdlField2.class, type.getField("Value"));
+ field.set(
+ strct,
+ wrapValue(
+ value, field.getType(), false, false, wrapDefaulted,
+ isDefaulted, wrapOptional));
+ UnoRuntime.queryInterface(
+ XIdlField2.class, type.getField("IsAmbiguous")).set(
+ strct, Boolean.valueOf(isAmbiguous));
+ } catch (com.sun.star.lang.IllegalArgumentException e) {
+ throw new RuntimeException(e);
+ } catch (com.sun.star.lang.IllegalAccessException e) {
+ throw new RuntimeException(e);
+ }
+ return strct[0];
+ } else if (wrapDefaulted
+ && type.getName().startsWith(
+ "com.sun.star.beans.Defaulted<"))
+ {
+ Object[] strct = new Object[1];
+ type.createObject(strct);
+ try {
+ XIdlField2 field = UnoRuntime.queryInterface(
+ XIdlField2.class, type.getField("Value"));
+ field.set(
+ strct,
+ wrapValue(
+ value, field.getType(), wrapAmbiguous, isAmbiguous,
+ false, false, wrapOptional));
+ UnoRuntime.queryInterface(
+ XIdlField2.class, type.getField("IsDefaulted")).set(
+ strct, Boolean.valueOf(isDefaulted));
+ } catch (com.sun.star.lang.IllegalArgumentException e) {
+ throw new RuntimeException(e);
+ } catch (com.sun.star.lang.IllegalAccessException e) {
+ throw new RuntimeException(e);
+ }
+ return strct[0];
+ } else if (wrapOptional
+ && type.getName().startsWith("com.sun.star.beans.Optional<"))
+ {
+ Object[] strct = new Object[1];
+ type.createObject(strct);
+ boolean present = !AnyConverter.isVoid(value);
+ try {
+ UnoRuntime.queryInterface(
+ XIdlField2.class, type.getField("IsPresent")).set(
+ strct, Boolean.valueOf(present));
+ if (present) {
+ XIdlField2 field = UnoRuntime.queryInterface(
+ XIdlField2.class, type.getField("Value"));
+ field.set(
+ strct,
+ wrapValue(
+ value, field.getType(), wrapAmbiguous, isAmbiguous,
+ wrapDefaulted, isDefaulted, false));
+ }
+ } catch (com.sun.star.lang.IllegalArgumentException e) {
+ throw new RuntimeException(e);
+ } catch (com.sun.star.lang.IllegalAccessException e) {
+ throw new RuntimeException(e);
+ }
+ return strct[0];
+ } else {
+ if (wrapAmbiguous || wrapDefaulted || wrapOptional) {
+ throw new RuntimeException("unexpected type of attribute");
+ }
+ return value;
+ }
+ }
+
+ private static XTypeDescription resolveTypedefs(XTypeDescription type) {
+ while (type.getTypeClass() == TypeClass.TYPEDEF) {
+ type = UnoRuntime.queryInterface(
+ XIndirectTypeDescription.class, type).getReferencedType();
+ }
+ return type;
+ }
+
+ private PropertyData get(Object object, String propertyName)
+ throws UnknownPropertyException
+ {
+ PropertyData p = properties.get(propertyName);
+ if (p == null || !p.present) {
+ throw new UnknownPropertyException(propertyName, object);
+ }
+ return p;
+ }
+
+ private void checkUnknown(String propertyName)
+ throws UnknownPropertyException
+ {
+ if (propertyName.length() != 0) {
+ get(this, propertyName);
+ }
+ }
+
+ private static final class PropertyData {
+ public PropertyData(Property property, boolean present) {
+ this.property = property;
+ this.present = present;
+ }
+
+ public final Property property;
+ public final boolean present;
+ }
+
+ private final class Info extends WeakBase implements XPropertySetInfo
+ {
+ public Info(Map<String,PropertyData> properties) {
+ this.properties = properties;
+ }
+
+ public Property[] getProperties() {
+ ArrayList<Property> al = new ArrayList<Property>(properties.size());
+ for (Iterator<PropertyData> i = properties.values().iterator(); i.hasNext();) {
+ PropertyData p = i.next();
+ if (p.present) {
+ al.add(p.property);
+ }
+ }
+ return al.toArray(new Property[al.size()]);
+ }
+
+ public Property getPropertyByName(String name)
+ throws UnknownPropertyException
+ {
+ return get(this, name).property;
+ }
+
+ public boolean hasPropertyByName(String name) {
+ PropertyData p = properties.get(name);
+ return p != null && p.present;
+ }
+
+ private final Map<String,PropertyData> properties;
+ }
+
+ private final XComponentContext context;
+ private final XInterface object;
+ private final Type type;
+ private final String[] absentOptional;
+ private final XIdlClass idlClass;
+ private final Map<String,PropertyData> properties; // from String to Property
+ private final String[] handleMap;
+
+ private HashMap<String,ArrayList<XPropertyChangeListener>> boundListeners
+ = new HashMap<String,ArrayList<XPropertyChangeListener>>();
+ // from String to Vector of XPropertyChangeListener
+ private HashMap<String,ArrayList<XVetoableChangeListener>> vetoListeners
+ = new HashMap<String,ArrayList<XVetoableChangeListener>>();
+ // from String to Vector of XVetoableChangeListener
+ private boolean disposed = false;
+}
diff --git a/ridljar/com/sun/star/lib/uno/helper/UnoUrl.java b/ridljar/com/sun/star/lib/uno/helper/UnoUrl.java
new file mode 100644
index 0000000000..22ea695f5b
--- /dev/null
+++ b/ridljar/com/sun/star/lib/uno/helper/UnoUrl.java
@@ -0,0 +1,401 @@
+/*
+ * 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 com.sun.star.lib.uno.helper;
+import java.io.UnsupportedEncodingException;
+import java.nio.ByteBuffer;
+import java.util.HashMap;
+
+/**
+ * Object representation and parsing of Uno Urls,
+ * which allow to locate a named Uno object in a
+ * different process. A Uno Url consists of the
+ * specification of a connection, protocol and
+ * rootOid delimited with a ';'.
+ * The syntax of a Uno Url is
+ *
+ * <code>
+ * [uno:]connection-type,parameters;protocol-name,parameters;objectname";
+ * </code>
+ *
+ * An example Uno Url will look like this:
+ *
+ * <code>
+ * socket,host=localhost,port=2002;urp;StarOffice.ServiceManager
+ * </code>
+ *
+ * For more information about Uno Url please consult
+ * <a href="http://udk.openoffice.org/common/man/spec/uno-url.html">
+ * http://udk.openoffice.org/common/man/spec/uno-url.html</a>
+ *
+ * Usage:
+ *
+ * <code>
+ * UnoUrl url = UnoUrl.parseUnoUrl("uno:socket,host=localhost,port=2002;urp;StarOffice.ServiceManager");
+ * </code>
+ */
+public class UnoUrl {
+
+ private static final String FORMAT_ERROR =
+ "syntax: [uno:]connection-type,parameters;protocol-name,parameters;objectname";
+
+ private static final String VALUE_CHAR_SET = "!$&'()*+-./:?@_~";
+ private static final String OID_CHAR_SET = VALUE_CHAR_SET + ",=";
+
+ private final UnoUrlPart connection;
+ private final UnoUrlPart protocol;
+ private final String rootOid;
+
+ private static class UnoUrlPart {
+
+ private final String partTypeName;
+ private final HashMap<String,String> partParameters;
+ private final String uninterpretedParameterString;
+
+ public UnoUrlPart(
+ String uninterpretedParameterString,
+ String partTypeName,
+ HashMap<String,String> partParameters) {
+ this.uninterpretedParameterString = uninterpretedParameterString;
+ this.partTypeName = partTypeName;
+ this.partParameters = partParameters;
+ }
+
+ public String getPartTypeName() {
+ return partTypeName;
+ }
+
+ public HashMap<String,String> getPartParameters() {
+ return partParameters;
+ }
+
+ public String getUninterpretedParameterString() {
+ return uninterpretedParameterString;
+ }
+
+ public String getUninterpretedString() {
+ StringBuffer buf = new StringBuffer(partTypeName);
+ if (uninterpretedParameterString.length() > 0) {
+ buf.append(',');
+ buf.append(uninterpretedParameterString);
+ }
+ return buf.toString();
+ }
+ }
+
+ private UnoUrl(
+ UnoUrlPart connectionPart,
+ UnoUrlPart protocolPart,
+ String rootOid) {
+ this.connection = connectionPart;
+ this.protocol = protocolPart;
+ this.rootOid = rootOid;
+ }
+
+ /**
+ * Returns the name of the connection of this
+ * Uno Url. Encoded characters are not allowed.
+ *
+ * @return The connection name as string.
+ */
+ public String getConnection() {
+ return connection.getPartTypeName();
+ }
+
+ /**
+ * Returns the name of the protocol of this
+ * Uno Url. Encoded characters are not allowed.
+ *
+ * @return The protocol name as string.
+ */
+ public String getProtocol() {
+ return protocol.getPartTypeName();
+ }
+
+ /**
+ * Return the object name. Encoded character are
+ * not allowed.
+ *
+ * @return The object name as String.
+ */
+ public String getRootOid() {
+ return rootOid;
+ }
+
+ /**
+ * Returns the protocol parameters as
+ * a Hashmap with key/value pairs. Encoded
+ * characters like '%41' are decoded.
+ *
+ * @return a HashMap with key/value pairs for protocol parameters.
+ */
+ public HashMap<String,String> getProtocolParameters() {
+ return protocol.getPartParameters();
+ }
+
+ /**
+ * Returns the connection parameters as
+ * a Hashmap with key/value pairs. Encoded
+ * characters like '%41' are decoded.
+ *
+ * @return a HashMap with key/value pairs for connection parameters.
+ */
+ public HashMap<String,String> getConnectionParameters() {
+ return connection.getPartParameters();
+ }
+
+ /**
+ * Returns the raw specification of the protocol
+ * parameters. Encoded characters like '%41' are
+ * not decoded.
+ *
+ * @return The uninterpreted protocol parameters as string.
+ */
+ public String getProtocolParametersAsString() {
+ return protocol.getUninterpretedParameterString();
+ }
+
+ /**
+ * Returns the raw specification of the connection
+ * parameters. Encoded characters like '%41' are
+ * not decoded.
+ *
+ * @return The uninterpreted connection parameters as string.
+ */
+ public String getConnectionParametersAsString() {
+ return connection.getUninterpretedParameterString();
+ }
+
+ /**
+ * Returns the raw specification of the protocol
+ * name and parameters. Encoded characters like '%41' are
+ * not decoded.
+ *
+ * @return The uninterpreted protocol name and parameters as string.
+ */
+ public String getProtocolAndParametersAsString() {
+ return protocol.getUninterpretedString();
+ }
+
+ /**
+ * Returns the raw specification of the connection
+ * name and parameters. Encoded characters like '%41' are
+ * not decoded.
+ *
+ * @return The uninterpreted connection name and parameters as string.
+ */
+ public String getConnectionAndParametersAsString() {
+ return connection.getUninterpretedString();
+ }
+
+ private static String decodeUTF8(String s)
+ throws com.sun.star.lang.IllegalArgumentException {
+
+ if (!s.contains("%")) {
+ return s;
+ }
+ try {
+ int length = s.length();
+ ByteBuffer bb = ByteBuffer.allocate(length);
+ for (int i = 0; i < length; i++) {
+ int ch = s.charAt(i);
+
+ if (ch == '%') {
+ if (i+3 > length)
+ throw new com.sun.star.lang.IllegalArgumentException(
+ "Incomplete trailing escape (%) pattern");
+ try {
+ ch = Integer.parseInt(s.substring(i+1,i+3),16);
+ } catch (NumberFormatException e) {
+ throw new com.sun.star.lang.IllegalArgumentException(e);
+ }
+ if (ch < 0)
+ throw new com.sun.star.lang.IllegalArgumentException(
+ "Illegal hex characters in escape (%) pattern - negative value");
+ i+=2;
+ }
+
+ bb.put((byte) (ch & 0xFF));
+ }
+
+ byte[] bytes = new byte[bb.position()];
+ System.arraycopy(bb.array(), 0, bytes, 0, bytes.length);
+ return new String(bytes, "UTF-8");
+ } catch (UnsupportedEncodingException e) {
+ throw new com.sun.star.lang.IllegalArgumentException(e,
+ "Couldn't convert parameter string to UTF-8 string");
+ }
+ }
+
+ private static HashMap<String,String> buildParamHashMap(String paramString)
+ throws com.sun.star.lang.IllegalArgumentException {
+ HashMap<String,String> params = new HashMap<String,String>();
+
+ int pos = 0;
+
+ while (true) {
+ char c = ',';
+
+ StringBuffer sb = new StringBuffer();
+ while ((pos < paramString.length())
+ && ((c = paramString.charAt(pos++)) != '=')) {
+ sb.append(c);
+ }
+ String aKey = sb.toString();
+
+ sb = new StringBuffer();
+ while ((pos < paramString.length())
+ && ((c = paramString.charAt(pos++)) != ',')
+ && c != ';') {
+ sb.append(c);
+ }
+ String aValue = sb.toString();
+
+ if ((aKey.length() > 0) && (aValue.length() > 0)) {
+
+ if (!isAlphaNumeric(aKey)) {
+ throw new com.sun.star.lang.IllegalArgumentException(
+ "The parameter key '"
+ + aKey
+ + "' may only consist of alpha numeric ASCII characters.");
+ }
+
+ if (!isValidString(aValue, VALUE_CHAR_SET + "%")) {
+ throw new com.sun.star.lang.IllegalArgumentException(
+ "The parameter value for key '" + aKey + "' contains illegal characters.");
+ }
+
+ params.put(aKey, decodeUTF8(aValue));
+ }
+
+ if ((pos >= paramString.length()) || (c != ','))
+ break;
+
+ }
+
+ return params;
+ }
+
+ private static UnoUrlPart parseUnoUrlPart(String thePart)
+ throws com.sun.star.lang.IllegalArgumentException {
+ String partName;
+ String theParamPart;
+ int index = thePart.indexOf(',');
+ if (index != -1) {
+ partName = thePart.substring(0, index).trim();
+ theParamPart = thePart.substring(index + 1).trim();
+ } else {
+ partName = thePart;
+ theParamPart = "";
+ }
+
+ if (!isAlphaNumeric(partName)) {
+ throw new com.sun.star.lang.IllegalArgumentException(
+ "The part name '"
+ + partName
+ + "' may only consist of alpha numeric ASCII characters.");
+ }
+
+ HashMap<String,String> params = buildParamHashMap(theParamPart);
+
+ return new UnoUrlPart(theParamPart, partName, params);
+ }
+
+ private static boolean isAlphaNumeric(String s) {
+ return isValidString(s, null);
+ }
+
+ private static boolean isValidString(String identifier, String validCharSet) {
+
+ int len = identifier.length();
+
+ for (int i = 0; i < len; i++) {
+
+ int ch = identifier.charAt(i);
+
+ boolean isValidChar =
+ ('A' <= ch && ch <= 'Z')
+ || ('a' <= ch && ch <= 'z')
+ || ('0' <= ch && ch <= '9');
+
+ if (!isValidChar && (validCharSet != null)) {
+ isValidChar = (validCharSet.indexOf(ch) != -1);
+ }
+
+ if (!isValidChar)
+ return false;
+ }
+
+ return true;
+ }
+
+ /**
+ * Parses the given Uno Url and returns
+ * an in memory object representation.
+ *
+ * @param unoUrl The given uno URl as string.
+ * @return Object representation of class UnoUrl.
+ * @throws IllegalArgumentException if Url cannot be parsed.
+ */
+ public static UnoUrl parseUnoUrl(String unoUrl)
+ throws com.sun.star.lang.IllegalArgumentException {
+
+ String url = unoUrl;
+
+ int index = url.indexOf(':');
+ if (index != -1) {
+ String unoStr = url.substring(0, index).trim();
+ if (!"uno".equals(unoStr)) {
+ throw new com.sun.star.lang.IllegalArgumentException(
+ "Uno Urls must start with 'uno:'. " + FORMAT_ERROR);
+ }
+ }
+
+ url = url.substring(index + 1).trim();
+
+ index = url.indexOf(';');
+ if (index == -1) {
+ throw new com.sun.star.lang.IllegalArgumentException("'"+unoUrl+"' is an invalid Uno Url. " + FORMAT_ERROR);
+ }
+
+ String connection = url.substring(0, index).trim();
+ url = url.substring(index + 1).trim();
+
+ UnoUrlPart connectionPart = parseUnoUrlPart(connection);
+
+ index = url.indexOf(';');
+ if (index == -1) {
+ throw new com.sun.star.lang.IllegalArgumentException("'"+unoUrl+"' is an invalid Uno Url. " + FORMAT_ERROR);
+ }
+
+ String protocol = url.substring(0, index).trim();
+ url = url.substring(index + 1).trim();
+
+ UnoUrlPart protocolPart = parseUnoUrlPart(protocol);
+
+ String rootOid = url.trim();
+ if (!isValidString(rootOid, OID_CHAR_SET)) {
+ throw new com.sun.star.lang.IllegalArgumentException(
+ "Root OID '"+ rootOid + "' contains illegal characters.");
+ }
+
+ return new UnoUrl(connectionPart, protocolPart, rootOid);
+
+ }
+
+}
diff --git a/ridljar/com/sun/star/lib/uno/helper/WeakAdapter.java b/ridljar/com/sun/star/lib/uno/helper/WeakAdapter.java
new file mode 100644
index 0000000000..67e01ac327
--- /dev/null
+++ b/ridljar/com/sun/star/lib/uno/helper/WeakAdapter.java
@@ -0,0 +1,94 @@
+/*
+ * 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 com.sun.star.lib.uno.helper;
+import java.lang.ref.WeakReference;
+import com.sun.star.uno.XAdapter;
+import com.sun.star.uno.XReference;
+import java.util.List;
+import java.util.Collections;
+import java.util.LinkedList;
+
+/** An XAdapter implementation that holds a weak reference (java.lang.ref.WeakReference)
+ * to an object. Clients can register listener (com.sun.star.lang.XReference) which
+ * are notified when the object (the one which is kept weak) is being finalized. That
+ * is, that object is being destroyed because there are not any hard references
+ * to it.
+ */
+public class WeakAdapter implements XAdapter
+{
+ // references the XWeak implementation
+ private final WeakReference<Object> m_weakRef;
+ // contains XReference objects registered by addReference
+ private final List<XReference> m_xreferenceList;
+
+ /**
+ *@param component the object that is to be held weak
+ */
+ public WeakAdapter(Object component)
+ {
+ m_weakRef= new WeakReference<Object>(component);
+ m_xreferenceList= Collections.synchronizedList( new LinkedList<XReference>());
+ }
+
+ /** Called by the XWeak implementation (WeakBase) when it is being finalized.
+ * It is only being called once.
+ * The registered XReference listeners are notified. On notification they are
+ * to unregister themselves. The notification is thread-safe. However, it is possible
+ * to add a listener during the notification process, which will never receive a
+ * notification. To prevent this, one would have to synchronize this method with
+ * the addReference method. But this can result in deadlocks in a multi-threaded
+ * environment.
+ */
+ void referentDying()
+ {
+ //synchronized call
+ XReference[] references= m_xreferenceList.toArray(new XReference[m_xreferenceList.size()]);
+ for (int i= references.length; i > 0; i--)
+ {
+ references[i-1].dispose();
+ }
+ }
+
+ /** Method of com.sun.star.uno.XAdapter. It is called to obtain a hard reference
+ * to the object which is kept weak by this instance.
+ * @return hard reference to the object
+ */
+ public Object queryAdapted()
+ {
+ return m_weakRef.get();
+ }
+
+ /** Method of com.sun.star.uno.XAdapter. Called by clients to register listener which
+ * are notified when the weak object is dying.
+ *@param xReference a listener
+ */
+ public void removeReference(XReference xReference)
+ {
+ m_xreferenceList.remove(xReference);
+ }
+
+ /** Method of com.sun.star.uno.XAdapter. Called by clients to unregister listeners.
+ *@param xReference listener
+ */
+ public void addReference(XReference xReference)
+ {
+ m_xreferenceList.add(xReference);
+ }
+}
+
diff --git a/ridljar/com/sun/star/lib/uno/helper/WeakBase.java b/ridljar/com/sun/star/lib/uno/helper/WeakBase.java
new file mode 100644
index 0000000000..ac175d3a6d
--- /dev/null
+++ b/ridljar/com/sun/star/lib/uno/helper/WeakBase.java
@@ -0,0 +1,101 @@
+/*
+ * 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 com.sun.star.lib.uno.helper;
+import com.sun.star.uno.XWeak;
+import com.sun.star.uno.XAdapter;
+import com.sun.star.lang.XTypeProvider;
+import com.sun.star.uno.Type;
+import java.util.ArrayList;
+import java.util.Map;
+import java.util.HashMap;
+
+
+/** This class can be used as the base class for UNO components. It implements the capability
+ * to be kept weak (com.sun.star.uno.XWeak) and it implements com.sun.star.lang.XTypeProvider
+ * which is necessary for using the component with StarBasic.
+ */
+public class WeakBase implements XWeak, XTypeProvider
+{
+ // Contains all WeakAdapter which have been created in this class
+ // They have to be notified when this object dies
+ private WeakAdapter m_adapter;
+
+ protected static Map<Class<?>,Type[]> _mapTypes = new HashMap<Class<?>,Type[]>();
+
+ /** Method of XWeak. The returned XAdapter implementation can be used to keep
+ * a weak reference to this object.
+ * @return a com.sun.star.uno.XAdapter implementation.
+ */
+ synchronized public XAdapter queryAdapter()
+ {
+ if (m_adapter == null)
+ m_adapter= new WeakAdapter(this);
+ return m_adapter;
+ }
+
+ /** Override of Object.finalize. When there are no references to this object anymore
+ * then the garbage collector calls this method. Thereby causing the adapter object
+ * to be notified. The adapter, in turn, notifies all listeners (com.sun.star.uno.XReference)
+ */
+ @Override
+ protected void finalize() throws java.lang.Throwable
+ {
+ if (m_adapter != null)
+ m_adapter.referentDying();
+ super.finalize();
+ }
+
+ /** Method of XTypeProvider. It returns an array of Type objects which represent
+ * all implemented UNO interfaces of this object.
+ * @return Type objects of all implemented interfaces.
+ */
+ public Type[] getTypes()
+ {
+ Type[] arTypes= _mapTypes.get( getClass());
+ if (arTypes == null)
+ {
+ ArrayList<Type> vec= new ArrayList<Type>();
+ Class currentClass= getClass();
+ do
+ {
+ Class interfaces[]= currentClass.getInterfaces();
+ for(int i = 0; i < interfaces.length; ++ i)
+ {
+ // Test if it is a UNO interface
+ if (com.sun.star.uno.XInterface.class.isAssignableFrom(interfaces[i]))
+ vec.add(new Type(interfaces[i]));
+ }
+ // get the superclass the currentClass inherits from
+ currentClass= currentClass.getSuperclass();
+ } while (currentClass != null);
+
+ Type types[]= vec.toArray(new Type[vec.size()]);
+ _mapTypes.put(getClass(), types);
+ arTypes= types;
+ }
+ return arTypes;
+ }
+
+ /** Obsolete method of XTypeProvider.
+ */
+ public byte[] getImplementationId()
+ {
+ return new byte[0];
+ }
+}
diff --git a/ridljar/com/sun/star/lib/uno/protocols/urp/Cache.java b/ridljar/com/sun/star/lib/uno/protocols/urp/Cache.java
new file mode 100644
index 0000000000..26c2d449d6
--- /dev/null
+++ b/ridljar/com/sun/star/lib/uno/protocols/urp/Cache.java
@@ -0,0 +1,114 @@
+/* -*- Mode: Java; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
+/*
+ * 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 com.sun.star.lib.uno.protocols.urp;
+
+import java.util.HashMap;
+
+/**
+ * An LRU cache for arbitrary objects.
+ *
+ * <p>This class is not synchronized, as any necessary synchronization will already
+ * take place in the client.</p>
+ */
+final class Cache {
+ /**
+ * Create a cache.
+ *
+ * @param size the maximum cache size, must be between 0, inclusive, and
+ * NOT_CACHED, exclusive.
+ */
+ public Cache(int size) {
+ maxSize = size;
+ }
+
+ public int add(boolean[] found, Object content) {
+ Entry e = map.get(content);
+ found[0] = e != null;
+ if (e == null) {
+ if (map.size() < maxSize) {
+ // There is still room for a new entry at the front:
+ e = new Entry(content, map.size(), null, first);
+ if (first == null) {
+ last = e;
+ } else {
+ first.prev = e;
+ }
+ first = e;
+ } else if (last != null) {
+ // Take last entry out and recycle as new front:
+ map.remove(last.content);
+ e = last;
+ e.content = content;
+ if (first != last) {
+ // Reached only if maxSize > 1:
+ last = last.prev;
+ last.next = null;
+ e.prev = null;
+ e.next = first;
+ first.prev = e;
+ first = e;
+ }
+ } else {
+ // Reached iff maxSize == 0:
+ return NOT_CACHED;
+ }
+ map.put(content, e);
+ } else if (e != first) {
+ // Move to front (reached only if maxSize > 1):
+ e.prev.next = e.next;
+ if (e.next == null) {
+ last = e.prev;
+ } else {
+ e.next.prev = e.prev;
+ }
+ e.prev = null;
+ e.next = first;
+ first.prev = e;
+ first = e;
+ }
+ return e.index;
+ }
+
+ public static final int NOT_CACHED = 0xFFFF;
+
+ private static final class Entry {
+ public Entry(Object content, int index, Entry prev, Entry next) {
+ this.content = content;
+ this.index = index;
+ this.prev = prev;
+ this.next = next;
+ }
+
+ public Object content;
+ public int index;
+ public Entry prev;
+ public Entry next;
+ }
+
+ // first/last form a list of 0 to maxSize entries, most recently used first;
+ // map contains the same entries; each entry has a unique index in the range
+ // 0 to maxSize - 1
+ private final int maxSize;
+ private final HashMap<Object, Entry> map = new HashMap<Object, Entry>(); // from Object to Entry
+ private Entry first = null;
+ private Entry last = null;
+}
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/ridljar/com/sun/star/lib/uno/protocols/urp/Marshal.java b/ridljar/com/sun/star/lib/uno/protocols/urp/Marshal.java
new file mode 100644
index 0000000000..106a8736cb
--- /dev/null
+++ b/ridljar/com/sun/star/lib/uno/protocols/urp/Marshal.java
@@ -0,0 +1,355 @@
+/* -*- Mode: Java; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
+/*
+ * 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 com.sun.star.lib.uno.protocols.urp;
+
+import java.io.ByteArrayOutputStream;
+import java.io.DataOutput;
+import java.io.DataOutputStream;
+import java.io.IOException;
+import java.lang.reflect.Array;
+import java.lang.reflect.InvocationTargetException;
+
+import com.sun.star.lib.uno.environments.remote.ThreadId;
+import com.sun.star.lib.uno.typedesc.FieldDescription;
+import com.sun.star.lib.uno.typedesc.TypeDescription;
+import com.sun.star.uno.Any;
+import com.sun.star.uno.Enum;
+import com.sun.star.uno.IBridge;
+import com.sun.star.uno.Type;
+import com.sun.star.uno.TypeClass;
+import com.sun.star.uno.XInterface;
+
+final class Marshal {
+ public Marshal(IBridge bridge, short cacheSize) {
+ this.bridge = bridge;
+ objectIdCache = new Cache(cacheSize);
+ threadIdCache = new Cache(cacheSize);
+ typeCache = new Cache(cacheSize);
+ }
+
+ public void write8Bit(int value) {
+ try {
+ output.writeByte(value);
+ } catch (IOException e) {
+ throw new RuntimeException(e);
+ }
+ }
+
+ public void write16Bit(int value) {
+ try {
+ output.writeShort(value);
+ } catch (IOException e) {
+ throw new RuntimeException(e);
+ }
+ }
+
+ public void writeObjectId(String objectId) {
+ try {
+ if (objectId == null) {
+ writeStringValue(null);
+ write16Bit(0xFFFF);
+ } else {
+ boolean[] found = new boolean[1];
+ int index = objectIdCache.add(found, objectId);
+ writeStringValue(found[0] ? null : objectId);
+ write16Bit(index);
+ }
+ } catch (IOException e) {
+ throw new RuntimeException(e);
+ }
+ }
+
+ public void writeInterface(XInterface object, Type type) {
+ writeObjectId((String) bridge.mapInterfaceTo(object, type));
+ }
+
+ public void writeThreadId(ThreadId threadId) {
+ try {
+ byte[] data = threadId.getBytes();
+ boolean[] found = new boolean[1];
+ int index = threadIdCache.add(found, data);
+ if (found[0]) {
+ writeCompressedNumber(0);
+ } else {
+ writeCompressedNumber(data.length);
+ writeBytes(data);
+ }
+ write16Bit(index);
+ } catch (IOException e) {
+ throw new RuntimeException(e);
+ }
+ }
+
+ public void writeType(TypeDescription type) {
+ try {
+ TypeClass typeClass = type.getTypeClass();
+ if (TypeDescription.isTypeClassSimple(typeClass)) {
+ write8Bit(typeClass.getValue());
+ } else {
+ boolean[] found = new boolean[1];
+ int index = typeCache.add(found, type.getTypeName());
+ write8Bit(typeClass.getValue() | (found[0] ? 0 : 0x80));
+ write16Bit(index);
+ if (!found[0]) {
+ writeStringValue(type.getTypeName());
+ }
+ }
+ } catch (IOException e) {
+ throw new RuntimeException(e);
+ }
+ }
+
+ public void writeValue(TypeDescription type, Object value) {
+ try {
+ switch(type.getTypeClass().getValue()) {
+ case TypeClass.VOID_value:
+ break;
+
+ case TypeClass.BOOLEAN_value:
+ writeBooleanValue((Boolean) value);
+ break;
+
+ case TypeClass.BYTE_value:
+ writeByteValue((Byte) value);
+ break;
+
+ case TypeClass.SHORT_value:
+ case TypeClass.UNSIGNED_SHORT_value:
+ writeShortValue((Short) value);
+ break;
+
+ case TypeClass.LONG_value:
+ case TypeClass.UNSIGNED_LONG_value:
+ writeLongValue((Integer) value);
+ break;
+
+ case TypeClass.HYPER_value:
+ case TypeClass.UNSIGNED_HYPER_value:
+ writeHyperValue((Long) value);
+ break;
+
+ case TypeClass.FLOAT_value:
+ writeFloatValue((Float) value);
+ break;
+
+ case TypeClass.DOUBLE_value:
+ writeDoubleValue((Double) value);
+ break;
+
+ case TypeClass.CHAR_value:
+ writeCharValue((Character) value);
+ break;
+
+ case TypeClass.STRING_value:
+ writeStringValue((String) value);
+ break;
+
+ case TypeClass.TYPE_value:
+ writeTypeValue((Type) value);
+ break;
+
+ case TypeClass.ANY_value:
+ writeAnyValue(value);
+ break;
+
+ case TypeClass.SEQUENCE_value:
+ writeSequenceValue(type, value);
+ break;
+
+ case TypeClass.ENUM_value:
+ writeEnumValue(type, (Enum) value);
+ break;
+
+ case TypeClass.STRUCT_value:
+ writeStructValue(type, value);
+ break;
+
+ case TypeClass.EXCEPTION_value:
+ writeExceptionValue(type, (Exception) value);
+ break;
+
+ case TypeClass.INTERFACE_value:
+ writeInterfaceValue(type, (XInterface) value);
+ break;
+
+ default:
+ throw new IllegalArgumentException("Bad type descriptor " + type);
+ }
+ } catch (ClassNotFoundException e) {
+ throw new RuntimeException(e);
+ } catch (IllegalAccessException e) {
+ throw new RuntimeException(e);
+ } catch (IOException e) {
+ throw new RuntimeException(e);
+ } catch (InvocationTargetException e) {
+ throw new RuntimeException(e);
+ } catch (NoSuchMethodException e) {
+ throw new RuntimeException(e);
+ }
+ }
+
+ public byte[] reset() {
+ byte[] data = buffer.toByteArray();
+ buffer.reset();
+ return data;
+ }
+
+ private void writeBooleanValue(Boolean value) throws IOException {
+ output.writeBoolean(value != null && value.booleanValue());
+ }
+
+ private void writeByteValue(Byte value) {
+ write8Bit(value == null ? 0 : value.byteValue());
+ }
+
+ private void writeShortValue(Short value) {
+ write16Bit(value == null ? 0 : value.shortValue());
+ }
+
+ private void writeLongValue(Integer value) throws IOException {
+ write32Bit(value == null ? 0 : value.intValue());
+ }
+
+ private void writeHyperValue(Long value) throws IOException {
+ output.writeLong(value == null ? 0 : value.longValue());
+ }
+
+ private void writeFloatValue(Float value) throws IOException {
+ output.writeFloat(value == null ? 0 : value.floatValue());
+ }
+
+ private void writeDoubleValue(Double value) throws IOException {
+ output.writeDouble(value == null ? 0 : value.doubleValue());
+ }
+
+ private void writeCharValue(Character value) throws IOException {
+ output.writeChar(value == null ? 0 : value.charValue());
+ }
+
+ private void writeStringValue(String value) throws IOException {
+ if (value == null) {
+ writeCompressedNumber(0);
+ } else {
+ byte[] data = value.getBytes("UTF8");
+ writeCompressedNumber(data.length);
+ writeBytes(data);
+ }
+ }
+
+ private void writeTypeValue(Type value) throws ClassNotFoundException {
+ writeType(
+ TypeDescription.getTypeDescription(
+ value == null ? Type.VOID : value));
+ }
+
+ private void writeAnyValue(Object value) throws ClassNotFoundException {
+ TypeDescription type;
+ if (value == null || value instanceof XInterface) {
+ type = TypeDescription.getTypeDescription(XInterface.class);
+ } else if (value instanceof Any) {
+ Any any = (Any) value;
+ type = TypeDescription.getTypeDescription(any.getType());
+ value = any.getObject();
+ } else if (value.getClass() == Object.class) {
+ // Avoid StackOverflowError:
+ throw new IllegalArgumentException(
+ "Object instance does not represent UNO value");
+ } else {
+ type = TypeDescription.getTypeDescription(value.getClass());
+ }
+ writeType(type);
+ writeValue(type, value);
+ }
+
+ private void writeSequenceValue(TypeDescription type, Object value) throws IOException {
+ if (value == null) {
+ writeCompressedNumber(0);
+ } else {
+ TypeDescription ctype = type.getComponentType();
+ if (ctype.getTypeClass() == TypeClass.BYTE) {
+ byte[] data = (byte[]) value;
+ writeCompressedNumber(data.length);
+ writeBytes(data);
+ } else {
+ int len = Array.getLength(value);
+ writeCompressedNumber(len);
+ for (int i = 0; i < len; ++i) {
+ writeValue(ctype, Array.get(value, i));
+ }
+ }
+ }
+ }
+
+ private void writeEnumValue(TypeDescription type, Enum value) throws IllegalAccessException, IOException, InvocationTargetException, NoSuchMethodException {
+ int n;
+ if (value == null) {
+ n = ((Enum)
+ (type.getZClass().getMethod("getDefault", (Class[]) null).
+ invoke(null, (Object[]) null))).
+ getValue();
+ } else {
+ n = value.getValue();
+ }
+ write32Bit(n);
+ }
+
+ private void writeStructValue(TypeDescription type, Object value) throws IllegalAccessException {
+ FieldDescription[] fields = type.getFieldDescriptions();
+ for (int i = 0; i < fields.length; ++i) {
+ writeValue(
+ fields[i].getTypeDescription(),
+ value == null ? null : fields[i].getField().get(value));
+ }
+ }
+
+ private void writeExceptionValue(TypeDescription type, Exception value) throws IllegalAccessException, IOException {
+ writeStringValue(value == null ? null : value.getMessage());
+ writeStructValue(type, value);
+ }
+
+ private void writeInterfaceValue(TypeDescription type, XInterface value) {
+ writeInterface(value, new Type(type));
+ }
+
+ private void write32Bit(int value) throws IOException {
+ output.writeInt(value);
+ }
+
+ private void writeCompressedNumber(int number) throws IOException {
+ if (number >= 0 && number < 0xFF) {
+ write8Bit(number);
+ } else {
+ write8Bit(0xFF);
+ write32Bit(number);
+ }
+ }
+
+ private void writeBytes(byte[] data) throws IOException {
+ output.write(data);
+ }
+
+ private final ByteArrayOutputStream buffer = new ByteArrayOutputStream();
+ private final DataOutput output = new DataOutputStream(buffer);
+ private final IBridge bridge;
+ private final Cache objectIdCache;
+ private final Cache threadIdCache;
+ private final Cache typeCache;
+}
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/ridljar/com/sun/star/lib/uno/protocols/urp/PendingRequests.java b/ridljar/com/sun/star/lib/uno/protocols/urp/PendingRequests.java
new file mode 100644
index 0000000000..928cdcd631
--- /dev/null
+++ b/ridljar/com/sun/star/lib/uno/protocols/urp/PendingRequests.java
@@ -0,0 +1,65 @@
+/* -*- Mode: Java; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
+/*
+ * 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 com.sun.star.lib.uno.protocols.urp;
+
+import java.util.HashMap;
+import java.util.Stack;
+
+import com.sun.star.lib.uno.environments.remote.ThreadId;
+import com.sun.star.lib.uno.typedesc.MethodDescription;
+
+final class PendingRequests {
+
+ public synchronized void push(ThreadId tid, Item item) {
+ Stack<Item> s = map.get(tid);
+ if (s == null) {
+ s = new Stack<Item>();
+ map.put(tid, s);
+ }
+ s.push(item);
+ }
+
+ public synchronized Item pop(ThreadId tid) {
+ Stack<Item> s = map.get(tid);
+ Item i = s.pop();
+ if (s.empty()) {
+ map.remove(tid);
+ }
+ return i;
+ }
+
+ public static final class Item {
+ public Item(
+ boolean internal, MethodDescription function, Object[] arguments)
+ {
+ this.internal = internal;
+ this.function = function;
+ this.arguments = arguments;
+ }
+
+ public final boolean internal;
+ public final MethodDescription function;
+ public final Object[] arguments;
+ }
+
+ private final HashMap<ThreadId, Stack<Item>> map = new HashMap<ThreadId, Stack<Item>>(); // from ThreadId to Stack of Item
+}
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/ridljar/com/sun/star/lib/uno/protocols/urp/Unmarshal.java b/ridljar/com/sun/star/lib/uno/protocols/urp/Unmarshal.java
new file mode 100644
index 0000000000..af37838fbc
--- /dev/null
+++ b/ridljar/com/sun/star/lib/uno/protocols/urp/Unmarshal.java
@@ -0,0 +1,476 @@
+/* -*- Mode: Java; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
+/*
+ * 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 com.sun.star.lib.uno.protocols.urp;
+
+import java.io.ByteArrayInputStream;
+import java.io.DataInputStream;
+import java.io.IOException;
+import java.io.UnsupportedEncodingException;
+import java.lang.reflect.Array;
+import java.lang.reflect.InvocationTargetException;
+
+import com.sun.star.lib.uno.environments.remote.ThreadId;
+import com.sun.star.lib.uno.typedesc.TypeDescription;
+import com.sun.star.uno.Any;
+import com.sun.star.uno.Enum;
+import com.sun.star.uno.IBridge;
+import com.sun.star.uno.Type;
+import com.sun.star.uno.TypeClass;
+import com.sun.star.uno.XInterface;
+import com.sun.star.lib.uno.typedesc.FieldDescription;
+
+final class Unmarshal {
+ public Unmarshal(IBridge bridge, int cacheSize) {
+ this.bridge = bridge;
+ objectIdCache = new String[cacheSize];
+ threadIdCache = new ThreadId[cacheSize];
+ typeCache = new TypeDescription[cacheSize];
+ reset(new byte[0]);
+ }
+
+ public int read8Bit() {
+ try {
+ return input.readUnsignedByte();
+ } catch (IOException e) {
+ throw new RuntimeException(e);
+ }
+ }
+
+ public int read16Bit() {
+ try {
+ return input.readUnsignedShort();
+ } catch (IOException e) {
+ throw new RuntimeException(e);
+ }
+ }
+
+ public String readObjectId() {
+ try {
+ String id = readStringValue();
+ int index = read16Bit();
+ if (index == 0xFFFF) {
+ if (id.length() == 0) {
+ id = null;
+ }
+ } else {
+ if (id.length() == 0) {
+ id = objectIdCache[index];
+ } else {
+ objectIdCache[index] = id;
+ }
+ }
+ return id;
+ } catch (IOException e) {
+ throw new RuntimeException(e);
+ }
+ }
+
+ public Object readInterface(Type type) {
+ String id = readObjectId();
+ return id == null ? null : bridge.mapInterfaceFrom(id, type);
+ }
+
+ public ThreadId readThreadId() {
+ try {
+ int len = readCompressedNumber();
+ byte[] data ;
+ ThreadId id = null;
+ if (len != 0) {
+ data = new byte[len];
+ readBytes(data);
+ id = new ThreadId(data);
+ }
+ int index = read16Bit();
+ if (index != 0xFFFF) {
+ if (len == 0) {
+ id = threadIdCache[index];
+ } else {
+ threadIdCache[index] = id;
+ }
+ }
+ return id;
+ } catch (IOException e) {
+ throw new RuntimeException(e);
+ }
+ }
+
+ public TypeDescription readType() {
+ int b = read8Bit();
+ TypeClass typeClass = TypeClass.fromInt(b & 0x7F);
+ if (typeClass == null) {
+ throw new RuntimeException(
+ "Reading TYPE with bad type class " + (b & 0x7F));
+ }
+ if (TypeDescription.isTypeClassSimple(typeClass)) {
+ if ((b & 0x80) != 0) {
+ throw new RuntimeException(
+ "Reading TYPE with bad type class/cache flag " + b);
+ }
+ return TypeDescription.getTypeDescription(typeClass);
+ } else {
+ int index = read16Bit();
+ TypeDescription type;
+ if ((b & 0x80) == 0) {
+ if (index >= typeCache.length) {
+ throw new RuntimeException(
+ "Reading TYPE with bad cache index " + index);
+ }
+ type = typeCache[index];
+ if (type == null) {
+ throw new RuntimeException(
+ "Reading TYPE with empty cache index " + index);
+ }
+ } else {
+ try {
+ type = TypeDescription.getTypeDescription(
+ readStringValue());
+ } catch (IOException e) {
+ throw new RuntimeException(e);
+ } catch (ClassNotFoundException e) {
+ throw new RuntimeException(e);
+ }
+ if (index != 0xFFFF) {
+ if (index >= typeCache.length) {
+ throw new RuntimeException(
+ "Reading TYPE with bad cache index " + index);
+ }
+ typeCache[index] = type;
+ }
+ }
+ return type;
+ }
+ }
+
+ public Object readValue(TypeDescription type) {
+ try {
+ switch (type.getTypeClass().getValue()) {
+ case TypeClass.VOID_value:
+ return null;
+
+ case TypeClass.BOOLEAN_value:
+ return readBooleanValue();
+
+ case TypeClass.BYTE_value:
+ return readByteValue();
+
+ case TypeClass.SHORT_value:
+ case TypeClass.UNSIGNED_SHORT_value:
+ return readShortValue();
+
+ case TypeClass.LONG_value:
+ case TypeClass.UNSIGNED_LONG_value:
+ return readLongValue();
+
+ case TypeClass.HYPER_value:
+ case TypeClass.UNSIGNED_HYPER_value:
+ return readHyperValue();
+
+ case TypeClass.FLOAT_value:
+ return readFloatValue();
+
+ case TypeClass.DOUBLE_value:
+ return readDoubleValue();
+
+ case TypeClass.CHAR_value:
+ return readCharValue();
+
+ case TypeClass.STRING_value:
+ return readStringValue();
+
+ case TypeClass.TYPE_value:
+ return readTypeValue();
+
+ case TypeClass.ANY_value:
+ return readAnyValue();
+
+ case TypeClass.SEQUENCE_value:
+ return readSequenceValue(type);
+
+ case TypeClass.ENUM_value:
+ return readEnumValue(type);
+
+ case TypeClass.STRUCT_value:
+ return readStructValue(type);
+
+ case TypeClass.EXCEPTION_value:
+ return readExceptionValue(type);
+
+ case TypeClass.INTERFACE_value:
+ return readInterfaceValue(type);
+
+ default:
+ throw new IllegalArgumentException("Bad type descriptor " + type);
+ }
+ } catch (IOException e) {
+ throw new RuntimeException(e);
+ }
+ }
+
+ public boolean hasMore() {
+ try {
+ return input.available() > 0;
+ } catch (IOException e) {
+ throw new RuntimeException(e);
+ }
+ }
+
+ public void reset(byte[] data) {
+ input = new DataInputStream(new ByteArrayInputStream(data));
+ }
+
+ private Boolean readBooleanValue() throws IOException {
+ return input.readBoolean() ? Boolean.TRUE : Boolean.FALSE;
+ }
+
+ private Byte readByteValue() throws IOException {
+ return Byte.valueOf(input.readByte());
+ }
+
+ private Short readShortValue() throws IOException {
+ return Short.valueOf(input.readShort());
+ }
+
+ private Integer readLongValue() throws IOException {
+ return Integer.valueOf(input.readInt());
+ }
+
+ private Long readHyperValue() throws IOException {
+ return Long.valueOf(input.readLong());
+ }
+
+ private Float readFloatValue() throws IOException {
+ return Float.valueOf(input.readFloat());
+ }
+
+ private Double readDoubleValue() throws IOException {
+ return Double.valueOf(input.readDouble());
+ }
+
+ private Character readCharValue() throws IOException {
+ return Character.valueOf(input.readChar());
+ }
+
+ private String readStringValue() throws IOException {
+ int len = readCompressedNumber();
+ byte[] data = new byte[len];
+ readBytes(data);
+ try {
+ return new String(data, "UTF8");
+ } catch (UnsupportedEncodingException e) {
+ throw new RuntimeException(e);
+ }
+ }
+
+ private Type readTypeValue() {
+ return new Type(readType());
+ }
+
+ private Object readAnyValue() throws IOException {
+ TypeDescription type = readType();
+ switch (type.getTypeClass().getValue()) {
+ case TypeClass.VOID_value:
+ return Any.VOID;
+
+ case TypeClass.BOOLEAN_value:
+ return readBooleanValue();
+
+ case TypeClass.BYTE_value:
+ return readByteValue();
+
+ case TypeClass.SHORT_value:
+ return readShortValue();
+
+ case TypeClass.UNSIGNED_SHORT_value:
+ return new Any(Type.UNSIGNED_SHORT, readShortValue());
+
+ case TypeClass.LONG_value:
+ return readLongValue();
+
+ case TypeClass.UNSIGNED_LONG_value:
+ return new Any(Type.UNSIGNED_LONG, readLongValue());
+
+ case TypeClass.HYPER_value:
+ return readHyperValue();
+
+ case TypeClass.UNSIGNED_HYPER_value:
+ return new Any(Type.UNSIGNED_HYPER, readHyperValue());
+
+ case TypeClass.FLOAT_value:
+ return readFloatValue();
+
+ case TypeClass.DOUBLE_value:
+ return readDoubleValue();
+
+ case TypeClass.CHAR_value:
+ return readCharValue();
+
+ case TypeClass.STRING_value:
+ return readStringValue();
+
+ case TypeClass.TYPE_value:
+ return readTypeValue();
+
+ case TypeClass.SEQUENCE_value:
+ {
+ Object value = readSequenceValue(type);
+ TypeDescription ctype = type.getComponentType();
+ while (ctype.getTypeClass() == TypeClass.SEQUENCE) {
+ ctype = ctype.getComponentType();
+ }
+ switch (ctype.getTypeClass().getValue()) {
+ case TypeClass.UNSIGNED_SHORT_value:
+ case TypeClass.UNSIGNED_LONG_value:
+ case TypeClass.UNSIGNED_HYPER_value:
+ return new Any(new Type(type), value);
+
+ case TypeClass.STRUCT_value:
+ if (ctype.hasTypeArguments()) {
+ return new Any(new Type(type), value);
+ }
+ default:
+ return value;
+ }
+ }
+
+ case TypeClass.ENUM_value:
+ return readEnumValue(type);
+
+ case TypeClass.STRUCT_value:
+ {
+ Object value = readStructValue(type);
+ return type.hasTypeArguments()
+ ? new Any(new Type(type), value) : value;
+ }
+
+ case TypeClass.EXCEPTION_value:
+ return readExceptionValue(type);
+
+ case TypeClass.INTERFACE_value:
+ {
+ Object value = readInterfaceValue(type);
+ return type.getZClass() == XInterface.class
+ ? value : new Any(new Type(type), value);
+ }
+
+ default:
+ throw new RuntimeException(
+ "Reading ANY with bad type " + type.getTypeClass());
+ }
+ }
+
+ private Object readSequenceValue(TypeDescription type) throws IOException {
+ int len = readCompressedNumber();
+ TypeDescription ctype = type.getComponentType();
+ if (ctype.getTypeClass() == TypeClass.BYTE) {
+ byte[] data = new byte[len];
+ readBytes(data);
+ return data;
+ } else {
+ Object value = Array.newInstance(
+ ctype.getTypeClass() == TypeClass.ANY
+ ? Object.class : ctype.getZClass(), len);
+ for (int i = 0; i < len; ++i) {
+ Array.set(value, i, readValue(ctype));
+ }
+ return value;
+ }
+ }
+
+ private Enum readEnumValue(TypeDescription type) throws IOException {
+ try {
+ return (Enum)
+ type.getZClass().getMethod(
+ "fromInt", new Class[] { int.class }).
+ invoke(null, new Object[] { readLongValue() });
+ } catch (IllegalAccessException e) {
+ throw new RuntimeException(e);
+ } catch (InvocationTargetException e) {
+ throw new RuntimeException(e);
+ } catch (NoSuchMethodException e) {
+ throw new RuntimeException(e);
+ }
+ }
+
+ private Object readStructValue(TypeDescription type) {
+ Object value;
+ try {
+ value = type.getZClass().newInstance();
+ } catch (IllegalAccessException e) {
+ throw new RuntimeException(e);
+ } catch (InstantiationException e) {
+ throw new RuntimeException(e);
+ }
+ readFields(type, value);
+ return value;
+ }
+
+ private Exception readExceptionValue(TypeDescription type) throws IOException {
+ Exception value;
+ try {
+ value = (Exception)
+ type.getZClass().getConstructor(new Class[] { String.class }).
+ newInstance(new Object[] { readStringValue() });
+ } catch (IllegalAccessException e) {
+ throw new RuntimeException(e);
+ } catch (InstantiationException e) {
+ throw new RuntimeException(e);
+ } catch (InvocationTargetException e) {
+ throw new RuntimeException(e);
+ } catch (NoSuchMethodException e) {
+ throw new RuntimeException(e);
+ }
+ readFields(type, value);
+ return value;
+ }
+
+ private Object readInterfaceValue(TypeDescription type) {
+ return readInterface(new Type(type));
+ }
+
+ private int readCompressedNumber() throws IOException {
+ int number = read8Bit();
+ return number < 0xFF ? number : input.readInt();
+ }
+
+ private void readBytes(byte[] data) throws IOException {
+ input.readFully(data);
+ }
+
+ private void readFields(TypeDescription type, Object value) {
+ FieldDescription[] fields = type.getFieldDescriptions();
+ for (int i = 0; i < fields.length; ++i) {
+ try {
+ fields[i].getField().set(
+ value,
+ readValue(
+ fields[i].getTypeDescription()));
+ } catch (IllegalAccessException e) {
+ throw new RuntimeException(e);
+ }
+ }
+ }
+
+ private final IBridge bridge;
+ private final String[] objectIdCache;
+ private final ThreadId[] threadIdCache;
+ private final TypeDescription[] typeCache;
+ private DataInputStream input;
+}
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/ridljar/com/sun/star/lib/uno/protocols/urp/UrpMessage.java b/ridljar/com/sun/star/lib/uno/protocols/urp/UrpMessage.java
new file mode 100644
index 0000000000..34cdf70739
--- /dev/null
+++ b/ridljar/com/sun/star/lib/uno/protocols/urp/UrpMessage.java
@@ -0,0 +1,48 @@
+/* -*- Mode: Java; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
+/*
+ * 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 com.sun.star.lib.uno.protocols.urp;
+
+import com.sun.star.lib.uno.environments.remote.Message;
+import com.sun.star.lib.uno.environments.remote.ThreadId;
+import com.sun.star.lib.uno.typedesc.MethodDescription;
+import com.sun.star.lib.uno.typedesc.TypeDescription;
+import com.sun.star.uno.XCurrentContext;
+
+final class UrpMessage extends Message {
+ public UrpMessage(
+ ThreadId threadId, boolean request, String objectId,
+ TypeDescription type, MethodDescription method, boolean synchronous,
+ XCurrentContext currentContext, boolean abnormalTermination,
+ Object result, Object[] arguments, boolean internal)
+ {
+ super(
+ threadId, request, objectId, type, method, synchronous,
+ currentContext, abnormalTermination, result, arguments);
+ this.internal = internal;
+ }
+
+ public boolean isInternal() {
+ return internal;
+ }
+
+ private final boolean internal;
+}
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/ridljar/com/sun/star/lib/uno/protocols/urp/urp.java b/ridljar/com/sun/star/lib/uno/protocols/urp/urp.java
new file mode 100644
index 0000000000..0ce9d35be7
--- /dev/null
+++ b/ridljar/com/sun/star/lib/uno/protocols/urp/urp.java
@@ -0,0 +1,760 @@
+/* -*- Mode: Java; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
+/*
+ * 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 com.sun.star.lib.uno.protocols.urp;
+
+import com.sun.star.bridge.InvalidProtocolChangeException;
+import com.sun.star.bridge.ProtocolProperty;
+import com.sun.star.bridge.XProtocolProperties;
+import com.sun.star.lang.DisposedException;
+import com.sun.star.lib.uno.environments.remote.IProtocol;
+import com.sun.star.lib.uno.environments.remote.Message;
+import com.sun.star.lib.uno.environments.remote.ThreadId;
+import com.sun.star.lib.uno.typedesc.MethodDescription;
+import com.sun.star.lib.uno.typedesc.TypeDescription;
+import com.sun.star.uno.Any;
+import com.sun.star.uno.IBridge;
+import com.sun.star.uno.Type;
+import com.sun.star.uno.TypeClass;
+import com.sun.star.uno.UnoRuntime;
+import com.sun.star.uno.XCurrentContext;
+import java.io.DataInput;
+import java.io.DataInputStream;
+import java.io.DataOutputStream;
+import java.io.IOException;
+import java.io.InputStream;
+import java.io.OutputStream;
+import java.lang.reflect.Array;
+import java.util.ArrayList;
+import java.util.Random;
+import java.util.StringTokenizer;
+
+/**
+ * This class internally relies on the availability of Java UNO type information
+ * for the interface type <code>com.sun.star.bridge.XProtocolProperties</code>,
+ * even though URP itself does not rely on that type.
+ */
+public final class urp implements IProtocol {
+ public urp(
+ IBridge bridge, String attributes, InputStream input,
+ OutputStream output)
+ {
+ this.input = new DataInputStream(input);
+ this.output = new DataOutputStream(output);
+ marshal = new Marshal(bridge, CACHE_SIZE);
+ unmarshal = new Unmarshal(bridge, CACHE_SIZE);
+ forceSynchronous = parseAttributes(attributes);
+ }
+
+ /**
+ *
+ * @see IProtocol#init
+ */
+ public void init() throws IOException {
+ synchronized (monitor) {
+ if (state == STATE_INITIAL0) {
+ sendRequestChange();
+ }
+ }
+ }
+
+ /**
+ *
+ * @see IProtocol#terminate
+ */
+ public void terminate() {
+ synchronized (monitor) {
+ state = STATE_TERMINATED;
+ initialized = true;
+ monitor.notifyAll();
+ }
+ }
+
+ /**
+ *
+ * @see IProtocol#readMessage
+ */
+ public Message readMessage() throws IOException {
+ for (;;) {
+ if (!unmarshal.hasMore()) {
+ unmarshal.reset(readBlock());
+ if (!unmarshal.hasMore()) {
+ throw new IOException("closeConnection message received");
+ }
+ }
+ UrpMessage msg;
+ int header = unmarshal.read8Bit();
+ if ((header & HEADER_LONGHEADER) != 0) {
+ if ((header & HEADER_REQUEST) != 0) {
+ msg = readLongRequest(header);
+ } else {
+ msg = readReply(header);
+ }
+ } else {
+ msg = readShortRequest(header);
+ }
+ if (msg.isInternal()) {
+ handleInternalMessage(msg);
+ } else {
+ return msg;
+ }
+ }
+ }
+
+ /**
+ *
+ * @see IProtocol#writeRequest
+ */
+ public boolean writeRequest(
+ String oid, TypeDescription type, String function, ThreadId tid,
+ Object[] arguments)
+ throws IOException
+ {
+ if (oid.equals(PROPERTIES_OID)) {
+ throw new IllegalArgumentException("illegal OID " + oid);
+ }
+ synchronized (monitor) {
+ while (!initialized) {
+ try {
+ monitor.wait();
+ } catch (InterruptedException e) {
+ Thread.currentThread().interrupt();
+ throw new RuntimeException(e);
+ }
+ }
+ if (state == STATE_TERMINATED) {
+ throw new DisposedException();
+ }
+ return writeRequest(false, oid, type, function, tid, arguments);
+ }
+ }
+
+ /**
+ *
+ * @see IProtocol#writeReply
+ */
+ public void writeReply(boolean exception, ThreadId tid, Object result)
+ throws IOException
+ {
+ synchronized (output) {
+ writeQueuedReleases();
+ int header = HEADER_LONGHEADER;
+ PendingRequests.Item pending = pendingIn.pop(tid);
+ TypeDescription resultType;
+ TypeDescription[] argTypes;
+ Object[] args;
+ if (exception) {
+ header |= HEADER_EXCEPTION;
+ resultType = TypeDescription.getTypeDescription(TypeClass.ANY);
+ argTypes = null;
+ args = null;
+ } else {
+ resultType = pending.function.getReturnSignature();
+ argTypes = pending.function.getOutSignature();
+ args = pending.arguments;
+ }
+ if (!tid.equals(outL1Tid)) {
+ header |= HEADER_NEWTID;
+ outL1Tid = tid;
+ } else {
+ tid = null;
+ }
+ marshal.write8Bit(header);
+ if (tid != null) {
+ marshal.writeThreadId(tid);
+ }
+ marshal.writeValue(resultType, result);
+ if (argTypes != null) {
+ for (int i = 0; i < argTypes.length; ++i) {
+ if (argTypes[i] != null) {
+ marshal.writeValue(
+ argTypes[i].getComponentType(),
+ Array.get(args[i], 0));
+ }
+ }
+ }
+ writeBlock(true);
+ }
+ }
+
+ private void sendRequestChange() throws IOException {
+ if (propertiesTid == null) {
+ propertiesTid = ThreadId.createFresh();
+ }
+ random = randomGenerator.nextInt();
+ writeRequest(
+ true, PROPERTIES_OID,
+ TypeDescription.getTypeDescription(XProtocolProperties.class),
+ PROPERTIES_FUN_REQUEST_CHANGE, propertiesTid,
+ new Object[] { Integer.valueOf(random) });
+ state = STATE_REQUESTED;
+ }
+
+ private void handleInternalMessage(Message message) throws IOException {
+ if (message.isRequest()) {
+ String t = message.getType().getTypeName();
+ if (!t.equals("com.sun.star.bridge.XProtocolProperties")) {
+ throw new IOException(
+ "read URP protocol properties request with unsupported"
+ + " type " + t);
+ }
+ int fid = message.getMethod().getIndex();
+ switch (fid) {
+ case PROPERTIES_FID_REQUEST_CHANGE:
+ checkSynchronousPropertyRequest(message);
+ synchronized (monitor) {
+ switch (state) {
+ case STATE_INITIAL0:
+ case STATE_INITIAL:
+ writeReply(
+ false, message.getThreadId(), Integer.valueOf(1));
+ state = STATE_WAIT;
+ break;
+ case STATE_REQUESTED:
+ int n
+ = ((Integer) message.getArguments()[0]).intValue();
+ if (random < n) {
+ writeReply(
+ false, message.getThreadId(), Integer.valueOf(1));
+ state = STATE_WAIT;
+ } else if (random == n) {
+ writeReply(
+ false, message.getThreadId(), Integer.valueOf(-1));
+ state = STATE_INITIAL;
+ sendRequestChange();
+ } else {
+ writeReply(
+ false, message.getThreadId(), Integer.valueOf(0));
+ }
+ break;
+ default:
+ writeReply(
+ true, message.getThreadId(),
+ new com.sun.star.uno.RuntimeException(
+ "read URP protocol properties requestChange"
+ + " request in illegal state"));
+ break;
+ }
+ }
+ break;
+ case PROPERTIES_FID_COMMIT_CHANGE:
+ checkSynchronousPropertyRequest(message);
+ synchronized (monitor) {
+ if (state == STATE_WAIT) {
+ ProtocolProperty[] p = (ProtocolProperty[])
+ message.getArguments()[0];
+ boolean ok = true;
+ boolean cc = false;
+ int i = 0;
+ for (; i < p.length; ++i) {
+ if (p[i].Name.equals(PROPERTY_CURRENT_CONTEXT)) {
+ cc = true;
+ } else {
+ ok = false;
+ break;
+ }
+ }
+ if (ok) {
+ writeReply(false, message.getThreadId(), null);
+ } else {
+ writeReply(
+ true, message.getThreadId(),
+ new InvalidProtocolChangeException(
+ "", null, p[i], 1));
+ }
+ state = STATE_INITIAL;
+ if (!initialized) {
+ if (cc) {
+ currentContext = true;
+ initialized = true;
+ monitor.notifyAll();
+ } else {
+ sendRequestChange();
+ }
+ }
+ } else {
+ writeReply(
+ true, message.getThreadId(),
+ new com.sun.star.uno.RuntimeException(
+ "read URP protocol properties commitChange"
+ + " request in illegal state"));
+ }
+ }
+ break;
+ default:
+ throw new IOException(
+ "read URP protocol properties request with unsupported"
+ + " function ID " + fid);
+ }
+ } else {
+ synchronized (monitor) {
+ if (state == STATE_COMMITTED) {
+ // commitChange reply:
+ if (!message.isAbnormalTermination()) {
+ currentContext = true;
+ }
+ state = STATE_INITIAL;
+ initialized = true;
+ monitor.notifyAll();
+ } else {
+ // requestChange reply:
+ if (message.isAbnormalTermination()) {
+ // remote side probably does not support negotiation:
+ state = STATE_INITIAL;
+ initialized = true;
+ monitor.notifyAll();
+ } else {
+ int n = ((Integer) message.getResult()).intValue();
+ switch (n) {
+ case -1:
+ case 0:
+ break;
+ case 1:
+ writeRequest(
+ true, PROPERTIES_OID,
+ TypeDescription.getTypeDescription(
+ XProtocolProperties.class),
+ PROPERTIES_FUN_COMMIT_CHANGE, propertiesTid,
+ new Object[] {
+ new ProtocolProperty[] {
+ new ProtocolProperty(
+ PROPERTY_CURRENT_CONTEXT,
+ Any.VOID) } });
+ state = STATE_COMMITTED;
+ break;
+ default:
+ throw new IOException(
+ "read URP protocol properties "
+ + PROPERTIES_FUN_REQUEST_CHANGE
+ + " reply with illegal return value " + n);
+ }
+ }
+ }
+ }
+ }
+ }
+
+ private void checkSynchronousPropertyRequest(Message message)
+ throws IOException
+ {
+ if (!message.isSynchronous()) {
+ throw new IOException(
+ "read URP protocol properties request for synchronous function"
+ + " marked as not SYNCHRONOUS");
+ }
+ }
+
+ private byte[] readBlock() throws IOException {
+ int size = input.readInt();
+ input.readInt(); // ignore count
+ byte[] bytes = new byte[size];
+ input.readFully(bytes);
+ return bytes;
+ }
+
+ private UrpMessage readLongRequest(int header) throws IOException {
+ boolean sync = false;
+ if ((header & HEADER_MOREFLAGS) != 0) {
+ if (unmarshal.read8Bit() != (HEADER_MUSTREPLY | HEADER_SYNCHRONOUS))
+ {
+ throw new IOException(
+ "read URP request with bad MUSTREPLY/SYNCHRONOUS byte");
+ }
+ sync = true;
+ }
+ int funId = (header & HEADER_FUNCTIONID16) != 0
+ ? unmarshal.read16Bit() : unmarshal.read8Bit();
+ if ((header & HEADER_NEWTYPE) != 0) {
+ inL1Type = unmarshal.readType();
+ if (inL1Type.getTypeClass() != TypeClass.INTERFACE) {
+ throw new IOException(
+ "read URP request with non-interface type " + inL1Type);
+ }
+ }
+ if ((header & HEADER_NEWOID) != 0) {
+ inL1Oid = unmarshal.readObjectId();
+ }
+ if ((header & HEADER_NEWTID) != 0) {
+ inL1Tid = unmarshal.readThreadId();
+ }
+ return readRequest(funId, sync);
+ }
+
+ private UrpMessage readShortRequest(int header) throws IOException {
+ int funId = (header & HEADER_FUNCTIONID14) != 0
+ ? ((header & HEADER_FUNCTIONID) << 8) | unmarshal.read8Bit()
+ : header & HEADER_FUNCTIONID;
+ return readRequest(funId, false);
+ }
+
+ private UrpMessage readRequest(int functionId, boolean forcedSynchronous)
+ throws IOException
+ {
+ boolean internal = PROPERTIES_OID.equals(inL1Oid);
+ // inL1Oid may be null in XInstanceProvider.getInstance("")
+ XCurrentContext cc =
+ (currentContext && !internal
+ && functionId != MethodDescription.ID_RELEASE)
+ ? (XCurrentContext) unmarshal.readInterface(
+ new Type(XCurrentContext.class))
+ : null;
+ MethodDescription desc = inL1Type.getMethodDescription(functionId);
+ if (desc == null) {
+ throw new IOException(
+ "read URP request with unsupported function ID " + functionId);
+ }
+ TypeDescription[] inSig = desc.getInSignature();
+ TypeDescription[] outSig = desc.getOutSignature();
+ Object[] args = new Object[inSig.length];
+ for (int i = 0; i < args.length; ++i) {
+ if (inSig[i] != null) {
+ if (outSig[i] != null) {
+ Object inout = Array.newInstance(
+ outSig[i].getComponentType().getZClass(), 1);
+ Array.set(
+ inout, 0,
+ unmarshal.readValue(
+ outSig[i].getComponentType()));
+ args[i] = inout;
+ } else {
+ args[i] = unmarshal.readValue(inSig[i]);
+ }
+ } else {
+ args[i] = Array.newInstance(
+ outSig[i].getComponentType().getZClass(), 1);
+ }
+ }
+ boolean sync = forcedSynchronous || !desc.isOneway();
+ if (sync) {
+ pendingIn.push(
+ inL1Tid, new PendingRequests.Item(internal, desc, args));
+ }
+ return new UrpMessage(
+ inL1Tid, true, inL1Oid, inL1Type, desc, sync, cc, false, null, args,
+ internal);
+ }
+
+ private UrpMessage readReply(int header) {
+ if ((header & HEADER_NEWTID) != 0) {
+ inL1Tid = unmarshal.readThreadId();
+ }
+ PendingRequests.Item pending = pendingOut.pop(inL1Tid);
+ TypeDescription resultType;
+ TypeDescription[] argTypes;
+ Object[] args;
+ boolean exception = (header & HEADER_EXCEPTION) != 0;
+ if (exception) {
+ resultType = TypeDescription.getTypeDescription(TypeClass.ANY);
+ argTypes = null;
+ args = null;
+ } else {
+ resultType = pending.function.getReturnSignature();
+ argTypes = pending.function.getOutSignature();
+ args = pending.arguments;
+ }
+ Object result = resultType == null
+ ? null : unmarshal.readValue(resultType);
+ if (argTypes != null) {
+ for (int i = 0; i < argTypes.length; ++i) {
+ if (argTypes[i] != null) {
+ Array.set(
+ args[i], 0,
+ unmarshal.readValue(
+ argTypes[i].getComponentType()));
+ }
+ }
+ }
+ return new UrpMessage(
+ inL1Tid, false, null, null, null, false, null, exception, result,
+ args, pending.internal);
+ }
+
+ private boolean writeRequest(
+ boolean internal, String oid, TypeDescription type, String function,
+ ThreadId tid, Object[] arguments)
+ throws IOException
+ {
+ MethodDescription desc = type.getMethodDescription(function);
+ synchronized (output) {
+ if (desc.getIndex() == MethodDescription.ID_RELEASE
+ && releaseQueue.size() < MAX_RELEASE_QUEUE_SIZE)
+ {
+ releaseQueue.add(
+ new QueuedRelease(internal, oid, type, desc, tid));
+ return false;
+ } else {
+ writeQueuedReleases();
+ return writeRequest(
+ internal, oid, type, desc, tid, arguments, true);
+ }
+ }
+ }
+
+ private boolean writeRequest(
+ boolean internal, String oid, TypeDescription type,
+ MethodDescription desc, ThreadId tid, Object[] arguments,
+ boolean flush)
+ throws IOException
+ {
+ int funId = desc.getIndex();
+ if (funId < 0 || funId > MAX_FUNCTIONID16) {
+ throw new IllegalArgumentException(
+ "function ID " + funId + " out of range");
+ }
+ boolean forceSync = forceSynchronous
+ && funId != MethodDescription.ID_RELEASE;
+ boolean moreFlags = forceSync && desc.isOneway();
+ boolean longHeader = moreFlags;
+ int header = 0;
+ if (!type.equals(outL1Type)) {
+ longHeader = true;
+ header |= HEADER_NEWTYPE;
+ outL1Type = type;
+ } else {
+ type = null;
+ }
+ if (!oid.equals(outL1Oid)) {
+ longHeader = true;
+ header |= HEADER_NEWOID;
+ outL1Oid = oid;
+ } else {
+ oid = null;
+ }
+ if (!tid.equals(outL1Tid)) {
+ longHeader = true;
+ header |= HEADER_NEWTID;
+ outL1Tid = tid;
+ } else {
+ tid = null;
+ }
+ if (funId > MAX_FUNCTIONID14) {
+ longHeader = true;
+ }
+ if (longHeader) {
+ header |= HEADER_LONGHEADER | HEADER_REQUEST;
+ if (funId > MAX_FUNCTIONID8) {
+ header |= HEADER_FUNCTIONID16;
+ }
+ if (moreFlags) {
+ header |= HEADER_MOREFLAGS;
+ }
+ marshal.write8Bit(header);
+ if (moreFlags) {
+ marshal.write8Bit(HEADER_MUSTREPLY | HEADER_SYNCHRONOUS);
+ }
+ if (funId > MAX_FUNCTIONID8) {
+ marshal.write16Bit(funId);
+ } else {
+ marshal.write8Bit(funId);
+ }
+ if (type != null) {
+ marshal.writeType(type);
+ }
+ if (oid != null) {
+ marshal.writeObjectId(oid);
+ }
+ if (tid != null) {
+ marshal.writeThreadId(tid);
+ }
+ } else {
+ if (funId > HEADER_FUNCTIONID) {
+ marshal.write8Bit(HEADER_FUNCTIONID14 | (funId >> 8));
+ }
+ marshal.write8Bit(funId);
+ }
+ if (currentContext && !internal
+ && funId != MethodDescription.ID_RELEASE)
+ {
+ marshal.writeInterface(
+ UnoRuntime.getCurrentContext(),
+ new Type(XCurrentContext.class));
+ }
+ TypeDescription[] inSig = desc.getInSignature();
+ TypeDescription[] outSig = desc.getOutSignature();
+ for (int i = 0; i < inSig.length; ++i) {
+ if (inSig[i] != null) {
+ if (outSig[i] != null) {
+ marshal.writeValue(
+ outSig[i].getComponentType(),
+ ((Object[]) arguments[i])[0]);
+ } else {
+ marshal.writeValue(
+ inSig[i], arguments[i]);
+ }
+ }
+ }
+ boolean sync = forceSync || !desc.isOneway();
+ if (sync) {
+ pendingOut.push(
+ outL1Tid, new PendingRequests.Item(internal, desc, arguments));
+ }
+ writeBlock(flush);
+ return sync;
+ }
+
+ private void writeBlock(boolean flush) throws IOException {
+ byte[] data = marshal.reset();
+ output.writeInt(data.length);
+ output.writeInt(1);
+ output.write(data);
+ if (flush) {
+ output.flush();
+ }
+ }
+
+ private void writeQueuedReleases() throws IOException {
+ for (int i = releaseQueue.size(); i > 0;) {
+ --i;
+ QueuedRelease r = releaseQueue.get(i);
+ writeRequest(
+ r.internal, r.objectId, r.type, r.method, r.threadId, null,
+ false);
+ releaseQueue.remove(i);
+ }
+ }
+
+ private static boolean parseAttributes(String attributes) {
+ boolean forceSynchronous = true;
+ if (attributes != null) {
+ StringTokenizer t = new StringTokenizer(attributes, ",");
+ while (t.hasMoreTokens()) {
+ String a = t.nextToken();
+ String v = null;
+ int i = a.indexOf('=');
+ if (i >= 0) {
+ v = a.substring(i + 1);
+ a = a.substring(0, i);
+ }
+ if (a.equalsIgnoreCase("ForceSynchronous")) {
+ forceSynchronous = parseBooleanAttributeValue(a, v);
+ } else if (a.equalsIgnoreCase("negotiate")) {
+ // Ignored:
+ parseBooleanAttributeValue(a, v);
+ } else {
+ throw new IllegalArgumentException(
+ "unknown protocol attribute " + a);
+ }
+ }
+ }
+ return forceSynchronous;
+ }
+
+ private static boolean parseBooleanAttributeValue(
+ String attribute, String value)
+ {
+ if (value == null) {
+ throw new IllegalArgumentException(
+ "missing value for protocol attribute " + attribute);
+ }
+ if (value.equals("0")) {
+ return false;
+ } else if (value.equals("1")) {
+ return true;
+ } else {
+ throw new IllegalArgumentException(
+ "bad value " + value + " for protocol attribute " + attribute);
+ }
+ }
+
+ private static final class QueuedRelease {
+ public QueuedRelease(
+ boolean internal, String objectId, TypeDescription type,
+ MethodDescription method, ThreadId threadId)
+ {
+ this.internal = internal;
+ this.objectId = objectId;
+ this.type = type;
+ this.method = method;
+ this.threadId = threadId;
+ }
+
+ public final boolean internal;
+ public final String objectId;
+ public final TypeDescription type;
+ public final MethodDescription method;
+ public final ThreadId threadId;
+ }
+
+ private static final String PROPERTIES_OID = "UrpProtocolProperties";
+ private static final int PROPERTIES_FID_REQUEST_CHANGE = 4;
+ private static final String PROPERTIES_FUN_REQUEST_CHANGE = "requestChange";
+ private static final int PROPERTIES_FID_COMMIT_CHANGE = 5;
+ private static final String PROPERTIES_FUN_COMMIT_CHANGE = "commitChange";
+ private static final String PROPERTY_CURRENT_CONTEXT = "CurrentContext";
+
+ private static final short CACHE_SIZE = 256;
+
+ private static final int HEADER_LONGHEADER = 0x80;
+ private static final int HEADER_REQUEST = 0x40;
+ private static final int HEADER_NEWTYPE = 0x20;
+ private static final int HEADER_NEWOID = 0x10;
+ private static final int HEADER_NEWTID = 0x08;
+ private static final int HEADER_FUNCTIONID16 = 0x04;
+ private static final int HEADER_MOREFLAGS = 0x01;
+ private static final int HEADER_MUSTREPLY = 0x80;
+ private static final int HEADER_SYNCHRONOUS = 0x40;
+ private static final int HEADER_FUNCTIONID14 = 0x40;
+ private static final int HEADER_FUNCTIONID = 0x3F;
+ private static final int HEADER_EXCEPTION = 0x20;
+
+ private static final int MAX_FUNCTIONID16 = 0xFFFF;
+ private static final int MAX_FUNCTIONID14 = 0x3FFF;
+ private static final int MAX_FUNCTIONID8 = 0xFF;
+
+ private static final int STATE_INITIAL0 = 0;
+ private static final int STATE_INITIAL = 1;
+ private static final int STATE_REQUESTED = 2;
+ private static final int STATE_COMMITTED = 3;
+ private static final int STATE_WAIT = 4;
+ private static final int STATE_TERMINATED = 5;
+
+ private static final int MAX_RELEASE_QUEUE_SIZE = 100;
+
+ private static final Random randomGenerator = new Random();
+
+ private final DataInput input;
+ private final DataOutputStream output;
+
+ private final Marshal marshal;
+ private final Unmarshal unmarshal;
+
+ private final boolean forceSynchronous;
+
+ private final PendingRequests pendingIn = new PendingRequests();
+ private final PendingRequests pendingOut = new PendingRequests();
+
+ private final Object monitor = new Object();
+ private int state = STATE_INITIAL0;
+ private boolean initialized = false;
+ private ThreadId propertiesTid = null;
+ private int random;
+ private boolean currentContext = false;
+
+ private ThreadId inL1Tid = null;
+ private String inL1Oid = null;
+ private TypeDescription inL1Type = null;
+
+ private ThreadId outL1Tid = null;
+ private String outL1Oid = null;
+ private TypeDescription outL1Type = null;
+
+ private final ArrayList<QueuedRelease> releaseQueue = new ArrayList<QueuedRelease>(); // of QueuedRelease
+}
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/ridljar/com/sun/star/lib/uno/typedesc/FieldDescription.java b/ridljar/com/sun/star/lib/uno/typedesc/FieldDescription.java
new file mode 100644
index 0000000000..6dcdc99db9
--- /dev/null
+++ b/ridljar/com/sun/star/lib/uno/typedesc/FieldDescription.java
@@ -0,0 +1,78 @@
+/*
+ * 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 com.sun.star.lib.uno.typedesc;
+
+import java.lang.reflect.Field;
+
+/**
+ * Describes non method members.
+ */
+public final class FieldDescription {
+ public FieldDescription(
+ String name, int index, TypeDescription typeDescription, Field field)
+ {
+ this.name = name;
+ this.index = index;
+ this.typeDescription = typeDescription;
+ this.field = field;
+ }
+
+ public String getName() {
+ return name;
+ }
+
+ public boolean isUnsigned() {
+ return MemberDescriptionHelper.isUnsigned(typeDescription);
+ }
+
+ public boolean isAny() {
+ return MemberDescriptionHelper.isAny(typeDescription);
+ }
+
+ public boolean isInterface() {
+ return MemberDescriptionHelper.isInterface(typeDescription);
+ }
+
+ public int getIndex() {
+ return index;
+ }
+
+ /**
+ * Gives the name of this member.
+ * <p>
+ * @return the name
+ */
+ public TypeDescription getTypeDescription() {
+ return typeDescription;
+ }
+
+ /**
+ * Gives native java field of this member.
+ * <p>
+ * @return the java field
+ */
+ public Field getField() {
+ return field;
+ }
+
+ private final String name;
+ private final int index;
+ private final TypeDescription typeDescription;
+ private final Field field;
+}
diff --git a/ridljar/com/sun/star/lib/uno/typedesc/MemberDescriptionHelper.java b/ridljar/com/sun/star/lib/uno/typedesc/MemberDescriptionHelper.java
new file mode 100644
index 0000000000..27a5361f32
--- /dev/null
+++ b/ridljar/com/sun/star/lib/uno/typedesc/MemberDescriptionHelper.java
@@ -0,0 +1,54 @@
+/*
+ * 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 com.sun.star.lib.uno.typedesc;
+
+import com.sun.star.uno.TypeClass;
+
+final class MemberDescriptionHelper {
+ public static boolean isUnsigned(TypeDescription desc) {
+ switch (getElementTypeClass(desc).getValue()) {
+ case TypeClass.UNSIGNED_SHORT_value:
+ case TypeClass.UNSIGNED_LONG_value:
+ case TypeClass.UNSIGNED_HYPER_value:
+ return true;
+
+ default:
+ return false;
+ }
+ }
+
+ public static boolean isAny(TypeDescription desc) {
+ return getElementTypeClass(desc) == TypeClass.ANY;
+ }
+
+ public static boolean isInterface(TypeDescription desc) {
+ return getElementTypeClass(desc) == TypeClass.INTERFACE;
+ }
+
+ private static TypeClass getElementTypeClass(TypeDescription desc) {
+ for (;; desc = desc.getComponentType()) {
+ TypeClass tc = desc.getTypeClass();
+ if (tc != TypeClass.SEQUENCE) {
+ return tc;
+ }
+ }
+ }
+
+ private MemberDescriptionHelper() {} // do not instantiate
+}
diff --git a/ridljar/com/sun/star/lib/uno/typedesc/MethodDescription.java b/ridljar/com/sun/star/lib/uno/typedesc/MethodDescription.java
new file mode 100644
index 0000000000..6cbbb1678f
--- /dev/null
+++ b/ridljar/com/sun/star/lib/uno/typedesc/MethodDescription.java
@@ -0,0 +1,131 @@
+/*
+ * 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 com.sun.star.lib.uno.typedesc;
+
+import java.lang.reflect.Method;
+
+/**
+ * Allows to examine a method in detail. It gives a view to java methods from a UNO point.
+ */
+public final class MethodDescription {
+ MethodDescription(
+ String name, int index, boolean oneway, TypeDescription[] inSignature,
+ TypeDescription[] outSignature, TypeDescription returnSignature,
+ Method method)
+ {
+ this.name = name;
+ this.index = index;
+ this.oneway = oneway;
+ this.inSignature = inSignature;
+ this.outSignature = outSignature;
+ this.returnSignature = returnSignature;
+ this.method = method;
+ }
+
+ MethodDescription(MethodDescription other, int index) {
+ this(
+ other.getName(), index, other.isOneway(), other.getInSignature(),
+ other.getOutSignature(), other.getReturnSignature(),
+ other.getMethod());
+ }
+
+ public String getName() {
+ return name;
+ }
+
+ public boolean isUnsigned() {
+ return MemberDescriptionHelper.isUnsigned(returnSignature);
+ }
+
+ public boolean isAny() {
+ return MemberDescriptionHelper.isAny(returnSignature);
+ }
+
+ public boolean isInterface() {
+ return MemberDescriptionHelper.isInterface(returnSignature);
+ }
+
+ public int getIndex() {
+ return index;
+ }
+
+ /**
+ * Indicates if this method is <code>oneWay</code>,
+ * respectively if this method may become executed asynchronously.
+ * @return true means may execute asynchronously .
+ */
+ public boolean isOneway() {
+ return oneway;
+ }
+
+ /**
+ * Indicates if this method is const.
+ * @return true means it is const.
+ */
+ public boolean isConst() {
+ return false;
+ }
+
+ /**
+ * Gives any array of <code>TypeDescription</code> of
+ * the [in] parameters.
+ * @return the in parameters
+ */
+ public TypeDescription[] getInSignature() {
+ return inSignature;
+ }
+
+ /**
+ * Gives any array of <code>TypeDescription</code> of
+ * the [out] parameters.
+ * @return the out parameters
+ */
+ public TypeDescription[] getOutSignature() {
+ return outSignature;
+ }
+
+ /**
+ * Gives the <code>TypeDescription</code> of
+ * the return type.
+ * @return the return type <code>TypeDescription</code>
+ */
+ public TypeDescription getReturnSignature() {
+ return returnSignature;
+ }
+
+ /**
+ * Gives native java method of this method.
+ * @return the java method
+ */
+ public Method getMethod() {
+ return method;
+ }
+
+ public static final int ID_QUERY_INTERFACE = 0;
+ public static final int ID_ACQUIRE = 1;
+ public static final int ID_RELEASE = 2;
+
+ private final String name;
+ private final int index;
+ private final boolean oneway;
+ private final TypeDescription[] inSignature;
+ private final TypeDescription[] outSignature;
+ private final TypeDescription returnSignature;
+ private final Method method;
+}
diff --git a/ridljar/com/sun/star/lib/uno/typedesc/TypeDescription.java b/ridljar/com/sun/star/lib/uno/typedesc/TypeDescription.java
new file mode 100644
index 0000000000..a3c3bcd528
--- /dev/null
+++ b/ridljar/com/sun/star/lib/uno/typedesc/TypeDescription.java
@@ -0,0 +1,819 @@
+/*
+ * 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 com.sun.star.lib.uno.typedesc;
+
+import com.sun.star.lib.uno.typeinfo.AttributeTypeInfo;
+import com.sun.star.lib.uno.typeinfo.MemberTypeInfo;
+import com.sun.star.lib.uno.typeinfo.MethodTypeInfo;
+import com.sun.star.lib.uno.typeinfo.ParameterTypeInfo;
+import com.sun.star.lib.uno.typeinfo.TypeInfo;
+import com.sun.star.uno.Type;
+import com.sun.star.uno.TypeClass;
+import java.lang.ref.ReferenceQueue;
+import java.lang.ref.SoftReference;
+import java.lang.reflect.Field;
+import java.lang.reflect.Method;
+import java.util.ArrayList;
+import java.util.HashMap;
+
+/**
+ * Supplies information about UNO types. Allows to examine a type
+ * in detail (e.g. it is used for marshaling/unmarshaling).
+ *
+ * @since UDK2.0
+ */
+public final class TypeDescription {
+ public static TypeDescription getTypeDescription(String typeName)
+ throws ClassNotFoundException
+ {
+ Type t = new Type(typeName);
+ if (t.getTypeClass() == TypeClass.UNKNOWN) {
+ if (typeName.startsWith("[]")) {
+ t = new Type(typeName, TypeClass.SEQUENCE);
+ } else {
+ t = new Type(Class.forName(typeName));
+ }
+ }
+ return get(t);
+ }
+
+ public static TypeDescription getTypeDescription(Class<?> zClass) {
+ return getDefinitely(new Type(zClass));
+ }
+
+ public static TypeDescription getTypeDescription(Type type)
+ throws ClassNotFoundException
+ {
+ //TODO: synchronize on type?
+ TypeDescription desc = type.getTypeDescription();
+ if (desc == null) {
+ desc = getTypeDescription(type.getTypeName());
+ type.setTypeDescription(desc);
+ }
+ return desc;
+ }
+
+ public static TypeDescription getTypeDescription(TypeClass typeClass) {
+ switch (typeClass.getValue()) {
+ case TypeClass.VOID_value:
+ return getDefinitely(Type.VOID);
+
+ case TypeClass.BOOLEAN_value:
+ return getDefinitely(Type.BOOLEAN);
+
+ case TypeClass.BYTE_value:
+ return getDefinitely(Type.BYTE);
+
+ case TypeClass.SHORT_value:
+ return getDefinitely(Type.SHORT);
+
+ case TypeClass.UNSIGNED_SHORT_value:
+ return getDefinitely(Type.UNSIGNED_SHORT);
+
+ case TypeClass.LONG_value:
+ return getDefinitely(Type.LONG);
+
+ case TypeClass.UNSIGNED_LONG_value:
+ return getDefinitely(Type.UNSIGNED_LONG);
+
+ case TypeClass.HYPER_value:
+ return getDefinitely(Type.HYPER);
+
+ case TypeClass.UNSIGNED_HYPER_value:
+ return getDefinitely(Type.UNSIGNED_HYPER);
+
+ case TypeClass.FLOAT_value:
+ return getDefinitely(Type.FLOAT);
+
+ case TypeClass.DOUBLE_value:
+ return getDefinitely(Type.DOUBLE);
+
+ case TypeClass.CHAR_value:
+ return getDefinitely(Type.CHAR);
+
+ case TypeClass.STRING_value:
+ return getDefinitely(Type.STRING);
+
+ case TypeClass.TYPE_value:
+ return getDefinitely(Type.TYPE);
+
+ case TypeClass.ANY_value:
+ return getDefinitely(Type.ANY);
+
+ default:
+ return null;
+ }
+ }
+
+ public static boolean isTypeClassSimple(TypeClass typeClass) {
+ return getTypeDescription(typeClass) != null;
+ }
+
+ /**
+ * Gets the <code>TypeDescription</code> of the
+ * super, if it exists.
+ * @return the <code>TypeDescription</code>.
+ */
+ public TypeDescription getSuperType() {
+ // Arbitrarily take the first super type:
+ return superTypes == null || superTypes.length == 0
+ ? null : superTypes[0];
+ }
+
+ /**
+ * Gets the <code>MethodDescription</code> for every
+ * method, if this type is an interface. Otherwise
+ * returns <code>null</code>.
+ * @return the <code>MethodDescription[]</code>.
+ */
+ public MethodDescription[] getMethodDescriptions() {
+ initMethodDescriptions();
+ return methodDescriptions; //TODO: clone?
+ }
+
+ /**
+ * Gets the <code>MethodDescription</code> for the
+ * method with index methodId, if it exists, otherwise
+ * returns <code>null</code>.
+ *
+ * @param methodId the index.
+ *
+ * @return the <code>MethodDescription</code>.
+ */
+ public MethodDescription getMethodDescription(int methodId) {
+ initMethodDescriptions();
+ return methodId < 0
+ ? null
+ : methodId < superMethodDescriptions.length
+ ? superMethodDescriptions[methodId]
+ : (methodId - superMethodDescriptions.length
+ < methodDescriptions.length)
+ ? methodDescriptions[methodId - superMethodDescriptions.length]
+ : null;
+ }
+
+ /**
+ * Gets the <code>MethodDescription</code> for the
+ * method with the name <code>name</code>, if it exists,
+ * otherwise returns <code>null</code>.
+ *
+ * @param name the name of the method.
+ *
+ * @return the <code>MethodDescription</code>.
+ */
+ public MethodDescription getMethodDescription(String name) {
+ initMethodDescriptions();
+ for (int i = 0; i < superMethodDescriptions.length; ++i) {
+ if (superMethodDescriptions[i].getName().equals(name)) {
+ return superMethodDescriptions[i];
+ }
+ }
+ for (int i = 0; i < methodDescriptions.length; ++i) {
+ if (methodDescriptions[i].getName().equals(name)) {
+ return methodDescriptions[i];
+ }
+ }
+ return null;
+ }
+
+ /**
+ * Gets the <code>FieldDescription</code> for every
+ * field, if this type is an interface. Otherwise
+ * returns <code>null</code>.
+ * @return the <code>FieldDescription[]</code>.
+ */
+ public FieldDescription[] getFieldDescriptions() {
+ return fieldDescriptions; //TODO: clone?
+ }
+
+ /**
+ * Gets the <code>FieldDescription</code> for the
+ * field with the name <code>name</code>, if it exists,
+ * otherwise returns <code>null</code>.
+ *
+ * @param name the name of the field.
+ *
+ * @return the <code>FieldDescription</code>.
+ */
+ public FieldDescription getFieldDescription(String name) {
+ for (int i = 0; i < fieldDescriptions.length; ++i) {
+ if (fieldDescriptions[i].getName().equals(name)) {
+ return fieldDescriptions[i];
+ }
+ }
+ return superTypes != null && superTypes.length == 1
+ ? superTypes[0].getFieldDescription(name) : null;
+ }
+
+ /**
+ * Gets the IDL <code>TypeClass</code> of the type.
+ * @return the <code>TypeClass</code>.
+ */
+ public TypeClass getTypeClass() {
+ return typeClass;
+ }
+
+ /**
+ * Gets the component <code>TypeDescription</code> if
+ * this is an array type, otherwise returns <code>null</code>.
+ * @return the <code>TypeDescription</code>
+ */
+ public TypeDescription getComponentType() {
+ return componentType;
+ }
+
+ /**
+ * Gets the (UNO) type name.
+ * <table>
+ * <caption>Mapping from UNO types to type names</caption>
+ * <thead>
+ * <tr><th>UNO type</th><th>type name</th></tr>
+ * </thead>
+ * <tbody>
+ * <tr><td>VOID</td><td><code>"void"</code></td></tr>
+ * <tr><td>BOOLEAN</td><td><code>"boolean"</code></td></tr>
+ * <tr><td>CHAR</td><td><code>"char"</code></td></tr>
+ * <tr><td>BYTE</td><td><code>"byte"</code></td></tr>
+ * <tr><td>SHORT</td><td><code>"short"</code></td></tr>
+ * <tr>
+ * <td>UNSIGNED SHORT</td><td><code>"unsigned short"</code></td>
+ * </tr>
+ * <tr><td>LONG</td><td><code>"long"</code></td></tr>
+ * <tr><td>UNSIGNED LONG</td><td><code>"unsigned long"</code></td></tr>
+ * <tr><td>HYPER</td><td><code>"hyper"</code></td></tr>
+ * <tr>
+ * <td>UNSIGNED HYPER</td><td><code>"unsigned hyper"</code></td>
+ * </tr>
+ * <tr><td>FLOAT</td><td><code>"float"</code></td></tr>
+ * <tr><td>DOUBLE</td><td><code>"double"</code></td></tr>
+ * <tr><td>STRING</td><td><code>"string"</code></td></tr>
+ * <tr><td>TYPE</td><td><code>"type"</code></td></tr>
+ * <tr><td>ANY</td><td><code>"any"</code></td></tr>
+ * <tr>
+ * <td>sequence type of base type <var>T</var></td>
+ * <td><code>"[]"</code> followed by type name for <var>T</var></td>
+ * </tr>
+ * <tr>
+ * <td>enum type named <var>N</var></td>
+ * <td><var>N</var> (see below)</td>
+ * </tr>
+ * <tr>
+ * <td>struct type named <var>N</var></td>
+ * <td><var>N</var> (see below)</td>
+ * </tr>
+ * <tr>
+ * <td>exception type named <var>N</var></td>
+ * <td><var>N</var> (see below)</td>
+ * </tr>
+ * <tr>
+ * <td>interface type named <var>N</var></td>
+ * <td><var>N</var> (see below)</td>
+ * </tr>
+ * </tbody>
+ * </table>
+ * <p>For a UNO type named <var>N</var>, consisting of a sequence of module
+ * names <var>M<sub>1</sub></var>, ..., <var>M<sub>n</sub></var> followed by
+ * a simple name <var>S</var>, the corresponding type name consists of the
+ * same sequence of module names and simple name, with <code>"."</code>
+ * separating the individual elements.</p>
+ * @return the type name.
+ */
+ public String getTypeName() {
+ return typeName;
+ }
+
+ /**
+ * Gets the (Java) array type name.
+ * <p>The array type name is defined to be the Java class name (as returned
+ * by <code>Class.forName</code>) of the Java array class that corresponds
+ * to the UNO sequence type with this type (the UNO type represented by this
+ * <code>TypeDescription</code> instance) as base type. For an
+ * <code>TypeDescription</code> instance representing the UNO type VOID,
+ * the array type name is defined to be
+ * <code>"[Ljava.lang.Void;"</code>.</p>
+ * @return the array type name.
+ */
+ public String getArrayTypeName() {
+ return arrayTypeName;
+ }
+
+ /**
+ * Gets the corresponding java class for the type.
+ * @return the corresponding java class.
+ */
+ public Class<?> getZClass() {
+ return zClass;
+ }
+
+ public boolean hasTypeArguments() {
+ return hasTypeArguments;
+ }
+
+ // @see Object#toString
+ @Override
+ public String toString() {
+ return "[" + getClass().getName() + ": " + getTypeClass() + ", "
+ + getTypeName() + "]";
+ }
+
+ private static TypeDescription getDefinitely(Type type) {
+ try {
+ return get(type);
+ } catch (ClassNotFoundException e) {
+ throw new IllegalArgumentException("this cannot happen: " + e);
+ }
+ }
+
+ private static TypeDescription get(Type type) throws ClassNotFoundException
+ {
+ String typeName = type.getTypeName();
+ TypeDescription desc = cache.get(typeName);
+ if (desc == null) {
+ desc = create(type);
+ cache.put(desc);
+ }
+ return desc;
+ }
+
+ private static TypeDescription create(Type type)
+ throws ClassNotFoundException
+ {
+ TypeClass typeClass = type.getTypeClass();
+ String typeName = type.getTypeName();
+ Class<?> zClass = type.getZClass();
+ if (zClass == null) {
+ throw new ClassNotFoundException("UNO type " + type);
+ }
+ switch (typeClass.getValue()) {
+ case TypeClass.VOID_value:
+ return new TypeDescription(
+ typeClass, typeName, "[Ljava.lang.Void;", zClass, null, null);
+
+ case TypeClass.BOOLEAN_value:
+ return new TypeDescription(
+ typeClass, typeName, "[Z", zClass, null, null);
+
+ case TypeClass.BYTE_value:
+ return new TypeDescription(
+ typeClass, typeName, "[B", zClass, null, null);
+
+ case TypeClass.SHORT_value:
+ case TypeClass.UNSIGNED_SHORT_value:
+ return new TypeDescription(
+ typeClass, typeName, "[S", zClass, null, null);
+
+ case TypeClass.LONG_value:
+ case TypeClass.UNSIGNED_LONG_value:
+ return new TypeDescription(
+ typeClass, typeName, "[I", zClass, null, null);
+
+ case TypeClass.HYPER_value:
+ case TypeClass.UNSIGNED_HYPER_value:
+ return new TypeDescription(
+ typeClass, typeName, "[J", zClass, null, null);
+
+ case TypeClass.FLOAT_value:
+ return new TypeDescription(
+ typeClass, typeName, "[F", zClass, null, null);
+
+ case TypeClass.DOUBLE_value:
+ return new TypeDescription(
+ typeClass, typeName, "[D", zClass, null, null);
+
+ case TypeClass.CHAR_value:
+ return new TypeDescription(
+ typeClass, typeName, "[C", zClass, null, null);
+
+ case TypeClass.STRING_value:
+ return new TypeDescription(
+ typeClass, typeName, "[Ljava.lang.String;", zClass, null, null);
+
+ case TypeClass.TYPE_value:
+ return new TypeDescription(
+ typeClass, typeName, "[Lcom.sun.star.uno.Type;", zClass, null,
+ null);
+
+ case TypeClass.ANY_value:
+ return new TypeDescription(
+ typeClass, typeName, "[Ljava.lang.Object;", zClass, null, null);
+
+ case TypeClass.SEQUENCE_value:
+ {
+ // assert typeName.startsWith("[]");
+ TypeDescription componentType = getTypeDescription(
+ typeName.substring("[]".length()));
+ // assert zClass.getName().startsWith("[");
+ return new TypeDescription(
+ typeClass, typeName, "[" + zClass.getName(), zClass, null,
+ componentType);
+ }
+
+ case TypeClass.ENUM_value:
+ // assert !zClass.getName().startsWith("[");
+ return new TypeDescription(
+ typeClass, typeName, "[L" + zClass.getName() + ";", zClass,
+ null, null);
+
+ case TypeClass.STRUCT_value:
+ {
+ // This code exploits the fact that an instantiated polymorphic
+ // struct type may not be the direct base of a struct type:
+ Class<?> superClass = zClass.getSuperclass();
+ TypeDescription[] superTypes = superClass != Object.class
+ ? new TypeDescription[] { get(new Type(superClass)) }
+ : null;
+ // assert !zClass.getName().startsWith("[");
+ return new TypeDescription(
+ typeClass, typeName, "[L" + zClass.getName() + ";", zClass,
+ superTypes, null);
+ }
+
+ case TypeClass.EXCEPTION_value:
+ {
+ TypeDescription[] superTypes
+ = typeName.equals("com.sun.star.uno.Exception")
+ || typeName.equals("com.sun.star.uno.RuntimeException")
+ ? null
+ : new TypeDescription[] {
+ get(new Type(zClass.getSuperclass())) };
+ // assert !zClass.getName().startsWith("[");
+ return new TypeDescription(
+ typeClass, typeName, "[L" + zClass.getName() + ";", zClass,
+ superTypes, null);
+ }
+
+ case TypeClass.INTERFACE_value:
+ {
+ List superTypes = new List();
+ Class<?>[] interfaces = zClass.getInterfaces();
+ for (int i = 0; i < interfaces.length; ++i) {
+ Type t = new Type(interfaces[i]);
+ if (t.getTypeClass() == TypeClass.INTERFACE) {
+ TypeDescription desc = getDefinitely(t);
+ TypeDescription[] descs = desc.superTypes;
+ for (int j = 0; j < descs.length; ++j) {
+ superTypes.add(descs[j]);
+ }
+ superTypes.add(desc);
+ }
+ }
+ // assert !zClass.getName().startsWith("[");
+ return new TypeDescription(
+ typeClass, typeName, "[L" + zClass.getName() + ";", zClass,
+ superTypes.toArray(), null);
+ }
+
+ default:
+ throw new IllegalArgumentException("given type has bad type class");
+ }
+ }
+
+ private TypeDescription(
+ TypeClass typeClass, String typeName, String arrayTypeName,
+ Class<?> zClass, TypeDescription[] superTypes,
+ TypeDescription componentType)
+ {
+ this.typeClass = typeClass;
+ this.typeName = typeName;
+ this.arrayTypeName = arrayTypeName;
+ this.zClass = zClass;
+ this.superTypes = superTypes;
+ this.componentType = componentType;
+ TypeDescription[] args = calculateTypeArguments();
+ this.hasTypeArguments = args != null;
+ this.fieldDescriptions = calculateFieldDescriptions(args);
+ // methodDescriptions must be initialized lazily, to avoid problems with
+ // circular dependencies (a super-interface that has a sub-interface as
+ // method parameter type; an interface that has a struct as method
+ // parameter type, and the struct has the interface as member type)
+ }
+
+ private synchronized void initMethodDescriptions() {
+ if (methodDescriptions != null || typeClass != TypeClass.INTERFACE) {
+ return;
+ }
+ if (superTypes.length == 0) { // com.sun.star.uno.XInterface
+ superMethodDescriptions = new MethodDescription[0];
+ methodDescriptions = new MethodDescription[] {
+ new MethodDescription(
+ "queryInterface", MethodDescription.ID_QUERY_INTERFACE,
+ false, new TypeDescription[] { getDefinitely(Type.TYPE) },
+ new TypeDescription[] { null }, getDefinitely(Type.ANY),
+ null),
+ new MethodDescription(
+ "acquire", MethodDescription.ID_ACQUIRE, true,
+ new TypeDescription[0], new TypeDescription[0],
+ getDefinitely(Type.VOID), null),
+ new MethodDescription(
+ "release", MethodDescription.ID_RELEASE, true,
+ new TypeDescription[0], new TypeDescription[0],
+ getDefinitely(Type.VOID), null) };
+ } else {
+ int methodOffset = 0;
+ ArrayList<MethodDescription> superList = new ArrayList<MethodDescription>();
+ for (int i = 0; i < superTypes.length; ++i) {
+ MethodDescription[] ds = superTypes[i].getMethodDescriptions();
+ for (int j = 0; j < ds.length; ++j) {
+ superList.add(new MethodDescription(ds[j], methodOffset++));
+ }
+ }
+ superMethodDescriptions = superList.toArray(
+ new MethodDescription[superList.size()]);
+ ArrayList<MethodDescription> directList = new ArrayList<MethodDescription>();
+ TypeInfo[] infos = getTypeInfo();
+ int infoCount = infos == null ? 0 : infos.length;
+ int index = 0;
+ Method[] methods = zClass.getDeclaredMethods();
+ for (int i = 0; i < infoCount;) {
+ if (infos[i] instanceof AttributeTypeInfo) {
+ AttributeTypeInfo info = (AttributeTypeInfo) infos[i++];
+ if (info.getIndex() != index) {
+ throw new IllegalArgumentException(
+ "Bad UNOTYPEINFO for " + zClass
+ + ": entries not ordererd");
+ }
+ String getterName = "get" + info.getName();
+ Method getter = findMethod(methods, getterName);
+ Type t = info.getUnoType();
+ TypeDescription type = t == null
+ ? getTypeDescription(getter.getReturnType(), info)
+ : getDefinitely(t);
+ directList.add(
+ new MethodDescription(
+ getterName, index++ + methodOffset, false,
+ new TypeDescription[0], new TypeDescription[0],
+ type, getter));
+ if (!info.isReadOnly()) {
+ String setterName = "set" + info.getName();
+ Method setter = findMethod(methods, setterName);
+ directList.add(
+ new MethodDescription(
+ setterName, index++ + methodOffset, false,
+ new TypeDescription[] { type },
+ new TypeDescription[] { null },
+ getDefinitely(Type.VOID), setter));
+ }
+ } else {
+ MethodTypeInfo info = (MethodTypeInfo) infos[i++];
+ if (info.getIndex() != index) {
+ throw new IllegalArgumentException(
+ "Bad UNOTYPEINFO for " + zClass
+ + ": entries not ordererd");
+ }
+ Method method = findMethod(methods, info.getName());
+ Class<?>[] params = method.getParameterTypes();
+ TypeDescription[] in = new TypeDescription[params.length];
+ TypeDescription[] out
+ = new TypeDescription[params.length];
+ for (int j = 0; j < params.length; ++j) {
+ ParameterTypeInfo p = null;
+ if (i < infoCount
+ && infos[i] instanceof ParameterTypeInfo
+ && ((ParameterTypeInfo) infos[i]).getIndex() == j)
+ {
+ p = (ParameterTypeInfo) infos[i++];
+ }
+ Type pt = p == null ? null : p.getUnoType();
+ TypeDescription d = pt == null
+ ? getTypeDescription(params[j], p)
+ : getDefinitely(pt);
+ if (p == null || p.isIN()) {
+ in[j] = d;
+ }
+ if (p != null && p.isOUT()) {
+ out[j] = d;
+ }
+ }
+ Type t = info.getUnoType();
+ directList.add(
+ new MethodDescription(
+ info.getName(), index++ + methodOffset,
+ info.isOneway(), in, out,
+ (t == null
+ ? getTypeDescription(method.getReturnType(), info)
+ : getDefinitely(t)),
+ method));
+ }
+ }
+ methodDescriptions = directList.toArray(
+ new MethodDescription[directList.size()]);
+ }
+ }
+
+ private TypeDescription[] calculateTypeArguments() {
+ if (typeClass != TypeClass.STRUCT) {
+ return null;
+ }
+ int i = typeName.indexOf('<');
+ if (i < 0) {
+ return null;
+ }
+ java.util.List<TypeDescription> args = new java.util.ArrayList<TypeDescription>();
+ do {
+ ++i; // skip '<' or ','
+ int j = i;
+ loop:
+ for (int level = 0; j != typeName.length(); ++j) {
+ switch (typeName.charAt(j)) {
+ case ',':
+ if (level == 0) {
+ break loop;
+ }
+ break;
+
+ case '<':
+ ++level;
+ break;
+
+ case '>':
+ if (level == 0) {
+ break loop;
+ }
+ --level;
+ break;
+ }
+ }
+ if (j != typeName.length()) {
+ Type t = new Type(typeName.substring(i, j));
+ if (t.getZClass() == null) {
+ throw new IllegalArgumentException(
+ "UNO type name \"" + typeName
+ + "\" contains bad type argument \""
+ + typeName.substring(i, j) + "\"");
+ }
+ args.add(getDefinitely(t));
+ }
+ i = j;
+ } while (i != typeName.length() && typeName.charAt(i) != '>');
+ if (i != typeName.length() - 1 || typeName.charAt(i) != '>'
+ || args.isEmpty())
+ {
+ throw new IllegalArgumentException(
+ "UNO type name \"" + typeName + "\" is syntactically invalid");
+ }
+ return args.toArray(
+ new TypeDescription[args.size()]);
+ }
+
+ private FieldDescription[] calculateFieldDescriptions(
+ TypeDescription[] typeArguments)
+ {
+ if (typeClass != TypeClass.STRUCT && typeClass != TypeClass.EXCEPTION) {
+ return null;
+ }
+ TypeInfo[] infos = getTypeInfo();
+ int infoCount = infos == null ? 0 : infos.length;
+ TypeDescription superType = getSuperType();
+ FieldDescription[] superDescs = superType == null
+ ? null : superType.getFieldDescriptions();
+ int superCount = superDescs == null ? 0 : superDescs.length;
+ FieldDescription[] descs = new FieldDescription[
+ superCount + infoCount];
+ if (superCount != 0) {
+ System.arraycopy(superDescs, 0, descs, 0, superCount);
+ }
+ for (int i = 0; i < infoCount; ++i) {
+ MemberTypeInfo info = (MemberTypeInfo) infos[i];
+ if (info.getIndex() != i) {
+ throw new IllegalArgumentException(
+ "Bad UNOTYPEINFO for " + zClass + ": entries not ordererd");
+ }
+ Field field;
+ try {
+ field = zClass.getDeclaredField(info.getName());
+ } catch (NoSuchFieldException e) {
+ throw new IllegalArgumentException(
+ "Bad UNOTYPEINFO for " + zClass + ": " + e);
+ }
+ Type t = info.getUnoType();
+ int index = info.getTypeParameterIndex();
+ descs[i + superCount] = new FieldDescription(
+ info.getName(), i + superCount,
+ (index >= 0
+ ? typeArguments[index]
+ : t == null
+ ? getTypeDescription(field.getType(), info)
+ : getDefinitely(t)),
+ field);
+ }
+ return descs;
+ }
+
+ private TypeInfo[] getTypeInfo() {
+ try {
+ return (TypeInfo[])
+ zClass.getDeclaredField("UNOTYPEINFO").get(null);
+ } catch (NoSuchFieldException e) {
+ return null;
+ } catch (IllegalAccessException e) {
+ throw new IllegalArgumentException(
+ "Bad UNOTYPEINFO for " + zClass + ": " + e);
+ }
+ }
+
+ private Method findMethod(Method[] methods, String name) {
+ for (int i = 0; i < methods.length; ++i) {
+ if (methods[i].getName().equals(name)) {
+ return methods[i];
+ }
+ }
+ throw new IllegalArgumentException(
+ "Bad UNOTYPEINFO for " + zClass + ": no method " + name);
+ }
+
+ private static TypeDescription getTypeDescription(
+ Class<?> zClass, TypeInfo typeInfo)
+ {
+ return getDefinitely(
+ new Type(
+ zClass,
+ typeInfo != null
+ && (typeInfo.isUnsigned() || typeInfo.isInterface())));
+ }
+
+ private static final class List {
+
+ public void add(TypeDescription desc) {
+ if (!list.contains(desc)) {
+ list.add(desc);
+ }
+ }
+
+ public TypeDescription[] toArray() {
+ return list.toArray(
+ new TypeDescription[list.size()]);
+ }
+
+ private final ArrayList<TypeDescription> list = new ArrayList<TypeDescription>();
+ }
+
+ private static final class Cache {
+
+ public TypeDescription get(String typeName) {
+ synchronized (map) {
+ cleanUp();
+ Entry e = map.get(typeName);
+ return e == null ? null : (TypeDescription) e.get();
+ }
+ }
+
+ public void put(TypeDescription desc) {
+ synchronized (map) {
+ cleanUp();
+ map.put(desc.getTypeName(), new Entry(desc, queue));
+ }
+ }
+
+ private void cleanUp() {
+ for (;;) {
+ Object tmp = queue.poll();
+ Entry e = (Entry)tmp;
+ if (e == null) {
+ break;
+ }
+ map.remove(e.typeName);
+ }
+ }
+
+ private static final class Entry extends SoftReference<TypeDescription> {
+ public Entry(TypeDescription desc, ReferenceQueue<TypeDescription> queue) {
+ super(desc, queue);
+ typeName = desc.getTypeName();
+ }
+
+ public final String typeName;
+ }
+
+ private final HashMap<String, Entry> map = new HashMap<String, Entry>();
+ private final ReferenceQueue<TypeDescription> queue = new ReferenceQueue<TypeDescription>();
+ }
+
+ private static final Cache cache = new Cache();
+
+ private final TypeClass typeClass;
+ private final String typeName;
+ private final String arrayTypeName;
+ private final Class<?> zClass;
+ private final TypeDescription[] superTypes;
+ private final TypeDescription componentType;
+ private final boolean hasTypeArguments;
+ private final FieldDescription[] fieldDescriptions;
+ private MethodDescription[] methodDescriptions = null;
+ private MethodDescription[] superMethodDescriptions;
+}
diff --git a/ridljar/com/sun/star/lib/uno/typeinfo/AttributeTypeInfo.java b/ridljar/com/sun/star/lib/uno/typeinfo/AttributeTypeInfo.java
new file mode 100644
index 0000000000..3230528e14
--- /dev/null
+++ b/ridljar/com/sun/star/lib/uno/typeinfo/AttributeTypeInfo.java
@@ -0,0 +1,86 @@
+/*
+ * 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 com.sun.star.lib.uno.typeinfo;
+
+import com.sun.star.uno.Type;
+
+public class AttributeTypeInfo extends TypeInfo
+{
+ protected int m_index;
+ private final Type m_unoType; // @since UDK 3.2
+
+ /**
+ Create an attribute type info with a UNO type that cannot unambiguously
+ be represented as a Java&nbsp;1.2 type.
+
+ @param name the name of this attribute; must not be <code>null</code>
+
+ @param index the index among the direct members
+
+ @param flags any flags (<code>READONLY</code>, <code>BOUND</code>,
+ <code>UNSIGNED</code>, <code>ANY</code>, <code>INTERFACE</code>)
+
+ @param unoType the exact UNO type; or <code>null</code> if the UNO type
+ is already unambiguously represented by the Java&nbsp;1.2 type
+
+ @since UDK 3.2
+ */
+ public AttributeTypeInfo(String name, int index, int flags, Type unoType) {
+ super(name, flags);
+ m_index = index;
+ m_unoType = unoType;
+ }
+
+ public AttributeTypeInfo(String name, int index, int flags)
+ {
+ this(name, index, flags, null);
+ }
+
+ public int getIndex()
+ {
+ return m_index;
+ }
+
+ public boolean isReadOnly()
+ {
+ return (m_flags & TypeInfo.READONLY) != 0;
+ }
+
+ /**
+ Returns the status of the 'bound' flag.
+
+ @since UDK 3.2
+ */
+ public final boolean isBound() {
+ return (m_flags & TypeInfo.BOUND) != 0;
+ }
+
+ /**
+ Get the exact UNO type of this attribute type info, in case it cannot
+ unambiguously be represented as a Java&nbsp;1.2 type.
+
+ @return the exact UNO type of this attribute type info, or
+ <code>null</code> if the UNO type is already unambiguously represented by
+ the Java&nbsp;1.2 type
+
+ @since UDK 3.2
+ */
+ public final Type getUnoType() {
+ return m_unoType;
+ }
+}
diff --git a/ridljar/com/sun/star/lib/uno/typeinfo/ConstantTypeInfo.java b/ridljar/com/sun/star/lib/uno/typeinfo/ConstantTypeInfo.java
new file mode 100644
index 0000000000..2676718cf9
--- /dev/null
+++ b/ridljar/com/sun/star/lib/uno/typeinfo/ConstantTypeInfo.java
@@ -0,0 +1,32 @@
+/*
+ * 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 com.sun.star.lib.uno.typeinfo;
+
+/**
+ @deprecated <code>UNOTYPEINFO</code> for constants is not needed
+ */
+@Deprecated
+public class ConstantTypeInfo extends TypeInfo
+{
+ public ConstantTypeInfo(String name, int flags)
+ {
+ super(name, flags);
+ }
+}
+
+
diff --git a/ridljar/com/sun/star/lib/uno/typeinfo/MemberTypeInfo.java b/ridljar/com/sun/star/lib/uno/typeinfo/MemberTypeInfo.java
new file mode 100644
index 0000000000..5b3f669fee
--- /dev/null
+++ b/ridljar/com/sun/star/lib/uno/typeinfo/MemberTypeInfo.java
@@ -0,0 +1,96 @@
+/*
+ * 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 com.sun.star.lib.uno.typeinfo;
+
+import com.sun.star.uno.Type;
+
+public class MemberTypeInfo extends TypeInfo
+{
+ int m_index;
+ private final Type m_unoType; // @since UDK 3.2
+ private final int m_typeParameterIndex; // @since UDK 3.2
+
+ /**
+ Create a member type info with a UNO type that cannot unambiguously be
+ represented as a Java&nbsp;1.2 type.
+
+ @param name the name of this member; must not be <code>null</code>
+
+ @param index the index among the direct members
+
+ @param flags any flags (<code>UNSIGNED</code>, <code>ANY</code>,
+ <code>INTERFACE</code>, <code>TYPE_PARAMETER</code>)
+
+ @param unoType the exact UNO type; or <code>null</code> if the UNO type
+ is already unambiguously represented by the Java&nbsp;1.2 type
+
+ @param typeParameterIndex the index of the type parameter that determines
+ the type of this parameterized member; or <code>-1</code> if this member
+ is of an explicit type, or is the member of a plain struct type
+
+ @since UDK 3.2
+ */
+ public MemberTypeInfo(
+ String name, int index, int flags, Type unoType, int typeParameterIndex)
+ {
+ super(name, flags);
+ m_index = index;
+ m_unoType = unoType;
+ m_typeParameterIndex = typeParameterIndex;
+ }
+
+ public MemberTypeInfo(String name, int index, int flags )
+ {
+ this(name, index, flags, null, -1);
+ }
+
+ public int getIndex()
+ {
+ return m_index;
+ }
+
+ /**
+ Get the exact UNO type of this member type info, in case it cannot
+ unambiguously be represented as a Java&nbsp;1.2 type.
+
+ @return the exact UNO type of this member type info, or <code>null</code>
+ if the UNO type is already unambiguously represented by the Java&nbsp;1.2
+ type
+
+ @since UDK 3.2
+ */
+ public final Type getUnoType() {
+ return m_unoType;
+ }
+
+ /**
+ Returns the index of the type parameter that determines the parameterized
+ type of this member.
+
+ @return the index of the type parameter that determines the type of this
+ parameterized member; if this member is of an explicit type, or is the
+ member of a plain struct type, <code>-1</code> is returned
+
+ @since UDK 3.2
+ */
+ public final int getTypeParameterIndex() {
+ return m_typeParameterIndex;
+ }
+}
+
+
diff --git a/ridljar/com/sun/star/lib/uno/typeinfo/MethodTypeInfo.java b/ridljar/com/sun/star/lib/uno/typeinfo/MethodTypeInfo.java
new file mode 100644
index 0000000000..319e63514c
--- /dev/null
+++ b/ridljar/com/sun/star/lib/uno/typeinfo/MethodTypeInfo.java
@@ -0,0 +1,89 @@
+/*
+ * 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 com.sun.star.lib.uno.typeinfo;
+
+import com.sun.star.uno.Type;
+
+public class MethodTypeInfo extends TypeInfo
+{
+ protected int m_index;
+ private final Type m_unoType; // @since UDK 3.2
+
+ /**
+ Create a method type info with a UNO return type that cannot
+ unambiguously be represented as a Java&nbsp;1.2 type.
+
+ @param name the name of this method; must not be <code>null</code>
+
+ @param index the index among the direct members
+
+ @param flags any flags (<code>ONEWAY</code>, <code>UNSIGNED</code>,
+ <code>ANY</code>, <code>INTERFACE</code>)
+
+ @param unoType the exact UNO return type; or <code>null</code> if the UNO
+ type is already unambiguously represented by the Java&nbsp;1.2 type
+
+ @since UDK 3.2
+ */
+ public MethodTypeInfo(String name, int index, int flags, Type unoType) {
+ super(name, flags);
+ m_index = index;
+ m_unoType = unoType;
+ }
+
+ public MethodTypeInfo(String name, int index, int flags)
+ {
+ this(name, index, flags, null);
+ }
+
+ public int getIndex()
+ {
+ return m_index;
+ }
+
+ public boolean isReturnUnsigned()
+ {
+ return isUnsigned();
+ }
+
+ public boolean isOneway()
+ {
+ return (m_flags & TypeInfo.ONEWAY) != 0;
+ }
+
+ public boolean isConst()
+ {
+ return (m_flags & TypeInfo.CONST) != 0;
+ }
+
+ /**
+ Get the exact UNO return type of this method type info, in case it cannot
+ unambiguously be represented as a Java&nbsp;1.2 type.
+
+ @return the exact UNO return type of this method type info, or
+ <code>null</code> if the UNO type is already unambiguously represented by
+ the Java&nbsp;1.2 type
+
+ @since UDK 3.2
+ */
+ public final Type getUnoType() {
+ return m_unoType;
+ }
+}
+
+
diff --git a/ridljar/com/sun/star/lib/uno/typeinfo/ParameterTypeInfo.java b/ridljar/com/sun/star/lib/uno/typeinfo/ParameterTypeInfo.java
new file mode 100644
index 0000000000..f15ddc816a
--- /dev/null
+++ b/ridljar/com/sun/star/lib/uno/typeinfo/ParameterTypeInfo.java
@@ -0,0 +1,105 @@
+/*
+ * 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 com.sun.star.lib.uno.typeinfo;
+
+import com.sun.star.uno.Type;
+
+public class ParameterTypeInfo extends TypeInfo
+{
+ protected int m_index;
+ protected String m_methodName;
+ private final Type m_unoType; // @since UDK 3.2
+
+ /**
+ Create a parameter type info with a UNO type that cannot unambiguously be
+ represented as a Java&nbsp;1.2 type.
+
+ @param name the name of this parameter; must not be <code>null</code>
+
+ @param methodName the name of the method; must not be <code>null</code>
+
+ @param index the index among the parameters
+
+ @param flags any flags (<code>IN</code>, <code>OUT</code>,
+ <code>UNSIGNED</code>, <code>ANY</code>, <code>INTERFACE</code>)
+
+ @param unoType the exact UNO type; or <code>null</code> if the UNO type
+ is already unambiguously represented by the Java&nbsp;1.2 type
+
+ @since UDK 3.2
+ */
+ public ParameterTypeInfo(
+ String name, String methodName, int index, int flags, Type unoType)
+ {
+ super(name, flags);
+ m_index = index;
+ m_methodName = methodName;
+ m_unoType = unoType;
+ }
+
+ public ParameterTypeInfo(String name, String methodName, int index, int flags)
+ {
+ this(name, methodName, index, flags, null);
+ }
+
+ public String getMethodName()
+ {
+ return m_methodName;
+ }
+
+ public int getIndex()
+ {
+ return m_index;
+ }
+
+ public boolean isIN()
+ {
+ return ((m_flags & TypeInfo.IN) != 0 ||
+ (m_flags & (TypeInfo.IN | TypeInfo.OUT)) == 0); // nothing set => IN
+ }
+
+ public boolean isOUT()
+ {
+ return (m_flags & TypeInfo.OUT) != 0;
+ }
+
+ public boolean isINOUT()
+ {
+ return (m_flags & (TypeInfo.IN | TypeInfo.OUT)) == (TypeInfo.IN | TypeInfo.OUT);
+ }
+
+ /**
+ Get the exact UNO type of this parameter type info, in case it cannot
+ unambiguously be represented as a Java&nbsp;1.2 type.
+
+ <p>If this is an out or in&ndash;out parameter, the UNO type must be a
+ sequence type, taking into account that such a parameter is represented
+ in Java as a parameter of array type.</p>
+
+ @return the exact UNO type of this parameter type info, or
+ <code>null</code> if the UNO type is already unambiguously represented by
+ the Java&nbsp;1.2 type
+
+ @since UDK 3.2
+ */
+ public final Type getUnoType() {
+ return m_unoType;
+ }
+}
+
+
diff --git a/ridljar/com/sun/star/lib/uno/typeinfo/TypeInfo.java b/ridljar/com/sun/star/lib/uno/typeinfo/TypeInfo.java
new file mode 100644
index 0000000000..2503029fe0
--- /dev/null
+++ b/ridljar/com/sun/star/lib/uno/typeinfo/TypeInfo.java
@@ -0,0 +1,76 @@
+/*
+ * 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 com.sun.star.lib.uno.typeinfo;
+
+
+/** Defines a class to describe additional type information.
+ */
+public class TypeInfo
+{
+ public static final int IN = 0x00000001;
+ public static final int OUT = 0x00000002;
+ public static final int UNSIGNED = 0x00000004;
+ public static final int READONLY = 0x00000008;
+ public static final int ONEWAY = 0x00000010;
+ public static final int CONST = 0x00000020;
+ public static final int ANY = 0x00000040;
+ public static final int INTERFACE = 0x00000080;
+
+ /**
+ Marks an extended attribute of an interface type as bound.
+
+ <p>Only used in the <code>flags</code> argument of the
+ <code>AttributeTypeInfo</code> constructors.</p>
+
+ @since UDK 3.2
+ */
+ public static final int BOUND = 0x00000100;
+
+ protected int m_flags;
+ protected String m_name;
+
+ public TypeInfo(String name, int flags)
+ {
+ m_name = name;
+ m_flags = flags;
+ }
+
+ public String getName()
+ {
+ return m_name;
+ }
+
+ public int getFlags() {
+ return m_flags;
+ }
+
+ public boolean isUnsigned()
+ {
+ return (m_flags & TypeInfo.UNSIGNED) != 0;
+ }
+
+ public boolean isAny()
+ {
+ return (m_flags & TypeInfo.ANY) != 0;
+ }
+
+ public boolean isInterface()
+ {
+ return (m_flags & TypeInfo.INTERFACE) != 0;
+ }
+}
diff --git a/ridljar/com/sun/star/lib/util/AsynchronousFinalizer.java b/ridljar/com/sun/star/lib/util/AsynchronousFinalizer.java
new file mode 100644
index 0000000000..588b8fe388
--- /dev/null
+++ b/ridljar/com/sun/star/lib/util/AsynchronousFinalizer.java
@@ -0,0 +1,117 @@
+/* -*- Mode: Java; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
+/*
+ * 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 com.sun.star.lib.util;
+
+import java.util.LinkedList;
+
+/**
+ * Helper class to asynchronously execute finalize methods.
+ *
+ * <p>Current JVMs seem not to be robust against long-running finalize methods,
+ * in that such long-running finalize methods may lead to OutOfMemoryErrors.
+ * This class mitigates the problem by asynchronously shifting the bodies of
+ * potentially long-running finalize methods into an extra thread. Classes that
+ * make use of this in their finalize methods are the proxies used in the
+ * intra-process JNI UNO bridge and the inter-process Java URP UNO bridge (where
+ * in both cases finalizers lead to synchronous UNO release calls).</p>
+ *
+ * <p>Irrespective whether JVMs are getting more mature and should no longer
+ * have problems with long-running finalize methods, at least the JNI UNO bridge
+ * needs some way to stop finalization of proxies (to C++ objects) well before
+ * process exit, as provided by drain().</p>
+ */
+public final class AsynchronousFinalizer {
+ public AsynchronousFinalizer() {
+ thread = new Thread("AsynchronousFinalizer") {
+ @Override
+ public void run() {
+ for (;;) {
+ Job j;
+ synchronized (queue) {
+ for (;;) {
+ if (done) {
+ return;
+ }
+ if (!queue.isEmpty()) {
+ break;
+ }
+ try {
+ queue.wait();
+ } catch (InterruptedException e) {
+ return;
+ }
+ }
+ j = queue.remove(0);
+ }
+ try {
+ j.run();
+ } catch (Throwable e) {}
+ }
+ }
+ };
+ thread.start();
+ }
+
+ /**
+ * Add a job to be executed asynchronously.
+ *
+ * <p>The run method of the given job is called exactly once. If it terminates
+ * abnormally by throwing any Throwable, that is ignored.</p>
+ *
+ * @param job represents the body of some finalize method; must not be null.
+ */
+ public void add(Job job) {
+ synchronized (queue) {
+ boolean first = queue.isEmpty();
+ queue.add(job);
+ if (first) {
+ queue.notify();
+ }
+ }
+ }
+
+ public void drain() throws InterruptedException {
+ synchronized (queue) {
+ done = true;
+ queue.notify();
+ }
+ // tdf#123481 Only join if we are not in our own thread, else we have a deadlock
+ if (Thread.currentThread() != thread)
+ thread.join();
+ }
+
+ /**
+ * An interface to represent bodies of finalize methods.
+ *
+ * Similar to <code>Runnable</code>, except that the run method may throw any
+ * <code>Throwable</code> (which is effectively ignored by
+ * <code>AsynchronousFinalizer.add</code>, similar to any <code>Throwables</code>
+ * raised by finalize being ignored).
+ */
+ public interface Job {
+ void run() throws Throwable;
+ }
+
+ private final LinkedList<Job> queue = new LinkedList<Job>();
+ private final Thread thread;
+ private boolean done = false;
+}
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/ridljar/com/sun/star/lib/util/DisposeListener.java b/ridljar/com/sun/star/lib/util/DisposeListener.java
new file mode 100644
index 0000000000..6fdde2a8d7
--- /dev/null
+++ b/ridljar/com/sun/star/lib/util/DisposeListener.java
@@ -0,0 +1,34 @@
+/*
+ * 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 com.sun.star.lib.util;
+
+/**
+ * Counterpart to <code>DisposeNotifier</code>.
+ *
+ * @see DisposeNotifier
+ */
+public interface DisposeListener {
+ /**
+ * Callback fired by a <code>DisposeNotifier</code> once it is disposed.
+ *
+ * @param source the <code>DisposeNotifier</code> that fires the callback;
+ * will never be <code>null</code>
+ */
+ void notifyDispose(DisposeNotifier source);
+}
diff --git a/ridljar/com/sun/star/lib/util/DisposeNotifier.java b/ridljar/com/sun/star/lib/util/DisposeNotifier.java
new file mode 100644
index 0000000000..ebe0008d07
--- /dev/null
+++ b/ridljar/com/sun/star/lib/util/DisposeNotifier.java
@@ -0,0 +1,44 @@
+/*
+ * 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 com.sun.star.lib.util;
+
+/**
+ * Optional interface to be implemented by objects stored in a
+ * <code>WeakMap</code>.
+ *
+ * @see WeakMap
+ */
+public interface DisposeNotifier {
+ /**
+ * Adds a dispose listener, to be notified when this object is disposed.
+ *
+ * <p>It is unspecified what happens when the same listener is added
+ * multiple times.</p>
+ *
+ * <p>It is unspecified exactly when the <code>notifyDispose</code> callback
+ * is fired: immediately before the notifier is disposed, while it is in the
+ * process of disposing, or some time after it got disposed. But even if
+ * adding a listener to an already disposed notifier, the listener must
+ * eventually receive a <code>notifyDispose</code> callback.</p>
+ *
+ * @param listener a dispose listener, to be notified when this object is
+ * disposed; must not be <code>null</code>
+ */
+ void addDisposeListener(DisposeListener listener);
+}
diff --git a/ridljar/com/sun/star/lib/util/NativeLibraryLoader.java b/ridljar/com/sun/star/lib/util/NativeLibraryLoader.java
new file mode 100644
index 0000000000..eb5c6af34e
--- /dev/null
+++ b/ridljar/com/sun/star/lib/util/NativeLibraryLoader.java
@@ -0,0 +1,132 @@
+/* -*- Mode: Java; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
+/*
+ * 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 com.sun.star.lib.util;
+
+import java.io.File;
+import java.net.URL;
+import java.net.URLClassLoader;
+
+/**
+ * Helper functions to locate and load native files.
+ *
+ * <p>The methods in this class are designed to find the requested resources in
+ * as many cases as possible. They search various places, roughly from most
+ * specific to most general. This works well if a component is known to bring
+ * with it a certain resource, and that resource has to be found. However, it
+ * might not work very well in cases where you want to check whether a
+ * component brings with it a certain resource or not: a similarly named
+ * resource from another component might be found by the eager search
+ * algorithm.</p>
+ */
+public final class NativeLibraryLoader {
+ /**
+ * Load a system library, using a given class loader to locate the library.
+ *
+ * <p>This is similar to <code>System.loadLibrary</code>.</p>
+ *
+ * @param loader a class loader; may be null.
+ * @param libname the library name; how this name is mapped to a system
+ * library name is system dependent.
+ */
+ public static void loadLibrary(ClassLoader loader, String libname) {
+ String sysname = System.mapLibraryName(libname);
+ // At least Oracle's 1.7.0_51 now maps to .dylib rather than .jnilib:
+ if (System.getProperty("os.name").startsWith("Mac")
+ && sysname.endsWith(".dylib"))
+ {
+ sysname
+ = sysname.substring(0, sysname.length() - "dylib".length())
+ + "jnilib";
+ }
+ File path = getResource(loader, sysname);
+ if (path == null) {
+ // If the library cannot be found as a class loader resource, try
+ // the global System.loadLibrary as a last resort:
+ System.loadLibrary(libname);
+ } else {
+ System.load(path.getAbsolutePath());
+ }
+ }
+
+ /**
+ * Locate a system resource, using a given class loader.
+ *
+ * <p>This is similar to <code>ClassLoader.getResource</code>, but only works
+ * for local resources (local files), and adds additional functionality for
+ * <code>URLClassLoaders</code>.</p>
+ *
+ * @param loader a class loader; may be null.
+ * @param name a resource name (that is, the name of a file).
+ * @return a File locating the resource, or null if the resource was not
+ * found.
+ */
+ public static File getResource(ClassLoader loader, String name) {
+ if (loader != null) {
+ File path = UrlToFileMapper.mapUrlToFile(loader.getResource(name));
+ if (path != null) {
+ return path;
+ }
+ }
+ // URLClassLoaders work on lists of URLs, which are typically URLs
+ // locating JAR files (scheme://auth/dir1/dir2/some.jar). The following
+ // code looks for resource name beside the JAR file
+ // (scheme://auth/dir1/dir2/name) and one directory up
+ // (scheme://auth/dir1/name). The second step is important in a typical
+ // OOo installation, where the JAR files are in the program/classes
+ // directory while the shared libraries are in the program directory.
+ if (!(loader instanceof URLClassLoader)) {
+ return null;
+ }
+ URL[] urls = ((URLClassLoader) loader).getURLs();
+ for (int i = 0; i < urls.length; ++i) {
+ File path = UrlToFileMapper.mapUrlToFile(urls[i]);
+ if (path != null) {
+ File dir = path.isDirectory() ? path : path.getParentFile();
+ if (dir != null) {
+ path = new File(dir, name);
+ if (path.exists()) {
+ return path;
+ }
+ dir = dir.getParentFile();
+ if (dir != null) {
+ path = new File(dir, name);
+ if (path.exists()) {
+ return path;
+ }
+ // On macOS, dir is now the Resources dir,
+ // we want to look in Frameworks
+ if (System.getProperty("os.name").startsWith("Mac")
+ && dir.getName().equals("Resources")) {
+ dir = dir.getParentFile();
+ path = new File(dir, "Frameworks/" + name);
+ if (path.exists()) {
+ return path;
+ }
+ }
+ }
+ }
+ }
+ }
+ return null;
+ }
+
+ private NativeLibraryLoader() {} // do not instantiate
+}
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/ridljar/com/sun/star/lib/util/StringHelper.java b/ridljar/com/sun/star/lib/util/StringHelper.java
new file mode 100644
index 0000000000..de8b5253aa
--- /dev/null
+++ b/ridljar/com/sun/star/lib/util/StringHelper.java
@@ -0,0 +1,46 @@
+/* -*- Mode: Java; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
+/*
+ * 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 com.sun.star.lib.util;
+
+/**
+ * jurt.jar internal string helper methods.
+ */
+public final class StringHelper
+{
+ private StringHelper() {} // do not instantiate
+
+ public static String replace(String str, char from, String to) {
+ StringBuffer b = new StringBuffer();
+ for (int i = 0;;) {
+ int j = str.indexOf(from, i);
+ if (j == -1) {
+ b.append(str.substring(i));
+ break;
+ } else {
+ b.append(str.substring(i, j));
+ b.append(to);
+ i = j + 1;
+ }
+ }
+ return b.toString();
+ }
+}
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/ridljar/com/sun/star/lib/util/UrlToFileMapper.java b/ridljar/com/sun/star/lib/util/UrlToFileMapper.java
new file mode 100644
index 0000000000..131890f54f
--- /dev/null
+++ b/ridljar/com/sun/star/lib/util/UrlToFileMapper.java
@@ -0,0 +1,94 @@
+/* -*- Mode: Java; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
+/*
+ * 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 com.sun.star.lib.util;
+
+import java.io.File;
+import java.io.UnsupportedEncodingException;
+import java.net.URI;
+import java.net.URISyntaxException;
+import java.net.URL;
+import java.net.URLEncoder;
+
+/**
+ * Maps Java URL representations to File representations, on any Java version.
+ *
+ * This used to be used to do URL to File mapping in pre-Java1.4 days, but since
+ * we now require Java 1.5, it is largely unnecessary.
+ *
+ * @since UDK 3.2.8
+ */
+public final class UrlToFileMapper {
+
+ /**
+ * Maps Java URL representations to File representations.
+ *
+ * @param url some URL, possibly null.
+ * @return a corresponding File, or null on failure.
+ */
+ public static File mapUrlToFile(URL url) {
+ if (url == null) {
+ return null;
+ } else {
+ try {
+ // where encodedUrl is url.toString(), but since that may contain
+ // unsafe characters (e.g., space, " "), it is encoded, as otherwise
+ // the URI constructor might throw java.net.URISyntaxException (in
+ // Java 1.5, URL.toURI might be used instead).
+ String encodedUrl = encode(url.toString());
+ URI uri = new URI(encodedUrl);
+ try {
+ return new File(uri);
+ } catch (IllegalArgumentException e) {
+ return null;
+ }
+ } catch (URISyntaxException ex) {
+ throw new RuntimeException(ex); // should never happen
+ }
+ }
+ }
+
+ private static String encode(String url) {
+ StringBuffer buf = new StringBuffer(url.length());
+ for (int i = 0; i < url.length(); ++i) {
+ char c = url.charAt(i);
+ // The RFC 2732 <uric> characters: !$&'()*+,-./:;=?@[]_~ plus digits
+ // and letters; additionally, do not encode % again.
+ if (c >= 'a' && c <= 'z' || c >= '?' && c <= '['
+ || c >= '$' && c <= ';' || c == '!' || c == '=' || c == ']'
+ || c == '_' || c == '~')
+ {
+ buf.append(c);
+ } else if (c == ' ') {
+ buf.append("%20");
+ } else {
+ try {
+ String enc = URLEncoder.encode(Character.toString(c), "UTF-8");
+ buf.append(enc);
+ } catch (UnsupportedEncodingException e) {
+ throw new RuntimeException(e); // should never happen
+ }
+ }
+ }
+ return buf.toString();
+ }
+
+ private UrlToFileMapper() {}
+}
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/ridljar/com/sun/star/lib/util/WeakMap.java b/ridljar/com/sun/star/lib/util/WeakMap.java
new file mode 100644
index 0000000000..4d63d27286
--- /dev/null
+++ b/ridljar/com/sun/star/lib/util/WeakMap.java
@@ -0,0 +1,323 @@
+/*
+ * 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 com.sun.star.lib.util;
+
+import java.lang.ref.ReferenceQueue;
+import java.lang.ref.WeakReference;
+import java.util.Collection;
+import java.util.HashMap;
+import java.util.Iterator;
+import java.util.Map;
+import java.util.Set;
+
+/**
+ * A hash map that holds values of type <code>WeakReference</code>.
+ *
+ * <p>Like <code>HashMap</code>, this implementation provides all of the
+ * optional map operations, and permits the <code>null</code> key.</p>
+ *
+ * <p>Also like <code>HashMap</code>, this implementation is not synchronized.
+ * If multiple threads share an instance, and at least one of them executes any
+ * modifying operations on the <code>WeakMap</code>, they have to use external
+ * synchronization.</p>
+ *
+ * <p>Unlike other map implementations, <code>WeakMap</code> is asymmetric in
+ * that <code>put</code> expects the given value to be a plain object that is
+ * then wrapped in a <code>WeakReference</code>, while the occurrences of values
+ * in all other methods (<code>containsValue</code>, <code>entrySet</code>,
+ * <code>equals</code>, <code>get</code>, <code>hashCode</code>,
+ * <code>remove</code>, <code>values</code>, and also the return value of
+ * <code>put</code>) expect already wrapped instances of
+ * <code>WeakReference</code>. That is, after <code>weakMap.put("key",
+ * o)</code>, <code>weakMap.get("key").equals(o)</code> does not work as
+ * na&iuml;vely expected; neither does
+ * <code>weakMap1.putAll(weakMap2)</code>.</p>
+ *
+ * <p>At an arbitrary time after the <code>WeakReference</code> value of an
+ * entry has been cleared by the garbage collector, the entry is automatically
+ * removed from the map.</p>
+ *
+ * <p>Values placed into a <code>WeakMap</code> may optionally support the
+ * <code>DisposeNotifier</code> interface. For those that do, the associated
+ * <code>WeakReference</code> wrappers are automatically cleared as soon as the
+ * values are disposed.</p>
+ *
+ * Note that this class does not actually implement the Map interface properly,
+ * the type of the return value of the entrySet and values methods is wrong,
+ * but the "implements Map" is retained for backward compatibility.
+ */
+public final class WeakMap<K,V> implements Map {
+
+ /**
+ * Declare the map as WeakReference instead of Entry because it makes the return
+ * type signatures of values() and keySet() cleaner.
+ */
+ private final HashMap<K, WeakReference<V>> map = new HashMap<K, WeakReference<V>>();
+ private final ReferenceQueue<V> queue = new ReferenceQueue<V>();
+
+ /**
+ * Constructs an empty <code>WeakMap</code>.
+ */
+ public WeakMap() {}
+
+ /**
+ * Constructs a new <code>WeakMap</code> with the same mappings as the
+ * specified <code>Map</code>.
+ *
+ * @param m the map whose mappings are to be placed in this map
+ */
+ public WeakMap(Map<K,V> m) {
+ putAll(m);
+ }
+
+ /**
+ * Returns the number of key&ndash;value mappings in this map.
+ *
+ * <p>This is a non-modifying operation.</p>
+ *
+ * @return the number of key&ndash;value mappings in this map
+ */
+ public int size() {
+ return map.size();
+ }
+
+ /**
+ * Returns <code>true</code> if this map contains no key&ndash;value
+ * mappings.
+ *
+ * <p>This is a non-modifying operation.</p>
+ *
+ * @return <code>true</code> if this map contains no key&ndash;value
+ * mappings
+ */
+ public boolean isEmpty() {
+ return map.isEmpty();
+ }
+
+ /**
+ * Returns <code>true</code> if this map contains a mapping for the
+ * specified key.
+ *
+ * <p>This is a non-modifying operation.</p>
+ *
+ * @param key the key whose presence in this map is to be tested
+ * @return <code>true</code> if this map contains a mapping for the
+ * specified key
+ */
+ public boolean containsKey(/*K*/ Object key) {
+ return map.containsKey(key);
+ }
+
+ /**
+ * Returns <code>true</code> if this map maps one or more keys to the
+ * specified value.
+ *
+ * <p>This is a non-modifying operation.</p>
+ *
+ * @param value the value whose presence in this map is to be tested
+ * @return <code>true</code> if this map maps one or more keys to the
+ * specified value
+ */
+ public boolean containsValue(Object /*WeakReference<V>*/ value) {
+ return map.containsValue(value);
+ }
+
+ /**
+ * Returns the value to which the specified key is mapped in this map, or
+ * <code>null</code> if the map contains no mapping for this key.
+ *
+ * <p>This is a non-modifying operation.</p>
+ *
+ * @param key the key whose associated value is to be returned
+ *
+ * @return the value to which this map maps the specified key, or
+ * <code>null</code> if the map contains no mapping for this key
+ */
+ public WeakReference<V> get(/*K*/ Object key) {
+ return map.get(key);
+ }
+
+ /**
+ * Associates the specified value with the specified key in this map.
+ *
+ * <p>This is a modifying operation.</p>
+ *
+ * @param key the key with which the specified value is to be associated
+ * @param value the value to be associated with the specified key. This
+ * must be a plain object, which is then wrapped in a
+ * <code>WeakReference</code>.
+ * @return previous value associated with the specified key, or
+ * <code>null</code> if there was no mapping for the key
+ */
+ @SuppressWarnings("unchecked")
+ public Object /*WeakReference<V>*/ put(/*K*/ Object key, /*V*/ Object value) {
+ cleanUp();
+ return map.put((K) key, new Entry<K,V>((K) key, (V) value, queue));
+ }
+
+ /**
+ * Removes the mapping for this key from this map if present.
+ *
+ * <p>This is a modifying operation.</p>
+ *
+ * @param key the key whose mapping is to be removed from the map
+ * @return previous value associated with the specified key, or
+ * <code>null</code> if there was no mapping for the key
+ */
+ public Object /*WeakReference<V>*/ remove(/*K*/ Object key) {
+ cleanUp();
+ return map.remove(key);
+ }
+
+ /**
+ * Copies all of the mappings from the specified map to this map.
+ *
+ * <p>This is a modifying operation.</p>
+ *
+ * @param m mappings to be stored in this map. The values of those mappings
+ * must be plain objects, which are then wrapped in instances of
+ * <code>WeakReference</code>.
+ */
+ @SuppressWarnings("unchecked")
+ public void putAll(Map/*<K,V>*/ m) {
+ cleanUp();
+ for (Iterator<Map.Entry<K,V>> i = m.entrySet().iterator(); i.hasNext();) {
+ Map.Entry<K,V> e = i.next();
+ K k = e.getKey();
+ map.put(k, new Entry<K,V>(k, e.getValue(), queue));
+ }
+ }
+
+ /**
+ * Removes all mappings from this map.
+ *
+ * <p>This is a modifying operation.</p>
+ */
+ public void clear() {
+ cleanUp();
+ map.clear();
+ }
+
+ /**
+ * Returns a view of the keys contained in this map.
+ *
+ * <p>This is a non-modifying operation.</p>
+ *
+ * @return a set view of the keys contained in this map
+ */
+ public Set<K> keySet() {
+ return map.keySet();
+ }
+
+ /**
+ * Returns a collection view of the values contained in this map.
+ *
+ * <p>This is a non-modifying operation.</p>
+ *
+ * @return a collection view of the values contained in this map
+ */
+ public Collection<WeakReference<V>> values() {
+ return map.values();
+ }
+
+ /**
+ * Returns a collection view of the mappings contained in this map.
+ *
+ * <p>This is a non-modifying operation.</p>
+ *
+ * @return a collection view of the mappings contained in this map
+ */
+ public Set/*<Map.Entry<K,WeakReference<V>>>*/ entrySet() {
+ return map.entrySet();
+ }
+
+ @Override
+ public boolean equals(Object o) {
+ return map.equals(o);
+ }
+
+ @Override
+ public int hashCode() {
+ return map.hashCode();
+ }
+
+ /**
+ * Returns the referent of a <code>WeakReference</code>, silently handling a
+ * <code>null</code> argument.
+ *
+ * <p>This static method is useful to wrap around the return values of
+ * methods like <code>get</code>.</p>
+ *
+ * @param ref must be either an instance of <code>WeakReference</code> or
+ * <code>null</code>
+ * @return the referent of the specified <code>WeakReference</code>, or
+ * <code>null</code> if <code>ref</code> is <code>null</code>
+ */
+ @SuppressWarnings("unchecked")
+ public static <T> T getValue(Object /*WeakReference<T>*/ ref) {
+ return ref == null ? null : ((WeakReference<T>) ref).get();
+ }
+
+ /**
+ * cleanUp() must only be called from within modifying methods. Otherwise,
+ * the implementations of entrySet, keySet and values would break
+ * (Specifically, iterating over the collections returned by those
+ * methods), as non-modifying methods might modify the underlying map.
+ **/
+ @SuppressWarnings("unchecked")
+ private void cleanUp() {
+ for (;;) {
+ Entry<K,V> e = (Entry<K,V>) queue.poll();
+ if (e == null) {
+ break;
+ }
+ // It is possible that an Entry e1 becomes weakly reachable, then
+ // another Entry e2 is added to the map for the same key, and only
+ // then e1 is enqueued. To not erroneously remove the new e2 in
+ // that case, check whether the map still contains e1:
+ Object k = e.key;
+ if (e == map.get(k)) {
+ map.remove(k);
+ }
+ }
+ }
+
+ private static final class Entry<K,V> extends WeakReference<V>
+ implements DisposeListener
+ {
+ private final K key;
+
+ private Entry(K key, V value, ReferenceQueue<V> queue) {
+ super(value, queue);
+ this.key = key;
+ if (value instanceof DisposeNotifier) {
+ ((DisposeNotifier) value).addDisposeListener(this);
+ }
+ }
+
+ /**
+ * @see DisposeListener#notifyDispose(DisposeNotifier)
+ */
+ public void notifyDispose(DisposeNotifier source) {
+ clear();
+ enqueue();
+ }
+ }
+
+}
diff --git a/ridljar/com/sun/star/uno/Any.java b/ridljar/com/sun/star/uno/Any.java
new file mode 100644
index 0000000000..2f4976436d
--- /dev/null
+++ b/ridljar/com/sun/star/uno/Any.java
@@ -0,0 +1,151 @@
+/*
+ * 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 com.sun.star.uno;
+
+
+/**
+ * The UNO IDL type any is mapped to java type <code>java.lang.Object</code>.
+ * <p>
+ * In special cases it is necessary to have an explicit any to additionally transport
+ * an exact type. For instance if you want to pass an object reference via
+ * an interprocess connection using an any, you should use this class to add
+ * an explicit interface type, so the remote counterpart doesn't need to invoke
+ * a queryInterface).
+ * </p>
+ */
+public class Any {
+ /**
+ * The type of the any.
+ *
+ * @see #getType
+ */
+ protected Type _type;
+
+ /**
+ * The data of the any.
+ *
+ * @see #getObject
+ */
+ protected Object _object;
+
+ public static final Any VOID = new Any(new Type("void", TypeClass.VOID),
+ null);
+ // do not use Type.VOID here to avoid circular dependencies between
+ // static members of Any and Type
+
+ /**
+ * Constructs a new any.
+ *
+ * @param zInterface the type of the any.
+ * @param object the data of the any.
+ * @deprecated as of UDK 2.0
+ */
+ @Deprecated
+ public Any(Class<?> zInterface, Object object) {
+ this(new Type(zInterface), object);
+ }
+
+ /**
+ * Constructs a new any with a given type and value
+ *
+ * @param type the UNO type of the any.
+ * @param object the value of the any.
+ */
+ public Any(Type type, Object object) {
+ if (type.equals(Type.ANY)) {
+ throw new IllegalArgumentException("Any cannot contain Any");
+ }
+ _type = type;
+ _object = object;
+ }
+
+ /**
+ * Complete a UNO <code>ANY</code> (make sure it is wrapped up as an
+ * <code>Any</code> instance).
+ *
+ * @param any a Java value representing a UNO <code>ANY</code> value.
+ * @return a complete Java value (that is, an <code>Any</code> instance)
+ * representing the same UNO <code>ANY</code> value as the given argument.
+ * @since UDK 3.2.3
+ */
+ public static final Any complete(Object any) {
+ return any instanceof Any
+ ? (Any) any
+ : new Any(
+ new Type(any == null ? XInterface.class : any.getClass()), any);
+ }
+
+ /**
+ * Gets the type of the value within the any.
+ *
+ * @return the type of the value within the any.
+ */
+ public Type getType() {
+ return _type;
+ }
+
+ /**
+ * Gets the value within the any.
+ *
+ * @return gets the value within the any.
+ */
+ public Object getObject() {
+ return _object;
+ }
+
+ /**
+ * Indicates whether some other object is equal to this one.
+ *
+ * @param obj the reference object with which to compare.
+ * @return <code>true</code> if this object is the same as the obj argument;
+ * <code>false</code> otherwise.
+ * @see java.lang.Object#equals
+ */
+ @Override
+ public boolean equals(Object obj) {
+ return obj instanceof Any && _type.equals(((Any) obj)._type)
+ && (_object == null
+ ? ((Any) obj)._object == null
+ : _object.equals(((Any) obj)._object));
+ }
+
+ /**
+ * Returns a hash code value for the object.
+ *
+ * @return a hash code value for this object.
+ * @see java.lang.Object#hashCode
+ */
+ @Override
+ public int hashCode() {
+ return _type.hashCode() * 13
+ + (_object == null ? 0 : _object.hashCode());
+ }
+
+ /**
+ * Returns a string representation of the object.
+ *
+ * @return a string representation of the object.
+ * @see java.lang.Object#toString
+ */
+ @Override
+ public String toString() {
+ return "Any[" + _type + ", " + _object + "]";
+ }
+}
diff --git a/ridljar/com/sun/star/uno/AnyConverter.java b/ridljar/com/sun/star/uno/AnyConverter.java
new file mode 100644
index 0000000000..b37eab254e
--- /dev/null
+++ b/ridljar/com/sun/star/uno/AnyConverter.java
@@ -0,0 +1,668 @@
+/* -*- Mode: Java; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
+/*
+ * 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 com.sun.star.uno;
+
+/**
+ * This class provides static methods which aim at exploring the contents of an
+ * Any and extracting its value.
+ *
+ * <p>All public methods take an Object argument that either is the immediate object,
+ * such as Boolean, Type, interface implementation, or an Any that contains an
+ * object.</p>
+ *
+ * <p>The methods which extract the value do a widening conversion. See the
+ * method comments for the respective conversions.</p>
+ */
+public class AnyConverter
+{
+ /**
+ * Determines the type of an Any object.
+ *
+ * @param object any object.
+ * @return type object.
+ */
+ public static Type getType( Object object )
+ {
+ Type t;
+ if (null == object)
+ {
+ t = m_XInterface_type;
+ }
+ else if (object instanceof Any)
+ {
+ t = ((Any)object).getType();
+ // nested any
+ if (TypeClass.ANY_value == t.getTypeClass().getValue())
+ return getType( ((Any)object).getObject() );
+ }
+ else
+ {
+ t = new Type( object.getClass() );
+ }
+ return t;
+ }
+
+ /**
+ * Checks if the any contains the idl type <code>void</code>.
+ *
+ * @param object the object to check.
+ * @return true when the any is void, false otherwise.
+ */
+ public static boolean isVoid(Object object){
+ return containsType(TypeClass.VOID, object);
+ }
+
+ /**
+ * Checks if the any contains a value of the idl type <code>char</code>.
+ *
+ * @param object the object to check.
+ * @return true when the any contains a char, false otherwise.
+ */
+ public static boolean isChar(Object object){
+ return containsType(TypeClass.CHAR, object);
+ }
+
+ /**
+ * Checks if the any contains a value of the idl type <code>boolean</code>.
+ *
+ * @param object the object to check.
+ * @return true when the any contains a boolean, false otherwise.
+ */
+ public static boolean isBoolean(Object object){
+ return containsType(TypeClass.BOOLEAN, object);
+ }
+
+ /**
+ * Checks if the any contains a value of the idl type <code>byte</code>.
+ *
+ * @param object the object to check.
+ * @return true when the any contains a byte, false otherwise.
+ */
+ public static boolean isByte(Object object){
+ return containsType(TypeClass.BYTE, object);
+ }
+
+ /**
+ * Checks if the any contains a value of the idl type <code>short</code>.
+ *
+ * @param object the object to check.
+ * @return true when the any contains a short, false otherwise.
+ */
+ public static boolean isShort(Object object){
+ return containsType(TypeClass.SHORT, object);
+ }
+
+ /**
+ * Checks if the any contains a value of the idl type <code>long</code>
+ * (which maps to a java-int).
+ *
+ * @param object the object to check.
+ * @return true when the any contains a int, false otherwise.
+ */
+ public static boolean isInt(Object object){
+ return containsType(TypeClass.LONG, object);
+ }
+
+ /**
+ * Checks if the any contains a value of the idl type <code>hyper</code>
+ * (which maps to a java-long).
+ *
+ * @param object the object to check.
+ * @return true when the any contains a long, false otherwise.
+ */
+ public static boolean isLong(Object object){
+ return containsType(TypeClass.HYPER, object);
+ }
+
+ /**
+ * Checks if the any contains a value of the idl type <code>float</code>.
+ *
+ * @param object the object to check.
+ * @return true when the any contains a float, false otherwise.
+ */
+ public static boolean isFloat(Object object){
+ return containsType(TypeClass.FLOAT, object);
+ }
+
+ /**
+ * Checks if the any contains a value of the idl type <code>double</code>.
+ *
+ * @param object the object to check.
+ * @return true when the any contains a double, false otherwise.
+ */
+ public static boolean isDouble(Object object){
+ return containsType(TypeClass.DOUBLE, object);
+ }
+
+ /**
+ * Checks if the any contains a value of the idl type <code>string</code>.
+ *
+ * @param object the object to check.
+ * @return true when the any contains a string, false otherwise.
+ */
+ public static boolean isString(Object object){
+ return containsType(TypeClass.STRING, object);
+ }
+
+ /**
+ * Checks if the any contains a value of the idl type <code>enum</code>.
+ *
+ * @param object the object to check.
+ * @return true if the any contains an enum, false otherwise.
+ */
+ public static boolean isEnum(Object object)
+ {
+ return containsType(TypeClass.ENUM, object);
+ }
+
+ /**
+ * Checks if the any contains a value of the idl type <code>type</code>.
+ *
+ * @param object the object to check.
+ * @return true when the any contains a type, false otherwise.
+ */
+ public static boolean isType(Object object){
+ return containsType(TypeClass.TYPE, object);
+ }
+
+ /**
+ * Checks if the any contains an interface, struct, exception, sequence or enum.
+ *
+ * <p>If <em>object</em> is an any with an interface type, then true is also
+ * returned if the any contains a null reference. This is because interfaces
+ * are allowed to have a null value contrary to other UNO types.</p>
+ *
+ * @param object the object to check.
+ * @return true if the any contains an object.
+ */
+ public static boolean isObject(Object object)
+ {
+ int tc = getType(object).getTypeClass().getValue();
+ return (TypeClass.INTERFACE_value == tc ||
+ TypeClass.STRUCT_value == tc ||
+ TypeClass.EXCEPTION_value == tc ||
+ TypeClass.SEQUENCE_value == tc ||
+ TypeClass.ENUM_value == tc);
+ }
+
+ /**
+ * Checks if the any contains UNO idl sequence value (meaning a java array
+ * containing elements which are values of UNO idl types).
+ *
+ * @param object the object to check.
+ * @return true when the any contains an object which implements interfaces,
+ * false otherwise.
+ */
+ public static boolean isArray(Object object){
+ return containsType(TypeClass.SEQUENCE, object);
+ }
+
+ /**
+ * Converts a Char object or an Any object containing a Char object into a
+ * simple char.
+ *
+ * @param object the object to convert.
+ * @return the char contained within the object.
+ * @throws com.sun.star.lang.IllegalArgumentException in case no char is
+ * contained within object.
+ *
+ * @see #isChar
+ */
+ public static char toChar(Object object) throws com.sun.star.lang.IllegalArgumentException{
+ Character ret= (Character)convertSimple(TypeClass.CHAR, null, object);
+ return ret.charValue();
+ }
+
+ /**
+ * Converts a Boolean object or an Any object containing a Boolean object
+ * into a simple boolean.
+ *
+ * @param object the object to convert.
+ * @return the boolean contained within the object
+ * @throws com.sun.star.lang.IllegalArgumentException in case no boolean is
+ * contained within object
+ *
+ * @see #isBoolean
+ */
+ public static boolean toBoolean(Object object) throws com.sun.star.lang.IllegalArgumentException{
+ Boolean ret= (Boolean)convertSimple(TypeClass.BOOLEAN, null, object);
+ return ret.booleanValue();
+ }
+
+ /**
+ * Converts a Byte object or an Any object containing a Byte object into a
+ * simple byte.
+ *
+ * @param object the object to convert.
+ * @return the boolean contained within the object.
+ * @throws com.sun.star.lang.IllegalArgumentException in case no byte is
+ * contained within object.
+ *
+ * @see #isBoolean
+ */
+ public static byte toByte(Object object) throws com.sun.star.lang.IllegalArgumentException{
+ Byte ret= (Byte)convertSimple(TypeClass.BYTE, null, object);
+ return ret.byteValue();
+ }
+
+ /**
+ * Converts a number object into a simple short and allows widening conversions.
+ *
+ * <p>Allowed argument types are Byte, Short or Any containing these types.</p>
+ *
+ * @param object the object to convert.
+ * @throws com.sun.star.lang.IllegalArgumentException in case no short or
+ * byte is contained within object.
+ *
+ * @return the short contained within the object.
+ */
+ public static short toShort(Object object) throws com.sun.star.lang.IllegalArgumentException{
+ Short ret= (Short)convertSimple(TypeClass.SHORT, null, object);
+ return ret.shortValue();
+ }
+ /**
+ * Converts a number object into an idl unsigned short and allows widening
+ * conversions.
+ *
+ * <p>Allowed argument types are Anies containing idl unsigned short values.</p>
+ *
+ * @param object the object to convert.
+ * @throws com.sun.star.lang.IllegalArgumentException in case no idl unsigned
+ * short is contained within Any.
+ *
+ * @return an (unsigned) short.
+ */
+ public static short toUnsignedShort(Object object)
+ throws com.sun.star.lang.IllegalArgumentException
+ {
+ Short ret= (Short)convertSimple(TypeClass.UNSIGNED_SHORT, null, object);
+ return ret.shortValue();
+ }
+
+ /**
+ * Converts a number object into a simple int and allows widening conversions.
+ *
+ * <p>Allowed argument types are Byte, Short, Integer or Any containing these
+ * types.</p>
+ *
+ * @param object the object to convert.
+ * @throws com.sun.star.lang.IllegalArgumentException in case no short, byte
+ * or int is contained within object.
+ *
+ * @return the int contained within the object.
+ */
+ public static int toInt(Object object) throws com.sun.star.lang.IllegalArgumentException{
+ Integer ret= (Integer) convertSimple( TypeClass.LONG, null, object);
+ return ret.intValue();
+ }
+ /**
+ * Converts a number object into an idl unsigned long and allows widening
+ * conversions.
+ *
+ * <p>Allowed argument types are Anies containing idl unsigned short or
+ * unsigned long values.</p>
+ *
+ * @param object the object to convert.
+ * @throws com.sun.star.lang.IllegalArgumentException in case no idl unsigned
+ * short nor unsigned long is contained within Any.
+ *
+ * @return an (unsigned) int.
+ */
+ public static int toUnsignedInt(Object object)
+ throws com.sun.star.lang.IllegalArgumentException
+ {
+ Integer ret = (Integer)convertSimple(TypeClass.UNSIGNED_LONG, null, object);
+ return ret.intValue();
+ }
+
+ /**
+ * Converts a number object into a simple long and allows widening conversions.
+ *
+ * <p>Allowed argument types are Byte, Short, Integer, Long or Any containing
+ * these types.</p>
+ *
+ * @param object the object to convert.
+ * @throws com.sun.star.lang.IllegalArgumentException in case no short, byte,
+ * int or long is contained within object.
+ *
+ * @return the long contained within the object.
+ */
+ public static long toLong(Object object) throws com.sun.star.lang.IllegalArgumentException{
+ Long ret= (Long) convertSimple( TypeClass.HYPER, null, object);
+ return ret.longValue();
+ }
+ /**
+ * Converts a number object into an idl unsigned hyper and allows widening
+ * conversions.
+ *
+ * <p>Allowed argument types are Anies containing idl unsigned short, unsigned
+ * long or unsigned hyper values.</p>
+ *
+ * @param object the object to convert.
+ * @throws com.sun.star.lang.IllegalArgumentException in case no idl unsigned
+ * short, nor unsigned long nor unsigned hyper is contained within object.
+ *
+ * @return an (unsigned) long.
+ */
+ public static long toUnsignedLong(Object object)
+ throws com.sun.star.lang.IllegalArgumentException
+ {
+ Long ret = (Long)convertSimple(TypeClass.UNSIGNED_HYPER, null, object);
+ return ret.longValue();
+ }
+
+ /**
+ * Converts a number object into a simple float and allows widening conversions.
+ *
+ * <p>Allowed argument types are Byte, Short, Float or Any containing these
+ * types.</p>
+ *
+ * @param object the object to convert.
+ * @throws com.sun.star.lang.IllegalArgumentException in case no byte, short
+ * or float is contained within object.
+ *
+ * @return the float contained within the object.
+ */
+ public static float toFloat(Object object) throws com.sun.star.lang.IllegalArgumentException{
+ Float ret= (Float) convertSimple( TypeClass.FLOAT,null, object);
+ return ret.floatValue();
+ }
+
+ /**
+ * Converts a number object into a simple double and allows widening conversions.
+ *
+ * <p>Allowed argument types are Byte, Short, Int, Float, Double or Any
+ * containing these types.</p>
+ *
+ * @param object the object to convert.
+ * @throws com.sun.star.lang.IllegalArgumentException in case no byte, short,
+ * int, float or double is contained within object.
+ *
+ * @return the double contained within the object.
+ */
+ public static double toDouble(Object object) throws com.sun.star.lang.IllegalArgumentException {
+ Double ret= (Double) convertSimple( TypeClass.DOUBLE, null, object);
+ return ret.doubleValue();
+ }
+
+ /**
+ * Converts a string or an any containing a string into a string.
+ *
+ * @param object the object to convert.
+ * @throws com.sun.star.lang.IllegalArgumentException in case no string is
+ * contained within object.
+ *
+ * @return the string contained within the object.
+ */
+ public static String toString(Object object) throws com.sun.star.lang.IllegalArgumentException {
+ return (String) convertSimple( TypeClass.STRING, null, object);
+ }
+
+ /**
+ * Converts a Type or an any containing a Type into a Type.
+ *
+ * @param object the object to convert.
+ * @throws com.sun.star.lang.IllegalArgumentException in case no type is
+ * contained within object.
+ *
+ * @return the type contained within the object.
+ */
+ public static Type toType(Object object) throws com.sun.star.lang.IllegalArgumentException {
+ return (Type) convertSimple( TypeClass.TYPE, null, object);
+ }
+
+ /**
+ * Converts a UNO object (struct, exception, sequence, enum or interface) or
+ * an Any containing these types into a UNO object of a specified destination
+ * type.
+ *
+ * <p> For interfaces, the argument <em>object</em> is queried for the interface
+ * specified by the <em>type</em> argument.</p>
+ *
+ * <p>That query (UnoRuntime.queryInterface) might return null, if the interface
+ * is not implemented or a null-ref or a VOID any is given.</p>
+ *
+ * @param type type of the returned value.
+ * @param object the object that is to be converted.
+ * @throws com.sun.star.lang.IllegalArgumentException in case conversion is
+ * not possible.
+ *
+ * @return destination object.
+ */
+ public static Object toObject(Type type, Object object)
+ throws com.sun.star.lang.IllegalArgumentException
+ {
+ return convertSimple( type.getTypeClass(), type, object );
+ }
+ /**
+ * Converts a UNO object (struct, exception, sequence, enum or interface) or
+ * an Any containing these types into a UNO object of a specified destination
+ * type.
+ *
+ * <p>For interfaces, the argument <em>object</em> is queried for the interface
+ * specified by the <em>type</em> argument. That query (UnoRuntime.queryInterface)
+ * might return null, if the interface is not implemented or a null-ref or a
+ * VOID any is given.</p>
+ *
+ * @param clazz class of the returned value.
+ * @param object the object that is to be converted.
+ * @throws com.sun.star.lang.IllegalArgumentException in case conversion is
+ * not possible.
+ *
+ * @return destination object.
+ */
+ public static Object toObject(Class<?> clazz, Object object)
+ throws com.sun.star.lang.IllegalArgumentException
+ {
+ return toObject( new Type( clazz ), object );
+ }
+
+ /**
+ * Converts an array or an any containing an array into an array.
+ *
+ * @param object the object to convert.
+ * @throws com.sun.star.lang.IllegalArgumentException in case no array is
+ * contained within object.
+ *
+ * @return the array contained within the object.
+ */
+ public static Object toArray( Object object) throws com.sun.star.lang.IllegalArgumentException {
+ return convertSimple( TypeClass.SEQUENCE, null, object);
+ }
+
+ /**
+ * Examines the argument <em>object</em> if is correspond to the type in
+ * argument <em>what</em>.
+ *
+ * <p><em>object</em> is either matched directly against the type or if it is
+ * an any then the contained object is matched against the type.</p>
+ */
+ private static boolean containsType( TypeClass what, Object object){
+ return (getType(object).getTypeClass().getValue() == what.getValue());
+ }
+
+ private static final Type m_XInterface_type = new Type( XInterface.class );
+
+ private static Object convertSimple( TypeClass destTClass, Type destType, Object object_ )
+ throws com.sun.star.lang.IllegalArgumentException
+ {
+ Object object;
+ Type type;
+ if (object_ instanceof Any) {
+ // unbox
+ Any a = (Any)object_;
+ object = a.getObject();
+ type = a.getType();
+ // nested any
+ if (TypeClass.ANY_value == type.getTypeClass().getValue())
+ return convertSimple( destTClass, destType, object );
+ } else {
+ object = object_;
+ type = (null == object ? m_XInterface_type : new Type( object.getClass() ));
+ }
+
+ int tc = type.getTypeClass().getValue();
+ int dest_tc = destTClass.getValue();
+
+ if (null == object) {
+ // special for interfaces
+ if (TypeClass.INTERFACE_value == tc && dest_tc == tc)
+ return null;
+ } else {
+ switch (dest_tc) {
+ case TypeClass.CHAR_value:
+ if (tc == TypeClass.CHAR_value)
+ return object;
+ break;
+ case TypeClass.BOOLEAN_value:
+ if (tc == TypeClass.BOOLEAN_value)
+ return object;
+ break;
+ case TypeClass.BYTE_value:
+ if (tc == TypeClass.BYTE_value)
+ return object;
+ break;
+ case TypeClass.SHORT_value:
+ switch (tc) {
+ case TypeClass.BYTE_value:
+ return Short.valueOf( ((Byte)object).byteValue() );
+ case TypeClass.SHORT_value:
+ return object;
+ }
+ break;
+ case TypeClass.UNSIGNED_SHORT_value:
+ switch (tc) {
+ case TypeClass.UNSIGNED_SHORT_value:
+ return object;
+ }
+ break;
+ case TypeClass.LONG_value:
+ switch (tc) {
+ case TypeClass.BYTE_value:
+ return Integer.valueOf( ((Byte)object).byteValue() );
+ case TypeClass.SHORT_value:
+ case TypeClass.UNSIGNED_SHORT_value:
+ return Integer.valueOf( ((Short)object).shortValue() );
+ case TypeClass.LONG_value:
+ return object;
+ }
+ break;
+ case TypeClass.UNSIGNED_LONG_value:
+ switch (tc) {
+ case TypeClass.UNSIGNED_SHORT_value:
+ return Integer.valueOf( ((Short)object).shortValue() );
+ case TypeClass.UNSIGNED_LONG_value:
+ return object;
+ }
+ break;
+ case TypeClass.HYPER_value:
+ switch (tc) {
+ case TypeClass.BYTE_value:
+ return Long.valueOf( ((Byte)object).byteValue() );
+ case TypeClass.SHORT_value:
+ case TypeClass.UNSIGNED_SHORT_value:
+ return Long.valueOf( ((Short)object).shortValue() );
+ case TypeClass.LONG_value:
+ case TypeClass.UNSIGNED_LONG_value:
+ return Long.valueOf( ((Integer)object).intValue() );
+ case TypeClass.HYPER_value:
+ return object;
+ }
+ break;
+ case TypeClass.UNSIGNED_HYPER_value:
+ switch (tc) {
+ case TypeClass.UNSIGNED_SHORT_value:
+ return Long.valueOf( ((Short)object).shortValue() );
+ case TypeClass.UNSIGNED_LONG_value:
+ return Long.valueOf( ((Integer)object).intValue() );
+ case TypeClass.UNSIGNED_HYPER_value:
+ return object;
+ }
+ break;
+ case TypeClass.FLOAT_value:
+ switch (tc) {
+ case TypeClass.BYTE_value:
+ return Float.valueOf( ((Byte)object).byteValue() );
+ case TypeClass.SHORT_value:
+ return Float.valueOf( ((Short)object).shortValue() );
+ case TypeClass.FLOAT_value:
+ return object;
+ }
+ break;
+ case TypeClass.DOUBLE_value:
+ switch (tc) {
+ case TypeClass.BYTE_value:
+ return Double.valueOf( ((Byte)object).byteValue() );
+ case TypeClass.SHORT_value:
+ return Double.valueOf( ((Short)object).shortValue() );
+ case TypeClass.LONG_value:
+ return Double.valueOf( ((Integer)object).intValue() );
+ case TypeClass.FLOAT_value:
+ return Double.valueOf( ((Float)object).floatValue() );
+ case TypeClass.DOUBLE_value:
+ return object;
+ }
+ break;
+ case TypeClass.ENUM_value:
+ if (tc == TypeClass.ENUM_value &&
+ (null == destType || destType.equals( type ) /* optional destType */))
+ {
+ return object;
+ }
+ break;
+ case TypeClass.STRING_value:
+ if (tc == TypeClass.STRING_value)
+ return object;
+ break;
+ case TypeClass.TYPE_value:
+ if (tc == TypeClass.TYPE_value)
+ return object;
+ break;
+ case TypeClass.INTERFACE_value:
+ // Because object is a class, not an interface, it is
+ // controversial what kind of Type "new Type(object.class)"
+ // above should return (UNKNOWN or INTERFACE), so that we should
+ // not check here for "tc == TypeClass.INTERFACE_value".
+ // Instead, we check whether object (indirectly) derives from
+ // XInterface:
+ if (object instanceof XInterface)
+ return UnoRuntime.queryInterface( destType, object );
+ break;
+ case TypeClass.STRUCT_value:
+ case TypeClass.EXCEPTION_value:
+ if (destType.isSupertypeOf(type)) {
+ return object;
+ }
+ break;
+ case TypeClass.SEQUENCE_value:
+ if (tc == TypeClass.SEQUENCE_value &&
+ (null == destType || destType.equals( type ) /* optional destType */))
+ {
+ return object;
+ }
+ break;
+ }
+ }
+ throw new com.sun.star.lang.IllegalArgumentException(
+ "The Argument did not hold the proper type");
+ }
+}
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/ridljar/com/sun/star/uno/Ascii.java b/ridljar/com/sun/star/uno/Ascii.java
new file mode 100644
index 0000000000..ce51088935
--- /dev/null
+++ b/ridljar/com/sun/star/uno/Ascii.java
@@ -0,0 +1,43 @@
+/* -*- Mode: Java; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
+/*
+ * 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 com.sun.star.uno;
+
+/**
+ * The Ascii class represents the IDL build in type <code>ascii</code>.
+ *
+ * @deprecated do not use.
+ */
+@Deprecated
+public final class Ascii {
+ public final char ascii;
+
+ /**
+ * Constructs a new <code>Ascii</code>.
+ *
+ * @deprecated do not use.
+ * @param c the char value.
+ */
+ @Deprecated
+ public Ascii(char c) {
+ ascii = c;
+ }
+}
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/ridljar/com/sun/star/uno/AsciiString.java b/ridljar/com/sun/star/uno/AsciiString.java
new file mode 100644
index 0000000000..8b744c5a22
--- /dev/null
+++ b/ridljar/com/sun/star/uno/AsciiString.java
@@ -0,0 +1,44 @@
+/* -*- Mode: Java; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
+/*
+ * 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 com.sun.star.uno;
+
+/**
+ * The Ascii class represents the IDL build in type <code>asciistring</code>.
+ *
+ * @deprecated do not use.
+ */
+@Deprecated
+public final class AsciiString {
+ public final String asciistring;
+
+ /**
+ * Constructs a new <code>AsciiString</code>.
+ *
+ * @deprecated do not use.
+ * @param s the String value.
+ */
+ @Deprecated
+ public AsciiString(String s) {
+ asciistring = s;
+ }
+
+}
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/ridljar/com/sun/star/uno/Enum.java b/ridljar/com/sun/star/uno/Enum.java
new file mode 100644
index 0000000000..8bd50876dd
--- /dev/null
+++ b/ridljar/com/sun/star/uno/Enum.java
@@ -0,0 +1,50 @@
+/*
+ * 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 com.sun.star.uno;
+
+/**
+ * The Enum class is the base class for all classes generated
+ * as java binding for the IDL type enum.
+ * <p>
+ * Each java mapped enum class provides static member of this class
+ * which represents the enum values.
+ * You cannot create an object of this class or subclass direct, to
+ * avoid enum values with integer values outside the defined range.
+ * </p>
+ */
+public abstract class Enum {
+ private final int m_value;
+
+ /**
+ * Constructs an enum value.
+ * @param value the integer value of this enum value.
+ */
+ protected Enum(int value) {
+ m_value = value;
+ }
+
+ /**
+ * Get the integer value of an enum value.
+ * @return the integer value.
+ */
+ public final int getValue() {
+ return m_value;
+ }
+}
+
diff --git a/ridljar/com/sun/star/uno/IBridge.java b/ridljar/com/sun/star/uno/IBridge.java
new file mode 100644
index 0000000000..5cd9fda704
--- /dev/null
+++ b/ridljar/com/sun/star/uno/IBridge.java
@@ -0,0 +1,94 @@
+/*
+ * 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 com.sun.star.uno;
+
+import java.io.IOException;
+
+/**
+ * This is abstract interface for bridges.
+ *
+ * <p>Bridges are able to map one object from one UNO environment to another and
+ * vice versa.</p>
+ *
+ * @see com.sun.star.uno.IBridge
+ * @see com.sun.star.uno.IQueryInterface
+ * @see com.sun.star.uno.UnoRuntime
+ *
+ * @deprecated As of UDK 3.2, this interface is deprecated, without offering a
+ * replacement.
+ */
+@Deprecated
+public interface IBridge {
+ /**
+ * Maps an object from the source environment to the destination
+ * environment.
+ *
+ * @param object the object to map
+ * @param type the type of the interface that shall be mapped
+ * @return the object in the destination environment
+ */
+ Object mapInterfaceTo(Object object, Type type);
+
+ /**
+ * Maps an object from the destination environment to the source
+ * environment.
+ *
+ * @param object the object to map
+ * @param type the type of the interface that shall be mapped
+ * @return the object in the source environment
+ */
+ Object mapInterfaceFrom(Object object, Type type);
+
+ /**
+ * Returns the source environment.
+ *
+ * @return the source environment of this bridge
+ */
+ IEnvironment getSourceEnvironment();
+
+ /**
+ * Returns the destination environment.
+ *
+ * @return the destination environment of this bridge
+ */
+ IEnvironment getTargetEnvironment();
+
+ /**
+ * Increases the life count.
+ */
+ void acquire();
+
+ /**
+ * Decreases the life count.
+ *
+ * <p>If the life count drops to zero, the bridge disposes itself.</p>
+ */
+ void release();
+
+ /**
+ * Disposes the bridge.
+ *
+ * <p>Sends involved threads an <code>InterruptedException</code>. Releases
+ * mapped objects.</p>
+ *
+ * @throws InterruptedException it's deprecated so who cares.
+ * @throws IOException it's deprecated so who cares.
+ */
+ void dispose() throws InterruptedException, IOException;
+}
diff --git a/ridljar/com/sun/star/uno/IEnvironment.java b/ridljar/com/sun/star/uno/IEnvironment.java
new file mode 100644
index 0000000000..5d32893052
--- /dev/null
+++ b/ridljar/com/sun/star/uno/IEnvironment.java
@@ -0,0 +1,144 @@
+/*
+ * 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 com.sun.star.uno;
+
+/**
+ * The interface implemented by UNO environments.
+ *
+ * <p>With this interface, objects can be registered at and revoked from an
+ * environment.</p>
+ *
+ * @see com.sun.star.uno.IBridge
+ * @see com.sun.star.uno.IQueryInterface
+ * @see com.sun.star.uno.UnoRuntime
+ *
+ * @deprecated As of UDK 3.2, this interface is deprecated, without offering a
+ * replacement.
+ */
+@Deprecated
+public interface IEnvironment {
+ /**
+ * Gets the context of this environment.
+ *
+ * @return the context of this environment
+ */
+ Object getContext();
+
+ /**
+ * Gets the name of this environment.
+ *
+ * @return the name of this environment
+ */
+ String getName();
+
+ /**
+ * Registers one UNO interface facet of an object.
+ *
+ * <p>Such an object will typically be one of three things:
+ * <ul>
+ * <li>A local Java object, to be mapped out of this environment via a given
+ * bridge.</li>
+ * <li>A proxy object, mapped into this environment via some bridge
+ * <var>B1</var>, and now to be mapped out of this environment via a
+ * given bridge <var>B2</var>.</li>
+ * <li>A proxy object, created as a remote object is mapped into this
+ * environment via a given bridge.</li>
+ * </ul>
+ *
+ * <p>The object actually registered may differ from the specified
+ * <code>object</code> that is passed as an argument. This enables an
+ * environment to work in a multi-threaded scenario, where two threads can
+ * call <code>registerInterface</code> for the same combination of
+ * <code>oid</code> and <code>type</code> at the same time; the race
+ * condition is solved by letting one of the calls register its argument
+ * <code>object</code>, ignoring the argument <code>object</code> of the
+ * other call, and letting both calls return the same
+ * <code>object</code>.</p>
+ *
+ * <p>The registered object is held only weakly by the environment. After a
+ * call to <code>registerInterface</code>, a call to
+ * <code>getRegisteredInterface</code> only succeeds as long as the
+ * registered object is still strongly reachable, and the registered object
+ * has not been explicitly revoked by calling
+ * <code>revokeInterface</code>.</p>
+ *
+ * @param object the object to register; must be non-null
+ * @param oid in-out parameter containing the OID of <code>object</code>.
+ * This must be a non-null reference to an array of length at least one;
+ * the zeroth element is used to pass the argument in and out. If the
+ * zeroth element is null on input, the OID will be computed and passed
+ * out (that is, the zeroth element will never be null upon normal
+ * return).
+ * @param type the UNO interface type to register. This argument must be
+ * non-null, and must denote a UNO interface type. The given
+ * <code>object</code> should implement this <code>type</code>.
+ * @return the registered object (may differ from the <code>object</code>
+ * passed in); will never be null
+ */
+ Object registerInterface(Object object, String[] oid, Type type);
+
+ /**
+ * Explicitly revokes a UNO interface facet.
+ *
+ * <p>Calls to <code>registerInterface</code> and
+ * <code>revokeInterface</code> must be paired. A facet is only removed
+ * from the environment when it has been revoked as often as it has been
+ * registered. This may change in the future, so that a facet would be
+ * removed upon the first call to <code>revokeInterface</code> (and calls to
+ * <code>revokeInterface</code> would no longer be necessary if the calling
+ * code does not want to control the temporal extent of the
+ * registration).</p>
+ *
+ * <p>It is not an error if the specified facet is not registered at this
+ * environment (either because no corresponding object has ever been
+ * registered, or it has been explicitly revoked, or it is no longer
+ * strongly reachable). In such a case, this method simply does
+ * nothing.</p>
+ *
+ * @param oid the OID of the object to revoke; must be non-null
+ * @param type the UNO interface type of the object to revoke. This
+ * argument must be non-null, and must denote a UNO interface type.
+ */
+ void revokeInterface(String oid, Type type);
+
+ /**
+ * Retrieves a registered object, specified by OID and UNO interface type.
+ *
+ * @param oid the OID of the object to retrieve; must be non-null
+ * @param type the UNO interface type of the object to retrieve. This
+ * argument must be non-null, and must denote a UNO interface type.
+ * @return the registered object, or null if none is found
+ */
+ Object getRegisteredInterface(String oid, Type type);
+
+ /**
+ * Retrieves the OID for a registered object.
+ *
+ * @param object a registered object; must be non-null
+ * @return the OID of the <code>object</code>; will never be null
+ */
+ String getRegisteredObjectIdentifier(Object object);
+
+ /**
+ * Lists the registered objects to <code>System.out</code>.
+ *
+ * <p>This is for debug purposes.</p>
+ */
+ void list();
+}
diff --git a/ridljar/com/sun/star/uno/IMapping.java b/ridljar/com/sun/star/uno/IMapping.java
new file mode 100644
index 0000000000..fdf6d8207f
--- /dev/null
+++ b/ridljar/com/sun/star/uno/IMapping.java
@@ -0,0 +1,41 @@
+/*
+ * 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 com.sun.star.uno;
+
+/**
+ * With a mapping objects can be mapped from one environment to another.
+ *
+ * <p>This interface exists for compatibility with the binary UNO API.</p>
+ *
+ * @see com.sun.star.uno.IBridge
+ *
+ * @deprecated As of UDK 3.2, this interface is deprecated, without offering a
+ * replacement.
+ */
+@Deprecated
+public interface IMapping {
+ /**
+ * Maps an interface from one environment to another.
+ *
+ * @param object source object that is to be mapped
+ * @param type description of the interface that is to be mapped
+ * @return the object mapped to the destination environment
+ */
+ Object mapInterface(Object object, Type type);
+}
diff --git a/ridljar/com/sun/star/uno/IQueryInterface.java b/ridljar/com/sun/star/uno/IQueryInterface.java
new file mode 100644
index 0000000000..7857d62054
--- /dev/null
+++ b/ridljar/com/sun/star/uno/IQueryInterface.java
@@ -0,0 +1,60 @@
+/*
+ * 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 com.sun.star.uno;
+
+/**
+ * This is the delegator interface for Java objects implementing interfaces of
+ * an underlying UNO object.
+ *
+ * <p>Calls are delegated through the <code>UnoRuntime</code> to this
+ * interface. Implement this interface in case you want to customize the
+ * behaviour of <code>UnoRuntime.queryInterface</code>.</p>
+ *
+ * @see com.sun.star.uno.UnoRuntime
+ */
+public interface IQueryInterface {
+ /**
+ * Returns the unique object identifier (OID) of the underlying UNO object.
+ *
+ * @return the OID of the underlying object
+ */
+ String getOid();
+
+ /**
+ * Returns an object implementing the requested interface type.
+ *
+ * @param type the requested UNO interface type; must be a <code>Type</code>
+ * object representing a UNO interface type
+ * @return a reference to the requested UNO interface type if available,
+ * otherwise <code>null</code>
+ * @see com.sun.star.uno.UnoRuntime
+ */
+ Object queryInterface(Type type);
+
+ /**
+ * Tests if the given reference represents a facet of the underlying UNO
+ * object.
+ *
+ * @param object a reference to any Java object representing (a facet of) a
+ * UNO object; may be <code>null</code>
+ * @return <code>true</code> if and only if <code>object</code> is not
+ * <code>null</code> and represents the same UNO object as this object
+ */
+ boolean isSame(Object object);
+}
diff --git a/ridljar/com/sun/star/uno/MappingException.java b/ridljar/com/sun/star/uno/MappingException.java
new file mode 100644
index 0000000000..7670a790ad
--- /dev/null
+++ b/ridljar/com/sun/star/uno/MappingException.java
@@ -0,0 +1,65 @@
+/* -*- Mode: Java; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
+/*
+ * 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 com.sun.star.uno;
+
+
+/**
+ * The mapping Exception.
+ *
+ * <p>The exception is replaced by the com.sun.star.lang.DisposedException.</p>
+ *
+ * @see com.sun.star.uno.UnoRuntime
+ * @see com.sun.star.uno.IQueryInterface
+ * @see com.sun.star.uno.IBridge
+ *
+ * @deprecated since UDK 3.0.2
+ */
+@Deprecated
+public class MappingException extends com.sun.star.uno.RuntimeException {
+ /**
+ * Constructs an empty <code>MappingException</code>.
+ */
+ public MappingException() {
+ super();
+ }
+
+ /**
+ * Constructs an <code>MappingException</code> with a detail message.
+ *
+ * @param message the detail message.
+ */
+ public MappingException(String message) {
+ super(message);
+ }
+
+ /**
+ * Constructs an <code>MappingException</code> with a detail message and a
+ * context.
+ *
+ * @param message the detail message.
+ * @param context the context.
+ */
+ public MappingException(String message, Object context) {
+ super(message, context);
+ }
+}
+
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/ridljar/com/sun/star/uno/Type.java b/ridljar/com/sun/star/uno/Type.java
new file mode 100644
index 0000000000..0589b64cbb
--- /dev/null
+++ b/ridljar/com/sun/star/uno/Type.java
@@ -0,0 +1,699 @@
+/*
+ * 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 com.sun.star.uno;
+
+import java.util.HashMap;
+
+import com.sun.star.lib.uno.typedesc.TypeDescription;
+
+/**
+ * Represents the UNO built-in type <code>TYPE</code>.
+ *
+ * <p>The UNO type is not directly mapped to <code>java.lang.Class</code> for at
+ * least two reasons. For one, some UNO types (like <code>UNSIGNED
+ * SHORT</code>) do not have a matching Java class. For another, it can be
+ * necessary to describe a type which is unknown to the Java runtime system
+ * (for example, for delaying the need of a class, so that it is possible to
+ * generate it on the fly.)</p>
+ *
+ * <p>A <code>Type</code> is uniquely determined by its type class (a
+ * <code>TypeClass</code>) and its type name (a <code>String</code>); these two
+ * will never be <code>null</code>. A <code>Type</code> may have an additional
+ * "z class" (a <code>java.lang.Class</code>), giving a Java class type that
+ * corresponds to the UNO type. Also, a <code>Type</code> can cache a type
+ * description (a <code>com.sun.star.uno.typedesc.TypeDescription</code>), which can be
+ * computed and set by <code>TypeDescription.getTypeDescription</code>.
+ */
+public class Type {
+ // The following private static members and static initializer must come
+ // first in the class definition, so that the class can be initialized
+ // successfully:
+
+ private static final String TYPE_NAME_VOID = "void";
+ private static final String TYPE_NAME_BOOLEAN = "boolean";
+ private static final String TYPE_NAME_BYTE = "byte";
+ private static final String TYPE_NAME_SHORT = "short";
+ private static final String TYPE_NAME_UNSIGNED_SHORT = "unsigned short";
+ private static final String TYPE_NAME_LONG = "long";
+ private static final String TYPE_NAME_UNSIGNED_LONG = "unsigned long";
+ private static final String TYPE_NAME_HYPER = "hyper";
+ private static final String TYPE_NAME_UNSIGNED_HYPER = "unsigned hyper";
+ private static final String TYPE_NAME_FLOAT = "float";
+ private static final String TYPE_NAME_DOUBLE = "double";
+ private static final String TYPE_NAME_CHAR = "char";
+ private static final String TYPE_NAME_STRING = "string";
+ private static final String TYPE_NAME_TYPE = "type";
+ private static final String TYPE_NAME_ANY = "any";
+
+ // must be sorted same as TypeClass:
+ private static final String[] __typeClassToTypeName = new String[] {
+ TYPE_NAME_VOID,
+ TYPE_NAME_CHAR,
+ TYPE_NAME_BOOLEAN,
+ TYPE_NAME_BYTE,
+ TYPE_NAME_SHORT,
+ TYPE_NAME_UNSIGNED_SHORT,
+ TYPE_NAME_LONG,
+ TYPE_NAME_UNSIGNED_LONG,
+ TYPE_NAME_HYPER,
+ TYPE_NAME_UNSIGNED_HYPER,
+ TYPE_NAME_FLOAT,
+ TYPE_NAME_DOUBLE,
+ TYPE_NAME_STRING,
+ TYPE_NAME_TYPE,
+ TYPE_NAME_ANY
+ };
+
+ private static final class TypeInfo {
+ TypeInfo(
+ TypeClass thePrimary, TypeClass theAlternative,
+ boolean theSequenceComponentType)
+ {
+ primary = thePrimary;
+ alternative = theAlternative;
+ sequenceComponentType = theSequenceComponentType;
+ }
+
+ final TypeClass primary;
+ final TypeClass alternative;
+ final boolean sequenceComponentType;
+ }
+
+ private static final HashMap<Class<?>, TypeInfo> __javaClassToTypeClass =
+ new HashMap<Class<?>, TypeInfo>();
+ static {
+ __javaClassToTypeClass.put(
+ void.class, new TypeInfo(TypeClass.VOID, TypeClass.VOID, false));
+ __javaClassToTypeClass.put(
+ Void.class, new TypeInfo(TypeClass.VOID, TypeClass.VOID, false));
+ __javaClassToTypeClass.put(
+ boolean.class,
+ new TypeInfo(TypeClass.BOOLEAN, TypeClass.BOOLEAN, true));
+ __javaClassToTypeClass.put(
+ Boolean.class,
+ new TypeInfo(TypeClass.BOOLEAN, TypeClass.BOOLEAN, false));
+ __javaClassToTypeClass.put(
+ byte.class, new TypeInfo(TypeClass.BYTE, TypeClass.BYTE, true));
+ __javaClassToTypeClass.put(
+ Byte.class, new TypeInfo(TypeClass.BYTE, TypeClass.BYTE, false));
+ __javaClassToTypeClass.put(
+ short.class,
+ new TypeInfo(TypeClass.SHORT, TypeClass.UNSIGNED_SHORT, true));
+ __javaClassToTypeClass.put(
+ Short.class,
+ new TypeInfo(TypeClass.SHORT, TypeClass.UNSIGNED_SHORT, false));
+ __javaClassToTypeClass.put(
+ int.class,
+ new TypeInfo(TypeClass.LONG, TypeClass.UNSIGNED_LONG, true));
+ __javaClassToTypeClass.put(
+ Integer.class,
+ new TypeInfo(TypeClass.LONG, TypeClass.UNSIGNED_LONG, false));
+ __javaClassToTypeClass.put(
+ long.class,
+ new TypeInfo(TypeClass.HYPER, TypeClass.UNSIGNED_HYPER, true));
+ __javaClassToTypeClass.put(
+ Long.class,
+ new TypeInfo(TypeClass.HYPER, TypeClass.UNSIGNED_HYPER, false));
+ __javaClassToTypeClass.put(
+ float.class, new TypeInfo(TypeClass.FLOAT, TypeClass.FLOAT, true));
+ __javaClassToTypeClass.put(
+ Float.class, new TypeInfo(TypeClass.FLOAT, TypeClass.FLOAT, false));
+ __javaClassToTypeClass.put(
+ double.class,
+ new TypeInfo(TypeClass.DOUBLE, TypeClass.DOUBLE, true));
+ __javaClassToTypeClass.put(
+ Double.class,
+ new TypeInfo(TypeClass.DOUBLE, TypeClass.DOUBLE, false));
+ __javaClassToTypeClass.put(
+ char.class, new TypeInfo(TypeClass.CHAR, TypeClass.CHAR, true));
+ __javaClassToTypeClass.put(
+ Character.class,
+ new TypeInfo(TypeClass.CHAR, TypeClass.CHAR, false));
+ __javaClassToTypeClass.put(
+ String.class,
+ new TypeInfo(TypeClass.STRING, TypeClass.STRING, true));
+ __javaClassToTypeClass.put(
+ Type.class, new TypeInfo(TypeClass.TYPE, TypeClass.TYPE, true));
+ __javaClassToTypeClass.put(
+ Any.class, new TypeInfo(TypeClass.ANY, TypeClass.ANY, true));
+ __javaClassToTypeClass.put(
+ Object.class,
+ new TypeInfo(TypeClass.ANY, TypeClass.INTERFACE, true));
+ }
+
+ public static final Type VOID = new Type(void.class);
+ public static final Type CHAR = new Type(char.class);
+ public static final Type BOOLEAN = new Type(boolean.class);
+ public static final Type BYTE = new Type(byte.class);
+ public static final Type SHORT = new Type(short.class);
+ public static final Type UNSIGNED_SHORT = new Type(
+ TYPE_NAME_UNSIGNED_SHORT, TypeClass.UNSIGNED_SHORT);
+ public static final Type LONG = new Type(int.class);
+ public static final Type UNSIGNED_LONG = new Type(
+ TYPE_NAME_UNSIGNED_LONG, TypeClass.UNSIGNED_LONG);
+ public static final Type HYPER = new Type(long.class);
+ public static final Type UNSIGNED_HYPER = new Type(
+ TYPE_NAME_UNSIGNED_HYPER, TypeClass.UNSIGNED_HYPER);
+ public static final Type FLOAT = new Type(float.class);
+ public static final Type DOUBLE = new Type(double.class);
+ public static final Type STRING = new Type(String.class);
+ public static final Type TYPE = new Type(Type.class);
+ public static final Type ANY = new Type(Any.class);
+
+ /**
+ * Constructs a new <code>Type</code> which defaults to <code>VOID</code>.
+ */
+ public Type() {
+ init(null, void.class, false, false, false);
+ }
+
+ /**
+ * Constructs a new <code>Type</code> with the given type class and type
+ * name.
+ *
+ * @param typeName the type name. Must not be <code>null</code>.
+ * @param typeClass the type class. Must not be <code>null</code>, and must
+ * match the <code>typeName</code> (for example, it is illegal to
+ * combine a <code>typeName</code> of <code>"void"</code> with a
+ * <code>typeClass</code> of <code>BOOLEAN</code>).
+ */
+ public Type(String typeName, TypeClass typeClass) {
+ _typeClass = typeClass;
+ _typeName = typeName;
+ }
+
+ /**
+ * Constructs a new <code>Type</code> from the given
+ * <code>java.lang.Class</code>.
+ *
+ * <p>This is equivalent to <code>Type(zClass, false)</code>.</p>
+ *
+ * @param zClass the Java class of this type. Must not be
+ * <code>null</code>.
+ */
+ public Type(Class<?> zClass) {
+ init(null, zClass, false, false, false);
+ }
+
+ /**
+ * Constructs a new <code>Type</code> from the given
+ * <code>java.lang.Class</code>, handling ambiguous cases.
+ *
+ * <p>In certain cases, one Java class corresponds to two UNO types (e.g.,
+ * the Java class <code>short[].class</code> corresponds to both a sequence
+ * of <code>SHORT</code> and a sequence of <code>UNSIGNED SHORT</code> in
+ * UNO). In such ambiguous cases, the parameter <code>alternative</code>
+ * controls which UNO type is chosen:
+ * <ul>
+ * <li>If the Java type is (an array type with element type)
+ * <code>short</code> or <code>java.lang.Short</code>: If
+ * <code>alternative</code> is <code>false</code>, the chosen UNO type is
+ * (a sequence type with element type) <code>SHORT</code>. If
+ * <code>alternative</code> is <code>true</code>, the chosen UNO type is
+ * (a sequence type with element type) <code>UNSIGNED SHORT</code>.</li>
+ *
+ * <li>If the Java type is (an array type with element type)
+ * <code>int</code> or <code>java.lang.Integer</code>: If
+ * <code>alternative</code> is <code>false</code>, the chosen UNO type is
+ * (a sequence type with element type) <code>LONG</code>. If
+ * <code>alternative</code> is <code>true</code>, the chosen UNO type is
+ * (a sequence type with element type) <code>UNSIGNED LONG</code>.</li>
+ *
+ * <li>If the Java type is (an array type with element type)
+ * <code>long</code> or <code>java.lang.Long</code>: If
+ * <code>alternative</code> is <code>false</code>, the chosen UNO type is
+ * (a sequence type with element type) <code>HYPER</code>. If
+ * <code>alternative</code> is <code>true</code>, the chosen UNO type is
+ * (a sequence type with element type) <code>UNSIGNED HYPER</code>.</li>
+ *
+ * <li>If the Java type is (an array type with element type)
+ * <code>java.lang.Object</code>: If <code>alternative</code> is
+ * <code>false</code>, the chosen UNO type is (a sequence type with
+ * element type) <code>ANY</code>. If <code>alternative</code> is
+ * <code>true</code>, the chosen UNO type is (a sequence type with element
+ * type) <code>com.sun.star.uno.XInterface</code>.</li>
+ * </ul>
+ * <p>In all other cases, the value of <code>alternative</code> is
+ * ignored.</p>
+ *
+ * <p>This constructor cannot be used to create <code>Type</code> instances
+ * that represent (sequences of) instantiated polymorphic struct types.</p>
+ *
+ * @param zClass the Java class of this type; must not be <code>null</code>
+ * @param alternative controls which UNO type to choose in case of
+ * ambiguities
+ *
+ * @since UDK 3.2.0
+ */
+ public Type(Class<?> zClass, boolean alternative) {
+ init(null, zClass, alternative, false, false);
+ }
+
+ private Type(
+ Class<?> zClass, boolean alternative, boolean sequenceComponentType)
+ {
+ init(null, zClass, alternative, false, sequenceComponentType);
+ }
+
+ /**
+ * Constructs a new <code>Type</code> from the given type description.
+ *
+ * <em>For internal URE use only. Not to be used by client code.</em>
+ *
+ * @param typeDescription a type description. Must not be
+ * <code>null</code>.
+ */
+ public Type(TypeDescription typeDescription) {
+ _typeName = typeDescription.getTypeName();
+ _typeClass = typeDescription.getTypeClass();
+ _iTypeDescription = typeDescription;
+ }
+
+ /**
+ * Constructs a new <code>Type</code> with the given type name.
+ *
+ * @param typeName the name of this type; must not be <code>null</code>.
+ */
+ public Type(String typeName) {
+ if (typeName.startsWith("[]")) {
+ _typeName = typeName;
+ _typeClass = TypeClass.SEQUENCE;
+ return;
+ }
+ for (int i = 0; i < __typeClassToTypeName.length; ++i) {
+ if (__typeClassToTypeName[i].equals(typeName)) {
+ _typeName = typeName;
+ _typeClass = TypeClass.fromInt(i);
+ return;
+ }
+ }
+ int i = typeName.indexOf('<');
+ try {
+ init(
+ typeName,
+ Class.forName(i < 0 ? typeName : typeName.substring(0, i)),
+ false, i >= 0, false);
+ } catch (ClassNotFoundException e) {
+ throw new RuntimeException(e);
+ }
+ }
+
+ /**
+ * Constructs a new <code>Type</code> with the given type class.
+ *
+ * @param typeClass the type class of this type; must not be
+ * <code>null</code>. Only type classes for simple types are allowed
+ * here.
+ *
+ * @throws IllegalArgumentException if the given <code>typeClass</code> is
+ * not simple (for example, a struct or an interface type). This
+ * constructor could not find out the type name in such a case.
+ */
+ public Type(TypeClass typeClass) {
+ if(__isTypeClassPrimitive(typeClass)) {
+ _typeClass = typeClass;
+ _typeName = __typeClassToTypeName[typeClass.getValue()];
+ }
+ else
+ throw new IllegalArgumentException(typeClass + " is not primitive");
+ }
+
+ /**
+ * Gets the type class.
+ *
+ * @return the type class. Will never be <code>null</code>, but might be
+ * <code>UNKNOWN</code>.
+ */
+ public TypeClass getTypeClass() {
+ return _typeClass;
+ }
+
+ /**
+ * Gets the type name.
+ *
+ * @return the type name; will never be <code>null</code>
+ */
+ public String getTypeName() {
+ return _typeName;
+ }
+
+ /**
+ * Gets the Java class.
+ *
+ * @return the type name; may be <code>null</code> in extreme situations
+ * (inconsistent <code>TypeClass</code>, error loading a class)
+ */
+ public Class<?> getZClass() {
+ synchronized (this) {
+ if (_class == null) {
+ _class = determineClass();
+ }
+ }
+ return _class;
+ }
+
+ /**
+ * Gives the type description of this type.
+ *
+ * <em>For internal URE use only. Not to be used by client code.</em>
+ *
+ * @return the type description; may be <code>null</code>
+ */
+ public TypeDescription getTypeDescription() {
+ return _iTypeDescription;
+ }
+
+ /**
+ * Sets the type description for this type.
+ *
+ * <em>For internal URE use only. Not to be used by client code.</em>
+ *
+ * @param typeDescription the type description
+ */
+ public void setTypeDescription(TypeDescription typeDescription) {
+ _iTypeDescription = typeDescription;
+ }
+
+ /**
+ * Determines whether this UNO type is a supertype of another UNO type.
+ *
+ * UNO only defines the following supertype relations:
+ * (1) A struct type t1 is a supertype of a struct type t2, if either t1
+ * and t2 are the same, or t1 is a direct or indirect parent of t2.
+ * (2) An exception type t1 is a supertype of an exception type t2, if
+ * either t1 and t2 are the same, or t1 is a direct or indirect parent
+ * of t2.
+ * (3) An interface type t1 is a supertype of an interface type t2, if
+ * either t1 and t2 are the same, or t1 is a direct or indirect parent
+ * of t2.
+ *
+ * Following the conventions of the Java UNO language binding,
+ * com.sun.star.uno.Exception is not considered a supertype of
+ * com.sun.star.uno.RuntimeException or any exception type derived from
+ * com.sun.star.uno.RuntimeException.
+ *
+ * @param type some Type
+ * @return true if this type is a supertype of the given type
+ *
+ * @since UDK 3.2.0
+ */
+ public boolean isSupertypeOf(Type type) {
+ if (_typeClass != type._typeClass) {
+ return false;
+ }
+ switch (_typeClass.getValue()) {
+ case TypeClass.SEQUENCE_value:
+ case TypeClass.ENUM_value:
+ return _typeName.equals(type._typeName);
+
+ case TypeClass.STRUCT_value:
+ // This check exploits the fact that an instantiated polymorphic
+ // struct type may not be the direct base of a struct type:
+ if (_typeName.indexOf('<') >= 0 || type._typeName.indexOf('<') >= 0)
+ {
+ return _typeName.equals(type._typeName);
+ }
+ // fall-through
+ case TypeClass.EXCEPTION_value:
+ case TypeClass.INTERFACE_value:
+ Class<?> c1 = getZClass();
+ Class<?> c2 = type.getZClass();
+ return c1 != null && c2 != null && c1.isAssignableFrom(c2);
+
+ default:
+ return true;
+ }
+ }
+
+ /**
+ * Indicates whether some other object is equal to this one.
+ *
+ * @param obj the reference object with which to compare.
+ * @return <code>true</code> if this object is the same as the obj argument;
+ * <code>false</code> otherwise.
+ * @see java.lang.Object#equals
+ */
+ @Override
+ public boolean equals(Object obj) {
+ return obj instanceof Type
+ && _typeClass == ((Type) obj)._typeClass
+ && _typeName.equals(((Type) obj)._typeName);
+ }
+
+ /**
+ * Returns a hash code value for the object.
+ *
+ * @return a hash code value for this object.
+ * @see java.lang.Object#hashCode
+ */
+ @Override
+ public int hashCode() {
+ return _typeName.hashCode();
+ }
+
+ /**
+ * Returns a string representation of the object.
+ *
+ * @return a string representation of the object.
+ * @see java.lang.Object#toString
+ */
+ @Override
+ public String toString() {
+ return "Type[" + _typeName + "]";
+ }
+
+ private void init(
+ String name, Class<?> zClass, boolean alternative, boolean arguments,
+ boolean sequenceComponentType)
+ {
+ TypeInfo info = __javaClassToTypeClass.get(zClass);
+ if (info != null) {
+ if (sequenceComponentType && !info.sequenceComponentType) {
+ throw new IllegalArgumentException(
+ zClass + " cannot be sequence component type");
+ }
+ // info only contains primitive type classes, except for
+ // TypeClass.INTERFACE, which stands for XInterface (the alternative
+ // interpretation of java.lang.Object):
+ _typeClass = alternative ? info.alternative : info.primary;
+ _typeName = _typeClass == TypeClass.INTERFACE
+ ? XInterface.class.getName()
+ : __typeClassToTypeName[_typeClass.getValue()];
+ // do not assign _class from zClass, as _class should always be
+ // normalized (e.g., boolean.class instead of
+ // java.lang.Boolean.class); getZClass will later calculate the
+ // correct class when needed
+ } else if (zClass.isArray()) {
+ Type t = new Type(zClass.getComponentType(), alternative, true);
+ _typeClass = t.getTypeClass() != TypeClass.UNKNOWN
+ ? TypeClass.SEQUENCE : TypeClass.UNKNOWN;
+ _typeName = "[]" + t.getTypeName();
+ // do not assign _class from zClass, as _class should always be
+ // normalized (e.g., boolean[].class instead of
+ // java.lang.Boolean[].class); getZClass will later calculate the
+ // correct class when needed
+ } else if (Enum.class.isAssignableFrom(zClass)) {
+ _typeClass = zClass != Enum.class
+ ? TypeClass.ENUM : TypeClass.UNKNOWN;
+ _typeName = zClass.getName();
+ _class = zClass;
+ } else if (Throwable.class.isAssignableFrom(zClass)) {
+ _typeClass
+ = com.sun.star.uno.Exception.class.isAssignableFrom(zClass)
+ || com.sun.star.uno.RuntimeException.class.isAssignableFrom(
+ zClass)
+ ? TypeClass.EXCEPTION : TypeClass.UNKNOWN;
+ _typeName = zClass.getName();
+ _class = zClass;
+ } else if (zClass.isInterface()) {
+ _typeClass = XInterface.class.isAssignableFrom(zClass)
+ ? TypeClass.INTERFACE : TypeClass.UNKNOWN;
+ _typeName = zClass.getName();
+ _class = zClass;
+ } else if (XInterface.class.isAssignableFrom(zClass)) {
+ // This case is needed by code that uses this constructor to
+ // calculate the UNO type corresponding to a Java object:
+ _typeClass = TypeClass.INTERFACE;
+ _typeName = XInterface.class.getName();
+ _class = XInterface.class;
+ } else {
+ // assert zClass != Object.class && !zClass.isPrimitive();
+ _typeClass = TypeClass.STRUCT;
+ _typeName = name == null ? zClass.getName() : name;
+ _class = zClass;
+ }
+ if (arguments && _typeClass != TypeClass.STRUCT) {
+ throw new IllegalArgumentException(
+ zClass + " cannot have type arguments");
+ }
+ }
+
+ private Class<?> determineClass() {
+ switch (_typeClass.getValue()) {
+ case TypeClass.VOID_value:
+ return _typeName.equals(TYPE_NAME_VOID) ? void.class : null;
+
+ case TypeClass.BOOLEAN_value:
+ return _typeName.equals(TYPE_NAME_BOOLEAN) ? boolean.class : null;
+
+ case TypeClass.BYTE_value:
+ return _typeName.equals(TYPE_NAME_BYTE) ? byte.class : null;
+
+ case TypeClass.SHORT_value:
+ return _typeName.equals(TYPE_NAME_SHORT) ? short.class : null;
+
+ case TypeClass.UNSIGNED_SHORT_value:
+ return _typeName.equals(TYPE_NAME_UNSIGNED_SHORT)
+ ? short.class : null;
+
+ case TypeClass.LONG_value:
+ return _typeName.equals(TYPE_NAME_LONG) ? int.class : null;
+
+ case TypeClass.UNSIGNED_LONG_value:
+ return _typeName.equals(TYPE_NAME_UNSIGNED_LONG) ? int.class : null;
+
+ case TypeClass.HYPER_value:
+ return _typeName.equals(TYPE_NAME_HYPER) ? long.class : null;
+
+ case TypeClass.UNSIGNED_HYPER_value:
+ return _typeName.equals(TYPE_NAME_UNSIGNED_HYPER)
+ ? long.class : null;
+
+ case TypeClass.FLOAT_value:
+ return _typeName.equals(TYPE_NAME_FLOAT) ? float.class : null;
+
+ case TypeClass.DOUBLE_value:
+ return _typeName.equals(TYPE_NAME_DOUBLE) ? double.class : null;
+
+ case TypeClass.CHAR_value:
+ return _typeName.equals(TYPE_NAME_CHAR) ? char.class : null;
+
+ case TypeClass.STRING_value:
+ return _typeName.equals(TYPE_NAME_STRING) ? String.class : null;
+
+ case TypeClass.TYPE_value:
+ return _typeName.equals(TYPE_NAME_TYPE) ? Type.class : null;
+
+ case TypeClass.ANY_value:
+ return _typeName.equals(TYPE_NAME_ANY) ? Object.class : null;
+
+ case TypeClass.SEQUENCE_value:
+ StringBuffer buf = new StringBuffer();
+ int offset = 0;
+ for (; _typeName.startsWith("[]", offset); offset += "[]".length())
+ {
+ buf.append('[');
+ }
+ if (buf.length() == 0) {
+ return null;
+ }
+ String base = _typeName.substring(offset);
+ if (base.equals(TYPE_NAME_VOID)) {
+ buf.append('V');
+ } else if (base.equals(TYPE_NAME_BOOLEAN)) {
+ buf.append('Z');
+ } else if (base.equals(TYPE_NAME_BYTE)) {
+ buf.append('B');
+ } else if (base.equals(TYPE_NAME_SHORT)
+ || base.equals(TYPE_NAME_UNSIGNED_SHORT)) {
+ buf.append('S');
+ } else if (base.equals(TYPE_NAME_LONG)
+ || base.equals(TYPE_NAME_UNSIGNED_LONG)) {
+ buf.append('I');
+ } else if (base.equals(TYPE_NAME_HYPER)
+ || base.equals(TYPE_NAME_UNSIGNED_HYPER)) {
+ buf.append('J');
+ } else if (base.equals(TYPE_NAME_FLOAT)) {
+ buf.append('F');
+ } else if (base.equals(TYPE_NAME_DOUBLE)) {
+ buf.append('D');
+ } else if (base.equals(TYPE_NAME_CHAR)) {
+ buf.append('C');
+ } else if (base.equals(TYPE_NAME_STRING)) {
+ buf.append("Ljava.lang.String;");
+ } else if (base.equals(TYPE_NAME_TYPE)) {
+ buf.append("Lcom.sun.star.uno.Type;");
+ } else if (base.equals(TYPE_NAME_ANY)) {
+ buf.append("Ljava.lang.Object;");
+ } else {
+ int args = base.indexOf('<');
+ if (args >= 0) {
+ base = base.substring(0, args);
+ }
+ Class<?> c;
+ try {
+ c = Class.forName(base);
+ } catch (ClassNotFoundException e) {
+ return null;
+ }
+ if (args < 0 && new Type(c).getTypeClass() == TypeClass.UNKNOWN)
+ {
+ return null;
+ }
+ buf.append('L');
+ buf.append(base);
+ buf.append(';');
+ }
+ try {
+ return Class.forName(buf.toString());
+ } catch (ClassNotFoundException e) {
+ return null;
+ }
+
+ case TypeClass.ENUM_value:
+ case TypeClass.EXCEPTION_value:
+ case TypeClass.INTERFACE_value:
+ {
+ Class<?> c;
+ try {
+ c = Class.forName(_typeName);
+ } catch (ClassNotFoundException e) {
+ return null;
+ }
+ return new Type(c).equals(this) ? c : null;
+ }
+
+ case TypeClass.STRUCT_value:
+ {
+ int args = _typeName.indexOf('<');
+ Class<?> c;
+ try {
+ c = Class.forName(
+ args < 0 ? _typeName : _typeName.substring(0, args));
+ } catch (ClassNotFoundException e) {
+ return null;
+ }
+ return args >= 0 || new Type(c).equals(this) ? c : null;
+ }
+
+ default:
+ return null;
+ }
+ }
+
+ private static boolean __isTypeClassPrimitive(TypeClass typeClass) {
+ return typeClass.getValue() < __typeClassToTypeName.length;
+ }
+
+ private TypeClass _typeClass; // TODO should be final
+ private String _typeName; // TODO should be final
+
+ private Class<?> _class;
+ private TypeDescription _iTypeDescription;
+}
diff --git a/ridljar/com/sun/star/uno/UnoRuntime.java b/ridljar/com/sun/star/uno/UnoRuntime.java
new file mode 100644
index 0000000000..9c2eedbd4e
--- /dev/null
+++ b/ridljar/com/sun/star/uno/UnoRuntime.java
@@ -0,0 +1,726 @@
+/*
+ * 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 com.sun.star.uno;
+
+import java.io.IOException;
+import java.lang.reflect.Array;
+import java.lang.reflect.Constructor;
+import java.util.ArrayList;
+import java.util.Iterator;
+import java.util.UUID;
+import java.util.WeakHashMap;
+
+import com.sun.star.lib.uno.typedesc.FieldDescription;
+import com.sun.star.lib.uno.typedesc.TypeDescription;
+import com.sun.star.lib.util.WeakMap;
+
+/**
+ * The central class needed for implementing or using UNO components in Java.
+ *
+ * <p>The methods <code>queryInterface</code> and <code>areSame</code> delegate
+ * calls to the implementing objects and are used instead of casts,
+ * <code>instanceof</code>, <code>==</code>, and <code>equals</code>.</p>
+ *
+ * <p>For historic reasons, this class is not <code>final</code>, and has a
+ * <code>public</code> constructor. These artifacts are considered mistakes,
+ * which might be corrected in a future version of this class, so client code
+ * should not rely on them.</p>
+ *
+ * @see com.sun.star.uno.IBridge
+ * @see com.sun.star.uno.IEnvironment
+ * @see com.sun.star.uno.IQueryInterface
+ */
+public class UnoRuntime {
+ /**
+ * @deprecated As of UDK&nbsp;3.2.0, do not create instances of this class.
+ * It is considered a historic mistake to have a <code>public</code>
+ * constructor for this class, which only has <code>static</code> members.
+ * Also, this class might be changed to become <code>final</code> in a
+ * future version.
+ */
+ @Deprecated
+ public UnoRuntime() {}
+
+ /**
+ * Generates a worldwide unique identifier string.
+ *
+ * <p>It is guaranteed that every invocation of this method generates a new
+ * ID, which is unique within the VM. The quality of &ldquo;worldwide
+ * unique&rdquo; will depend on the actual implementation, you should look
+ * at the source to determine if it meets your requirements.</p>
+ *
+ * @return a unique <code>String</code>
+ */
+ public static String getUniqueKey() {
+ synchronized (uniqueKeyLock) {
+ if (uniqueKeyCount == Long.MAX_VALUE) {
+ long time;
+ for (time = System.currentTimeMillis(); time == uniqueKeyTime;)
+ {
+ // Conservatively sleep for 100 millisecond to wait for
+ // System.currentTimeMillis() to change:
+ try {
+ Thread.sleep(100);
+ } catch (InterruptedException e) {
+ Thread.currentThread().interrupt();
+ }
+ }
+ uniqueKeyTime = time;
+ uniqueKeyCount = Long.MIN_VALUE;
+ }
+ return uniqueKeyHostPrefix + Long.toString(uniqueKeyTime, 16) + ":"
+ + Long.toString(uniqueKeyCount++, 16);
+ }
+ }
+
+ /**
+ * Generates a worldwide unique object identifier (OID) for the given
+ * Java object.
+ *
+ * <p>It is guaranteed that subsequent calls to this method with the same
+ * Java object will give the same ID.</p>
+ *
+ * <p>This method is generally of little use for client code. It should be
+ * considered a mistake that this method is published at all.</p>
+ *
+ * @param object any object for which an OID shall be generated; must not be
+ * <code>null</code>
+ * @return the generated OID
+ * @see com.sun.star.uno.IQueryInterface#getOid
+ */
+ public static String generateOid(Object object) {
+ String oid = null;
+ if (object instanceof IQueryInterface) {
+ oid = ((IQueryInterface) object).getOid();
+ }
+ if (oid == null) {
+ synchronized (oidMap) {
+ oid = oidMap.get(object);
+ if (oid == null) {
+ oid = UUID.randomUUID().toString() + oidSuffix;
+ oidMap.put(object, oid);
+ }
+ }
+ }
+ return oid;
+ }
+
+ /**
+ * Queries the given UNO object for the given UNO interface type.
+ *
+ * <p>This method returns <code>null</code> in case the given UNO object
+ * does not support the given UNO interface type (or is itself
+ * <code>null</code>). Otherwise, a reference to a Java object implementing
+ * the Java interface type corresponding to the given UNO interface is
+ * returned. In the latter case, it is unspecified whether the returned
+ * Java object is the same as the given object, or is another facet of that
+ * UNO object.</p>
+ *
+ * @param type the requested UNO interface type; must be a <code>Type</code>
+ * object representing a UNO interface type
+ * @param object a reference to any Java object representing (a facet of) a
+ * UNO object; may be <code>null</code>
+ * @return a reference to the requested UNO interface type if available,
+ * otherwise <code>null</code>
+ * @see com.sun.star.uno.IQueryInterface#queryInterface
+ */
+ public static Object queryInterface(Type type, Object object) {
+ // Gracefully handle those situations where the passed in UNO object is
+ // wrapped in an Any. Strictly speaking, such a situation constitutes a
+ // bug, but it is anticipated that such situations will arise quite
+ // often in practice (especially since UNO Anys containing an XInterface
+ // reference are not wrapped in a Java Any, but UNO Anys containing any
+ // other interface reference are wrapped in a Java Any, which can lead
+ // to confusion).
+ if (object instanceof Any) {
+ Any a = (Any) object;
+ if (a.getType().getTypeClass() == TypeClass.INTERFACE) {
+ object = a.getObject();
+ }
+ }
+ if (object instanceof IQueryInterface) {
+ object = ((IQueryInterface) object).queryInterface(type);
+ if (object instanceof Any) {
+ Any a = (Any) object;
+ object = a.getType().getTypeClass() == TypeClass.INTERFACE
+ ? a.getObject() : null;
+ }
+ }
+ // Ensure that the object implements the requested interface type:
+ Class<?> c = type.getZClass();
+ if (c == null || !c.isInstance(object)) {
+ object = null;
+ }
+ return object;
+ }
+
+ /**
+ * Queries the given UNO object for the given Java class (which must
+ * represent a UNO interface type).
+ *
+ * @param <T> the requested UNO interface type.
+ * @param zInterface a Java class representing a UNO interface type
+ * @param object a reference to any Java object representing (a facet of) a
+ * UNO object; may be <code>null</code>
+ * @return a reference to the requested UNO interface type if available,
+ * otherwise <code>null</code>
+ * @see #queryInterface(Type, Object)
+ */
+ @SuppressWarnings("unchecked")
+ public static <T> T queryInterface(Class<T> zInterface, Object object) {
+ return (T) queryInterface(new Type(zInterface), object);
+ }
+
+ /**
+ Tests two UNO <code>ANY</code> values for equality.
+
+ <p>Two UNO values are <dfn>equal</dfn> if and only if they are of the
+ same UNO type&nbsp;<var>t</var>, and they meet the following condition,
+ depending on&nbsp;<var>t</var>:</p>
+ <ul>
+ <li>If <var>t</var> is a primitive type, then both values must denote
+ the same element of the set of values of&nbsp;<var>t</var>.</li>
+
+ <li>If <var>t</var> is a structured type, then both values must
+ recursively contain corresponding values that are equal.</li>
+
+ <li>If <var>t</var> is an interface type, then the two values must be
+ either both null references, or both references to the same UNO
+ object.</li>
+ </ul>
+
+ @param any1 a Java value representing a UNO <code>ANY</code> value.
+
+ @param any2 a Java value representing a UNO <code>ANY</code> value.
+
+ @return <code>true</code> if and only if the two arguments represent
+ equal UNO values.
+ */
+ public static boolean areSame(Object any1, Object any2) {
+ Any a1 = Any.complete(any1);
+ Any a2 = Any.complete(any2);
+ Type t = a1.getType();
+ if (!a2.getType().equals(t)) {
+ return false;
+ }
+ Object v1 = a1.getObject();
+ Object v2 = a2.getObject();
+ switch (t.getTypeClass().getValue()) {
+ case TypeClass.VOID_value:
+ return true;
+ case TypeClass.BOOLEAN_value:
+ case TypeClass.BYTE_value:
+ case TypeClass.SHORT_value:
+ case TypeClass.UNSIGNED_SHORT_value:
+ case TypeClass.LONG_value:
+ case TypeClass.UNSIGNED_LONG_value:
+ case TypeClass.HYPER_value:
+ case TypeClass.UNSIGNED_HYPER_value:
+ case TypeClass.FLOAT_value:
+ case TypeClass.DOUBLE_value:
+ case TypeClass.CHAR_value:
+ case TypeClass.STRING_value:
+ case TypeClass.TYPE_value:
+ return v1.equals(v2);
+ case TypeClass.SEQUENCE_value:
+ int n = Array.getLength(v1);
+ if (n != Array.getLength(v2)) {
+ return false;
+ }
+ for (int i = 0; i < n; ++i) {
+ // Recursively using areSame on Java values that are (boxed)
+ // elements of Java arrays representing UNO sequence values,
+ // instead of on Java values that are representations of UNO ANY
+ // values, works by chance:
+ if (!areSame(Array.get(v1, i), Array.get(v2, i))) {
+ return false;
+ }
+ }
+ return true;
+ case TypeClass.ENUM_value:
+ return v1 == v2;
+ case TypeClass.STRUCT_value:
+ case TypeClass.EXCEPTION_value:
+ FieldDescription[] fs;
+ try {
+ fs = TypeDescription.getTypeDescription(t).
+ getFieldDescriptions();
+ } catch (ClassNotFoundException e) {
+ throw new java.lang.RuntimeException(e);
+ }
+ for (int i = 0; i< fs.length; ++i) {
+ Type ft = new Type(fs[i].getTypeDescription());
+ try {
+ // Recursively using areSame on Java values that are (boxed)
+ // fields of Java classes representing UNO struct or
+ // exception values, instead of on Java values that are
+ // representations of UNO ANY values, works by chance:
+ if (!areSame(
+ completeValue(ft, fs[i].getField().get(v1)),
+ completeValue(ft, fs[i].getField().get(v2))))
+ {
+ return false;
+ }
+ } catch (IllegalAccessException e) {
+ throw new java.lang.RuntimeException(e);
+ }
+ }
+ return true;
+ case TypeClass.INTERFACE_value:
+ return v1 == v2
+ || (v1 instanceof IQueryInterface
+ && ((IQueryInterface) v1).isSame(v2))
+ || (v2 instanceof IQueryInterface
+ && ((IQueryInterface) v2).isSame(v1));
+ default:
+ throw new java.lang.RuntimeException(
+ "com.sun.star.uno.Any has bad com.sun.star.uno.TypeClass");
+ }
+ }
+
+ /**
+ Complete a UNO value (make sure it is no invalid <code>null</code>
+ value).
+
+ <p>This is useful for members of parameterized type of instantiated
+ polymorphic struct types, as <code>null</code> is a valid value there
+ (and only there, for all types except <code>ANY</code> and interface
+ types).</p>
+
+ @param type a non-void, non-exception UNO type.
+
+ @param value a Java value representing a UNO value of the given UNO type,
+ or <code>null</code>.
+
+ @return the given value, or the neutral value of the given type, if the
+ given value was an invalid <code>null</code> value.
+
+ @since UDK 3.2.3
+ */
+ public static final Object completeValue(Type type, Object value) {
+ if (value != null) {
+ return value;
+ }
+ switch (type.getTypeClass().getValue()) {
+ case TypeClass.BOOLEAN_value:
+ return Boolean.FALSE;
+ case TypeClass.BYTE_value:
+ return Byte.valueOf((byte) 0);
+ case TypeClass.SHORT_value:
+ case TypeClass.UNSIGNED_SHORT_value:
+ return Short.valueOf((short) 0);
+ case TypeClass.LONG_value:
+ case TypeClass.UNSIGNED_LONG_value:
+ return Integer.valueOf(0);
+ case TypeClass.HYPER_value:
+ case TypeClass.UNSIGNED_HYPER_value:
+ return Long.valueOf(0);
+ case TypeClass.FLOAT_value:
+ return Float.valueOf(0.0f);
+ case TypeClass.DOUBLE_value:
+ return Double.valueOf(0.0);
+ case TypeClass.CHAR_value:
+ return Character.valueOf('\u0000');
+ case TypeClass.STRING_value:
+ return "";
+ case TypeClass.TYPE_value:
+ return Type.VOID;
+ case TypeClass.ANY_value:
+ case TypeClass.INTERFACE_value:
+ return null;
+ case TypeClass.SEQUENCE_value:
+ return Array.newInstance(type.getZClass().getComponentType(), 0);
+ case TypeClass.STRUCT_value:
+ try {
+ return type.getZClass().getConstructor((Class[]) null).
+ newInstance((Object[]) null);
+ } catch (java.lang.RuntimeException e) {
+ throw e;
+ } catch (java.lang.Exception e) {
+ throw new java.lang.RuntimeException(e);
+ }
+ case TypeClass.ENUM_value:
+ try {
+ return type.getZClass().getMethod("getDefault", (Class[]) null).
+ invoke(null, (Object[]) null);
+ } catch (java.lang.RuntimeException e) {
+ throw e;
+ } catch (java.lang.Exception e) {
+ throw new java.lang.RuntimeException(e);
+ }
+ default:
+ throw new IllegalArgumentException(
+ "com.sun.star.uno.UnoRuntime.completeValue called with bad"
+ + " com.sun.star.uno.Type");
+ }
+ }
+
+ /**
+ * Gets the current context of the current thread, or <code>null</code> if
+ * no context has been set for the current thread.
+ *
+ * <p>The current context is thread local, which means that this method
+ * returns the context that was last set for this thread.</p>
+ *
+ * @return the current context of the current thread, or <code>null</code>
+ * if no context has been set for the current thread
+ */
+ public static XCurrentContext getCurrentContext() {
+ return currentContext.get();
+ }
+
+ /**
+ * Sets the current context for the current thread.
+ *
+ * <p>The current context is thread local. To support a stacking behaviour,
+ * every function that sets the current context should reset it to the
+ * original value when exiting (for example, within a <code>finally</code>
+ * block).</p>
+ *
+ * @param context the context to be set; if <code>null</code>, any
+ * previously set context will be removed
+ */
+ public static void setCurrentContext(XCurrentContext context) {
+ if (context == null) {
+ currentContext.remove();
+ } else {
+ currentContext.set(context);
+ }
+ }
+
+ /**
+ * Retrieves an environment of type <code>name</code> with context
+ * <code>context</code>.
+ *
+ * <p>Environments are held weakly by this class. If the requested
+ * environment already exists, this methods simply returns it. Otherwise,
+ * this method looks for it under
+ * <code>com.sun.star.lib.uno.environments.<var>name</var>.<!--
+ * --><var>name</var>_environment</code>.</p>
+ *
+ * @param name the name of the environment
+ * @param context the context of the environment
+ * @throws Exception if something goes awry.
+ * @return an environment.
+ * @see com.sun.star.uno.IEnvironment
+ *
+ * @deprecated As of UDK&nbsp;3.2.0, this method is deprecated, without
+ * offering a replacement.
+ */
+ @Deprecated
+ public static IEnvironment getEnvironment(String name, Object context)
+ throws java.lang.Exception
+ {
+ synchronized (environments) {
+ IEnvironment env = WeakMap.getValue(
+ environments.get(name + context));
+ if (env == null) {
+ Class<?> c = Class.forName(
+ "com.sun.star.lib.uno.environments." + name + "." + name
+ + "_environment");
+ Constructor<?> ctor = c.getConstructor(
+ new Class[] { Object.class });
+ env = (IEnvironment) ctor.newInstance(new Object[] { context });
+ environments.put(name + context, env);
+ }
+ return env;
+ }
+ }
+
+ /**
+ * Gets a bridge from environment <code>from</code> to environment
+ * <code>to</code>.
+ *
+ * <p>Creates a new bridge, if the requested bridge does not yet exist, and
+ * hands the arguments to the bridge.</p>
+ *
+ * <p>If the requested bridge does not exist, it is searched for in package
+ * <code>com.sun.star.lib.uno.bridges.<var>from</var>_<var>to</var>;</code>
+ * and the root classpath as
+ * <code><var>from</var>_<var>to</var>_bridge</code>.</p>
+ *
+ * @param from the source environment
+ * @param to the target environment
+ * @param args the initial arguments for the bridge
+ * @throws Exception if something goes awry.
+ * @return the requested bridge
+ * @see #getBridgeByName
+ * @see com.sun.star.uno.IBridge
+ * @see com.sun.star.uno.IEnvironment
+ *
+ * @deprecated As of UDK&nbsp;3.2.0, this method is deprecated, without
+ * offering a replacement.
+ */
+ @Deprecated
+ public static IBridge getBridge(
+ IEnvironment from, IEnvironment to, Object[] args)
+ throws java.lang.Exception
+ {
+ synchronized (bridges) {
+ String name = from.getName() + "_" + to.getName();
+ String hashName = from.getName() + from.getContext() + "_"
+ + to.getName() + to.getContext();
+ IBridge bridge = WeakMap.getValue(bridges.get(hashName));
+ if(bridge == null) {
+ Class<?> zClass = null;
+ String className = name + "_bridge";
+ try {
+ zClass = Class.forName(className);
+ } catch (ClassNotFoundException e) {
+ className = "com.sun.star.lib.uno.bridges." + name + "."
+ + className;
+ zClass = Class.forName(className);
+ }
+ Class<?>[] signature = {
+ IEnvironment.class, IEnvironment.class, args.getClass() };
+ Constructor<?> constructor = zClass.getConstructor(signature);
+ Object[] iargs = { from, to, args };
+ bridge = (IBridge) constructor.newInstance(iargs);
+ bridges.put(hashName, bridge);
+ }
+ return bridge;
+ }
+ }
+
+ /**
+ * Gets a bridge from environment <code>from</code> to environment
+ * <code>to</code>.
+ *
+ * <p>Creates a new bridge, if the requested bridge does not yet exist, and
+ * hands the arguments to the bridge.</p>
+ *
+ * <p>If the requested bridge does not exist, it is searched for in package
+ * <code>com.sun.star.lib.uno.bridges.<var>from</var>_<var>to</var>;</code>
+ * and the root classpath as
+ * <code><var>from</var>_<var>to</var>_bridge</code>. The used environments
+ * are retrieved through <code>getEnvironment</code>.</p>
+ *
+ * @param from the name of the source environment
+ * @param fromContext the context for the source environment
+ * @param to the name of the target environment
+ * @param toContext the context for the target environment
+ * @param args the initial arguments for the bridge
+ * @throws Exception if something goes awry.
+ * @return the requested bridge
+ * @see #getBridge
+ * @see #getEnvironment
+ * @see com.sun.star.uno.IBridge
+ * @see com.sun.star.uno.IEnvironment
+ *
+ * @deprecated As of UDK&nbsp;3.2.0, this method is deprecated, without
+ * offering a replacement.
+ */
+ @Deprecated
+ public static IBridge getBridgeByName(
+ String from, Object fromContext, String to, Object toContext,
+ Object[] args) throws java.lang.Exception
+ {
+ return getBridge(
+ getEnvironment(from, fromContext), getEnvironment(to, toContext),
+ args);
+ }
+
+ /**
+ * Returns an array of all active bridges.
+ *
+ * @return an array of <code>IBridge</code> objects
+ * @see com.sun.star.uno.IBridge
+ *
+ * @deprecated As of UDK&nbsp;3.2.0, this method is deprecated, without
+ * offering a replacement.
+ */
+ @Deprecated
+ public static IBridge[] getBridges() {
+ ArrayList<Object> l = new ArrayList<Object>();
+ synchronized (bridges) {
+ for (Iterator<java.lang.ref.WeakReference<IBridge>> i = bridges.values().iterator(); i.hasNext();) {
+ IBridge o = WeakMap.getValue(i.next());
+ if (o != null) {
+ l.add(o);
+ }
+ }
+ }
+ return l.toArray(new IBridge[l.size()]);
+ }
+
+ /**
+ * Gets a mapping from environment <code>from</code> to environment
+ * <code>to</code>.
+ *
+ * <p>Mappings are like bridges, except that with mappings one can only map
+ * in one direction. Mappings are here for compatibility with the binary
+ * UNO API. Mappings are implemented as wrappers around bridges.</p>
+ *
+ * @param from the source environment
+ * @param to the target environment
+ * @throws Exception if something goes awry.
+ * @return the requested mapping
+ * @see com.sun.star.uno.IEnvironment
+ * @see com.sun.star.uno.IMapping
+ *
+ * @deprecated As of UDK&nbsp;3.2.0, this method is deprecated, without
+ * offering a replacement.
+ */
+ @Deprecated
+ public static IMapping getMapping(IEnvironment from, IEnvironment to)
+ throws java.lang.Exception
+ {
+ IBridge bridge;
+ try {
+ bridge = getBridge(from, to, null);
+ }
+ catch (ClassNotFoundException e) {
+ bridge = new BridgeTurner(getBridge(to, from, null));
+ }
+ return new MappingWrapper(bridge);
+ }
+
+ /**
+ * Gets a mapping from environment <code>from</code> to environment
+ * <code>to</code>.
+ *
+ * <p>The used environments are retrieved through
+ * <code>getEnvironment</code>.</p>
+ *
+ * @param from the name of the source environment
+ * @param to the name of the target environment
+ * @throws Exception if something goes awry.
+ * @return the requested mapping
+ * @see #getEnvironment
+ * @see #getMapping
+ * @see com.sun.star.uno.IMapping
+ *
+ * @deprecated As of UDK&nbsp;3.2.0, this method is deprecated, without
+ * offering a replacement.
+ */
+ @Deprecated
+ public static IMapping getMappingByName(String from, String to)
+ throws java.lang.Exception
+ {
+ return getMapping(getEnvironment(from, null), getEnvironment(to, null));
+ }
+
+ /**
+ * Resets this <code>UnoRuntime</code> to its initial state.
+ *
+ * <p>Releases all references to bridges and environments.</p>
+ *
+ * @return true if another thread didn't re-insert some bridge or
+ * environment before the method returns. Why that information
+ * would be useful is anybody's guess.
+ *
+ * @deprecated As of UDK&nbsp;3.2.0, this method is deprecated, without
+ * offering a replacement.
+ */
+ @Deprecated
+ public static boolean reset() {
+ synchronized (bridges) {
+ for (Iterator<java.lang.ref.WeakReference<IBridge>> i = bridges.values().iterator(); i.hasNext();) {
+ IBridge b = WeakMap.getValue(i.next());
+ if (b != null) {
+ // The following call to dispose was originally made to
+ // com.sun.star.lib.sandbox.Disposable.dispose, which cannot
+ // throw an InterruptedException or IOException:
+ try {
+ b.dispose();
+ } catch (InterruptedException e) {
+ Thread.currentThread();
+ Thread.interrupted();
+ throw new RuntimeException(
+ "Unexpected exception in UnoRuntime.reset: " + e);
+ } catch (IOException e) {
+ throw new RuntimeException(
+ "Unexpected exception in UnoRuntime.reset: " + e);
+ }
+ }
+ }
+ bridges.clear();
+ }
+ environments.clear();
+ return bridges.isEmpty() && environments.isEmpty();
+ }
+
+ /**
+ * @deprecated As of UDK&nbsp;3.2.0, do not use this internal field.
+ */
+ @Deprecated
+ public static final boolean DEBUG = false;
+
+ private static final class BridgeTurner implements IBridge {
+ public BridgeTurner(IBridge bridge) {
+ this.bridge = bridge;
+ }
+
+ public Object mapInterfaceTo(Object object, Type type) {
+ return bridge.mapInterfaceFrom(object, type);
+ }
+
+ public Object mapInterfaceFrom(Object object, Type type) {
+ return bridge.mapInterfaceTo(object, type);
+ }
+
+ public IEnvironment getSourceEnvironment() {
+ return bridge.getTargetEnvironment();
+ }
+
+ public IEnvironment getTargetEnvironment() {
+ return bridge.getSourceEnvironment();
+ }
+
+ public void acquire() {
+ bridge.acquire();
+ }
+
+ public void release() {
+ bridge.release();
+ }
+
+ public void dispose() throws InterruptedException, IOException {
+ bridge.dispose();
+ }
+
+ private final IBridge bridge;
+ }
+
+ private static final class MappingWrapper implements IMapping {
+ public MappingWrapper(IBridge bridge) {
+ this.bridge = bridge;
+ }
+
+ public Object mapInterface(Object object, Type type) {
+ return bridge.mapInterfaceTo(object, type);
+ }
+
+ private final IBridge bridge;
+ }
+
+ private static final WeakHashMap<Object,String> oidMap = new WeakHashMap<Object,String>();
+ private static final String uniqueKeyHostPrefix
+ = Integer.toString(new Object().hashCode(), 16) + ":";
+ private static final Object uniqueKeyLock = new Object();
+ private static long uniqueKeyTime = System.currentTimeMillis();
+ private static long uniqueKeyCount = Long.MIN_VALUE;
+
+ private static final String oidSuffix = ";java[];" + getUniqueKey();
+
+ private static final ThreadLocal<XCurrentContext> currentContext = new ThreadLocal<XCurrentContext>();
+
+ private static final WeakMap<String,IEnvironment> environments = new WeakMap<String,IEnvironment>();
+ private static final WeakMap<String,IBridge> bridges = new WeakMap<String,IBridge>();
+}
diff --git a/ridljar/com/sun/star/uno/WeakReference.java b/ridljar/com/sun/star/uno/WeakReference.java
new file mode 100644
index 0000000000..a6b171ac2e
--- /dev/null
+++ b/ridljar/com/sun/star/uno/WeakReference.java
@@ -0,0 +1,154 @@
+/* -*- Mode: Java; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
+/*
+ * 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 com.sun.star.uno;
+
+/**
+ * This class holds weak reference to an object.
+ *
+ * <p>It actually holds a reference to a <code>com.sun.star.XAdapter</code>
+ * implementation and obtains a hard reference if necessary.
+ */
+public class WeakReference
+{
+ private OWeakRefListener m_listener;
+ // There is no default constructor. Every instance must register itself with the
+ // XAdapter interface, which is done in the constructors. Assume we have this code
+ // WeakReference ref= new WeakReference();
+ // ref = someOtherWeakReference;
+ //
+ // ref would not be notified (XReference.dispose()) because it did not register
+ // itself. Therefore the XAdapter would be kept alive although this is not
+ // necessary.
+
+ /**
+ * Creates an instance of this class.
+ *
+ * @param obj another instance that is to be copied.
+ */
+ public WeakReference(WeakReference obj)
+ {
+ if (obj == null) {
+ return;
+ }
+ Object weakImpl = obj.get();
+ if (weakImpl == null) {
+ return;
+ }
+ XWeak weak = UnoRuntime.queryInterface(XWeak.class, weakImpl);
+ if (weak != null) {
+ XAdapter adapter = weak.queryAdapter();
+ if (adapter != null)
+ m_listener = new OWeakRefListener(adapter);
+ }
+ }
+
+ /**
+ * Creates an instance of this class.
+ *
+ * @param obj XWeak implementation.
+ */
+ public WeakReference(Object obj)
+ {
+ XWeak weak= UnoRuntime.queryInterface(XWeak.class, obj);
+ if (weak != null)
+ {
+ XAdapter adapter= weak.queryAdapter();
+ if (adapter != null)
+ m_listener= new OWeakRefListener(adapter);
+ }
+ }
+
+ /**
+ * Returns a hard reference to the object that is kept weak by this class.
+ *
+ * @return a hard reference to the XWeak implementation.
+ */
+ public Object get()
+ {
+ if (m_listener != null)
+ return m_listener.get();
+ return null;
+ }
+}
+
+/**
+ * Implementation of com.sun.star.uno.XReference for use with WeakReference.
+ *
+ * <p>It keeps the XAdapter implementation and registers always with it.
+ * Deregistering occurs on notification by the adapter and the adapter is
+ * released.</p>
+ */
+class OWeakRefListener implements XReference
+{
+ private XAdapter m_adapter;
+
+ /**
+ * The constructor registered this object with adapter.
+ *
+ * @param adapter the XAdapter implementation.
+ */
+ OWeakRefListener( XAdapter adapter)
+ {
+ m_adapter= adapter;
+ m_adapter.addReference(this);
+ }
+
+ /**
+ * Method of <code>com.sun.star.uno.XReference</code>.
+ *
+ * <p>When called, it deregisters this object with the adapter and releases
+ * the reference to it.</p>
+ */
+ synchronized public void dispose()
+ {
+ if (m_adapter != null)
+ {
+ m_adapter.removeReference(this);
+ m_adapter= null;
+ }
+ }
+
+ /**
+ * Obtains a hard reference to the object which is kept weak by the adapter
+ * and returns it.
+ *
+ * @return hard reference to the otherwise weakly kept object.
+ */
+ synchronized Object get()
+ {
+ Object retVal= null;
+ if (m_adapter != null)
+ {
+ retVal= m_adapter.queryAdapted();
+ if (retVal == null)
+ {
+ // If this object registered as listener with XAdapter while it was notifying
+ // the listeners then this object might not have been notified. If queryAdapted
+ // returned null then the weak kept object is dead and the listeners have already
+ // been notified. And we missed it.
+ m_adapter.removeReference(this);
+ m_adapter= null;
+ }
+ }
+ return retVal;
+ }
+}
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */