Add a FunctionBasedURPConnection and a websocket URP connector

- FunctionBasedURPConnection is used to enable a client to open a URP
  connection to a fresh Kit instance in COOL.
- This URP connector can be used with that and
  https://github.com/CollaboraOnline/online/pull/6992 to use a Java Uno
  Remote Protocol client over websockets
- For interoperability with existing Collabora Online websockets a
  prefix (urp ) is added to each message sent and a similar prefix
  (urp: ) is expected on each message recieved. This allows sending over
  the same websocket as other data is being transmitted through. If you
  are writing a bridge to work with this, you will need to add/strip the
  prefixes accordingly
- This commit uses Java WebSocket
  (https://github.com/TooTallNate/Java-WebSocket) to send data over
  websockets.

Change-Id: I2bda3d0b988bef7883f9b6829eeb5b7ae8075f27
Signed-off-by: Skyler Grey <skyler.grey@collabora.com>
Reviewed-on: https://gerrit.libreoffice.org/c/core/+/151171
Tested-by: Jenkins
Reviewed-by: Caolán McNamara <caolan.mcnamara@collabora.com>
This commit is contained in:
Skyler Grey 2023-08-18 13:30:35 +00:00 committed by Caolán McNamara
parent cb72f56977
commit 8e246331f6
27 changed files with 1792 additions and 1 deletions

View file

@ -136,6 +136,7 @@ $(WORKDIR)/download: $(BUILDDIR)/config_$(gb_Side).mk $(SRCDIR)/download.lst $(S
$(call fetch_Optional,HYPHEN,HYPHEN_TARBALL) \
$(call fetch_Optional,ICU,ICU_TARBALL) \
$(call fetch_Optional,ICU,ICU_DATA_TARBALL) \
$(call fetch_Optional,JAVA_WEBSOCKET,JAVA_WEBSOCKET_TARBALL) \
$(call fetch_Optional,JFREEREPORT,JFREEREPORT_FLOW_ENGINE_TARBALL) \
$(call fetch_Optional,JFREEREPORT,JFREEREPORT_FLUTE_TARBALL) \
$(call fetch_Optional,JFREEREPORT,JFREEREPORT_LIBBASE_TARBALL) \

View file

@ -3915,6 +3915,17 @@ endef
endif # SYSTEM_JFREEREPORT
# no known distro packaged Java-Websocket at present
ifeq ($(ENABLE_JAVA),TRUE)
$(eval $(call gb_Helper_register_jars_for_install,URE,ure, \
java_websocket \
))
endif
define gb_Jar__use_java_websocket
$(call gb_Jar_use_jar,$(1),java_websocket)
endef
# Executables

View file

@ -12690,6 +12690,17 @@ AC_SUBST(LIBASSUAN_LIBS)
AC_SUBST(GPGMEPP_CFLAGS)
AC_SUBST(GPGMEPP_LIBS)
AC_MSG_CHECKING([whether to build Java Websocket for the UNO remote websocket client])
if test "$with_java" != "no"; then
AC_MSG_RESULT([yes])
ENABLE_JAVA_WEBSOCKET=TRUE
BUILD_TYPE="$BUILD_TYPE JAVA_WEBSOCKET"
else
AC_MSG_RESULT([no])
ENABLE_JAVA_WEBSOCKET=
fi
AC_SUBST(ENABLE_JAVA_WEBSOCKET)
AC_MSG_CHECKING([whether to build the Wiki Publisher extension])
if test "x$enable_ext_wiki_publisher" = "xyes" -a "x$enable_extension_integration" != "xno" -a "$with_java" != "no"; then
AC_MSG_RESULT([yes])

View file

@ -3681,10 +3681,12 @@ void DesktopLOKTest::testABI()
CPPUNIT_ASSERT_EQUAL(classOffset(15), offsetof(struct _LibreOfficeKitClass, dumpState));
CPPUNIT_ASSERT_EQUAL(classOffset(16), offsetof(struct _LibreOfficeKitClass, extractRequest));
CPPUNIT_ASSERT_EQUAL(classOffset(17), offsetof(struct _LibreOfficeKitClass, trimMemory));
CPPUNIT_ASSERT_EQUAL(classOffset(18), offsetof(struct _LibreOfficeKitClass, startURP));
CPPUNIT_ASSERT_EQUAL(classOffset(19), offsetof(struct _LibreOfficeKitClass, stopURP));
// When extending LibreOfficeKit with a new function pointer, add new assert for the offsetof the
// new function pointer and bump this assert for the size of the class.
CPPUNIT_ASSERT_EQUAL(classOffset(18), sizeof(struct _LibreOfficeKitClass));
CPPUNIT_ASSERT_EQUAL(classOffset(20), sizeof(struct _LibreOfficeKitClass));
CPPUNIT_ASSERT_EQUAL(documentClassOffset(0), offsetof(struct _LibreOfficeKitDocumentClass, destroy));
CPPUNIT_ASSERT_EQUAL(documentClassOffset(1), offsetof(struct _LibreOfficeKitDocumentClass, saveAs));

View file

@ -49,6 +49,7 @@
#include <memory>
#include <iostream>
#include <string_view>
#include <queue>
#include <boost/property_tree/json_parser.hpp>
#include <boost/algorithm/string.hpp>
@ -86,6 +87,7 @@
#include <comphelper/servicehelper.hxx>
#include <comphelper/sequenceashashmap.hxx>
#include <com/sun/star/connection/XConnection.hpp>
#include <com/sun/star/document/MacroExecMode.hpp>
#include <com/sun/star/beans/XPropertySet.hpp>
#include <com/sun/star/container/XNameAccess.hpp>
@ -108,6 +110,10 @@
#include <com/sun/star/text/TextContentAnchorType.hpp>
#include <com/sun/star/document/XRedlinesSupplier.hpp>
#include <com/sun/star/ui/GlobalAcceleratorConfiguration.hpp>
#include <com/sun/star/bridge/BridgeFactory.hpp>
#include <com/sun/star/bridge/XBridgeFactory.hpp>
#include <com/sun/star/bridge/XBridge.hpp>
#include <com/sun/star/uno/XNamingService.hpp>
#include <com/sun/star/xml/crypto/SEInitializer.hpp>
#include <com/sun/star/xml/crypto/XSEInitializer.hpp>
@ -121,6 +127,7 @@
#include <com/sun/star/i18n/LocaleCalendar2.hpp>
#include <com/sun/star/i18n/ScriptType.hpp>
#include <com/sun/star/lang/DisposedException.hpp>
#include <com/sun/star/lang/XMultiServiceFactory.hpp>
#include <editeng/flstitem.hxx>
#ifdef IOS
@ -228,6 +235,9 @@ using namespace css;
using namespace vcl;
using namespace desktop;
using namespace utl;
using namespace bridge;
using namespace uno;
using namespace lang;
static LibLibreOffice_Impl *gImpl = nullptr;
static bool lok_preinit_2_called = false;
@ -2567,6 +2577,13 @@ static char* lo_extractRequest(LibreOfficeKit* pThis,
static void lo_trimMemory(LibreOfficeKit* pThis, int nTarget);
static int
lo_startURP(LibreOfficeKit* pThis, void* pReceiveURPFromLOContext, void** pSendURPToLOContext,
int (*fnReceiveURPFromLO)(void* pContext, const signed char* pBuffer, int nLen),
int (**pfnSendURPToLO)(void* pContext, const signed char* pBuffer, int nLen));
static void lo_stopURP(LibreOfficeKit* pThis, void* pSendURPToLOContext);
static void lo_runLoop(LibreOfficeKit* pThis,
LibreOfficeKitPollCallback pPollCallback,
LibreOfficeKitWakeCallback pWakeCallback,
@ -2609,6 +2626,8 @@ LibLibreOffice_Impl::LibLibreOffice_Impl()
m_pOfficeClass->dumpState = lo_dumpState;
m_pOfficeClass->extractRequest = lo_extractRequest;
m_pOfficeClass->trimMemory = lo_trimMemory;
m_pOfficeClass->startURP = lo_startURP;
m_pOfficeClass->stopURP = lo_stopURP;
gOfficeClass = m_pOfficeClass;
}
@ -3160,6 +3179,214 @@ static void lo_trimMemory(LibreOfficeKit* /* pThis */, int nTarget)
}
}
namespace
{
class FunctionBasedURPInstanceProvider
: public ::cppu::WeakImplHelper<css::bridge::XInstanceProvider>
{
private:
css::uno::Reference<css::uno::XComponentContext> m_rContext;
public:
FunctionBasedURPInstanceProvider(
const css::uno::Reference<css::uno::XComponentContext>& rxContext);
// XInstanceProvider
virtual css::uno::Reference<css::uno::XInterface>
SAL_CALL getInstance(const OUString& aName) override;
};
// InstanceProvider
FunctionBasedURPInstanceProvider::FunctionBasedURPInstanceProvider(
const Reference<XComponentContext>& rxContext)
: m_rContext(rxContext)
{
}
Reference<XInterface> FunctionBasedURPInstanceProvider::getInstance(const OUString& aName)
{
Reference<XInterface> rInstance;
if (aName == "StarOffice.ServiceManager")
{
rInstance.set(m_rContext->getServiceManager());
}
else if (aName == "StarOffice.ComponentContext")
{
rInstance = m_rContext;
}
else if (aName == "StarOffice.NamingService")
{
Reference<XNamingService> rNamingService(
m_rContext->getServiceManager()->createInstanceWithContext(
"com.sun.star.uno.NamingService", m_rContext),
UNO_QUERY);
if (rNamingService.is())
{
rNamingService->registerObject("StarOffice.ServiceManager",
m_rContext->getServiceManager());
rNamingService->registerObject("StarOffice.ComponentContext", m_rContext);
rInstance = rNamingService;
}
}
return rInstance;
}
class FunctionBasedURPConnection : public cppu::WeakImplHelper<css::connection::XConnection>
{
public:
explicit FunctionBasedURPConnection(void*, int (*)(void* pContext, const signed char* pBuffer,
int nLen));
~FunctionBasedURPConnection();
// These overridden member functions use "read" and "write" from the point of view of LO,
// i.e. the opposite to how startURP() uses them.
virtual sal_Int32 SAL_CALL read(Sequence<sal_Int8>& aReadBytes,
sal_Int32 nBytesToRead) override;
virtual void SAL_CALL write(const Sequence<sal_Int8>& aData) override;
virtual void SAL_CALL flush() override;
virtual void SAL_CALL close() override;
virtual OUString SAL_CALL getDescription() override;
void setBridge(Reference<XBridge>);
int addClientURPToBuffer(const signed char* pBuffer, int nLen);
void* getContext();
inline static int g_connectionCount = 0;
private:
std::shared_ptr<std::deque<signed char>> m_pBuffer;
void* m_pRecieveFromLOContext;
int (*m_fnReceiveURPFromLO)(void* pContext, const signed char* pBuffer, int nLen);
Reference<XBridge> m_URPBridge;
std::atomic<bool> m_closed = false;
std::condition_variable m_URPInBuffer;
std::mutex m_bufferMutex;
};
FunctionBasedURPConnection::FunctionBasedURPConnection(
void* pRecieveFromLOContext,
int (*fnRecieveFromLO)(void* pContext, const signed char* pBuffer, int nLen))
: m_pBuffer(std::make_shared<std::deque<signed char>>())
, m_pRecieveFromLOContext(pRecieveFromLOContext)
, m_fnReceiveURPFromLO(fnRecieveFromLO)
{
g_connectionCount++;
}
FunctionBasedURPConnection::~FunctionBasedURPConnection()
{
Reference<XComponent> xComp(m_URPBridge, UNO_QUERY_THROW);
xComp->dispose(); // TODO: check this doesn't deadlock
}
int sendURPToLO(void* pContext /* FunctionBasedURPConnection* */, const signed char* pBuffer,
int nLen)
{
return static_cast<FunctionBasedURPConnection*>(pContext)->addClientURPToBuffer(pBuffer, nLen);
}
int FunctionBasedURPConnection::addClientURPToBuffer(const signed char* pBuffer, int nLen)
{
{
std::scoped_lock lock(m_bufferMutex);
if (m_closed)
{
// We can't write URP to a closed connection
SAL_WARN("lok.urp", "A client attempted to write URP to a closed "
"FunctionBasedURPConnection... ignoring");
return 0;
}
m_pBuffer->insert(m_pBuffer->end(), pBuffer, pBuffer + nLen);
}
m_URPInBuffer.notify_one();
return nLen;
}
void* FunctionBasedURPConnection::getContext() { return this; }
sal_Int32 FunctionBasedURPConnection::read(Sequence<sal_Int8>& aReadBytes, sal_Int32 nBytesToRead)
{
if (aReadBytes.getLength() != nBytesToRead)
{
aReadBytes.realloc(nBytesToRead);
}
sal_Int8* result = aReadBytes.getArray();
// As with osl::StreamPipe, we must always read nBytesToRead...
{
std::unique_lock lock(m_bufferMutex);
if (nBytesToRead < 0)
{
return 0;
}
m_URPInBuffer.wait(
lock, [this, nBytesToRead] { return static_cast<sal_Int32>(m_pBuffer->size()) >= nBytesToRead; });
std::copy(m_pBuffer->begin(), m_pBuffer->begin() + nBytesToRead, result);
m_pBuffer->erase(m_pBuffer->begin(), m_pBuffer->begin() + nBytesToRead);
}
return nBytesToRead;
}
void FunctionBasedURPConnection::write(const Sequence<sal_Int8>& aData)
{
m_fnReceiveURPFromLO(m_pRecieveFromLOContext, aData.getConstArray(), aData.getLength());
}
void FunctionBasedURPConnection::flush() {}
void FunctionBasedURPConnection::close()
{
SAL_INFO("lok.urp", "Requested to close FunctionBasedURPConnection");
m_closed = true;
}
OUString FunctionBasedURPConnection::getDescription() { return ""; }
void FunctionBasedURPConnection::setBridge(Reference<XBridge> xBridge) { m_URPBridge = xBridge; }
}
static int
lo_startURP(LibreOfficeKit* /* pThis */, void* pRecieveFromLOContext, void** ppSendToLOContext,
int (*fnReceiveURPFromLO)(void* pContext, const signed char* pBuffer, int nLen),
int (**pfnSendURPToLO)(void* pContext, const signed char* pBuffer, int nLen))
{
// Here we will roughly do what desktop LO does when one passes a command-line switch like
// --accept=socket,port=nnnn;urp;StarOffice.ServiceManager. Except that no listening socket will
// be created. The communication to the URP will be through the fnReceiveURPFromLO and pfnSendURPToLO functions.
rtl::Reference<FunctionBasedURPConnection> connection(
new FunctionBasedURPConnection(pRecieveFromLOContext, fnReceiveURPFromLO));
*pfnSendURPToLO = sendURPToLO;
*ppSendToLOContext = connection->getContext();
Reference<XBridgeFactory> xBridgeFactory = css::bridge::BridgeFactory::create(xContext);
Reference<XInstanceProvider> xInstanceProvider(new FunctionBasedURPInstanceProvider(xContext));
Reference<XBridge> xBridge(xBridgeFactory->createBridge(
"functionurp" + OUString::number(FunctionBasedURPConnection::g_connectionCount), "urp",
connection, xInstanceProvider));
connection->setBridge(std::move(xBridge));
return true;
}
/**
* Stop a function based URP connection that you started with lo_startURP above
*
* @param pSendToLOContext a pointer to the context you got back using your ppSendToLOContext before */
static void lo_stopURP(LibreOfficeKit* /* pThis */,
void* pSendToLOContext /* FunctionBasedURPConnection* */)
{
static_cast<FunctionBasedURPConnection*>(pSendToLOContext)->close();
}
static void lo_registerCallback (LibreOfficeKit* pThis,
LibreOfficeKitCallback pCallback,
void* pData)

View file

@ -249,6 +249,11 @@ ICU_DATA_TARBALL := icu4c-73_2-data.zip
# three static lines
# so that git cherry-pick
# will not run into conflicts
JAVA_WEBSOCKET_SHA256SUM := a6828b35d1f938fee2335945f3d3c563cbbfa58ce7eb0bf72778d0fa7a550720
JAVA_WEBSOCKET_TARBALL := Java-WebSocket-1.5.4.tar.gz
# three static lines
# so that git cherry-pick
# will not run into conflicts
JFREEREPORT_FLOW_ENGINE_SHA256SUM := 233f66e8d25c5dd971716d4200203a612a407649686ef3b52075d04b4c9df0dd
JFREEREPORT_FLOW_ENGINE_TARBALL := ba2930200c9f019c2d93a8c88c651a0f-flow-engine-0.9.4.zip
JFREEREPORT_FLUTE_SHA256SUM := 1b5b24f7bc543c0362b667692f78db8bab4ed6dafc6172f104d0bd3757d8a133

View file

@ -50,6 +50,7 @@ $(eval $(call gb_Module_add_moduledirs,external,\
$(call gb_Helper_optional,HUNSPELL,hunspell) \
$(call gb_Helper_optional,HYPHEN,hyphen) \
$(call gb_Helper_optional,ICU,icu) \
$(call gb_Helper_optional,JAVA_WEBSOCKET,java_websocket) \
$(call gb_Helper_optional,JFREEREPORT,jfreereport) \
$(call gb_Helper_optional,LIBJPEG_TURBO,libjpeg-turbo) \
$(call gb_Helper_optional,LCMS2,lcms2) \

View file

@ -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_ExternalPackage_ExternalPackage,java_websocket_project,java_websocket))
$(eval $(call gb_ExternalPackage_use_external_project,java_websocket_project,java_websocket))
$(eval $(call gb_ExternalPackage_add_file,java_websocket_project,$(LIBO_SHARE_JAVA_FOLDER)/java_websocket.jar,dist/java_websocket.jar))
# vim: set noet sw=4 ts=4:

View file

@ -0,0 +1,31 @@
# -*- 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_ExternalProject_ExternalProject,java_websocket))
$(eval $(call gb_ExternalProject_register_targets,java_websocket,\
build \
))
$(call gb_ExternalProject_get_state_target,java_websocket,build) :
$(call gb_Trace_StartRange,java_websocket,EXTERNAL)
$(call gb_ExternalProject_run,build,\
JAVA_HOME=$(JAVA_HOME_FOR_BUILD) \
$(ICECREAM_RUN) "$(ANT)" \
$(if $(verbose),-v,-q) \
-f build.xml \
-Dbuild.label="build-$(LIBO_VERSION_MAJOR).$(LIBO_VERSION_MINOR).$(LIBO_VERSION_MICRO).$(LIBO_VERSION_PATCH)" \
-Dant.build.javac.source=$(JAVA_SOURCE_VER) \
-Dant.build.javac.target=$(JAVA_TARGET_VER) \
$(if $(debug),-Dbuild.debug="on") \
jar \
)
$(call gb_Trace_EndRange,java_websocket,EXTERNAL)
# vim: set noet sw=4 ts=4:

7
external/java_websocket/Makefile vendored Normal file
View file

@ -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:

View file

@ -0,0 +1,18 @@
# -*- 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,java_websocket))
$(eval $(call gb_Module_add_targets,java_websocket,\
ExternalPackage_java_websocket \
ExternalProject_java_websocket \
UnpackedTarball_java_websocket \
))
# vim: set noet sw=4 ts=4:

3
external/java_websocket/README vendored Normal file
View file

@ -0,0 +1,3 @@
Java WebSocket Implmentation from [https://github.com/TooTallNate/Java-WebSocket].
To send data over websockets, enabling uno over websockets.

View file

@ -0,0 +1,21 @@
# -*- 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_UnpackedTarball_UnpackedTarball,java_websocket))
$(eval $(call gb_UnpackedTarball_set_tarball,java_websocket,$(JAVA_WEBSOCKET_TARBALL),,java_websocket))
$(eval $(call gb_UnpackedTarball_set_patchlevel,java_websocket,1))
$(eval $(call gb_UnpackedTarball_add_patches,java_websocket,\
external/java_websocket/patches/ant-build.patch \
external/java_websocket/patches/no-slf4j.patch \
))
# vim: set noet sw=4 ts=4:

View file

@ -0,0 +1,26 @@
--- /dev/null 1970-01-01 01:00:00.000000000 +0100
+++ b/build.xml 2023-08-30 11:43:05.152647141 +0100
@@ -0,0 +1,23 @@
+<project default="all">
+ <target name="all" depends="jar" />
+
+ <target name="compile">
+ <mkdir dir="build/classes" />
+ <javac includeantruntime="false" srcdir="src/main/java"
+ destdir="build/classes">
+ </javac>
+ </target>
+
+ <target name="jar" depends="compile">
+ <mkdir dir="dist"/>
+ <jar destfile="dist/java_websocket.jar">
+ <fileset dir="build/classes" includes="**/*.class" />
+ </jar>
+ </target>
+
+ <target name="clean">
+ <delete dir="build" />
+ <delete dir="dist" />
+ </target>
+
+</project>

View file

@ -0,0 +1,748 @@
diff -ru a/src/main/java/org/java_websocket/AbstractWebSocket.java b/src/main/java/org/java_websocket/AbstractWebSocket.java
--- a/src/main/java/org/java_websocket/AbstractWebSocket.java 2023-07-20 21:24:05.000000000 +0100
+++ b/src/main/java/org/java_websocket/AbstractWebSocket.java 2023-08-30 12:06:11.004719499 +0100
@@ -33,9 +33,7 @@
import java.util.concurrent.TimeUnit;
import org.java_websocket.framing.CloseFrame;
import org.java_websocket.util.NamedThreadFactory;
-import org.slf4j.Logger;
-import org.slf4j.LoggerFactory;
-
+import java.util.logging.Logger;
/**
* Base class for additional implementations for the server as well as the client
@@ -47,7 +45,7 @@
*
* @since 1.4.0
*/
- private final Logger log = LoggerFactory.getLogger(AbstractWebSocket.class);
+ private final Logger log = Logger.getLogger(AbstractWebSocket.class.getName());
/**
* Attribute which allows you to deactivate the Nagle's algorithm
@@ -118,12 +116,12 @@
synchronized (syncConnectionLost) {
this.connectionLostTimeout = TimeUnit.SECONDS.toNanos(connectionLostTimeout);
if (this.connectionLostTimeout <= 0) {
- log.trace("Connection lost timer stopped");
+ log.fine("Connection lost timer stopped");
cancelConnectionLostTimer();
return;
}
if (this.websocketRunning) {
- log.trace("Connection lost timer restarted");
+ log.fine("Connection lost timer restarted");
//Reset all the pings
try {
ArrayList<WebSocket> connections = new ArrayList<>(getConnections());
@@ -135,7 +133,7 @@
}
}
} catch (Exception e) {
- log.error("Exception during connection lost restart", e);
+ log.severe("Exception during connection lost restart" + " : " + e);
}
restartConnectionLostTimer();
}
@@ -151,7 +149,7 @@
synchronized (syncConnectionLost) {
if (connectionLostCheckerService != null || connectionLostCheckerFuture != null) {
this.websocketRunning = false;
- log.trace("Connection lost timer stopped");
+ log.fine("Connection lost timer stopped");
cancelConnectionLostTimer();
}
}
@@ -165,10 +163,10 @@
protected void startConnectionLostTimer() {
synchronized (syncConnectionLost) {
if (this.connectionLostTimeout <= 0) {
- log.trace("Connection lost timer deactivated");
+ log.fine("Connection lost timer deactivated");
return;
}
- log.trace("Connection lost timer started");
+ log.fine("Connection lost timer started");
this.websocketRunning = true;
restartConnectionLostTimer();
}
@@ -228,14 +226,14 @@
}
WebSocketImpl webSocketImpl = (WebSocketImpl) webSocket;
if (webSocketImpl.getLastPong() < minimumPongTime) {
- log.trace("Closing connection due to no pong received: {}", webSocketImpl);
+ log.fine("Closing connection due to no pong received: {}" + " : " + webSocketImpl);
webSocketImpl.closeConnection(CloseFrame.ABNORMAL_CLOSE,
"The connection was closed because the other endpoint did not respond with a pong in time. For more information check: https://github.com/TooTallNate/Java-WebSocket/wiki/Lost-connection-detection");
} else {
if (webSocketImpl.isOpen()) {
webSocketImpl.sendPing();
} else {
- log.trace("Trying to ping a non open connection: {}", webSocketImpl);
+ log.fine("Trying to ping a non open connection: {}" + " : " + webSocketImpl);
}
}
}
diff -ru a/src/main/java/org/java_websocket/drafts/Draft_6455.java b/src/main/java/org/java_websocket/drafts/Draft_6455.java
--- a/src/main/java/org/java_websocket/drafts/Draft_6455.java 2023-07-20 21:24:05.000000000 +0100
+++ b/src/main/java/org/java_websocket/drafts/Draft_6455.java 2023-08-30 12:16:03.534083539 +0100
@@ -66,8 +66,8 @@
import org.java_websocket.protocols.Protocol;
import org.java_websocket.util.Base64;
import org.java_websocket.util.Charsetfunctions;
-import org.slf4j.Logger;
-import org.slf4j.LoggerFactory;
+import java.util.logging.Level;
+import java.util.logging.Logger;
/**
* Implementation for the RFC 6455 websocket protocol This is the recommended class for your
@@ -110,7 +110,7 @@
*
* @since 1.4.0
*/
- private final Logger log = LoggerFactory.getLogger(Draft_6455.class);
+ private final Logger log = Logger.getLogger(Draft_6455.class.getName());
/**
* Attribute for the used extension in this draft
@@ -263,7 +263,7 @@
throws InvalidHandshakeException {
int v = readVersion(handshakedata);
if (v != 13) {
- log.trace("acceptHandshakeAsServer - Wrong websocket version.");
+ log.fine("acceptHandshakeAsServer - Wrong websocket version.");
return HandshakeState.NOT_MATCHED;
}
HandshakeState extensionState = HandshakeState.NOT_MATCHED;
@@ -272,7 +272,7 @@
if (knownExtension.acceptProvidedExtensionAsServer(requestedExtension)) {
negotiatedExtension = knownExtension;
extensionState = HandshakeState.MATCHED;
- log.trace("acceptHandshakeAsServer - Matching extension found: {}", negotiatedExtension);
+ log.fine("acceptHandshakeAsServer - Matching extension found: {}" + " : " + negotiatedExtension);
break;
}
}
@@ -281,7 +281,7 @@
if (protocolState == HandshakeState.MATCHED && extensionState == HandshakeState.MATCHED) {
return HandshakeState.MATCHED;
}
- log.trace("acceptHandshakeAsServer - No matching extension or protocol found.");
+ log.fine("acceptHandshakeAsServer - No matching extension or protocol found.");
return HandshakeState.NOT_MATCHED;
}
@@ -295,7 +295,7 @@
for (IProtocol knownProtocol : knownProtocols) {
if (knownProtocol.acceptProvidedProtocol(requestedProtocol)) {
protocol = knownProtocol;
- log.trace("acceptHandshake - Matching protocol found: {}", protocol);
+ log.fine("acceptHandshake - Matching protocol found: {}" + " : " + protocol);
return HandshakeState.MATCHED;
}
}
@@ -306,12 +306,12 @@
public HandshakeState acceptHandshakeAsClient(ClientHandshake request, ServerHandshake response)
throws InvalidHandshakeException {
if (!basicAccept(response)) {
- log.trace("acceptHandshakeAsClient - Missing/wrong upgrade or connection in handshake.");
+ log.fine("acceptHandshakeAsClient - Missing/wrong upgrade or connection in handshake.");
return HandshakeState.NOT_MATCHED;
}
if (!request.hasFieldValue(SEC_WEB_SOCKET_KEY) || !response
.hasFieldValue(SEC_WEB_SOCKET_ACCEPT)) {
- log.trace("acceptHandshakeAsClient - Missing Sec-WebSocket-Key or Sec-WebSocket-Accept");
+ log.fine("acceptHandshakeAsClient - Missing Sec-WebSocket-Key or Sec-WebSocket-Accept");
return HandshakeState.NOT_MATCHED;
}
@@ -320,7 +320,7 @@
seckeyChallenge = generateFinalKey(seckeyChallenge);
if (!seckeyChallenge.equals(seckeyAnswer)) {
- log.trace("acceptHandshakeAsClient - Wrong key for Sec-WebSocket-Key.");
+ log.fine("acceptHandshakeAsClient - Wrong key for Sec-WebSocket-Key.");
return HandshakeState.NOT_MATCHED;
}
HandshakeState extensionState = HandshakeState.NOT_MATCHED;
@@ -329,7 +329,7 @@
if (knownExtension.acceptProvidedExtensionAsClient(requestedExtension)) {
negotiatedExtension = knownExtension;
extensionState = HandshakeState.MATCHED;
- log.trace("acceptHandshakeAsClient - Matching extension found: {}", negotiatedExtension);
+ log.fine("acceptHandshakeAsClient - Matching extension found: {}" + " : " + negotiatedExtension);
break;
}
}
@@ -338,7 +338,7 @@
if (protocolState == HandshakeState.MATCHED && extensionState == HandshakeState.MATCHED) {
return HandshakeState.MATCHED;
}
- log.trace("acceptHandshakeAsClient - No matching extension or protocol found.");
+ log.fine("acceptHandshakeAsClient - No matching extension or protocol found.");
return HandshakeState.NOT_MATCHED;
}
@@ -467,8 +467,8 @@
@Override
public ByteBuffer createBinaryFrame(Framedata framedata) {
getExtension().encodeFrame(framedata);
- if (log.isTraceEnabled()) {
- log.trace("afterEnconding({}): {}", framedata.getPayloadData().remaining(),
+ if (log.isLoggable(Level.FINE)) {
+ log.fine("afterEnconding({}): {}" + " : " + framedata.getPayloadData().remaining() + " : " +
(framedata.getPayloadData().remaining() > 1000 ? "too big to display"
: new String(framedata.getPayloadData().array())));
}
@@ -587,8 +587,8 @@
}
currentDecodingExtension.isFrameValid(frame);
currentDecodingExtension.decodeFrame(frame);
- if (log.isTraceEnabled()) {
- log.trace("afterDecoding({}): {}", frame.getPayloadData().remaining(),
+ if (log.isLoggable(Level.FINE)) {
+ log.fine("afterDecoding({}): {}" + " : " + frame.getPayloadData().remaining() + " : " +
(frame.getPayloadData().remaining() > 1000 ? "too big to display"
: new String(frame.getPayloadData().array())));
}
@@ -615,7 +615,7 @@
int payloadlength = oldPayloadlength;
int realpacketsize = oldRealpacketsize;
if (optcode == Opcode.PING || optcode == Opcode.PONG || optcode == Opcode.CLOSING) {
- log.trace("Invalid frame: more than 125 octets");
+ log.fine("Invalid frame: more than 125 octets");
throw new InvalidFrameException("more than 125 octets");
}
if (payloadlength == 126) {
@@ -647,15 +647,15 @@
*/
private void translateSingleFrameCheckLengthLimit(long length) throws LimitExceededException {
if (length > Integer.MAX_VALUE) {
- log.trace("Limit exedeed: Payloadsize is to big...");
+ log.fine("Limit exedeed: Payloadsize is to big...");
throw new LimitExceededException("Payloadsize is to big...");
}
if (length > maxFrameSize) {
- log.trace("Payload limit reached. Allowed: {} Current: {}", maxFrameSize, length);
+ log.fine("Payload limit reached. Allowed: {} Current: {}" + " : " + maxFrameSize + " : " + length);
throw new LimitExceededException("Payload limit reached.", maxFrameSize);
}
if (length < 0) {
- log.trace("Limit underflow: Payloadsize is to little...");
+ log.fine("Limit underflow: Payloadsize is to little...");
throw new LimitExceededException("Payloadsize is to little...");
}
}
@@ -670,7 +670,7 @@
private void translateSingleFrameCheckPacketSize(int maxpacketsize, int realpacketsize)
throws IncompleteException {
if (maxpacketsize < realpacketsize) {
- log.trace("Incomplete frame: maxpacketsize < realpacketsize");
+ log.fine("Incomplete frame: maxpacketsize < realpacketsize");
throw new IncompleteException(realpacketsize);
}
}
@@ -903,7 +903,7 @@
} else if (!frame.isFin() || curop == Opcode.CONTINUOUS) {
processFrameContinuousAndNonFin(webSocketImpl, frame, curop);
} else if (currentContinuousFrame != null) {
- log.error("Protocol error: Continuous frame sequence not completed.");
+ log.severe("Protocol error: Continuous frame sequence not completed.");
throw new InvalidDataException(CloseFrame.PROTOCOL_ERROR,
"Continuous frame sequence not completed.");
} else if (curop == Opcode.TEXT) {
@@ -911,7 +911,7 @@
} else if (curop == Opcode.BINARY) {
processFrameBinary(webSocketImpl, frame);
} else {
- log.error("non control or continious frame expected");
+ log.severe("non control or continious frame expected");
throw new InvalidDataException(CloseFrame.PROTOCOL_ERROR,
"non control or continious frame expected");
}
@@ -932,13 +932,13 @@
} else if (frame.isFin()) {
processFrameIsFin(webSocketImpl, frame);
} else if (currentContinuousFrame == null) {
- log.error("Protocol error: Continuous frame sequence was not started.");
+ log.severe("Protocol error: Continuous frame sequence was not started.");
throw new InvalidDataException(CloseFrame.PROTOCOL_ERROR,
"Continuous frame sequence was not started.");
}
//Check if the whole payload is valid utf8, when the opcode indicates a text
if (curop == Opcode.TEXT && !Charsetfunctions.isValidUTF8(frame.getPayloadData())) {
- log.error("Protocol error: Payload is not UTF8");
+ log.severe("Protocol error: Payload is not UTF8");
throw new InvalidDataException(CloseFrame.NO_UTF8);
}
//Checking if the current continuous frame contains a correct payload with the other frames combined
@@ -969,7 +969,7 @@
* @param e the runtime exception
*/
private void logRuntimeException(WebSocketImpl webSocketImpl, RuntimeException e) {
- log.error("Runtime exception during onWebsocketMessage", e);
+ log.severe("Runtime exception during onWebsocketMessage" + " : " + e);
webSocketImpl.getWebSocketListener().onWebsocketError(webSocketImpl, e);
}
@@ -999,7 +999,7 @@
private void processFrameIsFin(WebSocketImpl webSocketImpl, Framedata frame)
throws InvalidDataException {
if (currentContinuousFrame == null) {
- log.trace("Protocol error: Previous continuous frame sequence not completed.");
+ log.fine("Protocol error: Previous continuous frame sequence not completed.");
throw new InvalidDataException(CloseFrame.PROTOCOL_ERROR,
"Continuous frame sequence was not started.");
}
@@ -1036,7 +1036,7 @@
*/
private void processFrameIsNotFin(Framedata frame) throws InvalidDataException {
if (currentContinuousFrame != null) {
- log.trace("Protocol error: Previous continuous frame sequence not completed.");
+ log.fine("Protocol error: Previous continuous frame sequence not completed.");
throw new InvalidDataException(CloseFrame.PROTOCOL_ERROR,
"Previous continuous frame sequence not completed.");
}
@@ -1102,7 +1102,7 @@
long totalSize = getByteBufferListSize();
if (totalSize > maxFrameSize) {
clearBufferList();
- log.trace("Payload limit reached. Allowed: {} Current: {}", maxFrameSize, totalSize);
+ log.fine("Payload limit reached. Allowed: {} Current: {}" + " : " + maxFrameSize + " : " + totalSize);
throw new LimitExceededException(maxFrameSize);
}
}
diff -ru a/src/main/java/org/java_websocket/server/WebSocketServer.java b/src/main/java/org/java_websocket/server/WebSocketServer.java
--- a/src/main/java/org/java_websocket/server/WebSocketServer.java 2023-07-20 21:24:05.000000000 +0100
+++ b/src/main/java/org/java_websocket/server/WebSocketServer.java 2023-08-30 12:06:46.372798355 +0100
@@ -67,8 +67,7 @@
import org.java_websocket.framing.Framedata;
import org.java_websocket.handshake.ClientHandshake;
import org.java_websocket.handshake.Handshakedata;
-import org.slf4j.Logger;
-import org.slf4j.LoggerFactory;
+import java.util.logging.Logger;
/**
* <tt>WebSocketServer</tt> is an abstract class that only takes care of the
@@ -84,7 +83,7 @@
*
* @since 1.4.0
*/
- private final Logger log = LoggerFactory.getLogger(WebSocketServer.class);
+ private final Logger log = Logger.getLogger(WebSocketServer.class.getName());
/**
* Holds the list of active WebSocket connections. "Active" means WebSocket handshake is complete
@@ -611,7 +610,7 @@
try {
selector.close();
} catch (IOException e) {
- log.error("IOException during selector.close", e);
+ log.severe("IOException during selector.close" + " : " + e);
onError(null, e);
}
}
@@ -619,7 +618,7 @@
try {
server.close();
} catch (IOException e) {
- log.error("IOException during server.close", e);
+ log.severe("IOException during server.close" + " : " + e);
onError(null, e);
}
}
@@ -677,13 +676,13 @@
} catch (IOException e) {
// there is nothing that must be done here
}
- log.trace("Connection closed because of exception", ex);
+ log.fine("Connection closed because of exception" + " : " + ex);
}
}
}
private void handleFatal(WebSocket conn, Exception e) {
- log.error("Shutdown due to fatal error", e);
+ log.severe("Shutdown due to fatal error" + " : " + e);
onError(conn, e);
String causeMessage = e.getCause() != null ? " caused by " + e.getCause().getClass().getName() : "";
@@ -692,7 +691,7 @@
stop(0, errorMessage);
} catch (InterruptedException e1) {
Thread.currentThread().interrupt();
- log.error("Interrupt during stop", e);
+ log.severe("Interrupt during stop" + " : " + e);
onError(null, e1);
}
@@ -760,8 +759,8 @@
removed = this.connections.remove(ws);
} else {
//Don't throw an assert error if the ws is not in the list. e.g. when the other endpoint did not send any handshake. see #512
- log.trace(
- "Removing connection which is not in the connections collection! Possible no handshake received! {}",
+ log.fine(
+ "Removing connection which is not in the connections collection! Possible no handshake received! {}" + " : " +
ws);
}
}
@@ -1065,7 +1064,7 @@
setUncaughtExceptionHandler(new UncaughtExceptionHandler() {
@Override
public void uncaughtException(Thread t, Throwable e) {
- log.error("Uncaught exception in thread {}: {}", t.getName(), e);
+ log.severe("Uncaught exception in thread {}: {}" + " : " + t.getName() + " : " + e);
}
});
}
@@ -1089,11 +1088,11 @@
} catch (InterruptedException e) {
Thread.currentThread().interrupt();
} catch (VirtualMachineError | ThreadDeath | LinkageError e) {
- log.error("Got fatal error in worker thread {}", getName());
+ log.severe("Got fatal error in worker thread {}" + " : " + getName());
Exception exception = new Exception(e);
handleFatal(ws, exception);
} catch (Throwable e) {
- log.error("Uncaught exception in thread {}: {}", getName(), e);
+ log.severe("Uncaught exception in thread {}: {}" + " : " + getName() + " : " + e);
if (ws != null) {
Exception exception = new Exception(e);
onWebsocketError(ws, exception);
@@ -1113,7 +1112,7 @@
try {
ws.decode(buf);
} catch (Exception e) {
- log.error("Error while reading from remote connection", e);
+ log.severe("Error while reading from remote connection" + " : " + e);
} finally {
pushBuffer(buf);
}
diff -ru a/src/main/java/org/java_websocket/SSLSocketChannel2.java b/src/main/java/org/java_websocket/SSLSocketChannel2.java
--- a/src/main/java/org/java_websocket/SSLSocketChannel2.java 2023-07-20 21:24:05.000000000 +0100
+++ b/src/main/java/org/java_websocket/SSLSocketChannel2.java 2023-08-30 12:05:33.937636854 +0100
@@ -47,8 +47,8 @@
import javax.net.ssl.SSLException;
import javax.net.ssl.SSLSession;
import org.java_websocket.interfaces.ISSLChannel;
-import org.slf4j.Logger;
-import org.slf4j.LoggerFactory;
+import java.util.logging.Level;
+import java.util.logging.Logger;
/**
* Implements the relevant portions of the SocketChannel interface with the SSLEngine wrapper.
@@ -66,7 +66,7 @@
*
* @since 1.4.0
*/
- private final Logger log = LoggerFactory.getLogger(SSLSocketChannel2.class);
+ private final Logger log = Logger.getLogger(SSLSocketChannel2.class.getName());
protected ExecutorService exec;
@@ -256,13 +256,13 @@
inCrypt = ByteBuffer.allocate(netBufferMax);
}
}
- if (inData.remaining() != 0 && log.isTraceEnabled()) {
- log.trace(new String(inData.array(), inData.position(), inData.remaining()));
+ if (inData.remaining() != 0 && log.isLoggable(Level.FINE)) {
+ log.fine(new String(inData.array(), inData.position(), inData.remaining()));
}
inData.rewind();
inData.flip();
- if (inCrypt.remaining() != 0 && log.isTraceEnabled()) {
- log.trace(new String(inCrypt.array(), inCrypt.position(), inCrypt.remaining()));
+ if (inCrypt.remaining() != 0 && log.isLoggable(Level.FINE)) {
+ log.fine(new String(inCrypt.array(), inCrypt.position(), inCrypt.remaining()));
}
inCrypt.rewind();
inCrypt.flip();
@@ -498,4 +498,4 @@
saveCryptData = null;
}
}
-}
\ No newline at end of file
+}
diff -ru a/src/main/java/org/java_websocket/SSLSocketChannel.java b/src/main/java/org/java_websocket/SSLSocketChannel.java
--- a/src/main/java/org/java_websocket/SSLSocketChannel.java 2023-07-20 21:24:05.000000000 +0100
+++ b/src/main/java/org/java_websocket/SSLSocketChannel.java 2023-08-30 11:55:09.427244528 +0100
@@ -39,8 +39,7 @@
import javax.net.ssl.SSLSession;
import org.java_websocket.interfaces.ISSLChannel;
import org.java_websocket.util.ByteBufferUtils;
-import org.slf4j.Logger;
-import org.slf4j.LoggerFactory;
+import java.util.logging.Logger;
/**
@@ -70,7 +69,7 @@
*
* @since 1.4.0
*/
- private final Logger log = LoggerFactory.getLogger(SSLSocketChannel.class);
+ private final Logger log = Logger.getLogger(SSLSocketChannel.class.getName());
/**
* The underlying socket channel
@@ -148,7 +147,7 @@
try {
socketChannel.close();
} catch (IOException e) {
- log.error("Exception during the closing of the channel", e);
+ log.severe("Exception during the closing of the channel" + " : " + e);
}
}
}
@@ -176,7 +175,7 @@
try {
result = engine.unwrap(peerNetData, peerAppData);
} catch (SSLException e) {
- log.error("SSLException during unwrap", e);
+ log.severe("SSLException during unwrap" + " : " + e);
throw e;
}
switch (result.getStatus()) {
@@ -490,7 +489,7 @@
try {
engine.closeInbound();
} catch (Exception e) {
- log.error(
+ log.severe(
"This engine was forced to close inbound, without having received the proper SSL/TLS close notification message from the peer, due to end of stream.");
}
closeConnection();
@@ -536,4 +535,4 @@
public SSLEngine getSSLEngine() {
return engine;
}
-}
\ No newline at end of file
+}
diff -ru a/src/main/java/org/java_websocket/WebSocketImpl.java b/src/main/java/org/java_websocket/WebSocketImpl.java
--- a/src/main/java/org/java_websocket/WebSocketImpl.java 2023-07-20 21:24:05.000000000 +0100
+++ b/src/main/java/org/java_websocket/WebSocketImpl.java 2023-08-30 12:12:26.045577651 +0100
@@ -61,8 +61,8 @@
import org.java_websocket.protocols.IProtocol;
import org.java_websocket.server.WebSocketServer.WebSocketWorker;
import org.java_websocket.util.Charsetfunctions;
-import org.slf4j.Logger;
-import org.slf4j.LoggerFactory;
+import java.util.logging.Level;
+import java.util.logging.Logger;
/**
* Represents one end (client or server) of a single WebSocketImpl connection. Takes care of the
@@ -95,7 +95,7 @@
*
* @since 1.4.0
*/
- private final Logger log = LoggerFactory.getLogger(WebSocketImpl.class);
+ private final Logger log = Logger.getLogger(WebSocketImpl.class.getName());
/**
* Queue of buffers that need to be sent to the client.
@@ -224,8 +224,8 @@
*/
public void decode(ByteBuffer socketBuffer) {
assert (socketBuffer.hasRemaining());
- if (log.isTraceEnabled()) {
- log.trace("process({}): ({})", socketBuffer.remaining(),
+ if (log.isLoggable(Level.FINE)) {
+ log.fine("process({}): ({})" + " : " + socketBuffer.remaining() + " : " +
(socketBuffer.remaining() > 1000 ? "too big to display"
: new String(socketBuffer.array(), socketBuffer.position(), socketBuffer.remaining())));
}
@@ -280,7 +280,7 @@
socketBuffer.reset();
Handshakedata tmphandshake = d.translateHandshake(socketBuffer);
if (!(tmphandshake instanceof ClientHandshake)) {
- log.trace("Closing due to wrong handshake");
+ log.fine("Closing due to wrong handshake");
closeConnectionDueToWrongHandshake(
new InvalidDataException(CloseFrame.PROTOCOL_ERROR, "wrong http function"));
return false;
@@ -293,11 +293,11 @@
try {
response = wsl.onWebsocketHandshakeReceivedAsServer(this, d, handshake);
} catch (InvalidDataException e) {
- log.trace("Closing due to wrong handshake. Possible handshake rejection", e);
+ log.fine("Closing due to wrong handshake. Possible handshake rejection" + " : " + e);
closeConnectionDueToWrongHandshake(e);
return false;
} catch (RuntimeException e) {
- log.error("Closing due to internal server error", e);
+ log.severe("Closing due to internal server error" + " : " + e);
wsl.onWebsocketError(this, e);
closeConnectionDueToInternalServerError(e);
return false;
@@ -313,7 +313,7 @@
}
}
if (draft == null) {
- log.trace("Closing due to protocol error: no draft matches");
+ log.fine("Closing due to protocol error: no draft matches");
closeConnectionDueToWrongHandshake(
new InvalidDataException(CloseFrame.PROTOCOL_ERROR, "no draft matches"));
}
@@ -322,7 +322,7 @@
// special case for multiple step handshakes
Handshakedata tmphandshake = draft.translateHandshake(socketBuffer);
if (!(tmphandshake instanceof ClientHandshake)) {
- log.trace("Closing due to protocol error: wrong http function");
+ log.fine("Closing due to protocol error: wrong http function");
flushAndClose(CloseFrame.PROTOCOL_ERROR, "wrong http function", false);
return false;
}
@@ -333,7 +333,7 @@
open(handshake);
return true;
} else {
- log.trace("Closing due to protocol error: the handshake did finally not match");
+ log.fine("Closing due to protocol error: the handshake did finally not match");
close(CloseFrame.PROTOCOL_ERROR, "the handshake did finally not match");
}
return false;
@@ -342,7 +342,7 @@
draft.setParseMode(role);
Handshakedata tmphandshake = draft.translateHandshake(socketBuffer);
if (!(tmphandshake instanceof ServerHandshake)) {
- log.trace("Closing due to protocol error: wrong http function");
+ log.fine("Closing due to protocol error: wrong http function");
flushAndClose(CloseFrame.PROTOCOL_ERROR, "wrong http function", false);
return false;
}
@@ -352,11 +352,11 @@
try {
wsl.onWebsocketHandshakeReceivedAsClient(this, handshakerequest, handshake);
} catch (InvalidDataException e) {
- log.trace("Closing due to invalid data exception. Possible handshake rejection", e);
+ log.fine("Closing due to invalid data exception. Possible handshake rejection" + " : " + e);
flushAndClose(e.getCloseCode(), e.getMessage(), false);
return false;
} catch (RuntimeException e) {
- log.error("Closing since client was never connected", e);
+ log.severe("Closing since client was never connected" + " : " + e);
wsl.onWebsocketError(this, e);
flushAndClose(CloseFrame.NEVER_CONNECTED, e.getMessage(), false);
return false;
@@ -364,12 +364,12 @@
open(handshake);
return true;
} else {
- log.trace("Closing due to protocol error: draft {} refuses handshake", draft);
+ log.fine("Closing due to protocol error: draft {} refuses handshake" + " : " + draft);
close(CloseFrame.PROTOCOL_ERROR, "draft " + draft + " refuses handshake");
}
}
} catch (InvalidHandshakeException e) {
- log.trace("Closing due to invalid handshake", e);
+ log.fine("Closing due to invalid handshake" + " : " + e);
close(e);
}
} catch (IncompleteHandshakeException e) {
@@ -398,24 +398,24 @@
try {
frames = draft.translateFrame(socketBuffer);
for (Framedata f : frames) {
- log.trace("matched frame: {}", f);
+ log.fine("matched frame: {}" + " : " + f);
draft.processFrame(this, f);
}
} catch (LimitExceededException e) {
if (e.getLimit() == Integer.MAX_VALUE) {
- log.error("Closing due to invalid size of frame", e);
+ log.severe("Closing due to invalid size of frame" + " : " + e);
wsl.onWebsocketError(this, e);
}
close(e);
} catch (InvalidDataException e) {
- log.error("Closing due to invalid data in frame", e);
+ log.severe("Closing due to invalid data in frame" + " : " + e);
wsl.onWebsocketError(this, e);
close(e);
} catch (VirtualMachineError | ThreadDeath | LinkageError e) {
- log.error("Got fatal error during frame processing");
+ log.severe("Got fatal error during frame processing");
throw e;
} catch (Error e) {
- log.error("Closing web socket due to an error during frame processing");
+ log.severe("Closing web socket due to an error during frame processing");
Exception exception = new Exception(e);
wsl.onWebsocketError(this, exception);
String errorMessage = "Got error " + e.getClass().getName();
@@ -491,7 +491,7 @@
sendFrame(closeFrame);
}
} catch (InvalidDataException e) {
- log.error("generated frame is invalid", e);
+ log.severe("generated frame is invalid" + " : " + e);
wsl.onWebsocketError(this, e);
flushAndClose(CloseFrame.ABNORMAL_CLOSE, "generated frame is invalid", false);
}
@@ -551,9 +551,9 @@
channel.close();
} catch (IOException e) {
if (e.getMessage() != null && e.getMessage().equals("Broken pipe")) {
- log.trace("Caught IOException: Broken pipe during closeConnection()", e);
+ log.fine("Caught IOException: Broken pipe during closeConnection()" + " : " + e);
} else {
- log.error("Exception during channel.close()", e);
+ log.severe("Exception during channel.close()" + " : " + e);
wsl.onWebsocketError(this, e);
}
}
@@ -601,7 +601,7 @@
try {
wsl.onWebsocketClosing(this, code, message, remote);
} catch (RuntimeException e) {
- log.error("Exception in onWebsocketClosing", e);
+ log.severe("Exception in onWebsocketClosing" + " : " + e);
wsl.onWebsocketError(this, e);
}
if (draft != null) {
@@ -678,7 +678,7 @@
}
ArrayList<ByteBuffer> outgoingFrames = new ArrayList<>();
for (Framedata f : frames) {
- log.trace("send frame: {}", f);
+ log.fine("send frame: {}" + " : " + f);
outgoingFrames.add(draft.createBinaryFrame(f));
}
write(outgoingFrames);
@@ -729,7 +729,7 @@
// Stop if the client code throws an exception
throw new InvalidHandshakeException("Handshake data rejected by client.");
} catch (RuntimeException e) {
- log.error("Exception in startHandshake", e);
+ log.severe("Exception in startHandshake" + " : " + e);
wsl.onWebsocketError(this, e);
throw new InvalidHandshakeException("rejected because of " + e);
}
@@ -739,8 +739,8 @@
}
private void write(ByteBuffer buf) {
- log.trace("write({}): {}", buf.remaining(),
- buf.remaining() > 1000 ? "too big to display" : new String(buf.array()));
+ log.fine("write({}): {}" + " : " + buf.remaining() + " : " +
+ (buf.remaining() > 1000 ? "too big to display" : new String(buf.array())));
outQueue.add(buf);
wsl.onWriteDemand(this);
@@ -760,7 +760,7 @@
}
private void open(Handshakedata d) {
- log.trace("open using draft: {}", draft);
+ log.fine("open using draft: {}" + " : " + draft);
readyState = ReadyState.OPEN;
updateLastPong();
try {

View file

@ -131,6 +131,15 @@ struct _LibreOfficeKitClass
/// @see lok::Office::trimMemory
/// @since LibreOffice 7.6
void (*trimMemory) (LibreOfficeKit* pThis, int nTarget);
/// @see lok::Office::startURP
int (*startURP)(LibreOfficeKit* pThis, void* pReceiveURPFromLOContext,
void** ppSendURPToLOContext,
int (*fnReceiveURPFromLO)(void* pContext, const signed char* pBuffer, int nLen),
int (**pfnSendURPToLO)(void* pContext, const signed char* pBuffer, int nLen));
/// @see lok::Office::stopURP
void (*stopURP)(LibreOfficeKit* pThis, void* pSendURPToLOContext);
};
#define LIBREOFFICEKIT_DOCUMENT_HAS(pDoc,member) LIBREOFFICEKIT_HAS_MEMBER(LibreOfficeKitDocumentClass,member,(pDoc)->pClass->nSize)

View file

@ -1166,6 +1166,32 @@ public:
{
mpThis->pClass->trimMemory(mpThis, nTarget);
}
/**
* Start a UNO acceptor using the function pointers provides to read and write data to/from the acceptor.
*
* @param pReceiveURPFromLOContext A pointer that will be passed to your fnRecieveURPFromLO function
* @param ppSendURPToLOContext A pointer to a pointer that you should give to the function passing URP to LO will be stored in this.
* @param fnReceiveURPFromLO A function pointer that LO should use to pass URP back to the caller
* @param pfnSendURPToLO A function pointer pointer that the caller should use to pass URP to LO will be stored in this.
*/
bool startURP(void* pReceiveURPFromLOContext, void** ppSendURPToLOContext,
int (*fnReceiveURPFromLO)(void* pContext, const signed char* pBuffer, int nLen),
int (**pfnSendURPToLO)(void* pContext, const signed char* pBuffer, int nLen))
{
return mpThis->pClass->startURP(mpThis, pReceiveURPFromLOContext, ppSendURPToLOContext,
fnReceiveURPFromLO, pfnSendURPToLO);
}
/**
* Stop a function based URP connection you previously started with startURP
*
* @param pSendURPToLOContext the context you got back in the ppSendURPToLOContext argument when starting the connection
*/
void stopURP(void* pSendURPToLOContext)
{
mpThis->pClass->stopURP(mpThis, pSendURPToLOContext);
}
};
/// Factory method to create a lok::Office instance.

View file

@ -328,6 +328,7 @@ certain functionality.
@li @c lok.tiledrendering
@li @c lok.dialog
@li @c lok.a11y - LOK accessibility
@li @c lok.urp - Uno Remote Protocol
@section l10ntools

View file

@ -253,6 +253,24 @@
ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
OTHER DEALINGS IN THE SOFTWARE.</p>
</div>
<div class="JAVA_WEBSOCKET">
<h2>Java WebSocket</h2>
<p>The following software may be included in this product: Java WebSocket. Use of any of this software is governed
by the terms of the license below:</p>
<h3>The MIT License</h3>
<p>Copyright (c) 2010-2020 Nathan Rajlich</p>
<p>Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated
documentation files (the "Software"), to deal in the Software without restriction, including without limitation
the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software,
and to permit persons to whom the Software is furnished to do so, subject to the following conditions:</p>
<p>The above copyright notice and this permission notice shall be included in all copies or substantial
portions of the Software.</p>
<p>THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT
LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT
SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN
ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
OTHER DEALINGS IN THE SOFTWARE.</p>
</div>
<div class="JFREEREPORT">
<h2>Flute</h2>
<p>The following software may be included in this product: Flute. Use of any of this software is governed by the

View file

@ -18,11 +18,16 @@ $(eval $(call gb_Jar_use_jars,libreoffice, \
unoloader \
))
$(eval $(call gb_Jar_use_externals,libreoffice,\
java_websocket \
))
$(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, \
java_websocket.jar \
unoloader.jar \
$(if $(filter MACOSX,$(OS)),../../Frameworks/,../) \
))
@ -63,6 +68,9 @@ $(eval $(call gb_Jar_add_sourcefiles,libreoffice,\
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/connections/websocket/ConnectionDescriptor \
ridljar/com/sun/star/lib/connections/websocket/WebsocketConnection \
ridljar/com/sun/star/lib/connections/websocket/websocketConnector \
ridljar/com/sun/star/lib/uno/Proxy \
ridljar/com/sun/star/lib/uno/adapter/ByteArrayToXInputStreamAdapter \
ridljar/com/sun/star/lib/uno/adapter/InputStreamToXInputStreamAdapter \

View file

@ -32,6 +32,7 @@ import com.sun.star.lib.util.NativeLibraryLoader;
import com.sun.star.loader.XImplementationLoader;
import com.sun.star.uno.UnoRuntime;
import com.sun.star.uno.XComponentContext;
import com.sun.star.beans.XPropertySet;
import java.io.BufferedReader;
import java.io.File;
@ -397,6 +398,68 @@ public class Bootstrap {
return xContext;
}
/**
* Bootstraps the component context from a websocket location.
*
* @param url
* the ws:// or wss:// url of the websocket server
*
* @throws BootstrapException if things go awry.
*
* @return a bootstrapped component context.
*
* @since LibreOffice 24.2
*/
public static final XComponentContext bootstrapWebsocketConnection( String url )
throws BootstrapException {
XComponentContext xContext = null;
try {
// create default local component context
XComponentContext xLocalContext =
createInitialComponentContext( (Map<String, Object>) null );
if ( xLocalContext == null )
throw new BootstrapException( "no local component context!" );
// initial service manager
XMultiComponentFactory xLocalServiceManager =
xLocalContext.getServiceManager();
if ( xLocalServiceManager == null )
throw new BootstrapException( "no initial service manager!" );
// create a URL resolver
XUnoUrlResolver xUrlResolver =
UnoUrlResolver.create( xLocalContext );
// connection string
String sConnect = "uno:websocket"
+ ",url=" + url
+ ";urp;StarOffice.ComponentContext";
try {
// try to connect to office
Object xOfficeServiceManager = xUrlResolver.resolve(sConnect);
xContext = UnoRuntime.queryInterface(XComponentContext.class, xOfficeServiceManager);
if ( xContext == null )
throw new BootstrapException( "no component context!" );
} catch ( com.sun.star.connection.NoConnectException ex ) {
throw new BootstrapException(ex);
}
} catch ( BootstrapException e ) {
throw e;
} catch ( java.lang.RuntimeException e ) {
throw e;
} catch ( java.lang.Exception e ) {
throw new BootstrapException( e );
}
return xContext;
}
private static final Random randomPipeName = new Random();
private static void pipe(

View file

@ -0,0 +1,60 @@
/* -*- Mode: Java; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
/*
* This file is part of the LibreOffice project.
*
* This Source Code Form is subject to the terms of the Mozilla Public
* License, v. 2.0. If a copy of the MPL was not distributed with this
* file, You can obtain one at http://mozilla.org/MPL/2.0/.
*
* This file incorporates work covered by the following license notice:
*
* Licensed to the Apache Software Foundation (ASF) under one or more
* contributor license agreements. See the NOTICE file distributed
* with this work for additional information regarding copyright
* ownership. The ASF licenses this file to you under the Apache
* License, Version 2.0 (the "License"); you may not use this file
* except in compliance with the License. You may obtain a copy of
* the License at http://www.apache.org/licenses/LICENSE-2.0 .
*/
package com.sun.star.lib.connections.websocket;
import java.util.Arrays;
import java.util.Iterator;
/**
* Helper class for <code>websocketConnector</code>.
*/
final class ConnectionDescriptor {
public ConnectionDescriptor(String description)
throws com.sun.star.lang.IllegalArgumentException {
Iterator<String> descriptionParts = Arrays.stream(description.split(",")).iterator();
descriptionParts
.next(); // skip over the first part as it's the protocol not a real parameter
while (descriptionParts.hasNext())
{
String parameter = descriptionParts.next();
String[] pair = parameter.split("=", 2);
if (pair.length != 2)
{
throw new com.sun.star.lang.IllegalArgumentException(
String.format("parameter %s lacks '='", parameter));
}
String key = pair[0];
String value = pair[1];
if (key.equalsIgnoreCase("url")) {
url = value;
}
}
}
public String getURL() {
return url;
}
private String url = null;
}
/* vim:set shiftwidth=4 softtabstop=4 expandtab: */

View file

@ -0,0 +1,335 @@
/* -*- Mode: Java; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
/*
* This file is part of the LibreOffice project.
*
* This Source Code Form is subject to the terms of the Mozilla Public
* License, v. 2.0. If a copy of the MPL was not distributed with this
* file, You can obtain one at http://mozilla.org/MPL/2.0/.
*
* This file incorporates work covered by the following license notice:
*
* Licensed to the Apache Software Foundation (ASF) under one or more
* contributor license agreements. See the NOTICE file distributed
* with this work for additional information regarding copyright
* ownership. The ASF licenses this file to you under the Apache
* License, Version 2.0 (the "License"); you may not use this file
* except in compliance with the License. You may obtain a copy of
* the License at http://www.apache.org/licenses/LICENSE-2.0 .
*/
package com.sun.star.lib.connections.websocket;
import java.io.BufferedInputStream;
import java.io.BufferedOutputStream;
import java.io.IOException;
import java.io.InputStream;
import java.io.OutputStream;
import java.io.PipedInputStream;
import java.io.PipedOutputStream;
import java.net.ProtocolException;
import java.net.Socket;
import java.net.URI;
import java.net.URISyntaxException;
import java.nio.ByteBuffer;
import java.util.ArrayList;
import java.util.Arrays;
import javax.swing.text.html.HTMLDocument.Iterator;
import com.sun.star.connection.XConnection;
import com.sun.star.connection.XConnectionBroadcaster;
import com.sun.star.io.XStreamListener;
import org.java_websocket.client.WebSocketClient;
import org.java_websocket.handshake.ServerHandshake;
/**
* The WebsocketConnection implements the <code>XConnection</code> interface
* and is uses by the <code>WebsocketConnector</code>.
*
* <p>This class is not part of the provided <code>api</code>.</p>
*
* @see com.sun.star.lib.connections.socket.socketAcceptor
* @see com.sun.star.lib.connections.socket.socketConnector
* @see com.sun.star.connection.XConnection
*/
public class WebsocketConnection extends WebSocketClient implements XConnection, XConnectionBroadcaster {
/**
* When set to true, enables various debugging output.
*/
public static final boolean DEBUG = false;
static final byte[] outgoingPrefix = { 'u', 'r', 'p', ' ' };
protected String _description;
protected InputStream _inputStream;
protected OutputStream _outputStream;
protected InputStream _outputStreamReader;
protected OutputStream _inputStreamWriter;
protected ArrayList<XStreamListener> _listeners;
/**
* Constructs a new <code>WebsocketConnection</code>.
*
* @param description the description of the connection.
* @param desc the websocket ConnectionDescriptor containing information such as the websocket URL
*/
public WebsocketConnection(String description, ConnectionDescriptor desc) throws IOException, URISyntaxException, InterruptedException {
super(new URI(desc.getURL()));
if (DEBUG) System.err.println("##### " + getClass().getName() + " - instantiated " + description + " " + desc);
_description = description;
PipedOutputStream inputStreamWriter = new PipedOutputStream();
PipedInputStream inputPipe = new PipedInputStream(inputStreamWriter);
PipedOutputStream outputPipe = new PipedOutputStream();
PipedInputStream outputStreamReader = new PipedInputStream(outputPipe);
_inputStream = new BufferedInputStream(inputPipe);
_inputStreamWriter = inputStreamWriter;
_outputStream = new BufferedOutputStream(outputPipe);
_outputStreamReader = outputStreamReader;
_listeners = new ArrayList<XStreamListener>();
connectBlocking();
}
public void addStreamListener(XStreamListener aListener )
throws com.sun.star.uno.RuntimeException {
_listeners.add(aListener);
}
public void removeStreamListener(XStreamListener aListener )
throws com.sun.star.uno.RuntimeException {
_listeners.remove(aListener);
}
private void notifyListeners_open() {
for (XStreamListener xStreamListener : _listeners) {
xStreamListener.started();
}
}
private void notifyListeners_close() {
for (XStreamListener xStreamListener : _listeners) {
xStreamListener.closed();
}
}
private void notifyListeners_error(com.sun.star.uno.Exception exception) {
for (XStreamListener xStreamListener : _listeners) {
xStreamListener.error(exception);
}
}
/**
* Read the required number of bytes.
*
* @param bytes the outparameter, where the bytes have to be placed.
* @param nBytesToRead the number of bytes to read.
* @return the number of bytes read.
*
* @see com.sun.star.connection.XConnection#read
*/
public int read(/*OUT*/byte[][] bytes, int nBytesToRead)
throws com.sun.star.io.IOException, com.sun.star.uno.RuntimeException {
String errMessage = null;
int read_bytes = 0;
bytes[0] = new byte[nBytesToRead];
try {
_inputStreamWriter.flush();
int count ;
do {
count = _inputStream.read(bytes[0], read_bytes, nBytesToRead - read_bytes);
if(count == -1)
errMessage = "EOF reached - " + getDescription();
read_bytes += count;
}
while(read_bytes >= 0 && read_bytes < nBytesToRead && count >= 0);
} catch(IOException ioException) {
if(DEBUG) {
System.err.println("##### " + getClass().getName() + ".read - exception occurred:" + ioException);
ioException.printStackTrace();
}
errMessage = ioException.toString();
}
if(errMessage != null) {
com.sun.star.io.IOException unoIOException = new com.sun.star.io.IOException(errMessage);
notifyListeners_error(unoIOException);
throw unoIOException;
}
if (DEBUG) System.err.println(String.format("##### %s - read %s bytes of %s requested", getClass().getName(), Integer.toString(read_bytes), Integer.toString(nBytesToRead)));
return read_bytes;
}
/**
* Write bytes.
*
* @param aData the bytes to write.
* @see com.sun.star.connection.XConnection#write
*/
public void write(byte aData[]) throws com.sun.star.io.IOException,
com.sun.star.uno.RuntimeException {
try {
_outputStream.write(aData);
} catch(IOException ioException) {
com.sun.star.io.IOException unoIOException = new com.sun.star.io.IOException(ioException);
notifyListeners_error(unoIOException);
throw unoIOException;
}
if (DEBUG) System.err.println(String.format("##### %s - wrote %s bytes", getClass().getName(), Integer.toString(aData.length)));
}
/**
* Sends the data over the websocket to whatever is on the other side.
*
* **NOTE**: unlike with genuine streams, without flushing the data is
* never sent
*
* @see com.sun.star.connection.XConnection#flush
*/
public void flush() throws com.sun.star.io.IOException,
com.sun.star.uno.RuntimeException {
try {
_outputStream.flush();
Integer available = _outputStreamReader.available();
byte[] outputBytes = new byte[available + outgoingPrefix.length];
System.arraycopy(outgoingPrefix, 0, outputBytes, 0, outgoingPrefix.length);
_outputStreamReader.read(outputBytes, outgoingPrefix.length, available);
send(outputBytes);
} catch(IOException ioException) {
com.sun.star.io.IOException unoIOException = new com.sun.star.io.IOException(ioException);
notifyListeners_error(unoIOException);
throw unoIOException;
}
if (DEBUG)
System.err.println(String.format("##### %s - flushed", getClass().getName()));
}
/**
* Closes the connection.
*
* @see com.sun.star.connection.XConnection#close
*/
public void close() throws com.sun.star.uno.RuntimeException {
if (DEBUG) System.err.println("##### " + getClass().getName() + " - socket closed");
}
/**
* Gives a description of the connection.
*
* @return the description.
* @see com.sun.star.connection.XConnection#getDescription
*/
public String getDescription() throws com.sun.star.uno.RuntimeException {
return _description;
}
@Override
public void onOpen(ServerHandshake handshakedata) {
notifyListeners_open();
}
@Override
public void onClose(int code, String reason, boolean remote) {
notifyListeners_close();
}
@Override
public void onMessage(String message) {
String[] messageParts = message.split(": ", 2);
if (messageParts.length != 2)
{
notifyListeners_error(new com.sun.star.uno.Exception(new ProtocolException(String.format("Recieved URP/WS message (%s) without a type specifier. Messages must be proceeded by 'urp: '", message))));
return;
}
String messageType = messageParts[0];
if (!messageType.equals("urp"))
{
if (DEBUG) System.err.println(String.format("##### %s - received %s message but that is not URP", getClass().getName(), messageType));
return;
}
byte[] messageBytes = messageParts[1].getBytes();
try {
_inputStreamWriter.write(messageBytes);
} catch (IOException e) {
notifyListeners_error(new com.sun.star.uno.Exception(e));
return;
}
if (DEBUG) System.err.println(String.format("##### %s - recieved %s chars", getClass().getName(), Integer.toString(messageBytes.length)));
}
@Override
public void onMessage(ByteBuffer message) {
byte[] prefixedMessageBytes = message.array();
String messageType = "";
boolean hasType = false;
int i;
for (i = 0; i < prefixedMessageBytes.length - 1; i++) {
if (prefixedMessageBytes[i] == ':' && (prefixedMessageBytes[i+1] == ' ' || prefixedMessageBytes[i+1] == '\n')) {
hasType = true;
break; // The type ends with ": ", so if we find this sequence we found the end of our type
}
messageType += (char)prefixedMessageBytes[i];
}
if(!hasType) {
notifyListeners_error(new com.sun.star.uno.Exception(new ProtocolException(String.format("Recieved URP/WS message (%s) without a type specifier. Binary messages must be proceeded by 'urp: ' or 'urp:\\n'", message))));
return;
}
int messageStartIndex = i + 2;
if (!messageType.equals("urp")) {
if (DEBUG) System.err.println(String.format("##### %s - recieved %s binary message but that is not URP", getClass().getName(), messageType));
return;
}
byte[] messageBytes = Arrays.copyOfRange(prefixedMessageBytes, messageStartIndex, prefixedMessageBytes.length);
try {
_inputStreamWriter.write(messageBytes);
} catch (IOException e) {
notifyListeners_error(new com.sun.star.uno.Exception(e));
return;
}
if (DEBUG) System.err.println(String.format("##### %s - recieved %s bytes", getClass().getName(), Integer.toString(prefixedMessageBytes.length)));
}
@Override
public void onError(Exception ex) {
notifyListeners_error(new com.sun.star.uno.Exception(ex));
}
}
/* vim:set shiftwidth=4 softtabstop=4 expandtab: */

View file

@ -0,0 +1,137 @@
/* -*- Mode: Java; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
/*
* This file is part of the LibreOffice project.
*
* This Source Code Form is subject to the terms of the Mozilla Public
* License, v. 2.0. If a copy of the MPL was not distributed with this
* file, You can obtain one at http://mozilla.org/MPL/2.0/.
*
* This file incorporates work covered by the following license notice:
*
* Licensed to the Apache Software Foundation (ASF) under one or more
* contributor license agreements. See the NOTICE file distributed
* with this work for additional information regarding copyright
* ownership. The ASF licenses this file to you under the Apache
* License, Version 2.0 (the "License"); you may not use this file
* except in compliance with the License. You may obtain a copy of
* the License at http://www.apache.org/licenses/LICENSE-2.0 .
*/
package com.sun.star.lib.connections.websocket;
import com.sun.star.comp.loader.FactoryHelper;
import com.sun.star.connection.ConnectionSetupException;
import com.sun.star.connection.NoConnectException;
import com.sun.star.connection.XConnection;
import com.sun.star.connection.XConnector;
import com.sun.star.lang.XMultiServiceFactory;
import com.sun.star.lang.XSingleServiceFactory;
import com.sun.star.registry.XRegistryKey;
import java.io.IOException;
import java.net.InetAddress;
import java.net.Socket;
import java.net.URISyntaxException;
import java.net.UnknownHostException;
/**
* A component that implements the <code>XConnector</code> interface.
*
* <p>The <code>websocketConnector</code> is a specialized component that uses
* websockets for communication. The <code>websocketConnector</code> is generally
* used by the <code>com.sun.star.connection.Connector</code> service.</p>
*
* @see com.sun.star.connection.XAcceptor
* @see com.sun.star.connection.XConnection
* @see com.sun.star.connection.XConnector
* @see com.sun.star.comp.loader.JavaLoader
*/
public final class websocketConnector implements XConnector {
/**
* The name of the service.
*
* <p>The <code>JavaLoader</code> accesses this through reflection.</p>
*
* @see com.sun.star.comp.loader.JavaLoader
*/
public static final String __serviceName
= "com.sun.star.connection.websocketConnector";
/**
* Returns a factory for creating the service.
*
* <p>This method is called by the <code>JavaLoader</code>.</p>
*
* @param implName the name of the implementation for which a service is
* requested.
* @param multiFactory the service manager to be used (if needed).
* @param regKey the registry key.
* @return an <code>XSingleServiceFactory</code> for creating the component.
*
* @see com.sun.star.comp.loader.JavaLoader
*/
public static XSingleServiceFactory __getServiceFactory(
String implName, XMultiServiceFactory multiFactory, XRegistryKey regKey)
{
return implName.equals(websocketConnector.class.getName())
? FactoryHelper.getServiceFactory(websocketConnector.class,
__serviceName, multiFactory,
regKey)
: null;
}
/**
* Connects via the described websocket to a waiting server.
*
* <p>The connection description has the following format:
* <code><var>type</var></code><!--
* -->*(<code><var>key</var>=<var>value</var></code>),
* where <code><var>type</var></code> should be <code>websocket</code>
* (ignoring case). Supported keys (ignoring case) currently are</p>
* <dl>
* <dt><code>url</code>
* <dd>The URL the websocket server is listening on, starting with
* either ws:// or wss://
* </dl>
*
* @param connectionDescription the description of the connection.
* @return an <code>XConnection</code> to the server.
*
* @see com.sun.star.connection.XAcceptor
* @see com.sun.star.connection.XConnection
*/
public synchronized XConnection connect(String connectionDescription)
throws NoConnectException, ConnectionSetupException
{
if (connected)
throw new ConnectionSetupException("Already connected to the socket");
ConnectionDescriptor desc;
try {
desc = new ConnectionDescriptor(connectionDescription);
} catch (com.sun.star.lang.IllegalArgumentException e) {
throw new ConnectionSetupException(e);
}
WebsocketConnection websocket = null;
try {
websocket = new WebsocketConnection(connectionDescription, desc);
connected = websocket.isOpen();
} catch (IOException e) {
throw new ConnectionSetupException(e);
} catch (URISyntaxException e) {
throw new ConnectionSetupException(e);
} catch (InterruptedException e) {
throw new ConnectionSetupException(e);
}
if (websocket == null || !connected)
throw new ConnectionSetupException("Could not connect to the server. Is it up?");
return websocket;
}
private boolean connected = false;
}
/* vim:set shiftwidth=4 softtabstop=4 expandtab: */

View file

@ -64,6 +64,7 @@ module org.libreoffice.uno
exports com.sun.star.ldap;
exports com.sun.star.lib.connections.pipe;
exports com.sun.star.lib.connections.socket;
exports com.sun.star.lib.connections.websocket;
exports com.sun.star.lib.uno;
exports com.sun.star.lib.uno.adapter;
exports com.sun.star.lib.uno.bridges.java_remote;

View file

@ -24,6 +24,9 @@ Sealed: true
Name: com/sun/star/lib/connections/socket/
Sealed: true
Name: com/sun/star/lib/connections/websocket/
Sealed: true
Name: com/sun/star/lib/uno/
Sealed: true

View file

@ -74,6 +74,7 @@ ELF platforms (Linux, Solaris, *BSD):
/opt/libreoffice/ure/lib/libstocserviceslo.so [private]
/opt/libreoffice/ure/lib/libuuresolverlo.so [private]
/opt/libreoffice/ure/share/java/java_uno.jar [private]
/opt/libreoffice/ure/share/java/java_websocket.jar [private]
/opt/libreoffice/ure/share/misc/javavendors.xml [private]
Windows:
@ -132,6 +133,7 @@ Program Files\URE\bin\stocserviceslo.dll [private]
Program Files\URE\bin\uuresolverlo.dll [private]
Program Files\URE\bin\uwinapi.dll [private]
Program Files\URE\java\java_uno.jar [private]
Program Files\URE\java\java_websocket.jar [private]
Program Files\URE\misc\javavendors.xml [private]
%windir%\assembly\cli_basetypes.dll [GAC]