1 /*
   2  * Copyright (c) 2001, 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 package com.sun.corba.se.impl.protocol;
  27 
  28 import java.util.Iterator;
  29 import java.util.HashMap;
  30 
  31 import javax.rmi.CORBA.Tie;
  32 
  33 import org.omg.CORBA.CompletionStatus;
  34 import org.omg.CORBA.Context;
  35 import org.omg.CORBA.ContextList;
  36 import org.omg.CORBA.ExceptionList;
  37 import org.omg.CORBA.NamedValue;
  38 import org.omg.CORBA.NVList;
  39 import org.omg.CORBA.Request;
  40 import org.omg.CORBA.TypeCode;
  41 
  42 import org.omg.CORBA.portable.ApplicationException;
  43 import org.omg.CORBA.portable.Delegate;
  44 import org.omg.CORBA.portable.InputStream;
  45 import org.omg.CORBA.portable.OutputStream;
  46 import org.omg.CORBA.portable.RemarshalException;
  47 import org.omg.CORBA.portable.ServantObject;
  48 
  49 import com.sun.corba.se.pept.broker.Broker;
  50 import com.sun.corba.se.pept.encoding.InputObject;
  51 import com.sun.corba.se.pept.encoding.OutputObject;
  52 import com.sun.corba.se.pept.protocol.ClientInvocationInfo;
  53 import com.sun.corba.se.pept.protocol.ClientRequestDispatcher;
  54 import com.sun.corba.se.pept.transport.ContactInfo;
  55 import com.sun.corba.se.pept.transport.ContactInfoList;
  56 import com.sun.corba.se.pept.transport.ContactInfoListIterator;
  57 
  58 import com.sun.corba.se.spi.presentation.rmi.StubAdapter;
  59 import com.sun.corba.se.spi.ior.IOR;
  60 import com.sun.corba.se.spi.logging.CORBALogDomains;
  61 import com.sun.corba.se.spi.orb.ORB;
  62 import com.sun.corba.se.spi.protocol.CorbaClientDelegate ;
  63 import com.sun.corba.se.spi.transport.CorbaContactInfo;
  64 import com.sun.corba.se.spi.transport.CorbaContactInfoList;
  65 import com.sun.corba.se.spi.transport.CorbaContactInfoListIterator;
  66 
  67 import com.sun.corba.se.impl.corba.RequestImpl;
  68 import com.sun.corba.se.impl.protocol.CorbaInvocationInfo;
  69 import com.sun.corba.se.impl.transport.CorbaContactInfoListImpl;
  70 import com.sun.corba.se.impl.util.JDKBridge;
  71 import com.sun.corba.se.impl.logging.ORBUtilSystemException;
  72 
  73 // implements com.sun.corba.se.impl.core.ClientRequestDispatcher
  74 // so RMI-IIOP Util.isLocal can call ClientRequestDispatcher.useLocalInvocation.
  75 
  76 /**
  77  * @author Harold Carr
  78  */
  79 public class CorbaClientDelegateImpl extends CorbaClientDelegate
  80 {
  81     private ORB orb;
  82     private ORBUtilSystemException wrapper ;
  83 
  84     private CorbaContactInfoList contactInfoList;
  85 
  86     public CorbaClientDelegateImpl(ORB orb,
  87                                    CorbaContactInfoList contactInfoList)
  88     {
  89         this.orb = orb;
  90         this.wrapper = ORBUtilSystemException.get( orb,
  91             CORBALogDomains.RPC_PROTOCOL ) ;
  92         this.contactInfoList = contactInfoList;
  93     }
  94 
  95     //
  96     // framework.subcontract.Delegate
  97     //
  98 
  99     public Broker getBroker()
 100     {
 101         return orb;
 102     }
 103 
 104     public ContactInfoList getContactInfoList()
 105     {
 106         return contactInfoList;
 107     }
 108 
 109     //
 110     // CORBA_2_3.portable.Delegate
 111     //
 112 
 113     public OutputStream request(org.omg.CORBA.Object self,
 114                                 String operation,
 115                                 boolean responseExpected)
 116     {
 117         ClientInvocationInfo invocationInfo =
 118             orb.createOrIncrementInvocationInfo();
 119         Iterator contactInfoListIterator =
 120             invocationInfo.getContactInfoListIterator();
 121         if (contactInfoListIterator == null) {
 122             contactInfoListIterator = contactInfoList.iterator();
 123             invocationInfo.setContactInfoListIterator(contactInfoListIterator);
 124         }
 125         if (! contactInfoListIterator.hasNext()) {
 126             throw ((CorbaContactInfoListIterator)contactInfoListIterator)
 127                 .getFailureException();
 128         }
 129         CorbaContactInfo contactInfo = (CorbaContactInfo) contactInfoListIterator.next();
 130         ClientRequestDispatcher subcontract = contactInfo.getClientRequestDispatcher();
 131         // Remember chosen subcontract for invoke and releaseReply.
 132         // NOTE: This is necessary since a stream is not available in
 133         // releaseReply if there is a client marshaling error or an
 134         // error in _invoke.
 135         invocationInfo.setClientRequestDispatcher(subcontract);
 136         return (OutputStream)
 137             subcontract.beginRequest(self, operation,
 138                                      !responseExpected, contactInfo);
 139     }
 140 
 141     public InputStream invoke(org.omg.CORBA.Object self, OutputStream output)
 142         throws
 143             ApplicationException,
 144             RemarshalException
 145     {
 146         ClientRequestDispatcher subcontract = getClientRequestDispatcher();
 147         return (InputStream)
 148             subcontract.marshalingComplete((Object)self, (OutputObject)output);
 149     }
 150 
 151     public void releaseReply(org.omg.CORBA.Object self, InputStream input)
 152     {
 153         // NOTE: InputStream may be null (e.g., exception request from PI).
 154         ClientRequestDispatcher subcontract = getClientRequestDispatcher();
 155         subcontract.endRequest(orb, self, (InputObject)input);
 156         orb.releaseOrDecrementInvocationInfo();
 157     }
 158 
 159     private ClientRequestDispatcher getClientRequestDispatcher()
 160     {
 161         return (ClientRequestDispatcher)
 162             ((CorbaInvocationInfo)orb.getInvocationInfo())
 163             .getClientRequestDispatcher();
 164     }
 165 
 166     public org.omg.CORBA.Object get_interface_def(org.omg.CORBA.Object obj)
 167     {
 168         InputStream is = null;
 169         // instantiate the stub
 170         org.omg.CORBA.Object stub = null ;
 171 
 172         try {
 173             OutputStream os = request(null, "_interface", true);
 174             is = (InputStream) invoke((org.omg.CORBA.Object)null, os);
 175 
 176             org.omg.CORBA.Object objimpl =
 177                 (org.omg.CORBA.Object) is.read_Object();
 178 
 179             // check if returned object is of correct type
 180             if ( !objimpl._is_a("IDL:omg.org/CORBA/InterfaceDef:1.0") )
 181                 throw wrapper.wrongInterfaceDef(CompletionStatus.COMPLETED_MAYBE);
 182 
 183             try {
 184                 stub = (org.omg.CORBA.Object)
 185                     JDKBridge.loadClass("org.omg.CORBA._InterfaceDefStub").
 186                         newInstance();
 187             } catch (Exception ex) {
 188                 throw wrapper.noInterfaceDefStub( ex ) ;
 189             }
 190 
 191             org.omg.CORBA.portable.Delegate del =
 192                 StubAdapter.getDelegate( objimpl ) ;
 193             StubAdapter.setDelegate( stub, del ) ;
 194         } catch (ApplicationException e) {
 195             // This cannot happen.
 196             throw wrapper.applicationExceptionInSpecialMethod( e ) ;
 197         } catch (RemarshalException e) {
 198             return get_interface_def(obj);
 199         } finally {
 200             releaseReply((org.omg.CORBA.Object)null, (InputStream)is);
 201         }
 202 
 203         return stub;
 204     }
 205 
 206     public boolean is_a(org.omg.CORBA.Object obj, String dest)
 207     {
 208         // dest is the typeId of the interface to compare against.
 209         // repositoryIds is the list of typeIds that the stub knows about.
 210 
 211         // First we look for an answer using local information.
 212 
 213         String [] repositoryIds = StubAdapter.getTypeIds( obj ) ;
 214         String myid = contactInfoList.getTargetIOR().getTypeId();
 215         if ( dest.equals(myid) ) {
 216             return true;
 217         }
 218         for ( int i=0; i<repositoryIds.length; i++ ) {
 219             if ( dest.equals(repositoryIds[i]) ) {
 220                 return true;
 221             }
 222         }
 223 
 224         // But repositoryIds may not be complete, so it may be necessary to
 225         // go to server.
 226 
 227         InputStream is = null;
 228         try {
 229             OutputStream os = request(null, "_is_a", true);
 230             os.write_string(dest);
 231             is = (InputStream) invoke((org.omg.CORBA.Object) null, os);
 232 
 233             return is.read_boolean();
 234 
 235         } catch (ApplicationException e) {
 236             // This cannot happen.
 237             throw wrapper.applicationExceptionInSpecialMethod( e ) ;
 238         } catch (RemarshalException e) {
 239             return is_a(obj, dest);
 240         } finally {
 241             releaseReply((org.omg.CORBA.Object)null, (InputStream)is);
 242         }
 243     }
 244 
 245     public boolean non_existent(org.omg.CORBA.Object obj)
 246     {
 247         InputStream is = null;
 248         try {
 249             OutputStream os = request(null, "_non_existent", true);
 250             is = (InputStream) invoke((org.omg.CORBA.Object)null, os);
 251 
 252             return is.read_boolean();
 253 
 254         } catch (ApplicationException e) {
 255             // This cannot happen.
 256             throw wrapper.applicationExceptionInSpecialMethod( e ) ;
 257         } catch (RemarshalException e) {
 258             return non_existent(obj);
 259         } finally {
 260             releaseReply((org.omg.CORBA.Object)null, (InputStream)is);
 261         }
 262     }
 263 
 264     public org.omg.CORBA.Object duplicate(org.omg.CORBA.Object obj)
 265     {
 266         return obj;
 267     }
 268 
 269     public void release(org.omg.CORBA.Object obj)
 270     {
 271         // DO NOT clear out internal variables to release memory
 272         // This delegate may be pointed-to by other objrefs.
 273     }
 274 
 275     // obj._get_delegate() == this due to the argument passing conventions in
 276     // portable.ObjectImpl, so we just ignore obj here.
 277     public boolean is_equivalent(org.omg.CORBA.Object obj,
 278                                  org.omg.CORBA.Object ref)
 279     {
 280         if ( ref == null )
 281             return false;
 282 
 283         // If ref is a local object, it is not a Stub!
 284         if (!StubAdapter.isStub(ref))
 285             return false ;
 286 
 287         Delegate del = StubAdapter.getDelegate(ref) ;
 288         if (del == null)
 289             return false ;
 290 
 291         // Optimize the x.is_equivalent( x ) case
 292         if (del == this)
 293             return true;
 294 
 295         // If delegate was created by a different ORB, return false
 296         if (!(del instanceof CorbaClientDelegateImpl))
 297             return false ;
 298 
 299         CorbaClientDelegateImpl corbaDelegate = (CorbaClientDelegateImpl)del ;
 300         CorbaContactInfoList ccil =
 301             (CorbaContactInfoList)corbaDelegate.getContactInfoList() ;
 302         return this.contactInfoList.getTargetIOR().isEquivalent(
 303             ccil.getTargetIOR() );
 304     }
 305 
 306     /**
 307      * This method overrides the org.omg.CORBA.portable.Delegate.equals method,
 308      * and does the equality check based on IOR equality.
 309      */
 310     public boolean equals(org.omg.CORBA.Object self, java.lang.Object other)
 311     {
 312         if (other == null)
 313             return false ;
 314 
 315         if (!StubAdapter.isStub(other)) {
 316             return false;
 317         }
 318 
 319         Delegate delegate = StubAdapter.getDelegate( other ) ;
 320         if (delegate == null)
 321             return false ;
 322 
 323         if (delegate instanceof CorbaClientDelegateImpl) {
 324             CorbaClientDelegateImpl otherDel = (CorbaClientDelegateImpl)
 325                 delegate ;
 326             IOR otherIor = otherDel.contactInfoList.getTargetIOR();
 327             return this.contactInfoList.getTargetIOR().equals(otherIor);
 328         }
 329 
 330         // Come here if other is not implemented by our ORB.
 331         return false;
 332     }
 333 
 334     public int hashCode(org.omg.CORBA.Object obj)
 335     {
 336         return this.hashCode() ;
 337     }
 338 
 339     public int hash(org.omg.CORBA.Object obj, int maximum)
 340     {
 341         int h = this.hashCode();
 342         if ( h > maximum )
 343             return 0;
 344         return h;
 345     }
 346 
 347     public Request request(org.omg.CORBA.Object obj, String operation)
 348     {
 349         return new RequestImpl(orb, obj, null, operation, null, null, null,
 350                                null);
 351     }
 352 
 353     public Request create_request(org.omg.CORBA.Object obj,
 354                                   Context ctx,
 355                                   String operation,
 356                                   NVList arg_list,
 357                                   NamedValue result)
 358     {
 359         return new RequestImpl(orb, obj, ctx, operation, arg_list,
 360                                result, null, null);
 361     }
 362 
 363     public Request create_request(org.omg.CORBA.Object obj,
 364                                   Context ctx,
 365                                   String operation,
 366                                   NVList arg_list,
 367                                   NamedValue result,
 368                                   ExceptionList exclist,
 369                                   ContextList ctxlist)
 370     {
 371         return new RequestImpl(orb, obj, ctx, operation, arg_list, result,
 372                                exclist, ctxlist);
 373     }
 374 
 375     public org.omg.CORBA.ORB orb(org.omg.CORBA.Object obj)
 376     {
 377         return this.orb;
 378     }
 379 
 380     /**
 381      * Returns true if this object is implemented by a local servant.
 382      *
 383      * REVISIT: locatedIOR should be replaced with a method call that
 384      *      returns the current IOR for this request (e.g. ContactInfoChooser).
 385      *
 386      * @param self The object reference which delegated to this delegate.
 387      * @return true only if the servant incarnating this object is located in
 388      * this ORB.
 389      */
 390     public boolean is_local(org.omg.CORBA.Object self)
 391     {
 392         // XXX this need to check isNextCallValid
 393         return contactInfoList.getEffectiveTargetIOR().getProfile().
 394             isLocal();
 395     }
 396 
 397     public ServantObject servant_preinvoke(org.omg.CORBA.Object self,
 398                                            String operation,
 399                                            Class expectedType)
 400     {
 401         return
 402             contactInfoList.getLocalClientRequestDispatcher()
 403             .servant_preinvoke(self, operation, expectedType);
 404     }
 405 
 406     public void servant_postinvoke(org.omg.CORBA.Object self,
 407                                    ServantObject servant)
 408     {
 409         contactInfoList.getLocalClientRequestDispatcher()
 410             .servant_postinvoke(self, servant);
 411     }
 412 
 413     // XXX Should this be public?
 414     /* Returns the codebase for object reference provided.
 415      * @param self the object reference whose codebase needs to be returned.
 416      * @return the codebase as a space delimited list of url strings or
 417      * null if none.
 418      */
 419     public String get_codebase(org.omg.CORBA.Object self)
 420     {
 421         if (contactInfoList.getTargetIOR() != null) {
 422             return contactInfoList.getTargetIOR().getProfile().getCodebase();
 423         }
 424         return null;
 425     }
 426 
 427     public String toString(org.omg.CORBA.Object self)
 428     {
 429         return contactInfoList.getTargetIOR().stringify();
 430     }
 431 
 432     ////////////////////////////////////////////////////
 433     //
 434     // java.lang.Object
 435     //
 436 
 437     public int hashCode()
 438     {
 439         return this.contactInfoList.hashCode();
 440     }
 441 }
 442 
 443 // End of file.