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

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

/*************************************************************************
*
*  $RCSfile: java_remote_bridge.java,v $
*
*  $Revision: 1.30.10.3 $
*
*  last change: $Author: vg $ $Date: 2004/03/18 11:52:19 $
*
*  The Contents of this file are made available subject to the terms of
*  either of the following licenses
*
*         - GNU Lesser General Public License Version 2.1
*         - Sun Industry Standards Source License Version 1.1
*
*  Sun Microsystems Inc., October, 2000
*
*  GNU Lesser General Public License Version 2.1
*  =============================================
*  Copyright 2000 by Sun Microsystems, Inc.
*  901 San Antonio Road, Palo Alto, CA 94303, USA
*
*  This library is free software; you can redistribute it and/or
*  modify it under the terms of the GNU Lesser General Public
*  License version 2.1, as published by the Free Software Foundation.
*
*  This library 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 for more details.
*
*  You should have received a copy of the GNU Lesser General Public
*  License along with this library; if not, write to the Free Software
*  Foundation, Inc., 59 Temple Place, Suite 330, Boston,
*  MA  02111-1307  USA
*
*
*  Sun Industry Standards Source License Version 1.1
*  =================================================
*  The contents of this file are subject to the Sun Industry Standards
*  Source License Version 1.1 (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.openoffice.org/license.html.
*
*  Software provided under this License is provided on an "AS IS" basis,
*  WITHOUT WARRANTY OF ANY KIND, EITHER EXPRESSED OR IMPLIED, INCLUDING,
*  WITHOUT LIMITATION, WARRANTIES THAT THE SOFTWARE IS FREE OF DEFECTS,
*  MERCHANTABLE, FIT FOR A PARTICULAR PURPOSE, OR NON-INFRINGING.
*  See the License for the specific provisions governing your rights and
*  obligations concerning the Software.
*
*  The Initial Developer of the Original Code is: Sun Microsystems, Inc.
*
*  Copyright: 2002 by Sun Microsystems, Inc.
*
*  All Rights Reserved.
*
*  Contributor(s): _______________________________________
*
*
************************************************************************/

package com.sun.star.lib.uno.bridges.java_remote;


import java.io.IOException;
import java.io.DataOutputStream;
import java.io.EOFException;
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.Enumeration;
import java.util.Hashtable;
import java.util.Vector;


import com.sun.star.lib.util.IInvokeHook;
import com.sun.star.lib.util.IInvokable;
import com.sun.star.lib.util.WeakTable;

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.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.sandbox.Disposable;

import com.sun.star.lib.uno.environments.java.java_environment;
import com.sun.star.lib.uno.environments.remote.IMessage;
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.ThreadId;
import com.sun.star.lib.uno.environments.remote.ThreadPoolFactory;
import com.sun.star.lib.uno.environments.remote.IThreadPool;

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

import com.sun.star.lib.util.IStableObject;
import com.sun.star.lib.util.IStableListener;

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.30.10.3 $ $ $Date: 2004/03/18 11:52:19 $
* @author       Kay Ramme
* @see         com.sun.star.lib.uno.environments.remote.IProtocol
* @since       UDK1.0
*/
public class java_remote_bridge
    implements IBridge, IReceiver, RequestHandler, XBridge, Disposable,
        XComponent, IStableObject
{
  /**
   * When set to true, enables various debugging output.
   */
  static private final boolean DEBUG = false;

  /**
   * E.g. to get privleges for security managers, it is
   * possible to set a hook for the <code>MessageDispatcher</code> thread.
   */
  static public IInvokeHook __MessageDispatcher_run_hook;


  public class MessageDispatcher extends Thread implements IInvokable {
    boolean _quit = false;
   
    private ThreadId _threadId;

    MessageDispatcher() {
      super("MessageDispatcher");
    }

    public void run() {
      _threadId = ThreadPoolFactory.getThreadId();

      if(__MessageDispatcher_run_hook != null) {
        try {
          __MessageDispatcher_run_hook.invoke(this, null);
        }
        catch(Exception exception) { // should not fly
          System.err.println(getClass().getName() + " - unexpected: method >invoke< threw an exception - " + exception);
          exception.printStackTrace();
        }
      }
      else
        invoke(null);
    }

    public Object invoke(Object params[]) {
      Throwable throwable = null;

      try {
        do {
          // Use the protocol to read a job.
          IMessage iMessage = _iProtocol.readMessage(_inputStream);
         
         
          if(iMessage.getThreadId().equals(_threadId)) {
            continue;
          }
         
          // Take care of special methods release and acquire
                    String operation = iMessage.getOperation();
                    String oid = iMessage.getOid();
          if(operation != null && operation.equals("release")) {
                        Type interfaceType = new Type(iMessage.getInterface());
            _java_environment.revokeInterface(oid, interfaceType );
            remRefHolder(interfaceType, oid);
           
            if(iMessage.mustReply())
              sendReply(false, iMessage.getThreadId(), null);
          }
          else if(operation != null && operation.equals("acquire")) {
                        Type interfaceType = new Type(iMessage.getInterface());
            String oid_o[] = new String[]{oid};
            _java_environment.registerInterface(null, oid_o, interfaceType );
           
            addRefHolder(null, interfaceType, oid);
          }
          else {
            Object object = null;
           
            if(operation != null) { // is it a request
                            Type interfaceType = new Type(iMessage.getInterface());
              object = _java_environment.getRegisteredInterface(oid, interfaceType);
             
              Object xexception = null;
             
              if(object == null) { // this is an unknown oid, so we may have to ask the XInstanceProvider
                if(_xInstanceProvider == null) // we have neither an object nor an instance provider -> exception
                  xexception = new com.sun.star.uno.RuntimeException(getClass().getName() + ".dispatch - no instance provider set and unknown object:" + oid);
               
                else {
                  try {
                    object = _xInstanceProvider.getInstance(oid);
                   
                    if(object == null && !operation.equals("queryInterface"))
                      xexception = new com.sun.star.uno.RuntimeException(
                        getClass().getName()
                        + ".dispatch: instance provider returned null and operation >"
                        + operation
                        + "< not supported on null");
                  }
                  catch(com.sun.star.container.NoSuchElementException noSuchElementException) {
                    xexception = new com.sun.star.uno.RuntimeException(getClass().getName() + ".dispatch - wrapped exception:" + noSuchElementException);
                  }
                  catch(com.sun.star.uno.RuntimeException runtimeException) {
                    xexception = runtimeException;
                  }
                }
              }
             
              if(xexception != null) {
                // an exception occurred while trying to get an instance.
                // propagate it.
                sendReply(true, iMessage.getThreadId(), xexception);
                iMessage = null;
              }
            }           
           
            if(iMessage != null) {
                // Queue the job for later execution.
                // Give this bridge as the disposeId, needed in case of disposing this bridge
              Job job = new Job(object, java_remote_bridge.this, iMessage);
             
              _iThreadPool.putJob(job);
              job = null;
            }
          }
         
          iMessage = null;
          // this is important to get rid of the job (especially while testing lifecycles)
        }
        while(!_quit);
      }
      catch(EOFException eofException) {
        if(!_quit && DEBUG) {
          System.err.println(getClass() + " - reading message - exception occurred: \"" + eofException + "\"");
          System.err.println(getClass() + " - giving up");
        }

        throwable = new DisposedException( eofException.getMessage() );
      }
      catch(Exception exception) {
        if(DEBUG) {
          System.err.println(getClass() + " - reading message - exception occurred: \"" + exception + "\"");
          exception.printStackTrace();
          System.err.println(getClass() + " - giving up");
        }
          if(DEBUG)
          exception.printStackTrace();

        throwable = new DisposedException( exception.getMessage() );
      }

      // dispose this bridge only within an error
            if (!_quit) {
                java_remote_bridge.this.dispose(throwable);
            }

      return null;
    }
  }


  protected XConnection       _xConnection;
  protected InputStream       _inputStream;       // wraps the connection to be an InputStream
  protected DataOutputStream      _outputStream;      // wraps the connection to be an OutputStream

  protected XInstanceProvider _xInstanceProvider;

  protected String            _name = "remote";
  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

  protected Hashtable         _refHolders;        // holds descriptions for out mapped objects, so we can release
                                                  // the outmapped objects when the bridge is to be disposed

  protected Vector            _listeners;
  protected Vector            _stableListeners;

  protected boolean           _negotiate;
  protected boolean           _forceSynchronous;

  protected IThreadPool       _iThreadPool;

    // Variable state must only be used while synchronized on this object:
    private int state = STATE_ALIVE;
    private static final int STATE_ALIVE = 0;
    private static final int STATE_DISPOSING = 1;
    private static final int STATE_DISPOSED = 2;

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

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


  // use a static class, it is smaller
  private static class RefHolder {
    Type  _type;
    String _oid;
    int    _mapCount;
        Object _hardRef;
            // keep a hard reference to the object, the java_environment will
            // only hold it weakly
  }

    private boolean hasRefHolder(String oid, Type type) {
        return _refHolders.containsKey(oid + type);
    }

  final void addRefHolder(Object obj, Type type, String oid) {
    acquire();

    synchronized(_refHolders) {
      RefHolder refHolder = (RefHolder)_refHolders.get(oid + type);

      if(refHolder == null) {
        refHolder = new RefHolder();
        refHolder._type = type;
        refHolder._oid = oid;
                refHolder._hardRef = obj;
       
        _refHolders.put(oid + type, refHolder);
      }
            // assert refHolder._hardRef == obj;
     
      ++ refHolder._mapCount;
    }
  }

  final void remRefHolder(Type type, String oid) {
    synchronized(_refHolders) {
      RefHolder refHolder = (RefHolder)_refHolders.get(oid + type);
     
      if(refHolder != null) {
        -- refHolder._mapCount;
        if(refHolder._mapCount <= 0)
          _refHolders.remove(oid + type);

        release();
      }
      else
        System.err.println(getClass().getName() + ".remRefHolder - warning - unknown oid:" + oid + " " + type);
    }
  }


  final void freeHolders() {
    if(DEBUG) System.err.println("#### " + getClass().getName() + ".freeHolders:" + _refHolders.size());

    synchronized(_refHolders) {
    Enumeration elements = _refHolders.elements();
    while(elements.hasMoreElements()) {
      RefHolder refHolder = (RefHolder)elements.nextElement();

      while(refHolder._mapCount > 0) {
        -- refHolder._mapCount;
       
        _java_environment.revokeInterface(refHolder._oid, refHolder._type);
        release();
      }
    }
    }
  }


  private String parseAttributes(String attributeList) {
    attributeList = attributeList.trim().toLowerCase();


    String protocol = null;

    int index = attributeList.indexOf(',');
    if(index >= 0) { // there are parameters
      protocol = attributeList.substring(0, index);
      attributeList = attributeList.substring(index + 1).trim();
    }
    else {
      protocol = attributeList;
      attributeList = "";
    }
    protocol = protocol.trim();

    boolean negotiateTouched = false;

    while(attributeList.length() > 0) {
      index = attributeList.indexOf(',');

      String word = null;

      if(index >= 0) {
        word = attributeList.substring(0, index).trim();
        attributeList = attributeList.substring(index + 1).trim();
      }
      else {
        word = attributeList.trim();
        attributeList = "";
      }

      String left = null;
      String right = null;

      index = word.indexOf('=');
      if(index >= 0) {
        left = word.substring(0, index).trim();
        right = word.substring(index + 1).trim();
      }
      else
        left = word;
       
      if(left.equals("negotiate")) {
        if(right != null)
          _negotiate = (Integer.parseInt(right) == 1);
        else
          _negotiate = true;

        negotiateTouched = true;
      }
      else if(left.equals("forcesynchronous")) {
        if(right != null)
          _forceSynchronous = (Integer.parseInt(right) == 1);
        else
          _forceSynchronous = true;

        if(_forceSynchronous && !negotiateTouched)
          _negotiate = true;
      }
      else
        System.err.println(getClass().getName() + ".<init> - unknown attribute:" + left);
    }

    if(_negotiate)
      throw new com.sun.star.uno.RuntimeException("java_remote_bridge: negotiation not available yet, use negotiate=0 to disable");

    return protocol;
  }

  /**
   * Constructs a new bridge.
   * <p>
   * This method is not part of the provided <code>api</code>
   * and should only be used by the UNO runtime.
   * <p>
   * @param  java_remote        the source environment
   * @param  remote_environment the remote environement, which is not neede by this bridge
   * @param  args               the custom parameters: arg[0] == protocol_name, arg[1] == xConnection, arg[2] == xInstanceProvider
   */
  public java_remote_bridge(IEnvironment java_environment, IEnvironment remote_environment, Object args[]) throws Exception {
    if(DEBUG) System.err.println("#### " + getClass().getName() + " - instantiated:" + args);

    String protocol = parseAttributes((String)args[0]);

    _java_environment   = java_environment;

    Class protocol_class = Class.forName("com.sun.star.lib.uno.protocols." + protocol + "." + protocol);
    Constructor protocol_constructor = protocol_class.getConstructor(new Class[] {IBridge.class});

      _iProtocol          = (IProtocol)protocol_constructor.newInstance(new Object[]{this});
    _xConnection        = (XConnection)args[1];
    _xInstanceProvider  = (XInstanceProvider)args[2];
    _inputStream        = new XConnectionInputStream_Adapter(_xConnection);
    _outputStream       = new DataOutputStream( new XConnectionOutputStream_Adapter(_xConnection) );

    if(args.length > 3)
      _name = (String)args[3];

    // be sure that all neccessary members are set
    if(_java_environment == null
        || _xConnection      == null
        || _iProtocol        == null
        || _inputStream      == null
        || _outputStream     == null)
      throw new com.sun.star.lang.IllegalArgumentException(getClass().getName());

    _refHolders       = new Hashtable();
    _listeners        = new Vector();
    _stableListeners  = new Vector();

        proxyFactory = new ProxyFactory(this, this);

    // create the message dispatcher and start it
      _messageDispatcher  = new MessageDispatcher();
    _messageDispatcher.start();

    _iThreadPool = ThreadPoolFactory.createThreadPool();
  }


  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
      }
    }
  }

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

    Enumeration elements = _stableListeners.elements();
    while(elements.hasMoreElements()) {
      IStableListener iStableListener = (IStableListener)elements.nextElement();

      iStableListener.deStable();
    }
  }

  /**
   * 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);
  }

  /**
   * Maps an object from the source environment to the destination environment.
   * <p>
   * @return     the object in the destination environment
   * @param      object     the object to map
   * @param      type       the interface under which is to be mapped
   * @see                   com.sun.star.uno.IBridge#mapInterfaceTo
   */
  public Object mapInterfaceTo(Object object, Type type) {
        checkDisposed();

    String oid[] = new String[1];

    // if object is a string, than it is already mapped as a virtuell proxy
    if(object instanceof String)
      oid[0] = (String)object;
    else {
            object = _java_environment.registerInterface(object, oid, type);
            // Taking the type into account is necessary (a) since the proxy
            // might be for an unrelated type, and (b) [TODO:] to be consistent
            // with the bug described in mapInterfaceFrom (base type vs. derived
            // type):
            if (!proxyFactory.isProxy(object, type)) {
                addRefHolder(object, type, oid[0]);
            }
    }
      if(DEBUG) System.err.println("##### " + getClass() + " - mapInterfaceTo:" + object + " interface:" + 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();
        // TODO  The following code is not correct.  Assume that X2 is an
        // interface type derived from X1, the local object o has been sent out
        // with mapInterfaceTo(o,X2), and is now received back as
        // mapInterfaceFrom(o,X1).  It should be detected that, since X1 is a
        // base type of X2, (o,X1) is the local object o registered as (o,X2),
        // and neither should a proxy be created, nor should a "release" be sent
        // back:
        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)) {
            try {
                sendRequest(oid, type, "release", null,
                            new Boolean[] { new Boolean(_forceSynchronous) },
                            new Boolean[] { new Boolean(_forceSynchronous) });
            } catch (Error e) {
                throw e;
            } catch (RuntimeException e) {
                throw e;
            } catch (Throwable e) {
                throw new com.sun.star.uno.RuntimeException(
                    getClass().getName() + ".mapInterfaceFrom - unexpected: "
                    + e);
            }
        }
    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 synchronized void release() {
    -- _life_count;

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

    if(_life_count <= 0)
      dispose(new com.sun.star.uno.RuntimeException("end of life"));
  }

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

  private synchronized void dispose(Throwable throwable) {
    if(DEBUG) System.err.println("##### " + getClass().getName() + ".dispose - life count:" + _life_count);

        if (state == STATE_ALIVE) {
      state = STATE_DISPOSING;

      notifyListeners();
      notifyStableListeners();

      try {
        // stop the dispatcher thread
        _messageDispatcher._quit = true;

        // close the connection
        _xConnection.close();
       
        // interrupt the dispatcher thread, if this thread is not the dispatcher
        if(Thread.currentThread() != _messageDispatcher &&  _messageDispatcher.isAlive()) {

          // THIS IS A ***WORKAROUND*** FOR LINUX SUN JDK1.3 PROBLEM:
          // THE MESSAGEDISPATCHER STAYS IN THE SOCKET READ METHOD,
          // EVEN IF THE SOCKET HAS BEEN CLOSED.
          // SUSPENDING AND RESUMING THE MESSAGEDISPATCHER LETS IT
          // NOTICE THE CLOSED SOCKET

          // NOTE!NOTE!NOTE! ONLY USE THIS WORKAROUND FOR LINUX JDK1.3.0
          // NOTE!NOTE!NOTE! FROM SUN OR BLACKDOWN
                    // NOTE!NOTE!NOTE! THIS WORKAROUND IS DANGEROUSE AND MAY HARDLOCK
                    // NOTE!NOTE!NOTE! THE VM
          if(System.getProperty("os.name", "notlinux").toLowerCase().equals("linux")
          && System.getProperty("java.version", "not1.3").startsWith("1.3.0")
          && (System.getProperty("java.vendor", "notsun").toLowerCase().indexOf("sun") != -1
                     || System.getProperty("java.vendor", "notblackdown").toLowerCase().indexOf("blackdown") != -1))
          {
            if(DEBUG) System.err.println("##### " + getClass().getName() + ".dispose - using linux workaround for SUN or BLACKDOWN jdk1.3.0");
            _messageDispatcher.suspend();
            _messageDispatcher.resume();
          }
            else
            if(DEBUG) System.err.println("##### " + getClass().getName() + ".dispose - not using linux workaround");

          _messageDispatcher.join(1000); // wait for thread to die

          if(_messageDispatcher.isAlive()) { // has not died yet, interrupt it
            _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();
                Object env = WeakTable.__getObject(_java_environment);
                if (env instanceof java_environment) {
                    ((java_environment) env).revokeAllProxies();
                }
       
        // see if life count is zero, if not give a warning
        if(_life_count != 0 && DEBUG)
          System.err.println(getClass().getName() + ".dispose - life count (proxies left):" + _life_count);


        if(DEBUG)
          _java_environment.list();

       
        // clear members
        _xConnection        = null;
        _java_environment   = null;
        _messageDispatcher  = null;

                // TODO!  Is it intended that state is left as STATE_DISPOSING
                // when an exception is thrown?
        state = STATE_DISPOSED;
      }
      catch(InterruptedException interruptedException) {
        System.err.println(getClass().getName() + ".dispose - InterruptedException:" + interruptedException);
      }
      catch(com.sun.star.io.IOException ioException) {
        System.err.println(getClass().getName() + ".dispose - IOException:" + ioException);
      }
    }
  }

  /**
   * Asks to map a remote object of name sInstanceName.
   * <p>
   * @param   sInstanceName   the name of the instance
   * @see     com.sun.star.bridge.XBridge#getInstance
   */
    public Object getInstance(String sInstanceName) {
    Object object = null;


    Type xInterface_type = null;
    try {
      xInterface_type = new Type(XInterface.class);
    }
    catch(Exception exception) {
        throw new com.sun.star.uno.RuntimeException(exception.getMessage());
      }


    try {
      object = sendRequest(sInstanceName,
               xInterface_type,
               "queryInterface",
               new Object[]{xInterface_type},
               null,
               null);
    }
    catch(RuntimeException runtimeException) {
      throw runtimeException;
    }
    catch(Throwable throwable) {
      throw new com.sun.star.uno.RuntimeException(getClass().getName() + ".getInstance - unexpected:" + throwable);
    }

    return object;
  }

  /**
   * 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 _iProtocol.getName() + "," + _xConnection.getDescription();
  }

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

        // FIXME  checkDisposed called outside of synchronized block
        checkDisposed();

        try {
            synchronized (_outputStream) {
                _iProtocol.writeReply(exception, threadId, result);
                _iProtocol.flush(_outputStream);
                _outputStream.flush();
            }
        } catch (Exception e) {
            dispose(e);
            throw new DisposedException(getClass().getName()
                                        + ".sendReply - unexpected: " + e);
        } catch (Error e) {
            dispose(e);
            throw e;
        }
    }

    public Object sendRequest(String oid, Type type, String operation,
                              Object[] args)
        throws Throwable
    {
        return sendRequest(
            oid, type, operation, args,
            _forceSynchronous ? new Boolean[] { Boolean.TRUE } : null,
            _forceSynchronous ? new Boolean[] { Boolean.TRUE } : null);
    }

  private Object sendRequest(Object object, Type type, String operation, Object params[], Boolean synchron[], Boolean mustReply[]) throws Throwable {
    if(DEBUG) System.err.println("##### " + getClass().getName() + ".sendRequest:" + object + " " + type +" " + operation + " " + synchron + " " + mustReply);
    Object result = null;

    if(synchron == null)
      synchron = new Boolean[1];

    if(mustReply == null)
      mustReply = new Boolean[1];

        checkDisposed();

    if(operation.equals("acquire")) acquire()// keep this bridge alife

    boolean goThroughThreadPool = false;

        ThreadId threadId = ThreadPoolFactory.getThreadId();
        Object handle = null;
    try {
      synchronized(_outputStream) {
        _iProtocol.writeRequest((String)object, TypeDescription.getTypeDescription(type), operation, threadId , params, synchron, mustReply);

        goThroughThreadPool = synchron[0].booleanValue()  && Thread.currentThread() != _messageDispatcher;

        if(goThroughThreadPool) // prepare a queue for this thread in the threadpool
          handle = _iThreadPool.attach( threadId );

        try {
          _iProtocol.flush(_outputStream);
          _outputStream.flush();
        }
        catch(IOException iOException) {
                    DisposedException disposedException =
                        new DisposedException( iOException.getMessage() );
          dispose(disposedException);
                    throw disposedException;
        }
      }

      if(goThroughThreadPool)
        result = _iThreadPool.enter( handle, threadId);

    }
    finally {
      if(goThroughThreadPool)
        _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;
  }


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

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


  public void addStableListener(IStableListener stableListener) {
    _stableListeners.addElement(stableListener);
  }

  public void removeStableListener(IStableListener stableListener) {
    _stableListeners.removeElement(stableListener);
  }

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

    private final ProxyFactory proxyFactory;
}
TOP

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

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.