From ed5640d8b587fbcfed7dd7967f3de04b37a76f26 Mon Sep 17 00:00:00 2001 From: Daniel Baumann Date: Sun, 7 Apr 2024 11:06:44 +0200 Subject: Adding upstream version 4:7.4.7. Signed-off-by: Daniel Baumann --- ridljar/BUCK | 46 + ridljar/CustomTarget_javamaker.mk | 26 + ridljar/CustomTarget_test_urp.mk | 28 + ridljar/InternalUnoApi_test_urp.mk | 16 + ridljar/Jar_libreoffice.mk | 139 +++ ridljar/Jar_ridl.mk | 16 + ridljar/Jar_unoloader.mk | 30 + ridljar/JunitTest_bridgefactory.mk | 28 + ridljar/JunitTest_connections.mk | 28 + ridljar/JunitTest_java.mk | 28 + ridljar/JunitTest_java_remote.mk | 36 + ridljar/JunitTest_remote.mk | 37 + ridljar/JunitTest_typedesc.mk | 24 + ridljar/JunitTest_uno.mk | 35 + ridljar/JunitTest_urp.mk | 35 + ridljar/JunitTest_util.mk | 27 + ridljar/Makefile | 7 + ridljar/Module_ridljar.mk | 36 + ridljar/README.md | 3 + .../sun/star/comp/bridgefactory/BridgeFactory.java | 212 ++++ .../com/sun/star/comp/connections/Acceptor.java | 153 +++ .../com/sun/star/comp/connections/Connector.java | 130 +++ .../comp/connections/ConstantInstanceProvider.java | 118 +++ .../sun/star/comp/connections/Implementation.java | 95 ++ .../sun/star/comp/connections/PipedConnection.java | 259 +++++ ridljar/com/sun/star/comp/helper/Bootstrap.java | 429 ++++++++ .../sun/star/comp/helper/BootstrapException.java | 82 ++ .../com/sun/star/comp/helper/ComponentContext.java | 308 ++++++ .../star/comp/helper/ComponentContextEntry.java | 64 ++ .../sun/star/comp/helper/SharedLibraryLoader.java | 175 +++ .../com/sun/star/comp/loader/FactoryHelper.java | 502 +++++++++ ridljar/com/sun/star/comp/loader/JavaLoader.java | 439 ++++++++ .../sun/star/comp/loader/JavaLoaderFactory.java | 90 ++ .../star/comp/loader/RegistrationClassFinder.java | 69 ++ .../star/comp/servicemanager/ServiceManager.java | 662 ++++++++++++ .../com/sun/star/comp/urlresolver/UrlResolver.java | 147 +++ .../star/lib/connections/pipe/PipeConnection.java | 213 ++++ .../star/lib/connections/pipe/pipeAcceptor.java | 123 +++ .../star/lib/connections/pipe/pipeConnector.java | 120 +++ .../connections/socket/ConnectionDescriptor.java | 98 ++ .../lib/connections/socket/SocketConnection.java | 235 +++++ .../lib/connections/socket/socketAcceptor.java | 202 ++++ .../lib/connections/socket/socketConnector.java | 174 +++ ridljar/com/sun/star/lib/uno/Proxy.java | 34 + .../adapter/ByteArrayToXInputStreamAdapter.java | 117 +++ .../adapter/InputStreamToXInputStreamAdapter.java | 145 +++ .../OutputStreamToXOutputStreamAdapter.java | 80 ++ .../adapter/XInputStreamToInputStreamAdapter.java | 218 ++++ .../adapter/XOutputStreamToByteArrayAdapter.java | 94 ++ .../XOutputStreamToOutputStreamAdapter.java | 117 +++ .../lib/uno/bridges/java_remote/BridgedObject.java | 43 + .../lib/uno/bridges/java_remote/ProxyFactory.java | 198 ++++ .../uno/bridges/java_remote/RequestHandler.java | 35 + .../XConnectionInputStream_Adapter.java | 76 ++ .../XConnectionOutputStream_Adapter.java | 89 ++ .../bridges/java_remote/java_remote_bridge.java | 700 ++++++++++++ .../uno/environments/java/java_environment.java | 312 ++++++ .../lib/uno/environments/remote/IProtocol.java | 93 ++ .../lib/uno/environments/remote/IReceiver.java | 40 + .../lib/uno/environments/remote/IThreadPool.java | 115 ++ .../uno/environments/remote/JavaThreadPool.java | 124 +++ .../environments/remote/JavaThreadPoolFactory.java | 87 ++ .../sun/star/lib/uno/environments/remote/Job.java | 163 +++ .../star/lib/uno/environments/remote/JobQueue.java | 373 +++++++ .../star/lib/uno/environments/remote/Message.java | 189 ++++ .../uno/environments/remote/NativeThreadPool.java | 94 ++ .../star/lib/uno/environments/remote/ThreadId.java | 109 ++ .../uno/environments/remote/ThreadPoolManager.java | 74 ++ .../environments/remote/remote_environment.java | 66 ++ .../com/sun/star/lib/uno/helper/ComponentBase.java | 136 +++ ridljar/com/sun/star/lib/uno/helper/Factory.java | 291 +++++ .../star/lib/uno/helper/InterfaceContainer.java | 864 +++++++++++++++ .../uno/helper/MultiTypeInterfaceContainer.java | 155 +++ .../com/sun/star/lib/uno/helper/PropertySet.java | 1103 +++++++++++++++++++ .../sun/star/lib/uno/helper/PropertySetMixin.java | 1111 ++++++++++++++++++++ ridljar/com/sun/star/lib/uno/helper/UnoUrl.java | 401 +++++++ .../com/sun/star/lib/uno/helper/WeakAdapter.java | 94 ++ ridljar/com/sun/star/lib/uno/helper/WeakBase.java | 101 ++ .../com/sun/star/lib/uno/protocols/urp/Cache.java | 114 ++ .../sun/star/lib/uno/protocols/urp/Marshal.java | 355 +++++++ .../lib/uno/protocols/urp/PendingRequests.java | 65 ++ .../sun/star/lib/uno/protocols/urp/Unmarshal.java | 476 +++++++++ .../sun/star/lib/uno/protocols/urp/UrpMessage.java | 48 + .../com/sun/star/lib/uno/protocols/urp/urp.java | 760 +++++++++++++ .../star/lib/uno/typedesc/FieldDescription.java | 78 ++ .../lib/uno/typedesc/MemberDescriptionHelper.java | 54 + .../star/lib/uno/typedesc/MethodDescription.java | 131 +++ .../sun/star/lib/uno/typedesc/TypeDescription.java | 819 +++++++++++++++ .../star/lib/uno/typeinfo/AttributeTypeInfo.java | 86 ++ .../star/lib/uno/typeinfo/ConstantTypeInfo.java | 32 + .../sun/star/lib/uno/typeinfo/MemberTypeInfo.java | 96 ++ .../sun/star/lib/uno/typeinfo/MethodTypeInfo.java | 89 ++ .../star/lib/uno/typeinfo/ParameterTypeInfo.java | 105 ++ .../com/sun/star/lib/uno/typeinfo/TypeInfo.java | 76 ++ .../sun/star/lib/util/AsynchronousFinalizer.java | 117 +++ ridljar/com/sun/star/lib/util/DisposeListener.java | 34 + ridljar/com/sun/star/lib/util/DisposeNotifier.java | 44 + .../com/sun/star/lib/util/NativeLibraryLoader.java | 141 +++ ridljar/com/sun/star/lib/util/StringHelper.java | 46 + ridljar/com/sun/star/lib/util/UrlToFileMapper.java | 94 ++ ridljar/com/sun/star/lib/util/WeakMap.java | 319 ++++++ ridljar/com/sun/star/uno/Any.java | 151 +++ ridljar/com/sun/star/uno/AnyConverter.java | 668 ++++++++++++ ridljar/com/sun/star/uno/Ascii.java | 43 + ridljar/com/sun/star/uno/AsciiString.java | 44 + ridljar/com/sun/star/uno/Enum.java | 50 + ridljar/com/sun/star/uno/IBridge.java | 94 ++ ridljar/com/sun/star/uno/IEnvironment.java | 144 +++ ridljar/com/sun/star/uno/IMapping.java | 41 + ridljar/com/sun/star/uno/IQueryInterface.java | 60 ++ ridljar/com/sun/star/uno/MappingException.java | 65 ++ ridljar/com/sun/star/uno/Type.java | 699 ++++++++++++ ridljar/com/sun/star/uno/UnoRuntime.java | 726 +++++++++++++ ridljar/com/sun/star/uno/WeakReference.java | 154 +++ ridljar/pom.libreoffice.xml | 44 + ridljar/pom.ridl.xml | 54 + ridljar/pom.unoloader.xml | 44 + ridljar/source/libreoffice/manifest | 0 ridljar/source/libreoffice/module-info.java | 142 +++ ridljar/source/unoloader/BUCK | 21 + .../com/sun/star/lib/unoloader/UnoClassLoader.java | 203 ++++ .../com/sun/star/lib/unoloader/UnoLoader.java | 85 ++ .../unoloader/com/sun/star/lib/unoloader/manifest | 1 + ridljar/source/unoloader/module-info.java | 12 + .../comp/bridgefactory/BridgeFactory_Test.java | 92 ++ .../comp/connections/PipedConnection_Test.java | 104 ++ .../bridges/java_remote/BridgedObject_Test.java | 64 ++ .../uno/bridges/java_remote/ProxyFactory_Test.java | 131 +++ .../java_remote/java_remote_bridge_Test.java | 239 +++++ .../environments/java/java_environment_Test.java | 55 + .../remote/JavaThreadPoolFactory_Test.java | 48 + .../lib/uno/environments/remote/JobQueue_Test.java | 263 +++++ .../lib/uno/environments/remote/TestIWorkAt.java | 43 + .../lib/uno/environments/remote/TestReceiver.java | 27 + .../lib/uno/environments/remote/TestWorkAt.java | 81 ++ .../lib/uno/environments/remote/ThreadId_Test.java | 57 + .../uno/environments/remote/ThreadPool_Test.java | 437 ++++++++ .../sun/star/lib/uno/protocols/urp/Cache_Test.java | 134 +++ .../lib/uno/protocols/urp/Marshaling_Test.java | 353 +++++++ .../star/lib/uno/protocols/urp/Protocol_Test.java | 311 ++++++ .../sun/star/lib/uno/protocols/urp/TestBridge.java | 106 ++ .../sun/star/lib/uno/protocols/urp/TestObject.java | 63 ++ .../sun/star/lib/uno/protocols/urp/interfaces.idl | 101 ++ .../lib/uno/typedesc/TypeDescription_Test.java | 298 ++++++ .../star/lib/util/NativeLibraryLoader_Test.java | 76 ++ .../test/com/sun/star/lib/util/WeakMap_Test.java | 74 ++ .../test/com/sun/star/uno/AnyConverter_Test.java | 904 ++++++++++++++++ ridljar/test/com/sun/star/uno/Any_Test.java | 48 + ridljar/test/com/sun/star/uno/Type_Test.java | 104 ++ .../sun/star/uno/UnoRuntime_EnvironmentTest.java | 85 ++ ridljar/test/com/sun/star/uno/UnoRuntime_Test.java | 196 ++++ .../test/com/sun/star/uno/WeakReference_Test.java | 107 ++ ridljar/util/manifest | 46 + 153 files changed, 26136 insertions(+) create mode 100644 ridljar/BUCK create mode 100644 ridljar/CustomTarget_javamaker.mk create mode 100644 ridljar/CustomTarget_test_urp.mk create mode 100644 ridljar/InternalUnoApi_test_urp.mk create mode 100644 ridljar/Jar_libreoffice.mk create mode 100644 ridljar/Jar_ridl.mk create mode 100644 ridljar/Jar_unoloader.mk create mode 100644 ridljar/JunitTest_bridgefactory.mk create mode 100644 ridljar/JunitTest_connections.mk create mode 100644 ridljar/JunitTest_java.mk create mode 100644 ridljar/JunitTest_java_remote.mk create mode 100644 ridljar/JunitTest_remote.mk create mode 100644 ridljar/JunitTest_typedesc.mk create mode 100644 ridljar/JunitTest_uno.mk create mode 100644 ridljar/JunitTest_urp.mk create mode 100644 ridljar/JunitTest_util.mk create mode 100644 ridljar/Makefile create mode 100644 ridljar/Module_ridljar.mk create mode 100644 ridljar/README.md create mode 100644 ridljar/com/sun/star/comp/bridgefactory/BridgeFactory.java create mode 100644 ridljar/com/sun/star/comp/connections/Acceptor.java create mode 100644 ridljar/com/sun/star/comp/connections/Connector.java create mode 100644 ridljar/com/sun/star/comp/connections/ConstantInstanceProvider.java create mode 100644 ridljar/com/sun/star/comp/connections/Implementation.java create mode 100644 ridljar/com/sun/star/comp/connections/PipedConnection.java create mode 100644 ridljar/com/sun/star/comp/helper/Bootstrap.java create mode 100644 ridljar/com/sun/star/comp/helper/BootstrapException.java create mode 100644 ridljar/com/sun/star/comp/helper/ComponentContext.java create mode 100644 ridljar/com/sun/star/comp/helper/ComponentContextEntry.java create mode 100644 ridljar/com/sun/star/comp/helper/SharedLibraryLoader.java create mode 100644 ridljar/com/sun/star/comp/loader/FactoryHelper.java create mode 100644 ridljar/com/sun/star/comp/loader/JavaLoader.java create mode 100644 ridljar/com/sun/star/comp/loader/JavaLoaderFactory.java create mode 100644 ridljar/com/sun/star/comp/loader/RegistrationClassFinder.java create mode 100644 ridljar/com/sun/star/comp/servicemanager/ServiceManager.java create mode 100644 ridljar/com/sun/star/comp/urlresolver/UrlResolver.java create mode 100644 ridljar/com/sun/star/lib/connections/pipe/PipeConnection.java create mode 100644 ridljar/com/sun/star/lib/connections/pipe/pipeAcceptor.java create mode 100644 ridljar/com/sun/star/lib/connections/pipe/pipeConnector.java create mode 100644 ridljar/com/sun/star/lib/connections/socket/ConnectionDescriptor.java create mode 100644 ridljar/com/sun/star/lib/connections/socket/SocketConnection.java create mode 100644 ridljar/com/sun/star/lib/connections/socket/socketAcceptor.java create mode 100644 ridljar/com/sun/star/lib/connections/socket/socketConnector.java create mode 100644 ridljar/com/sun/star/lib/uno/Proxy.java create mode 100644 ridljar/com/sun/star/lib/uno/adapter/ByteArrayToXInputStreamAdapter.java create mode 100644 ridljar/com/sun/star/lib/uno/adapter/InputStreamToXInputStreamAdapter.java create mode 100644 ridljar/com/sun/star/lib/uno/adapter/OutputStreamToXOutputStreamAdapter.java create mode 100644 ridljar/com/sun/star/lib/uno/adapter/XInputStreamToInputStreamAdapter.java create mode 100644 ridljar/com/sun/star/lib/uno/adapter/XOutputStreamToByteArrayAdapter.java create mode 100644 ridljar/com/sun/star/lib/uno/adapter/XOutputStreamToOutputStreamAdapter.java create mode 100644 ridljar/com/sun/star/lib/uno/bridges/java_remote/BridgedObject.java create mode 100644 ridljar/com/sun/star/lib/uno/bridges/java_remote/ProxyFactory.java create mode 100644 ridljar/com/sun/star/lib/uno/bridges/java_remote/RequestHandler.java create mode 100644 ridljar/com/sun/star/lib/uno/bridges/java_remote/XConnectionInputStream_Adapter.java create mode 100644 ridljar/com/sun/star/lib/uno/bridges/java_remote/XConnectionOutputStream_Adapter.java create mode 100644 ridljar/com/sun/star/lib/uno/bridges/java_remote/java_remote_bridge.java create mode 100644 ridljar/com/sun/star/lib/uno/environments/java/java_environment.java create mode 100644 ridljar/com/sun/star/lib/uno/environments/remote/IProtocol.java create mode 100644 ridljar/com/sun/star/lib/uno/environments/remote/IReceiver.java create mode 100644 ridljar/com/sun/star/lib/uno/environments/remote/IThreadPool.java create mode 100644 ridljar/com/sun/star/lib/uno/environments/remote/JavaThreadPool.java create mode 100644 ridljar/com/sun/star/lib/uno/environments/remote/JavaThreadPoolFactory.java create mode 100644 ridljar/com/sun/star/lib/uno/environments/remote/Job.java create mode 100644 ridljar/com/sun/star/lib/uno/environments/remote/JobQueue.java create mode 100644 ridljar/com/sun/star/lib/uno/environments/remote/Message.java create mode 100644 ridljar/com/sun/star/lib/uno/environments/remote/NativeThreadPool.java create mode 100644 ridljar/com/sun/star/lib/uno/environments/remote/ThreadId.java create mode 100644 ridljar/com/sun/star/lib/uno/environments/remote/ThreadPoolManager.java create mode 100644 ridljar/com/sun/star/lib/uno/environments/remote/remote_environment.java create mode 100644 ridljar/com/sun/star/lib/uno/helper/ComponentBase.java create mode 100644 ridljar/com/sun/star/lib/uno/helper/Factory.java create mode 100644 ridljar/com/sun/star/lib/uno/helper/InterfaceContainer.java create mode 100644 ridljar/com/sun/star/lib/uno/helper/MultiTypeInterfaceContainer.java create mode 100644 ridljar/com/sun/star/lib/uno/helper/PropertySet.java create mode 100644 ridljar/com/sun/star/lib/uno/helper/PropertySetMixin.java create mode 100644 ridljar/com/sun/star/lib/uno/helper/UnoUrl.java create mode 100644 ridljar/com/sun/star/lib/uno/helper/WeakAdapter.java create mode 100644 ridljar/com/sun/star/lib/uno/helper/WeakBase.java create mode 100644 ridljar/com/sun/star/lib/uno/protocols/urp/Cache.java create mode 100644 ridljar/com/sun/star/lib/uno/protocols/urp/Marshal.java create mode 100644 ridljar/com/sun/star/lib/uno/protocols/urp/PendingRequests.java create mode 100644 ridljar/com/sun/star/lib/uno/protocols/urp/Unmarshal.java create mode 100644 ridljar/com/sun/star/lib/uno/protocols/urp/UrpMessage.java create mode 100644 ridljar/com/sun/star/lib/uno/protocols/urp/urp.java create mode 100644 ridljar/com/sun/star/lib/uno/typedesc/FieldDescription.java create mode 100644 ridljar/com/sun/star/lib/uno/typedesc/MemberDescriptionHelper.java create mode 100644 ridljar/com/sun/star/lib/uno/typedesc/MethodDescription.java create mode 100644 ridljar/com/sun/star/lib/uno/typedesc/TypeDescription.java create mode 100644 ridljar/com/sun/star/lib/uno/typeinfo/AttributeTypeInfo.java create mode 100644 ridljar/com/sun/star/lib/uno/typeinfo/ConstantTypeInfo.java create mode 100644 ridljar/com/sun/star/lib/uno/typeinfo/MemberTypeInfo.java create mode 100644 ridljar/com/sun/star/lib/uno/typeinfo/MethodTypeInfo.java create mode 100644 ridljar/com/sun/star/lib/uno/typeinfo/ParameterTypeInfo.java create mode 100644 ridljar/com/sun/star/lib/uno/typeinfo/TypeInfo.java create mode 100644 ridljar/com/sun/star/lib/util/AsynchronousFinalizer.java create mode 100644 ridljar/com/sun/star/lib/util/DisposeListener.java create mode 100644 ridljar/com/sun/star/lib/util/DisposeNotifier.java create mode 100644 ridljar/com/sun/star/lib/util/NativeLibraryLoader.java create mode 100644 ridljar/com/sun/star/lib/util/StringHelper.java create mode 100644 ridljar/com/sun/star/lib/util/UrlToFileMapper.java create mode 100644 ridljar/com/sun/star/lib/util/WeakMap.java create mode 100644 ridljar/com/sun/star/uno/Any.java create mode 100644 ridljar/com/sun/star/uno/AnyConverter.java create mode 100644 ridljar/com/sun/star/uno/Ascii.java create mode 100644 ridljar/com/sun/star/uno/AsciiString.java create mode 100644 ridljar/com/sun/star/uno/Enum.java create mode 100644 ridljar/com/sun/star/uno/IBridge.java create mode 100644 ridljar/com/sun/star/uno/IEnvironment.java create mode 100644 ridljar/com/sun/star/uno/IMapping.java create mode 100644 ridljar/com/sun/star/uno/IQueryInterface.java create mode 100644 ridljar/com/sun/star/uno/MappingException.java create mode 100644 ridljar/com/sun/star/uno/Type.java create mode 100644 ridljar/com/sun/star/uno/UnoRuntime.java create mode 100644 ridljar/com/sun/star/uno/WeakReference.java create mode 100644 ridljar/pom.libreoffice.xml create mode 100644 ridljar/pom.ridl.xml create mode 100644 ridljar/pom.unoloader.xml create mode 100644 ridljar/source/libreoffice/manifest create mode 100644 ridljar/source/libreoffice/module-info.java create mode 100644 ridljar/source/unoloader/BUCK create mode 100644 ridljar/source/unoloader/com/sun/star/lib/unoloader/UnoClassLoader.java create mode 100644 ridljar/source/unoloader/com/sun/star/lib/unoloader/UnoLoader.java create mode 100644 ridljar/source/unoloader/com/sun/star/lib/unoloader/manifest create mode 100644 ridljar/source/unoloader/module-info.java create mode 100644 ridljar/test/com/sun/star/comp/bridgefactory/BridgeFactory_Test.java create mode 100644 ridljar/test/com/sun/star/comp/connections/PipedConnection_Test.java create mode 100644 ridljar/test/com/sun/star/lib/uno/bridges/java_remote/BridgedObject_Test.java create mode 100644 ridljar/test/com/sun/star/lib/uno/bridges/java_remote/ProxyFactory_Test.java create mode 100644 ridljar/test/com/sun/star/lib/uno/bridges/java_remote/java_remote_bridge_Test.java create mode 100644 ridljar/test/com/sun/star/lib/uno/environments/java/java_environment_Test.java create mode 100644 ridljar/test/com/sun/star/lib/uno/environments/remote/JavaThreadPoolFactory_Test.java create mode 100644 ridljar/test/com/sun/star/lib/uno/environments/remote/JobQueue_Test.java create mode 100644 ridljar/test/com/sun/star/lib/uno/environments/remote/TestIWorkAt.java create mode 100644 ridljar/test/com/sun/star/lib/uno/environments/remote/TestReceiver.java create mode 100644 ridljar/test/com/sun/star/lib/uno/environments/remote/TestWorkAt.java create mode 100644 ridljar/test/com/sun/star/lib/uno/environments/remote/ThreadId_Test.java create mode 100644 ridljar/test/com/sun/star/lib/uno/environments/remote/ThreadPool_Test.java create mode 100644 ridljar/test/com/sun/star/lib/uno/protocols/urp/Cache_Test.java create mode 100644 ridljar/test/com/sun/star/lib/uno/protocols/urp/Marshaling_Test.java create mode 100644 ridljar/test/com/sun/star/lib/uno/protocols/urp/Protocol_Test.java create mode 100644 ridljar/test/com/sun/star/lib/uno/protocols/urp/TestBridge.java create mode 100644 ridljar/test/com/sun/star/lib/uno/protocols/urp/TestObject.java create mode 100644 ridljar/test/com/sun/star/lib/uno/protocols/urp/interfaces.idl create mode 100644 ridljar/test/com/sun/star/lib/uno/typedesc/TypeDescription_Test.java create mode 100644 ridljar/test/com/sun/star/lib/util/NativeLibraryLoader_Test.java create mode 100644 ridljar/test/com/sun/star/lib/util/WeakMap_Test.java create mode 100644 ridljar/test/com/sun/star/uno/AnyConverter_Test.java create mode 100644 ridljar/test/com/sun/star/uno/Any_Test.java create mode 100644 ridljar/test/com/sun/star/uno/Type_Test.java create mode 100644 ridljar/test/com/sun/star/uno/UnoRuntime_EnvironmentTest.java create mode 100644 ridljar/test/com/sun/star/uno/UnoRuntime_Test.java create mode 100644 ridljar/test/com/sun/star/uno/WeakReference_Test.java create mode 100644 ridljar/util/manifest (limited to 'ridljar') diff --git a/ridljar/BUCK b/ridljar/BUCK new file mode 100644 index 000000000..b67d1c6a1 --- /dev/null +++ b/ridljar/BUCK @@ -0,0 +1,46 @@ + +genrule( + name = 'ridl-src', + cmd = ' && '.join([ + 'cd $TMP', + 'echo "FAKE SOURCE ARCHIVE" > README', + 'zip -qr $OUT *', + ]), + out = 'ridl-src.jar', + visibility = ['PUBLIC'], +) + +genrule( + name = 'ridl-javadoc', + cmd = ' && '.join([ + 'cd $TMP', + 'echo "FAKE JAVADOC ARCHIVE" > README', + 'zip -qr $OUT *', + ]), + out = 'ridl-javadoc.jar', + visibility = ['PUBLIC'], +) + +java_sources( + name = 'libreoffice-src', + srcs = glob(['com/**']), + root = '.', + visibility = ['PUBLIC'], +) + +java_doc( + name = 'libreoffice-javadoc', + title = 'LibreOffice types for the Java Uno typesystem', + pkgs = [ + 'com.sun.star.comp', + 'com.sun.star.lib', + 'com.sun.star.uno', + ], + paths = ['.'], + srcs = glob(['com/**']), + deps = [ + '//:unoloader', + '//:libreoffice', + ], + visibility = ['PUBLIC'], +) diff --git a/ridljar/CustomTarget_javamaker.mk b/ridljar/CustomTarget_javamaker.mk new file mode 100644 index 000000000..cc5ab33f8 --- /dev/null +++ b/ridljar/CustomTarget_javamaker.mk @@ -0,0 +1,26 @@ +# -*- Mode: makefile-gmake; tab-width: 4; indent-tabs-mode: t -*- +# +# 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/. +# + +$(eval $(call gb_CustomTarget_CustomTarget,ridljar/javamaker)) + +ridljar_DIR := $(call gb_CustomTarget_get_workdir,ridljar/javamaker) + +$(call gb_CustomTarget_get_target,ridljar/javamaker) : $(ridljar_DIR)/done + +$(ridljar_DIR)/done : $(call gb_UnoApi_get_target,udkapi) \ + $(call gb_Executable_get_runtime_dependencies,javamaker) \ + | $(ridljar_DIR)/.dir + $(call gb_Output_announce,$(subst $(WORKDIR)/,,$@),$(true),JVM,1) + $(call gb_Trace_StartRange,$(subst $(WORKDIR)/,,$@),JVM) + $(call gb_Helper_abbreviate_dirs, \ + rm -r $(ridljar_DIR) && \ + $(call gb_Helper_execute,javamaker -O$(ridljar_DIR) $<) && touch $@) + $(call gb_Trace_EndRange,$(subst $(WORKDIR)/,,$@),JVM) + +# vim:set shiftwidth=4 tabstop=4 noexpandtab: diff --git a/ridljar/CustomTarget_test_urp.mk b/ridljar/CustomTarget_test_urp.mk new file mode 100644 index 000000000..88e87bf6d --- /dev/null +++ b/ridljar/CustomTarget_test_urp.mk @@ -0,0 +1,28 @@ +# -*- Mode: makefile-gmake; tab-width: 4; indent-tabs-mode: t -*- +# +# 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/. +# + +$(eval $(call gb_CustomTarget_CustomTarget,ridljar/test/com/sun/star/lib/uno/protocols/urp)) + +ridljar_TESTURP := $(call gb_CustomTarget_get_workdir,ridljar/test/com/sun/star/lib/uno/protocols/urp) + +$(call gb_CustomTarget_get_target,ridljar/test/com/sun/star/lib/uno/protocols/urp) : $(ridljar_TESTURP)/done + +$(ridljar_TESTURP)/done : \ + $(call gb_UnoApiTarget_get_target,test_urp) \ + $(call gb_UnoApi_get_target,udkapi) \ + $(call gb_Executable_get_runtime_dependencies,javamaker) + $(call gb_Output_announce,$(subst $(WORKDIR)/,,$@),$(true),JVM,1) + $(call gb_Trace_StartRange,$(subst $(WORKDIR)/,,$@),JVM) + rm -rf $(ridljar_TESTURP) && \ + $(call gb_Helper_execute,javamaker -O$(ridljar_TESTURP) -nD $< \ + -X$(call gb_UnoApi_get_target,udkapi)) && \ + touch $@ + $(call gb_Trace_EndRange,$(subst $(WORKDIR)/,,$@),JVM) + +# vim:set shiftwidth=4 tabstop=4 noexpandtab: diff --git a/ridljar/InternalUnoApi_test_urp.mk b/ridljar/InternalUnoApi_test_urp.mk new file mode 100644 index 000000000..0fb6cf7c4 --- /dev/null +++ b/ridljar/InternalUnoApi_test_urp.mk @@ -0,0 +1,16 @@ +# -*- Mode: makefile-gmake; tab-width: 4; indent-tabs-mode: t -*- +# +# 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/. +# + +$(eval $(call gb_InternalUnoApi_InternalUnoApi,test_urp,ridljar/test/com/sun/star/lib/uno/protocols/urp/interfaces.idl)) + +$(eval $(call gb_InternalUnoApi_use_api,test_urp,\ + udkapi \ +)) + +# vim: set noet sw=4 ts=4: diff --git a/ridljar/Jar_libreoffice.mk b/ridljar/Jar_libreoffice.mk new file mode 100644 index 000000000..d34ae3f5e --- /dev/null +++ b/ridljar/Jar_libreoffice.mk @@ -0,0 +1,139 @@ +# -*- Mode: makefile-gmake; tab-width: 4; indent-tabs-mode: t -*- +# +# 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/. +# + +$(eval $(call gb_Jar_Jar,libreoffice,org.libreoffice.uno)) + +$(eval $(call gb_Jar_use_customtargets,libreoffice,\ + ridljar/javamaker \ + unoil/javamaker \ +)) + +$(eval $(call gb_Jar_use_jars,libreoffice, \ + unoloader \ +)) + +$(eval $(call gb_Jar_set_packageroot,libreoffice,com)) + +$(eval $(call gb_Jar_set_manifest,libreoffice,$(SRCDIR)/ridljar/util/manifest)) + +$(eval $(call gb_Jar_add_manifest_classpath,libreoffice, \ + unoloader.jar \ + $(if $(filter MACOSX,$(OS)),../../Frameworks/,../) \ +)) + +# ugly: the module-info.class is manually added here since it's not in "com" dir +$(eval $(call gb_Jar_add_packagedirs,libreoffice,\ + $(call gb_CustomTarget_get_workdir,ridljar/javamaker)/com \ + $(call gb_CustomTarget_get_workdir,unoil/javamaker)/com \ + $(call gb_JavaClassSet_get_classdir,$(call gb_Jar_get_classsetname,libreoffice))/module-info.class \ +)) + +$(eval $(call gb_Jar_add_sourcefiles_java9,libreoffice,\ + ridljar/source/libreoffice/module-info \ +)) + +$(eval $(call gb_Jar_add_sourcefiles,libreoffice,\ + ridljar/com/sun/star/comp/bridgefactory/BridgeFactory \ + ridljar/com/sun/star/comp/connections/Acceptor \ + ridljar/com/sun/star/comp/connections/Connector \ + ridljar/com/sun/star/comp/connections/ConstantInstanceProvider \ + ridljar/com/sun/star/comp/connections/Implementation \ + ridljar/com/sun/star/comp/connections/PipedConnection \ + ridljar/com/sun/star/comp/helper/Bootstrap \ + ridljar/com/sun/star/comp/helper/BootstrapException \ + ridljar/com/sun/star/comp/helper/ComponentContext \ + ridljar/com/sun/star/comp/helper/ComponentContextEntry \ + ridljar/com/sun/star/comp/helper/SharedLibraryLoader \ + ridljar/com/sun/star/comp/loader/FactoryHelper \ + ridljar/com/sun/star/comp/loader/JavaLoader \ + ridljar/com/sun/star/comp/loader/JavaLoaderFactory \ + ridljar/com/sun/star/comp/loader/RegistrationClassFinder \ + ridljar/com/sun/star/comp/servicemanager/ServiceManager \ + ridljar/com/sun/star/comp/urlresolver/UrlResolver \ + ridljar/com/sun/star/lib/connections/pipe/PipeConnection \ + ridljar/com/sun/star/lib/connections/pipe/pipeAcceptor \ + ridljar/com/sun/star/lib/connections/pipe/pipeConnector \ + ridljar/com/sun/star/lib/connections/socket/ConnectionDescriptor \ + ridljar/com/sun/star/lib/connections/socket/SocketConnection \ + ridljar/com/sun/star/lib/connections/socket/socketAcceptor \ + ridljar/com/sun/star/lib/connections/socket/socketConnector \ + ridljar/com/sun/star/lib/uno/Proxy \ + ridljar/com/sun/star/lib/uno/adapter/ByteArrayToXInputStreamAdapter \ + ridljar/com/sun/star/lib/uno/adapter/InputStreamToXInputStreamAdapter \ + ridljar/com/sun/star/lib/uno/adapter/OutputStreamToXOutputStreamAdapter \ + ridljar/com/sun/star/lib/uno/adapter/XInputStreamToInputStreamAdapter \ + ridljar/com/sun/star/lib/uno/adapter/XOutputStreamToByteArrayAdapter \ + ridljar/com/sun/star/lib/uno/adapter/XOutputStreamToOutputStreamAdapter \ + ridljar/com/sun/star/lib/uno/bridges/java_remote/BridgedObject \ + ridljar/com/sun/star/lib/uno/bridges/java_remote/ProxyFactory \ + ridljar/com/sun/star/lib/uno/bridges/java_remote/RequestHandler \ + ridljar/com/sun/star/lib/uno/bridges/java_remote/XConnectionInputStream_Adapter \ + ridljar/com/sun/star/lib/uno/bridges/java_remote/XConnectionOutputStream_Adapter \ + ridljar/com/sun/star/lib/uno/bridges/java_remote/java_remote_bridge \ + ridljar/com/sun/star/lib/uno/environments/java/java_environment \ + ridljar/com/sun/star/lib/uno/environments/remote/IProtocol \ + ridljar/com/sun/star/lib/uno/environments/remote/IReceiver \ + ridljar/com/sun/star/lib/uno/environments/remote/IThreadPool \ + ridljar/com/sun/star/lib/uno/environments/remote/JavaThreadPool \ + ridljar/com/sun/star/lib/uno/environments/remote/JavaThreadPoolFactory \ + ridljar/com/sun/star/lib/uno/environments/remote/Job \ + ridljar/com/sun/star/lib/uno/environments/remote/JobQueue \ + ridljar/com/sun/star/lib/uno/environments/remote/Message \ + ridljar/com/sun/star/lib/uno/environments/remote/NativeThreadPool \ + ridljar/com/sun/star/lib/uno/environments/remote/ThreadId \ + ridljar/com/sun/star/lib/uno/environments/remote/ThreadPoolManager \ + ridljar/com/sun/star/lib/uno/environments/remote/remote_environment \ + ridljar/com/sun/star/lib/uno/helper/ComponentBase \ + ridljar/com/sun/star/lib/uno/helper/Factory \ + ridljar/com/sun/star/lib/uno/helper/InterfaceContainer \ + ridljar/com/sun/star/lib/uno/helper/MultiTypeInterfaceContainer \ + ridljar/com/sun/star/lib/uno/helper/PropertySet \ + ridljar/com/sun/star/lib/uno/helper/PropertySetMixin \ + ridljar/com/sun/star/lib/uno/helper/UnoUrl \ + ridljar/com/sun/star/lib/uno/helper/WeakAdapter \ + ridljar/com/sun/star/lib/uno/helper/WeakBase \ + ridljar/com/sun/star/lib/uno/protocols/urp/Cache \ + ridljar/com/sun/star/lib/uno/protocols/urp/Marshal \ + ridljar/com/sun/star/lib/uno/protocols/urp/PendingRequests \ + ridljar/com/sun/star/lib/uno/protocols/urp/Unmarshal \ + ridljar/com/sun/star/lib/uno/protocols/urp/UrpMessage \ + ridljar/com/sun/star/lib/uno/protocols/urp/urp \ + ridljar/com/sun/star/lib/uno/typedesc/FieldDescription \ + ridljar/com/sun/star/lib/uno/typedesc/MemberDescriptionHelper \ + ridljar/com/sun/star/lib/uno/typedesc/MethodDescription \ + ridljar/com/sun/star/lib/uno/typedesc/TypeDescription \ + ridljar/com/sun/star/lib/uno/typeinfo/AttributeTypeInfo \ + ridljar/com/sun/star/lib/uno/typeinfo/ConstantTypeInfo \ + ridljar/com/sun/star/lib/uno/typeinfo/MemberTypeInfo \ + ridljar/com/sun/star/lib/uno/typeinfo/MethodTypeInfo \ + ridljar/com/sun/star/lib/uno/typeinfo/ParameterTypeInfo \ + ridljar/com/sun/star/lib/uno/typeinfo/TypeInfo \ + ridljar/com/sun/star/lib/util/AsynchronousFinalizer \ + ridljar/com/sun/star/lib/util/DisposeListener \ + ridljar/com/sun/star/lib/util/DisposeNotifier \ + ridljar/com/sun/star/lib/util/NativeLibraryLoader \ + ridljar/com/sun/star/lib/util/StringHelper \ + ridljar/com/sun/star/lib/util/UrlToFileMapper \ + ridljar/com/sun/star/lib/util/WeakMap \ + ridljar/com/sun/star/uno/Any \ + ridljar/com/sun/star/uno/AnyConverter \ + ridljar/com/sun/star/uno/Ascii \ + ridljar/com/sun/star/uno/AsciiString \ + ridljar/com/sun/star/uno/Enum \ + ridljar/com/sun/star/uno/IBridge \ + ridljar/com/sun/star/uno/IEnvironment \ + ridljar/com/sun/star/uno/IMapping \ + ridljar/com/sun/star/uno/IQueryInterface \ + ridljar/com/sun/star/uno/MappingException \ + ridljar/com/sun/star/uno/Type \ + ridljar/com/sun/star/uno/UnoRuntime \ + ridljar/com/sun/star/uno/WeakReference \ +)) + +# vim:set noet sw=4 ts=4: diff --git a/ridljar/Jar_ridl.mk b/ridljar/Jar_ridl.mk new file mode 100644 index 000000000..5ebd4589b --- /dev/null +++ b/ridljar/Jar_ridl.mk @@ -0,0 +1,16 @@ +# -*- Mode: makefile-gmake; tab-width: 4; indent-tabs-mode: t -*- +# +# 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/. +# + +$(eval $(call gb_Jar_Jar,ridl)) + +$(eval $(call gb_Jar_add_manifest_classpath,ridl, \ + libreoffice.jar \ +)) + +# vim:set noet sw=4 ts=4: diff --git a/ridljar/Jar_unoloader.mk b/ridljar/Jar_unoloader.mk new file mode 100644 index 000000000..2acf20b5b --- /dev/null +++ b/ridljar/Jar_unoloader.mk @@ -0,0 +1,30 @@ +# -*- Mode: makefile-gmake; tab-width: 4; indent-tabs-mode: t -*- +# +# 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/. +# + +$(eval $(call gb_Jar_Jar,unoloader,org.libreoffice.unoloader)) + +$(eval $(call gb_Jar_set_packageroot,unoloader,com)) + +$(eval $(call gb_Jar_set_manifest,unoloader,$(SRCDIR)/ridljar/source/unoloader/com/sun/star/lib/unoloader/manifest)) + +# the module-info.class is manually added here since it's not in "com" dir +$(eval $(call gb_Jar_add_packagedirs,unoloader,\ + $(call gb_JavaClassSet_get_classdir,$(call gb_Jar_get_classsetname,unoloader))/module-info.class \ +)) + +$(eval $(call gb_Jar_add_sourcefiles_java9,unoloader,\ + ridljar/source/unoloader/module-info \ +)) + +$(eval $(call gb_Jar_add_sourcefiles,unoloader,\ + ridljar/source/unoloader/com/sun/star/lib/unoloader/UnoClassLoader \ + ridljar/source/unoloader/com/sun/star/lib/unoloader/UnoLoader \ +)) + +# vim:set noet sw=4 ts=4: diff --git a/ridljar/JunitTest_bridgefactory.mk b/ridljar/JunitTest_bridgefactory.mk new file mode 100644 index 000000000..c50dbcf6d --- /dev/null +++ b/ridljar/JunitTest_bridgefactory.mk @@ -0,0 +1,28 @@ +# -*- Mode: makefile-gmake; tab-width: 4; indent-tabs-mode: t -*- +# +# 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/. +# + +$(eval $(call gb_JunitTest_JunitTest,ridl_bridgefactory)) + +$(eval $(call gb_Jar_use_customtargets,ridl_bridgefactory, \ + ridljar/javamaker \ +)) + +$(eval $(call gb_JunitTest_use_jar_classset,ridl_bridgefactory,libreoffice)) + +$(eval $(call gb_JunitTest_add_classpath,ridl_bridgefactory,$(call gb_CustomTarget_get_workdir,ridljar/javamaker))) + +$(eval $(call gb_JunitTest_add_sourcefiles,ridl_bridgefactory,\ + ridljar/test/com/sun/star/comp/bridgefactory/BridgeFactory_Test \ +)) + +$(eval $(call gb_JunitTest_add_classes,ridl_bridgefactory,\ + com.sun.star.comp.bridgefactory.BridgeFactory_Test \ +)) + +# vim:set noet sw=4 ts=4: diff --git a/ridljar/JunitTest_connections.mk b/ridljar/JunitTest_connections.mk new file mode 100644 index 000000000..8c8496e35 --- /dev/null +++ b/ridljar/JunitTest_connections.mk @@ -0,0 +1,28 @@ +# -*- Mode: makefile-gmake; tab-width: 4; indent-tabs-mode: t -*- +# +# 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/. +# + +$(eval $(call gb_JunitTest_JunitTest,ridl_connections)) + +$(eval $(call gb_Jar_use_customtargets,ridl_connections, \ + ridljar/javamaker \ +)) + +$(eval $(call gb_JunitTest_use_jar_classset,ridl_connections,libreoffice)) + +$(eval $(call gb_JunitTest_add_classpath,ridl_connections,$(call gb_CustomTarget_get_workdir,ridljar/javamaker))) + +$(eval $(call gb_JunitTest_add_sourcefiles,ridl_connections,\ + ridljar/test/com/sun/star/comp/connections/PipedConnection_Test \ +)) + +$(eval $(call gb_JunitTest_add_classes,ridl_connections,\ + com.sun.star.comp.connections.PipedConnection_Test \ +)) + +# vim:set noet sw=4 ts=4: diff --git a/ridljar/JunitTest_java.mk b/ridljar/JunitTest_java.mk new file mode 100644 index 000000000..be174cfe2 --- /dev/null +++ b/ridljar/JunitTest_java.mk @@ -0,0 +1,28 @@ +# -*- Mode: makefile-gmake; tab-width: 4; indent-tabs-mode: t -*- +# +# 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/. +# + +$(eval $(call gb_JunitTest_JunitTest,ridl_java)) + +$(eval $(call gb_Jar_use_customtargets,ridl_java, \ + ridljar/javamaker \ +)) + +$(eval $(call gb_JunitTest_use_jar_classset,ridl_java,libreoffice)) + +$(eval $(call gb_JunitTest_add_classpath,ridl_java,$(call gb_CustomTarget_get_workdir,ridljar/javamaker))) + +$(eval $(call gb_JunitTest_add_sourcefiles,ridl_java,\ + ridljar/test/com/sun/star/lib/uno/environments/java/java_environment_Test \ +)) + +$(eval $(call gb_JunitTest_add_classes,ridl_java,\ + com.sun.star.lib.uno.environments.java.java_environment_Test \ +)) + +# vim:set noet sw=4 ts=4: diff --git a/ridljar/JunitTest_java_remote.mk b/ridljar/JunitTest_java_remote.mk new file mode 100644 index 000000000..2039e1282 --- /dev/null +++ b/ridljar/JunitTest_java_remote.mk @@ -0,0 +1,36 @@ +# -*- Mode: makefile-gmake; tab-width: 4; indent-tabs-mode: t -*- +# +# 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/. +# + +$(eval $(call gb_JunitTest_JunitTest,ridl_java_remote)) + +$(eval $(call gb_JunitTest_use_jars,ridl_java_remote,\ + OOoRunner \ +)) + +$(eval $(call gb_Jar_use_customtargets,ridl_java_remote, \ + ridljar/javamaker \ +)) + +$(eval $(call gb_JunitTest_use_jar_classset,ridl_java_remote,libreoffice)) + +$(eval $(call gb_JunitTest_add_classpath,ridl_java_remote,$(call gb_CustomTarget_get_workdir,ridljar/javamaker))) + +$(eval $(call gb_JunitTest_add_sourcefiles,ridl_java_remote,\ + ridljar/test/com/sun/star/lib/uno/bridges/java_remote/BridgedObject_Test \ + ridljar/test/com/sun/star/lib/uno/bridges/java_remote/ProxyFactory_Test \ + ridljar/test/com/sun/star/lib/uno/bridges/java_remote/java_remote_bridge_Test \ +)) + +$(eval $(call gb_JunitTest_add_classes,ridl_java_remote,\ + com.sun.star.lib.uno.bridges.java_remote.BridgedObject_Test \ + com.sun.star.lib.uno.bridges.java_remote.ProxyFactory_Test \ + com.sun.star.lib.uno.bridges.java_remote.java_remote_bridge_Test \ +)) + +# vim:set noet sw=4 ts=4: diff --git a/ridljar/JunitTest_remote.mk b/ridljar/JunitTest_remote.mk new file mode 100644 index 000000000..340618676 --- /dev/null +++ b/ridljar/JunitTest_remote.mk @@ -0,0 +1,37 @@ +# -*- Mode: makefile-gmake; tab-width: 4; indent-tabs-mode: t -*- +# +# 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/. +# + +$(eval $(call gb_JunitTest_JunitTest,ridl_remote)) + +$(eval $(call gb_Jar_use_customtargets,ridl_remote, \ + ridljar/javamaker \ +)) + +$(eval $(call gb_JunitTest_use_jar_classset,ridl_remote,libreoffice)) + +$(eval $(call gb_JunitTest_add_classpath,ridl_remote,$(call gb_CustomTarget_get_workdir,ridljar/javamaker))) + +$(eval $(call gb_JunitTest_add_sourcefiles,ridl_remote,\ + ridljar/test/com/sun/star/lib/uno/environments/remote/JavaThreadPoolFactory_Test \ + ridljar/test/com/sun/star/lib/uno/environments/remote/JobQueue_Test \ + ridljar/test/com/sun/star/lib/uno/environments/remote/TestIWorkAt \ + ridljar/test/com/sun/star/lib/uno/environments/remote/TestReceiver \ + ridljar/test/com/sun/star/lib/uno/environments/remote/TestWorkAt \ + ridljar/test/com/sun/star/lib/uno/environments/remote/ThreadId_Test \ + ridljar/test/com/sun/star/lib/uno/environments/remote/ThreadPool_Test \ +)) + +$(eval $(call gb_JunitTest_add_classes,ridl_remote,\ + com.sun.star.lib.uno.environments.remote.JavaThreadPoolFactory_Test \ + com.sun.star.lib.uno.environments.remote.JobQueue_Test \ + com.sun.star.lib.uno.environments.remote.ThreadId_Test \ + com.sun.star.lib.uno.environments.remote.ThreadPool_Test \ +)) + +# vim:set noet sw=4 ts=4: diff --git a/ridljar/JunitTest_typedesc.mk b/ridljar/JunitTest_typedesc.mk new file mode 100644 index 000000000..4497731aa --- /dev/null +++ b/ridljar/JunitTest_typedesc.mk @@ -0,0 +1,24 @@ +# -*- Mode: makefile-gmake; tab-width: 4; indent-tabs-mode: t -*- +# +# 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/. +# + +$(eval $(call gb_JunitTest_JunitTest,ridljar_typedesc)) + +$(eval $(call gb_JunitTest_use_jars,ridljar_typedesc,\ + libreoffice \ +)) + +$(eval $(call gb_JunitTest_add_sourcefiles,ridljar_typedesc,\ + ridljar/test/com/sun/star/lib/uno/typedesc/TypeDescription_Test \ +)) + +$(eval $(call gb_JunitTest_add_classes,ridljar_typedesc,\ + com.sun.star.lib.uno.typedesc.TypeDescription_Test \ +)) + +# vim:set noet sw=4 ts=4: diff --git a/ridljar/JunitTest_uno.mk b/ridljar/JunitTest_uno.mk new file mode 100644 index 000000000..885c5fc43 --- /dev/null +++ b/ridljar/JunitTest_uno.mk @@ -0,0 +1,35 @@ +# -*- Mode: makefile-gmake; tab-width: 4; indent-tabs-mode: t -*- +# +# 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/. +# + +$(eval $(call gb_JunitTest_JunitTest,ridljar_uno)) + +$(eval $(call gb_JunitTest_use_jars,ridljar_uno,\ + OOoRunner \ + libreoffice \ +)) + +$(eval $(call gb_JunitTest_add_sourcefiles,ridljar_uno,\ + ridljar/test/com/sun/star/uno/AnyConverter_Test \ + ridljar/test/com/sun/star/uno/Any_Test \ + ridljar/test/com/sun/star/uno/Type_Test \ + ridljar/test/com/sun/star/uno/UnoRuntime_EnvironmentTest \ + ridljar/test/com/sun/star/uno/UnoRuntime_Test \ + ridljar/test/com/sun/star/uno/WeakReference_Test \ +)) + +$(eval $(call gb_JunitTest_add_classes,ridljar_uno,\ + com.sun.star.uno.AnyConverter_Test \ + com.sun.star.uno.Any_Test \ + com.sun.star.uno.Type_Test \ + com.sun.star.uno.UnoRuntime_EnvironmentTest \ + com.sun.star.uno.UnoRuntime_Test \ + com.sun.star.uno.WeakReference_Test \ +)) + +# vim:set noet sw=4 ts=4: diff --git a/ridljar/JunitTest_urp.mk b/ridljar/JunitTest_urp.mk new file mode 100644 index 000000000..3f5f76eae --- /dev/null +++ b/ridljar/JunitTest_urp.mk @@ -0,0 +1,35 @@ +# -*- Mode: makefile-gmake; tab-width: 4; indent-tabs-mode: t -*- +# +# 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/. +# + +$(eval $(call gb_JunitTest_JunitTest,ridl_urp)) + +$(eval $(call gb_JunitTest_use_customtargets,ridl_urp,\ + ridljar/test/com/sun/star/lib/uno/protocols/urp \ + ridljar/javamaker \ +)) + +$(eval $(call gb_JunitTest_use_jar_classset,ridl_urp,libreoffice)) + +$(eval $(call gb_JunitTest_add_classpath,ridl_urp,$(call gb_CustomTarget_get_workdir,ridljar/javamaker))) + +$(eval $(call gb_JunitTest_add_sourcefiles,ridl_urp,\ + ridljar/test/com/sun/star/lib/uno/protocols/urp/Cache_Test \ + ridljar/test/com/sun/star/lib/uno/protocols/urp/Marshaling_Test \ + ridljar/test/com/sun/star/lib/uno/protocols/urp/Protocol_Test \ + ridljar/test/com/sun/star/lib/uno/protocols/urp/TestBridge \ + ridljar/test/com/sun/star/lib/uno/protocols/urp/TestObject \ +)) + +$(eval $(call gb_JunitTest_add_classes,ridl_urp,\ + com.sun.star.lib.uno.protocols.urp.Cache_Test \ + com.sun.star.lib.uno.protocols.urp.Marshaling_Test \ + com.sun.star.lib.uno.protocols.urp.Protocol_Test \ +)) + +# vim:set noet sw=4 ts=4: diff --git a/ridljar/JunitTest_util.mk b/ridljar/JunitTest_util.mk new file mode 100644 index 000000000..2896e5760 --- /dev/null +++ b/ridljar/JunitTest_util.mk @@ -0,0 +1,27 @@ +# -*- Mode: makefile-gmake; tab-width: 4; indent-tabs-mode: t -*- +# +# 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/. +# + +$(eval $(call gb_JunitTest_JunitTest,ridljar_util)) + +$(eval $(call gb_JunitTest_use_jars,ridljar_util,\ + OOoRunner \ + libreoffice \ +)) + +$(eval $(call gb_JunitTest_add_sourcefiles,ridljar_util,\ + ridljar/test/com/sun/star/lib/util/NativeLibraryLoader_Test \ + ridljar/test/com/sun/star/lib/util/WeakMap_Test \ +)) + +$(eval $(call gb_JunitTest_add_classes,ridljar_util,\ + com.sun.star.lib.util.NativeLibraryLoader_Test \ + com.sun.star.lib.util.WeakMap_Test \ +)) + +# vim:set noet sw=4 ts=4: diff --git a/ridljar/Makefile b/ridljar/Makefile new file mode 100644 index 000000000..ccb1c85a0 --- /dev/null +++ b/ridljar/Makefile @@ -0,0 +1,7 @@ +# -*- Mode: makefile-gmake; tab-width: 4; indent-tabs-mode: t -*- + +module_directory:=$(dir $(realpath $(firstword $(MAKEFILE_LIST)))) + +include $(module_directory)/../solenv/gbuild/partial_build.mk + +# vim: set noet sw=4 ts=4: diff --git a/ridljar/Module_ridljar.mk b/ridljar/Module_ridljar.mk new file mode 100644 index 000000000..3d286c546 --- /dev/null +++ b/ridljar/Module_ridljar.mk @@ -0,0 +1,36 @@ +# -*- Mode: makefile-gmake; tab-width: 4; indent-tabs-mode: t -*- +# +# 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/. +# + +$(eval $(call gb_Module_Module,ridljar)) + +ifneq ($(ENABLE_JAVA),) + +$(eval $(call gb_Module_add_targets,ridljar,\ + CustomTarget_javamaker \ + Jar_libreoffice \ + Jar_ridl \ + Jar_unoloader \ +)) + +$(eval $(call gb_Module_add_check_targets,ridljar,\ + CustomTarget_test_urp \ + InternalUnoApi_test_urp \ + JunitTest_bridgefactory \ + JunitTest_connections \ + JunitTest_java \ + JunitTest_java_remote \ + JunitTest_remote \ + JunitTest_typedesc \ + JunitTest_uno \ + JunitTest_urp \ + JunitTest_util \ +)) +endif + +# vim:set noet sw=4 ts=4: diff --git a/ridljar/README.md b/ridljar/README.md new file mode 100644 index 000000000..437f24c2c --- /dev/null +++ b/ridljar/README.md @@ -0,0 +1,3 @@ +# Java UNO Types Generator + +Implements types for the Java UNO typesystem. 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 000000000..031e60d3f --- /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 XBridgeFactory Interface. + * + *

It wraps the UnoRuntime#getBridgeByNamemethod and delivers a + * XBridge component.

+ * + *

This component is only usable for remote bridges.

+ * + * @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 JavaLoader accesses this through + * reflection. + */ + public static final String __serviceName = "com.sun.star.bridge.BridgeFactory"; + + /** + * Gives a factory for creating the service. + * + *

This method is called by the JavaLoader.

+ * + * @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 XSingleServiceFactory 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 sName. + * + * @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 vector = new ArrayList(); + + 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 000000000..996eaeb85 --- /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 XAcceptor interface. + * + *

The Acceptor is a general component, that uses less general + * components (like com.sun.star.connection.socketAcceptor) to + * implement its functionality.

+ * + * @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. + * + *

The JavaLoader accesses this through reflection.

+ * + * @see com.sun.star.comp.loader.JavaLoader + */ + public static final String __serviceName + = "com.sun.star.connection.Acceptor"; + + /** + * Returns a factory for creating the service. + * + *

This method is called by the JavaLoader.

+ * + * @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 XSingleServiceFactory 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 Acceptor that uses the given service + * factory to create a specific XAcceptor. + * + * @param serviceFactory the service factory to use. + */ + public Acceptor(XMultiServiceFactory serviceFactory) { + this.serviceFactory = serviceFactory; + } + + /** + * Accepts a connection request via the given connection type. + * + *

This call blocks until a connection has been established.

+ * + *

The connection description has the following format: + * type*(key=value). + * The specific XAcceptor implementation is instantiated + * through the service factory as + * com.sun.star.connection.typeAcceptor (with + * type in lower case).

+ * + * @param connectionDescription the description of the connection. + * @return an XConnection 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 000000000..6ffab9eea --- /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 XConnector interface. + * + *

The Connector is a general component, that uses less general + * components (like com.sun.star.connection.socketConnector) to + * implement its functionality.

+ * + * @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. + * + *

The JavaLoader accesses this through reflection.

+ * + * @see com.sun.star.comp.loader.JavaLoader + */ + public static final String __serviceName + = "com.sun.star.connection.Connector"; + + /** + * Returns a factory for creating the service. + * + *

This method is called by the JavaLoader.

+ * + * @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 XSingleServiceFactory 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 Connector that uses the given service + * factory to create a specific XConnector. + * + * @param serviceFactory the service factory to use. + */ + public Connector(XMultiServiceFactory serviceFactory) { + this.serviceFactory = serviceFactory; + } + + /** + * Connects via the given connection type to a waiting server. + * + *

The connection description has the following format: + * type*(key=value). + * The specific XConnector implementation is instantiated + * through the service factory as + * com.sun.star.connection.typeConnector (with + * type in lower case).

+ * + * @param connectionDescription the description of the connection. + * @return an XConnection 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 000000000..6c2fcb2d8 --- /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 ConstantInstanceProvider is a component + * that implements the XInstanceProvider 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 JavaLoader accesses this through + * reflection. + */ + private static final String __serviceName = "com.sun.star.comp.connection.InstanceProvider"; + + /** + * Gives a factory for creating the service. + *

This method is called by the JavaLoader.

+ * + * @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 XSingleServiceFactory 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 ConstantInstanceProvider. + *

Uses the provided ServiceManager as the provided instance.

+ * + * @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 000000000..94cabe253 --- /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 Acceptor and Connector. + */ +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: + * type*(key=value). + * The specific service implementation is instantiated through the + * service factory as + * com.sun.star.connection.typeservice + * (with type in lower case, and + * service either Acceptor or + * Connector). + * @param serviceClass the IDL interface type for which to query the + * requested service. + * @param serviceType must be either Acceptor or + * Connector. + * @return an instance of the requested service. Never returns + * null. + * @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 000000000..631cfae40 --- /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 PipedConnection is a component that implements the + * XConnection Interface. + *

It is useful for Thread communication in one Process.

+ * + * @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 JavaLoader accesses this through + * reflection. + */ + private static final String __serviceName = "com.sun.star.connection.PipedConnection"; + + /** + * Gives a factory for creating the service. + *

This method is called by the JavaLoader.

+ * + * @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 XSingleServiceFactory 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 PipedConnection, 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 000000000..edf21d7d2 --- /dev/null +++ b/ridljar/com/sun/star/comp/helper/Bootstrap.java @@ -0,0 +1,429 @@ +// -*- 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 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: +
    +
  • com.sun.star.comp.loader.JavaLoader
  • +
  • com.sun.star.comp.urlresolver.UrlResolver
  • +
  • com.sun.star.comp.bridgefactory.BridgeFactory
  • +
  • com.sun.star.comp.connections.Connector
  • +
  • com.sun.star.comp.connections.Acceptor
  • +
  • com.sun.star.comp.servicemanager.ServiceManager
  • +
+ + Other services can be inserted into the service manager by + using its XSet interface: +
+        XSet xSet = UnoRuntime.queryInterface( XSet.class, aMultiComponentFactory );
+        // insert the service manager
+        xSet.insert( aSingleComponentFactory );
+    
+*/ +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: + *
+     *     List list = Arrays.asList( Bootstrap.getDefaultOptions() );
+     *     list.remove("--nologo");
+     *     list.remove("--nodefault");
+     *     list.add("--invisible");
+     *
+     *     Bootstrap.bootstrap( list.toArray( new String[list.size()] );
+     * 
+ * + * @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 context_entries ) + throws Exception + { + return createInitialComponentContext((Map) 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 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( 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 com.sun.star.lang.ServiceManager. + * + * @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) 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 + cppuhelper/defaultBootstrap_InitialComponentContext(). + */ + public static final XComponentContext defaultBootstrap_InitialComponentContext() + throws Exception + { + return defaultBootstrap_InitialComponentContext( (String) null, (Map) 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 bootstrap_parameters ) + throws Exception + { + return defaultBootstrap_InitialComponentContext(ini_file, (Map) bootstrap_parameters); + + } + /** Bootstraps the initial component context from a native UNO installation. + + See also + cppuhelper/defaultBootstrap_InitialComponentContext(). + + @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 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 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) 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; + } + + 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 000000000..11911bbc0 --- /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 BootstrapException with null as + * the target exception. + */ + public BootstrapException() { + super(); + } + + /** + * Constructs a BootstrapException with the specified + * detail message. + * + * @param message the detail message + */ + public BootstrapException( String message ) { + super( message ); + } + + /** + * Constructs a BootstrapException 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 BootstrapException 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 000000000..34649d563 --- /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 m_table; + private XComponentContext m_xDelegate; + + private XMultiComponentFactory m_xSMgr; + private boolean m_bDisposeSMgr; + + private ArrayList m_eventListener; + + public ComponentContext( Hashtable table, XComponentContext xDelegate ) + { + this((Map) 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 table, XComponentContext xDelegate ) + { + m_eventListener = new ArrayList(); + 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 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 000000000..aa402d29c --- /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. +

+ 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 (=> service name) object for this. +

+*/ +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 000000000..035644efa --- /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 SharedLibraryLoader class provides the functionality of the com.sun.star.loader.SharedLibrary + * service. + * + * See also UNOIDL com.sun.star.lang.ServiceManager. + * + * @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 com.sun.star.lang.ServiceManager and + * com.sun.star.registry.RegistryKey. + * + * @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 com.sun.star.lang.ServiceManager and + * com.sun.star.registry.RegistryKey. + * + * @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 com.sun.star.lang.ServiceManager and + * com.sun.star.registry.RegistryKey. + * + * @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 com.sun.star.lang.ServiceManager and + * com.sun.star.registry.RegistryKey. + * + * @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 000000000..fe56f594f --- /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. + * + *

This class has default implementations for getServiceFactory + * and writeRegistryServiceInfo.

+ * + * @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. + * + *

Several services are supported.

+ * + * @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 000000000..42dee0da5 --- /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 JavaLoader class provides the functionality of the + * com.sun.star.loader.Java service. + * + *

Therefore the JavaLoader activates external UNO components + * which are implemented in Java.

+ * + *

The loader is used by the ServiceManager.

+ * + * @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. + * + *

Creates a new instance of the JavaLoader class.

+ */ + public JavaLoader() {} + + /** + * Creates a new JavaLoader object. + * + *

The specified com.sun.star.lang.XMultiServiceFactory is + * the ServiceManager service which can be delivered to all + * components the JavaLoader is loading.

+ * + *

To set the MultiServiceFactory you can use the + * com.sun.star.lang.XInitialization interface, either.

+ * + * @param factory the ServiceManager. + * @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 com.sun.star.lang.XMultiServiceFactory should be set at + * the loader. + * + * @param args - the first parameter (args[0]) specifies the ServiceManager. + * @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. + * + *

The JavaLoader 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.

+ * + *

To get the factory the inspects the class for the optional static member + * functions __getServiceFactory resp. getServiceFactory (DEPRECATED).

+ * + * @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. + * + *

If the component supports the optional + * methods __writeRegistryServiceInfo, writeRegistryServiceInfo (DEPRECATED), + * the call is delegated to that method. Otherwise a default registration + * will be accomplished.

+ * + * @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 JavaLoader. + * + * @param implName the name of the desired component. + * @param multiFactory the ServiceManager is delivered to the factory. + * @param regKey not used - can be null. + * @return the factory for the JavaLoader. + */ + public static XSingleServiceFactory getServiceFactory( String implName, + XMultiServiceFactory multiFactory, + XRegistryKey regKey) + { + if ( implName.equals(JavaLoader.class.getName()) ) + return new JavaLoaderFactory( multiFactory ); + + return null; + } + + /** + * Registers the JavaLoader at the registry. + * + * @param regKey root key under which the JavaLoader 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 000000000..edf4f7a3a --- /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 000000000..e7679da16 --- /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 000000000..574983f1e --- /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 ServiceManager class is an implementation of the + * ServiceManagerthe central class needed for implementing or using + * UNO components in Java. + * + *

The Methods queryInterface and isSame delegate + * calls to the implementing objects and are used instead of casts and identity + * comparisons.

+ * + * @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 eventListener; + java.util.HashMap factoriesByImplNames; + java.util.HashMap> factoriesByServiceNames; // keys: + + private com.sun.star.uno.XComponentContext m_xDefaultContext; + + /** + * Creates a new instance of the ServiceManager. + */ + public ServiceManager() { + eventListener = new ArrayList(); + factoriesByImplNames = new java.util.HashMap(); + factoriesByServiceNames = new java.util.HashMap>(); + m_xDefaultContext = null; + } + + public void setDefaultContext(XComponentContext context) { + m_xDefaultContext = context; + } + + /** + * Creates a new instance of a specified service. + * + *

Therefore the associated factory of the service is looked up and used + * to instantiate a new component.

+ * + * @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. + * + *

Therefore the associated factory of the service is looked up and used + * to instantiate a new component.

+ * + * @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. + * + *

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.

+ * + * @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 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 ServiceManager 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 EventListener. + * + *

The listener is notified when a service is added (removed) to (from) + * the ServiceManager.

+ * + *

If the listener is already registered a + * com.sun.star.uno.RuntimeException will be thrown.

+ * + * @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 EventListener from the ServiceManager. + * + *

If the listener is not registered a com.sun.star.uno.RuntimeException + * will be thrown.

+ * + * @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 ServiceManager. + * + *

The given object argument must provide a XServiceInfo + * interface.

+ * + * @param object object which provides a XServiceInfo 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 SingleServiceFactory to the ServiceManager. + * + * @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 vec ; + + for (String serviceName : serviceNames) { + if (!factoriesByServiceNames.containsKey(serviceName)) { + DEBUG("> no registered services found under " + serviceName + ": adding..."); + factoriesByServiceNames.put(serviceName, new ArrayList()); + } + 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 SingleServiceFactory from the ServiceManager. + * + * @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 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 ServiceManager + * + * @return the UNO type of the ServiceManager. + * @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 serviceList = factoriesByServiceNames.get(serviceName); + + if (serviceList != null) + enumer = new ServiceEnumerationImpl( serviceList.iterator() ); + else + enumer = new ServiceEnumerationImpl(); + + return enumer; + } + + /** + * Returns the implementation name of the ServiceManager component. + * + * @return the class name of the ServiceManager. + * @see com.sun.star.lang.XServiceInfo + */ + public String getImplementationName() + throws com.sun.star.uno.RuntimeException + { + return getClass().getName(); + } + + /** + * Checks if the ServiceManager 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 ServiceEnumerationImpl class provides an + * implementation of the @see com.sun.star.container.XEnumeration interface. + * + *

It is an inner wrapper for a java.util.Enumeration object.

+ * + * @see com.sun.star.lang.XSingleServiceFactory + * @see com.sun.star.lang.XServiceInfo + * @since UDK1.0 + */ + static class ServiceEnumerationImpl implements XEnumeration { + java.util.Iterator 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 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 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. + * + *

If no further elements available a com.sun.star.container.NoSuchElementException + * exception will be thrown.

+ * + * @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 000000000..7585dabf6 --- /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 UnoUrlResolver 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. + * + *

This method is called by the JavaLoader.

+ * + * @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 XSingleServiceFactory 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 000000000..b3a686f17 --- /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 XConnection interface + * and is uses by the PipeConnector and the PipeAcceptor. + * This class is not part of the provided api. + * + * 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 _aListeners; + protected boolean _bFirstRead; + + /** + * Constructs a new PipeConnection. + * + * @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(); + _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 000000000..983eb3265 --- /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 XAcceptor interface. + * + *

The pipeAcceptor is a specialized component that uses TCP + * pipes for communication. The pipeAcceptor is generally used + * by the com.sun.star.connection.Acceptor service.

+ * + * @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. + * + *

The JavaLoader accesses this through reflection.

+ * + * @see com.sun.star.comp.loader.JavaLoader + */ + public static final String __serviceName + = "com.sun.star.connection.pipeAcceptor"; + + /** + * Returns a factory for creating the service. + * + *

This method is called by the JavaLoader.

+ * + * @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 XSingleServiceFactory 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. + * + *

This call blocks until a connection has been established.

+ * + *

The connection description has the following format: + * type*(key=value), + * where type should be pipe + * (ignoring case). Supported keys (ignoring case) currently are

+ *
+ *
host + *
The name or address of the accepting interface (defaults to + * 0, meaning any interface). + *
port + *
The TCP port number to accept on (defaults to 6001). + *
backlog + *
The maximum length of the acceptor's queue (defaults to + * 50). + *
tcpnodelay + *
A flag (0/1) enabling or disabling Nagle's + * algorithm on the resulting connection. + *
+ * + * @param connectionDescription the description of the connection. + * @return an XConnection 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 000000000..192d35007 --- /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 XConnector interface. + * + *

The pipeConnector is a specialized component that uses TCP + * pipes for communication. The pipeConnector is generally + * used by the com.sun.star.connection.Connector service.

+ * + * @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. + * + *

The JavaLoader accesses this through reflection.

+ * + * @see com.sun.star.comp.loader.JavaLoader + */ + public static final String __serviceName = "com.sun.star.connection.pipeConnector"; + + /** + * Returns a factory for creating the service. + * + *

This method is called by the JavaLoader.

+ * + * @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 XSingleServiceFactory 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. + * + *

The connection description has the following format: + * type*(key=value), + * where type should be pipe + * (ignoring case). Supported keys (ignoring case) currently are

+ *
+ *
host + *
The name or address of the server. Must be present. + *
port + *
The TCP port number of the server (defaults to 6001). + *
tcpnodelay + *
A flag (0/1) enabling or disabling Nagle's + * algorithm on the resulting connection. + *
+ * + * @param connectionDescription the description of the connection. + * @return an XConnection 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 000000000..5a88d41ba --- /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 socketAcceptor and socketConnector. + * + *

FIXME: Once those classes have been moved from jurt to + * javaunohelper, they should use + * com.sun.star.lib.uno.helper.UnoUrl either instead of this class + * or underneath this class.

+ */ +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 000000000..a906496f2 --- /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 XConnection interface + * and is uses by the SocketConnector and the SocketAcceptor. + * + *

This class is not part of the provided api.

+ * + * @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 _listeners; + protected boolean _firstRead; + + /** + * Constructs a new SocketConnection. + * + * @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(); + _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 000000000..4000a1d0a --- /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 XAcceptor interface. + * + *

The socketAcceptor is a specialized component that uses TCP + * sockets for communication. The socketAcceptor is generally used + * by the com.sun.star.connection.Acceptor service.

+ * + * @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. + * + *

The JavaLoader accesses this through reflection.

+ * + * @see com.sun.star.comp.loader.JavaLoader + */ + public static final String __serviceName + = "com.sun.star.connection.socketAcceptor"; + + /** + * Returns a factory for creating the service. + * + *

This method is called by the JavaLoader.

+ * + * @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 XSingleServiceFactory 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. + * + *

This call blocks until a connection has been established.

+ * + *

The connection description has the following format: + * type*(key=value), + * where type should be socket + * (ignoring case). Supported keys (ignoring case) currently are

+ *
+ *
host + *
The name or address of the accepting interface (defaults to + * 0, meaning any interface). + *
port + *
The TCP port number to accept on (defaults to 6001). + *
backlog + *
The maximum length of the acceptor's queue (defaults to + * 50). + *
tcpnodelay + *
A flag (0/1) enabling or disabling Nagle's + * algorithm on the resulting connection. + *
+ * + * @param connectionDescription the description of the connection. + * @return an XConnection 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 000000000..c9a15d1f5 --- /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 XConnector interface. + * + *

The socketConnector is a specialized component that uses TCP + * sockets for communication. The socketConnector is generally + * used by the com.sun.star.connection.Connector service.

+ * + * @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. + * + *

The JavaLoader accesses this through reflection.

+ * + * @see com.sun.star.comp.loader.JavaLoader + */ + public static final String __serviceName + = "com.sun.star.connection.socketConnector"; + + /** + * Returns a factory for creating the service. + * + *

This method is called by the JavaLoader.

+ * + * @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 XSingleServiceFactory 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. + * + *

The connection description has the following format: + * type*(key=value), + * where type should be socket + * (ignoring case). Supported keys (ignoring case) currently are

+ *
+ *
host + *
The name or address of the server. Must be present. + *
port + *
The TCP port number of the server (defaults to 6001). + *
tcpnodelay + *
A flag (0/1) enabling or disabling Nagle's + * algorithm on the resulting connection. + *
+ * + * @param connectionDescription the description of the connection. + * @return an XConnection 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/uno/Proxy.java b/ridljar/com/sun/star/lib/uno/Proxy.java new file mode 100644 index 000000000..7d3612758 --- /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. + * + *

Currently, this interface is used internally by + * com.sun.star.lib.uno.environments.java.java_environment to + * distinguish between proxies and local objects. Any proxy object that shall + * be registered at the java_environment must implement this marker + * interface.

+ */ +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 000000000..2d3e9a848 --- /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 000000000..3d60e5a11 --- /dev/null +++ b/ridljar/com/sun/star/lib/uno/adapter/InputStreamToXInputStreamAdapter.java @@ -0,0 +1,145 @@ +/* + * 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 InputStreamToInputXStreamAdapter wraps the + Java InputStream object into a + UNO XInputStream object. + This allows users to access an InputStream + as if it were an XInputStream. + */ +public final class InputStreamToXInputStreamAdapter implements XInputStream { + + /** + * Internal store to the InputStream + */ + private final InputStream iIn; + + /** + * Constructor. + * + * @param in The XInputStream to be + * accessed as an InputStream. + */ + 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; + 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 <= 0) { + return 0; + } + return ((int)bytesRead); + + + } 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 (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 <= 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); + } +} + 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 000000000..2842e3df0 --- /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 OutputStreamToXOutputStreamAdapter wraps + a UNO XOutputStream into a Java OutputStream + object in a Java. This allows users to access an OutputStream + as if it were an XOutputStream. + */ +public final class OutputStreamToXOutputStreamAdapter implements XOutputStream { + + /** + * Internal handle to the OutputStream + */ + OutputStream iOut; + + /** + * Constructor. + * + * @param out The XOutputStream to be + * accessed as an OutputStream. + */ + 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 000000000..25f1798fb --- /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 XInputStreamToInputStreamAdapter wraps + * the UNO XInputStream object in a Java + * InputStream. This allows users to access + * an XInputStream as if it were an + * InputStream. + */ +public final class XInputStreamToInputStreamAdapter extends InputStream { + + /** + * Internal handle to the XInputStream + */ + private final XInputStream xin; + + /** + * Constructor. + * + * @param in The XInputStream to be + * accessed as an InputStream. + */ + 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 + * XInputStreamToInputStreamAdapter 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 000000000..48871277a --- /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 000000000..8104cf42f --- /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 XOutputStreamToOutputStreamAdapter wraps + * the UNO XOutputStream object in a Java + * OutputStream. This allows users to access + * an XOutputStream as if it were an + * OutputStream. + */ +public final class XOutputStreamToOutputStreamAdapter extends OutputStream { + + /** + * Internal handle to the XInputStream + */ + XOutputStream xout; + + /** + * Constructor. + * + * @param out The XOutputStream to be + * accessed as an OutputStream. + */ + 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 000000000..0a724f059 --- /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 000000000..1b3848983 --- /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 java_remote_bridge. + * + *

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.

+ */ +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 000000000..d5246bf26 --- /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 ProxyFactory (which + * receive requests in the form of method calls) and + * java_remote_bridge (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 000000000..8d660e88c --- /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 000000000..ac198f8fd --- /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 000000000..392e031e3 --- /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. + * + *

Therefore various interfaces are implemented.

+ * + *

The protocol to used is passed by name, the bridge + * then looks for it under com.sun.star.lib.uno.protocols.

+ * + * @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 _listeners = new ArrayList(); + + 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). + * + *

When this bridge is disposed, all remaining ref holder entries are + * released.

+ */ + 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> refHolders = new HashMap>(); + // from OID (String) to LinkedList of RefHolder + + private boolean hasRefHolder(String oid, Type type) { + synchronized (refHolders) { + LinkedList 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 l = refHolders.get(oid); + if (l == null) { + l = new LinkedList(); + refHolders.put(oid, l); + } + boolean found = false; + for (Iterator 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 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>> i1 = refHolders.entrySet().iterator(); i1.hasNext();) + { + Map.Entry> e = i1.next(); + String oid = e.getKey(); + LinkedList l = e.getValue(); + for (Iterator 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 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. + *

This method is not part of the provided api + * and should only be used by the UNO runtime.

+ * + * @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. + * + *

If the life count drops to zero, the bridge disposes itself.

+ * + * @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 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 this: + private final ArrayList disposeListeners = new ArrayList(); +} + +/* 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 000000000..89e4b1088 --- /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. + * + *

The java_environment implements the IEnvironment interface + * defined in the uno runtime.

+ * + * @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. + * + *

This method should be part of IEnvironment. It is called + * from com.sun.star.lib.uno.bridges.java_remote.java_remote_bridge.dispose.

+ */ + 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 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 level2map = + new HashMap(); + } + + private static final class Level2Entry extends WeakReference { + public Level2Entry( + String oid, Type type, Object object, ReferenceQueue 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 level1map = + new HashMap(); + private final ReferenceQueue queue = new ReferenceQueue(); + } + + 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 000000000..c2ecbf9a0 --- /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. + * + *

A class implementing a given protocol prot must be named + * com.sun.star.lib.uno.protocols.prot.prot + * and must have a public constructor that takes four arguments: The first + * argument of type com.sun.star.uno.IBridge must not be null. The + * second argument of type String represents any attributes; it may + * be null if there are no attributes. The third argument of type + * java.io.InputStream must not be null. The fourth argument of + * type java.io.OutputStream must not be null.

+ */ +public interface IProtocol { + /** + * Initializes the connection. + * + *

This method must be called exactly once, after the + * readMessage loop has already been established.

+ */ + void init() throws IOException; + + void terminate(); + + /** + * Reads a request or reply message. + * + *

Access to this method from multiple threads must be properly + * synchronized.

+ * + * @return a non-null message; if the input stream is exhausted, a + * java.io.IOException 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 type, or either + * "queryInterface" or "release"). + * @param tid a non-null TID. + * @param arguments a list of UNO arguments compatible with the given + * type and function; may be null to represent + * an empty list. + * @return true 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 true if the reply corresponds to a raised + * exception. + * @param tid a non-null TID. + * @param result if exception is true, a non-null + * UNO exception; otherwise, a UNO return value, which may be null to + * represent a VOID 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 000000000..e39ae3d4d --- /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 true 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 000000000..1de31ad04 --- /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. + * + *

The function exists for performance.

+ * + * @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. + * + *

The function exists for performance.

+ * + * @see #attach() + * @see #detach() + */ + void detach( Object handle, ThreadId id ); + + /** + * Lets this thread enter the thread pool. + * + *

This thread then executes all jobs put via putJob until + * a reply job arrives.

+ * + * @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. + * + *

This thread then executes all jobs put via putJob until + * a reply job arrives.

+ * + * @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 + * DisposedException with the given Throwable 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 000000000..332306be0 --- /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 000000000..181a3e17e --- /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 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 threadIdMap = new WeakHashMap(); + private final HashMap jobQueues = new HashMap(); +} + +/* 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 000000000..8ec4492c4 --- /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 queryInterface call. + * + * @return the result of the call (should be an Any). + */ + 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 000000000..b71525ba5 --- /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 JobQueue implements a queue for jobs. + * + *

For every jobs thread id exists a job queue which is registered + * at the ThreadPool.

+ * + *

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 putjob) into the async queue, which is only + * known by the sync queue.

+ * + * @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 jobList = new ArrayList(); + + 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.:" + _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 000000000..b34295ae3 --- /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. + * + *

Valid for all kinds of messages.

+ * + * @return the (non-null) thread ID. + */ + public final ThreadId getThreadId() { + return threadId; + } + + /** + * Returns whether the message is a request or a reply. + * + *

Valid for all kinds of messages.

+ * + * @return true for a request, false for a reply. + */ + public final boolean isRequest() { + return request; + } + + /** + * Returns the object ID of a request message. + * + *

Valid only for request messages.

+ * + * @return the (non-null) object ID for a request, + * null for a reply. + */ + public final String getObjectId() { + return objectId; + } + + /** + * Returns the type of a request message. + * + *

Valid only for request messages.

+ * + * @return the (non-null) type for a request, null + * for a reply. + */ + public final TypeDescription getType() { + return type; + } + + /** + * Returns the method description of a request message. + * + *

Valid only for request messages. The returned + * MethodDescription is consistent with the type of the + * message.

+ * + * @return the (non-null) method description for a request, + * null for a reply. + */ + public final MethodDescription getMethod() { + return method; + } + + /** + * Returns whether the request message is synchronous. + * + *

Valid only for request messages.

+ * + * @return true for a synchronous request, false + * for an asynchronous request or a reply. + */ + public final boolean isSynchronous() { + return synchronous; + } + + /** + * Returns the current context of a request message. + * + *

Valid only for request messages.

+ * + * @return the current context (which may be null) for a + * request, null for a reply. + */ + public XCurrentContext getCurrentContext() { + return currentContext; + } + + /** + * Returns whether the reply message represents abnormal termination. + * + *

Valid only for reply messages.

+ * + * @return true for a reply that represents abnormal + * termination, false for a reply that represents normal + * termination or a request. + */ + public final boolean isAbnormalTermination() { + return abnormalTermination; + } + + /** + * Returns the result of a reply message. + * + *

Valid only for reply messages.

+ * + * @return any (possibly null) return value for a reply that + * represents normal termination, the (non-null) exception for + * a reply that represents abnormal termination, null for a + * request. + */ + public final Object getResult() { + return result; + } + + /** + * Returns the arguments of a message. + * + *

Valid only for request messages and reply messages that represent + * normal termination. Any returned array must not be modified.

+ * + * @return the in and in– { + * }out arguments for a request (possibly + * null for a parameterless function), the out and in– { + * }out + * arguments for a reply that represents normal termination (possibly + * null for a parameterless function), null 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 000000000..f77bbb466 --- /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 000000000..f8dacc78c --- /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 true if this object is the same as the obj argument; + * false 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 000000000..2014f5167 --- /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. + * + *

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.

+ * + *

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 org.openoffice.native (to be set by the + * native code that starts the JVM) to determine which implementation + * to use.

+ */ +public final class ThreadPoolManager { + /** + * Creates a thread pool instance. + * + * @return a new thread pool instance; will never be null. + */ + 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 false 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 000000000..09259c8cb --- /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 000000000..d886ef702 --- /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 000000000..056d9549d --- /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. + +

+ Note: This factory implementation does not support lang.XSingleServiceFactory. +

+*/ +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 000000000..e858ced81 --- /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 + *
+ * 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.
+ * 
+ * + * 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 ArrayList instance to be the + * list's current size. An application can use this operation to minimize + * the storage of an ArrayList 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 ArrayList 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 true (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 + * (index < 0 || index > size()). + */ + 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 (index + * < 0 || index > size()). + * @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(index + * < 0 || index > size()). + * @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; itrue if this list contains the specified element. + * + * @param elem element whose presence in this List is to be tested. + * @return true 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 (index + * < 0 || index >= size()). + */ + 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 equals method. + * + * @param elem an object. + * @return the index of the first occurrence of the argument in this + * list; returns -1 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 true if this list has no elements; + * false 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 ArrayList instance. The contained + * references are copied but the objects not. + * + * @return a clone of this List 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 (index + * < 0 || index >= size()). + */ + 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 + * (index < 0 || index >= size()). + */ + 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.

+ * + * 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 + * null. This is useful in determining the length of the list + * only if the caller knows that the list does not contain any + * null 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 000000000..9b061f81c --- /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 map= new HashMap(); + + /** 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 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 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 it= null; + synchronized(this) + { + it= map.values().iterator(); + } + while (it.hasNext() ) { + it.next().disposeAndClear(evt); + } + } + + synchronized public void clear() + { + Iterator 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 000000000..67a4f0c98 --- /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

+ * Properties have to be registered by one of the registerProperty methods. They take among other + * arguments an Object named id 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.

+ * Example: + *

+ *  public class Foo extends PropertySet
+ *  {
+ *      protected int intProp;
+ *
+ *      public Foo()
+ *      {
+ *          registerProperty("PropertyA", 0, new Type(int.class), (short)0, "intProp");
+ *      }
+ *  }
+ *
+ *  
+ */ +public class PropertySet extends ComponentBase implements XPropertySet, XFastPropertySet, +XMultiPropertySet +{ + private HashMap _nameToPropertyMap; + private HashMap _handleToPropertyMap; + private HashMap _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 id with it. + * id 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 id 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.
+ * 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 propertyName. + */ + protected Property getProperty(String propertyName) + { + return _nameToPropertyMap.get(propertyName); + } + + /** Returns the Property object with a handle (Property.Handle) as specified by the argument + * nHandle. 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 nHandle + */ + 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 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 id 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(); + _handleToPropertyMap= new HashMap(); + _propertyToIdMap= new HashMap(); + } + + /** 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: + *
    + *
  • java.lang.Boolean
  • + *
  • java.lang.Character
  • + *
  • java.lang.Byte
  • + *
  • java.lang.Short
  • + *
  • java.lang.Integer
  • + *
  • java.lang.Long
  • + *
  • java.lang.Float
  • + *
  • java.lang.Double
  • + *
  • String
  • + *
  • com.sun.star.uno.Type
  • + *
  • objects which implement UNO interfaces
  • + *
  • arrays which contain elements of the types above
  • + *
  • com.sun.star.uno.Any containing an instance of one of the above types
  • + *
+ * + * 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 value 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 + * value = 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 value = 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. + *

+ * 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: + *

+     *  set.setPropertyValue( "PropA", Byte.valueOf( (byte)111));
+     *  
+ * 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 newVal. 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. + *

+ * The method handles Any arguments the same as Object arguments. That is, the setVal 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 setVal 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 setVal 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 newVal + * returns the XInterface. + * + * If a member is a UNO interface, then setVal is queried for this interface and the result is returned. + * If setVal is null then newVal will be null too after return. + *

+ * If a property value is stored using a primitive type the out-parameters + * curVal and newVal 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. newVal 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= new Character(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= new Float(AnyConverter.toFloat(obj)); + else if (cl.equals(double.class)) + retVal= new Double(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= new Character(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= new Float(AnyConverter.toFloat(obj)); + else if (cl.equals(Double.class)) + retVal= new Double(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}.
+ * 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 bVetoable 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 000000000..0c050d676 --- /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. + +

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) + com.sun.star.beans.XPropertySet, + com.sun.star.beans.XFastPropertySet, and + com.sun.star.beans.XPropertyAccess to it.

+ +

Client code should not use the monitors associated with instances of this + class, as they are used for internal purposes.

+ + @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 + com.sun.star.reflection.theCoreReflection and + com.sun.star.reflection.theTypeDescriptionManager singletons + + @param object the client UNO object into which this instance is mixed in; + must not be null, and must support the given type + + @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 + com.sun.star.beans.XPropertySet.getPropertySetInfo, + com.sun.star.beans.XPropertySet.addPropertyChangeListener, + com.sun.star.beans.XPropertySet.removePropertyChangeListener, + com.sun.star.beans.XPropertySet.addVetoableChangeListener, + and com.sun.star.beans.XPropertySet.removeVetoableChangeListener; 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 + absentOptional 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 + com.sun.star.beans.UnknownPropertyException), 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 + com.sun.star.beans.UnknownPropertyException) but is not + contained in the given absentOptional, then it will be + visible via + com.sun.star.beans.XPropertySet.getPropertySetInfo as a + com.sun.star.beans.Property with a set + com.sun.star.beans.PropertyAttribute.OPTIONAL. If the given + object does not implement + com.sun.star.beans.XPropertySet, then the given + absentOptional 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 map = new HashMap(); + ArrayList handleNames = new ArrayList(); + initProperties(ifc, map, handleNames, new HashSet()); + properties = map; + handleMap = handleNames.toArray(new String[handleNames.size()]); + } + + /** + A method used by clients when implementing UNO interface type attribute + setter functions. + +

First, this method checks whether this instance has already been + disposed (see {@link #dispose}), and throws a + com.sun.star.beans.DisposedException if applicable. For a + constrained attribute (whose setter can explicitly raise + com.sun.star.beans.PropertyVetoException), this method + notifies any com.sun.star.beans.XVetoableChangeListeners. + For a bound attribute, this method modifies the passed-in + bound so that it can afterwards be used to notify any + com.sun.star.beans.XPropertyChangeListeners. This method + should be called before storing the new attribute value, and + bound.notifyListeners() should be called exactly once after + storing the new attribute value (in case the attribute is bound; + otherwise, calling bound.notifyListeners() is ignored). + Furthermore, bound.notifyListeners() and this method have to + be called from the same thread.

+ + @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 + com.sun.star.beans.PropertyChangeEvent.OldValue, which is + rather useless, anyway (see “Using the Observer Pattern” in + + OpenOffice.org Coding Guidelines). If the attribute + that is going to be set is neither bound nor constrained, or if + com.sun.star.beans.PropertyChangeEvent.OldValue 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 + com.sun.star.beans.PropertyChangeEvent.NewValue, which is + rather useless, anyway (see “Using the Observer Pattern” in + + OpenOffice.org Coding Guidelines), unless 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 + com.sun.star.beans.PropertyChangeEvent.NewValue 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 specificVeto = null; + ArrayList unspecificVeto = null; + synchronized (this) { + if (disposed) { + throw new DisposedException("disposed", object); + } + if ((p.Attributes & PropertyAttribute.CONSTRAINED) != 0) { + ArrayList o = vetoListeners.get(propertyName); + if (o != null) { + specificVeto = new ArrayList(o); + } + o = vetoListeners.get(""); + if (o != null) { + unspecificVeto = new ArrayList(o); + } + } + if ((p.Attributes & PropertyAttribute.BOUND) != 0) { + // assert bound != null; + ArrayList o = boundListeners.get(propertyName); + if (o != null) { + bound.specificListeners = new ArrayList(o); + } + o = boundListeners.get(""); + if (o != null) { + bound.unspecificListeners = new ArrayList(o); + } + } + } + if ((p.Attributes & PropertyAttribute.CONSTRAINED) != 0) { + PropertyChangeEvent event = new PropertyChangeEvent( + object, propertyName, false, p.Handle, oldValue, newValue); + if (specificVeto != null) { + for (Iterator i = specificVeto.iterator(); i.hasNext();) { + try { + i.next().vetoableChange(event); + } catch (DisposedException e) {} + } + } + if (unspecificVeto != null) { + for (Iterator 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)}. + +

This method is useful for attributes that are not constrained.

+ + @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. + +

See com.sun.star.lang.XComponent for the general concept + of disposing UNO objects. On the first call to this method, all + registered listeners + (com.sun.star.beans.XPropertyChangeListeners and + com.sun.star.beans.XVetoableChangeListeners) are notified of + the disposing source. Any subsequent calls to this method are + ignored.

+ */ + public void dispose() { + HashMap> bound; + HashMap> veto; + synchronized (this) { + bound = boundListeners; + boundListeners = null; + veto = vetoListeners; + vetoListeners = null; + disposed = true; + } + EventObject event = new EventObject(object); + if (bound != null) { + for (Iterator> i = bound.values().iterator(); i.hasNext();) { + for (Iterator j = i.next().iterator(); j.hasNext();) + { + j.next().disposing(event); + } + } + } + if (veto != null) { + for (Iterator> i = veto.values().iterator(); i.hasNext();) { + for (Iterator j = i.next().iterator(); j.hasNext();) + { + j.next().disposing(event); + } + } + } + } + + /** + Implements + com.sun.star.beans.XPropertySet.getPropertySetInfo. + @return See com.sun.star.beans.XPropertySet + */ + public XPropertySetInfo getPropertySetInfo() { + return new Info(properties); + } + + /** + Implements com.sun.star.beans.XPropertySet.setPropertyValue. + @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 com.sun.star.beans.XPropertySet.getPropertyValue. + @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 + com.sun.star.beans.XPropertySet.addPropertyChangeListener. + +

If a listener is added more than once, it will receive all relevant + notifications multiple times.

+ + @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 v = boundListeners.get(propertyName); + if (v == null) { + v = new ArrayList(); + boundListeners.put(propertyName, v); + } + v.add(listener); + } + } + if (disp) { + listener.disposing(new EventObject(object)); + } + } + + /** + Implements + com.sun.star.beans.XPropertySet.removePropertyChangeListener. + + @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 v = boundListeners.get(propertyName); + if (v != null) { + v.remove(listener); + } + } + } + } + + /** + Implements + com.sun.star.beans.XPropertySet.addVetoableChangeListener. + +

If a listener is added more than once, it will receive all relevant + notifications multiple times.

+ + @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 v = vetoListeners.get(propertyName); + if (v == null) { + v = new ArrayList(); + vetoListeners.put(propertyName, v); + } + v.add(listener); + } + } + if (disp) { + listener.disposing(new EventObject(object)); + } + } + + /** + Implements + com.sun.star.beans.XPropertySet.removeVetoableChangeListener. + + @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 v = vetoListeners.get(propertyName); + if (v != null) { + v.remove(listener); + } + } + } + } + + /** + Implements + com.sun.star.beans.XFastPropertySet.setFastPropertyValue. + + @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 + com.sun.star.beans.XFastPropertySet.getFastPropertyValue. + + @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 + com.sun.star.beans.XPropertyAccess.getPropertyValues. + + @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 + com.sun.star.beans.XPropertyAccess.setPropertyValues. + + @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 + com.sun.star.beans.XPropertyChangeListeners. + + @see #prepareSet(String, Object, Object, + PropertySetMixin.BoundListeners) + */ + public void notifyListeners() { + if (specificListeners != null) { + for (Iterator i = specificListeners.iterator(); i.hasNext();) { + try { + i.next().propertyChange(event); + } catch (DisposedException e) {} + } + } + if (unspecificListeners != null) { + for (Iterator i = unspecificListeners.iterator(); i.hasNext();) + { + try { + i.next().propertyChange(event); + } catch (DisposedException e) {} + } + } + } + + private ArrayList specificListeners = null; + private ArrayList unspecificListeners = null; + private PropertyChangeEvent event = null; + } + + private XIdlClass getReflection(String typeName) { + return theCoreReflection.get(context).forName(typeName); + } + + private void initProperties( + XTypeDescription type, HashMap map, ArrayList handleNames, HashSet 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 properties) { + this.properties = properties; + } + + public Property[] getProperties() { + ArrayList al = new ArrayList(properties.size()); + for (Iterator 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 properties; + } + + private final XComponentContext context; + private final XInterface object; + private final Type type; + private final String[] absentOptional; + private final XIdlClass idlClass; + private final Map properties; // from String to Property + private final String[] handleMap; + + private HashMap> boundListeners + = new HashMap>(); + // from String to Vector of XPropertyChangeListener + private HashMap> vetoListeners + = new HashMap>(); + // 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 000000000..8bb4d2643 --- /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 + * + * + * [uno:]connection-type,parameters;protocol-name,parameters;objectname"; + * + * + * An example Uno Url will look like this: + * + * + * socket,host=localhost,port=2002;urp;StarOffice.ServiceManager + * + * + * For more information about Uno Url please consult + * + * http://udk.openoffice.org/common/man/spec/uno-url.html + * + * Usage: + * + * + * UnoUrl url = UnoUrl.parseUnoUrl("socket,host=localhost,port=2002;urp;StarOffice.ServiceManager"); + * + */ +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 partParameters; + private final String uninterpretedParameterString; + + public UnoUrlPart( + String uninterpretedParameterString, + String partTypeName, + HashMap partParameters) { + this.uninterpretedParameterString = uninterpretedParameterString; + this.partTypeName = partTypeName; + this.partParameters = partParameters; + } + + public String getPartTypeName() { + return partTypeName; + } + + public HashMap 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 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 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 buildParamHashMap(String paramString) + throws com.sun.star.lang.IllegalArgumentException { + HashMap params = new HashMap(); + + 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 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 000000000..67e01ac32 --- /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 m_weakRef; + // contains XReference objects registered by addReference + private final List m_xreferenceList; + + /** + *@param component the object that is to be held weak + */ + public WeakAdapter(Object component) + { + m_weakRef= new WeakReference(component); + m_xreferenceList= Collections.synchronizedList( new LinkedList()); + } + + /** 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 000000000..ac175d3a6 --- /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,Type[]> _mapTypes = new HashMap,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 vec= new ArrayList(); + 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 000000000..26c2d449d --- /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. + * + *

This class is not synchronized, as any necessary synchronization will already + * take place in the client.

+ */ +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 map = new HashMap(); // 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 000000000..106a8736c --- /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 000000000..928cdcd63 --- /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 s = map.get(tid); + if (s == null) { + s = new Stack(); + map.put(tid, s); + } + s.push(item); + } + + public synchronized Item pop(ThreadId tid) { + Stack 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> map = new HashMap>(); // 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 000000000..c16d19291 --- /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 new Float(input.readFloat()); + } + + private Double readDoubleValue() throws IOException { + return new Double(input.readDouble()); + } + + private Character readCharValue() throws IOException { + return new Character(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 000000000..34cdf7073 --- /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 000000000..0ce9d35be --- /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 com.sun.star.bridge.XProtocolProperties, + * 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 releaseQueue = new ArrayList(); // 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 000000000..6dcdc99db --- /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. + *

+ * @return the name + */ + public TypeDescription getTypeDescription() { + return typeDescription; + } + + /** + * Gives native java field of this member. + *

+ * @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 000000000..27a5361f3 --- /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 000000000..6cbbb1678 --- /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 oneWay, + * 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 TypeDescription of + * the [in] parameters. + * @return the in parameters + */ + public TypeDescription[] getInSignature() { + return inSignature; + } + + /** + * Gives any array of TypeDescription of + * the [out] parameters. + * @return the out parameters + */ + public TypeDescription[] getOutSignature() { + return outSignature; + } + + /** + * Gives the TypeDescription of + * the return type. + * @return the return type TypeDescription + */ + 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 000000000..a3c3bcd52 --- /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 TypeDescription of the + * super, if it exists. + * @return the TypeDescription. + */ + public TypeDescription getSuperType() { + // Arbitrarily take the first super type: + return superTypes == null || superTypes.length == 0 + ? null : superTypes[0]; + } + + /** + * Gets the MethodDescription for every + * method, if this type is an interface. Otherwise + * returns null. + * @return the MethodDescription[]. + */ + public MethodDescription[] getMethodDescriptions() { + initMethodDescriptions(); + return methodDescriptions; //TODO: clone? + } + + /** + * Gets the MethodDescription for the + * method with index methodId, if it exists, otherwise + * returns null. + * + * @param methodId the index. + * + * @return the MethodDescription. + */ + 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 MethodDescription for the + * method with the name name, if it exists, + * otherwise returns null. + * + * @param name the name of the method. + * + * @return the MethodDescription. + */ + 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 FieldDescription for every + * field, if this type is an interface. Otherwise + * returns null. + * @return the FieldDescription[]. + */ + public FieldDescription[] getFieldDescriptions() { + return fieldDescriptions; //TODO: clone? + } + + /** + * Gets the FieldDescription for the + * field with the name name, if it exists, + * otherwise returns null. + * + * @param name the name of the field. + * + * @return the FieldDescription. + */ + 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 TypeClass of the type. + * @return the TypeClass. + */ + public TypeClass getTypeClass() { + return typeClass; + } + + /** + * Gets the component TypeDescription if + * this is an array type, otherwise returns null. + * @return the TypeDescription + */ + public TypeDescription getComponentType() { + return componentType; + } + + /** + * Gets the (UNO) type name. + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + *
Mapping from UNO types to type names
UNO typetype name
VOID"void"
BOOLEAN"boolean"
CHAR"char"
BYTE"byte"
SHORT"short"
UNSIGNED SHORT"unsigned short"
LONG"long"
UNSIGNED LONG"unsigned long"
HYPER"hyper"
UNSIGNED HYPER"unsigned hyper"
FLOAT"float"
DOUBLE"double"
STRING"string"
TYPE"type"
ANY"any"
sequence type of base type T"[]" followed by type name for T
enum type named NN (see below)
struct type named NN (see below)
exception type named NN (see below)
interface type named NN (see below)
+ *

For a UNO type named N, consisting of a sequence of module + * names M1, ..., Mn followed by + * a simple name S, the corresponding type name consists of the + * same sequence of module names and simple name, with "." + * separating the individual elements.

+ * @return the type name. + */ + public String getTypeName() { + return typeName; + } + + /** + * Gets the (Java) array type name. + *

The array type name is defined to be the Java class name (as returned + * by Class.forName) of the Java array class that corresponds + * to the UNO sequence type with this type (the UNO type represented by this + * TypeDescription instance) as base type. For an + * TypeDescription instance representing the UNO type VOID, + * the array type name is defined to be + * "[Ljava.lang.Void;".

+ * @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 superList = new ArrayList(); + 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 directList = new ArrayList(); + 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 args = new java.util.ArrayList(); + 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 list = new ArrayList(); + } + + 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 { + public Entry(TypeDescription desc, ReferenceQueue queue) { + super(desc, queue); + typeName = desc.getTypeName(); + } + + public final String typeName; + } + + private final HashMap map = new HashMap(); + private final ReferenceQueue queue = new ReferenceQueue(); + } + + 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 000000000..3230528e1 --- /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 1.2 type. + + @param name the name of this attribute; must not be null + + @param index the index among the direct members + + @param flags any flags (READONLY, BOUND, + UNSIGNED, ANY, INTERFACE) + + @param unoType the exact UNO type; or null if the UNO type + is already unambiguously represented by the Java 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 1.2 type. + + @return the exact UNO type of this attribute type info, or + null if the UNO type is already unambiguously represented by + the Java 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 000000000..2676718cf --- /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 UNOTYPEINFO 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 000000000..5b3f669fe --- /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 1.2 type. + + @param name the name of this member; must not be null + + @param index the index among the direct members + + @param flags any flags (UNSIGNED, ANY, + INTERFACE, TYPE_PARAMETER) + + @param unoType the exact UNO type; or null if the UNO type + is already unambiguously represented by the Java 1.2 type + + @param typeParameterIndex the index of the type parameter that determines + the type of this parameterized member; or -1 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 1.2 type. + + @return the exact UNO type of this member type info, or null + if the UNO type is already unambiguously represented by the Java 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, -1 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 000000000..319e63514 --- /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 1.2 type. + + @param name the name of this method; must not be null + + @param index the index among the direct members + + @param flags any flags (ONEWAY, UNSIGNED, + ANY, INTERFACE) + + @param unoType the exact UNO return type; or null if the UNO + type is already unambiguously represented by the Java 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 1.2 type. + + @return the exact UNO return type of this method type info, or + null if the UNO type is already unambiguously represented by + the Java 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 000000000..f15ddc816 --- /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 1.2 type. + + @param name the name of this parameter; must not be null + + @param methodName the name of the method; must not be null + + @param index the index among the parameters + + @param flags any flags (IN, OUT, + UNSIGNED, ANY, INTERFACE) + + @param unoType the exact UNO type; or null if the UNO type + is already unambiguously represented by the Java 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 1.2 type. + +

If this is an out or in–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.

+ + @return the exact UNO type of this parameter type info, or + null if the UNO type is already unambiguously represented by + the Java 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 000000000..2503029fe --- /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. + +

Only used in the flags argument of the + AttributeTypeInfo constructors.

+ + @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 000000000..588b8fe38 --- /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. + * + *

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).

+ * + *

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().

+ */ +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. + * + *

The run method of the given job is called exactly once. If it terminates + * abnormally by throwing any Throwable, that is ignored.

+ * + * @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 Runnable, except that the run method may throw any + * Throwable (which is effectively ignored by + * AsynchronousFinalizer.add, similar to any Throwables + * raised by finalize being ignored). + */ + public interface Job { + void run() throws Throwable; + } + + private final LinkedList queue = new LinkedList(); + 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 000000000..6fdde2a8d --- /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 DisposeNotifier. + * + * @see DisposeNotifier + */ +public interface DisposeListener { + /** + * Callback fired by a DisposeNotifier once it is disposed. + * + * @param source the DisposeNotifier that fires the callback; + * will never be null + */ + 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 000000000..ebe0008d0 --- /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 + * WeakMap. + * + * @see WeakMap + */ +public interface DisposeNotifier { + /** + * Adds a dispose listener, to be notified when this object is disposed. + * + *

It is unspecified what happens when the same listener is added + * multiple times.

+ * + *

It is unspecified exactly when the notifyDispose 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 notifyDispose callback.

+ * + * @param listener a dispose listener, to be notified when this object is + * disposed; must not be null + */ + 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 000000000..d255a71ea --- /dev/null +++ b/ridljar/com/sun/star/lib/util/NativeLibraryLoader.java @@ -0,0 +1,141 @@ +/* -*- 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; +import com.sun.star.lib.unoloader.UnoClassLoader; + +/** + * Helper functions to locate and load native files. + * + *

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.

+ */ +public final class NativeLibraryLoader { + static { + // if it's some other class loader, then resolving the symbol + // Java_com_sun_star_bridges_jni_1uno_JNI_1proxy_dispatch_1call in + // java_uno will not work and result in UnsatisfiedLinkError + if (!(NativeLibraryLoader.class.getClassLoader() instanceof com.sun.star.lib.unoloader.UnoClassLoader)) { + System.err.println("warning: com.sun.star.lib.util.NativeLibraryLoader must be loaded by com.sun.star.lib.unoloader.UnoClassLoader for java_uno bridge to work (not a problem if this is using Java remote bridge or unit test)"); + } + } + /** + * Load a system library, using a given class loader to locate the library. + * + *

This is similar to System.loadLibrary.

+ * + * @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. + * + *

This is similar to ClassLoader.getResource, but only works + * for local resources (local files), and adds additional functionality for + * URLClassLoaders.

+ * + * @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 000000000..de8b5253a --- /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 000000000..131890f54 --- /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 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 000000000..f3b3b55a3 --- /dev/null +++ b/ridljar/com/sun/star/lib/util/WeakMap.java @@ -0,0 +1,319 @@ +/* + * 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 WeakReference. + * + *

Like HashMap, this implementation provides all of the + * optional map operations, and permits the null key.

+ * + *

Also like HashMap, this implementation is not synchronized. + * If multiple threads share an instance, and at least one of them executes any + * modifying operations on the WeakMap, they have to use external + * synchronization.

+ * + *

Unlike other map implementations, WeakMap is asymmetric in + * that put expects the given value to be a plain object that is + * then wrapped in a WeakReference, while the occurrences of values + * in all other methods (containsValue, entrySet, + * equals, get, hashCode, + * remove, values, and also the return value of + * put) expect already wrapped instances of + * WeakReference. That is, after weakMap.put("key", + * o), weakMap.get("key").equals(o) does not work as + * naïvely expected; neither does + * weakMap1.putAll(weakMap2).

+ * + *

At an arbitrary time after the WeakReference value of an + * entry has been cleared by the garbage collector, the entry is automatically + * removed from the map.

+ * + *

Values placed into a WeakMap may optionally support the + * DisposeNotifier interface. For those that do, the associated + * WeakReference wrappers are automatically cleared as soon as the + * values are disposed.

+ * + * 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 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> map = new HashMap>(); + private final ReferenceQueue queue = new ReferenceQueue(); + + /** + * Constructs an empty WeakMap. + */ + public WeakMap() {} + + /** + * Constructs a new WeakMap with the same mappings as the + * specified Map. + * + * @param m the map whose mappings are to be placed in this map + */ + public WeakMap(Map m) { + putAll(m); + } + + /** + * Returns the number of key–value mappings in this map. + * + *

This is a non-modifying operation.

+ * + * @return the number of key–value mappings in this map + */ + public int size() { + return map.size(); + } + + /** + * Returns true if this map contains no key–value + * mappings. + * + *

This is a non-modifying operation.

+ * + * @return true if this map contains no key–value + * mappings + */ + public boolean isEmpty() { + return map.isEmpty(); + } + + /** + * Returns true if this map contains a mapping for the + * specified key. + * + *

This is a non-modifying operation.

+ * + * @param key the key whose presence in this map is to be tested + * @return true if this map contains a mapping for the + * specified key + */ + public boolean containsKey(/*K*/ Object key) { + return map.containsKey(key); + } + + /** + * Returns true if this map maps one or more keys to the + * specified value. + * + *

This is a non-modifying operation.

+ * + * @param value the value whose presence in this map is to be tested + * @return true if this map maps one or more keys to the + * specified value + */ + public boolean containsValue(Object /*WeakReference*/ value) { + return map.containsValue(value); + } + + /** + * Returns the value to which the specified key is mapped in this map, or + * null if the map contains no mapping for this key. + * + *

This is a non-modifying operation.

+ * + * @param key the key whose associated value is to be returned + * + * @return the value to which this map maps the specified key, or + * null if the map contains no mapping for this key + */ + public WeakReference get(/*K*/ Object key) { + return map.get(key); + } + + /** + * Associates the specified value with the specified key in this map. + * + *

This is a modifying operation.

+ * + * @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 + * WeakReference. + * @return previous value associated with the specified key, or + * null if there was no mapping for the key + */ + public Object /*WeakReference*/ put(/*K*/ Object key, /*V*/ Object value) { + cleanUp(); + return map.put((K) key, new Entry((K) key, (V) value, queue)); + } + + /** + * Removes the mapping for this key from this map if present. + * + *

This is a modifying operation.

+ * + * @param key the key whose mapping is to be removed from the map + * @return previous value associated with the specified key, or + * null if there was no mapping for the key + */ + public Object /*WeakReference*/ remove(/*K*/ Object key) { + cleanUp(); + return map.remove(key); + } + + /** + * Copies all of the mappings from the specified map to this map. + * + *

This is a modifying operation.

+ * + * @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 + * WeakReference. + */ + public void putAll(Map/**/ m) { + cleanUp(); + for (Iterator> i = m.entrySet().iterator(); i.hasNext();) { + Map.Entry e = i.next(); + K k = e.getKey(); + map.put(k, new Entry(k, e.getValue(), queue)); + } + } + + /** + * Removes all mappings from this map. + * + *

This is a modifying operation.

+ */ + public void clear() { + cleanUp(); + map.clear(); + } + + /** + * Returns a view of the keys contained in this map. + * + *

This is a non-modifying operation.

+ * + * @return a set view of the keys contained in this map + */ + public Set keySet() { + return map.keySet(); + } + + /** + * Returns a collection view of the values contained in this map. + * + *

This is a non-modifying operation.

+ * + * @return a collection view of the values contained in this map + */ + public Collection> values() { + return map.values(); + } + + /** + * Returns a collection view of the mappings contained in this map. + * + *

This is a non-modifying operation.

+ * + * @return a collection view of the mappings contained in this map + */ + public Set/*>>*/ 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 WeakReference, silently handling a + * null argument. + * + *

This static method is useful to wrap around the return values of + * methods like get.

+ * + * @param ref must be either an instance of WeakReference or + * null + * @return the referent of the specified WeakReference, or + * null if ref is null + */ + public static T getValue(Object /*WeakReference*/ ref) { + return ref == null ? null : ((WeakReference) 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. + **/ + private void cleanUp() { + for (;;) { + Entry e = (Entry) 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 extends WeakReference + implements DisposeListener + { + private final K key; + + private Entry(K key, V value, ReferenceQueue 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 000000000..2f4976436 --- /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 java.lang.Object. + *

+ * 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). + *

+ */ +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 ANY (make sure it is wrapped up as an + * Any instance). + * + * @param any a Java value representing a UNO ANY value. + * @return a complete Java value (that is, an Any instance) + * representing the same UNO ANY 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 true if this object is the same as the obj argument; + * false 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 000000000..d36542e1a --- /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. + * + *

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.

+ * + *

The methods which extract the value do a widening conversion. See the + * method comments for the respective conversions.

+ */ +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 void. + * + * @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 char. + * + * @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 boolean. + * + * @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 byte. + * + * @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 short. + * + * @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 long + * (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 hyper + * (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 float. + * + * @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 double. + * + * @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 string. + * + * @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 enum. + * + * @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 type. + * + * @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. + * + *

If object 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.

+ * + * @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. + * + *

Allowed argument types are Byte, Short or Any containing these types.

+ * + * @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. + * + *

Allowed argument types are Anies containing idl unsigned short values.

+ * + * @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. + * + *

Allowed argument types are Byte, Short, Integer or Any containing these + * types.

+ * + * @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. + * + *

Allowed argument types are Anies containing idl unsigned short or + * unsigned long values.

+ * + * @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. + * + *

Allowed argument types are Byte, Short, Integer, Long or Any containing + * these types.

+ * + * @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. + * + *

Allowed argument types are Anies containing idl unsigned short, unsigned + * long or unsigned hyper values.

+ * + * @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. + * + *

Allowed argument types are Byte, Short, Float or Any containing these + * types.

+ * + * @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. + * + *

Allowed argument types are Byte, Short, Int, Float, Double or Any + * containing these types.

+ * + * @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. + * + *

For interfaces, the argument object is queried for the interface + * specified by the type argument.

+ * + *

That query (UnoRuntime.queryInterface) might return null, if the interface + * is not implemented or a null-ref or a VOID any is given.

+ * + * @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. + * + *

For interfaces, the argument object is queried for the interface + * specified by the type argument. That query (UnoRuntime.queryInterface) + * might return null, if the interface is not implemented or a null-ref or a + * VOID any is given.

+ * + * @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 object if is correspond to the type in + * argument what. + * + *

object is either matched directly against the type or if it is + * an any then the contained object is matched against the type.

+ */ + 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 new Float( ((Byte)object).byteValue() ); + case TypeClass.SHORT_value: + return new Float( ((Short)object).shortValue() ); + case TypeClass.FLOAT_value: + return object; + } + break; + case TypeClass.DOUBLE_value: + switch (tc) { + case TypeClass.BYTE_value: + return new Double( ((Byte)object).byteValue() ); + case TypeClass.SHORT_value: + return new Double( ((Short)object).shortValue() ); + case TypeClass.LONG_value: + return new Double( ((Integer)object).intValue() ); + case TypeClass.FLOAT_value: + return new Double( ((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 000000000..ce5108893 --- /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 ascii. + * + * @deprecated do not use. + */ +@Deprecated +public final class Ascii { + public final char ascii; + + /** + * Constructs a new Ascii. + * + * @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 000000000..8b744c5a2 --- /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 asciistring. + * + * @deprecated do not use. + */ +@Deprecated +public final class AsciiString { + public final String asciistring; + + /** + * Constructs a new AsciiString. + * + * @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 000000000..8bd50876d --- /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. + *

+ * 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. + *

+ */ +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 000000000..51babcdfc --- /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. + * + *

Bridges are able to map one object from one UNO environment to another and + * vice versa.

+ * + * @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. + * + *

If the life count drops to zero, the bridge disposes itself.

+ */ + void release(); + + /** + * Disposes the bridge. + * + *

Sends involved threads an InterruptedException. Releases + * mapped objects.

+ * + * @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 000000000..5d3289305 --- /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. + * + *

With this interface, objects can be registered at and revoked from an + * environment.

+ * + * @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. + * + *

Such an object will typically be one of three things: + *

    + *
  • A local Java object, to be mapped out of this environment via a given + * bridge.
  • + *
  • A proxy object, mapped into this environment via some bridge + * B1, and now to be mapped out of this environment via a + * given bridge B2.
  • + *
  • A proxy object, created as a remote object is mapped into this + * environment via a given bridge.
  • + *
+ * + *

The object actually registered may differ from the specified + * object that is passed as an argument. This enables an + * environment to work in a multi-threaded scenario, where two threads can + * call registerInterface for the same combination of + * oid and type at the same time; the race + * condition is solved by letting one of the calls register its argument + * object, ignoring the argument object of the + * other call, and letting both calls return the same + * object.

+ * + *

The registered object is held only weakly by the environment. After a + * call to registerInterface, a call to + * getRegisteredInterface only succeeds as long as the + * registered object is still strongly reachable, and the registered object + * has not been explicitly revoked by calling + * revokeInterface.

+ * + * @param object the object to register; must be non-null + * @param oid in-out parameter containing the OID of object. + * 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 + * object should implement this type. + * @return the registered object (may differ from the object + * passed in); will never be null + */ + Object registerInterface(Object object, String[] oid, Type type); + + /** + * Explicitly revokes a UNO interface facet. + * + *

Calls to registerInterface and + * revokeInterface 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 revokeInterface (and calls to + * revokeInterface would no longer be necessary if the calling + * code does not want to control the temporal extent of the + * registration).

+ * + *

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.

+ * + * @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 object; will never be null + */ + String getRegisteredObjectIdentifier(Object object); + + /** + * Lists the registered objects to System.out. + * + *

This is for debug purposes.

+ */ + 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 000000000..fdf6d8207 --- /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. + * + *

This interface exists for compatibility with the binary UNO API.

+ * + * @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 000000000..7857d6205 --- /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. + * + *

Calls are delegated through the UnoRuntime to this + * interface. Implement this interface in case you want to customize the + * behaviour of UnoRuntime.queryInterface.

+ * + * @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 Type + * object representing a UNO interface type + * @return a reference to the requested UNO interface type if available, + * otherwise null + * @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 null + * @return true if and only if object is not + * null 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 000000000..7670a790a --- /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. + * + *

The exception is replaced by the com.sun.star.lang.DisposedException.

+ * + * @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 MappingException. + */ + public MappingException() { + super(); + } + + /** + * Constructs an MappingException with a detail message. + * + * @param message the detail message. + */ + public MappingException(String message) { + super(message); + } + + /** + * Constructs an MappingException 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 000000000..0589b64cb --- /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 TYPE. + * + *

The UNO type is not directly mapped to java.lang.Class for at + * least two reasons. For one, some UNO types (like UNSIGNED + * SHORT) 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.)

+ * + *

A Type is uniquely determined by its type class (a + * TypeClass) and its type name (a String); these two + * will never be null. A Type may have an additional + * "z class" (a java.lang.Class), giving a Java class type that + * corresponds to the UNO type. Also, a Type can cache a type + * description (a com.sun.star.uno.typedesc.TypeDescription), which can be + * computed and set by TypeDescription.getTypeDescription. + */ +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, TypeInfo> __javaClassToTypeClass = + new HashMap, 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 Type which defaults to VOID. + */ + public Type() { + init(null, void.class, false, false, false); + } + + /** + * Constructs a new Type with the given type class and type + * name. + * + * @param typeName the type name. Must not be null. + * @param typeClass the type class. Must not be null, and must + * match the typeName (for example, it is illegal to + * combine a typeName of "void" with a + * typeClass of BOOLEAN). + */ + public Type(String typeName, TypeClass typeClass) { + _typeClass = typeClass; + _typeName = typeName; + } + + /** + * Constructs a new Type from the given + * java.lang.Class. + * + *

This is equivalent to Type(zClass, false).

+ * + * @param zClass the Java class of this type. Must not be + * null. + */ + public Type(Class zClass) { + init(null, zClass, false, false, false); + } + + /** + * Constructs a new Type from the given + * java.lang.Class, handling ambiguous cases. + * + *

In certain cases, one Java class corresponds to two UNO types (e.g., + * the Java class short[].class corresponds to both a sequence + * of SHORT and a sequence of UNSIGNED SHORT in + * UNO). In such ambiguous cases, the parameter alternative + * controls which UNO type is chosen: + *

    + *
  • If the Java type is (an array type with element type) + * short or java.lang.Short: If + * alternative is false, the chosen UNO type is + * (a sequence type with element type) SHORT. If + * alternative is true, the chosen UNO type is + * (a sequence type with element type) UNSIGNED SHORT.
  • + * + *
  • If the Java type is (an array type with element type) + * int or java.lang.Integer: If + * alternative is false, the chosen UNO type is + * (a sequence type with element type) LONG. If + * alternative is true, the chosen UNO type is + * (a sequence type with element type) UNSIGNED LONG.
  • + * + *
  • If the Java type is (an array type with element type) + * long or java.lang.Long: If + * alternative is false, the chosen UNO type is + * (a sequence type with element type) HYPER. If + * alternative is true, the chosen UNO type is + * (a sequence type with element type) UNSIGNED HYPER.
  • + * + *
  • If the Java type is (an array type with element type) + * java.lang.Object: If alternative is + * false, the chosen UNO type is (a sequence type with + * element type) ANY. If alternative is + * true, the chosen UNO type is (a sequence type with element + * type) com.sun.star.uno.XInterface.
  • + *
+ *

In all other cases, the value of alternative is + * ignored.

+ * + *

This constructor cannot be used to create Type instances + * that represent (sequences of) instantiated polymorphic struct types.

+ * + * @param zClass the Java class of this type; must not be null + * @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 Type from the given type description. + * + * For internal URE use only. Not to be used by client code. + * + * @param typeDescription a type description. Must not be + * null. + */ + public Type(TypeDescription typeDescription) { + _typeName = typeDescription.getTypeName(); + _typeClass = typeDescription.getTypeClass(); + _iTypeDescription = typeDescription; + } + + /** + * Constructs a new Type with the given type name. + * + * @param typeName the name of this type; must not be null. + */ + 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 Type with the given type class. + * + * @param typeClass the type class of this type; must not be + * null. Only type classes for simple types are allowed + * here. + * + * @throws IllegalArgumentException if the given typeClass 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 null, but might be + * UNKNOWN. + */ + public TypeClass getTypeClass() { + return _typeClass; + } + + /** + * Gets the type name. + * + * @return the type name; will never be null + */ + public String getTypeName() { + return _typeName; + } + + /** + * Gets the Java class. + * + * @return the type name; may be null in extreme situations + * (inconsistent TypeClass, error loading a class) + */ + public Class getZClass() { + synchronized (this) { + if (_class == null) { + _class = determineClass(); + } + } + return _class; + } + + /** + * Gives the type description of this type. + * + * For internal URE use only. Not to be used by client code. + * + * @return the type description; may be null + */ + public TypeDescription getTypeDescription() { + return _iTypeDescription; + } + + /** + * Sets the type description for this type. + * + * For internal URE use only. Not to be used by client code. + * + * @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 true if this object is the same as the obj argument; + * false 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 000000000..1f011aa77 --- /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. + * + *

The methods queryInterface and areSame delegate + * calls to the implementing objects and are used instead of casts, + * instanceof, ==, and equals.

+ * + *

For historic reasons, this class is not final, and has a + * public 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.

+ * + * @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 3.2.0, do not create instances of this class. + * It is considered a historic mistake to have a public + * constructor for this class, which only has static members. + * Also, this class might be changed to become final in a + * future version. + */ + @Deprecated + public UnoRuntime() {} + + /** + * Generates a worldwide unique identifier string. + * + *

It is guaranteed that every invocation of this method generates a new + * ID, which is unique within the VM. The quality of “worldwide + * unique” will depend on the actual implementation, you should look + * at the source to determine if it meets your requirements.

+ * + * @return a unique String + */ + 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. + * + *

It is guaranteed that subsequent calls to this method with the same + * Java object will give the same ID.

+ * + *

This method is generally of little use for client code. It should be + * considered a mistake that this method is published at all.

+ * + * @param object any object for which an OID shall be generated; must not be + * null + * @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. + * + *

This method returns null in case the given UNO object + * does not support the given UNO interface type (or is itself + * null). 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.

+ * + * @param type the requested UNO interface type; must be a Type + * object representing a UNO interface type + * @param object a reference to any Java object representing (a facet of) a + * UNO object; may be null + * @return a reference to the requested UNO interface type if available, + * otherwise null + * @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 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 null + * @return a reference to the requested UNO interface type if available, + * otherwise null + * @see #queryInterface(Type, Object) + */ + @SuppressWarnings("unchecked") + public static T queryInterface(Class zInterface, Object object) { + return (T) queryInterface(new Type(zInterface), object); + } + + /** + Tests two UNO ANY values for equality. + +

Two UNO values are equal if and only if they are of the + same UNO type t, and they meet the following condition, + depending on t:

+
    +
  • If t is a primitive type, then both values must denote + the same element of the set of values of t.
  • + +
  • If t is a structured type, then both values must + recursively contain corresponding values that are equal.
  • + +
  • If t is an interface type, then the two values must be + either both null references, or both references to the same UNO + object.
  • +
+ + @param any1 a Java value representing a UNO ANY value. + + @param any2 a Java value representing a UNO ANY value. + + @return true 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 null + value). + +

This is useful for members of parameterized type of instantiated + polymorphic struct types, as null is a valid value there + (and only there, for all types except ANY and interface + types).

+ + @param type a non-void, non-exception UNO type. + + @param value a Java value representing a UNO value of the given UNO type, + or null. + + @return the given value, or the neutral value of the given type, if the + given value was an invalid null 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 new Float(0.0f); + case TypeClass.DOUBLE_value: + return new Double(0.0); + case TypeClass.CHAR_value: + return new Character('\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 null if + * no context has been set for the current thread. + * + *

The current context is thread local, which means that this method + * returns the context that was last set for this thread.

+ * + * @return the current context of the current thread, or null + * 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. + * + *

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 finally + * block).

+ * + * @param context the context to be set; if null, 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 name with context + * context. + * + *

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 + * com.sun.star.lib.uno.environments.name.name_environment.

+ * + * @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 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 from to environment + * to. + * + *

Creates a new bridge, if the requested bridge does not yet exist, and + * hands the arguments to the bridge.

+ * + *

If the requested bridge does not exist, it is searched for in package + * com.sun.star.lib.uno.bridges.from_to; + * and the root classpath as + * from_to_bridge.

+ * + * @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 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 from to environment + * to. + * + *

Creates a new bridge, if the requested bridge does not yet exist, and + * hands the arguments to the bridge.

+ * + *

If the requested bridge does not exist, it is searched for in package + * com.sun.star.lib.uno.bridges.from_to; + * and the root classpath as + * from_to_bridge. The used environments + * are retrieved through getEnvironment.

+ * + * @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 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 IBridge objects + * @see com.sun.star.uno.IBridge + * + * @deprecated As of UDK 3.2.0, this method is deprecated, without + * offering a replacement. + */ + @Deprecated + public static IBridge[] getBridges() { + ArrayList l = new ArrayList(); + synchronized (bridges) { + for (Iterator> 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 from to environment + * to. + * + *

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.

+ * + * @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 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 from to environment + * to. + * + *

The used environments are retrieved through + * getEnvironment.

+ * + * @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 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 UnoRuntime to its initial state. + * + *

Releases all references to bridges and environments.

+ * + * @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 3.2.0, this method is deprecated, without + * offering a replacement. + */ + @Deprecated + public static boolean reset() { + synchronized (bridges) { + for (Iterator> 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 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 oidMap = new WeakHashMap(); + 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 currentContext = new ThreadLocal(); + + private static final WeakMap environments = new WeakMap(); + private static final WeakMap bridges = new WeakMap(); +} diff --git a/ridljar/com/sun/star/uno/WeakReference.java b/ridljar/com/sun/star/uno/WeakReference.java new file mode 100644 index 000000000..a6b171ac2 --- /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. + * + *

It actually holds a reference to a com.sun.star.XAdapter + * 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. + * + *

It keeps the XAdapter implementation and registers always with it. + * Deregistering occurs on notification by the adapter and the adapter is + * released.

+ */ +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 com.sun.star.uno.XReference. + * + *

When called, it deregisters this object with the adapter and releases + * the reference to it.

+ */ + 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: */ diff --git a/ridljar/pom.libreoffice.xml b/ridljar/pom.libreoffice.xml new file mode 100644 index 000000000..ca6438ebe --- /dev/null +++ b/ridljar/pom.libreoffice.xml @@ -0,0 +1,44 @@ + + 4.0.0 + org.libreoffice + libreoffice + @version@ + jar + LibreOffice - Public UNO Java Classes + Public UNO Java Classes (formerly jurt,juh,ridl,unoil) + https://www.libreoffice.org + + + + Mozilla Public License, Version 2.0 + https://www.mozilla.org/en-US/MPL/2.0 + repo + + + + + https://cgit.freedesktop.org/libreoffice/core + https://gerrit.libreoffice.org/#/admin/projects/core + + + + + The Document Foundation + + + + + + LibreOffice Development Mailing List + libreoffice@lists.freedesktop.org + http://lists.freedesktop.org/mailman/listinfo/libreoffice + http://lists.freedesktop.org/mailman/listinfo/libreoffice + http://lists.freedesktop.org/archives/libreoffice + + + + + https://bugs.documentfoundation.org + LibreOffice Issue Tracker + + diff --git a/ridljar/pom.ridl.xml b/ridljar/pom.ridl.xml new file mode 100644 index 000000000..9990dd45e --- /dev/null +++ b/ridljar/pom.ridl.xml @@ -0,0 +1,54 @@ + + 4.0.0 + org.libreoffice + ridl + @version@ + jar + LibreOffice - Types for the Java Uno typesystem + Types for the Java Uno typesystem + https://www.libreoffice.org + + + + + org.libreoffice + libreoffice + @version@ + + + + + + + Mozilla Public License, Version 2.0 + https://www.mozilla.org/en-US/MPL/2.0 + repo + + + + + https://cgit.freedesktop.org/libreoffice/core + https://gerrit.libreoffice.org/#/admin/projects/core + + + + + The Document Foundation + + + + + + LibreOffice Development Mailing List + libreoffice@lists.freedesktop.org + http://lists.freedesktop.org/mailman/listinfo/libreoffice + http://lists.freedesktop.org/mailman/listinfo/libreoffice + http://lists.freedesktop.org/archives/libreoffice + + + + + https://bugs.documentfoundation.org + LibreOffice Issue Tracker + + diff --git a/ridljar/pom.unoloader.xml b/ridljar/pom.unoloader.xml new file mode 100644 index 000000000..b509bdf31 --- /dev/null +++ b/ridljar/pom.unoloader.xml @@ -0,0 +1,44 @@ + + 4.0.0 + org.libreoffice + unoloader + @version@ + jar + LibreOffice - UNO loader + UNO loader + https://www.libreoffice.org + + + + Mozilla Public License, Version 2.0 + https://www.mozilla.org/en-US/MPL/2.0 + repo + + + + + https://cgit.freedesktop.org/libreoffice/core + https://gerrit.libreoffice.org/#/admin/projects/core + + + + + The Document Foundation + + + + + + LibreOffice Development Mailing List + libreoffice@lists.freedesktop.org + http://lists.freedesktop.org/mailman/listinfo/libreoffice + http://lists.freedesktop.org/mailman/listinfo/libreoffice + http://lists.freedesktop.org/archives/libreoffice + + + + + https://bugs.documentfoundation.org + LibreOffice Issue Tracker + + diff --git a/ridljar/source/libreoffice/manifest b/ridljar/source/libreoffice/manifest new file mode 100644 index 000000000..e69de29bb diff --git a/ridljar/source/libreoffice/module-info.java b/ridljar/source/libreoffice/module-info.java new file mode 100644 index 000000000..8d24c7ccb --- /dev/null +++ b/ridljar/source/libreoffice/module-info.java @@ -0,0 +1,142 @@ +/* + * 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/. + */ + +module org.libreoffice.uno +{ + requires org.libreoffice.unoloader; + + exports com.sun.star.accessibility; + exports com.sun.star.animations; + exports com.sun.star.auth; + exports com.sun.star.awt; + exports com.sun.star.awt.grid; + exports com.sun.star.awt.tab; + exports com.sun.star.awt.tree; + exports com.sun.star.beans; + exports com.sun.star.bridge; + exports com.sun.star.bridge.oleautomation; + exports com.sun.star.chart; + exports com.sun.star.chart2; + exports com.sun.star.chart2.data; + exports com.sun.star.comp.bridgefactory; + exports com.sun.star.comp.connections; + exports com.sun.star.comp.helper; + exports com.sun.star.comp.loader; + exports com.sun.star.comp.servicemanager; + exports com.sun.star.comp.urlresolver; + exports com.sun.star.configuration; + exports com.sun.star.configuration.backend; + exports com.sun.star.connection; + exports com.sun.star.container; + exports com.sun.star.cui; + exports com.sun.star.datatransfer; + exports com.sun.star.datatransfer.clipboard; + exports com.sun.star.datatransfer.dnd; + exports com.sun.star.deployment; + exports com.sun.star.deployment.test; + exports com.sun.star.deployment.ui; + exports com.sun.star.document; + exports com.sun.star.drawing; + exports com.sun.star.drawing.framework; + exports com.sun.star.embed; + exports com.sun.star.form; + exports com.sun.star.form.binding; + exports com.sun.star.form.control; + exports com.sun.star.form.runtime; + exports com.sun.star.form.submission; + exports com.sun.star.form.validation; + exports com.sun.star.formula; + exports com.sun.star.frame; + exports com.sun.star.frame.status; + exports com.sun.star.gallery; + exports com.sun.star.geometry; + exports com.sun.star.graphic; + exports com.sun.star.i18n; + exports com.sun.star.inspection; + exports com.sun.star.io; + exports com.sun.star.java; + exports com.sun.star.lang; + exports com.sun.star.ldap; + exports com.sun.star.lib.connections.pipe; + exports com.sun.star.lib.connections.socket; + exports com.sun.star.lib.uno; + exports com.sun.star.lib.uno.adapter; + exports com.sun.star.lib.uno.bridges.java_remote; + exports com.sun.star.lib.uno.environments.java; + exports com.sun.star.lib.uno.environments.remote; + exports com.sun.star.lib.uno.helper; + exports com.sun.star.lib.uno.protocols.urp; + exports com.sun.star.lib.uno.typedesc; + exports com.sun.star.lib.uno.typeinfo; + exports com.sun.star.lib.util; + exports com.sun.star.linguistic2; + exports com.sun.star.loader; + exports com.sun.star.logging; + exports com.sun.star.mail; + exports com.sun.star.media; + exports com.sun.star.mozilla; + exports com.sun.star.office; + exports com.sun.star.packages; + exports com.sun.star.packages.manifest; + exports com.sun.star.packages.zip; + exports com.sun.star.presentation; + exports com.sun.star.qa; + exports com.sun.star.rdf; + exports com.sun.star.reflection; + exports com.sun.star.registry; + exports com.sun.star.rendering; + exports com.sun.star.report; + exports com.sun.star.report.inspection; + exports com.sun.star.report.meta; + exports com.sun.star.resource; + exports com.sun.star.scanner; + exports com.sun.star.script; + exports com.sun.star.script.browse; + exports com.sun.star.script.provider; + exports com.sun.star.script.vba; + exports com.sun.star.sdb; + exports com.sun.star.sdb.application; + exports com.sun.star.sdb.tools; + exports com.sun.star.sdbc; + exports com.sun.star.sdbcx; + exports com.sun.star.security; + exports com.sun.star.setup; + exports com.sun.star.sheet; + exports com.sun.star.sheet.opencl; + exports com.sun.star.smarttags; + exports com.sun.star.style; + exports com.sun.star.svg; + exports com.sun.star.system; + exports com.sun.star.table; + exports com.sun.star.task; + exports com.sun.star.text; + exports com.sun.star.text.textfield; + exports com.sun.star.tiledrendering; + exports com.sun.star.ucb; + exports com.sun.star.ui; + exports com.sun.star.ui.dialogs; + exports com.sun.star.ui.test; + exports com.sun.star.uno; + exports com.sun.star.uri; + exports com.sun.star.util; + exports com.sun.star.view; + exports com.sun.star.xforms; + exports com.sun.star.xml; + exports com.sun.star.xml.crypto; + exports com.sun.star.xml.crypto.sax; + exports com.sun.star.xml.csax; + exports com.sun.star.xml.dom; + exports com.sun.star.xml.dom.events; + exports com.sun.star.xml.dom.views; + exports com.sun.star.xml.input; + exports com.sun.star.xml.sax; + exports com.sun.star.xml.wrapper; + exports com.sun.star.xml.xpath; + exports com.sun.star.xml.xslt; + exports com.sun.star.xsd; +} diff --git a/ridljar/source/unoloader/BUCK b/ridljar/source/unoloader/BUCK new file mode 100644 index 000000000..1c2b20f06 --- /dev/null +++ b/ridljar/source/unoloader/BUCK @@ -0,0 +1,21 @@ + +java_sources( + name = 'unoloader-src', + srcs = glob(['com/**']), + root = '.', + visibility = ['PUBLIC'], +) + +java_doc( + name = 'unoloader-javadoc', + title = 'LibreOffice Uno loader', + pkgs = [ + 'com.sun.star.lib.unoloader', + ], + paths = ['.'], + srcs = glob(['com/**']), + deps = [ + '//:ridl', + ], + visibility = ['PUBLIC'], +) diff --git a/ridljar/source/unoloader/com/sun/star/lib/unoloader/UnoClassLoader.java b/ridljar/source/unoloader/com/sun/star/lib/unoloader/UnoClassLoader.java new file mode 100644 index 000000000..822d1609c --- /dev/null +++ b/ridljar/source/unoloader/com/sun/star/lib/unoloader/UnoClassLoader.java @@ -0,0 +1,203 @@ +/* + * 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.unoloader; + +import java.io.IOException; +import java.lang.reflect.InvocationTargetException; +import java.net.MalformedURLException; +import java.net.URL; +import java.net.URLClassLoader; +import java.util.jar.Attributes; +import java.util.jar.Manifest; +import java.util.jar.JarInputStream; + +/** + * The root UNO class loader. + * + *

This class loader is able to load all published URE classes, including the + * classes representing the published URE UNO types. For consistency, it is + * important that within each Java UNO environment there is one instance of this + * class loader that is the defining class loader of all published URE classes + * (and hence of all unpublished URE classes, too) and of all classes + * representing UNO types (the published URE UNO types, any unpublished URE UNO + * types, and any additional UNO types introduced by components; for the latter, + * {@link #addURL} may be necessary).

+ * + *

This is an internal, unstable class of the Uno Runtime Environment; it + * should not be used by client code.

+ * + * @since UDK 3.2.0 + */ +public final class UnoClassLoader extends URLClassLoader { + /** + * Instantiates the root UNO class loader. + * + * @param base a base URL relative to which the URE JARs + * (java_uno.jar and libreoffice.jar) + * can be found; must not be null. + * + * @param classPath an array of URLs that form the class path of this class + * loader; may be null, which is the same as an empty array. + * The URLs are interpreted in the same way as the arguments of a {@link + * URLClassLoader}. + * + * @param parent the parent class loader for delegation. + * + * @throws MalformedURLException if the given base URL is + * malformed. + */ + public UnoClassLoader(URL base, URL[] classPath, ClassLoader parent) + throws MalformedURLException + { + super(createUrls(base, classPath), parent); + } + + /** + * Obtains a class loader for a UNO JAR. + * + * @param jar the URL of a UNO JAR; must not be null. + * + * @param mainAttributes represents the main section of the manifest of the + * given JAR jar; null if the given JAR does not + * have a manifest. (This redundant parameter is there for performance + * reasons, as typically the caller of this method already has this + * information available.) + * + * @return an appropriate class loader; will never be null. + * + * @throws MalformedURLException if the given jar URL or any of + * the UNO-Type-Path URLs specified in the given JAR are malformed. + */ + public ClassLoader getClassLoader(URL jar, Attributes mainAttributes) + throws MalformedURLException + { + String path = mainAttributes == null ? + null : mainAttributes.getValue("UNO-Type-Path"); + if (path == null) { + path = "<>"; + } + for (int i = 0; i < path.length();) { + while (i < path.length() && path.charAt(i) == ' ') { + ++i; + } + if (i < path.length()) { + String url; + if (path.charAt(i) == '<') { + int j = path.indexOf('>', i + 1); + if (j < 0) { + url = path.substring(i + 1); + i = path.length(); + } else { + url = path.substring(i + 1, j); + i = j + 1; + } + } else { + int j = path.indexOf(' ', i + 1); + if (j < 0) { + j = path.length(); + } + url = path.substring(i, j); + i = j; + } + addURL(new URL(jar, url)); + } + } + return URLClassLoader.newInstance(new URL[] { jar }, this); + } + + /** + * Executes a UNO JAR. + * + * @param jar the URL of a UNO JAR that specifies a Main-Class; must not be + * null. + * + * @param arguments any arguments passed to the main method of + * the specified Main-Class of the given JAR jar; must not be + * null. + * + * @throws IOException if there are any problems processing the given JAR + * jar. + * + * @throws ClassNotFoundException if the given JAR jar does not + * specify a Main-Class, or if the specified Main-Class cannot be found. + * + * @throws NoSuchMethodException if the specified Main-Class of the given + * JAR jar does not have an appropriate main + * method. + * + * @throws InvocationTargetException if an exception occurs while executing + * the main method of the specified Main-Class of the given JAR + * jar. + */ + public void execute(URL jar, String[] arguments) + throws IOException, ClassNotFoundException, NoSuchMethodException, + InvocationTargetException + { + Attributes attr = getJarMainAttributes(jar); + String name = attr == null + ? null : attr.getValue(Attributes.Name.MAIN_CLASS); + if (name == null) { + throw new ClassNotFoundException( + jar + " does not specify a main class"); + } + try { + getClassLoader(jar, attr).loadClass(name.replace('/', '.')). + getMethod("main", new Class[] { String[].class }). + invoke(null, new Object[] { arguments }); + } catch (IllegalAccessException e) { + throw new RuntimeException("impossible " + e); + } + } + + /** + * Obtains the main section of the manifest of a JAR. + * + * @param jar the URL of a JAR; must not be null. + * + * @return the representation of the main section of the manifest of the + * given JAR jar, or null if the given JAR does + * not have a manifest. + * + * @throws IOException if there are any problems processing the given JAR + * jar. + */ + public static Attributes getJarMainAttributes(URL jar) throws IOException { + JarInputStream s = new JarInputStream(jar.openStream()); + Manifest mf; + try { + mf = s.getManifest(); + } finally { + s.close(); + } + return mf == null ? null : mf.getMainAttributes(); + } + + private static URL[] createUrls(URL base, URL[] classPath) + throws MalformedURLException + { + final int JARS = 2; + URL[] urls = new URL[JARS + (classPath == null ? 0 : classPath.length)]; + urls[0] = new URL(base, "java_uno.jar"); //TODO get rid of it here + urls[1] = new URL(base, "libreoffice.jar"); + if (classPath != null) { + System.arraycopy(classPath, 0, urls, JARS, classPath.length); + } + return urls; + } +} diff --git a/ridljar/source/unoloader/com/sun/star/lib/unoloader/UnoLoader.java b/ridljar/source/unoloader/com/sun/star/lib/unoloader/UnoLoader.java new file mode 100644 index 000000000..23059b7b4 --- /dev/null +++ b/ridljar/source/unoloader/com/sun/star/lib/unoloader/UnoLoader.java @@ -0,0 +1,85 @@ +/* + * 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.unoloader; + +import java.io.IOException; +import java.lang.reflect.InvocationTargetException; +import java.net.MalformedURLException; +import java.net.URL; +import java.security.AccessController; +import java.security.PrivilegedActionException; +import java.security.PrivilegedExceptionAction; + +/** + * A helper class for executing UNO JARs. + * + *

This class is not yet stable.

+ * + * @since UDK 3.2.0 + */ +public final class UnoLoader { + /** + * Executes a UNO JAR. + * + * @param base a base URL relative to which the URE JARs + * (libreoffice.jar, etc.) can be found; must + * not be null. + * + * @param jar the URL of a UNO JAR that specifies a Main-Class; must not be + * null. + * + * @param arguments any arguments passed to the main method of + * the specified Main-Class of the given JAR jar; must not be + * null. + * + * @throws IOException if the given base URL is malformed, or + * if there are any problems processing the given JAR jar. + * + * @throws ClassNotFoundException if the given JAR jar does not + * specify a Main-Class, or if the specified Main-Class cannot be found. + * + * @throws NoSuchMethodException if the specified Main-Class of the given + * JAR jar does not have an appropriate main + * method. + * + * @throws InvocationTargetException if an exception occurs while executing + * the main method of the specified Main-Class of the given JAR + * jar. + */ + public static void execute(final URL base, URL jar, String[] arguments) + throws IOException, ClassNotFoundException, NoSuchMethodException, + InvocationTargetException + { + UnoClassLoader cl; + try { + cl = (UnoClassLoader) AccessController.doPrivileged( + new PrivilegedExceptionAction() { + public Object run() throws MalformedURLException { + return new UnoClassLoader( + base, null, UnoLoader.class.getClassLoader()); + } + }); + } catch (PrivilegedActionException e) { + throw (MalformedURLException) e.getException(); + } + cl.execute(jar, arguments); + } + + private UnoLoader() {} +} diff --git a/ridljar/source/unoloader/com/sun/star/lib/unoloader/manifest b/ridljar/source/unoloader/com/sun/star/lib/unoloader/manifest new file mode 100644 index 000000000..7ad02e156 --- /dev/null +++ b/ridljar/source/unoloader/com/sun/star/lib/unoloader/manifest @@ -0,0 +1 @@ +Sealed: true diff --git a/ridljar/source/unoloader/module-info.java b/ridljar/source/unoloader/module-info.java new file mode 100644 index 000000000..6eed39c96 --- /dev/null +++ b/ridljar/source/unoloader/module-info.java @@ -0,0 +1,12 @@ +/* + * 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/. + */ + +module org.libreoffice.unoloader +{ + exports com.sun.star.lib.unoloader; +} diff --git a/ridljar/test/com/sun/star/comp/bridgefactory/BridgeFactory_Test.java b/ridljar/test/com/sun/star/comp/bridgefactory/BridgeFactory_Test.java new file mode 100644 index 000000000..965653bf7 --- /dev/null +++ b/ridljar/test/com/sun/star/comp/bridgefactory/BridgeFactory_Test.java @@ -0,0 +1,92 @@ +/* -*- 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 com.sun.star.bridge.BridgeExistsException; +import com.sun.star.bridge.XBridge; +import com.sun.star.comp.connections.PipedConnection; +import com.sun.star.lang.XComponent; +import com.sun.star.uno.UnoRuntime; +import org.junit.Test; +import static org.junit.Assert.*; + +public final class BridgeFactory_Test { + @Test public void test() throws Exception { + PipedConnection rightSide = new PipedConnection(new Object[0]); + PipedConnection leftSide = new PipedConnection(new Object[]{rightSide}); + + BridgeFactory bridgeFactory = new BridgeFactory(); // create the needed bridgeFactory + + // create a bridge + XBridge xBridge = bridgeFactory.createBridge("testbridge", "urp", leftSide, null); + + // test that we get the same bridge + assertTrue( + UnoRuntime.areSame( + xBridge, bridgeFactory.getBridge("testbridge"))); + + // test that we can not create another bridge with same name + try { + bridgeFactory.createBridge("testbridge", "urp", leftSide, null); + + fail(); + } + catch(BridgeExistsException bridgeExistsException) { + } + + + // test getExistingBridges + XBridge xBridges[] = bridgeFactory.getExistingBridges(); + assertTrue(UnoRuntime.areSame(xBridge, xBridges[0])); + + // dispose the bridge + XComponent xComponent = UnoRuntime.queryInterface(XComponent.class, xBridge); + xComponent.dispose(); + + + // test that the bridge has been removed + assertTrue(bridgeFactory.getBridge("testbridge") == null); + + + + rightSide = new PipedConnection(new Object[0]); + leftSide = new PipedConnection(new Object[]{rightSide}); + + + // test that we really get a new bridge + XBridge xBridge_new = bridgeFactory.createBridge("testbridge", "urp", leftSide, null); + assertFalse(UnoRuntime.areSame(xBridge, xBridge_new)); + + for(int i = 0; i <10000; ++ i) { + Object x[] = new Object[100]; + } + + // test getExistingBridges + xBridges = bridgeFactory.getExistingBridges(); + assertEquals(1, xBridges.length); + assertTrue(UnoRuntime.areSame(xBridge_new, xBridges[0])); + + // dispose the new bridge + XComponent xComponent_new = UnoRuntime.queryInterface(XComponent.class, xBridge_new); + xComponent_new.dispose(); + } +} + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/ridljar/test/com/sun/star/comp/connections/PipedConnection_Test.java b/ridljar/test/com/sun/star/comp/connections/PipedConnection_Test.java new file mode 100644 index 000000000..6cfef789d --- /dev/null +++ b/ridljar/test/com/sun/star/comp/connections/PipedConnection_Test.java @@ -0,0 +1,104 @@ +/* -*- 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.io.IOException; +import org.junit.Test; +import static org.junit.Assert.*; + +public final class PipedConnection_Test { + private static final int ROUNDS = 2000; + + @Test public void test() throws Exception { + PipedConnection rightSide = new PipedConnection(new Object[0]); + PipedConnection leftSide = new PipedConnection(new Object[]{rightSide}); + + Reader reader = new Reader(rightSide); + Writer writer = new Writer(leftSide); + + reader.start(); + writer.start(); + + writer.join(); + reader.join(); + + assertTrue(writer._state); + assertTrue(reader._state); + assertEquals(ROUNDS, reader._rounds); + } + + private static class Reader extends Thread { + PipedConnection _pipedConnection; + boolean _state = false; + int _rounds = 0; + + Reader(PipedConnection pipedConnection) { + _pipedConnection = pipedConnection; + } + + @Override + public void run() { + try { + for (byte v = 0;; v++) { + byte[][] b = new byte[1][]; + int n = _pipedConnection.read(b, 1); + if (n == 0) { + break; + } + assertEquals(1, n); + assertEquals(1, b[0].length); + assertEquals(v, b[0][0]); + ++_rounds; + } + _pipedConnection.close(); + _state = true; + } catch (IOException e) { + throw new RuntimeException(e); + } + } + } + + private static class Writer extends Thread { + PipedConnection _pipedConnection; + boolean _state = false; + + Writer(PipedConnection pipedConnection) { + _pipedConnection = pipedConnection; + } + + @Override + public void run() { + try { + byte v = 0; + for (int i = 0; i != ROUNDS; ++i) { + byte[] b = new byte[] { v++ }; + _pipedConnection.write(b); + _pipedConnection.flush(); + } + _pipedConnection.close(); + _state = true; + } catch (IOException e) { + throw new RuntimeException(e); + } + } + } +} + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/ridljar/test/com/sun/star/lib/uno/bridges/java_remote/BridgedObject_Test.java b/ridljar/test/com/sun/star/lib/uno/bridges/java_remote/BridgedObject_Test.java new file mode 100644 index 000000000..e7dc9c0e1 --- /dev/null +++ b/ridljar/test/com/sun/star/lib/uno/bridges/java_remote/BridgedObject_Test.java @@ -0,0 +1,64 @@ +/* -*- 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.uno.Type; +import com.sun.star.uno.XInterface; +import org.junit.Test; +import static org.junit.Assert.*; + +public final class BridgedObject_Test { + @Test public void test() { + RequestHandler handler = new RequestHandler() { + public Object sendRequest( + String oid, Type type, String operation, Object[] args) + { + return null; + } + }; + XBridge bridge1 = new TestBridge(); + ProxyFactory factory1 = new ProxyFactory(handler, bridge1); + XBridge bridge2 = new TestBridge(); + ProxyFactory factory2 = new ProxyFactory(handler, bridge2); + Object object0 = new Object(); + Object object1 = factory1.create("", new Type(XInterface.class)); + Object object2 = factory2.create("", new Type(XInterface.class)); + assertNull(BridgedObject.getBridge(object0)); + assertSame(bridge1, BridgedObject.getBridge(object1)); + assertSame(bridge2, BridgedObject.getBridge(object2)); + } + + private static final class TestBridge implements XBridge { + public Object getInstance(String instanceName) { + return null; + } + + public String getName() { + return null; + } + + public String getDescription() { + return null; + } + } +} + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/ridljar/test/com/sun/star/lib/uno/bridges/java_remote/ProxyFactory_Test.java b/ridljar/test/com/sun/star/lib/uno/bridges/java_remote/ProxyFactory_Test.java new file mode 100644 index 000000000..45fc02f89 --- /dev/null +++ b/ridljar/test/com/sun/star/lib/uno/bridges/java_remote/ProxyFactory_Test.java @@ -0,0 +1,131 @@ +/* -*- 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.IQueryInterface; +import com.sun.star.uno.MappingException; +import com.sun.star.uno.Type; +import com.sun.star.uno.UnoRuntime; +import com.sun.star.uno.XInterface; +import com.sun.star.uno.XNamingService; +import java.lang.reflect.InvocationTargetException; +import java.lang.reflect.Method; +import java.lang.reflect.UndeclaredThrowableException; +import org.junit.Test; +import static org.junit.Assert.*; + +public final class ProxyFactory_Test { + @Test public void testQueryInterface() { + TestRequestHandler handler = new TestRequestHandler(); + Type type = new Type(XNamingService.class); + Object proxy = new ProxyFactory(handler, null).create("TestOID", type); + assertSame(proxy, ((IQueryInterface) proxy).queryInterface(type)); + assertSame(proxy, UnoRuntime.queryInterface(type, proxy)); + } + + @Test public void testExceptionHandling() throws Exception { + TestRequestHandler handler = new TestRequestHandler(); + Object proxy = new ProxyFactory(handler, null).create( + "TestOID", new Type(XNamingService.class)); + testExceptions( + handler, + proxy.getClass().getMethod("queryInterface", + new Class[] { Type.class }), + proxy, new Object[] { new Type(XInterface.class) }, + new Class[] { null, MappingException.class, + com.sun.star.uno.RuntimeException.class, + UndeclaredThrowableException.class, + NullPointerException.class, + UndeclaredThrowableException.class }); + testExceptions( + handler, + proxy.getClass().getMethod("getRegisteredObject", + new Class[] { String.class }), + proxy, new Object[] { "TestName" }, + new Class[] { null, MappingException.class, + com.sun.star.uno.RuntimeException.class, + com.sun.star.uno.Exception.class, + NullPointerException.class, Exception.class }); + } + + private void testExceptions(TestRequestHandler handler, Method method, + Object obj, Object[] args, Class[] exceptions) + throws Exception + { + for (int i = 0; i < exceptions.length; ++i) { + handler.setModus(i); + testExceptionType(method, obj, args, exceptions[i]); + } + } + + private void testExceptionType(Method method, Object obj, Object[] args, + Class exception) throws Exception { + try { + method.invoke(obj, args); + assertNull(exception); + } catch (InvocationTargetException e) { + assertNotNull(exception); + assertTrue(exception.isInstance(e.getTargetException())); + // TODO check stack trace + } + } + + private static final class TestRequestHandler implements RequestHandler { + public Object sendRequest(String oid, Type type, String operation, + Object[] args) + throws Throwable + { + if (operation.equals("release")) { + return null; + } + int m; + synchronized (lock) { + m = modus; + } + switch (m) { + case 0: + return operation.equals("getInstance") ? "TestResult" : null; + case 1: + // TODO What is this test, with an obviously obsoleted + // MappingException, good for? + throw new MappingException(); + case 2: + throw new com.sun.star.uno.RuntimeException(); + case 3: + throw new com.sun.star.uno.Exception(); + case 4: + throw new NullPointerException(); + default: + throw new Throwable(); + } + } + + public void setModus(int modus) { + synchronized (lock) { + this.modus = modus; + } + } + + private final Object lock = new Object(); + private int modus = 0; + } +} + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/ridljar/test/com/sun/star/lib/uno/bridges/java_remote/java_remote_bridge_Test.java b/ridljar/test/com/sun/star/lib/uno/bridges/java_remote/java_remote_bridge_Test.java new file mode 100644 index 000000000..53e150527 --- /dev/null +++ b/ridljar/test/com/sun/star/lib/uno/bridges/java_remote/java_remote_bridge_Test.java @@ -0,0 +1,239 @@ +/* -*- 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.bridge.XInstanceProvider; +import com.sun.star.comp.connections.PipedConnection; +import com.sun.star.connection.XConnection; +import com.sun.star.container.NoSuchElementException; +import com.sun.star.lib.uno.environments.java.java_environment; +import com.sun.star.lib.uno.typeinfo.MethodTypeInfo; +import com.sun.star.lib.uno.typeinfo.TypeInfo; +import com.sun.star.uno.IQueryInterface; +import com.sun.star.uno.Type; +import com.sun.star.uno.UnoRuntime; +import com.sun.star.uno.XInterface; +import org.junit.Test; +import util.WaitUnreachable; +import static org.junit.Assert.*; + +public final class java_remote_bridge_Test { + @Test public void test() throws Exception { + String protocol = "urp"; + + XConnection connectionA = new PipedConnection(new Object[0]); + XConnection connectionB = new PipedConnection( + new Object[] { connectionA }); + java_remote_bridge bridgeA = new java_remote_bridge( + new java_environment(null), null, + new Object[] { protocol, connectionA, new TestInstanceProvider() }); + java_remote_bridge bridgeB = new java_remote_bridge( + new java_environment(null), null, + new Object[] { protocol, connectionB, null }); + + testGetInstance(bridgeA, bridgeB); + testLifeCycle(bridgeA, bridgeB); + } + + private void testGetInstance(XBridge bridgeA, XBridge bridgeB) { + assertNull(bridgeB.getInstance(TestInstanceProvider.NAME_NULL)); + + try { + bridgeB.getInstance(TestInstanceProvider.NAME_RUNTIME_EXCEPTION); + fail("throw RuntimeException"); + } catch (com.sun.star.uno.RuntimeException e) { + assertTrue( + e.getMessage().indexOf( + TestInstanceProvider.NAME_RUNTIME_EXCEPTION) + != -1); + } + + try { + bridgeB.getInstance( + TestInstanceProvider.NAME_NO_SUCH_ELEMENT_EXCEPTION); + fail("throw NoSuchElementException"); + } catch (com.sun.star.uno.RuntimeException e) { + assertTrue( + e.getMessage().indexOf( + TestInstanceProvider.NAME_NO_SUCH_ELEMENT_EXCEPTION) + != -1); + } + + try { + bridgeA.getInstance(TestInstanceProvider.NAME_ANYTHING); + fail("no instance provider"); + } catch (com.sun.star.uno.RuntimeException e) { + assertTrue(e.getMessage().startsWith("unknown OID ")); + } + } + + private void testLifeCycle(java_remote_bridge bridgeA, + java_remote_bridge bridgeB) + throws InterruptedException + { + // Repeatedly, objects are mapped from bridgeA to bridgeB, where proxies + // for those objects (for the XInterface and TestInterface facets) are + // created. The proxies at bridgeB keep both bridges alive; after those + // proxies have been garbage-collected, both bridges should be disposed. + // It does not work to map a local object from bridgeA to bridgeB, as + // bridgeB would find this object as a local one, too (via the shared, + // static localObjects Registry in java_environment): bridgeB would not + // create a proxy, would rather send back a "release" to bridgeA, and + // both bridges would be disposed while the first object is being + // mapped. Therefore, a HACK is used to install TestProxy objects + // (which behave as if they got mapped in to bridgeA from somewhere + // else) at bridgeA and map those. + + final int COUNT = 100; + XInterface[] proxyBXInterface = new XInterface[COUNT]; + TestInterface[] proxyBTestInterface = new TestInterface[COUNT]; + for (int i = 0; i < COUNT; ++i) { + String name = "TestOID" + i; + Object proxyA = new TestProxy(name); + bridgeA.getSourceEnvironment().registerInterface( + proxyA, new String[] { name }, new Type(XInterface.class)); + + proxyBXInterface[i] = (XInterface) bridgeB.getInstance(name); + + // map object: + proxyBTestInterface[i] = UnoRuntime.queryInterface( + TestInterface.class, proxyBXInterface[i]); + proxyBTestInterface[i].function(); + + // remap object once: + TestInterface remapped = UnoRuntime.queryInterface( + TestInterface.class, proxyBXInterface[i]); + remapped.function(); + + // remap object twice: + remapped = UnoRuntime.queryInterface( + TestInterface.class, proxyBXInterface[i]); + remapped.function(); + } + + assertEquals(3 * COUNT, TestProxy.getCount()); + + // The following checks rely on the implementation detail that mapping + // different facets of a UNO object (XInterface and TestInterface) leads + // to different proxies: + + assertEquals("bridge A life count", 2 * COUNT, bridgeA.getLifeCount()); + assertEquals("bridge B life count", 2 * COUNT, bridgeB.getLifeCount()); +/*TODO: below test fails with "expected:<200> but was:<204>": + assertEquals("proxy count", 2 * COUNT, ProxyFactory.getDebugCount()); +*/ + + System.out.println("waiting for proxies to become unreachable:"); + for (int i = 0; i < COUNT; ++i) { + WaitUnreachable u1 = new WaitUnreachable(proxyBXInterface[i]); + WaitUnreachable u2 = new WaitUnreachable(proxyBTestInterface[i]); + proxyBXInterface[i] = null; + proxyBTestInterface[i] = null; + u1.waitUnreachable(); + u2.waitUnreachable(); + } + // For whatever strange reason, this sleep seems to be necessary to + // reliably ensure that even the last proxy's finalization is over + // before the following assert is executed: + Thread.sleep(1000); + + assertEquals("proxy count", 0, ProxyFactory.getDebugCount()); + + System.out.println("waiting for pending messages to be done"); + while (bridgeA.getLifeCount() != 0 || bridgeB.getLifeCount() != 0) { + Thread.sleep(100); + } + + assertEquals("Zero bridge A life count", 0, bridgeA.getLifeCount()); + assertEquals("Zero bridge B life count", 0, bridgeB.getLifeCount()); + assertEquals("Zero proxy count", 0, ProxyFactory.getDebugCount()); + } + + public interface TestInterface extends XInterface { + void function(); + + TypeInfo[] UNOTYPEINFO = new TypeInfo[] { + new MethodTypeInfo("function", 0, 0) }; + } + + private static final class TestInstanceProvider + implements XInstanceProvider + { + public Object getInstance(String name) throws NoSuchElementException { + if (name.equals(NAME_NULL)) { + return null; + } else if (name.equals(NAME_RUNTIME_EXCEPTION)) { + throw new com.sun.star.uno.RuntimeException( + getClass().getName() + ", throwing: " + name); + } else if (name.equals(NAME_NO_SUCH_ELEMENT_EXCEPTION)) { + throw new NoSuchElementException( + getClass().getName() + ", throwing: " + name); + } else { + throw new IllegalStateException(); + } + } + + public static final String NAME_NULL = "return null"; + public static final String NAME_RUNTIME_EXCEPTION + = "throw RuntimeException"; + public static final String NAME_NO_SUCH_ELEMENT_EXCEPTION + = "throw NoSuchElementException"; + public static final String NAME_ANYTHING = "anything"; + } + + private static final class TestProxy + implements com.sun.star.lib.uno.Proxy, IQueryInterface, + TestInterface + { + public TestProxy(String oid) { + this.oid = oid; + } + + public Object queryInterface(Type type) { + // type should be either XInterface or TestInterface... + return this; + } + + public boolean isSame(Object object) { + return object instanceof TestProxy + && oid.equals(((TestProxy) object).oid); + } + + public String getOid() { + return oid; + } + + public void function() { + synchronized (getClass()) { + ++count; + } + } + + public static synchronized int getCount() { + return count; + } + + private final String oid; + + private static int count = 0; + } +} + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/ridljar/test/com/sun/star/lib/uno/environments/java/java_environment_Test.java b/ridljar/test/com/sun/star/lib/uno/environments/java/java_environment_Test.java new file mode 100644 index 000000000..9381e2af4 --- /dev/null +++ b/ridljar/test/com/sun/star/lib/uno/environments/java/java_environment_Test.java @@ -0,0 +1,55 @@ +/* -*- 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.Type; +import com.sun.star.uno.XInterface; +import org.junit.Test; +import static org.junit.Assert.*; + +public final class java_environment_Test { + @Test public void test() { + java_environment env = new java_environment(null); + + Object obj = Integer.valueOf(3); + String[] oid = new String[1]; + + Object obj2 = env.registerInterface(obj, oid, + new Type(XInterface.class)); + Object obj3 = env.registerInterface(obj, oid, + new Type(XInterface.class)); + // Register ordinary interface twice: + assertSame(obj, obj2); + assertSame(obj, obj3); + + // Ask for registered interface: + assertSame( + obj, + env.getRegisteredInterface(oid[0], new Type(XInterface.class))); + + env.revokeInterface(oid[0], new Type(XInterface.class)); + env.revokeInterface(oid[0], new Type(XInterface.class)); + // Revoke interface: + assertNull( + env.getRegisteredInterface(oid[0], new Type(XInterface.class))); + } +} + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/ridljar/test/com/sun/star/lib/uno/environments/remote/JavaThreadPoolFactory_Test.java b/ridljar/test/com/sun/star/lib/uno/environments/remote/JavaThreadPoolFactory_Test.java new file mode 100644 index 000000000..2d2264f06 --- /dev/null +++ b/ridljar/test/com/sun/star/lib/uno/environments/remote/JavaThreadPoolFactory_Test.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.environments.remote; + +import org.junit.Test; +import static org.junit.Assert.*; + +public final class JavaThreadPoolFactory_Test { + @Test public void test() throws InterruptedException { + ThreadId i1 = JavaThreadPoolFactory.getThreadId(); + assertEquals(i1, JavaThreadPoolFactory.getThreadId()); + final ThreadId[] i2 = new ThreadId[1]; + new Thread() { + @Override + public void run() { + synchronized (i2) { + i2[0] = JavaThreadPoolFactory.getThreadId(); + i2.notify(); + } + } + }.start(); + synchronized (i2) { + while (i2[0] == null) { + i2.wait(); + } + } + assertFalse(i1.equals(i2[0])); + } +} + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/ridljar/test/com/sun/star/lib/uno/environments/remote/JobQueue_Test.java b/ridljar/test/com/sun/star/lib/uno/environments/remote/JobQueue_Test.java new file mode 100644 index 000000000..a63c9c7ed --- /dev/null +++ b/ridljar/test/com/sun/star/lib/uno/environments/remote/JobQueue_Test.java @@ -0,0 +1,263 @@ +/* -*- 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 org.junit.Test; +import static org.junit.Assert.*; + +public final class JobQueue_Test { + @Test public void testThreadLeavesJobQueueOnDispose0() + throws InterruptedException + { + testThreadLeavesJobQueueOnDispose(0); + } + + @Test public void testThreadLeavesJobQueueOnDispose5000() + throws InterruptedException + { + testThreadLeavesJobQueueOnDispose(5000); + } + + private void testThreadLeavesJobQueueOnDispose(int waitTime) + throws InterruptedException + { + TestThread t = new TestThread(waitTime); + t.waitToStart(); + String msg = "xcxxxxxxxx"; + t._jobQueue.dispose(t._disposeId, new RuntimeException (msg)); + t.waitToTerminate(); +/*TODO: below test fails with "expected: but was:": + assertEquals(msg, t._message); +*/ + } + + @Test public void testThreadLeavesJobQueueOnReply0() + throws InterruptedException + { + testThreadLeavesJobQueueOnReply(0); + } + + @Test public void testThreadLeavesJobQueueOnReply5000() + throws InterruptedException + { + testThreadLeavesJobQueueOnReply(5000); + } + + private void testThreadLeavesJobQueueOnReply(int waitTime) + throws InterruptedException + { + TestThread t = new TestThread(waitTime); + t.waitToStart(); + // put reply job: + t._jobQueue.putJob( + new Job(null, __iReceiver, + new Message( + null, false, "oid", __workAt_td, null, false, null, + false, null, null)), + null); + t.waitToTerminate(); + assertTrue(true); // TODO! ??? + } + + @Test public void testStaticThreadExecutesJobs0() + throws InterruptedException + { + testStaticThreadExecutesJobs(0); + } + + @Test public void testStaticThreadExecutesJobs5000() + throws InterruptedException + { + testStaticThreadExecutesJobs(5000); + } + + private void testStaticThreadExecutesJobs(int waitTime) + throws InterruptedException + { + TestThread t = new TestThread(waitTime); + t.waitToStart(); + testExecuteJobs(t._jobQueue); + t._jobQueue.dispose(t._disposeId, + new RuntimeException("xxxxxxxxxxxxx")); + t.waitToTerminate(); + } + + @Test public void testDynamicThreadExecutesJob() throws InterruptedException + { + testExecuteJobs( + new JobQueue( + __javaThreadPoolFactory, ThreadId.createFresh(), true)); + } + + @Test public void testStaticThreadExecutesAsyncs() + throws InterruptedException + { + TestThread t = new TestThread(); + JobQueue async_jobQueue = new JobQueue(__javaThreadPoolFactory, + t._threadId); + assertEquals(1, async_jobQueue._ref_count); + t._jobQueue = __javaThreadPoolFactory.getJobQueue(t._threadId); + assertEquals(1, t._jobQueue._ref_count); + t.waitToStart(); + TestWorkAt workAt = new TestWorkAt(); + testAsyncJobQueue(workAt, async_jobQueue, t._threadId); + t._jobQueue.dispose(t._disposeId, + new RuntimeException("xxxxxxxxxxxxx")); + t.waitToTerminate(); + assertEquals(TestWorkAt.MESSAGES, workAt._async_counter); + assertEquals(TestWorkAt.MESSAGES, workAt._sync_counter); + } + + @Test public void testDynamicThreadExecutesAsyncs() + throws InterruptedException + { + ThreadId threadId = ThreadId.createFresh(); + JobQueue async_jobQueue = new JobQueue(__javaThreadPoolFactory, + threadId); + TestWorkAt workAt = new TestWorkAt(); + testAsyncJobQueue(workAt, async_jobQueue, threadId); + assertEquals(TestWorkAt.MESSAGES, workAt._async_counter); + assertEquals(TestWorkAt.MESSAGES, workAt._sync_counter); + } + + private void testExecuteJobs(JobQueue jobQueue) throws InterruptedException + { + TestWorkAt workAt = new TestWorkAt(); + testSendRequests(workAt, "increment", jobQueue); + synchronized (workAt) { + jobQueue.putJob(new Job(workAt, __iReceiver, + new Message( + null, true, "oid", __workAt_td, + __workAt_td.getMethodDescription( + "notifyme"), + true, null, false, null, null)), + null); + while (!workAt._notified) { + workAt.wait(); + } + } + assertEquals(TestWorkAt.MESSAGES, workAt._counter); + } + + private void testAsyncJobQueue(TestWorkAt workAt, JobQueue async_jobQueue, + ThreadId threadId) + throws InterruptedException + { + // put slow async calls first, followed by fast sync calls: + testSendRequests(workAt, "asyncCall", async_jobQueue); + testSendRequests(workAt, "syncCall", + __javaThreadPoolFactory.getJobQueue(threadId)); + synchronized (workAt) { + async_jobQueue._sync_jobQueue.putJob( + new Job(workAt, __iReceiver, + new Message( + null, true, "oid", __workAt_td, + __workAt_td.getMethodDescription("notifyme"), + true, null, false, null, null)), + null); + while (!workAt._notified) { + workAt.wait(); + } + } + assertTrue(workAt.passedAsyncTest()); + } + + private void testSendRequests(TestWorkAt workAt, String operation, + JobQueue jobQueue) { + Message iMessage = new Message( + null, true, "oid", __workAt_td, + __workAt_td.getMethodDescription(operation), + true, null, false, null, null); + for (int i = 0; i < TestWorkAt.MESSAGES; ++ i) { + Thread.yield(); // force scheduling + jobQueue.putJob(new Job(workAt, __iReceiver, iMessage), + new Object()); + } + } + + private static final class TestThread extends Thread { + public final ThreadId _threadId = JavaThreadPoolFactory.getThreadId(); + public final Object _disposeId = new Object(); + public JobQueue _jobQueue = null; + + public TestThread(int waitTime) { + this.waitTime = waitTime; + _jobQueue = new JobQueue(__javaThreadPoolFactory, _threadId, false); + } + + public TestThread() { + waitTime = 0; + } + + @Override + public void run() { + synchronized (lock) { + state = STATE_STARTED; + lock.notifyAll(); + } + try { + if (waitTime != 0) { + Thread.sleep(waitTime); + } + _jobQueue.enter(_disposeId); + } catch (Throwable e) { + } + synchronized (lock) { + state = STATE_DONE; + lock.notifyAll(); + } + } + + public void waitToStart() throws InterruptedException { + start(); + synchronized (lock) { + while (state == STATE_INITIAL) { + lock.wait(); + } + } + } + + public void waitToTerminate() throws InterruptedException { + synchronized (lock) { + while (state != STATE_DONE) { + lock.wait(); + } + } + join(); + } + + private final int waitTime; + + private final Object lock = new Object(); + private int state = STATE_INITIAL; + private static final int STATE_INITIAL = 0; + private static final int STATE_STARTED = 1; + private static final int STATE_DONE = 2; + } + + private static final JavaThreadPoolFactory __javaThreadPoolFactory + = new JavaThreadPoolFactory(); + private static final IReceiver __iReceiver = new TestReceiver(); + private static final TypeDescription __workAt_td + = TypeDescription.getTypeDescription(TestIWorkAt.class); +} + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/ridljar/test/com/sun/star/lib/uno/environments/remote/TestIWorkAt.java b/ridljar/test/com/sun/star/lib/uno/environments/remote/TestIWorkAt.java new file mode 100644 index 000000000..7bb71a80e --- /dev/null +++ b/ridljar/test/com/sun/star/lib/uno/environments/remote/TestIWorkAt.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.environments.remote; + + +import com.sun.star.lib.uno.typeinfo.MethodTypeInfo; +import com.sun.star.lib.uno.typeinfo.TypeInfo; +import com.sun.star.uno.XInterface; + +public interface TestIWorkAt extends XInterface { + void syncCall() throws Throwable ; + void asyncCall() throws Throwable ; + + void increment() throws Throwable; + + void notifyme(); + + TypeInfo UNOTYPEINFO[] = { + new MethodTypeInfo("increment", 0, 0), + new MethodTypeInfo("notifyme", 1, 0), + new MethodTypeInfo("syncCall", 2, 0), + new MethodTypeInfo("asyncCall", 3, 0) + }; +} + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/ridljar/test/com/sun/star/lib/uno/environments/remote/TestReceiver.java b/ridljar/test/com/sun/star/lib/uno/environments/remote/TestReceiver.java new file mode 100644 index 000000000..6c8f36885 --- /dev/null +++ b/ridljar/test/com/sun/star/lib/uno/environments/remote/TestReceiver.java @@ -0,0 +1,27 @@ +/* -*- 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 TestReceiver implements IReceiver { + public void sendReply(boolean exception, ThreadId threadId, Object result) { + } +} + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/ridljar/test/com/sun/star/lib/uno/environments/remote/TestWorkAt.java b/ridljar/test/com/sun/star/lib/uno/environments/remote/TestWorkAt.java new file mode 100644 index 000000000..93297815c --- /dev/null +++ b/ridljar/test/com/sun/star/lib/uno/environments/remote/TestWorkAt.java @@ -0,0 +1,81 @@ +/* -*- 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 static org.junit.Assert.*; + +class TestWorkAt implements TestIWorkAt { + /** + * When set to true, enables various debugging output. + */ + private static final boolean DEBUG = false; + + static final int MESSAGES = 35; + + + int _counter; + + int _sync_counter; + int _async_counter; + + private boolean _passedAsync = true; + boolean _notified = false; + + public synchronized void syncCall() throws Throwable { + ++ _sync_counter; + + // at least in currently run tests this should never fire, so don't + // defer the check until passedAsyncTest and assert here + assertEquals(MESSAGES, _async_counter); + if(_async_counter != MESSAGES) + _passedAsync = false; + + if(DEBUG) System.err.println("syncCall:" + _sync_counter + " " + _passedAsync + " " + Thread.currentThread()); + } + + public synchronized void asyncCall() throws Throwable { + ++ _async_counter; + + if(DEBUG) System.err.println("asyncCall:" + _async_counter + " " + Thread.currentThread()); + } + + public synchronized void increment() throws Throwable { + if(DEBUG) System.err.println("increment - " + Thread.currentThread()); + + ++ _counter; + notifyAll(); + } + + public synchronized void notifyme() { + if(DEBUG) System.err.println("\t\t\tnotifying me" + Thread.currentThread()); + + notifyAll(); + + _notified = true; + } + + public synchronized boolean passedAsyncTest() { + assertEquals(MESSAGES, _sync_counter); + assertTrue(_passedAsync); + return _passedAsync && (_sync_counter == MESSAGES); + } +} + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/ridljar/test/com/sun/star/lib/uno/environments/remote/ThreadId_Test.java b/ridljar/test/com/sun/star/lib/uno/environments/remote/ThreadId_Test.java new file mode 100644 index 000000000..8ee7f4a4c --- /dev/null +++ b/ridljar/test/com/sun/star/lib/uno/environments/remote/ThreadId_Test.java @@ -0,0 +1,57 @@ +/* -*- 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.Arrays; +import org.junit.Test; +import static org.junit.Assert.*; + +public final class ThreadId_Test { + @Test public void test() { + ThreadId i1 = ThreadId.createFresh(); + assertTrue(i1.equals(i1)); + assertFalse(i1.equals(null)); + assertFalse(i1.equals(new Object())); + assertEquals(i1.hashCode(), i1.hashCode()); + byte[] i1bytes = i1.getBytes(); + assertNotNull(i1bytes); + assertTrue(i1bytes.length >= 5); + assertEquals('j', i1bytes[0]); + assertEquals('a', i1bytes[1]); + assertEquals('v', i1bytes[2]); + assertEquals('a', i1bytes[3]); + assertEquals(':', i1bytes[4]); + assertArrayEquals(i1bytes, i1.getBytes()); + + ThreadId i2 = ThreadId.createFresh(); + assertFalse(i1.equals(i2)); + assertFalse(i2.equals(i1)); + assertFalse(Arrays.equals(i1bytes, i2.getBytes())); + + ThreadId i3 = new ThreadId(i1bytes); + assertTrue(i3.equals(i1)); + assertFalse(i3.equals(i2)); + assertTrue(i1.equals(i3)); + assertEquals(i1.hashCode(), i3.hashCode()); + assertArrayEquals(i1bytes, i3.getBytes()); + } +} + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/ridljar/test/com/sun/star/lib/uno/environments/remote/ThreadPool_Test.java b/ridljar/test/com/sun/star/lib/uno/environments/remote/ThreadPool_Test.java new file mode 100644 index 000000000..7da68db23 --- /dev/null +++ b/ridljar/test/com/sun/star/lib/uno/environments/remote/ThreadPool_Test.java @@ -0,0 +1,437 @@ +/* -*- 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 org.junit.Test; +import static org.junit.Assert.*; + +public class ThreadPool_Test { + @Test public void testDispose() throws InterruptedException { + IThreadPool iThreadPool = ThreadPoolManager.create(); + TestThread testThread = new TestThread(iThreadPool); + + ThreadId threadId = null; + + // start the test thread + synchronized(testThread) { + testThread.start(); + + testThread.wait(); + + threadId = testThread._threadId; + + // let the thread attach and enter the threadpool + testThread.notifyAll(); + } + + String message = "blabla"; + + // terminate the test thread + synchronized(testThread) { + // put reply job + iThreadPool.dispose(new RuntimeException(message)); + + testThread.wait(); + } + + testThread.join(); + +/*TODO: below test fails with "expected: but was:": + assertEquals(message, testThread._message); +*/ + } + + @Test public void testThreadAsync() throws InterruptedException { + TestWorkAt workAt = new TestWorkAt(); + + ThreadId threadId = ThreadId.createFresh(); + + // queue asyncs + for(int i = 0; i < TestWorkAt.MESSAGES; ++ i) { + Thread.yield(); // force scheduling + putJob(workAt, false, threadId, "increment"); + } + + synchronized(workAt) { + putJob(workAt, false, threadId, "notifyme"); + + while(!workAt._notified) { + workAt.wait(); + } + } + + assertEquals(TestWorkAt.MESSAGES, workAt._counter); + } + + @Test public void testDynamicThreadSync() throws InterruptedException { + TestWorkAt workAt = new TestWorkAt(); + + ThreadId threadId = ThreadId.createFresh(); + + // queue asyncs + for(int i = 0; i < TestWorkAt.MESSAGES; ++ i) { + Thread.yield(); // force scheduling + putJob(workAt, true, threadId, "increment"); + } + + synchronized(workAt) { + putJob(workAt, true, threadId, "notifyme"); + + while(!workAt._notified) { + workAt.wait(); + } + } + + assertEquals(TestWorkAt.MESSAGES, workAt._counter); + } + + @Test public void testStaticThreadSync() throws InterruptedException { + TestWorkAt workAt = new TestWorkAt(); + + TestThread testThread = new TestThread(); + + ThreadId threadId = null; + + // start the test thread + synchronized(testThread) { + testThread.start(); + + testThread.wait(); + + threadId = testThread._threadId; + + // let the thread attach and enter the threadpool + testThread.notifyAll(); + } + + // queue syncs + for(int i = 0; i < TestWorkAt.MESSAGES; ++ i) { + Thread.yield(); // force scheduling + putJob(workAt, true, threadId, "increment"); + } + + // terminate the test thread + synchronized(testThread) { + // put reply job + putJob(workAt, true, threadId, null); + + testThread.wait(); + } + + testThread.join(); + + assertEquals(TestWorkAt.MESSAGES, workAt._counter); + } + + @Test public void testDynamicThreadAsyncSyncOrder() + throws InterruptedException + { + TestWorkAt workAt = new TestWorkAt(); + + ThreadId threadId = ThreadId.createFresh(); + + // queue asyncs + for(int i = 0; i < TestWorkAt.MESSAGES; ++ i) { + Thread.yield(); // force scheduling + putJob(workAt, false, threadId, "asyncCall"); + } + + // queue syncs + for(int i = 0; i < TestWorkAt.MESSAGES; ++ i) { + Thread.yield(); // force scheduling + putJob(workAt, true, threadId, "syncCall"); + } + + synchronized(workAt) { + putJob(workAt, true, threadId, "notifyme"); + + while(!workAt._notified) { + workAt.wait(); + } + } + + assertTrue(workAt.passedAsyncTest()); + } + + @Test public void testStaticThreadAsyncSyncOrder() + throws InterruptedException + { + TestWorkAt workAt = new TestWorkAt(); + + TestThread testThread = new TestThread(); + + // start the test thread + synchronized(testThread) { + testThread.start(); + + testThread.wait(); + } + + ThreadId threadId = testThread._threadId; + + // queue asyncs + for(int i = 0; i < TestWorkAt.MESSAGES; ++ i) { + Thread.yield(); // force scheduling + putJob(workAt, false, threadId, "asyncCall"); + } + + // let the thread attach and enter the threadpool + synchronized(testThread) { + testThread.notifyAll(); + } + + // queue syncs + for(int i = 0; i < TestWorkAt.MESSAGES; ++ i) { + Thread.yield(); // force scheduling + putJob(workAt, true, threadId, "syncCall"); + } + + // terminate the test thread + synchronized(testThread) { + // put reply job + putJob(workAt, true, threadId, null); + + testThread.wait(); + } + + testThread.join(); + + assertTrue(workAt.passedAsyncTest()); + } + + @Test public void testStress() throws InterruptedException { + TestWorkAt workAt = new TestWorkAt(); + for (int i = 0; i < TestWorkAt.MESSAGES; ++i) { + Thread.yield(); // force scheduling + ThreadId threadID = ThreadId.createFresh(); + putJob(workAt, true, threadID, "increment"); + putJob(workAt, false, threadID, "increment"); + } + synchronized (workAt) { + while (workAt._counter < 2 * TestWorkAt.MESSAGES) { + workAt.wait(); + } + } + + abstract class Stress extends Thread { + private Stress(int count) { + this.count = count; + } + + @Override + public void run() { + try { + for (int i = 0; i < count; ++i) { + runTest(); + } + } catch (Throwable e) { + e.printStackTrace(System.err); + } + } + + protected abstract void runTest() throws InterruptedException; + + private final int count; + } + + Stress stress1 = new Stress(50) { + @Override + protected void runTest() throws InterruptedException { + testThreadAsync(); + } + }; + stress1.start(); + + Stress stress2 = new Stress(50) { + @Override + protected void runTest() throws InterruptedException { + testDynamicThreadSync(); + } + }; + stress2.start(); + + Stress stress3 = new Stress(50) { + @Override + protected void runTest() throws InterruptedException { + testStaticThreadSync(); + } + }; + stress3.start(); + + Stress stress4 = new Stress(50) { + @Override + protected void runTest() throws InterruptedException { + testDynamicThreadAsyncSyncOrder(); + } + }; + stress4.start(); + + Stress stress5 = new Stress(50) { + @Override + protected void runTest() throws InterruptedException { + testStaticThreadAsyncSyncOrder(); + } + }; + stress5.start(); + + Stress stress6 = new Stress(500) { + @Override + protected void runTest() throws InterruptedException { + testDispose(); + } + }; + stress6.start(); + + stress1.join(); + stress2.join(); + stress3.join(); + stress4.join(); + stress5.join(); + stress6.join(); + } + + @Test public void testAsyncSync() throws InterruptedException { + TestWorkAt workAt = new TestWorkAt(); + ThreadId threadId = ThreadId.createFresh(); + MyWorkAt myWorkAt = new MyWorkAt( workAt ); + + // queue asyncs + for(int i = 0; i < TestWorkAt.MESSAGES; ++ i) { + if( i == 2 ) + { + putJob( myWorkAt, false , threadId, "asyncCall" ); + } + putJob(workAt, false, threadId, "asyncCall"); + } + + synchronized(workAt) { + putJob(workAt, false, threadId, "notifyme"); + + while(!workAt._notified) { + workAt.wait(); + } + } + + assertEquals(TestWorkAt.MESSAGES, workAt._async_counter); + assertTrue(myWorkAt._success); + } + + private static void putJob(TestIWorkAt iWorkAt, boolean synchron, + ThreadId threadId, String operation) { + __iThreadPool.putJob( + new Job(iWorkAt, __iReceiver, + new Message( + threadId, operation != null, "oid", __workAt_td, + (operation == null + ? null + : ((MethodDescription) + __workAt_td.getMethodDescription(operation))), + synchron, null, false, null, null))); + } + + private static final class TestThread extends Thread { + ThreadId _threadId; + IThreadPool _iThreadPool; + + TestThread() { + this(__iThreadPool); + } + + TestThread(IThreadPool iThreadPool) { + _iThreadPool = iThreadPool; + } + + @Override + public void run() { + _threadId = _iThreadPool.getThreadId(); + + + try { + synchronized(this) { + // notify that we are running + notify(); + + _iThreadPool.attach(); + + // wait until we should continue + wait(); + } + + _iThreadPool.enter(); + } + catch(Throwable throwable) { + } + + _iThreadPool.detach(); + + synchronized(this) { + // notify the listeners that we are dying + notifyAll(); + } + } + } + + private static final class MyWorkAt implements TestIWorkAt { + public MyWorkAt( TestWorkAt async_WorkAt ) { + _async_WorkAt = async_WorkAt; + } + + public void syncCall() throws Throwable + { + Message iMessage = new Message( + __iThreadPool.getThreadId(), false, "oid", __workAt_td, null, + false, null, false, null, null); + + // marshal reply + ThreadPool_Test.__iThreadPool.putJob( + new Job(this, ThreadPool_Test. __iReceiver, iMessage)); + } + + public void asyncCall() throws Throwable { + for (int i = 0 ; i < 5 ; ++i) { + ThreadPool_Test.__iThreadPool.attach(); + ThreadPool_Test.putJob(this, true, __iThreadPool.getThreadId(), + "syncCall"); + // wait for reply + ThreadPool_Test.__iThreadPool.enter(); + ThreadPool_Test.__iThreadPool.detach(); + } + // async must have waited for this call + _success = _async_WorkAt._async_counter == 2; + } + + public void increment() throws Throwable {} + + public void notifyme() {} + + public boolean _success = false; + + private final TestWorkAt _async_WorkAt; + } + + private static final IThreadPool __iThreadPool = ThreadPoolManager.create(); + private static final IReceiver __iReceiver = new TestReceiver(); + private static final TypeDescription __workAt_td + = TypeDescription.getTypeDescription(TestIWorkAt.class); +} + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/ridljar/test/com/sun/star/lib/uno/protocols/urp/Cache_Test.java b/ridljar/test/com/sun/star/lib/uno/protocols/urp/Cache_Test.java new file mode 100644 index 000000000..a7d93733d --- /dev/null +++ b/ridljar/test/com/sun/star/lib/uno/protocols/urp/Cache_Test.java @@ -0,0 +1,134 @@ +/* -*- 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 org.junit.Test; +import static org.junit.Assert.*; + +public final class Cache_Test { + @Test public void test0() { + Cache c = new Cache(0); + boolean[] f = new boolean[1]; + int i; + i = c.add(f, "a"); + assertTrue(i == Cache.NOT_CACHED && !f[0]); + i = c.add(f, "a"); + assertTrue(i == Cache.NOT_CACHED && !f[0]); + i = c.add(f, "b"); + assertTrue(i == Cache.NOT_CACHED && !f[0]); + i = c.add(f, "a"); + assertTrue(i == Cache.NOT_CACHED && !f[0]); + } + + @Test public void test1() { + Cache c = new Cache(1); + boolean[] f = new boolean[1]; + int i; + i = c.add(f, "a"); + assertTrue(i == 0 && !f[0]); + i = c.add(f, "a"); + assertTrue(i == 0 && f[0]); + i = c.add(f, "b"); + assertTrue(i == 0 && !f[0]); + i = c.add(f, "b"); + assertTrue(i == 0 && f[0]); + i = c.add(f, "a"); + assertTrue(i == 0 && !f[0]); + } + + @Test public void test2() { + Cache c = new Cache(2); + boolean[] f = new boolean[1]; + int i; + i = c.add(f, "a"); + assertTrue(i == 0 && !f[0]); + i = c.add(f, "a"); + assertTrue(i == 0 && f[0]); + i = c.add(f, "b"); + assertTrue(i == 1 && !f[0]); + i = c.add(f, "b"); + assertTrue(i == 1 && f[0]); + i = c.add(f, "a"); + assertTrue(i == 0 && f[0]); + i = c.add(f, "c"); + assertTrue(i == 1 && !f[0]); + i = c.add(f, "b"); + assertTrue(i == 0 && !f[0]); + } + + @Test public void test3() { + Cache c = new Cache(3); + boolean[] f = new boolean[1]; + int i; + i = c.add(f, "a"); + assertTrue(i == 0 && !f[0]); + i = c.add(f, "a"); + assertTrue(i == 0 && f[0]); + i = c.add(f, "b"); + assertTrue(i == 1 && !f[0]); + i = c.add(f, "a"); + assertTrue(i == 0 && f[0]); + i = c.add(f, "c"); + assertTrue(i == 2 && !f[0]); + i = c.add(f, "d"); + assertTrue(i == 1 && !f[0]); + i = c.add(f, "d"); + assertTrue(i == 1 && f[0]); + } + + @Test public void testNothingLostFromLruList() { + // Regardless in what order arbitrary values from 0, ..., 3 are inserted + // into a size-4 cache, afterwards adding -1, ..., -4 must return each + // possible index in the range from 0, ..., 3 exactly once (so their sum + // must be 6); this code systematically tests all such arbitrary ways up + // to length 8 (the code arguably violates recommendations for writing + // good tests, but actually helped track down an error in the Cache + // implementation): + int[] a = new int[8]; + for (int i = 0; i < a.length; ++i) { + for (int j = 0; j < i; ++j) { + a[j] = 0; + } + for (;;) { + Cache c = new Cache(4); + for (int k = 0; k < i; ++k) { + c.add(new boolean[1], a[k]); + } + assertEquals( + 6, + (c.add(new boolean[1], -1) + c.add(new boolean[1], -2) + + c.add(new boolean[1], -3) + c.add(new boolean[1], -4))); + int j = i - 1; + while (j >= 0 && a[j] == 3) { + --j; + } + if (j < 0) { + break; + } + ++a[j]; + for (int k = j + 1; k < i; ++k) { + a[k] = 0; + } + } + } + } +} + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/ridljar/test/com/sun/star/lib/uno/protocols/urp/Marshaling_Test.java b/ridljar/test/com/sun/star/lib/uno/protocols/urp/Marshaling_Test.java new file mode 100644 index 000000000..5cf5f73e6 --- /dev/null +++ b/ridljar/test/com/sun/star/lib/uno/protocols/urp/Marshaling_Test.java @@ -0,0 +1,353 @@ +/* -*- 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.typedesc.TypeDescription; +import com.sun.star.uno.Any; +import com.sun.star.uno.Type; +import com.sun.star.uno.TypeClass; +import com.sun.star.uno.XInterface; +import java.lang.reflect.Array; +import java.lang.reflect.Field; +import java.lang.reflect.Modifier; +import org.junit.Test; +import static org.junit.Assert.*; + +public final class Marshaling_Test { + @Test public void test() throws Exception { + short cacheSize = (short)256; + TestBridge testBridge = new TestBridge(); + Marshal marshal = new Marshal(testBridge, cacheSize); + + TestObject testObject = new TestObject(); + + TestPrimitiveSeqStruct x = new TestPrimitiveSeqStruct(); + x.zAny = new Object[]{Integer.valueOf(1), new Double(2) }; + + + Object data[] = new Object[] { + new com.sun.star.uno.RuntimeException("testRuntimeException"), + new com.sun.star.uno.Exception("testException"), + Boolean.TRUE, + Byte.valueOf((byte)47), + new Character('k'), + new Double(0.12345), + TestEnum.B, + new Float(0.5678), + Integer.valueOf(0), + Integer.valueOf(128), + Integer.valueOf(0x0f00), + Integer.valueOf(0x0f0000), + Integer.valueOf(0x0f000000), + Integer.valueOf(-128), + Integer.valueOf(0xff00), + Integer.valueOf(0xff0000), + Integer.valueOf(0xff000000), + Long.valueOf(666L), + Short.valueOf((short)444), + "blabla", + Integer.valueOf(10), // Any as object + Integer.valueOf(10), // Any as object + new Any(new Type(Integer.class), Integer.valueOf(10)), // Any as Any + new Any(new Type(Integer.class), Integer.valueOf(10)), // Any as Any + null, + new TestPrimitiveStruct(), + x, + new byte[]{1,2,3,4,5,6,7}, // primitive sequence + new int[]{7,6,5,4,3,2,1}, // primitive sequence + new Object[]{Integer.valueOf(123), "hallo"}, // any sequence + new TestPrimitiveStruct[]{new TestPrimitiveStruct(), new TestPrimitiveStruct()}, // sequence of primitive structs + new TestPrimitiveSeqStruct[]{new TestPrimitiveSeqStruct(), new TestPrimitiveSeqStruct()}, // sequence of primitive structs + new TestNestedStruct(), + new TestNestedSeqStruct(), + new Type(Void.class), + new Type(String.class), + new Type(Object.class), + new Type(Byte.class), + new Type(Integer.class), + new Type(Double.class), + new Type(Float.class), + new Type(Character.class), + new Type(Short.class), + new Type(Boolean.class), + new Type(void.class), + new Type(byte.class), + new Type(int.class), + new Type(double.class), + new Type(float.class), + new Type(char.class), + new Type(short.class), + new Type(boolean.class), + new Type(Class.forName("[Ljava.lang.String;")), + new Type(Class.forName("[Ljava.lang.Object;")), + new Type(Class.forName("[B")), + new Type(Class.forName("[Z")), + new Type("boolean"), + new Type("byte"), + new Type("char"), + new Type("short"), + new Type("long"), + new Type("hyper"), + new Type("float"), + new Type("double"), + new Type("string"), + new Type("void"), + new Type("any"), + new Type( + "com.sun.star.lib.uno.protocols.urp.TestEnum", TypeClass.ENUM), + new Type("[]boolean", TypeClass.SEQUENCE), + new Type("[][]byte", TypeClass.SEQUENCE), + new Type("[][][]char", TypeClass.SEQUENCE), + new Type("[][][][]short", TypeClass.SEQUENCE), + new Type("[][][][][]any", TypeClass.SEQUENCE), + new Type("com.sun.star.uno.XInterface", TypeClass.INTERFACE), + new Type("[]com.sun.star.uno.XInterface", TypeClass.SEQUENCE), + testObject, + testObject, + new TestInterfaceStruct(testObject, null) + }; + + TypeDescription dataTypes[] = new TypeDescription[] { + TypeDescription.getTypeDescription(com.sun.star.uno.RuntimeException.class), + TypeDescription.getTypeDescription(com.sun.star.uno.Exception.class), + TypeDescription.getTypeDescription(Boolean.class), + TypeDescription.getTypeDescription(Byte.class), + TypeDescription.getTypeDescription(Character.class), + TypeDescription.getTypeDescription(Double.class), + TypeDescription.getTypeDescription(TestEnum.class), + TypeDescription.getTypeDescription(Float.class), + TypeDescription.getTypeDescription(Integer.class), + TypeDescription.getTypeDescription(Integer.class), + TypeDescription.getTypeDescription(Integer.class), + TypeDescription.getTypeDescription(Integer.class), + TypeDescription.getTypeDescription(Integer.class), + TypeDescription.getTypeDescription(Integer.class), + TypeDescription.getTypeDescription(Integer.class), + TypeDescription.getTypeDescription(Integer.class), + TypeDescription.getTypeDescription(Integer.class), + TypeDescription.getTypeDescription(Long.class), + TypeDescription.getTypeDescription(Short.class), + TypeDescription.getTypeDescription(String.class), + TypeDescription.getTypeDescription(Object.class), + TypeDescription.getTypeDescription(Any.class), + TypeDescription.getTypeDescription(Any.class), + TypeDescription.getTypeDescription(Object.class), + TypeDescription.getTypeDescription(XInterface.class), + TypeDescription.getTypeDescription(TestPrimitiveStruct.class), + TypeDescription.getTypeDescription(TestPrimitiveSeqStruct.class), + TypeDescription.getTypeDescription(Class.forName("[B")), + TypeDescription.getTypeDescription(Class.forName("[I")), + TypeDescription.getTypeDescription(Class.forName("[Lcom.sun.star.uno.Any;")), + TypeDescription.getTypeDescription( + Class.forName( + "[Lcom.sun.star.lib.uno.protocols.urp." + + "TestPrimitiveStruct;")), + TypeDescription.getTypeDescription( + Class.forName( + "[Lcom.sun.star.lib.uno.protocols.urp." + + "TestPrimitiveSeqStruct;")), + TypeDescription.getTypeDescription(TestNestedStruct.class), + TypeDescription.getTypeDescription(TestNestedSeqStruct.class), + TypeDescription.getTypeDescription(Type.class), + TypeDescription.getTypeDescription(Type.class), + TypeDescription.getTypeDescription(Type.class), + TypeDescription.getTypeDescription(Type.class), + TypeDescription.getTypeDescription(Type.class), + TypeDescription.getTypeDescription(Type.class), + TypeDescription.getTypeDescription(Type.class), + TypeDescription.getTypeDescription(Type.class), + TypeDescription.getTypeDescription(Type.class), + TypeDescription.getTypeDescription(Type.class), + TypeDescription.getTypeDescription(Type.class), + TypeDescription.getTypeDescription(Type.class), + TypeDescription.getTypeDescription(Type.class), + TypeDescription.getTypeDescription(Type.class), + TypeDescription.getTypeDescription(Type.class), + TypeDescription.getTypeDescription(Type.class), + TypeDescription.getTypeDescription(Type.class), + TypeDescription.getTypeDescription(Type.class), + TypeDescription.getTypeDescription(Type.class), + TypeDescription.getTypeDescription(Type.class), + TypeDescription.getTypeDescription(Type.class), + TypeDescription.getTypeDescription(Type.class), + TypeDescription.getTypeDescription(Type.class), + TypeDescription.getTypeDescription(Type.class), + TypeDescription.getTypeDescription(Type.class), + TypeDescription.getTypeDescription(Type.class), + TypeDescription.getTypeDescription(Type.class), + TypeDescription.getTypeDescription(Type.class), + TypeDescription.getTypeDescription(Type.class), + TypeDescription.getTypeDescription(Type.class), + TypeDescription.getTypeDescription(Type.class), + TypeDescription.getTypeDescription(Type.class), + TypeDescription.getTypeDescription(Type.class), + TypeDescription.getTypeDescription(Type.class), + TypeDescription.getTypeDescription(Type.class), + TypeDescription.getTypeDescription(Type.class), + TypeDescription.getTypeDescription(Type.class), + TypeDescription.getTypeDescription(Type.class), + TypeDescription.getTypeDescription(Type.class), + TypeDescription.getTypeDescription(Type.class), + TypeDescription.getTypeDescription(Type.class), + TypeDescription.getTypeDescription(XInterface.class), + TypeDescription.getTypeDescription(XInterface.class), + TypeDescription.getTypeDescription(TestInterfaceStruct.class), + }; + + + Unmarshal unmarshal = new Unmarshal(testBridge, cacheSize); + for(int i = 0; i < dataTypes.length; ++ i) { + Object op1 = data[i]; + marshal.writeValue(dataTypes[i], data[i]); + + unmarshal.reset(marshal.reset()); + + Object op2 = unmarshal.readValue(dataTypes[i]); + + if(op1 instanceof Any) + op1 = ((Any)op1).getObject(); + + assertTrue(compareObjects(op1, op2)); + } + } + + private static boolean compareArrays(Object op1, Object op2) throws Exception { + boolean result = true; + if((op1.getClass().getComponentType() == op2.getClass().getComponentType()) + && (Array.getLength(op1) == Array.getLength(op2))) + { + for(int i = 0; i < Array.getLength(op1); ++ i) + result = result & compareObjects(Array.get(op1, i), Array.get(op2, i)); + } + + return result; + } + + private static boolean compareInterfaces(XInterface op1, XInterface op2) { + return op1 == op2; + } + + private static boolean compareStructs(Class zClass, Object op1, Object op2) throws Exception { + boolean result = true; + + Field fields[] = zClass.getFields(); + + for(int i = 0; i < fields.length && result; ++ i) { + if((fields[i].getModifiers() & (Modifier.STATIC | Modifier.TRANSIENT)) == 0) { // neither static nor transient ? + result = result & compareObjects(fields[i].get(op1), fields[i].get(op2)); + + if(!result) + System.err.println("blabal :" + fields[i]); + } + } + + return result; + } + + private static boolean compareStructs(Object op1, Object op2) throws Exception { + boolean result = true; + + if(op1.getClass() != op2.getClass()) + result = false; + else { + result = compareStructs(op1.getClass(), op1, op2); + } + + return result; + } + + private static boolean compareThrowable(Throwable op1, Throwable op2) throws Exception { + boolean result = true; + + if(op1.getClass() != op2.getClass()) + result = false; + else { + result = compareStructs(op1.getClass(), op1, op2); + + result = result & op1.getMessage().equals(op2.getMessage()); + } + + return result; + } + + private static boolean compareObjects(Object op1, Object op2) throws Exception { + boolean result = false; + + if(op1 == op2) + result = true; + + else if(op1.getClass().isPrimitive() && op2.getClass().isPrimitive()) + result = op1.equals(op2); + + else if(op1.getClass() == Byte.class && op2.getClass() == Byte.class) + result = op1.equals(op2); + + else if(op1.getClass() == Type.class && op2.getClass() == Type.class) + result = op1.equals(op2); + + else if(op1.getClass() == Boolean.class && op2.getClass() == Boolean.class) + result = op1.equals(op2); + + else if(op1.getClass() == Short.class && op2.getClass() == Short.class) + result = op1.equals(op2); + + else if(Throwable.class.isAssignableFrom(op1.getClass()) && Throwable.class.isAssignableFrom(op2.getClass())) + result = compareThrowable((Throwable)op1, (Throwable)op2); + + else if(op1.getClass() == Integer.class && op2.getClass() == Integer.class) + result = op1.equals(op2); + + else if(op1.getClass() == Character.class && op2.getClass() == Character.class) + result = op1.equals(op2); + + else if(op1.getClass() == Long.class && op2.getClass() == Long.class) + result = op1.equals(op2); + + else if(op1.getClass() == Void.class && op2.getClass() == Void.class) + result = op1.equals(op2); + + else if(op1.getClass() == Float.class && op2.getClass() == Float.class) + result = op1.equals(op2); + + else if(op1.getClass() == Double.class && op2.getClass() == Double.class) + result = op1.equals(op2); + + else if(op1.getClass().isArray() && op2.getClass().isArray()) + result = compareArrays(op1, op2); + + else if(op1.getClass() == Void.class || op2.getClass() == void.class) // write nothing ? + result = true; + + else if(XInterface.class.isAssignableFrom(op1.getClass()) && XInterface.class.isAssignableFrom(op2.getClass())) + result = compareInterfaces((XInterface)op1, (XInterface)op2); + + else if(op1.getClass() == String.class && op2.getClass() == String.class) // is it a String ? + result = ((String)op1).equals(op2); + + else if(op1.getClass() == Type.class && op2.getClass() == Type.class) // types? + result = op1.equals(op2); + + else // otherwise it must be a struct + result = compareStructs(op1, op2); + + return result; + } +} + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/ridljar/test/com/sun/star/lib/uno/protocols/urp/Protocol_Test.java b/ridljar/test/com/sun/star/lib/uno/protocols/urp/Protocol_Test.java new file mode 100644 index 000000000..cda58aad8 --- /dev/null +++ b/ridljar/test/com/sun/star/lib/uno/protocols/urp/Protocol_Test.java @@ -0,0 +1,311 @@ +/* -*- 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.IProtocol; +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.IBridge; +import com.sun.star.uno.Type; +import com.sun.star.uno.XInterface; +import java.io.IOException; +import java.io.InputStream; +import java.io.OutputStream; +import java.io.PipedInputStream; +import java.io.PipedOutputStream; +import java.util.LinkedList; +import org.junit.Test; +import static org.junit.Assert.*; + +public final class Protocol_Test { + @Test public void test() throws Exception { + IBridge iBridge = new TestBridge(); + PipedInputStream inA = new PipedInputStream(); + PipedOutputStream outA = new PipedOutputStream(inA); + PipedInputStream inB = new PipedInputStream(); + PipedOutputStream outB = new PipedOutputStream(inB); + Endpoint iSender = new Endpoint(iBridge, inA, outB); + Endpoint iReceiver = new Endpoint(iBridge, inB, outA); + + TestObject testObject = new TestObject(); + String oId = (String)iBridge.mapInterfaceTo(testObject, new Type(XInterface.class)); + + testCall(iSender, iReceiver, oId); + testCallWithInParameter(iSender, iReceiver, oId); + testCallWithOutParameter(iSender, iReceiver, oId); + testCallWithInOutParameter(iSender, iReceiver, oId); + testCallWithResult(iSender, iReceiver, oId); + testCallWhichRaisesException(iSender, iReceiver, oId); + testCallWithIn_Out_InOut_Paramters_and_result(iSender, iReceiver, oId); + testCallWhichReturnsAny(iSender, iReceiver, oId); + } + + public void testCall( + Endpoint iSender, Endpoint iReceiver, String oId) throws Exception + { + // send an ordinary request + iSender.writeRequest( + oId, TypeDescription.getTypeDescription(TestXInterface.class), + "method", new ThreadId(new byte[] { 0, 1 }), new Object[0]); + iReceiver.readMessage(); + + // send a reply + iReceiver.writeReply(false, new ThreadId(new byte[] { 0, 1 }), null); + iSender.readMessage(); + } + + public void testCallWithInParameter( + Endpoint iSender, Endpoint iReceiver, String oId) throws Exception + { + // send an ordinary request + iSender.writeRequest( + oId, TypeDescription.getTypeDescription(TestXInterface.class), + "methodWithInParameter", new ThreadId(new byte[] { 0, 1 }), + new Object[] { "hallo" }); + Message iMessage = iReceiver.readMessage(); + Object[] t_params = iMessage.getArguments(); + assertEquals("hallo", t_params[0]); + + // send a reply + iReceiver.writeReply(false, new ThreadId(new byte[] { 0, 1 }), null); + iMessage = iSender.readMessage(); + } + + public void testCallWithOutParameter( + Endpoint iSender, Endpoint iReceiver, String oId) throws Exception + { + Object params[] = new Object[]{new String[1]}; + iSender.writeRequest( + oId, TypeDescription.getTypeDescription(TestXInterface.class), + "methodWithOutParameter", new ThreadId(new byte[] { 0, 1 }), + params); + Message iMessage = iReceiver.readMessage(); + + + Object[] t_params = iMessage.getArguments(); + ((String [])t_params[0])[0] = "testString"; + + // send an exception as reply + iReceiver.writeReply(false, new ThreadId(new byte[] { 0, 1 }), null); + iSender.readMessage(); + + assertEquals("testString", ((String [])params[0])[0]); + } + + public void testCallWithInOutParameter( + Endpoint iSender, Endpoint iReceiver, String oId) throws Exception + { + Object params[] = new Object[]{new String[]{"inString"}}; + iSender.writeRequest( + oId, TypeDescription.getTypeDescription(TestXInterface.class), + "methodWithInOutParameter", new ThreadId(new byte[] { 0, 1 }), + params); + Message iMessage = iReceiver.readMessage(); + + + Object[] t_params = iMessage.getArguments(); + assertEquals("inString", ((String [])t_params[0])[0]); + + // provide reply + ((String [])t_params[0])[0] = "outString"; + + // send an exception as reply + iReceiver.writeReply(false, new ThreadId(new byte[] { 0, 1 }), null); + iSender.readMessage(); + + assertEquals("outString", ((String [])params[0])[0]); + } + + public void testCallWithResult( + Endpoint iSender, Endpoint iReceiver, String oId) throws Exception + { + // send an ordinary request + iSender.writeRequest( + oId, TypeDescription.getTypeDescription(TestXInterface.class), + "methodWithResult", new ThreadId(new byte[] { 0, 1 }), + new Object[0]); + iReceiver.readMessage(); + + // send a reply + iReceiver.writeReply( + false, new ThreadId(new byte[] { 0, 1 }), "resultString"); + Message iMessage = iSender.readMessage(); + Object result = iMessage.getResult(); + + assertEquals("resultString", result); + } + + public void testCallWhichRaisesException( + Endpoint iSender, Endpoint iReceiver, String oId) throws Exception + { + // send a second request + iSender.writeRequest( + oId, TypeDescription.getTypeDescription(TestXInterface.class), + "method", new ThreadId(new byte[] { 0, 1 }), new Object[0]); + iReceiver.readMessage(); + + // send an exception as reply + iReceiver.writeReply( + true, new ThreadId(new byte[] { 0, 1 }), + new com.sun.star.uno.RuntimeException("test the exception")); + Message iMessage = iSender.readMessage(); + + Object result = iMessage.getResult(); + + assertTrue(result instanceof com.sun.star.uno.RuntimeException); + } + + public void testCallWithIn_Out_InOut_Paramters_and_result( + Endpoint iSender, Endpoint iReceiver, String oId) throws Exception + { + Object params[] = new Object[]{"hallo", new String[1], new String[]{"inOutString"}}; + iSender.writeRequest( + oId, TypeDescription.getTypeDescription(TestXInterface.class), + "MethodWithIn_Out_InOut_Paramters_and_result", + new ThreadId(new byte[] { 0, 1 }), params); + Message iMessage = iReceiver.readMessage(); + + Object[] t_params = iMessage.getArguments(); + + assertEquals("hallo", t_params[0]); + + assertEquals("inOutString", ((String [])t_params[2])[0]); + + ((String [])t_params[1])[0] = "outString"; + ((String [])t_params[2])[0] = "inOutString_res"; + + // send an exception as reply + iReceiver.writeReply( + false, new ThreadId(new byte[] { 0, 1 }), "resultString"); + iMessage = iSender.readMessage(); + + Object result = iMessage.getResult(); + assertEquals("outString", ((String [])params[1])[0]); + + assertEquals("inOutString_res", ((String [])params[2])[0]); + + assertEquals("resultString", result); + } + + public void testCallWhichReturnsAny( + Endpoint iSender, Endpoint iReceiver, String oId) throws Exception + { + // send an ordinary request + iSender.writeRequest( + oId, TypeDescription.getTypeDescription(TestXInterface.class), + "returnAny", new ThreadId(new byte[] { 0, 1 }), null); + iReceiver.readMessage(); + // send a reply + iReceiver.writeReply( + false, new ThreadId(new byte[] { 0, 1 }), Any.VOID); + Message iMessage = iSender.readMessage(); + Object result = iMessage.getResult(); + assertTrue( + result instanceof Any && + ((TypeDescription.getTypeDescription(((Any) result).getType()). + getZClass()) == + void.class)); + + // send an ordinary request + iSender.writeRequest( + oId, TypeDescription.getTypeDescription(TestXInterface.class), + "returnAny", new ThreadId(new byte[] { 0, 1 }), null); + iReceiver.readMessage(); + // send a reply + iReceiver.writeReply( + false, new ThreadId(new byte[] { 0, 1 }), + new Any(XInterface.class, null)); + iMessage = iSender.readMessage(); + result = iMessage.getResult(); + assertNull(result); + + // send an ordinary request + iSender.writeRequest( + oId, TypeDescription.getTypeDescription(TestXInterface.class), + "returnAny", new ThreadId(new byte[] { 0, 1 }), null); + iReceiver.readMessage(); + // send a reply + iReceiver.writeReply( + false, new ThreadId(new byte[] { 0, 1 }), Integer.valueOf(501)); + iMessage = iSender.readMessage(); + result = iMessage.getResult(); + assertEquals(501, result); + } + + private static final class Endpoint { + public Endpoint(IBridge bridge, InputStream input, OutputStream output) + throws IOException + { + protocol = new urp(bridge, null, input, output); + new Thread() { + @Override + public void run() { + for (;;) { + Object o; + try { + o = protocol.readMessage(); + } catch (IOException e) { + o = e; + } + synchronized (queue) { + queue.addLast(o); + } + } + } + }.start(); + protocol.init(); + } + + public Message readMessage() throws IOException { + for (;;) { + synchronized (queue) { + if (!queue.isEmpty()) { + Object o = queue.removeFirst(); + if (o instanceof Message) { + return (Message) o; + } else { + throw (IOException) o; + } + } + } + } + } + + public boolean writeRequest( + String oid, TypeDescription type, String function, ThreadId tid, + Object[] arguments) + throws IOException + { + return protocol.writeRequest(oid, type, function, tid, arguments); + } + + public void writeReply(boolean exception, ThreadId tid, Object result) + throws IOException + { + protocol.writeReply(exception, tid, result); + } + + private final IProtocol protocol; + private final LinkedList queue = new LinkedList(); + } +} + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/ridljar/test/com/sun/star/lib/uno/protocols/urp/TestBridge.java b/ridljar/test/com/sun/star/lib/uno/protocols/urp/TestBridge.java new file mode 100644 index 000000000..acd1b3948 --- /dev/null +++ b/ridljar/test/com/sun/star/lib/uno/protocols/urp/TestBridge.java @@ -0,0 +1,106 @@ +/* -*- 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.IOException; + +import java.util.HashMap; + + +import com.sun.star.uno.IBridge; +import com.sun.star.uno.IEnvironment; +import com.sun.star.uno.Type; + + +class TestBridge implements IBridge { + private static final boolean DEBUG = false; + + private final HashMap _hashtable = new HashMap(); + + private IEnvironment _source ;//= new com.sun.star.lib.uno.environments.java.java_environment(null); + + + private class MyEnv implements IEnvironment { + public Object getContext() { + return null; + } + + public String getName() { + return null; + } + + public Object registerInterface(Object object, String oId[], Type type) { + return null; + } + + public void revokeInterface(String oId, Type type) { + } + + public Object getRegisteredInterface(String oid, Type type) { + Object object = _hashtable.get(oid); + + if(DEBUG) System.err.println("##### " + getClass().getName() + ".getRegisteredInterface:" + oid + " " + object); + + return object; + } + + public String getRegisteredObjectIdentifier(Object object) { + return null; + } + + public void list() { + } + } + + TestBridge() { + _source = new MyEnv(); + } + + public Object mapInterfaceTo(Object object, Type type) { + if (object == null) { + return null; + } else { + String oid = ">" + object.toString() + type.toString() + "<"; + _hashtable.put(oid, object); + return oid; + } + } + + public Object mapInterfaceFrom(Object object, Type type) { + String oid = (String)object; + + return _hashtable.get(oid); + } + + public IEnvironment getSourceEnvironment() { + return _source; + } + + public IEnvironment getTargetEnvironment() { + return null; + } + + public void acquire() {} + + public void release() {} + + public void dispose() throws InterruptedException, IOException {} +} + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/ridljar/test/com/sun/star/lib/uno/protocols/urp/TestObject.java b/ridljar/test/com/sun/star/lib/uno/protocols/urp/TestObject.java new file mode 100644 index 000000000..f36710e1d --- /dev/null +++ b/ridljar/test/com/sun/star/lib/uno/protocols/urp/TestObject.java @@ -0,0 +1,63 @@ +/* -*- 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; + + + +class TestObject implements TestXInterface { + public void method1( /*IN*/java.lang.Object itf ) throws com.sun.star.uno.Exception, com.sun.star.uno.RuntimeException { + } + + public void method2( /*OUT*/java.lang.Object[] itf ) throws com.sun.star.uno.Exception, com.sun.star.uno.RuntimeException { + } + + public void method3( /*INOUT*/java.lang.Object[] itf ) throws com.sun.star.uno.Exception, com.sun.star.uno.RuntimeException { + } + + public Object method4( ) throws com.sun.star.uno.Exception, com.sun.star.uno.RuntimeException { + return null; + } + + public Object returnAny( ) throws com.sun.star.uno.Exception, com.sun.star.uno.RuntimeException { + return null; + } + + + public void method() throws com.sun.star.uno.Exception, com.sun.star.uno.RuntimeException { + } + + public void methodWithInParameter( /*IN*/String text ) throws com.sun.star.uno.Exception, com.sun.star.uno.RuntimeException { + } + + public void methodWithOutParameter( /*OUT*/String[] text ) throws com.sun.star.uno.Exception, com.sun.star.uno.RuntimeException { + } + + public void methodWithInOutParameter( /*INOUT*/String[] text ) throws com.sun.star.uno.Exception, com.sun.star.uno.RuntimeException { + } + + public String methodWithResult( ) throws com.sun.star.uno.Exception, com.sun.star.uno.RuntimeException { + return "TestObject_resultString"; + } + + public String MethodWithIn_Out_InOut_Paramters_and_result( /*IN*/String text, /*OUT*/String[] outtext, /*INOUT*/String[] inouttext ) throws com.sun.star.uno.Exception, com.sun.star.uno.RuntimeException { + return "TestObject_resultString"; + } +} + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/ridljar/test/com/sun/star/lib/uno/protocols/urp/interfaces.idl b/ridljar/test/com/sun/star/lib/uno/protocols/urp/interfaces.idl new file mode 100644 index 000000000..4ea1c8ebc --- /dev/null +++ b/ridljar/test/com/sun/star/lib/uno/protocols/urp/interfaces.idl @@ -0,0 +1,101 @@ +/* -*- Mode: C++; 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 . + */ + +#include +#include +#include +#include + +module com { module sun { module star { module lib { module uno { +module protocols { module urp { + + struct TestPrimitiveStruct { + boolean zBool; + short zShort; + unsigned short zUShort; + long zLong; + unsigned long zULong; + hyper zHyper; + unsigned hyper zUHyper; + float zFloat; + double zDouble; + char zChar; + byte zByte; + string zString; + any zAny; + }; + + struct TestPrimitiveSeqStruct { + sequence zBool; + sequence zShort; + sequence zUShort; + sequence zLong; + sequence zULong; + sequence zHyper; + sequence zUHyper; + sequence zFloat; + sequence zDouble; + sequence zChar; + sequence zByte; + sequence zString; + sequence zAny; + }; + + struct TestNestedStruct { + TestPrimitiveStruct primitiveStruct; + TestPrimitiveSeqStruct primitiveSeqStruct; + }; + + struct TestNestedSeqStruct { + sequence< sequence< long > > val; + }; + + interface TestXInterface : com::sun::star::uno::XInterface { + void method1([in] com::sun::star::uno::XInterface itf) raises( com::sun::star::uno::Exception ); + void method2([out] com::sun::star::uno::XInterface itf) raises( com::sun::star::uno::Exception ); + void method3([inout] com::sun::star::uno::XInterface itf) raises( com::sun::star::uno::Exception ); + com::sun::star::uno::XInterface method4() raises( com::sun::star::uno::Exception ); + + any returnAny() raises( com::sun::star::uno::Exception ); + + void method() raises( com::sun::star::uno::Exception ); + void methodWithInParameter([in] string text) raises( com::sun::star::uno::Exception ); + void methodWithOutParameter([out] string text) raises( com::sun::star::uno::Exception ); + void methodWithInOutParameter([inout] string text) raises( com::sun::star::uno::Exception ); + string methodWithResult() raises( com::sun::star::uno::Exception ); + + string MethodWithIn_Out_InOut_Paramters_and_result([in] string text, [out] string outtext, [inout] string inouttext) raises( com::sun::star::uno::Exception ); + }; + + struct TestInterfaceStruct + { + com::sun::star::uno::XInterface hallo; + + com::sun::star::beans::XPropertySet hallo2; + }; + + enum TestEnum { + A = 7, + B = 8, + C = 11 + }; + +}; }; }; }; }; }; }; + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/ridljar/test/com/sun/star/lib/uno/typedesc/TypeDescription_Test.java b/ridljar/test/com/sun/star/lib/uno/typedesc/TypeDescription_Test.java new file mode 100644 index 000000000..13271dc0e --- /dev/null +++ b/ridljar/test/com/sun/star/lib/uno/typedesc/TypeDescription_Test.java @@ -0,0 +1,298 @@ +/* + * 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.MethodTypeInfo; +import com.sun.star.lib.uno.typeinfo.TypeInfo; +import com.sun.star.uno.Any; +import com.sun.star.uno.Type; +import com.sun.star.uno.TypeClass; +import com.sun.star.uno.XInterface; +import com.sun.star.uno.XNamingService; +import org.junit.Test; +import static org.junit.Assert.*; + +public final class TypeDescription_Test { + @Test public void test() throws Exception { + TypeDescription voidTD = TypeDescription.getTypeDescription( + void.class); + TypeDescription stringTD = TypeDescription.getTypeDescription( + String.class); + TypeDescription typeTD = TypeDescription.getTypeDescription( + Type.class); + TypeDescription anyTD = TypeDescription.getTypeDescription(Any.class); + TypeDescription interfaceTD = TypeDescription.getTypeDescription( + XInterface.class); + + MethodSignature sigBuildinSyncTypeToAny = new MethodSignature( + true, false, new TypeDescription[] { typeTD }, + new TypeDescription[1], anyTD); + MethodSignature sigBuildinAsyncToVoid = new MethodSignature( + true, true, new TypeDescription[0], new TypeDescription[0], + voidTD); + MethodSignature sigAddonSyncStringToVoid = new MethodSignature( + false, false, new TypeDescription[] { stringTD }, + new TypeDescription[1], voidTD); + MethodSignature sigAddonSyncStringInterfaceToVoid = new MethodSignature( + false, false, new TypeDescription[] { stringTD, interfaceTD }, + new TypeDescription[2], voidTD); + MethodSignature sigAddonSyncStringToInterface = new MethodSignature( + false, false, new TypeDescription[] { stringTD }, + new TypeDescription[1], interfaceTD); + + TypeSignature emptyTypeSig = new TypeSignature( + null, new String[0], null, new String[0], null); + TypeSignature interfaceTypeSig = new TypeSignature( + null, new String[] { "queryInterface", "acquire", "release" }, + new MethodSignature[] { sigBuildinSyncTypeToAny, + sigBuildinAsyncToVoid, + sigBuildinAsyncToVoid }, + new String[0], null); + TypeSignature exceptionTypeSig = new TypeSignature( + null, new String[0], null, + new String[]{"Context"}, new TypeSignature[] { interfaceTypeSig }); + // com.sun.star.uno.Exception.idl says that Exception (a) has no + // base exception, and (b) has two fields, Message and Context; the + // generated com.sun.star.uno.Exception.java, however, (a) is + // inherited from java.lang.Exception, and (b) has only one field, + // Context, as Message is inherited from java.lang.Exception + TypeSignature namingServiceTypeSig = new TypeSignature( + interfaceTypeSig, + new String[] { "getRegisteredObject", "registerObject", + "revokeObject" }, + new MethodSignature[] { sigAddonSyncStringToInterface, + sigAddonSyncStringInterfaceToVoid, + sigAddonSyncStringToVoid }, + new String[0], null); + + Object[] byteData = new Object[] { + "byte", "[B", byte.class, TypeClass.BYTE }; + Object[] stringData = new Object[] { + "string", "[Ljava.lang.String;", java.lang.String.class, + TypeClass.STRING }; + Object[] typeClassData = new Object[] { + "com.sun.star.uno.TypeClass", "[Lcom.sun.star.uno.TypeClass;", + TypeClass.class, TypeClass.ENUM }; + Object[] interfaceData = new Object[] { + "com.sun.star.uno.XInterface", "[Lcom.sun.star.uno.XInterface;", + XInterface.class, TypeClass.INTERFACE }; + Object[] exceptionData = new Object [] { + "com.sun.star.uno.Exception", "[Lcom.sun.star.uno.Exception;", + com.sun.star.uno.Exception.class, TypeClass.EXCEPTION, + new Object[] { interfaceData } }; + Object[] namingServiceData = new Object[] { + "com.sun.star.uno.XNamingService", + "[Lcom.sun.star.uno.XNamingService;", XNamingService.class, + TypeClass.INTERFACE, null, interfaceData }; + + emptyTypeSig.test("TypeSignature.test(byte)", byteData, + TypeDescription.getTypeDescription("byte")); + emptyTypeSig.test("TypeSignature.test(string)", stringData, + TypeDescription.getTypeDescription("string")); + emptyTypeSig.test("TypeSignature.test(TypeClass)", typeClassData, + TypeDescription.getTypeDescription( + "com.sun.star.uno.TypeClass")); + exceptionTypeSig.test("TypeSignature.test(com.sun.star.uno.Exception)", + exceptionData, + TypeDescription.getTypeDescription( + "com.sun.star.uno.Exception")); + interfaceTypeSig.test("TypeSignature.test(XInterface)", interfaceData, + TypeDescription.getTypeDescription( + "com.sun.star.uno.XInterface")); + namingServiceTypeSig.test("TypeSignature.test(XNamingService)", + namingServiceData, + TypeDescription.getTypeDescription( + "com.sun.star.uno.XNamingService")); + } + + @Test public void testUnsigned() throws ClassNotFoundException { + assertEquals( + "TypeDescription for UNSIGNED LONG", "unsigned long", + TypeDescription.getTypeDescription(Type.UNSIGNED_LONG).getTypeName()); + } + + @Test public void testGetMethodDescription() { + TypeDescription td = TypeDescription.getTypeDescription(XDerived.class); + td.getMethodDescription("fn"); + } + + @Test public void testSequence() throws ClassNotFoundException { + assertEquals( + "unsigned short", + TypeDescription.getTypeDescription("[]unsigned short").getComponentType().getTypeName()); + } + + public interface XBase extends XInterface { + void fn(); + + TypeInfo[] UNOTYPEINFO = { new MethodTypeInfo("fn", 0, 0) }; + } + + public interface XDerived extends XBase { + TypeInfo[] UNOTYPEINFO = null; + } + + private final class MethodSignature { + public MethodSignature( + boolean buildIn, boolean oneWay, TypeDescription[] inParameters, + TypeDescription[] outParameters, TypeDescription returnValue) + { + this.buildIn = buildIn; + this.oneWay = oneWay; + this.inParameters = inParameters; + this.outParameters = outParameters; + this.returnValue = returnValue; + } + + public void test(String prefix, int index, + MethodDescription description) { + assertEquals(prefix + "; getIndex", index, description.getIndex()); + assertEquals( + prefix + "; getMethod", buildIn, + description.getMethod() == null); + assertEquals(prefix + "; isOneway", oneWay, description.isOneway()); + TypeDescription[] in = description.getInSignature(); + assertEquals( + prefix + "; getInSignature", inParameters.length, in.length); + for (int i = 0; i < in.length; ++i) { + assertEquals( + prefix + "; getInSignature " + i, inParameters[i], in[i]); + } + TypeDescription[] out = description.getOutSignature(); + assertEquals( + prefix + "; getOutSignature", outParameters.length, out.length); + for (int i = 0; i < out.length; ++i) { + assertTrue( + prefix + "; getOutSignature " + i, + (out[i] == null + ? outParameters[i] == null + : out[i].equals(outParameters[i]))); + } + assertEquals( + prefix + "; getReturnSignature", returnValue, + description.getReturnSignature()); + } + + private final boolean buildIn; + private final boolean oneWay; + private final TypeDescription[] inParameters; + private final TypeDescription[] outParameters; + private final TypeDescription returnValue; + } + + private final class TypeSignature { + public TypeSignature(TypeSignature superType, String[] methodNames, + MethodSignature[] methodSignatures, + String[] fieldNames, + TypeSignature[] fieldSignatures) { + this._superType = superType; + this.methodNames = methodNames; + this.methodSignatures = methodSignatures; + methodOffset = superType == null ? 0 + : superType.methodOffset + superType.methodNames.length; + this.fieldSignatures = fieldSignatures; + this.fieldNames = fieldNames; + fieldOffset = superType == null ? 0 + : superType.fieldOffset + superType.fieldNames.length; + } + + public void test(String prefix, Object[] data, + TypeDescription description) throws Exception { + assertEquals( + prefix + "; getTypeName", data[0], description.getTypeName()); + assertEquals( + prefix + "; equals", + TypeDescription.getTypeDescription((String)data[0]), + description); + assertEquals( + prefix + "; getArrayTypeName", data[1], + description.getArrayTypeName()); + assertSame( + prefix + "; getZClass", data[2], description.getZClass()); + assertSame( + prefix + "; getTypeClass", data[3], description.getTypeClass()); + assertNull( + prefix + "; getComponentType", description.getComponentType()); + + MethodDescription[] mds = description.getMethodDescriptions(); + assertTrue( + prefix + "; getMethodDescriptions", + mds == null + ? methodSignatures == null + : mds.length == methodSignatures.length); + if (methodSignatures != null) { + for (int i = 0; i < methodSignatures.length; ++i) { + methodSignatures[i].test( + prefix + "; getMethodDescriptions " + i, + i + methodOffset, mds[i]); + } + } + for (int i = 0; i < methodNames.length; ++i) { + MethodDescription md = description.getMethodDescription( + i + methodOffset); + assertNotNull( + prefix + "; getMethodDescription " + (i + methodOffset), + md); + methodSignatures[i].test( + prefix + "; getMethodDescription " + (i + methodOffset), + i + methodOffset, md); + } + for (int i = 0; i < methodNames.length; ++i) { + MethodDescription md = description.getMethodDescription( + methodNames[i]); + assertNotNull( + prefix + "; getMethodDescription " + methodNames[i], md); + methodSignatures[i].test( + prefix + "; getMethodDescription " + methodNames[i], + i + methodOffset, md); + } + + FieldDescription[] fds = description.getFieldDescriptions(); + assertTrue( + prefix + "; getFieldDescriptions", + fds == null + ? fieldSignatures == null + : fds.length == fieldSignatures.length); + if (fieldSignatures != null) { + for (int i = 0; i < fieldSignatures.length; ++i) { + fieldSignatures[i].test( + prefix + "; getFieldDescriptions " + i, + (Object[]) ((Object[]) data[4])[i], + fds[i].getTypeDescription()); + } + } + + TypeDescription supert = description.getSuperType(); + assertEquals( + prefix + "; getSuperType", data.length < 6, supert == null); + if (supert != null && data[5] != null) { + _superType.test(prefix + "; getSuperType", (Object[]) data[5], + supert); + } + } + + private final TypeSignature _superType; + private final MethodSignature[] methodSignatures; + private final String[] methodNames; + private final int methodOffset; + private final TypeSignature[] fieldSignatures; + private final String[] fieldNames; + private final int fieldOffset; + } +} diff --git a/ridljar/test/com/sun/star/lib/util/NativeLibraryLoader_Test.java b/ridljar/test/com/sun/star/lib/util/NativeLibraryLoader_Test.java new file mode 100644 index 000000000..e4101f2dd --- /dev/null +++ b/ridljar/test/com/sun/star/lib/util/NativeLibraryLoader_Test.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.util; + +import java.io.File; +import java.net.MalformedURLException; +import java.net.URL; +import org.junit.Test; +import static org.junit.Assert.*; + +public final class NativeLibraryLoader_Test { + @Test public void testEncoded() throws MalformedURLException { + File dir = new File(System.getProperty("user.dir")); + File subdir = new File(dir, "with space"); + File file1 = new File(subdir, "file"); + + String fileUrl = dir.toURI().toURL().toString(); + if (!fileUrl.endsWith("/")) { + fileUrl += "/"; + } + fileUrl += "with%20space/file"; + final URL url = new URL(fileUrl); + + File file2 = NativeLibraryLoader.getResource( + new ClassLoader() { + @Override + public URL getResource(String name) { + return url; + } + }, + "dummy"); + assertEquals("Files are equal", file1, file2); + } + + @Test public void testUnencoded() throws MalformedURLException { + File dir = new File(System.getProperty("user.dir")); + File subdir = new File(dir, "with space"); + File file1 = new File(subdir, "file"); + + String fileUrl = dir.toURI().toURL().toString(); + if (!fileUrl.endsWith("/")) { + fileUrl += "/"; + } + fileUrl += "with space/file"; + final URL url = new URL(fileUrl); + + File file2 = NativeLibraryLoader.getResource( + new ClassLoader() { + @Override + public URL getResource(String name) { + return url; + } + }, + "dummy"); + assertEquals("Files are equal", file1, file2); + } +} + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/ridljar/test/com/sun/star/lib/util/WeakMap_Test.java b/ridljar/test/com/sun/star/lib/util/WeakMap_Test.java new file mode 100644 index 000000000..378a1ac78 --- /dev/null +++ b/ridljar/test/com/sun/star/lib/util/WeakMap_Test.java @@ -0,0 +1,74 @@ +/* + * 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 org.junit.Test; +import util.WaitUnreachable; +import static org.junit.Assert.*; + +public final class WeakMap_Test { + @Test public void test() { + WeakMap m = new WeakMap(); + assertEquals(0, m.size()); + assertTrue(m.isEmpty()); + assertFalse(m.containsKey("key1")); + assertFalse(m.containsValue(null)); + WaitUnreachable u1 = new WaitUnreachable(new Object()); + m.put("key1", u1.get()); + WaitUnreachable u2 = new WaitUnreachable(new Disposable()); + m.put("key2", u2.get()); + assertEquals(2, m.size()); + assertFalse(m.isEmpty()); + assertTrue(m.containsKey("key1")); + assertTrue(m.containsKey("key2")); + assertFalse(m.containsKey("key3")); + assertTrue(m.containsValue(m.get("key1"))); + assertTrue(m.containsValue(m.get("key2"))); + assertEquals(u1.get(), WeakMap.getValue(m.get("key1"))); + assertEquals(u2.get(), WeakMap.getValue(m.get("key2"))); + assertEquals(2, m.values().size()); + assertTrue(m.values().contains(m.get("key1"))); + assertTrue(m.values().contains(m.get("key2"))); + u1.waitUnreachable(); + assertNull(WeakMap.getValue(m.get("key1"))); + ((Disposable) u2.get()).dispose(); + assertNull(WeakMap.getValue(m.get("key2"))); + m.clear(); + u2.waitUnreachable(); + assertEquals(0, m.size()); + m.put("key2", new Object()); + assertEquals(1, m.size()); + } + + // This simple class (single listener, no synchronization) exploits + // knowledge about the implementation of WeakMap: + private static final class Disposable implements DisposeNotifier { + public void addDisposeListener(DisposeListener listener) { + this.listener = listener; + } + + public void dispose() { + if (listener != null) { + listener.notifyDispose(this); + } + } + + private DisposeListener listener = null; + } +} diff --git a/ridljar/test/com/sun/star/uno/AnyConverter_Test.java b/ridljar/test/com/sun/star/uno/AnyConverter_Test.java new file mode 100644 index 000000000..faa955a96 --- /dev/null +++ b/ridljar/test/com/sun/star/uno/AnyConverter_Test.java @@ -0,0 +1,904 @@ +/* -*- 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; + +import com.sun.star.lang.XTypeProvider; +import static org.junit.Assert.*; +import org.junit.Before; +import org.junit.Test; + +public final class AnyConverter_Test { + Any anyBool; + Any anyChar; + Any anyByte; + Any anyShort; + Any anyInt; + Any anyLong; + Any anyFloat; + Any anyDouble; + Any anyStr; + Any anyType; + Any anyArByte; + Any anyVoid; + Any anyXTypeProvider; + + Boolean aBool; + Character aChar; + Byte aByte; + Short aShort; + Integer aInt; + Long aLong; + Float aFloat; + Double aDouble; + Object aObj; + String aStr; + Type aType; + byte[] arByte; + + /** Class variables are initialized before each Test method */ + @Before public void setUp() + { + aBool= Boolean.TRUE; + aChar= new Character('A'); + aByte= Byte.valueOf((byte) 111); + aShort= Short.valueOf((short) 11111); + aInt= Integer.valueOf( 1111111); + aLong= Long.valueOf( 0xffffffff); + aFloat= new Float( 3.14); + aDouble= new Double( 3.145); + aObj= new ATypeProvider(); + aStr= "I am a string"; + aType= new Type(String.class); + arByte= new byte[] {1,2,3}; + + anyVoid= new Any(new Type(void.class), null); + anyBool= new Any(new Type(Boolean.TYPE), aBool); + anyChar= new Any(new Type(Character.TYPE), aChar); + anyByte= new Any(new Type(Byte.TYPE), aByte); + anyShort= new Any(new Type(Short.TYPE), aShort); + anyInt= new Any(new Type(Integer.TYPE), aInt); + anyLong= new Any(new Type(Long.TYPE), aLong); + anyFloat= new Any(new Type(Float.TYPE), aFloat); + anyDouble= new Any(new Type(Double.TYPE), aDouble); + anyStr= new Any(new Type(String.class), aStr); + anyType= new Any(new Type(Type.class), aType); + anyArByte= new Any(new Type(byte[].class), arByte); + anyXTypeProvider= new Any(new Type(XTypeProvider.class), aObj); + } + + @Test public void test_toBoolean() + throws com.sun.star.lang.IllegalArgumentException + { + // must work + boolean b= AnyConverter.toBoolean(aBool); + assertEquals(b, aBool.booleanValue()); + b= AnyConverter.toBoolean(anyBool); + assertEquals(b, ((Boolean)anyBool.getObject()).booleanValue()); + + // must fail + try { AnyConverter.toBoolean(aChar); fail(); + } catch (com.sun.star.lang.IllegalArgumentException ie) {} + try { AnyConverter.toBoolean(anyChar); fail(); + } catch (com.sun.star.lang.IllegalArgumentException ie) {} + try { AnyConverter.toBoolean(aByte); fail(); + } catch (com.sun.star.lang.IllegalArgumentException ie) {} + try { AnyConverter.toBoolean(anyByte); fail(); + } catch (com.sun.star.lang.IllegalArgumentException ie) {} + try { AnyConverter.toBoolean(aShort); fail(); + } catch (com.sun.star.lang.IllegalArgumentException ie) {} + try { AnyConverter.toBoolean(anyShort); fail(); + } catch (com.sun.star.lang.IllegalArgumentException ie) {} + try { AnyConverter.toBoolean(aInt); fail(); + } catch (com.sun.star.lang.IllegalArgumentException ie) {} + try { AnyConverter.toBoolean(anyInt); fail(); + } catch (com.sun.star.lang.IllegalArgumentException ie) {} + try { AnyConverter.toBoolean(aLong); fail(); + } catch (com.sun.star.lang.IllegalArgumentException ie) {} + try { AnyConverter.toBoolean(anyLong); fail(); + } catch (com.sun.star.lang.IllegalArgumentException ie) {} + try { AnyConverter.toBoolean(aFloat); fail(); + } catch (com.sun.star.lang.IllegalArgumentException ie) {} + try { AnyConverter.toBoolean(anyFloat); fail(); + } catch (com.sun.star.lang.IllegalArgumentException ie) {} + try { AnyConverter.toBoolean(aDouble); fail(); + } catch (com.sun.star.lang.IllegalArgumentException ie) {} + try { AnyConverter.toBoolean(anyDouble); fail(); + } catch (com.sun.star.lang.IllegalArgumentException ie) {} + try { AnyConverter.toBoolean(aObj); fail(); + } catch (com.sun.star.lang.IllegalArgumentException ie) {} + try { AnyConverter.toBoolean(aStr); fail(); + } catch (com.sun.star.lang.IllegalArgumentException ie) {} + try { AnyConverter.toBoolean(anyStr); fail(); + } catch (com.sun.star.lang.IllegalArgumentException ie) {} + try { AnyConverter.toBoolean(aType); fail(); + } catch (com.sun.star.lang.IllegalArgumentException ie) {} + try { AnyConverter.toBoolean(anyType); fail(); + } catch (com.sun.star.lang.IllegalArgumentException ie) {} + try { AnyConverter.toBoolean(anyVoid); fail(); + } catch (com.sun.star.lang.IllegalArgumentException ie) {} + try { AnyConverter.toBoolean(arByte); fail(); + } catch (com.sun.star.lang.IllegalArgumentException ie) {} + try { AnyConverter.toBoolean(anyArByte); fail(); + } catch (com.sun.star.lang.IllegalArgumentException ie) {} + } + + @Test public void test_toChar() + throws com.sun.star.lang.IllegalArgumentException + { + // must work + char b= AnyConverter.toChar(aChar); + assertEquals(b, aChar.charValue()); + b= AnyConverter.toChar(anyChar); + assertEquals(b, ((Character)anyChar.getObject()).charValue()); + + // must fail + try { AnyConverter.toChar(aBool); fail(); + } catch (com.sun.star.lang.IllegalArgumentException ie) {} + try { AnyConverter.toChar(anyBool); fail(); + } catch (com.sun.star.lang.IllegalArgumentException ie) {} + try { AnyConverter.toChar(aByte); fail(); + } catch (com.sun.star.lang.IllegalArgumentException ie) {} + try { AnyConverter.toChar(anyByte); fail(); + } catch (com.sun.star.lang.IllegalArgumentException ie) {} + try { AnyConverter.toChar(aShort); fail(); + } catch (com.sun.star.lang.IllegalArgumentException ie) {} + try { AnyConverter.toChar(anyShort); fail(); + } catch (com.sun.star.lang.IllegalArgumentException ie) {} + try { AnyConverter.toChar(aInt); fail(); + } catch (com.sun.star.lang.IllegalArgumentException ie) {} + try { AnyConverter.toChar(anyInt); fail(); + } catch (com.sun.star.lang.IllegalArgumentException ie) {} + try { AnyConverter.toChar(aLong); fail(); + } catch (com.sun.star.lang.IllegalArgumentException ie) {} + try { AnyConverter.toChar(anyLong); fail(); + } catch (com.sun.star.lang.IllegalArgumentException ie) {} + try { AnyConverter.toChar(aFloat); fail(); + } catch (com.sun.star.lang.IllegalArgumentException ie) {} + try { AnyConverter.toChar(anyFloat); fail(); + } catch (com.sun.star.lang.IllegalArgumentException ie) {} + try { AnyConverter.toChar(aDouble); fail(); + } catch (com.sun.star.lang.IllegalArgumentException ie) {} + try { AnyConverter.toChar(anyDouble); fail(); + } catch (com.sun.star.lang.IllegalArgumentException ie) {} + try { AnyConverter.toChar(aObj); fail(); + } catch (com.sun.star.lang.IllegalArgumentException ie) {} + try { AnyConverter.toChar(aStr); fail(); + } catch (com.sun.star.lang.IllegalArgumentException ie) {} + try { AnyConverter.toChar(anyStr); fail(); + } catch (com.sun.star.lang.IllegalArgumentException ie) {} + try { AnyConverter.toChar(aType); fail(); + } catch (com.sun.star.lang.IllegalArgumentException ie) {} + try { AnyConverter.toChar(anyType); fail(); + } catch (com.sun.star.lang.IllegalArgumentException ie) {} + try { AnyConverter.toChar(anyVoid); fail(); + } catch (com.sun.star.lang.IllegalArgumentException ie) {} + try { AnyConverter.toChar(arByte); fail(); + } catch (com.sun.star.lang.IllegalArgumentException ie) {} + try { AnyConverter.toChar(anyArByte); fail(); + } catch (com.sun.star.lang.IllegalArgumentException ie) {} + } + + @Test public void test_toByte() + throws com.sun.star.lang.IllegalArgumentException + { + // must work + byte val= AnyConverter.toByte(aByte); + assertEquals(val, aByte.byteValue()); + val= AnyConverter.toByte(anyByte); + assertEquals(val, ((Byte)anyByte.getObject()).byteValue()); + + // must fail + try { AnyConverter.toByte(aChar); fail(); + } catch (com.sun.star.lang.IllegalArgumentException ie) {} + try { AnyConverter.toByte(anyChar); fail(); + } catch (com.sun.star.lang.IllegalArgumentException ie) {} + try { AnyConverter.toByte(aShort); fail(); + } catch (com.sun.star.lang.IllegalArgumentException ie) {} + try { AnyConverter.toByte(anyShort); fail(); + } catch (com.sun.star.lang.IllegalArgumentException ie) {} + try { AnyConverter.toByte(aInt); fail(); + } catch (com.sun.star.lang.IllegalArgumentException ie) {} + try { AnyConverter.toByte(anyInt); fail(); + } catch (com.sun.star.lang.IllegalArgumentException ie) {} + try { AnyConverter.toByte(aLong); fail(); + } catch (com.sun.star.lang.IllegalArgumentException ie) {} + try { AnyConverter.toByte(anyLong); fail(); + } catch (com.sun.star.lang.IllegalArgumentException ie) {} + try { AnyConverter.toByte(aFloat); fail(); + } catch (com.sun.star.lang.IllegalArgumentException ie) {} + try { AnyConverter.toByte(anyFloat); fail(); + } catch (com.sun.star.lang.IllegalArgumentException ie) {} + try { AnyConverter.toByte(aDouble); fail(); + } catch (com.sun.star.lang.IllegalArgumentException ie) {} + try { AnyConverter.toByte(anyDouble); fail(); + } catch (com.sun.star.lang.IllegalArgumentException ie) {} + try { AnyConverter.toByte(aObj); fail(); + } catch (com.sun.star.lang.IllegalArgumentException ie) {} + try { AnyConverter.toByte(aStr); fail(); + } catch (com.sun.star.lang.IllegalArgumentException ie) {} + try { AnyConverter.toByte(anyStr); fail(); + } catch (com.sun.star.lang.IllegalArgumentException ie) {} + try { AnyConverter.toByte(aType); fail(); + } catch (com.sun.star.lang.IllegalArgumentException ie) {} + try { AnyConverter.toByte(anyType); fail(); + } catch (com.sun.star.lang.IllegalArgumentException ie) {} + try { AnyConverter.toByte(anyVoid); fail(); + } catch (com.sun.star.lang.IllegalArgumentException ie) {} + try { AnyConverter.toByte(arByte); fail(); + } catch (com.sun.star.lang.IllegalArgumentException ie) {} + try { AnyConverter.toByte(anyArByte); fail(); + } catch (com.sun.star.lang.IllegalArgumentException ie) {} + } + + @Test public void test_toShort() + throws com.sun.star.lang.IllegalArgumentException + { + // must work + short sh= AnyConverter.toShort(aByte); + assertEquals(sh, aByte.byteValue()); + sh= AnyConverter.toShort(aShort); + assertEquals(sh, aShort.shortValue()); + sh= AnyConverter.toShort(anyByte); + assertEquals(sh, ((Byte)anyByte.getObject()).byteValue()); + sh= AnyConverter.toShort(anyShort); + assertEquals(sh, ((Short) anyShort.getObject()).shortValue()); + Any a = new Any( Type.UNSIGNED_SHORT, Short.valueOf((short)5) ); + assertEquals(5, AnyConverter.toUnsignedShort( a )); + + // must fail + try { AnyConverter.toShort(a); fail(); + } catch (com.sun.star.lang.IllegalArgumentException ie) {} + try { AnyConverter.toUnsignedShort(anyShort); fail(); + } catch (com.sun.star.lang.IllegalArgumentException ie) {} + try { AnyConverter.toChar(aBool); fail(); + } catch (com.sun.star.lang.IllegalArgumentException ie) {} + try { AnyConverter.toChar(anyBool); fail(); + } catch (com.sun.star.lang.IllegalArgumentException ie) {} + try { AnyConverter.toShort(aChar); fail(); + } catch (com.sun.star.lang.IllegalArgumentException ie) {} + try { AnyConverter.toShort(anyChar); fail(); + } catch (com.sun.star.lang.IllegalArgumentException ie) {} + try { AnyConverter.toShort(aBool); fail(); + } catch (com.sun.star.lang.IllegalArgumentException ie) {} + try { AnyConverter.toShort(anyBool); fail(); + } catch (com.sun.star.lang.IllegalArgumentException ie) {} + try { AnyConverter.toShort(aInt); fail(); + } catch (com.sun.star.lang.IllegalArgumentException ie) {} + try { AnyConverter.toShort(anyInt); fail(); + } catch (com.sun.star.lang.IllegalArgumentException ie) {} + try { AnyConverter.toShort(aLong); fail(); + } catch (com.sun.star.lang.IllegalArgumentException ie) {} + try { AnyConverter.toShort(anyLong); fail(); + } catch (com.sun.star.lang.IllegalArgumentException ie) {} + try { AnyConverter.toShort(aFloat); fail(); + } catch (com.sun.star.lang.IllegalArgumentException ie) {} + try { AnyConverter.toShort(anyFloat); fail(); + } catch (com.sun.star.lang.IllegalArgumentException ie) {} + try { AnyConverter.toShort(aDouble); fail(); + } catch (com.sun.star.lang.IllegalArgumentException ie) {} + try { AnyConverter.toShort(anyDouble); fail(); + } catch (com.sun.star.lang.IllegalArgumentException ie) {} + try { AnyConverter.toShort(aObj); fail(); + } catch (com.sun.star.lang.IllegalArgumentException ie) {} + try { AnyConverter.toShort(aStr); fail(); + } catch (com.sun.star.lang.IllegalArgumentException ie) {} + try { AnyConverter.toShort(anyStr); fail(); + } catch (com.sun.star.lang.IllegalArgumentException ie) {} + try { AnyConverter.toShort(aType); fail(); + } catch (com.sun.star.lang.IllegalArgumentException ie) {} + try { AnyConverter.toShort(anyType); fail(); + } catch (com.sun.star.lang.IllegalArgumentException ie) {} + try { AnyConverter.toShort(anyVoid); fail(); + } catch (com.sun.star.lang.IllegalArgumentException ie) {} + try { AnyConverter.toShort(arByte); fail(); + } catch (com.sun.star.lang.IllegalArgumentException ie) {} + try { AnyConverter.toShort(anyArByte); fail(); + } catch (com.sun.star.lang.IllegalArgumentException ie) {} + } + + @Test public void test_toInt() + throws com.sun.star.lang.IllegalArgumentException + { + // must work + int val= AnyConverter.toInt(aByte); + assertEquals(val, aByte.byteValue()); + val= AnyConverter.toInt(aShort); + assertEquals(val, aShort.shortValue()); + val= AnyConverter.toInt(aInt); + assertEquals(val, aInt.intValue()); + val= AnyConverter.toInt(anyByte); + assertEquals(val, ((Byte)anyByte.getObject()).byteValue()); + val= AnyConverter.toInt(anyShort); + assertEquals(val, ((Short) anyShort.getObject()).shortValue()); + val= AnyConverter.toInt(anyInt); + assertEquals(val, ((Integer) anyInt.getObject()).intValue()); + Any a = new Any( Type.UNSIGNED_SHORT, Short.valueOf((short)5) ); + assertEquals(5, AnyConverter.toInt(a)); + assertEquals(5, AnyConverter.toUnsignedInt(a)); + a = new Any( Type.UNSIGNED_LONG, Integer.valueOf(5) ); + assertEquals(5, AnyConverter.toUnsignedInt(a)); + + // must fail + try { AnyConverter.toUnsignedInt(anyInt); fail(); + } catch (com.sun.star.lang.IllegalArgumentException ie) {} + try { AnyConverter.toInt(a); fail(); + } catch (com.sun.star.lang.IllegalArgumentException ie) {} + try { AnyConverter.toUnsignedInt(anyShort); fail(); + } catch (com.sun.star.lang.IllegalArgumentException ie) {} + try { AnyConverter.toInt(aChar); fail(); + } catch (com.sun.star.lang.IllegalArgumentException ie) {} + try { AnyConverter.toInt(anyChar); fail(); + } catch (com.sun.star.lang.IllegalArgumentException ie) {} + try { AnyConverter.toInt(aBool); fail(); + } catch (com.sun.star.lang.IllegalArgumentException ie) {} + try { AnyConverter.toInt(anyBool); fail(); + } catch (com.sun.star.lang.IllegalArgumentException ie) {} + try { AnyConverter.toInt(aLong); fail(); + } catch (com.sun.star.lang.IllegalArgumentException ie) {} + try { AnyConverter.toInt(anyLong); fail(); + } catch (com.sun.star.lang.IllegalArgumentException ie) {} + try { AnyConverter.toInt(aFloat); fail(); + } catch (com.sun.star.lang.IllegalArgumentException ie) {} + try { AnyConverter.toInt(anyFloat); fail(); + } catch (com.sun.star.lang.IllegalArgumentException ie) {} + try { AnyConverter.toInt(aDouble); fail(); + } catch (com.sun.star.lang.IllegalArgumentException ie) {} + try { AnyConverter.toInt(anyDouble); fail(); + } catch (com.sun.star.lang.IllegalArgumentException ie) {} + try { AnyConverter.toInt(aObj); fail(); + } catch (com.sun.star.lang.IllegalArgumentException ie) {} + try { AnyConverter.toInt(aStr); fail(); + } catch (com.sun.star.lang.IllegalArgumentException ie) {} + try { AnyConverter.toInt(anyStr); fail(); + } catch (com.sun.star.lang.IllegalArgumentException ie) {} + try { AnyConverter.toInt(aType); fail(); + } catch (com.sun.star.lang.IllegalArgumentException ie) {} + try { AnyConverter.toInt(anyType); fail(); + } catch (com.sun.star.lang.IllegalArgumentException ie) {} + try { AnyConverter.toInt(anyVoid); fail(); + } catch (com.sun.star.lang.IllegalArgumentException ie) {} + try { AnyConverter.toInt(arByte); fail(); + } catch (com.sun.star.lang.IllegalArgumentException ie) {} + try { AnyConverter.toInt(anyArByte); fail(); + } catch (com.sun.star.lang.IllegalArgumentException ie) {} + } + + @Test public void test_toLong() + throws com.sun.star.lang.IllegalArgumentException + { + // must work + long val= AnyConverter.toLong(aByte); + assertEquals(val, aByte.byteValue()); + val= AnyConverter.toLong(aShort); + assertEquals(val, aShort.shortValue()); + val= AnyConverter.toLong(aInt); + assertEquals(val, aInt.intValue()); + val= AnyConverter.toLong(aLong); + assertEquals(val, aLong.longValue()); + val= AnyConverter.toLong(anyByte); + assertEquals(val, ((Byte)anyByte.getObject()).byteValue()); + val= AnyConverter.toLong(anyShort); + assertEquals(val, ((Short) anyShort.getObject()).shortValue()); + val= AnyConverter.toLong(anyInt); + assertEquals(val, ((Integer) anyInt.getObject()).intValue()); + val= AnyConverter.toLong(anyLong); + assertEquals(val, ((Long) anyLong.getObject()).longValue()); + Any a = new Any( Type.UNSIGNED_SHORT, Short.valueOf((short)5) ); + assertEquals(5, AnyConverter.toLong(a)); + assertEquals(5, AnyConverter.toUnsignedLong(a)); + a = new Any( Type.UNSIGNED_LONG, Integer.valueOf(5) ); + assertEquals(5, AnyConverter.toUnsignedLong(a)); + assertEquals(5, AnyConverter.toLong(a)); + a = new Any( Type.UNSIGNED_HYPER, Long.valueOf(5) ); + assertEquals(5, AnyConverter.toUnsignedLong(a)); + + // must fail + try { AnyConverter.toUnsignedLong(anyShort); fail(); + } catch (com.sun.star.lang.IllegalArgumentException ie) {} + try { AnyConverter.toUnsignedLong(anyInt); fail(); + } catch (com.sun.star.lang.IllegalArgumentException ie) {} + try { AnyConverter.toLong(a); fail(); + } catch (com.sun.star.lang.IllegalArgumentException ie) {} + try { AnyConverter.toUnsignedLong(anyLong); fail(); + } catch (com.sun.star.lang.IllegalArgumentException ie) {} + try { AnyConverter.toLong(aChar); fail(); + } catch (com.sun.star.lang.IllegalArgumentException ie) {} + try { AnyConverter.toLong(anyChar); fail(); + } catch (com.sun.star.lang.IllegalArgumentException ie) {} + try { AnyConverter.toLong(aBool); fail(); + } catch (com.sun.star.lang.IllegalArgumentException ie) {} + try { AnyConverter.toLong(anyBool); fail(); + } catch (com.sun.star.lang.IllegalArgumentException ie) {} + try { AnyConverter.toLong(aFloat); fail(); + } catch (com.sun.star.lang.IllegalArgumentException ie) {} + try { AnyConverter.toLong(anyFloat); fail(); + } catch (com.sun.star.lang.IllegalArgumentException ie) {} + try { AnyConverter.toLong(aDouble); fail(); + } catch (com.sun.star.lang.IllegalArgumentException ie) {} + try { AnyConverter.toLong(anyDouble); fail(); + } catch (com.sun.star.lang.IllegalArgumentException ie) {} + try { AnyConverter.toLong(aObj); fail(); + } catch (com.sun.star.lang.IllegalArgumentException ie) {} + try { AnyConverter.toLong(aStr); fail(); + } catch (com.sun.star.lang.IllegalArgumentException ie) {} + try { AnyConverter.toLong(anyStr); fail(); + } catch (com.sun.star.lang.IllegalArgumentException ie) {} + try { AnyConverter.toLong(aType); fail(); + } catch (com.sun.star.lang.IllegalArgumentException ie) {} + try { AnyConverter.toLong(anyType); fail(); + } catch (com.sun.star.lang.IllegalArgumentException ie) {} + try { AnyConverter.toLong(anyVoid); fail(); + } catch (com.sun.star.lang.IllegalArgumentException ie) {} + try { AnyConverter.toLong(arByte); fail(); + } catch (com.sun.star.lang.IllegalArgumentException ie) {} + try { AnyConverter.toLong(anyArByte); fail(); + } catch (com.sun.star.lang.IllegalArgumentException ie) {} + } + + @Test public void test_toFloat() + throws com.sun.star.lang.IllegalArgumentException + { + // must work + float val= AnyConverter.toFloat(aByte); + assertEquals(val, aByte.byteValue(), 0); // 111 = 111.0 + val= AnyConverter.toFloat(anyByte); + assertEquals(val, ((Byte)anyByte.getObject()).byteValue(), 0); + val= AnyConverter.toFloat(aShort); + assertEquals(val, aShort.shortValue(), 0); //11111 = 11111.0 + val= AnyConverter.toFloat(anyShort); + assertEquals(val, ((Short) anyShort.getObject()).shortValue(), 0); + val= AnyConverter.toFloat(aFloat); + assertEquals(val, aFloat.floatValue(), 0); + val= AnyConverter.toFloat(anyFloat); + assertEquals(val, ((Float) anyFloat.getObject()).floatValue(), 0); + + // must fail + try { AnyConverter.toFloat(aChar); fail(); + } catch (com.sun.star.lang.IllegalArgumentException ie) {} + try { AnyConverter.toFloat(anyChar); fail(); + } catch (com.sun.star.lang.IllegalArgumentException ie) {} + try { AnyConverter.toFloat(aBool); fail(); + } catch (com.sun.star.lang.IllegalArgumentException ie) {} + try { AnyConverter.toFloat(anyBool); fail(); + } catch (com.sun.star.lang.IllegalArgumentException ie) {} + try { AnyConverter.toFloat(aInt); fail(); + } catch (com.sun.star.lang.IllegalArgumentException ie) {} + try { AnyConverter.toFloat(anyInt); fail(); + } catch (com.sun.star.lang.IllegalArgumentException ie) {} + try { AnyConverter.toFloat(aLong); fail(); + } catch (com.sun.star.lang.IllegalArgumentException ie) {} + try { AnyConverter.toFloat(anyLong); fail(); + } catch (com.sun.star.lang.IllegalArgumentException ie) {} + try { AnyConverter.toFloat(aDouble); fail(); + } catch (com.sun.star.lang.IllegalArgumentException ie) {} + try { AnyConverter.toFloat(anyDouble); fail(); + } catch (com.sun.star.lang.IllegalArgumentException ie) {} + try { AnyConverter.toFloat(aObj); fail(); + } catch (com.sun.star.lang.IllegalArgumentException ie) {} + try { AnyConverter.toFloat(aStr); fail(); + } catch (com.sun.star.lang.IllegalArgumentException ie) {} + try { AnyConverter.toFloat(anyStr); fail(); + } catch (com.sun.star.lang.IllegalArgumentException ie) {} + try { AnyConverter.toFloat(aType); fail(); + } catch (com.sun.star.lang.IllegalArgumentException ie) {} + try { AnyConverter.toFloat(anyType); fail(); + } catch (com.sun.star.lang.IllegalArgumentException ie) {} + try { AnyConverter.toFloat(anyVoid); fail(); + } catch (com.sun.star.lang.IllegalArgumentException ie) {} + try { AnyConverter.toFloat(arByte); fail(); + } catch (com.sun.star.lang.IllegalArgumentException ie) {} + try { AnyConverter.toFloat(anyArByte); fail(); + } catch (com.sun.star.lang.IllegalArgumentException ie) {} + } + + @Test public void test_toDouble() + throws com.sun.star.lang.IllegalArgumentException + { + // must work + double val= AnyConverter.toDouble(aByte); + assertEquals(val, aByte.byteValue(), 0); // 111 = 111.0 + val= AnyConverter.toDouble(anyByte); + assertEquals(val, ((Byte)anyByte.getObject()).byteValue(), 0); + val= AnyConverter.toDouble(aShort); + assertEquals(val, aShort.shortValue(), 0); //11111 = 11111.0 + val= AnyConverter.toDouble(anyShort); + assertEquals(val, ((Short) anyShort.getObject()).shortValue(), 0); + val= AnyConverter.toDouble(aInt); + assertEquals(val, aInt.intValue(), 0); + val= AnyConverter.toDouble(anyInt); + assertEquals(val, ((Integer) anyInt.getObject()).intValue(), 0); + val= AnyConverter.toDouble(aFloat); + assertEquals(val, aFloat.floatValue(), 0); + val= AnyConverter.toDouble(anyFloat); + float float1= ((Float) anyFloat.getObject()).floatValue(); + assertTrue(val <= (float1 + 0.1) || val >= (float1 - 0.1)); + val= AnyConverter.toDouble(aDouble); + assertEquals(val, aDouble.doubleValue(), 0); + val= AnyConverter.toDouble(anyDouble); + assertEquals(val, ((Double) anyDouble.getObject()).doubleValue(), 0); + + // must fail + try { AnyConverter.toDouble(aChar); fail(); + } catch (com.sun.star.lang.IllegalArgumentException ie) {} + try { AnyConverter.toDouble(anyChar); fail(); + } catch (com.sun.star.lang.IllegalArgumentException ie) {} + try { AnyConverter.toDouble(aBool); fail(); + } catch (com.sun.star.lang.IllegalArgumentException ie) {} + try { AnyConverter.toDouble(anyBool); fail(); + } catch (com.sun.star.lang.IllegalArgumentException ie) {} + try { AnyConverter.toDouble(aLong); fail(); + } catch (com.sun.star.lang.IllegalArgumentException ie) {} + try { AnyConverter.toDouble(anyLong); fail(); + } catch (com.sun.star.lang.IllegalArgumentException ie) {} + try { AnyConverter.toDouble(aObj); fail(); + } catch (com.sun.star.lang.IllegalArgumentException ie) {} + try { AnyConverter.toDouble(aStr); fail(); + } catch (com.sun.star.lang.IllegalArgumentException ie) {} + try { AnyConverter.toDouble(anyStr); fail(); + } catch (com.sun.star.lang.IllegalArgumentException ie) {} + try { AnyConverter.toDouble(aType); fail(); + } catch (com.sun.star.lang.IllegalArgumentException ie) {} + try { AnyConverter.toDouble(anyType); fail(); + } catch (com.sun.star.lang.IllegalArgumentException ie) {} + try { AnyConverter.toDouble(anyVoid); fail(); + } catch (com.sun.star.lang.IllegalArgumentException ie) {} + try { AnyConverter.toDouble(arByte); fail(); + } catch (com.sun.star.lang.IllegalArgumentException ie) {} + try { AnyConverter.toDouble(anyArByte); fail(); + } catch (com.sun.star.lang.IllegalArgumentException ie) {} + } + + @Test public void test_toObject() + throws com.sun.star.lang.IllegalArgumentException + { + // must work + Type _type= new Type(XTypeProvider.class); + Object val= AnyConverter.toObject(_type, aObj); + assertTrue(UnoRuntime.areSame(val, aObj)); + val= AnyConverter.toObject( + _type, new Any( new Type(XTypeProvider.class), null)); + assertNull(val); + + // structs, exceptions + com.sun.star.lang.IllegalArgumentException exc = + new com.sun.star.lang.IllegalArgumentException(); + Any any_exc = new Any( + new Type("com.sun.star.lang.IllegalArgumentException", + TypeClass.EXCEPTION), exc); + assertEquals( + exc, + AnyConverter.toObject( + new Type(com.sun.star.lang.IllegalArgumentException.class), + any_exc)); + assertEquals( + exc, + AnyConverter.toObject( + new Type(com.sun.star.uno.RuntimeException.class), any_exc)); + try { + AnyConverter.toObject( + new Type(com.sun.star.uno.Exception.class), any_exc); + fail(); + } catch (com.sun.star.lang.IllegalArgumentException ie) {} + any_exc = new Any(com.sun.star.lang.IllegalArgumentException.class, + exc); + assertEquals( + exc, + AnyConverter.toObject( + new Type(com.sun.star.lang.IllegalArgumentException.class), + any_exc)); + assertEquals( + exc, + AnyConverter.toObject( + new Type(com.sun.star.uno.RuntimeException.class), any_exc)); + try { + AnyConverter.toObject( + new Type(com.sun.star.uno.Exception.class), any_exc); + fail(); + } catch (com.sun.star.lang.IllegalArgumentException ie) {} + + // must fail + try { AnyConverter.toObject(_type, aType); fail(); + } catch (com.sun.star.lang.IllegalArgumentException ie) {} + try { AnyConverter.toObject(_type, anyType); fail(); + } catch (com.sun.star.lang.IllegalArgumentException ie) {} + try { AnyConverter.toObject(_type, anyVoid); fail(); + } catch (com.sun.star.lang.IllegalArgumentException ie) {} + try { AnyConverter.toObject(_type, new Object()); fail(); + } catch (com.sun.star.lang.IllegalArgumentException ie) {} + } + + @Test public void test_toString() + throws com.sun.star.lang.IllegalArgumentException + { + // must work + String val= AnyConverter.toString(aStr); + assertEquals(val, aStr); + val= AnyConverter.toString(anyStr); + assertEquals(val, anyStr.getObject()); + + // must fail + try { AnyConverter.toString(aBool); fail(); + } catch (com.sun.star.lang.IllegalArgumentException ie) {} + try { AnyConverter.toString(anyBool); fail(); + } catch (com.sun.star.lang.IllegalArgumentException ie) {} + try { AnyConverter.toString(aChar); fail(); + } catch (com.sun.star.lang.IllegalArgumentException ie) {} + try { AnyConverter.toString(anyChar); fail(); + } catch (com.sun.star.lang.IllegalArgumentException ie) {} + try { AnyConverter.toString(aByte); fail(); + } catch (com.sun.star.lang.IllegalArgumentException ie) {} + try { AnyConverter.toString(anyByte); fail(); + } catch (com.sun.star.lang.IllegalArgumentException ie) {} + try { AnyConverter.toString(aShort); fail(); + } catch (com.sun.star.lang.IllegalArgumentException ie) {} + try { AnyConverter.toString(anyShort); fail(); + } catch (com.sun.star.lang.IllegalArgumentException ie) {} + try { AnyConverter.toString(aInt); fail(); + } catch (com.sun.star.lang.IllegalArgumentException ie) {} + try { AnyConverter.toString(anyInt); fail(); + } catch (com.sun.star.lang.IllegalArgumentException ie) {} + try { AnyConverter.toString(aLong); fail(); + } catch (com.sun.star.lang.IllegalArgumentException ie) {} + try { AnyConverter.toString(anyLong); fail(); + } catch (com.sun.star.lang.IllegalArgumentException ie) {} + try { AnyConverter.toString(aFloat); fail(); + } catch (com.sun.star.lang.IllegalArgumentException ie) {} + try { AnyConverter.toString(anyFloat); fail(); + } catch (com.sun.star.lang.IllegalArgumentException ie) {} + try { AnyConverter.toString(aDouble); fail(); + } catch (com.sun.star.lang.IllegalArgumentException ie) {} + try { AnyConverter.toString(anyDouble); fail(); + } catch (com.sun.star.lang.IllegalArgumentException ie) {} + try { AnyConverter.toString(aObj); fail(); + } catch (com.sun.star.lang.IllegalArgumentException ie) {} + try { AnyConverter.toString(aType); fail(); + } catch (com.sun.star.lang.IllegalArgumentException ie) {} + try { AnyConverter.toString(anyType); fail(); + } catch (com.sun.star.lang.IllegalArgumentException ie) {} + try { AnyConverter.toString(anyVoid); fail(); + } catch (com.sun.star.lang.IllegalArgumentException ie) {} + try { AnyConverter.toString(arByte); fail(); + } catch (com.sun.star.lang.IllegalArgumentException ie) {} + try { AnyConverter.toString(anyArByte); fail(); + } catch (com.sun.star.lang.IllegalArgumentException ie) {} + } + + @Test public void test_toType() + throws com.sun.star.lang.IllegalArgumentException + { + // must work + Type val= AnyConverter.toType(aType); + assertSame(val, aType); + val= AnyConverter.toType(anyType); + assertSame(val, anyType.getObject()); + + // must fail + try { AnyConverter.toType(aBool); fail(); + } catch (com.sun.star.lang.IllegalArgumentException ie) {} + try { AnyConverter.toType(anyBool); fail(); + } catch (com.sun.star.lang.IllegalArgumentException ie) {} + try { AnyConverter.toType(aChar); fail(); + } catch (com.sun.star.lang.IllegalArgumentException ie) {} + try { AnyConverter.toType(anyChar); fail(); + } catch (com.sun.star.lang.IllegalArgumentException ie) {} + try { AnyConverter.toType(aByte); fail(); + } catch (com.sun.star.lang.IllegalArgumentException ie) {} + try { AnyConverter.toType(anyByte); fail(); + } catch (com.sun.star.lang.IllegalArgumentException ie) {} + try { AnyConverter.toType(aShort); fail(); + } catch (com.sun.star.lang.IllegalArgumentException ie) {} + try { AnyConverter.toType(anyShort); fail(); + } catch (com.sun.star.lang.IllegalArgumentException ie) {} + try { AnyConverter.toType(aInt); fail(); + } catch (com.sun.star.lang.IllegalArgumentException ie) {} + try { AnyConverter.toType(anyInt); fail(); + } catch (com.sun.star.lang.IllegalArgumentException ie) {} + try { AnyConverter.toType(aLong); fail(); + } catch (com.sun.star.lang.IllegalArgumentException ie) {} + try { AnyConverter.toType(anyLong); fail(); + } catch (com.sun.star.lang.IllegalArgumentException ie) {} + try { AnyConverter.toType(aFloat); fail(); + } catch (com.sun.star.lang.IllegalArgumentException ie) {} + try { AnyConverter.toType(anyFloat); fail(); + } catch (com.sun.star.lang.IllegalArgumentException ie) {} + try { AnyConverter.toType(aDouble); fail(); + } catch (com.sun.star.lang.IllegalArgumentException ie) {} + try { AnyConverter.toType(anyDouble); fail(); + } catch (com.sun.star.lang.IllegalArgumentException ie) {} + try { AnyConverter.toType(aObj); fail(); + } catch (com.sun.star.lang.IllegalArgumentException ie) {} + try { AnyConverter.toType(aStr); fail(); + } catch (com.sun.star.lang.IllegalArgumentException ie) {} + try { AnyConverter.toType(anyStr); fail(); + } catch (com.sun.star.lang.IllegalArgumentException ie) {} + try { AnyConverter.toType(anyVoid); fail(); + } catch (com.sun.star.lang.IllegalArgumentException ie) {} + try { AnyConverter.toType(arByte); fail(); + } catch (com.sun.star.lang.IllegalArgumentException ie) {} + try { AnyConverter.toType(anyArByte); fail(); + } catch (com.sun.star.lang.IllegalArgumentException ie) {} + } + + @Test public void test_toArray() + throws com.sun.star.lang.IllegalArgumentException + { + // must work + Object val= AnyConverter.toArray(arByte); + assertSame(val, arByte); + val= AnyConverter.toArray(anyArByte); + assertSame(val, anyArByte.getObject()); + + // must fail + try { AnyConverter.toType(aBool); fail(); + } catch (com.sun.star.lang.IllegalArgumentException ie) {} + try { AnyConverter.toType(anyBool); fail(); + } catch (com.sun.star.lang.IllegalArgumentException ie) {} + try { AnyConverter.toType(aChar); fail(); + } catch (com.sun.star.lang.IllegalArgumentException ie) {} + try { AnyConverter.toType(anyChar); fail(); + } catch (com.sun.star.lang.IllegalArgumentException ie) {} + try { AnyConverter.toType(aByte); fail(); + } catch (com.sun.star.lang.IllegalArgumentException ie) {} + try { AnyConverter.toType(anyByte); fail(); + } catch (com.sun.star.lang.IllegalArgumentException ie) {} + try { AnyConverter.toType(aShort); fail(); + } catch (com.sun.star.lang.IllegalArgumentException ie) {} + try { AnyConverter.toType(anyShort); fail(); + } catch (com.sun.star.lang.IllegalArgumentException ie) {} + try { AnyConverter.toType(aInt); fail(); + } catch (com.sun.star.lang.IllegalArgumentException ie) {} + try { AnyConverter.toType(anyInt); fail(); + } catch (com.sun.star.lang.IllegalArgumentException ie) {} + try { AnyConverter.toType(aLong); fail(); + } catch (com.sun.star.lang.IllegalArgumentException ie) {} + try { AnyConverter.toType(anyLong); fail(); + } catch (com.sun.star.lang.IllegalArgumentException ie) {} + try { AnyConverter.toType(aFloat); fail(); + } catch (com.sun.star.lang.IllegalArgumentException ie) {} + try { AnyConverter.toType(anyFloat); fail(); + } catch (com.sun.star.lang.IllegalArgumentException ie) {} + try { AnyConverter.toType(aDouble); fail(); + } catch (com.sun.star.lang.IllegalArgumentException ie) {} + try { AnyConverter.toType(anyDouble); fail(); + } catch (com.sun.star.lang.IllegalArgumentException ie) {} + try { AnyConverter.toType(aObj); fail(); + } catch (com.sun.star.lang.IllegalArgumentException ie) {} + try { AnyConverter.toType(aStr); fail(); + } catch (com.sun.star.lang.IllegalArgumentException ie) {} + try { AnyConverter.toType(anyStr); fail(); + } catch (com.sun.star.lang.IllegalArgumentException ie) {} + try { AnyConverter.toType(anyVoid); fail(); + } catch (com.sun.star.lang.IllegalArgumentException ie) {} + try { AnyConverter.toType(arByte); fail(); + } catch (com.sun.star.lang.IllegalArgumentException ie) {} + try { AnyConverter.toType(anyArByte); fail(); + } catch (com.sun.star.lang.IllegalArgumentException ie) {} + } + + @Test public void test_isBoolean() { + assertTrue(AnyConverter.isBoolean(aBool)); + assertTrue(AnyConverter.isBoolean(anyBool)); + assertFalse(AnyConverter.isBoolean(aChar)); + } + + @Test public void test_isChar() { + assertTrue(AnyConverter.isChar(aChar)); + assertTrue(AnyConverter.isChar(anyChar)); + assertFalse(AnyConverter.isChar(aBool)); + } + + @Test public void test_isByte() { + assertTrue(AnyConverter.isByte(aByte)); + assertTrue(AnyConverter.isByte(anyByte)); + assertFalse(AnyConverter.isByte(aBool)); + } + + @Test public void test_isShort() { + assertTrue(AnyConverter.isShort(aShort)); + assertTrue(AnyConverter.isShort(anyShort)); + assertEquals(Type.SHORT, AnyConverter.getType(anyShort)); + Any a = new Any( Type.UNSIGNED_SHORT, Short.valueOf((short)5) ); + assertEquals(Type.UNSIGNED_SHORT, AnyConverter.getType(a)); + assertFalse(AnyConverter.isShort(a)); + assertFalse(Type.SHORT.equals(AnyConverter.getType(a))); + assertFalse(AnyConverter.isShort(aBool)); + } + + @Test public void test_isInt() { + assertTrue(AnyConverter.isInt(aInt)); + assertTrue(AnyConverter.isInt(anyInt)); + assertEquals(Type.LONG, AnyConverter.getType(anyInt)); + Any a = new Any(Type.UNSIGNED_LONG, Integer.valueOf(5)); + assertEquals(Type.UNSIGNED_LONG, AnyConverter.getType(a)); + assertFalse(AnyConverter.isInt(a)); + assertFalse(Type.LONG.equals(AnyConverter.getType(a))); + assertFalse(AnyConverter.isInt(aBool)); + } + + @Test public void test_isLong() { + assertTrue(AnyConverter.isLong(aLong)); + assertTrue(AnyConverter.isLong(anyLong)); + assertEquals(Type.HYPER, AnyConverter.getType(anyLong)); + Any a = new Any( Type.UNSIGNED_HYPER, Long.valueOf(5) ); + assertEquals(Type.UNSIGNED_HYPER, AnyConverter.getType(a)); + assertFalse(AnyConverter.isLong(a)); + assertFalse(Type.HYPER.equals( AnyConverter.getType(a) )); + assertFalse(AnyConverter.isLong(aBool)); + } + + @Test public void test_isFloat() { + assertTrue(AnyConverter.isFloat(aFloat)); + assertTrue(AnyConverter.isFloat(anyFloat)); + assertFalse(AnyConverter.isFloat(aDouble)); + } + + @Test public void test_isDouble() { + assertTrue(AnyConverter.isDouble(aDouble)); + assertTrue(AnyConverter.isDouble(anyDouble)); + assertFalse(AnyConverter.isDouble(aFloat)); + } + + @Test public void test_isObject() { + assertTrue(AnyConverter.isObject(aObj)); + assertTrue(AnyConverter.isObject( new Any( XInterface.class, null))); + assertFalse(AnyConverter.isObject(new Object())); + } + + @Test public void test_isString() { + assertTrue(AnyConverter.isString(aStr)); + assertTrue(AnyConverter.isString(anyStr)); + assertFalse(AnyConverter.isString(new Object())); + } + + @Test public void test_isType() { + assertTrue(AnyConverter.isType(aType)); + assertTrue(AnyConverter.isType(anyType)); + assertFalse(AnyConverter.isType(new Object())); + } + + @Test public void test_isArray() { + assertTrue(AnyConverter.isArray(arByte)); + assertTrue(AnyConverter.isArray(anyArByte)); + assertFalse(AnyConverter.isArray(new Object())); + } + + @Test public void test_isVoid() { + assertTrue(AnyConverter.isVoid(anyVoid)); + assertFalse(AnyConverter.isVoid(new Object())); + } +} + + +class ATypeProvider implements com.sun.star.lang.XTypeProvider +{ + + public byte[] getImplementationId() + { + return new byte[0]; + } + + public com.sun.star.uno.Type[] getTypes() + { + return new Type[]{new Type(XTypeProvider.class)}; + } + +} + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/ridljar/test/com/sun/star/uno/Any_Test.java b/ridljar/test/com/sun/star/uno/Any_Test.java new file mode 100644 index 000000000..6dc3a15b1 --- /dev/null +++ b/ridljar/test/com/sun/star/uno/Any_Test.java @@ -0,0 +1,48 @@ +/* + * 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.logging.Level; +import java.util.logging.Logger; +import org.junit.Test; +import static org.junit.Assert.*; + +public final class Any_Test { + + private static final Logger logger = Logger.getLogger(Any_Test.class.getName()); + + @Test public void testAnyAny() { + try { + new Any(Type.ANY, null); + fail("IllegalArgumentException expected"); + } catch (IllegalArgumentException e) { + logger.log(Level.FINE, "IllegalArgumentException caught"); + } + } + + @Test public void testComplete() { + assertSame(Any.VOID, Any.complete(Any.VOID)); + assertEquals( + new Any(Type.LONG, Integer.valueOf(10)), Any.complete(Integer.valueOf(10))); + assertEquals( + new Any(new Type(XInterface.class), null), Any.complete(null)); + XInterface x = new XInterface() {}; + assertEquals(new Any(new Type(XInterface.class), x), Any.complete(x)); + } +} diff --git a/ridljar/test/com/sun/star/uno/Type_Test.java b/ridljar/test/com/sun/star/uno/Type_Test.java new file mode 100644 index 000000000..1499b8230 --- /dev/null +++ b/ridljar/test/com/sun/star/uno/Type_Test.java @@ -0,0 +1,104 @@ +/* + * 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 org.junit.Test; +import static org.junit.Assert.*; + +public final class Type_Test { + @Test public void testZClass() { + assertSame("VOID", void.class, new Type("void").getZClass()); + assertSame("BOOLEAN", boolean.class, new Type("boolean").getZClass()); + assertSame("BYTE", byte.class, new Type("byte").getZClass()); + assertSame("SHORT", short.class, new Type("short").getZClass()); + assertSame( + "UNSIGNED SHORT", short.class, + new Type("unsigned short").getZClass()); + assertSame("LONG", int.class, new Type("long").getZClass()); + assertSame( + "UNSIGNED LONG", int.class, new Type("unsigned long").getZClass()); + assertSame("HYPER", long.class, new Type("hyper").getZClass()); + assertSame( + "UNSIGNED HYPER", long.class, + new Type("unsigned hyper").getZClass()); + assertSame("FLOAT", float.class, new Type("float").getZClass()); + assertSame("DOUBLE", double.class, new Type("double").getZClass()); + assertSame("CHAR", char.class, new Type("char").getZClass()); + assertSame("STRING", String.class, new Type("string").getZClass()); + assertSame("TYPE", Type.class, new Type("type").getZClass()); + assertSame("ANY", Object.class, new Type("any").getZClass()); + assertSame( + "sequence of BOOLEAN", boolean[].class, + new Type("[]boolean", TypeClass.SEQUENCE).getZClass()); + assertSame( + "sequence of sequence of XComponentContext", + XComponentContext[][].class, + new Type("[][]com.sun.star.uno.XComponentContext", TypeClass.SEQUENCE).getZClass()); + assertSame( + "enum TypeClass", TypeClass.class, + new Type("com.sun.star.uno.TypeClass", TypeClass.ENUM).getZClass()); + assertSame( + "struct Uik", Uik.class, + new Type("com.sun.star.uno.Uik", TypeClass.STRUCT).getZClass()); + assertSame( + "exception Exception", com.sun.star.uno.Exception.class, + new Type("com.sun.star.uno.Exception", TypeClass.EXCEPTION).getZClass()); + assertSame( + "exception RuntimeException", + com.sun.star.uno.RuntimeException.class, + new Type("com.sun.star.uno.RuntimeException", TypeClass.EXCEPTION).getZClass()); + assertSame( + "exception DeploymentException", DeploymentException.class, + new Type("com.sun.star.uno.DeploymentException", TypeClass.EXCEPTION).getZClass()); + assertSame( + "interface XInterface", XInterface.class, + new Type("com.sun.star.uno.XInterface", TypeClass.INTERFACE).getZClass()); + assertSame( + "interface XComponentContext", XComponentContext.class, + new Type("com.sun.star.uno.XComponentContext", TypeClass.INTERFACE). getZClass()); + + assertSame(boolean.class, new Type(boolean.class).getZClass()); + assertSame(boolean.class, new Type(Boolean.class).getZClass()); + assertSame(boolean[].class, new Type(boolean[].class).getZClass()); + + try { + new Type(Boolean[].class); + fail(); + } catch (java.lang.RuntimeException e) {} + } + + @Test public void testIsSupertypeOf() { + Type ifc = new Type(com.sun.star.uno.XInterface.class); + Type ctx = new Type(com.sun.star.uno.XComponentContext.class); + Type exc = new Type(com.sun.star.uno.RuntimeException.class); + assertTrue("LONG :> LONG", Type.LONG.isSupertypeOf(Type.LONG)); + assertFalse("not ANY :> XInterface", Type.ANY.isSupertypeOf(ifc)); + assertTrue("ANY :> ANY", Type.ANY.isSupertypeOf(Type.ANY)); + assertFalse("not ANY :> LONG", Type.ANY.isSupertypeOf(Type.LONG)); + assertFalse("not XInterface :> ANY", ifc.isSupertypeOf(Type.ANY)); + assertTrue("XInterface :> XInterface", ifc.isSupertypeOf(ifc)); + assertTrue("XInterface :> XComponentContext", ifc.isSupertypeOf(ctx)); + assertFalse( + "not XComponentContext :> XInterface", ctx.isSupertypeOf(ifc)); + assertTrue( + "XComponentContext :> XComponentContext", ctx.isSupertypeOf(ctx)); + assertFalse( + "not XInterface :> RuntimeException", ifc.isSupertypeOf(exc)); + } +} diff --git a/ridljar/test/com/sun/star/uno/UnoRuntime_EnvironmentTest.java b/ridljar/test/com/sun/star/uno/UnoRuntime_EnvironmentTest.java new file mode 100644 index 000000000..b10adf12e --- /dev/null +++ b/ridljar/test/com/sun/star/uno/UnoRuntime_EnvironmentTest.java @@ -0,0 +1,85 @@ +/* -*- 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; + +import com.sun.star.comp.connections.PipedConnection; +import org.junit.Test; +import util.WaitUnreachable; +import static org.junit.Assert.*; + +public final class UnoRuntime_EnvironmentTest { + @Test public void test_getEnvironment() throws java.lang.Exception { + Object o1 = new Object(); + Object o2 = new Object(); + + // get two environments with different contexts + WaitUnreachable java_environment1 = new WaitUnreachable( + UnoRuntime.getEnvironment("java", o1)); + WaitUnreachable java_environment2 = new WaitUnreachable( + UnoRuntime.getEnvironment("java", o2)); + + // ensure that the environments are different + assertNotSame(java_environment1.get(), java_environment2.get()); + + // test if we get the same environment when we reget it + assertTrue( + UnoRuntime.areSame( + java_environment1.get(), + UnoRuntime.getEnvironment("java", o1))); + assertTrue( + UnoRuntime.areSame( + java_environment2.get(), + UnoRuntime.getEnvironment("java", o2))); + + // drop the environments and wait until they are gc + java_environment1.waitUnreachable(); + java_environment2.waitUnreachable(); + } + + @Test public void test_getBridge() throws java.lang.Exception { + PipedConnection conn = new PipedConnection(new Object[0]); + new PipedConnection(new Object[] { conn }); + + // get a bridge + IBridge iBridge = UnoRuntime.getBridgeByName( + "java", null, "remote", "testname", + new Object[] { "urp", conn, null }); + + // reget the bridge, it must be the same as above + IBridge iBridge_tmp = UnoRuntime.getBridgeByName( + "java", null, "remote", "testname", + new Object[] { "urp", conn, null }); + assertTrue(UnoRuntime.areSame(iBridge_tmp, iBridge)); + + // dispose the bridge, this removes the entry from the runtime + iBridge.dispose(); + + conn = new PipedConnection(new Object[0]); + new PipedConnection(new Object[] { conn }); + + // reget the bridge, it must be a different one + iBridge_tmp = UnoRuntime.getBridgeByName( + "java", null, "remote", "testname", + new Object[]{ "urp", conn, null }); + assertFalse(UnoRuntime.areSame(iBridge_tmp, iBridge)); + } +} + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/ridljar/test/com/sun/star/uno/UnoRuntime_Test.java b/ridljar/test/com/sun/star/uno/UnoRuntime_Test.java new file mode 100644 index 000000000..fb2afe8ae --- /dev/null +++ b/ridljar/test/com/sun/star/uno/UnoRuntime_Test.java @@ -0,0 +1,196 @@ +/* + * 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 com.sun.star.beans.Optional; +import org.junit.Test; +import static org.junit.Assert.*; + +public final class UnoRuntime_Test { + @Test public void test_generateOid() { + // Test if UnoRuntime generates an OID for a simple class: + assertNotNull("Test1", UnoRuntime.generateOid(new Test1())); + + // Test if UnoRuntime generates an OID for a class implementing + // IQueryInterface and returning null from getOid: + assertNotNull("Test2", UnoRuntime.generateOid(new Test2())); + + // Test if a delegator object has the same OID as its creator: + Test4 test4 = new Test4(); + Ifc ifc = UnoRuntime.queryInterface(Ifc.class, test4); + assertEquals( + "Test4", UnoRuntime.generateOid(ifc), + UnoRuntime.generateOid(test4)); + } + + @Test public void test_queryInterface() { + // Test if a query for an interface which is not supported returns null: + assertNull("Test1", UnoRuntime.queryInterface(Ifc.class, new Test1())); + + // Test if a query for an interface which is supported through + // IQueryInterface succeeds: + assertNotNull( + "Test2", UnoRuntime.queryInterface(Ifc.class, new Test2())); + + // Test if a query for an interface which is directly supported (through + // inheritance) succeeds: + assertNotNull( + "Test3", UnoRuntime.queryInterface(Ifc.class, new Test3())); + } + + @Test public void test_areSame() { + assertTrue( + UnoRuntime.areSame( + new Any(Type.UNSIGNED_LONG, Integer.valueOf(3)), + new Any(Type.UNSIGNED_LONG, Integer.valueOf(3)))); + assertFalse( + UnoRuntime.areSame( + new Any(Type.UNSIGNED_LONG, Integer.valueOf(3)), Integer.valueOf(3))); + assertFalse(UnoRuntime.areSame(new int[] { 1 }, new int[] { 1, 2 })); + assertTrue( + UnoRuntime.areSame( + TypeClass.UNSIGNED_LONG, + new Any(new Type(TypeClass.class), TypeClass.UNSIGNED_LONG))); + assertTrue( + UnoRuntime.areSame( + new Any( + new Type("com.sun.star.beans.Optional"), + new Optional()), + new Any( + new Type("com.sun.star.beans.Optional"), + new Optional(false, Integer.valueOf(0))))); + assertFalse(UnoRuntime.areSame(new Test1(), new Test2())); + Test2 test2 = new Test2(); + assertTrue( + "Test2", + UnoRuntime.areSame( + UnoRuntime.queryInterface(Ifc.class, test2), test2)); + } + + @SuppressWarnings("rawtypes") + @Test public void test_completeValue() { + assertEquals( + Integer.valueOf(0), UnoRuntime.completeValue(Type.UNSIGNED_LONG, null)); + Object v = UnoRuntime.completeValue( + new Type("[][]unsigned long"), null); + assertTrue(v instanceof int[][]); + assertEquals(0, ((int[][]) v).length); + assertSame( + TypeClass.VOID, + UnoRuntime.completeValue(new Type(TypeClass.class), null)); + v = UnoRuntime.completeValue( + new Type("com.sun.star.beans.Optional"), null); + assertTrue(v instanceof Optional); + assertFalse(((Optional) v).IsPresent); + assertNull(((Optional) v).Value); + } + + @Test public void test_currentContext() throws InterruptedException { + TestThread t1 = new TestThread(); + TestThread t2 = new TestThread(); + t1.start(); + t2.start(); + t1.join(); + t2.join(); + Object v1 = t1.context.getValueByName(""); + Object v2 = t2.context.getValueByName(""); + assertFalse(t1.context == t2.context); + assertSame(v1, t1); + assertSame(v2, t2); + assertNotSame(v1, v2); + } + + private interface Ifc extends XInterface {} + + private static class Test1 {} + + private static class Test2 implements XInterface, IQueryInterface { + public String getOid() { + return null; + } + + public Object queryInterface(Type type) { + return type.equals(new Type(Ifc.class)) ? t2 : null; + } + + public boolean isSame(Object object) { + return object == t2; + } + + private static final class T2 implements Ifc {} + + private final T2 t2 = new T2(); + } + + private static class Test3 implements Ifc {} + + private static class Test4 implements XInterface, IQueryInterface { + public String getOid() { + return null; + } + + public Object queryInterface(Type type) { + return type.equals(new Type(Ifc.class)) ? t4 : null; + } + + public boolean isSame(Object object) { + return object == t4; + } + + private final class T4 implements Ifc, IQueryInterface { + public String getOid() { + return UnoRuntime.generateOid(Test4.this); + } + + public Object queryInterface(Type type) { + return Test4.this.queryInterface(type); + } + + public boolean isSame(Object object) { + return UnoRuntime.areSame(Test4.this, object); + } + } + + private final T4 t4 = new T4(); + } + + private final class TestThread extends Thread { + @Override + public void run() { + //TODO: JUnit does not notice if these asserts fail: + assertNull(UnoRuntime.getCurrentContext()); + context = new TestCurrentContext(); + UnoRuntime.setCurrentContext(context); + assertSame(context, UnoRuntime.getCurrentContext()); + assertSame(this, context.getValueByName("")); + UnoRuntime.setCurrentContext(null); + assertNull(UnoRuntime.getCurrentContext()); + } + + public XCurrentContext context = null; + } + + private static final class TestCurrentContext implements XCurrentContext { + public Object getValueByName(String name) { + return value; + } + + private final Object value = Thread.currentThread(); + } +} diff --git a/ridljar/test/com/sun/star/uno/WeakReference_Test.java b/ridljar/test/com/sun/star/uno/WeakReference_Test.java new file mode 100644 index 000000000..960c05dad --- /dev/null +++ b/ridljar/test/com/sun/star/uno/WeakReference_Test.java @@ -0,0 +1,107 @@ +/* -*- 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; + +import java.util.ArrayList; +import java.util.Iterator; +import org.junit.Test; +import util.WaitUnreachable; +import static org.junit.Assert.*; + +public final class WeakReference_Test { + @Test public void test() { + Object o = new MockWeak(); + WeakReference r1 = new WeakReference(o); + WeakReference r2 = new WeakReference(r1); + assertSame(o, r1.get()); + assertSame(o, r2.get()); + WaitUnreachable u = new WaitUnreachable(o); + o = null; + u.waitUnreachable(); + assertNull("a3", r1.get()); + assertNull("a4", r2.get()); + } + + private static final class MockWeak implements XWeak { + public XAdapter queryAdapter() { + return adapter; + } + + @Override + protected void finalize() throws Throwable { + adapter.dispose(); + super.finalize(); + } + + private static final class Adapter implements XAdapter { + public Adapter(Object obj) { + ref = new java.lang.ref.WeakReference(obj); + } + + public Object queryAdapted() { + return ref.get(); + } + + public void addReference(XReference ref) { + synchronized (this) { + if (listeners != null) { + listeners.add(ref); + return; + } + } + ref.dispose(); + } + + public synchronized void removeReference(XReference ref) { + if (listeners != null) { + listeners.remove(ref); + } + } + + public void dispose() { + ArrayList l; + synchronized (this){ + l = listeners; + listeners = null; + } + if (l != null) { + java.lang.RuntimeException ex = null; + for (Iterator i = l.iterator(); i.hasNext();) { + try { + i.next().dispose(); + } catch (java.lang.RuntimeException e) { + ex = e; + } + } + if (ex != null) { + throw ex; + } + } + } + + private final java.lang.ref.WeakReference ref; + private ArrayList listeners = new ArrayList(); + } + + private final Adapter adapter = new Adapter(this); + } +} + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/ridljar/util/manifest b/ridljar/util/manifest new file mode 100644 index 000000000..bb1209f90 --- /dev/null +++ b/ridljar/util/manifest @@ -0,0 +1,46 @@ +Sealed: false + +Name: com/sun/star/comp/bridgefactory/ +Sealed: true + +Name: com/sun/star/comp/connections/ +Sealed: true + +Name: com/sun/star/comp/helper +Sealed: true + +Name: com/sun/star/comp/loader/ +Sealed: true + +Name: com/sun/star/comp/servicemanager/ +Sealed: true + +Name: com/sun/star/comp/urlresolver/ +Sealed: true + +Name: com/sun/star/lib/connections/pipe/ +Sealed: true + +Name: com/sun/star/lib/connections/socket/ +Sealed: true + +Name: com/sun/star/lib/uno/ +Sealed: true + +Name: com/sun/star/lib/uno/adapter +Sealed: true + +Name: com/sun/star/lib/uno/bridges/java_remote/ +Sealed: true + +Name: com/sun/star/lib/uno/environments/java/ +Sealed: true + +Name: com/sun/star/lib/uno/environments/remote/ +Sealed: true + +Name: com/sun/star/lib/uno/helper +Sealed: true + +Name: com/sun/star/lib/uno/protocols/urp/ +Sealed: true -- cgit v1.2.3