1 /*
   2  * Copyright (c) 1999, 2004, Oracle and/or its affiliates. All rights reserved.
   3  * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
   4  *
   5  * This code is free software; you can redistribute it and/or modify it
   6  * under the terms of the GNU General Public License version 2 only, as
   7  * published by the Free Software Foundation.  Oracle designates this
   8  * particular file as subject to the "Classpath" exception as provided
   9  * by Oracle in the LICENSE file that accompanied this code.
  10  *
  11  * This code is distributed in the hope that it will be useful, but WITHOUT
  12  * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
  13  * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
  14  * version 2 for more details (a copy is included in the LICENSE file that
  15  * accompanied this code).
  16  *
  17  * You should have received a copy of the GNU General Public License version
  18  * 2 along with this work; if not, write to the Free Software Foundation,
  19  * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
  20  *
  21  * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
  22  * or visit www.oracle.com if you need additional information or have any
  23  * questions.
  24  */
  25 /*
  26  * Licensed Materials - Property of IBM
  27  * RMI-IIOP v1.0
  28  * Copyright IBM Corp. 1998 1999  All Rights Reserved
  29  *
  30  */
  31 
  32 package com.sun.corba.se.impl.javax.rmi;
  33 
  34 import java.lang.reflect.Method ;
  35 
  36 import javax.rmi.CORBA.Tie;
  37 import javax.rmi.CORBA.Util;
  38 
  39 import java.rmi.RemoteException;
  40 import java.rmi.NoSuchObjectException;
  41 import java.rmi.Remote;
  42 
  43 import java.util.Properties;
  44 
  45 import org.omg.CORBA.ORB;
  46 import org.omg.CORBA.portable.Delegate;
  47 import org.omg.CORBA.SystemException;
  48 
  49 import java.rmi.server.UnicastRemoteObject;
  50 import java.rmi.server.RemoteStub;
  51 import java.rmi.server.ExportException;
  52 
  53 import java.net.URL;
  54 
  55 import com.sun.corba.se.impl.util.JDKBridge;
  56 import com.sun.corba.se.impl.util.Utility;
  57 import com.sun.corba.se.impl.util.RepositoryId;
  58 
  59 import com.sun.corba.se.spi.presentation.rmi.StubAdapter;
  60 
  61 import java.security.AccessController;
  62 import com.sun.corba.se.impl.orbutil.GetPropertyAction;
  63 
  64 /**
  65  * Server implementation objects may either inherit from
  66  * javax.rmi.PortableRemoteObject or they may implement a remote interface
  67  * and then use the exportObject method to register themselves as a server object.
  68  * The toStub method takes a server implementation and returns a stub that
  69  * can be used to access that server object.
  70  * The connect method makes a Remote object ready for remote communication.
  71  * The unexportObject method is used to deregister a server object, allowing it to become
  72  * available for garbage collection.
  73  * The narrow method takes an object reference or abstract interface type and
  74  * attempts to narrow it to conform to
  75  * the given interface. If the operation is successful the result will be an
  76  * object of the specified type, otherwise an exception will be thrown.
  77  */
  78 public class PortableRemoteObject
  79         implements javax.rmi.CORBA.PortableRemoteObjectDelegate {
  80 
  81     /**
  82      * Makes a server object ready to receive remote calls. Note
  83      * that subclasses of PortableRemoteObject do not need to call this
  84      * method, as it is called by the constructor.
  85      * @param obj the server object to export.
  86      * @exception RemoteException if export fails.
  87      */
  88     public void exportObject(Remote obj)
  89         throws RemoteException {
  90 
  91         if (obj == null) {
  92             throw new NullPointerException("invalid argument");
  93         }
  94 
  95         // Has this object already been exported to IIOP?
  96 
  97         if (Util.getTie(obj) != null) {
  98 
  99             // Yes, so this is an error...
 100 
 101             throw new ExportException (obj.getClass().getName() + " already exported");
 102         }
 103 
 104         // Can we load a Tie?
 105 
 106         Tie theTie = Utility.loadTie(obj);
 107 
 108         if (theTie != null) {
 109 
 110             // Yes, so export it to IIOP...
 111 
 112             Util.registerTarget(theTie,obj);
 113 
 114         } else {
 115 
 116             // No, so export to JRMP. If this is called twice for the
 117             // same object, it will throw an ExportException...
 118 
 119             UnicastRemoteObject.exportObject(obj);
 120         }
 121     }
 122 
 123     /**
 124      * Returns a stub for the given server object.
 125      * @param obj the server object for which a stub is required. Must either be a subclass
 126      * of PortableRemoteObject or have been previously the target of a call to
 127      * {@link #exportObject}.
 128      * @return the most derived stub for the object.
 129      * @exception NoSuchObjectException if a stub cannot be located for the given server object.
 130      */
 131     public Remote toStub (Remote obj)
 132         throws NoSuchObjectException
 133     {
 134         Remote result = null;
 135         if (obj == null) {
 136             throw new NullPointerException("invalid argument");
 137         }
 138 
 139         // If the class is already an IIOP stub then return it.
 140         if (StubAdapter.isStub( obj )) {
 141             return obj;
 142         }
 143 
 144         // If the class is already a JRMP stub then return it.
 145         if (obj instanceof java.rmi.server.RemoteStub) {
 146             return obj;
 147         }
 148 
 149         // Has it been exported to IIOP?
 150         Tie theTie = Util.getTie(obj);
 151 
 152         if (theTie != null) {
 153             result = Utility.loadStub(theTie,null,null,true);
 154         } else {
 155             if (Utility.loadTie(obj) == null) {
 156                 result = java.rmi.server.RemoteObject.toStub(obj);
 157             }
 158         }
 159 
 160         if (result == null) {
 161             throw new NoSuchObjectException("object not exported");
 162         }
 163 
 164         return result;
 165     }
 166 
 167     /**
 168      * Deregisters a server object from the runtime, allowing the object to become
 169      * available for garbage collection.
 170      * @param obj the object to unexport.
 171      * @exception NoSuchObjectException if the remote object is not
 172      * currently exported.
 173      */
 174     public void unexportObject(Remote obj)
 175         throws NoSuchObjectException {
 176 
 177         if (obj == null) {
 178             throw new NullPointerException("invalid argument");
 179         }
 180 
 181         if (StubAdapter.isStub(obj) ||
 182             obj instanceof java.rmi.server.RemoteStub) {
 183             throw new NoSuchObjectException(
 184                 "Can only unexport a server object.");
 185         }
 186 
 187         Tie theTie = Util.getTie(obj);
 188         if (theTie != null) {
 189             Util.unexportObject(obj);
 190         } else {
 191             if (Utility.loadTie(obj) == null) {
 192                 UnicastRemoteObject.unexportObject(obj,true);
 193             } else {
 194                 throw new NoSuchObjectException("Object not exported.");
 195             }
 196         }
 197     }
 198 
 199     /**
 200      * Checks to ensure that an object of a remote or abstract interface type
 201      * can be cast to a desired type.
 202      * @param narrowFrom the object to check.
 203      * @param narrowTo the desired type.
 204      * @return an object which can be cast to the desired type.
 205      * @throws ClassCastException if narrowFrom cannot be cast to narrowTo.
 206      */
 207     public java.lang.Object narrow ( java.lang.Object narrowFrom,
 208         java.lang.Class narrowTo) throws ClassCastException
 209     {
 210         java.lang.Object result = null;
 211 
 212         if (narrowFrom == null)
 213             return null;
 214 
 215         if (narrowTo == null)
 216             throw new NullPointerException("invalid argument");
 217 
 218         try {
 219             if (narrowTo.isAssignableFrom(narrowFrom.getClass()))
 220                 return narrowFrom;
 221 
 222             // Is narrowTo an interface that might be
 223             // implemented by a servant running on iiop?
 224             if (narrowTo.isInterface() &&
 225                 narrowTo != java.io.Serializable.class &&
 226                 narrowTo != java.io.Externalizable.class) {
 227 
 228                 org.omg.CORBA.Object narrowObj
 229                     = (org.omg.CORBA.Object) narrowFrom;
 230 
 231                 // Create an id from the narrowTo type...
 232                 String id = RepositoryId.createForAnyType(narrowTo);
 233 
 234                 if (narrowObj._is_a(id)) {
 235                     return Utility.loadStub(narrowObj,narrowTo);
 236                 } else {
 237                     throw new ClassCastException( "Object is not of remote type " +
 238                         narrowTo.getName() ) ;
 239                 }
 240             } else {
 241                 throw new ClassCastException( "Class " + narrowTo.getName() +
 242                     " is not a valid remote interface" ) ;
 243             }
 244         } catch(Exception error) {
 245             ClassCastException cce = new ClassCastException() ;
 246             cce.initCause( error ) ;
 247             throw cce ;
 248         }
 249     }
 250 
 251     /**
 252      * Makes a Remote object ready for remote communication. This normally
 253      * happens implicitly when the object is sent or received as an argument
 254      * on a remote method call, but in some circumstances it is useful to
 255      * perform this action by making an explicit call.  See the
 256      * {@link Stub#connect} method for more information.
 257      * @param target the object to connect.
 258      * @param source a previously connected object.
 259      * @throws RemoteException if <code>source</code> is not connected
 260      * or if <code>target</code> is already connected to a different ORB than
 261      * <code>source</code>.
 262      */
 263     public void connect (Remote target, Remote source)
 264         throws RemoteException
 265     {
 266         if (target == null || source == null) {
 267             throw new NullPointerException("invalid argument");
 268         }
 269 
 270         ORB orb = null;
 271         try {
 272             if (StubAdapter.isStub( source )) {
 273                 orb = StubAdapter.getORB( source ) ;
 274             } else {
 275                 // Is this a servant that was exported to iiop?
 276                 Tie tie = Util.getTie(source);
 277                 if (tie == null) {
 278                     /* loadTie always succeeds for dynamic RMI-IIOP
 279                     // No, can we get a tie for it?  If not,
 280                     // assume that source is a JRMP object...
 281                     if (Utility.loadTie(source) != null) {
 282                         // Yes, so it is an iiop object which
 283                         // has not been exported...
 284                         throw new RemoteException(
 285                             "'source' object not exported");
 286                     }
 287                     */
 288                 } else {
 289                     orb = tie.orb();
 290                 }
 291             }
 292         } catch (SystemException e) {
 293             throw new RemoteException("'source' object not connected", e );
 294         }
 295 
 296         boolean targetIsIIOP = false ;
 297         Tie targetTie = null;
 298         if (StubAdapter.isStub(target)) {
 299             targetIsIIOP = true;
 300         } else {
 301             targetTie = Util.getTie(target);
 302             if (targetTie != null) {
 303                 targetIsIIOP = true;
 304             } else {
 305                 /* loadTie always succeeds for dynamic RMI-IIOP
 306                 if (Utility.loadTie(target) != null) {
 307                     throw new RemoteException("'target' servant not exported");
 308                 }
 309                 */
 310             }
 311         }
 312 
 313         if (!targetIsIIOP) {
 314             // Yes. Do we have an ORB from the source object?
 315             // If not, we're done - there is nothing to do to
 316             // connect a JRMP object. If so, it is an error because
 317             // the caller mixed JRMP and IIOP...
 318             if (orb != null) {
 319                 throw new RemoteException(
 320                     "'source' object exported to IIOP, 'target' is JRMP");
 321             }
 322         } else {
 323             // The target object is IIOP. Make sure we have a
 324             // valid ORB from the source object...
 325             if (orb == null) {
 326                 throw new RemoteException(
 327                     "'source' object is JRMP, 'target' is IIOP");
 328             }
 329 
 330             // And, finally, connect it up...
 331             try {
 332                 if (targetTie != null) {
 333                     // Is the tie already connected?
 334                     try {
 335                         ORB existingOrb = targetTie.orb();
 336 
 337                         // Yes. Is it the same orb?
 338                         if (existingOrb == orb) {
 339 
 340                             // Yes, so nothing to do...
 341                             return;
 342                         } else {
 343                             // No, so this is an error...
 344                             throw new RemoteException(
 345                                 "'target' object was already connected");
 346                         }
 347                     } catch (SystemException e) {}
 348 
 349                     // No, so do it...
 350                     targetTie.orb(orb);
 351                 } else {
 352                     StubAdapter.connect( target, orb ) ;
 353                 }
 354             } catch (SystemException e) {
 355 
 356                 // The stub or tie was already connected...
 357                 throw new RemoteException(
 358                     "'target' object was already connected", e );
 359             }
 360         }
 361     }
 362 }