Package com.sun.star.lib.uno.bridges.java_remote

Source Code of com.sun.star.lib.uno.bridges.java_remote.java_remote_bridge$RefHolder

/*************************************************************************
*
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
*
* Copyright 2008 by Sun Microsystems, Inc.
*
* OpenOffice.org - a multi-platform office productivity suite
*
* $RCSfile: java_remote_bridge.java,v $
* $Revision: 1.45 $
*
* This file is part of OpenOffice.org.
*
* OpenOffice.org is free software: you can redistribute it and/or modify
* it under the terms of the GNU Lesser General Public License version 3
* only, as published by the Free Software Foundation.
*
* OpenOffice.org is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
* GNU Lesser General Public License version 3 for more details
* (a copy is included in the LICENSE file that accompanied this code).
*
* You should have received a copy of the GNU Lesser General Public License
* version 3 along with OpenOffice.org.  If not, see
* <http://www.openoffice.org/license.html>
* for a copy of the LGPLv3 License.
*
************************************************************************/
package com.sun.star.lib.uno.bridges.java_remote;


import java.io.IOException;
import java.io.InputStream;
import java.io.OutputStream;

import java.lang.reflect.Array;
import java.lang.reflect.Constructor;
import java.lang.reflect.InvocationTargetException;
import java.lang.reflect.Method;

import java.util.ArrayList;
import java.util.Enumeration;
import java.util.HashMap;
import java.util.Iterator;
import java.util.LinkedList;
import java.util.Map;
import java.util.Vector;

import com.sun.star.lib.util.DisposeListener;
import com.sun.star.lib.util.DisposeNotifier;

import com.sun.star.bridge.XBridge;
import com.sun.star.bridge.XInstanceProvider;

import com.sun.star.comp.loader.FactoryHelper;

import com.sun.star.connection.XConnection;
import com.sun.star.container.NoSuchElementException;
import com.sun.star.lang.EventObject;
import com.sun.star.lang.XComponent;
import com.sun.star.lang.XEventListener;
import com.sun.star.lang.XMultiServiceFactory;
import com.sun.star.lang.XSingleServiceFactory;
import com.sun.star.lang.DisposedException;

import com.sun.star.lib.uno.environments.java.java_environment;
import com.sun.star.lib.uno.environments.remote.IProtocol;
import com.sun.star.lib.uno.environments.remote.IReceiver;
import com.sun.star.lib.uno.environments.remote.Job;
import com.sun.star.lib.uno.environments.remote.Message;
import com.sun.star.lib.uno.environments.remote.ThreadId;
import com.sun.star.lib.uno.environments.remote.ThreadPoolManager;
import com.sun.star.lib.uno.environments.remote.IThreadPool;

import com.sun.star.lib.uno.typedesc.MethodDescription;
import com.sun.star.lib.uno.typedesc.TypeDescription;

import com.sun.star.registry.XRegistryKey;

import com.sun.star.uno.IBridge;
import com.sun.star.uno.IEnvironment;
import com.sun.star.uno.UnoRuntime;
import com.sun.star.uno.XInterface;
import com.sun.star.uno.Type;
import com.sun.star.uno.TypeClass;
import com.sun.star.uno.Any;

/**
* This class implements a remote bridge. Therefor
* various interfaces are implemented.
* <p>
* The protocol to used is passed by name, the bridge
* then looks for it under <code>com.sun.star.lib.uno.protocols</code>.
* <p>
* @version   $Revision: 1.45 $ $ $Date: 2008/04/11 11:18:08 $
* @author       Kay Ramme
* @since       UDK1.0
*/
public class java_remote_bridge
    implements IBridge, IReceiver, RequestHandler, XBridge, XComponent,
        DisposeNotifier
{
  /**
   * When set to true, enables various debugging output.
   */
  static private final boolean DEBUG = false;

    private final class MessageDispatcher extends Thread {
        public MessageDispatcher() {
            super("MessageDispatcher");
        }

        public void run() {
            try {
                for (;;) {
                    synchronized (this) {
                        if (terminate) {
                            break;
                        }
                    }
                    Message msg = _iProtocol.readMessage();
                    Object obj = null;
                    if (msg.isRequest()) {
                        String oid = msg.getObjectId();
                        Type type = new Type(msg.getType());
                        int fid = msg.getMethod().getIndex();
                        if (fid == MethodDescription.ID_RELEASE) {
                            _java_environment.revokeInterface(oid, type);
                            remRefHolder(type, oid);
                            if (msg.isSynchronous()) {
                                sendReply(false, msg.getThreadId(), null);
                            }
                            continue;
                        }
                        obj = _java_environment.getRegisteredInterface(
                            oid, type);
                        if (obj == null
                            && fid == MethodDescription.ID_QUERY_INTERFACE)
                        {
                            if (_xInstanceProvider == null) {
                                sendReply(
                                    true, msg.getThreadId(),
                                    new com.sun.star.uno.RuntimeException(
                                        "unknown OID " + oid));
                                continue;
                            } else {
                                UnoRuntime.setCurrentContext(
                                    msg.getCurrentContext());
                                try {
                                    obj = _xInstanceProvider.getInstance(oid);
                                } catch (com.sun.star.uno.RuntimeException e) {
                                    sendReply(true, msg.getThreadId(), e);
                                    continue;
                                } catch (Exception e) {
                                    sendReply(
                                        true, msg.getThreadId(),
                                        new com.sun.star.uno.RuntimeException(
                                            e.toString()));
                                    continue;
                                } finally {
                                    UnoRuntime.setCurrentContext(null);
                                }
                            }
                        }
                    }
                    _iThreadPool.putJob(
                        new Job(obj, java_remote_bridge.this, msg));
                }
            } catch (Throwable e) {
                dispose(new DisposedException(e.toString()));
            }
        }

        public synchronized void terminate() {
            terminate = true;
        }

        private boolean terminate = false;
    }

  protected XConnection       _xConnection;

  protected XInstanceProvider _xInstanceProvider;

  protected String            _name = "remote";
    private final String protocol;
  protected IProtocol         _iProtocol;
  protected IEnvironment      _java_environment;
  protected MessageDispatcher _messageDispatcher;
  protected int               _life_count = 0;    // determines if this bridge is alife, which is controlled by acquire and release calls

  private final Vector _listeners = new Vector();

  protected IThreadPool       _iThreadPool;

    // Variable disposed must only be used while synchronized on this object:
    private boolean disposed = false;

  /**
   * This method is for testing only.
   */
  int getLifeCount() {
    return _life_count;
  }

  /**
   * This method is for testing only.
   */
  IProtocol getProtocol() {
    return _iProtocol;
  }

    // The ref holder stuff strongly holds objects mapped out via this bridge
    // (the java_environment only holds them weakly).  When this bridge is
    // disposed, all remaining ref holder entries are released.

    private static final class RefHolder {
        public RefHolder(Type type, Object object) {
            this.type = type;
            this.object = object;
        }

        public Type getType() {
            return type;
        }

        public void acquire() {
            ++count;
        }

        public boolean release() {
            return --count == 0;
        }

        private final Type type;
        private final Object object;
        private int count = 1;
    }

  private final HashMap refHolders = new HashMap();
        // from OID (String) to LinkedList of RefHolder

    private boolean hasRefHolder(String oid, Type type) {
        synchronized (refHolders) {
            LinkedList l = (LinkedList) refHolders.get(oid);
            if (l != null) {
                for (Iterator i = l.iterator(); i.hasNext();) {
                    RefHolder rh = (RefHolder) i.next();
                    if (type.isSupertypeOf(rh.getType())) {
                        return true;
                    }
                }
            }
        }
        return false;
    }

    final void addRefHolder(Object obj, Type type, String oid) {
        synchronized (refHolders) {
            LinkedList l = (LinkedList) refHolders.get(oid);
            if (l == null) {
                l = new LinkedList();
                refHolders.put(oid, l);
            }
            boolean found = false;
            for (Iterator i = l.iterator(); !found && i.hasNext();) {
                RefHolder rh = (RefHolder) i.next();
                if (rh.getType().equals(type)) {
                    found = true;
                    rh.acquire();
                }
            }
            if (!found) {
                l.add(new RefHolder(type, obj));
            }
        }
        acquire();
    }

    final void remRefHolder(Type type, String oid) {
        synchronized (refHolders) {
            LinkedList l = (LinkedList) refHolders.get(oid);
            if (l != null) {
                for (Iterator i = l.iterator(); i.hasNext();) {
                    RefHolder rh = (RefHolder) i.next();
                    if (rh.getType().equals(type)) {
                        try {
                            if (rh.release()) {
                                l.remove(rh);
                                if (l.isEmpty()) {
                                    refHolders.remove(oid);
                                }
                            }
                        } finally {
                            release();
                        }
                        break;
                    }
                }
            }
        }
    }

    final void freeHolders() {
        synchronized (refHolders) {
            for (Iterator i1 = refHolders.entrySet().iterator(); i1.hasNext();)
            {
                Map.Entry e = (Map.Entry) i1.next();
                String oid = (String) e.getKey();
                LinkedList l = (LinkedList) e.getValue();
                for (Iterator i2 = l.iterator(); i2.hasNext();) {
                    RefHolder rh = (RefHolder) i2.next();
                    for (boolean done = false; !done;) {
                        done = rh.release();
                        _java_environment.revokeInterface(oid, rh.getType());
                        release();
                    }
                }
            }
            refHolders.clear();
        }
    }

    public java_remote_bridge(
        IEnvironment java_environment, IEnvironment remote_environment,
        Object[] args)
        throws Exception
    {
        _java_environment = java_environment;
        String proto = (String) args[0];
        _xConnection = (XConnection) args[1];
        _xInstanceProvider = (XInstanceProvider) args[2];
        if (args.length > 3) {
            _name = (String) args[3];
        }
        String attr;
        int i = proto.indexOf(',');
        if (i >= 0) {
            protocol = proto.substring(0, i);
            attr = proto.substring(i + 1);
        } else {
            protocol = proto;
            attr = null;
        }
        _iProtocol = (IProtocol) Class.forName(
            "com.sun.star.lib.uno.protocols." + protocol + "." + protocol).
            getConstructor(
                new Class[] {
                    IBridge.class, String.class, InputStream.class,
                    OutputStream.class }).
            newInstance(
                new Object[] {
                    this, attr,
                    new XConnectionInputStream_Adapter(_xConnection),
                    new XConnectionOutputStream_Adapter(_xConnection) });
        proxyFactory = new ProxyFactory(this, this);
        _iThreadPool = ThreadPoolManager.create();
        _messageDispatcher = new MessageDispatcher();
        _messageDispatcher.start();
        _iProtocol.init();
    }

  private void notifyListeners() {
    EventObject eventObject = new EventObject(this);

    Enumeration elements = _listeners.elements();
    while(elements.hasMoreElements()) {
      XEventListener xEventListener = (XEventListener)elements.nextElement();

      try {
        xEventListener.disposing(eventObject);
      }
      catch(com.sun.star.uno.RuntimeException runtimeException) {
        // we are here not interested in any exceptions
      }
    }
  }

  /**
   * Constructs a new bridge.
   * <p>
   * This method is not part of the provided <code>api</code>
   * and should only be used by the UNO runtime.
   * <p>
   * @deprecated as of UDK 1.0
   * <p>
   * @param  args               the custom parameters: arg[0] == protocol_name, arg[1] == xConnection, arg[2] == xInstanceProvider
   */
  public java_remote_bridge(Object args[]) throws Exception {
    this(UnoRuntime.getEnvironment("java", null), UnoRuntime.getEnvironment("remote", null), args);
  }

    // @see com.sun.star.uno.IBridge#mapInterfaceTo
    public Object mapInterfaceTo(Object object, Type type) {
        checkDisposed();
        if (object == null) {
            return null;
        } else {
            String[] oid = new String[1];
            object = _java_environment.registerInterface(object, oid, type);
            if (!proxyFactory.isProxy(object)) {
                // This branch must be taken iff object either is no proxy at
                // all or a proxy from some other bridge.  There are objects
                // that behave like objects for this bridge but that are not
                // detected as such by proxyFactory.isProxy.  The only known
                // case of such objects is com.sun.star.comp.beans.Wrapper,
                // which implements com.sun.star.lib.uno.Proxy and effectively
                // is a second proxy around a proxy that can be from this
                // bridge.  For that case, there is no problem, however:  Since
                // the proxies generated by ProxyFactory send each
                // queryInterface to the original object (i.e., they do not
                // short-circuit requests for a super-interface to themselves),
                // there will always be an appropriate ProxyFactory-proxy
                // registered at the _java_environment, so that the object
                // returned by _java_environment.registerInterface will never be
                // a com.sun.star.comp.beans.Wrapper.
                addRefHolder(object, type, oid[0]);
            }
            return oid[0];
        }
  }

  /**
   * Maps an object from destination environment to the source environment.
   * <p>
   * @return     the object in the source environment
   * @param      object     the object to map
   * @param      type       the interface under which is to be mapped
   * @see                   com.sun.star.uno.IBridge#mapInterfaceFrom
   */
  public Object mapInterfaceFrom(Object oId, Type type) {
        checkDisposed();
        // TODO  What happens if an exception is thrown after the call to
        // acquire, but before it is guaranteed that a pairing release will be
        // called eventually?
    acquire();
        String oid = (String) oId;
    Object object = _java_environment.getRegisteredInterface(oid, type);
        if (object == null) {
      object = _java_environment.registerInterface(
                proxyFactory.create(oid, type), new String[] { oid }, type);
                // the proxy sends a release when finalized
        } else if (!hasRefHolder(oid, type)) {
            sendInternalRequest(oid, type, "release", null);
        }
    return object;
  }

  /**
   * Gives the source environment.
   * <p>
   * @return   the source environment of this bridge
   * @see      com.sun.star.uno.IBridge#getSourceEnvironment
   */
  public IEnvironment getSourceEnvironment() {
    return _java_environment;
  }

  /**
   * Gives the destination environment.
   * <p>
   * @return   the destination environment of this bridge
   * @see      com.sun.star.uno.IBridge#getTargetEnvironment
   */
  public IEnvironment getTargetEnvironment() {
    return null;
  }

  /**
   * Increases the life count.
   * <p>
   * @see com.sun.star.uno.IBridge#acquire
   */
  public synchronized void acquire() {
    ++ _life_count;

    if(DEBUG) System.err.println("##### " + getClass().getName() + ".acquire:" + _life_count);
  }

  /**
   * Decreases the life count.
   * If the life count drops to zero, the bridge disposes itself.
   * <p>
   * @see com.sun.star.uno.IBridge#release
   */
    public void release() {
        boolean dispose;
        synchronized (this) {
            --_life_count;
            dispose = _life_count <= 0;
        }
        if (dispose) {
            dispose(new com.sun.star.uno.RuntimeException("end of life"));
        }
    }

  public void dispose() {
    dispose(new com.sun.star.uno.RuntimeException("user dispose"));
  }

    private void dispose(Throwable throwable) {
        synchronized (this) {
            if (disposed) {
                return;
            }
            disposed = true;
        }

        notifyListeners();
        for (Iterator i = disposeListeners.iterator(); i.hasNext();) {
            ((DisposeListener) i.next()).notifyDispose(this);
        }

        try {
            _messageDispatcher.terminate();

            _xConnection.close();

            if (Thread.currentThread() != _messageDispatcher
                && _messageDispatcher.isAlive())
            {
                // This is a workaround for a Linux Sun JDK1.3 problem:  The
                // message dispatcher stays in the socket read method, even if
                // the socket has been closed.  Suspending and resuming the
                // message dispatcher lets it notice the closed socket.  Only
                // use this workaround for Linux JRE 1.3.0 and 1.3.1 from Sun
                // and Blackdown.  This workaround is dangerouse and may
                // hardlock the VM.
                if (System.getProperty("os.name", "").toLowerCase().equals(
                        "linux")
          && System.getProperty("java.version", "").startsWith("1.3.")
          && (System.getProperty("java.vendor", "").toLowerCase().
                            indexOf("sun") != -1
                        || System.getProperty("java.vendor", "").toLowerCase().
                            indexOf("blackdown") != -1))
                {
                    _messageDispatcher.suspend();
                    _messageDispatcher.resume();
                }

                _messageDispatcher.join(1000);
                if (_messageDispatcher.isAlive()) {
                    _messageDispatcher.interrupt();
                    _messageDispatcher.join();
                }
            }

            // interrupt all jobs queued by this bridge
            _iThreadPool.dispose(throwable);

            // release all out-mapped objects and all in-mapped proxies:
            freeHolders();
            // assert _java_environment instanceof java_environment;
            ((java_environment) _java_environment).revokeAllProxies();

            if (DEBUG) {
        if (_life_count != 0) {
          System.err.println(getClass().getName()
                                       + ".dispose - life count (proxies left):"
                                       + _life_count);
                }
                _java_environment.list();
            }
       
            // clear members
            _xConnection        = null;
            _java_environment   = null;
            _messageDispatcher  = null;
        } catch (InterruptedException e) {
            System.err.println(getClass().getName()
                               + ".dispose - InterruptedException:" + e);
        } catch (com.sun.star.io.IOException e) {
            System.err.println(getClass().getName() + ".dispose - IOException:"
                               + e);
        }
  }

    // @see com.sun.star.bridge.XBridge#getInstance
    public Object getInstance(String instanceName) {
        Type t = new Type(XInterface.class);
        return sendInternalRequest(
            instanceName, t, "queryInterface", new Object[] { t });
    }

  /**
   * Gives the name of this bridge
   * <p>
   * @return  the name of this bridge
   * @see     com.sun.star.bridge.XBridge#getName
   */
    public String getName() {
    return _name;
  }

  /**
   * Gives a description of the connection type and protocol used
   * <p>
   * @return  connection type and protocol
   * @see     com.sun.star.bridge.XBridge#getDescription
   */
    public String getDescription() {
        return protocol + "," + _xConnection.getDescription();
  }

    public void sendReply(boolean exception, ThreadId threadId, Object result) {
        if (DEBUG) {
            System.err.println("##### " + getClass().getName() + ".sendReply: "
                               + exception + " " + result);
        }

        checkDisposed();

        try {
            _iProtocol.writeReply(exception, threadId, result);
        } catch (IOException e) {
            dispose(e);
            throw new DisposedException("unexpected " + e);
        } catch (RuntimeException e) {
            dispose(e);
            throw e;
        } catch (Error e) {
            dispose(e);
            throw e;
        }
    }

    public Object sendRequest(
        String oid, Type type, String operation, Object[] params)
        throws Throwable
    {
    Object result = null;

        checkDisposed();

    boolean goThroughThreadPool = false;

        ThreadId threadId = _iThreadPool.getThreadId();
        Object handle = _iThreadPool.attach(threadId);
        try {
            boolean sync;
            try {
                sync = _iProtocol.writeRequest(
                    oid, TypeDescription.getTypeDescription(type), operation,
                    threadId, params);
            } catch (IOException e) {
                DisposedException d = new DisposedException(e.toString());
                dispose(d);
                throw d;
            }
            if (sync && Thread.currentThread() != _messageDispatcher) {
                result = _iThreadPool.enter(handle, threadId);
            }
        } finally {
            _iThreadPool.detach(handle, threadId);
      if(operation.equals("release"))
        release(); // kill this bridge, if this was the last proxy
    }

    if(DEBUG) System.err.println("##### " + getClass().getName() + ".sendRequest left:" + result);

        // On the wire (at least in URP), the result of queryInterface is
        // transported as an ANY, but in Java it shall be transported as a
        // direct reference to the UNO object (represented as a Java Object),
        // never boxed in a com.sun.star.uno.Any:
        if (operation.equals("queryInterface") && result instanceof Any) {
            Any a = (Any) result;
            if (a.getType().getTypeClass() == TypeClass.INTERFACE) {
                result = a.getObject();
            } else {
                result = null; // should never happen
            }
        }

    return result;
  }

    private Object sendInternalRequest(
        String oid, Type type, String operation, Object[] arguments)
    {
        try {
            return sendRequest(oid, type, operation, arguments);
        } catch (Error e) {
            throw e;
        } catch (RuntimeException e) {
            throw e;
        } catch (Throwable e) {
            throw new RuntimeException("Unexpected " + e);
        }
    }

    // Methods XComponent
    public void addEventListener(XEventListener xEventListener) {
    _listeners.addElement(xEventListener);
  }

    public void removeEventListener(XEventListener xEventListener) {
    _listeners.removeElement(xEventListener);
  }

    // @see NotifyDispose.addDisposeListener
    public void addDisposeListener(DisposeListener listener) {
        synchronized (this) {
            if (!disposed) {
                disposeListeners.add(listener);
                return;
            }
        }
        listener.notifyDispose(this);
    }

    // This function must only be called while synchronized on this object:
    private synchronized void checkDisposed() {
        if (disposed) {
            throw new DisposedException("java_remote_bridge " + this
                                        + " is disposed");
        }
    }

    private final ProxyFactory proxyFactory;

    // Access to disposeListeners must be synchronized on <CODE>this</CODE>:
    private final ArrayList disposeListeners = new ArrayList();
}
TOP

Related Classes of com.sun.star.lib.uno.bridges.java_remote.java_remote_bridge$RefHolder

TOP
Copyright © 2018 www.massapi.com. All rights reserved.
All source code are property of their respective owners. Java is a trademark of Sun Microsystems, Inc and owned by ORACLE Inc. Contact coftware#gmail.com.