1 /*
   2  * Copyright (c) 2000, 2012, 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.interceptors;
  27 
  28 import java.util.HashMap ;
  29 
  30 import org.omg.CORBA.Any;
  31 import org.omg.CORBA.BAD_INV_ORDER;
  32 import org.omg.CORBA.BAD_PARAM;
  33 import org.omg.CORBA.CompletionStatus;
  34 import org.omg.CORBA.Context;
  35 import org.omg.CORBA.ContextList;
  36 import org.omg.CORBA.CTX_RESTRICT_SCOPE;
  37 import org.omg.CORBA.ExceptionList;
  38 import org.omg.CORBA.LocalObject;
  39 import org.omg.CORBA.NamedValue;
  40 import org.omg.CORBA.NO_IMPLEMENT;
  41 import org.omg.CORBA.NO_RESOURCES;
  42 import org.omg.CORBA.NVList;
  43 import org.omg.CORBA.Object;
  44 import org.omg.CORBA.ParameterMode;
  45 import org.omg.CORBA.Policy;
  46 import org.omg.CORBA.SystemException;
  47 import org.omg.CORBA.TypeCode;
  48 import org.omg.CORBA.INTERNAL;
  49 import org.omg.CORBA.UserException;
  50 import org.omg.CORBA.portable.ApplicationException;
  51 import org.omg.CORBA.portable.InputStream;
  52 import com.sun.corba.se.spi.servicecontext.ServiceContexts;
  53 import com.sun.corba.se.spi.servicecontext.UnknownServiceContext;
  54 
  55 import org.omg.IOP.ServiceContext;
  56 import org.omg.IOP.ServiceContextHelper;
  57 import org.omg.IOP.TaggedProfile;
  58 import org.omg.IOP.TaggedProfileHelper;
  59 import org.omg.IOP.TaggedComponent;
  60 import org.omg.IOP.TaggedComponentHelper;
  61 import org.omg.IOP.TAG_INTERNET_IOP;
  62 import org.omg.Dynamic.Parameter;
  63 import org.omg.PortableInterceptor.ClientRequestInfo;
  64 import org.omg.PortableInterceptor.LOCATION_FORWARD;
  65 import org.omg.PortableInterceptor.SUCCESSFUL;
  66 import org.omg.PortableInterceptor.SYSTEM_EXCEPTION;
  67 import org.omg.PortableInterceptor.TRANSPORT_RETRY;
  68 import org.omg.PortableInterceptor.USER_EXCEPTION;
  69 
  70 import com.sun.corba.se.pept.protocol.MessageMediator;
  71 
  72 import com.sun.corba.se.spi.ior.IOR;
  73 import com.sun.corba.se.spi.ior.iiop.IIOPProfileTemplate;
  74 import com.sun.corba.se.spi.ior.iiop.GIOPVersion;
  75 import com.sun.corba.se.spi.orb.ORB;
  76 import com.sun.corba.se.spi.protocol.CorbaMessageMediator;
  77 import com.sun.corba.se.spi.protocol.RetryType;
  78 import com.sun.corba.se.spi.transport.CorbaContactInfo;
  79 import com.sun.corba.se.spi.transport.CorbaContactInfoList;
  80 import com.sun.corba.se.spi.transport.CorbaContactInfoListIterator;
  81 
  82 import com.sun.corba.se.impl.encoding.CDROutputStream;
  83 import com.sun.corba.se.impl.encoding.CDRInputStream_1_0;
  84 import com.sun.corba.se.impl.orbutil.ORBUtility;
  85 import com.sun.corba.se.impl.protocol.CorbaInvocationInfo;
  86 import com.sun.corba.se.impl.util.RepositoryId;
  87 
  88 /**
  89  * Implementation of the ClientRequestInfo interface as specified in
  90  * orbos/99-12-02 section 5.4.2.
  91  */
  92 public final class ClientRequestInfoImpl
  93     extends RequestInfoImpl
  94     implements ClientRequestInfo
  95 {
  96 
  97     // The available constants for startingPointCall
  98     static final int CALL_SEND_REQUEST = 0;
  99     static final int CALL_SEND_POLL = 1;
 100 
 101     // The available constants for endingPointCall
 102     static final int CALL_RECEIVE_REPLY = 0;
 103     static final int CALL_RECEIVE_EXCEPTION = 1;
 104     static final int CALL_RECEIVE_OTHER = 2;
 105 
 106     //////////////////////////////////////////////////////////////////////
 107     //
 108     // NOTE: IF AN ATTRIBUTE IS ADDED, PLEASE UPDATE RESET();
 109     //
 110     //////////////////////////////////////////////////////////////////////
 111 
 112     // The current retry request status.  True if this request is being
 113     // retried and this info object is to be reused, or false otherwise.
 114     private RetryType retryRequest;
 115 
 116     // The number of times this info object has been (re)used.  This is
 117     // incremented every time a request is retried, and decremented every
 118     // time a request is complete.  When this reaches zero, the info object
 119     // is popped from the ClientRequestInfoImpl ThreadLocal stack in the ORB.
 120     private int entryCount = 0;
 121 
 122     // The RequestImpl is set when the call is DII based.
 123     // The DII query calls like ParameterList, ExceptionList,
 124     // ContextList will be delegated to RequestImpl.
 125     private org.omg.CORBA.Request request;
 126 
 127     // Sources of client request information
 128     private boolean diiInitiate;
 129     private CorbaMessageMediator messageMediator;
 130 
 131     // Cached information:
 132     private org.omg.CORBA.Object cachedTargetObject;
 133     private org.omg.CORBA.Object cachedEffectiveTargetObject;
 134     private Parameter[] cachedArguments;
 135     private TypeCode[] cachedExceptions;
 136     private String[] cachedContexts;
 137     private String[] cachedOperationContext;
 138     private String cachedReceivedExceptionId;
 139     private Any cachedResult;
 140     private Any cachedReceivedException;
 141     private TaggedProfile cachedEffectiveProfile;
 142     // key = Integer, value = IOP.ServiceContext.
 143     private HashMap cachedRequestServiceContexts;
 144     // key = Integer, value = IOP.ServiceContext.
 145     private HashMap cachedReplyServiceContexts;
 146     // key = Integer, value = TaggedComponent
 147     private HashMap cachedEffectiveComponents;
 148 
 149 
 150     protected boolean piCurrentPushed;
 151 
 152     //////////////////////////////////////////////////////////////////////
 153     //
 154     // NOTE: IF AN ATTRIBUTE IS ADDED, PLEASE UPDATE RESET();
 155     //
 156     //////////////////////////////////////////////////////////////////////
 157 
 158     /**
 159      * Reset the info object so that it can be reused for a retry,
 160      * for example.
 161      */
 162     void reset() {
 163         super.reset();
 164 
 165         // Please keep these in the same order that they're declared above.
 166 
 167         // 6763340
 168         retryRequest = RetryType.NONE;
 169 
 170         // Do not reset entryCount because we need to know when to pop this
 171         // from the stack.
 172 
 173         request = null;
 174         diiInitiate = false;
 175         messageMediator = null;
 176 
 177         // Clear cached attributes:
 178         cachedTargetObject = null;
 179         cachedEffectiveTargetObject = null;
 180         cachedArguments = null;
 181         cachedExceptions = null;
 182         cachedContexts = null;
 183         cachedOperationContext = null;
 184         cachedReceivedExceptionId = null;
 185         cachedResult = null;
 186         cachedReceivedException = null;
 187         cachedEffectiveProfile = null;
 188         cachedRequestServiceContexts = null;
 189         cachedReplyServiceContexts = null;
 190         cachedEffectiveComponents = null;
 191 
 192         piCurrentPushed = false;
 193 
 194         startingPointCall = CALL_SEND_REQUEST;
 195         endingPointCall = CALL_RECEIVE_REPLY;
 196 
 197     }
 198 
 199     /*
 200      **********************************************************************
 201      * Access protection
 202      **********************************************************************/
 203 
 204     // Method IDs for all methods in ClientRequestInfo.  This allows for a
 205     // convenient O(1) lookup for checkAccess().
 206     protected static final int MID_TARGET                  = MID_RI_LAST + 1;
 207     protected static final int MID_EFFECTIVE_TARGET        = MID_RI_LAST + 2;
 208     protected static final int MID_EFFECTIVE_PROFILE       = MID_RI_LAST + 3;
 209     protected static final int MID_RECEIVED_EXCEPTION      = MID_RI_LAST + 4;
 210     protected static final int MID_RECEIVED_EXCEPTION_ID   = MID_RI_LAST + 5;
 211     protected static final int MID_GET_EFFECTIVE_COMPONENT = MID_RI_LAST + 6;
 212     protected static final int MID_GET_EFFECTIVE_COMPONENTS
 213                                                            = MID_RI_LAST + 7;
 214     protected static final int MID_GET_REQUEST_POLICY      = MID_RI_LAST + 8;
 215     protected static final int MID_ADD_REQUEST_SERVICE_CONTEXT
 216                                                            = MID_RI_LAST + 9;
 217 
 218     // ClientRequestInfo validity table (see ptc/00-08-06 table 21-1).
 219     // Note: These must be in the same order as specified in contants.
 220     private static final boolean validCall[][] = {
 221         // LEGEND:
 222         // s_req = send_request     r_rep = receive_reply
 223         // s_pol = send_poll        r_exc = receive_exception
 224         //                          r_oth = receive_other
 225         //
 226         // A true value indicates call is valid at specified point.
 227         // A false value indicates the call is invalid.
 228         //
 229         //
 230         // NOTE: If the order or number of columns change, update
 231         // checkAccess() accordingly.
 232         //
 233         //                              { s_req, s_pol, r_rep, r_exc, r_oth }
 234         // RequestInfo methods:
 235         /*request_id*/                  { true , true , true , true , true  },
 236         /*operation*/                   { true , true , true , true , true  },
 237         /*arguments*/                   { true , false, true , false, false },
 238         /*exceptions*/                  { true , false, true , true , true  },
 239         /*contexts*/                    { true , false, true , true , true  },
 240         /*operation_context*/           { true , false, true , true , true  },
 241         /*result*/                      { false, false, true , false, false },
 242         /*response_expected*/           { true , true , true , true , true  },
 243         /*sync_scope*/                  { true , false, true , true , true  },
 244         /*reply_status*/                { false, false, true , true , true  },
 245         /*forward_reference*/           { false, false, false, false, true  },
 246         /*get_slot*/                    { true , true , true , true , true  },
 247         /*get_request_service_context*/ { true , false, true , true , true  },
 248         /*get_reply_service_context*/   { false, false, true , true , true  },
 249         //
 250         // ClientRequestInfo methods::
 251         /*target*/                      { true , true , true , true , true  },
 252         /*effective_target*/            { true , true , true , true , true  },
 253         /*effective_profile*/           { true , true , true , true , true  },
 254         /*received_exception*/          { false, false, false, true , false },
 255         /*received_exception_id*/       { false, false, false, true , false },
 256         /*get_effective_component*/     { true , false, true , true , true  },
 257         /*get_effective_components*/    { true , false, true , true , true  },
 258         /*get_request_policy*/          { true , false, true , true , true  },
 259         /*add_request_service_context*/ { true , false, false, false, false }
 260     };
 261 
 262 
 263     /*
 264      **********************************************************************
 265      * Public ClientRequestInfo interfaces
 266      **********************************************************************/
 267 
 268     /**
 269      * Creates a new ClientRequestInfo implementation.
 270      * The constructor is package scope since no other package need create
 271      * an instance of this class.
 272      */
 273     protected ClientRequestInfoImpl( ORB myORB ) {
 274         super( myORB );
 275         startingPointCall = CALL_SEND_REQUEST;
 276         endingPointCall = CALL_RECEIVE_REPLY;
 277     }
 278 
 279     /**
 280      * The object which the client called to perform the operation.
 281      */
 282     public org.omg.CORBA.Object target (){
 283         // access is currently valid for all states:
 284         //checkAccess( MID_TARGET );
 285         if (cachedTargetObject == null) {
 286             CorbaContactInfo corbaContactInfo = (CorbaContactInfo)
 287                 messageMediator.getContactInfo();
 288             cachedTargetObject =
 289                 iorToObject(corbaContactInfo.getTargetIOR());
 290         }
 291         return cachedTargetObject;
 292     }
 293 
 294     /**
 295      * The actual object on which the operation will be invoked.  If the
 296      * reply_status is LOCATION_FORWARD, then on subsequent requests,
 297      * effective_target will contain the forwarded IOR while target will
 298      * remain unchanged.
 299      */
 300     public org.omg.CORBA.Object effective_target() {
 301         // access is currently valid for all states:
 302         //checkAccess( MID_EFFECTIVE_TARGET );
 303 
 304         // Note: This is not necessarily the same as locatedIOR.
 305         // Reason: See the way we handle COMM_FAILURES in
 306         // ClientRequestDispatcher.createRequest, v1.32
 307 
 308         if (cachedEffectiveTargetObject == null) {
 309             CorbaContactInfo corbaContactInfo = (CorbaContactInfo)
 310                 messageMediator.getContactInfo();
 311             // REVISIT - get through chain like getLocatedIOR helper below.
 312             cachedEffectiveTargetObject =
 313                 iorToObject(corbaContactInfo.getEffectiveTargetIOR());
 314         }
 315         return cachedEffectiveTargetObject;
 316     }
 317 
 318     /**
 319      * The profile that will be used to send the request.  If a location
 320      * forward has occurred for this operation's object and that object's
 321      * profile change accordingly, then this profile will be that located
 322      * profile.
 323      */
 324     public TaggedProfile effective_profile (){
 325         // access is currently valid for all states:
 326         //checkAccess( MID_EFFECTIVE_PROFILE );
 327 
 328         if( cachedEffectiveProfile == null ) {
 329             CorbaContactInfo corbaContactInfo = (CorbaContactInfo)
 330                 messageMediator.getContactInfo();
 331             cachedEffectiveProfile =
 332                 corbaContactInfo.getEffectiveProfile().getIOPProfile();
 333         }
 334 
 335         // Good citizen: In the interest of efficiency, we assume interceptors
 336         // will not modify the returned TaggedProfile in any way so we need
 337         // not make a deep copy of it.
 338 
 339         return cachedEffectiveProfile;
 340     }
 341 
 342     /**
 343      * Contains the exception to be returned to the client.
 344      */
 345     public Any received_exception (){
 346         checkAccess( MID_RECEIVED_EXCEPTION );
 347 
 348         if( cachedReceivedException == null ) {
 349             cachedReceivedException = exceptionToAny( exception );
 350         }
 351 
 352         // Good citizen: In the interest of efficiency, we assume interceptors
 353         // will not modify the returned Any in any way so we need
 354         // not make a deep copy of it.
 355 
 356         return cachedReceivedException;
 357     }
 358 
 359     /**
 360      * The CORBA::RepositoryId of the exception to be returned to the client.
 361      */
 362     public String received_exception_id (){
 363         checkAccess( MID_RECEIVED_EXCEPTION_ID );
 364 
 365         if( cachedReceivedExceptionId == null ) {
 366             String result = null;
 367 
 368             if( exception == null ) {
 369                 // Note: exception should never be null here since we will
 370                 // throw a BAD_INV_ORDER if this is not called from
 371                 // receive_exception.
 372                 throw wrapper.exceptionWasNull() ;
 373             } else if( exception instanceof SystemException ) {
 374                 String name = exception.getClass().getName();
 375                 result = ORBUtility.repositoryIdOf(name);
 376             } else if( exception instanceof ApplicationException ) {
 377                 result = ((ApplicationException)exception).getId();
 378             }
 379 
 380             // _REVISIT_ We need to be able to handle a UserException in the
 381             // DII case.  How do we extract the ID from a UserException?
 382 
 383             cachedReceivedExceptionId = result;
 384         }
 385 
 386         return cachedReceivedExceptionId;
 387     }
 388 
 389     /**
 390      * Returns the IOP::TaggedComponent with the given ID from the profile
 391      * selected for this request.  IF there is more than one component for a
 392      * given component ID, it is undefined which component this operation
 393      * returns (get_effective_component should be called instead).
 394      */
 395     public TaggedComponent get_effective_component (int id){
 396         checkAccess( MID_GET_EFFECTIVE_COMPONENT );
 397 
 398         return get_effective_components( id )[0];
 399     }
 400 
 401     /**
 402      * Returns all the tagged components with the given ID from the profile
 403      * selected for this request.
 404      */
 405     public TaggedComponent[] get_effective_components (int id){
 406         checkAccess( MID_GET_EFFECTIVE_COMPONENTS );
 407         Integer integerId = new Integer( id );
 408         TaggedComponent[] result = null;
 409         boolean justCreatedCache = false;
 410 
 411         if( cachedEffectiveComponents == null ) {
 412             cachedEffectiveComponents = new HashMap();
 413             justCreatedCache = true;
 414         }
 415         else {
 416             // Look in cache:
 417             result = (TaggedComponent[])cachedEffectiveComponents.get(
 418                 integerId );
 419         }
 420 
 421         // null could mean we cached null or not in cache.
 422         if( (result == null) &&
 423             (justCreatedCache ||
 424             !cachedEffectiveComponents.containsKey( integerId ) ) )
 425         {
 426             // Not in cache.  Get it from the profile:
 427             CorbaContactInfo corbaContactInfo = (CorbaContactInfo)
 428                 messageMediator.getContactInfo();
 429             IIOPProfileTemplate ptemp =
 430                 (IIOPProfileTemplate)corbaContactInfo.getEffectiveProfile().
 431                 getTaggedProfileTemplate();
 432             result = ptemp.getIOPComponents(myORB, id);
 433             cachedEffectiveComponents.put( integerId, result );
 434         }
 435 
 436         // As per ptc/00-08-06, section 21.3.13.6., If not found, raise
 437         // BAD_PARAM with minor code INVALID_COMPONENT_ID.
 438         if( (result == null) || (result.length == 0) ) {
 439             throw stdWrapper.invalidComponentId( integerId ) ;
 440         }
 441 
 442         // Good citizen: In the interest of efficiency, we will assume
 443         // interceptors will not modify the returned TaggedCompoent[], or
 444         // the TaggedComponents inside of it.  Otherwise, we would need to
 445         // clone the array and make a deep copy of its contents.
 446 
 447         return result;
 448     }
 449 
 450     /**
 451      * Returns the given policy in effect for this operation.
 452      */
 453     public Policy get_request_policy (int type){
 454         checkAccess( MID_GET_REQUEST_POLICY );
 455         // _REVISIT_ Our ORB is not policy-based at this time.
 456         throw wrapper.piOrbNotPolicyBased() ;
 457     }
 458 
 459     /**
 460      * Allows interceptors to add service contexts to the request.
 461      * <p>
 462      * There is no declaration of the order of the service contexts.  They
 463      * may or may not appear in the order they are added.
 464      */
 465     public void add_request_service_context (ServiceContext service_context,
 466                                              boolean replace)
 467     {
 468         checkAccess( MID_ADD_REQUEST_SERVICE_CONTEXT );
 469 
 470         if( cachedRequestServiceContexts == null ) {
 471             cachedRequestServiceContexts = new HashMap();
 472         }
 473 
 474         addServiceContext( cachedRequestServiceContexts,
 475                            messageMediator.getRequestServiceContexts(),
 476                            service_context, replace );
 477     }
 478 
 479     // NOTE: When adding a method, be sure to:
 480     // 1. Add a MID_* constant for that method
 481     // 2. Call checkAccess at the start of the method
 482     // 3. Define entries in the validCall[][] table for interception points.
 483 
 484     /*
 485      **********************************************************************
 486      * Public RequestInfo interfaces
 487      *
 488      * These are implemented here because they have differing
 489      * implementations depending on whether this is a client or a server
 490      * request info object.
 491      **********************************************************************/
 492 
 493     /**
 494      * See RequestInfoImpl for javadoc.
 495      */
 496     public int request_id (){
 497         // access is currently valid for all states:
 498         //checkAccess( MID_REQUEST_ID );
 499         /*
 500          * NOTE: The requestId in client interceptors is the same as the
 501          * GIOP request id.  This works because both interceptors and
 502          * request ids are scoped by the ORB on the client side.
 503          */
 504         return messageMediator.getRequestId();
 505     }
 506 
 507     /**
 508      * See RequestInfoImpl for javadoc.
 509      */
 510     public String operation (){
 511         // access is currently valid for all states:
 512         //checkAccess( MID_OPERATION );
 513         return messageMediator.getOperationName();
 514     }
 515 
 516     /**
 517      * See RequestInfoImpl for javadoc.
 518      */
 519     public Parameter[] arguments (){
 520         checkAccess( MID_ARGUMENTS );
 521 
 522         if( cachedArguments == null ) {
 523             if( request == null ) {
 524                 throw stdWrapper.piOperationNotSupported1() ;
 525             }
 526 
 527             // If it is DII request then get the arguments from the DII req
 528             // and convert that into parameters.
 529             cachedArguments = nvListToParameterArray( request.arguments() );
 530         }
 531 
 532         // Good citizen: In the interest of efficiency, we assume
 533         // interceptors will be "good citizens" in that they will not
 534         // modify the contents of the Parameter[] array.  We also assume
 535         // they will not change the values of the containing Anys.
 536 
 537         return cachedArguments;
 538     }
 539 
 540     /**
 541      * See RequestInfoImpl for javadoc.
 542      */
 543     public TypeCode[] exceptions (){
 544         checkAccess( MID_EXCEPTIONS );
 545 
 546         if( cachedExceptions == null ) {
 547             if( request == null ) {
 548                throw stdWrapper.piOperationNotSupported2() ;
 549             }
 550 
 551             // Get the list of exceptions from DII request data, If there are
 552             // no exceptions raised then this method will return null.
 553             ExceptionList excList = request.exceptions( );
 554             int count = excList.count();
 555             TypeCode[] excTCList = new TypeCode[count];
 556             try {
 557                 for( int i = 0; i < count; i++ ) {
 558                     excTCList[i] = excList.item( i );
 559                 }
 560             } catch( Exception e ) {
 561                 throw wrapper.exceptionInExceptions( e ) ;
 562             }
 563 
 564             cachedExceptions = excTCList;
 565         }
 566 
 567         // Good citizen: In the interest of efficiency, we assume
 568         // interceptors will be "good citizens" in that they will not
 569         // modify the contents of the TypeCode[] array.  We also assume
 570         // they will not change the values of the containing TypeCodes.
 571 
 572         return cachedExceptions;
 573     }
 574 
 575     /**
 576      * See RequestInfoImpl for javadoc.
 577      */
 578     public String[] contexts (){
 579         checkAccess( MID_CONTEXTS );
 580 
 581         if( cachedContexts == null ) {
 582             if( request == null ) {
 583                 throw stdWrapper.piOperationNotSupported3() ;
 584             }
 585 
 586             // Get the list of contexts from DII request data, If there are
 587             // no contexts then this method will return null.
 588             ContextList ctxList = request.contexts( );
 589             int count = ctxList.count();
 590             String[] ctxListToReturn = new String[count];
 591             try {
 592                 for( int i = 0; i < count; i++ ) {
 593                     ctxListToReturn[i] = ctxList.item( i );
 594                 }
 595             } catch( Exception e ) {
 596                 throw wrapper.exceptionInContexts( e ) ;
 597             }
 598 
 599             cachedContexts = ctxListToReturn;
 600         }
 601 
 602         // Good citizen: In the interest of efficiency, we assume
 603         // interceptors will be "good citizens" in that they will not
 604         // modify the contents of the String[] array.
 605 
 606         return cachedContexts;
 607     }
 608 
 609     /**
 610      * See RequestInfoImpl for javadoc.
 611      */
 612     public String[] operation_context (){
 613         checkAccess( MID_OPERATION_CONTEXT );
 614 
 615         if( cachedOperationContext == null ) {
 616             if( request == null ) {
 617                 throw stdWrapper.piOperationNotSupported4() ;
 618             }
 619 
 620             // Get the list of contexts from DII request data, If there are
 621             // no contexts then this method will return null.
 622             Context ctx = request.ctx( );
 623             // _REVISIT_ The API for get_values is not compliant with the spec,
 624             // Revisit this code once it's fixed.
 625             // _REVISIT_ Our ORB doesn't support Operation Context, This code
 626             // will not be excerscised until it's supported.
 627             // The first parameter in get_values is the start_scope which
 628             // if blank makes it as a global scope.
 629             // The second parameter is op_flags which is set to RESTRICT_SCOPE
 630             // As there is only one defined in the spec.
 631             // The Third param is the pattern which is '*' requiring it to
 632             // get all the contexts.
 633             NVList nvList = ctx.get_values( "", CTX_RESTRICT_SCOPE.value,"*" );
 634             String[] context = new String[(nvList.count() * 2) ];
 635             if( ( nvList != null ) &&( nvList.count() != 0 ) ) {
 636                 // The String[] array will contain Name and Value for each
 637                 // context and hence double the size in the array.
 638                 int index = 0;
 639                 for( int i = 0; i < nvList.count(); i++ ) {
 640                     NamedValue nv;
 641                     try {
 642                         nv = nvList.item( i );
 643                     }
 644                     catch (Exception e ) {
 645                         return (String[]) null;
 646                     }
 647                     context[index] = nv.name();
 648                     index++;
 649                     context[index] = nv.value().extract_string();
 650                     index++;
 651                 }
 652             }
 653 
 654             cachedOperationContext = context;
 655         }
 656 
 657         // Good citizen: In the interest of efficiency, we assume
 658         // interceptors will be "good citizens" in that they will not
 659         // modify the contents of the String[] array.
 660 
 661         return cachedOperationContext;
 662     }
 663 
 664     /**
 665      * See RequestInfoImpl for javadoc.
 666      */
 667     public Any result (){
 668         checkAccess( MID_RESULT );
 669 
 670         if( cachedResult == null ) {
 671             if( request == null ) {
 672                 throw stdWrapper.piOperationNotSupported5() ;
 673             }
 674             // Get the result from the DII request data.
 675             NamedValue nvResult = request.result( );
 676 
 677             if( nvResult == null ) {
 678                 throw wrapper.piDiiResultIsNull() ;
 679             }
 680 
 681             cachedResult = nvResult.value();
 682         }
 683 
 684         // Good citizen: In the interest of efficiency, we assume that
 685         // interceptors will not modify the contents of the result Any.
 686         // Otherwise, we would need to create a deep copy of the Any.
 687 
 688         return cachedResult;
 689     }
 690 
 691     /**
 692      * See RequestInfoImpl for javadoc.
 693      */
 694     public boolean response_expected (){
 695         // access is currently valid for all states:
 696         //checkAccess( MID_RESPONSE_EXPECTED );
 697         return ! messageMediator.isOneWay();
 698     }
 699 
 700     /**
 701      * See RequestInfoImpl for javadoc.
 702      */
 703     public Object forward_reference (){
 704         checkAccess( MID_FORWARD_REFERENCE );
 705         // Check to make sure we are in LOCATION_FORWARD
 706         // state as per ptc/00-08-06, table 21-1
 707         // footnote 2.
 708         if( replyStatus != LOCATION_FORWARD.value ) {
 709             throw stdWrapper.invalidPiCall1() ;
 710         }
 711 
 712         // Do not cache this value since if an interceptor raises
 713         // forward request then the next interceptor in the
 714         // list should see the new value.
 715         IOR ior = getLocatedIOR();
 716         return iorToObject(ior);
 717     }
 718 
 719     private IOR getLocatedIOR()
 720     {
 721         IOR ior;
 722         CorbaContactInfoList contactInfoList = (CorbaContactInfoList)
 723             messageMediator.getContactInfo().getContactInfoList();
 724         ior = contactInfoList.getEffectiveTargetIOR();
 725         return ior;
 726     }
 727 
 728     protected void setLocatedIOR(IOR ior)
 729     {
 730         ORB orb = (ORB) messageMediator.getBroker();
 731 
 732         CorbaContactInfoListIterator iterator = (CorbaContactInfoListIterator)
 733             ((CorbaInvocationInfo)orb.getInvocationInfo())
 734             .getContactInfoListIterator();
 735 
 736         // REVISIT - this most likely causes reportRedirect to happen twice.
 737         // Once here and once inside the request dispatcher.
 738         iterator.reportRedirect(
 739             (CorbaContactInfo)messageMediator.getContactInfo(),
 740             ior);
 741     }
 742 
 743     /**
 744      * See RequestInfoImpl for javadoc.
 745      */
 746     public org.omg.IOP.ServiceContext get_request_service_context( int id ) {
 747         checkAccess( MID_GET_REQUEST_SERVICE_CONTEXT );
 748 
 749         if( cachedRequestServiceContexts == null ) {
 750             cachedRequestServiceContexts = new HashMap();
 751         }
 752 
 753         return  getServiceContext(cachedRequestServiceContexts,
 754                                   messageMediator.getRequestServiceContexts(),
 755                                   id);
 756     }
 757 
 758     /**
 759      * does not contain an etry for that ID, BAD_PARAM with a minor code of
 760      * TBD_BP is raised.
 761      */
 762     public org.omg.IOP.ServiceContext get_reply_service_context( int id ) {
 763         checkAccess( MID_GET_REPLY_SERVICE_CONTEXT );
 764 
 765         if( cachedReplyServiceContexts == null ) {
 766             cachedReplyServiceContexts = new HashMap();
 767         }
 768 
 769         // In the event this is called from a oneway, we will have no
 770         // response object.
 771         //
 772         // In the event this is called after a IIOPConnection.purgeCalls,
 773         // we will have a response object, but that object will
 774         // not contain a header (which would hold the service context
 775         // container).  See bug 4624102.
 776         //
 777         // REVISIT: this is the only thing used
 778         // from response at this time.  However, a more general solution
 779         // would avoid accessing other parts of response's header.
 780         //
 781         // Instead of throwing a NullPointer, we will
 782         // "gracefully" handle these with a BAD_PARAM with minor code 25.
 783 
 784         try {
 785             ServiceContexts serviceContexts =
 786                 messageMediator.getReplyServiceContexts();
 787             if (serviceContexts == null) {
 788                 throw new NullPointerException();
 789             }
 790             return getServiceContext(cachedReplyServiceContexts,
 791                                      serviceContexts, id);
 792         } catch (NullPointerException e) {
 793             // REVISIT how this is programmed - not what it does.
 794             // See purge calls test.  The waiter is woken up by the
 795             // call to purge calls - but there is no reply containing
 796             // service contexts.
 797             throw stdWrapper.invalidServiceContextId( e ) ;
 798         }
 799     }
 800 
 801     //
 802     // REVISIT
 803     // Override RequestInfoImpl connection to work in framework.
 804     //
 805 
 806     public com.sun.corba.se.spi.legacy.connection.Connection connection()
 807     {
 808         return (com.sun.corba.se.spi.legacy.connection.Connection)
 809             messageMediator.getConnection();
 810     }
 811 
 812 
 813 
 814     /*
 815      **********************************************************************
 816      * Package-scope interfaces
 817      **********************************************************************/
 818 
 819     protected void setInfo(MessageMediator messageMediator)
 820     {
 821         this.messageMediator = (CorbaMessageMediator)messageMediator;
 822         // REVISIT - so mediator can handle DII in subcontract.
 823         this.messageMediator.setDIIInfo(request);
 824     }
 825 
 826     /**
 827      * Set or reset the retry request flag.
 828      */
 829     void setRetryRequest( RetryType retryRequest ) {
 830         this.retryRequest = retryRequest;
 831     }
 832 
 833     /**
 834      * Retrieve the current retry request status.
 835      */
 836     RetryType getRetryRequest() {
 837         // 6763340
 838         return this.retryRequest;
 839     }
 840 
 841     /**
 842      * Increases the entry count by 1.
 843      */
 844     void incrementEntryCount() {
 845         this.entryCount++;
 846     }
 847 
 848     /**
 849      * Decreases the entry count by 1.
 850      */
 851     void decrementEntryCount() {
 852         this.entryCount--;
 853     }
 854 
 855     /**
 856      * Retrieve the current entry count
 857      */
 858     int getEntryCount() {
 859         return this.entryCount;
 860     }
 861 
 862     /**
 863      * Overridden from RequestInfoImpl.  Calls the super class, then
 864      * sets the ending point call depending on the reply status.
 865      */
 866     protected void setReplyStatus( short replyStatus ) {
 867         super.setReplyStatus( replyStatus );
 868         switch( replyStatus ) {
 869         case SUCCESSFUL.value:
 870             endingPointCall = CALL_RECEIVE_REPLY;
 871             break;
 872         case SYSTEM_EXCEPTION.value:
 873         case USER_EXCEPTION.value:
 874             endingPointCall = CALL_RECEIVE_EXCEPTION;
 875             break;
 876         case LOCATION_FORWARD.value:
 877         case TRANSPORT_RETRY.value:
 878             endingPointCall = CALL_RECEIVE_OTHER;
 879             break;
 880         }
 881     }
 882 
 883     /**
 884      * Sets DII request object in the RequestInfoObject.
 885      */
 886     protected void setDIIRequest(org.omg.CORBA.Request req) {
 887          request = req;
 888     }
 889 
 890     /**
 891      * Keeps track of whether initiate was called for a DII request.  The ORB
 892      * needs to know this so it knows whether to ignore a second call to
 893      * initiateClientPIRequest or not.
 894      */
 895     protected void setDIIInitiate( boolean diiInitiate ) {
 896         this.diiInitiate = diiInitiate;
 897     }
 898 
 899     /**
 900      * See comment for setDIIInitiate
 901      */
 902     protected boolean isDIIInitiate() {
 903         return this.diiInitiate;
 904     }
 905 
 906     /**
 907      * The PICurrent stack should only be popped if it was pushed.
 908      * This is generally the case.  But exceptions which occur
 909      * after the stub's entry to _request but before the push
 910      * end up in _releaseReply which will try to pop unless told not to.
 911      */
 912     protected void setPICurrentPushed( boolean piCurrentPushed ) {
 913         this.piCurrentPushed = piCurrentPushed;
 914     }
 915 
 916     protected boolean isPICurrentPushed() {
 917         return this.piCurrentPushed;
 918     }
 919 
 920     /**
 921      * Overridden from RequestInfoImpl.
 922      */
 923     protected void setException( Exception exception ) {
 924         super.setException( exception );
 925 
 926         // Clear cached values:
 927         cachedReceivedException = null;
 928         cachedReceivedExceptionId = null;
 929     }
 930 
 931     protected boolean getIsOneWay() {
 932         return ! response_expected();
 933     }
 934 
 935     /**
 936      * See description for RequestInfoImpl.checkAccess
 937      */
 938     protected void checkAccess( int methodID )
 939         throws BAD_INV_ORDER
 940     {
 941         // Make sure currentPoint matches the appropriate index in the
 942         // validCall table:
 943         int validCallIndex = 0;
 944         switch( currentExecutionPoint ) {
 945         case EXECUTION_POINT_STARTING:
 946             switch( startingPointCall ) {
 947             case CALL_SEND_REQUEST:
 948                 validCallIndex = 0;
 949                 break;
 950             case CALL_SEND_POLL:
 951                 validCallIndex = 1;
 952                 break;
 953             }
 954             break;
 955         case EXECUTION_POINT_ENDING:
 956             switch( endingPointCall ) {
 957             case CALL_RECEIVE_REPLY:
 958                 validCallIndex = 2;
 959                 break;
 960             case CALL_RECEIVE_EXCEPTION:
 961                 validCallIndex = 3;
 962                 break;
 963             case CALL_RECEIVE_OTHER:
 964                 validCallIndex = 4;
 965                 break;
 966             }
 967             break;
 968         }
 969 
 970         // Check the validCall table:
 971         if( !validCall[methodID][validCallIndex] ) {
 972             throw stdWrapper.invalidPiCall2() ;
 973         }
 974     }
 975 
 976 }
 977 
 978 // End of file.