mirror of git://gcc.gnu.org/git/gcc.git
				
				
				
			
		
			
				
	
	
		
			482 lines
		
	
	
		
			15 KiB
		
	
	
	
		
			Java
		
	
	
	
			
		
		
	
	
			482 lines
		
	
	
		
			15 KiB
		
	
	
	
		
			Java
		
	
	
	
| /* UnicastServerRef.java --
 | |
|    Copyright (c) 1996, 1997, 1998, 1999, 2002, 2003, 2004, 2006
 | |
|    Free Software Foundation, Inc.
 | |
| 
 | |
| This file is part of GNU Classpath.
 | |
| 
 | |
| GNU Classpath is free software; you can redistribute it and/or modify
 | |
| it under the terms of the GNU General Public License as published by
 | |
| the Free Software Foundation; either version 2, or (at your option)
 | |
| any later version.
 | |
| 
 | |
| GNU Classpath 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
 | |
| General Public License for more details.
 | |
| 
 | |
| You should have received a copy of the GNU General Public License
 | |
| along with GNU Classpath; see the file COPYING.  If not, write to the
 | |
| Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
 | |
| 02110-1301 USA.
 | |
| 
 | |
| Linking this library statically or dynamically with other modules is
 | |
| making a combined work based on this library.  Thus, the terms and
 | |
| conditions of the GNU General Public License cover the whole
 | |
| combination.
 | |
| 
 | |
| As a special exception, the copyright holders of this library give you
 | |
| permission to link this library with independent modules to produce an
 | |
| executable, regardless of the license terms of these independent
 | |
| modules, and to copy and distribute the resulting executable under
 | |
| terms of your choice, provided that you also meet, for each linked
 | |
| independent module, the terms and conditions of the license of that
 | |
| module.  An independent module is a module which is not derived from
 | |
| or based on this library.  If you modify this library, you may extend
 | |
| this exception to your version of the library, but you are not
 | |
| obligated to do so.  If you do not wish to do so, delete this
 | |
| exception statement from your version. */
 | |
| 
 | |
| 
 | |
| package gnu.java.rmi.server;
 | |
| 
 | |
| import java.io.ObjectInputStream;
 | |
| import java.lang.reflect.Constructor;
 | |
| import java.lang.reflect.InvocationTargetException;
 | |
| import java.lang.reflect.Method;
 | |
| import java.lang.reflect.Proxy;
 | |
| import java.rmi.Remote;
 | |
| import java.rmi.RemoteException;
 | |
| import java.rmi.server.ObjID;
 | |
| import java.rmi.server.RMIServerSocketFactory;
 | |
| import java.rmi.server.RemoteObjectInvocationHandler;
 | |
| import java.rmi.server.RemoteRef;
 | |
| import java.rmi.server.RemoteServer;
 | |
| import java.rmi.server.RemoteStub;
 | |
| import java.rmi.server.ServerNotActiveException;
 | |
| import java.rmi.server.Skeleton;
 | |
| import java.util.HashSet;
 | |
| import java.util.Hashtable;
 | |
| import java.util.Iterator;
 | |
| 
 | |
| /**
 | |
|  * This class connects the local, remotely available (exported) object to
 | |
|  * the local RMI server that accepts the remote calls.
 | |
|  */
 | |
| public class UnicastServerRef
 | |
|     extends UnicastRef
 | |
| {
 | |
| 
 | |
|   /**
 | |
|    * Use GNU Classpath v 0.20 SVUID for interoperability
 | |
|    */
 | |
|   private static final long serialVersionUID = - 5585608108300801246L;
 | |
| 
 | |
|   /**
 | |
|    * The class array, defining parameters of the jdk 1.2 RMI stub constructor.
 | |
|    */
 | |
|   private static final Class[] stubprototype = new Class[] { RemoteRef.class };
 | |
| 
 | |
|   /**
 | |
|    * The exported remote object itself.
 | |
|    */
 | |
|   Remote myself; // save the remote object itself
 | |
| 
 | |
|   /**
 | |
|    * The skeleton (if any), associated with the exported remote object.
 | |
|    */
 | |
|   protected Skeleton skel;
 | |
| 
 | |
|   /**
 | |
|    * The stub, associated with the exported remote object (may be proxy class).
 | |
|    */
 | |
|   protected Remote stub;
 | |
| 
 | |
|   /**
 | |
|    * The method table (RMI hash code to method) of the methods of the
 | |
|    * exported object.
 | |
|    */
 | |
|   protected Hashtable methods = new Hashtable();
 | |
| 
 | |
|   /**
 | |
|    * Used by serialization.
 | |
|    */
 | |
|   UnicastServerRef()
 | |
|   {
 | |
|   }
 | |
| 
 | |
|   public UnicastServerRef(ObjID id, int port, RMIServerSocketFactory ssf)
 | |
|       throws RemoteException
 | |
|   {
 | |
|     super(id);
 | |
|     manager = UnicastConnectionManager.getInstance(port, ssf);
 | |
|   }
 | |
| 
 | |
|   /**
 | |
|    * Export the object and return its remote stub. The method tries to locate
 | |
|    * existing stubs and skeletons. If this fails, the method instantiates the
 | |
|    * proxy stub class.
 | |
|    *
 | |
|    * Stubs and skeletons are always ignored (even if present) if the
 | |
|    * java.rmi.server.ignoreStubClasses property is set to true.
 | |
|    *
 | |
|    * @param obj the object being exported.
 | |
|    * @return the stub (existing class or proxy) of the exported object.
 | |
|    * @throws RemoteException if the export failed due any reason
 | |
|    */
 | |
|   public Remote exportObject(Remote obj) throws RemoteException
 | |
|   {
 | |
|     if (myself == null)
 | |
|       {
 | |
|         myself = obj;
 | |
|         // Save it to server manager, to let client calls in the same VM to
 | |
|         // issue local call
 | |
|         manager.serverobj = obj;
 | |
| 
 | |
|         String ignoreStubs;
 | |
| 
 | |
|         ClassLoader loader =obj.getClass().getClassLoader();
 | |
| 
 | |
|         // Stubs are always searched for the bootstrap classes that may have
 | |
|         // obsolete pattern and may still need also skeletons.
 | |
|         if (loader==null)
 | |
|           ignoreStubs = "false";
 | |
|         else
 | |
|           ignoreStubs = System.getProperty("java.rmi.server.ignoreStubClasses",
 | |
|                                            "false");
 | |
| 
 | |
|         if (! ignoreStubs.equals("true"))
 | |
|           {
 | |
|             // Find and install the stub
 | |
|             Class cls = obj.getClass();
 | |
| 
 | |
|             // where ist the _Stub? (check superclasses also)
 | |
|             Class expCls = findStubSkelClass(cls);
 | |
| 
 | |
|             if (expCls != null)
 | |
|               {
 | |
|                 stub = (RemoteStub) getHelperClass(expCls, "_Stub");
 | |
|                 // Find and install the skeleton (if there is one)
 | |
|                 skel = (Skeleton) getHelperClass(expCls, "_Skel");
 | |
|               }
 | |
|           }
 | |
| 
 | |
|         if (stub == null)
 | |
|           stub = createProxyStub(obj.getClass(), this);
 | |
| 
 | |
|         // Build hash of methods which may be called.
 | |
|         buildMethodHash(obj.getClass(), true);
 | |
| 
 | |
|         // Export it.
 | |
|         UnicastServer.exportObject(this);
 | |
|       }
 | |
| 
 | |
|     return stub;
 | |
|   }
 | |
| 
 | |
|   /**
 | |
|    * Get the stub (actual class or proxy) of the exported remote object.
 | |
|    *
 | |
|    * @return the remote stub (null if exportObject has not been called).
 | |
|    */
 | |
|   public Remote getStub()
 | |
|   {
 | |
|     return stub;
 | |
|   }
 | |
| 
 | |
|   /**
 | |
|    * Unexport the object (remove methods from the method hashcode table
 | |
|    * and call UnicastServer.unexportObject.
 | |
|    *
 | |
|    * @param obj the object being unexported
 | |
|    * @param force passed to the UnicastServer.unexportObject.
 | |
|    * @return value, returned by the UnicastServer.unexportObject.
 | |
|    */
 | |
|   public boolean unexportObject(Remote obj, boolean force)
 | |
|   {
 | |
|     // Remove all hashes of methods which may be called.
 | |
|     buildMethodHash(obj.getClass(), false);
 | |
|     return UnicastServer.unexportObject(this, force);
 | |
|   }
 | |
| 
 | |
|   /**
 | |
|    * Return the class in the hierarchy for that the stub class is defined.
 | |
|    * The Subs/Skels might not there for the actual class, but maybe for one of
 | |
|    * the superclasses.
 | |
|    *
 | |
|    * @return the class having stub defined, null if none.
 | |
|    */
 | |
|   protected Class findStubSkelClass(Class startCls)
 | |
|   {
 | |
|     Class cls = startCls;
 | |
| 
 | |
|     while (true)
 | |
|       {
 | |
|         try
 | |
|           {
 | |
|             String stubClassname = cls.getName() + "_Stub";
 | |
|             ClassLoader cl = cls.getClassLoader();
 | |
|             Class scls = cl == null ? Class.forName(stubClassname)
 | |
|                                    : cl.loadClass(stubClassname);
 | |
|             return cls; // found it
 | |
|           }
 | |
|         catch (ClassNotFoundException e)
 | |
|           {
 | |
|             Class superCls = cls.getSuperclass();
 | |
|             if (superCls == null
 | |
|                 || superCls == java.rmi.server.UnicastRemoteObject.class)
 | |
|               {
 | |
|                 return null;
 | |
|               }
 | |
|             cls = superCls;
 | |
|           }
 | |
|       }
 | |
|   }
 | |
| 
 | |
|   /**
 | |
|    * Get the helper (assisting) class with the given type.
 | |
|    *
 | |
|    * @param cls the class, for that the helper class is requested. This class
 | |
|    * and the requested helper class must share the same class loader.
 | |
|    *
 | |
|    * @param type the type of the assisting helper. The only currently supported
 | |
|    * non deprecated value is "_Stub" (load jdk 1.1 or 1.2 RMI stub). Another
 | |
|    * (deprecated) value is "_Skel" (load skeleton).
 | |
|    *
 | |
|    * @return the instantiated instance of the helper class or null if the
 | |
|    * helper class cannot be found or instantiated.
 | |
|    */
 | |
|   protected Object getHelperClass(Class cls, String type)
 | |
|   {
 | |
|     try
 | |
|       {
 | |
|         String classname = cls.getName();
 | |
|         ClassLoader cl = cls.getClassLoader();
 | |
|         Class scls = cl == null ? Class.forName(classname + type)
 | |
|                                : cl.loadClass(classname + type);
 | |
|         if (type.equals("_Stub"))
 | |
|           {
 | |
|             try
 | |
|               {
 | |
|                 // JDK 1.2 stubs
 | |
|                 Constructor con = scls.getConstructor(stubprototype);
 | |
|                 return (con.newInstance(new Object[] { this }));
 | |
|               }
 | |
|             catch (NoSuchMethodException e)
 | |
|               {
 | |
|               }
 | |
|             catch (InstantiationException e)
 | |
|               {
 | |
|               }
 | |
|             catch (IllegalAccessException e)
 | |
|               {
 | |
|               }
 | |
|             catch (IllegalArgumentException e)
 | |
|               {
 | |
|               }
 | |
|             catch (InvocationTargetException e)
 | |
|               {
 | |
|               }
 | |
|             // JDK 1.1 stubs
 | |
|             RemoteStub stub = (RemoteStub) scls.newInstance();
 | |
|             UnicastRemoteStub.setStubRef(stub, this);
 | |
|             return (stub);
 | |
|           }
 | |
|         else
 | |
|           {
 | |
|             // JDK 1.1 skel
 | |
|             return (scls.newInstance());
 | |
|           }
 | |
|       }
 | |
|     catch (ClassNotFoundException e)
 | |
|       {
 | |
|       }
 | |
|     catch (InstantiationException e)
 | |
|       {
 | |
|       }
 | |
|     catch (IllegalAccessException e)
 | |
|       {
 | |
|       }
 | |
|     return (null);
 | |
|   }
 | |
| 
 | |
|   public String getClientHost() throws ServerNotActiveException
 | |
|   {
 | |
|     return RemoteServer.getClientHost();
 | |
|   }
 | |
| 
 | |
|   /**
 | |
|    * Build the method has code table and put it into {@link #methods}
 | |
|    * (mapping RMI hashcode tos method). The same method is used to remove
 | |
|    * the table.
 | |
|    *
 | |
|    * @param cls the class for that the method table is built.
 | |
|    * @param build if true, the class methods are added to the table. If
 | |
|    * false, they are removed from the table.
 | |
|    */
 | |
|   protected void buildMethodHash(Class cls, boolean build)
 | |
|   {
 | |
|     Method[] meths = cls.getMethods();
 | |
|     for (int i = 0; i < meths.length; i++)
 | |
|       {
 | |
|         /* Don't need to include any java.xxx related stuff */
 | |
|         if (meths[i].getDeclaringClass().getName().startsWith("java."))
 | |
|           {
 | |
|             continue;
 | |
|           }
 | |
|         long hash = RMIHashes.getMethodHash(meths[i]);
 | |
|         if (build)
 | |
|           methods.put(new Long(hash), meths[i]);
 | |
|         else
 | |
|           methods.remove(new Long(hash));
 | |
|         // System.out.println("meth = " + meths[i] + ", hash = " + hash);
 | |
|       }
 | |
|   }
 | |
| 
 | |
|   Class getMethodReturnType(int method, long hash) throws Exception
 | |
|   {
 | |
|     if (method == - 1)
 | |
|       {
 | |
|         Method meth = (Method) methods.get(new Long(hash));
 | |
|         return meth.getReturnType();
 | |
|       }
 | |
|     else
 | |
|       return null;
 | |
|   }
 | |
| 
 | |
|   /**
 | |
|    * This method is called from the {@link UnicastServer#incomingMessageCall}
 | |
|    * to deliver the remote call to this object.
 | |
|    */
 | |
|   public Object incomingMessageCall(UnicastConnection conn, int method,
 | |
|                                     long hash) throws Exception
 | |
|   {
 | |
|     // System.out.println("method = " + method + ", hash = " + hash);
 | |
|     // If method is -1 then this is JDK 1.2 RMI - so use the hash
 | |
|     // to locate the method
 | |
|     if (method == - 1)
 | |
|       {
 | |
|         Method meth = (Method) methods.get(new Long(hash));
 | |
|         // System.out.println("class = " + myself.getClass() + ", meth = " +
 | |
|         // meth);
 | |
|         if (meth == null)
 | |
|           {
 | |
|             throw new NoSuchMethodException(
 | |
|               myself.getClass().getName()+" hash "+hash);
 | |
|           }
 | |
| 
 | |
|         ObjectInputStream in = conn.getObjectInputStream();
 | |
|         int nrargs = meth.getParameterTypes().length;
 | |
|         Object[] args = new Object[nrargs];
 | |
|         for (int i = 0; i < nrargs; i++)
 | |
|           {
 | |
|             /**
 | |
|              * For debugging purposes - we don't handle CodeBases quite right so
 | |
|              * we don't always find the stubs. This lets us know that.
 | |
|              */
 | |
|             try
 | |
|               {
 | |
|                 // need to handle primitive types
 | |
|                 args[i] = ((RMIObjectInputStream) in)
 | |
|                   .readValue(meth.getParameterTypes()[i]);
 | |
| 
 | |
|               }
 | |
|             catch (Exception t)
 | |
|               {
 | |
|                 t.printStackTrace();
 | |
|                 throw t;
 | |
|               }
 | |
|           }
 | |
|         //We must reinterpret the exception thrown by meth.invoke()
 | |
|         //return (meth.invoke(myself, args));
 | |
|         Object ret = null;
 | |
|         try
 | |
|           {
 | |
|             ret = meth.invoke(myself, args);
 | |
|           }
 | |
|         catch (InvocationTargetException e)
 | |
|           {
 | |
|             Throwable cause = e.getTargetException();
 | |
|             if (cause instanceof Exception)
 | |
|               {
 | |
|                 throw (Exception) cause;
 | |
|               }
 | |
|             else if (cause instanceof Error)
 | |
|               {
 | |
|                 throw (Error) cause;
 | |
|               }
 | |
|             else
 | |
|               {
 | |
|                 throw new Error(
 | |
|                   "The remote method threw a java.lang.Throwable that"+
 | |
|                   " is neither java.lang.Exception nor java.lang.Error.",
 | |
|                   e);
 | |
|               }
 | |
|           }
 | |
|         return ret;
 | |
|       }
 | |
|     // Otherwise this is JDK 1.1 style RMI - we find the skeleton
 | |
|     // and invoke it using the method number.  We wrap up our
 | |
|     // connection system in a UnicastRemoteCall so it appears in a
 | |
|     // way the Skeleton can handle.
 | |
|     else
 | |
|       {
 | |
|         if (skel == null)
 | |
|           throw new NoSuchMethodException("JDK 1.1 call - Skeleton required");
 | |
| 
 | |
|         UnicastRemoteCall call = new UnicastRemoteCall(conn);
 | |
|         skel.dispatch(myself, call, method, hash);
 | |
|         if (! call.isReturnValue())
 | |
|           return RMIVoidValue.INSTANCE;
 | |
|         else
 | |
|           return (call.returnValue());
 | |
|       }
 | |
|   }
 | |
| 
 | |
|   /**
 | |
|    * Create the 1.2 proxy stub in the case when the pre-generated stub is not
 | |
|    * available of the system is explicitly instructed to use proxy stubs.
 | |
|    *
 | |
|    * @param stubFor the class for that the proxy class must be constructed.
 | |
|    * @param reference the remote reference, used to find the given object
 | |
|    *
 | |
|    * @return the applicable proxy stub.
 | |
|    *
 | |
|    * @author Audrius Meskauskas (AudriusA@Bioinformatics.org)
 | |
|    */
 | |
|   Remote createProxyStub(Class stubFor, RemoteRef reference)
 | |
|   {
 | |
|     // Collect all interfaces, implemented by stubFor and derived from
 | |
|     // Remote (also Remote itself):
 | |
|     HashSet interfaces = new HashSet();
 | |
|     Class c = stubFor;
 | |
|     Class[] intfs;
 | |
| 
 | |
|     while (c != null)
 | |
|       {
 | |
|         intfs = c.getInterfaces();
 | |
|         for (int i = 0; i < intfs.length; i++)
 | |
|           {
 | |
|             if (Remote.class.isAssignableFrom(intfs[i]))
 | |
|               interfaces.add(intfs[i]);
 | |
|           }
 | |
|         c = c.getSuperclass();
 | |
|       }
 | |
| 
 | |
|     intfs = new Class[interfaces.size()];
 | |
|     Iterator it = interfaces.iterator();
 | |
| 
 | |
|     for (int i = 0; i < intfs.length; i++)
 | |
|       intfs[i] = (Class) it.next();
 | |
| 
 | |
|     RemoteObjectInvocationHandler handler =
 | |
|       new RemoteObjectInvocationHandler(reference);
 | |
| 
 | |
|     Object proxy =
 | |
|       Proxy.newProxyInstance(stubFor.getClassLoader(), intfs, handler);
 | |
| 
 | |
|     return (Remote) proxy;
 | |
|   }
 | |
| 
 | |
| 
 | |
| }
 |