diff options
author | Daniel Baumann <daniel.baumann@progress-linux.org> | 2024-04-07 09:06:44 +0000 |
---|---|---|
committer | Daniel Baumann <daniel.baumann@progress-linux.org> | 2024-04-07 09:06:44 +0000 |
commit | ed5640d8b587fbcfed7dd7967f3de04b37a76f26 (patch) | |
tree | 7a5f7c6c9d02226d7471cb3cc8fbbf631b415303 /ridljar/com/sun/star/lib/uno/environments/remote | |
parent | Initial commit. (diff) | |
download | libreoffice-ed5640d8b587fbcfed7dd7967f3de04b37a76f26.tar.xz libreoffice-ed5640d8b587fbcfed7dd7967f3de04b37a76f26.zip |
Adding upstream version 4:7.4.7.upstream/4%7.4.7upstream
Signed-off-by: Daniel Baumann <daniel.baumann@progress-linux.org>
Diffstat (limited to 'ridljar/com/sun/star/lib/uno/environments/remote')
12 files changed, 1527 insertions, 0 deletions
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. + * + * <p>A class implementing a given protocol <var>prot</var> must be named + * <code>com.sun.star.lib.uno.protocols.<var>prot</var>.<var>prot</var></code> + * and must have a public constructor that takes four arguments: The first + * argument of type <code>com.sun.star.uno.IBridge</code> must not be null. The + * second argument of type <code>String</code> represents any attributes; it may + * be null if there are no attributes. The third argument of type + * <code>java.io.InputStream</code> must not be null. The fourth argument of + * type <code>java.io.OutputStream</code> must not be null.</p> + */ +public interface IProtocol { + /** + * Initializes the connection. + * + * <p>This method must be called exactly once, after the + * <code>readMessage</code> loop has already been established.</p> + */ + void init() throws IOException; + + void terminate(); + + /** + * Reads a request or reply message. + * + * <p>Access to this method from multiple threads must be properly + * synchronized.</p> + * + * @return a non-null message; if the input stream is exhausted, a + * <code>java.io.IOException</code> is thrown instead. + */ + Message readMessage() throws IOException; + + /** + * Writes a request message. + * + * @param oid a non-null OID. + * @param type a non-null UNO type. + * @param function a non-null function (the name of a UNO interface method + * or attribute compatible with the given <code>type</code>, or either + * <code>"queryInterface"</code> or <code>"release"</code>). + * @param tid a non-null TID. + * @param arguments a list of UNO arguments compatible with the given + * <code>type</code> and <code>function</code>; may be null to represent + * an empty list. + * @return <code>true</code> if the request message is sent as a synchronous + * request. + */ + boolean writeRequest( + String oid, TypeDescription type, String function, ThreadId tid, + Object[] arguments) + throws IOException; + + /** + * Writes a reply message. + * + * @param exception <code>true</code> if the reply corresponds to a raised + * exception. + * @param tid a non-null TID. + * @param result if <code>exception</code> is <code>true</code>, a non-null + * UNO exception; otherwise, a UNO return value, which may be null to + * represent a <code>VOID</code> return value. + */ + void writeReply(boolean exception, ThreadId tid, Object result) + throws IOException; +} + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/ridljar/com/sun/star/lib/uno/environments/remote/IReceiver.java b/ridljar/com/sun/star/lib/uno/environments/remote/IReceiver.java new file mode 100644 index 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 <CODE>true</CODE> if an exception (instead of a normal + * result) is sent back. + * @param threadId the thread ID of the request. + * @param result the result of executing the request, or an exception thrown + * while executing the request. + */ + void sendReply(boolean exception, ThreadId threadId, Object result); +} + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/ridljar/com/sun/star/lib/uno/environments/remote/IThreadPool.java b/ridljar/com/sun/star/lib/uno/environments/remote/IThreadPool.java new file mode 100644 index 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. + * + * <p>The function exists for performance.</p> + * + * @return Returns a handle which can be used in enter and detach calls. + * @see #attach + */ + Object attach( ThreadId id ); + + /** + * Detaches this thread from the thread pool. + * @see #enter + */ + void detach(); + + /** + * As above, but hands in an already existing instance of the threadid of + * the current thread and a handle returned by attach. + * + * <p>The function exists for performance.</p> + * + * @see #attach() + * @see #detach() + */ + void detach( Object handle, ThreadId id ); + + /** + * Lets this thread enter the thread pool. + * + * <p>This thread then executes all jobs put via <code>putJob</code> until + * a reply job arrives.</p> + * + * @see #putJob + */ + Object enter() throws Throwable; + + /** + * As above but hands in an already existing instance of the threadid of + * the current thread and a handle returned by attach. + * + * <p>This thread then executes all jobs put via <code>putJob</code> until + * a reply job arrives.</p> + * + * @see #putJob + */ + Object enter( Object handle, ThreadId id ) throws Throwable; + + /** + * Queues a job into the jobQueue of the thread belonging to the jobs + * threadId. + * + * @param job the job + */ + void putJob(Job job); + + /** + * Disposes this thread pool, thus releasing all threads by throwing a + * <code>DisposedException</code> with the given <code>Throwable</code> cause. + * + * @param throwable the cause + */ + void dispose(Throwable throwable); + + + /** + * Destroys the thread pool and tries to join all created threads immediately. + */ + void destroy(); +} + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/ridljar/com/sun/star/lib/uno/environments/remote/JavaThreadPool.java b/ridljar/com/sun/star/lib/uno/environments/remote/JavaThreadPool.java new file mode 100644 index 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<JobQueue> c = jobQueues.values(); + qs = c.toArray(new JobQueue[c.size()]); + } + for (int i = 0; i < qs.length; ++i) { + qs[i].dispose(disposeId, throwable); + } + } + + public static ThreadId getThreadId() { + Thread t = Thread.currentThread(); + if (t instanceof JobQueue.JobDispatcher) { + return ((JobQueue.JobDispatcher) t).getThreadId(); + } else { + ThreadId id; + synchronized (threadIdMap) { + id = threadIdMap.get(t); + if (id == null) { + id = ThreadId.createFresh(); + threadIdMap.put(t, id); + } + } + return id; + } + } + + private static final WeakHashMap<Thread, ThreadId> threadIdMap = new WeakHashMap<Thread, ThreadId>(); + private final HashMap<ThreadId, JobQueue> jobQueues = new HashMap<ThreadId, JobQueue>(); +} + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/ridljar/com/sun/star/lib/uno/environments/remote/Job.java b/ridljar/com/sun/star/lib/uno/environments/remote/Job.java new file mode 100644 index 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 <code>queryInterface</code> call. + * + * @return the result of the call (should be an <code>Any</code>). + */ + protected Object dispatch_queryInterface(Type type) { + Class<?> zInterface = type.getTypeDescription().getZClass(); + + Object result = null; + + Object face = UnoRuntime.queryInterface(zInterface, _object); + // the hell knows why, but empty interfaces a given back as void anys + if(face != null) + result = new Any(type, face); + return result; + } + + /** + * Execute the job. + * + * @return the result of the message. + */ + public Object execute() throws Throwable { + if (_iMessage.isRequest()) { + Object result = null; + Throwable exception = null; + MethodDescription md = _iMessage.getMethod(); + Object[] args = _iMessage.getArguments(); + XCurrentContext oldCC = UnoRuntime.getCurrentContext(); + UnoRuntime.setCurrentContext(_iMessage.getCurrentContext()); + try { + result = md.getIndex() == MethodDescription.ID_QUERY_INTERFACE + ? dispatch_queryInterface((Type) args[0]) + : md.getMethod().invoke(_object, args); + } catch (InvocationTargetException e) { + exception = e.getCause(); + if (exception == null) { + exception = e; + } + } catch (Exception e) { + exception = e; + } finally { + UnoRuntime.setCurrentContext(oldCC); + } + if (_iMessage.isSynchronous()) { + if (exception == null) { + _iReceiver.sendReply( + false, _iMessage.getThreadId(), result); + } else { + // Here we have to be aware of non-UNO exceptions, because + // they may kill a remote side which does not know anything + // about their types: + if (!(exception instanceof com.sun.star.uno.Exception) + && !(exception instanceof + com.sun.star.uno.RuntimeException)) + { + StringWriter writer = new StringWriter(); + exception.printStackTrace(new PrintWriter(writer)); + exception = new com.sun.star.uno.RuntimeException( + "Java exception: <" + writer + ">", null); + } + _iReceiver.sendReply( + true, _iMessage.getThreadId(), exception); + } + } + return null; + } else if (_iMessage.isAbnormalTermination()) { + throw remoteUnoRequestRaisedException(_iMessage.getResult()); + } else { + return _iMessage.getResult(); + } + } + + public ThreadId getThreadId() { + return _iMessage.getThreadId(); + } + + public boolean isRequest() { + return _iMessage.isRequest(); + } + + public boolean isSynchronous() { + return _iMessage.isSynchronous(); + } + + public void dispose() { +// _oId = null; +// _iReceiver = null; +// _threadId = null; +// _object = null; +// _operation = null; +// _param = null; +// _exception = null; +// _zInterface = null; +// _disposeId = null; + } + + /** + * The name of this method is chosen to generate a somewhat self-explanatory + * stack trace. + */ + private Exception remoteUnoRequestRaisedException(Object exception) { + Exception e = (Exception) exception; + e.fillInStackTrace(); + return e; + } +} + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/ridljar/com/sun/star/lib/uno/environments/remote/JobQueue.java b/ridljar/com/sun/star/lib/uno/environments/remote/JobQueue.java new file mode 100644 index 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 <code>JobQueue</code> implements a queue for jobs. + * + * <p>For every jobs thread id exists a job queue which is registered + * at the <code>ThreadPool</code>.</p> + * + * <p>A JobQueue is split into a sync job queue and an async job queue. + * The sync job queue is the registered queue, it delegates async jobs + * (put by <code>putjob</code>) into the async queue, which is only + * known by the sync queue.</p> + * + * @see com.sun.star.lib.uno.environments.remote.IThreadPool + * @see com.sun.star.lib.uno.environments.remote.Job + * @see com.sun.star.lib.uno.environments.remote.ThreadId + * @since UDK1.0 + */ +public class JobQueue { + /** + * When set to true, enables various debugging output. + */ + private static final boolean DEBUG = false; + + final ArrayList<Job> jobList = new ArrayList<Job>(); + + private ThreadId _threadId; // the thread id of the queue + protected int _ref_count = 0; // the stack deepness + private boolean _createThread; // create a worker thread, if needed + private boolean _createThread_now; // create a worker thread, if needed + private Thread _worker_thread; // the thread that does the jobs + + private Object _disposeId; // the active dispose id + private Object _doDispose = null; + private Throwable _throwable; + + JobQueue _async_jobQueue; // chaining job queues for asyncs + protected JobQueue _sync_jobQueue; // chaining job queues for syncs + + private boolean _active = false; + + private JavaThreadPoolFactory _javaThreadPoolFactory; + + /** + * A thread for dispatching jobs. + */ + class JobDispatcher extends Thread { + Object _disposeId; + + JobDispatcher(Object disposeId) { + super("JobDispatcher"); + + if(DEBUG) System.err.println("JobQueue$JobDispatcher.<init>:" + _threadId); + + _disposeId = disposeId; + } + + ThreadId getThreadId() { + return _threadId; + } + + @Override + public void run() { + if(DEBUG) System.err.println("ThreadPool$JobDispatcher.run: " + Thread.currentThread()); + + try { + enter(2000, _disposeId); + } catch(Throwable throwable) { + synchronized (JobQueue.this) { + if(!jobList.isEmpty() || _active) { // there was a job in progress, so give a stack + System.err.println(getClass().getName() + " - exception occurred:" + throwable); + throwable.printStackTrace(System.err); + } + } + } + finally { + release(); + } + + if(DEBUG) System.err.println("##### " + getClass().getName() + ".run - exit:" + _threadId); + } + } + + + /** + * Constructs an async job queue with the given thread id which belongs to + * the given sync job queue. + * + * @param threadId the thread id. + * @see com.sun.star.lib.uno.environments.remote.ThreadId + */ + JobQueue(JavaThreadPoolFactory javaThreadPoolFactory, ThreadId threadId) { + _javaThreadPoolFactory = javaThreadPoolFactory; + _threadId = ThreadId.createFresh(); + + _sync_jobQueue = javaThreadPoolFactory.getJobQueue(threadId); + if(_sync_jobQueue == null) { + _sync_jobQueue = new JobQueue(javaThreadPoolFactory, threadId, true); + _sync_jobQueue.acquire(); + } + + _sync_jobQueue._async_jobQueue = this; + + _createThread = true; + _createThread_now = true; + + acquire(); + + if(DEBUG) System.err.println("##### " + getClass().getName() + " - init:" + _threadId); + } + + /** + * Constructs a sync job queue with the given thread id and the given thread. + * + * @param threadId the thread id. + * @param createThread if true, the queue creates a worker thread if needed. + * @see com.sun.star.lib.uno.environments.remote.ThreadId + */ + JobQueue(JavaThreadPoolFactory javaThreadPoolFactory, ThreadId threadId, boolean createThread){ + _javaThreadPoolFactory = javaThreadPoolFactory; + _threadId = threadId; + _createThread = createThread; + _createThread_now = createThread; + + if(DEBUG) System.err.println("##### " + getClass().getName() + " - init:" + _threadId + " " + createThread); + } + + /** + * Gives the thread id of this queue. + * + * @return the thread id. + * @see com.sun.star.lib.uno.environments.remote.ThreadId + */ + ThreadId getThreadId() { + return _threadId; + } + + synchronized void acquire() { + // add only synchronous queues . + if(_ref_count <= 0 && _sync_jobQueue == null ) + _javaThreadPoolFactory.addJobQueue(this); + + ++ _ref_count; + } + + synchronized void release() { + -- _ref_count; + + if(_ref_count <= 0) { + // only synchronous queues needs to be removed . + if( _sync_jobQueue == null ) + _javaThreadPoolFactory.removeJobQueue(this); + + + if(_sync_jobQueue != null) { + _sync_jobQueue._async_jobQueue = null; + _sync_jobQueue.release(); + } + } + } + + /** + * Removes a job from the queue. + * + * @param waitTime the maximum amount of time to wait for a job. + * @return a job or null if timed out. + */ + private Job removeJob(int waitTime) { + if(DEBUG) System.err.println("##### " + getClass().getName() + ".removeJob:" + jobList + " " + _threadId); + + Job job = null; + synchronized (this) { + // wait max. waitTime time for a job to enter the queue + boolean waited = false; + while(jobList.isEmpty() && (waitTime == 0 || !waited)) { + if(_doDispose == _disposeId) { + _doDispose = null; + throw (DisposedException) + new DisposedException().initCause(_throwable); + } + + // notify sync queues + notifyAll(); + + try { + // wait for new job + wait(waitTime); + } catch(InterruptedException interruptedException) { + throw new com.sun.star.uno.RuntimeException(getClass().getName() + ".removeJob - unexpected:" + interruptedException); + } + + // signal that we have already waited once + waited = true; + } + + + if(!jobList.isEmpty()) { + job = jobList.remove(0); + _active = true; + } + } + + // always wait for asynchron jobqueue to be finished ! + if(job != null && _async_jobQueue != null) { + synchronized(_async_jobQueue) { + // wait for async queue to be empty and last job to be done + while(_async_jobQueue._active || !_async_jobQueue.jobList.isEmpty()) { + if(DEBUG) System.err.println("waiting for async:" + _async_jobQueue.jobList + " " + _async_jobQueue._worker_thread); + + if(_doDispose == _disposeId) { + _doDispose = null; + throw (DisposedException) + new DisposedException().initCause(_throwable); + } + + try { + _async_jobQueue.wait(); + } catch(InterruptedException interruptedException) { + throw new com.sun.star.uno.RuntimeException(getClass().getName() + ".removeJob - unexpected:" + interruptedException); + } + } + } + } + + return job; + } + + /** + * Puts a job into the queue. + * + * @param job the job. + * @param disposeId a dispose id. + */ + synchronized void putJob(Job job, Object disposeId) { + if(DEBUG) System.err.println("##### " + getClass().getName() + ".putJob todoes: " + " job:" + job); + + jobList.add(job); + + if(_worker_thread == null && _createThread && _createThread_now) { // if there is no thread, which dispatches and if shall create one, create one + + acquire(); + + _createThread_now = false; + new JobDispatcher(disposeId).start(); + } + + // always notify possible waiters + notifyAll(); + } + + /** + * Enters the job queue. + * + * @param disposeId a dispose id. + * @return the result of the final job (reply). + */ + Object enter(Object disposeId) throws Throwable { + return enter(0, disposeId); // wait infinitely + } + + /** + * Enters the job queue. + * + * @param waitTime the maximum amount of time to wait for a job (0 means wait infinitely). + * @param disposeId a dispose id. + * @return the result of the final job (reply). + */ + Object enter(int waitTime, Object disposeId) throws Throwable { + if(DEBUG) System.err.println("#####" + getClass().getName() + ".enter: " + _threadId); + + boolean quit = false; + + Object hold_disposeId = _disposeId; + _disposeId = disposeId; + + Object result = null; + + Thread hold_worker_thread = _worker_thread; + _worker_thread = Thread.currentThread(); + + while(!quit) { + Job job = null; + + try { + job = removeJob(waitTime); + + if(job != null) { + try { + result = job.execute(); + } + finally { + _active = false; + } + + if (!job.isRequest()) { + job.dispose(); + + quit = true; + } + + job = null; + } + else + quit = true; + + + } + finally { // ensure that this queue becomes disposed, if necessary + if(DEBUG) System.err.println("##### " + getClass().getName() + ".enter leaving: " + _threadId + " " + _worker_thread + " " + hold_worker_thread + " " + result); + + synchronized(this) { + if(job != null || (quit && jobList.isEmpty())) { + _worker_thread = hold_worker_thread; + + _createThread_now = true; + + _disposeId = hold_disposeId; + + if(_sync_jobQueue != null) + notifyAll(); // notify waiters (e.g. this is an asyncQueue and there is a sync waiting) + } + else + quit = false; + + } + } + } + + return result; + } + + /** + * If the given disposeId is registered, interrupts the worker thread. + * + * @param disposeId the dispose id. + */ + synchronized void dispose(Object disposeId, Throwable throwable) { + if(_sync_jobQueue == null) { // dispose only sync queues + _doDispose = disposeId; + _throwable = throwable; + + // get thread out of wait and let it throw the throwable + if(DEBUG) System.err.println(getClass().getName() + ".dispose - notifying thread"); + + notifyAll(); + } + } +} + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/ridljar/com/sun/star/lib/uno/environments/remote/Message.java b/ridljar/com/sun/star/lib/uno/environments/remote/Message.java new file mode 100644 index 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. + * + * <p>Valid for all kinds of messages.</p> + * + * @return the (non-<code>null</code>) thread ID. + */ + public final ThreadId getThreadId() { + return threadId; + } + + /** + * Returns whether the message is a request or a reply. + * + * <p>Valid for all kinds of messages.</p> + * + * @return <code>true</code> for a request, <code>false</code> for a reply. + */ + public final boolean isRequest() { + return request; + } + + /** + * Returns the object ID of a request message. + * + * <p>Valid only for request messages.</p> + * + * @return the (non-<code>null</code>) object ID for a request, + * <code>null</code> for a reply. + */ + public final String getObjectId() { + return objectId; + } + + /** + * Returns the type of a request message. + * + * <p>Valid only for request messages.</p> + * + * @return the (non-<code>null</code>) type for a request, <code>null</code> + * for a reply. + */ + public final TypeDescription getType() { + return type; + } + + /** + * Returns the method description of a request message. + * + * <p>Valid only for request messages. The returned + * <code>MethodDescription</code> is consistent with the type of the + * message.</p> + * + * @return the (non-<code>null</code>) method description for a request, + * <code>null</code> for a reply. + */ + public final MethodDescription getMethod() { + return method; + } + + /** + * Returns whether the request message is synchronous. + * + * <p>Valid only for request messages.</p> + * + * @return <code>true</code> for a synchronous request, <code>false</code> + * for an asynchronous request or a reply. + */ + public final boolean isSynchronous() { + return synchronous; + } + + /** + * Returns the current context of a request message. + * + * <p>Valid only for request messages.</p> + * + * @return the current context (which may be <code>null</code>) for a + * request, <code>null</code> for a reply. + */ + public XCurrentContext getCurrentContext() { + return currentContext; + } + + /** + * Returns whether the reply message represents abnormal termination. + * + * <p>Valid only for reply messages.</p> + * + * @return <code>true</code> for a reply that represents abnormal + * termination, <code>false</code> for a reply that represents normal + * termination or a request. + */ + public final boolean isAbnormalTermination() { + return abnormalTermination; + } + + /** + * Returns the result of a reply message. + * + * <p>Valid only for reply messages.</p> + * + * @return any (possibly <code>null</code>) return value for a reply that + * represents normal termination, the (non-<code>null</code>) exception for + * a reply that represents abnormal termination, <code>null</code> for a + * request. + */ + public final Object getResult() { + return result; + } + + /** + * Returns the arguments of a message. + * + * <p>Valid only for request messages and reply messages that represent + * normal termination. Any returned array must not be modified.</p> + * + * @return the in and in– { + * }out arguments for a request (possibly + * <code>null</code> for a parameterless function), the out and in– { + * }out + * arguments for a reply that represents normal termination (possibly + * <code>null</code> for a parameterless function), <code>null</code> for a + * reply that represents abnormal termination. + */ + public final Object[] getArguments() { + return arguments; + } + + private final ThreadId threadId; + private final boolean request; + private final String objectId; + private final TypeDescription type; + private final MethodDescription method; + private final boolean synchronous; + private final XCurrentContext currentContext; + private final boolean abnormalTermination; + private final Object result; + private final Object[] arguments; +} + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/ridljar/com/sun/star/lib/uno/environments/remote/NativeThreadPool.java b/ridljar/com/sun/star/lib/uno/environments/remote/NativeThreadPool.java new file mode 100644 index 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 <code>true</code> if this object is the same as the obj argument; + * <code>false</code> otherwise. + * + * @see java.lang.Object#equals + */ + @Override + public boolean equals(Object obj) { + return obj instanceof ThreadId + && Arrays.equals(id, ((ThreadId) obj).id); + } + + /** + * Returns a hash code value for the object. + * + * @return a hash code value for this object. + * @see java.lang.Object#hashCode + */ + @Override + public int hashCode() { + int h = hash; + if (h == 0) { + // Same algorithm as java.util.List.hashCode (also see Java 1.5 + // java.util.Arrays.hashCode(byte[])): + h = 1; + for (int i = 0; i < id.length; ++i) { + h = 31 * h + id[i]; + } + hash = h; + } + return h; + } + + /** + * Returns a string representation of the object. + * + * @return a string representation of the object. + * @see java.lang.Object#toString + */ + @Override + public String toString() { + StringBuffer b = new StringBuffer("[ThreadId:"); + for (int i = 0; i < id.length; ++i) { + String n = Integer.toHexString(id[i] & 0xFF); + if (n.length() == 1) { + b.append('0'); + } + b.append(n); + } + b.append(']'); + return b.toString(); + } + + public byte[] getBytes() { + return id; + } + + private static final String PREFIX = "java:" + UnoRuntime.getUniqueKey() + ":"; + private static final AtomicLong count = new AtomicLong(0); + + private final byte[] id; + private int hash = 0; +} + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/ridljar/com/sun/star/lib/uno/environments/remote/ThreadPoolManager.java b/ridljar/com/sun/star/lib/uno/environments/remote/ThreadPoolManager.java new file mode 100644 index 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. + * + * <P>The thread pool factory is a process-wide resource. It is important that + * all UNO environments within a process share the same thread pool mechanisms: + * if a synchronous UNO call is bridged out from one local UNO environment over + * one remote bridge, and recursively calls back into another local UNO + * environment over another remote bridge, the code in the second environment + * should be executed in the thread that did the original call from the first + * environment.</P> + * + * <P>There are both a Java and a native thread pool factory. A pure Java + * process will always use the Java thread pool factory. A mixed process uses + * the system property <CODE>org.openoffice.native</CODE> (to be set by the + * native code that starts the JVM) to determine which implementation + * to use.</P> + */ +public final class ThreadPoolManager { + /** + * Creates a thread pool instance. + * + * @return a new thread pool instance; will never be <CODE>null</CODE>. + */ + public static synchronized IThreadPool create() { + if (useNative) { + return new NativeThreadPool(); + } else { + if (javaFactory == null) { + javaFactory = new JavaThreadPoolFactory(); + } + return javaFactory.createThreadPool(); + } + } + + /** + * Leads to using the native thread pool factory, unless a Java thread pool + * has already been created. + * + * @return <CODE>false</CODE> if a Java thread pool has already been created. + */ + public static synchronized boolean useNative() { + useNative = javaFactory == null; + return useNative; + } + + private static boolean useNative + = System.getProperty("org.openoffice.native") != null; + private static JavaThreadPoolFactory javaFactory = null; + + private ThreadPoolManager() {} // do not instantiate +} + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/ridljar/com/sun/star/lib/uno/environments/remote/remote_environment.java b/ridljar/com/sun/star/lib/uno/environments/remote/remote_environment.java new file mode 100644 index 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: */ |