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 package com.sun.corba.se.impl.interceptors;
  26 
  27 import org.omg.CORBA.Any;
  28 import org.omg.CORBA.BAD_INV_ORDER;
  29 import org.omg.CORBA.CompletionStatus;
  30 import org.omg.CORBA.INTERNAL;
  31 import org.omg.CORBA.LocalObject;
  32 import org.omg.CORBA.NO_IMPLEMENT;
  33 import org.omg.CORBA.NO_RESOURCES;
  34 import org.omg.CORBA.NVList;
  35 import org.omg.CORBA.Object;
  36 import org.omg.CORBA.Policy;
  37 import org.omg.CORBA.TypeCode;
  38 
  39 import org.omg.PortableServer.Servant;
  40 
  41 import org.omg.IOP.TaggedProfile;
  42 import org.omg.IOP.ServiceContext;
  43 
  44 import org.omg.Dynamic.Parameter;
  45 
  46 import org.omg.PortableInterceptor.InvalidSlot;
  47 import org.omg.PortableInterceptor.ServerRequestInfo;
  48 import org.omg.PortableInterceptor.LOCATION_FORWARD;
  49 import org.omg.PortableInterceptor.SUCCESSFUL;
  50 import org.omg.PortableInterceptor.SYSTEM_EXCEPTION;
  51 import org.omg.PortableInterceptor.TRANSPORT_RETRY;
  52 import org.omg.PortableInterceptor.USER_EXCEPTION;
  53 
  54 import com.sun.corba.se.spi.oa.ObjectAdapter;
  55 import com.sun.corba.se.spi.presentation.rmi.StubAdapter;
  56 
  57 import com.sun.corba.se.impl.protocol.giopmsgheaders.ReplyMessage;
  58 
  59 import com.sun.corba.se.spi.servicecontext.ServiceContexts;
  60 import com.sun.corba.se.spi.orb.ORB;
  61 
  62 import com.sun.corba.se.spi.ior.ObjectKeyTemplate;
  63 import com.sun.corba.se.spi.ior.ObjectAdapterId ;
  64 
  65 import com.sun.corba.se.spi.protocol.CorbaMessageMediator;
  66 
  67 import java.util.*;
  68 
  69 /**
  70  * Implementation of the ServerRequestInfo interface as specified in
  71  * orbos/99-12-02 section 5.4.3.
  72  */
  73 public final class ServerRequestInfoImpl
  74     extends RequestInfoImpl
  75     implements ServerRequestInfo
  76 {
  77     // The available constants for startingPointCall
  78     static final int CALL_RECEIVE_REQUEST_SERVICE_CONTEXT = 0;
  79 
  80     // The available constants for intermediatePointCall.  The default (0)
  81     // is receive_request, but can be set to none on demand.
  82     static final int CALL_RECEIVE_REQUEST = 0;
  83     static final int CALL_INTERMEDIATE_NONE = 1;
  84 
  85     // The available constants for endingPointCall
  86     static final int CALL_SEND_REPLY = 0;
  87     static final int CALL_SEND_EXCEPTION = 1;
  88     static final int CALL_SEND_OTHER = 2;
  89 
  90     //////////////////////////////////////////////////////////////////////
  91     //
  92     // NOTE: IF AN ATTRIBUTE IS ADDED, PLEASE UPDATE RESET();
  93     //
  94     //////////////////////////////////////////////////////////////////////
  95 
  96     // Set to true if the server ending point raised ForwardRequest at some
  97     // point in the ending point.
  98     private boolean forwardRequestRaisedInEnding;
  99 
 100     // Sources of server request information:
 101     private CorbaMessageMediator request;
 102     private java.lang.Object servant;
 103     private byte[] objectId;
 104     private ObjectKeyTemplate oktemp ;
 105 
 106     // Information cached from calls to oktemp
 107     private byte[] adapterId;
 108     private String[] adapterName;
 109 
 110     private ArrayList addReplyServiceContextQueue;
 111     private ReplyMessage replyMessage;
 112     private String targetMostDerivedInterface;
 113     private NVList dsiArguments;
 114     private Any dsiResult;
 115     private Any dsiException;
 116     private boolean isDynamic;
 117     private ObjectAdapter objectAdapter;
 118     private int serverRequestId;
 119 
 120     // Cached information:
 121     private Parameter[] cachedArguments;
 122     private Any cachedSendingException;
 123     // key = Integer, value = IOP.ServiceContext.
 124     private HashMap cachedRequestServiceContexts;
 125     // key = Integer, value = IOP.ServiceContext.
 126     private HashMap cachedReplyServiceContexts;
 127 
 128     //////////////////////////////////////////////////////////////////////
 129     //
 130     // NOTE: IF AN ATTRIBUTE IS ADDED, PLEASE UPDATE RESET();
 131     //
 132     //////////////////////////////////////////////////////////////////////
 133 
 134 
 135     /**
 136      * Reset the info object so that it can be reused for a retry,
 137      * for example.
 138      */
 139     void reset() {
 140         super.reset();
 141 
 142         // Please keep these in the same order as declared above.
 143 
 144         forwardRequestRaisedInEnding = false;
 145 
 146         request = null;
 147         servant = null;
 148         objectId = null;
 149         oktemp = null;
 150 
 151         adapterId = null;
 152         adapterName = null;
 153 
 154         addReplyServiceContextQueue = null;
 155         replyMessage = null;
 156         targetMostDerivedInterface = null;
 157         dsiArguments = null;
 158         dsiResult = null;
 159         dsiException = null;
 160         isDynamic = false;
 161         objectAdapter = null;
 162         serverRequestId = myORB.getPIHandler().allocateServerRequestId();
 163 
 164         // reset cached attributes:
 165         cachedArguments = null;
 166         cachedSendingException = null;
 167         cachedRequestServiceContexts = null;
 168         cachedReplyServiceContexts = null;
 169 
 170         startingPointCall = CALL_RECEIVE_REQUEST_SERVICE_CONTEXT;
 171         intermediatePointCall = CALL_RECEIVE_REQUEST;
 172         endingPointCall = CALL_SEND_REPLY;
 173     }
 174 
 175     /*
 176      **********************************************************************
 177      * Access protection
 178      **********************************************************************/
 179 
 180     // Method IDs for all methods in ServerRequestInfo.  This allows for a
 181     // convenient O(1) lookup for checkAccess().
 182     protected static final int MID_SENDING_EXCEPTION       = MID_RI_LAST +  1;
 183     protected static final int MID_OBJECT_ID               = MID_RI_LAST +  2;
 184     protected static final int MID_ADAPTER_ID              = MID_RI_LAST +  3;
 185     protected static final int MID_TARGET_MOST_DERIVED_INTERFACE
 186                                                            = MID_RI_LAST +  4;
 187     protected static final int MID_GET_SERVER_POLICY       = MID_RI_LAST +  5;
 188     protected static final int MID_SET_SLOT                = MID_RI_LAST +  6;
 189     protected static final int MID_TARGET_IS_A             = MID_RI_LAST +  7;
 190     protected static final int MID_ADD_REPLY_SERVICE_CONTEXT
 191                                                            = MID_RI_LAST +  8;
 192     protected static final int MID_SERVER_ID               = MID_RI_LAST +  9;
 193     protected static final int MID_ORB_ID                  = MID_RI_LAST +  10;
 194     protected static final int MID_ADAPTER_NAME            = MID_RI_LAST +  11;
 195 
 196     // ServerRequestInfo validity table (see ptc/00-08-06 table 21-2).
 197     // Note: These must be in the same order as specified in contants.
 198     private static final boolean validCall[][] = {
 199         // LEGEND:
 200         // r_rsc = receive_request_service_contexts
 201         // r_req = receive_request
 202         // s_rep = send_reply
 203         // s_exc = send_exception
 204         // s_oth = send_other
 205         //
 206         // A true value indicates call is valid at specified point.
 207         // A false value indicates the call is invalid.
 208         //
 209         // NOTE: If the order or number of columns change, update
 210         // checkAccess() accordingly.
 211         //
 212         //                              { r_rsc, r_req, s_rep, s_exc, s_oth }
 213         // RequestInfo methods:
 214         /*request_id*/                  { true , true , true , true , true  },
 215         /*operation*/                   { true , true , true , true , true  },
 216         /*arguments*/                   { false, true , true , false, false },
 217         /*exceptions*/                  { false, true , true , true , true  },
 218         /*contexts*/                    { false, true , true , true , true  },
 219         /*operation_context*/           { false, true , true , false, false },
 220         /*result*/                      { false, false, true , false, false },
 221         /*response_expected*/           { true , true , true , true , true  },
 222         /*sync_scope*/                  { true , true , true , true , true  },
 223         /*reply_status*/                { false, false, true , true , true  },
 224         /*forward_reference*/           { false, false, false, false, true  },
 225         /*get_slot*/                    { true , true , true , true , true  },
 226         /*get_request_service_context*/ { true , true , true , true , true  },
 227         /*get_reply_service_context*/   { false, false, true , true , true  },
 228         //
 229         // ServerRequestInfo methods::
 230         /*sending_exception*/           { false, false, false, true , false },
 231         /*object_id*/                   { false, true , true , true , true  },
 232         /*adapter_id*/                  { false, true , true , true , true  },
 233         /*target_most_derived_inte...*/ { false, true , false, false, false },
 234         /*get_server_policy*/           { true , true , true , true , true  },
 235         /*set_slot*/                    { true , true , true , true , true  },
 236         /*target_is_a*/                 { false, true , false, false, false },
 237         /*add_reply_service_context*/   { true , true , true , true , true  },
 238         /*orb_id*/                      { false, true , true , true , true  },
 239         /*server_id*/                   { false, true , true , true , true  },
 240         /*adapter_name*/                { false, true , true , true , true  }
 241     };
 242 
 243     /*
 244      **********************************************************************
 245      * Public interfaces
 246      **********************************************************************/
 247 
 248     /**
 249      * Creates a new ServerRequestInfo implementation.
 250      * The constructor is package scope since no other package need create
 251      * an instance of this class.
 252      */
 253     ServerRequestInfoImpl( ORB myORB ) {
 254         super( myORB );
 255         startingPointCall = CALL_RECEIVE_REQUEST_SERVICE_CONTEXT;
 256         intermediatePointCall = CALL_RECEIVE_REQUEST;
 257         endingPointCall = CALL_SEND_REPLY;
 258         serverRequestId = myORB.getPIHandler().allocateServerRequestId();
 259     }
 260 
 261     /**
 262      * Any containing the exception to be returned to the client.
 263      */
 264     public Any sending_exception () {
 265         checkAccess( MID_SENDING_EXCEPTION );
 266 
 267         if( cachedSendingException == null ) {
 268             Any result = null ;
 269 
 270             if( dsiException != null ) {
 271                 result = dsiException;
 272             } else if( exception != null ) {
 273                 result = exceptionToAny( exception );
 274             } else {
 275                 // sending_exception should not be callable if both dsiException
 276                 // and exception are null.
 277                 throw wrapper.exceptionUnavailable() ;
 278             }
 279 
 280             cachedSendingException = result;
 281         }
 282 
 283         return cachedSendingException;
 284     }
 285 
 286     /**
 287      * The opaque object_id describing the target of the operation invocation.
 288      */
 289     public byte[] object_id () {
 290         checkAccess( MID_OBJECT_ID );
 291 
 292         if( objectId == null ) {
 293             // For some reason, we never set object id.  This could be
 294             // because a servant locator caused a location forward or
 295             // raised an exception.  As per ptc/00-08-06, section 21.3.14,
 296             // we throw NO_RESOURCES
 297             throw stdWrapper.piOperationNotSupported6() ;
 298         }
 299 
 300         // Good citizen: In the interest of efficiency, we will assume
 301         // interceptors will not change the resulting byte[] array.
 302         // Otherwise, we would need to make a clone of this array.
 303 
 304         return objectId;
 305     }
 306 
 307     private void checkForNullTemplate()
 308     {
 309         if (oktemp == null) {
 310             // For some reason, we never set the ObjectKeyTemplate
 311             // because a servant locator caused a location forward or
 312             // raised an exception.  As per ptc/00-08-06, section 21.3.14,
 313             // we throw NO_RESOURCES
 314             throw stdWrapper.piOperationNotSupported7() ;
 315         }
 316     }
 317 
 318     public String server_id()
 319     {
 320         checkAccess( MID_SERVER_ID ) ;
 321         checkForNullTemplate() ;
 322 
 323         // Good citizen: In the interest of efficiency, we will assume
 324         // interceptors will not change the resulting byte[] array.
 325         // Otherwise, we would need to make a clone of this array.
 326 
 327         return Integer.toString( oktemp.getServerId() ) ;
 328     }
 329 
 330     public String orb_id()
 331     {
 332         checkAccess( MID_ORB_ID ) ;
 333 
 334         return myORB.getORBData().getORBId() ;
 335     }
 336 
 337     synchronized public String[] adapter_name()
 338     {
 339         checkAccess( MID_ADAPTER_NAME ) ;
 340 
 341         if (adapterName == null) {
 342             checkForNullTemplate() ;
 343 
 344             ObjectAdapterId oaid = oktemp.getObjectAdapterId() ;
 345             adapterName = oaid.getAdapterName() ;
 346         }
 347 
 348         return adapterName ;
 349     }
 350 
 351     /**
 352      * The opaque identifier for the object adapter.
 353      */
 354     synchronized public byte[] adapter_id ()
 355     {
 356         checkAccess( MID_ADAPTER_ID );
 357 
 358         if( adapterId == null ) {
 359             checkForNullTemplate() ;
 360             adapterId = oktemp.getAdapterId() ;
 361         }
 362 
 363         return adapterId;
 364     }
 365 
 366     /**
 367      * The RepositoryID for the most derived interface of the servant.
 368      */
 369     public String target_most_derived_interface () {
 370         checkAccess( MID_TARGET_MOST_DERIVED_INTERFACE );
 371         return targetMostDerivedInterface;
 372     }
 373 
 374     /**
 375      * Returns the policy in effect for this operation for the given policy
 376      * type.
 377      */
 378     public Policy get_server_policy (int type) {
 379         // access is currently valid for all states:
 380         //checkAccess( MID_GET_SERVER_POLICY );
 381 
 382         Policy result = null;
 383 
 384         if( objectAdapter != null ) {
 385             result = objectAdapter.getEffectivePolicy( type );
 386         }
 387 
 388         // _REVISIT_ RTF Issue: get_server_policy spec not in sync with
 389         // get_effective_policy spec.
 390 
 391         return result;
 392     }
 393 
 394     /**
 395      * Allows an Interceptor to set a slot in the Current that is in the scope
 396      * of the request.  If data already exists in that slot, it will be
 397      * overwritten.  If the ID does not define an allocated slot, InvalidSlot
 398      * is raised.
 399      */
 400     public void set_slot (int id, Any data) throws InvalidSlot {
 401         // access is currently valid for all states:
 402         //checkAccess( MID_SET_SLOT );
 403 
 404         slotTable.set_slot( id, data );
 405     }
 406 
 407     /**
 408      * Returns true if the servant is the given RepositoryId, false if it is
 409      * not.
 410      */
 411     public boolean target_is_a (String id) {
 412         checkAccess( MID_TARGET_IS_A );
 413 
 414         boolean result = false ;
 415         if( servant instanceof Servant ) {
 416             result = ((Servant)servant)._is_a( id );
 417         } else if (StubAdapter.isStub( servant )) {
 418             result = ((org.omg.CORBA.Object)servant)._is_a( id );
 419         } else {
 420             throw wrapper.servantInvalid() ;
 421         }
 422 
 423         return result;
 424     }
 425 
 426     /**
 427      * Allows Interceptors to add service contexts to the request.
 428      */
 429     public void add_reply_service_context ( ServiceContext service_context,
 430                                             boolean replace )
 431     {
 432         // access is currently valid for all states:
 433         //checkAccess( MID_ADD_REPLY_SERVICE_CONTEXT );
 434 
 435         if( currentExecutionPoint == EXECUTION_POINT_ENDING ) {
 436             ServiceContexts scs = replyMessage.getServiceContexts();
 437 
 438             // May be null.  If this is null, create a new one in its place.
 439             if( scs == null ) {
 440                 scs = new ServiceContexts( myORB );
 441                 replyMessage.setServiceContexts( scs );
 442             }
 443 
 444             if( cachedReplyServiceContexts == null ) {
 445                 cachedReplyServiceContexts = new HashMap();
 446             }
 447 
 448             // This is during and ending point, so we now have enough
 449             // information to add the reply service context.
 450             addServiceContext( cachedReplyServiceContexts, scs,
 451                                service_context, replace );
 452         }
 453 
 454         // We enqueue all adds for the following reasons:
 455         //
 456         // If we are not in the ending point then we do not yet have a
 457         // pointer to the ServiceContexts object so we cannot access the
 458         // service contexts until we get to the ending point.
 459         // So we enqueue this add reply service context request.
 460         // It is added when we do have a handle on the service contexts object.
 461         //
 462         // If we are in the ending point and we just add directly to the
 463         // SC container but then an interceptor raises a SystemException
 464         // then that add will be lost since a new container is created
 465         // for the SystemException response.
 466         //
 467         // Therefore we always enqueue and never dequeue (per request) so
 468         // that all adds will be completed.
 469 
 470         AddReplyServiceContextCommand addReply =
 471             new AddReplyServiceContextCommand();
 472         addReply.service_context = service_context;
 473         addReply.replace = replace;
 474 
 475         if( addReplyServiceContextQueue == null ) {
 476             addReplyServiceContextQueue = new ArrayList();
 477         }
 478 
 479         // REVISIT: this does not add to the cache.
 480         enqueue( addReply );
 481     }
 482 
 483     // NOTE: When adding a method, be sure to:
 484     // 1. Add a MID_* constant for that method
 485     // 2. Call checkAccess at the start of the method
 486     // 3. Define entries in the validCall[][] table for interception points.
 487 
 488     /*
 489      **********************************************************************
 490      * Public RequestInfo interfaces
 491      *
 492      * These are implemented here because they have differing
 493      * implementations depending on whether this is a client or a server
 494      * request info object.
 495      **********************************************************************/
 496 
 497     /**
 498      * See ServerRequestInfo for javadocs.
 499      */
 500     public int request_id (){
 501         // access is currently valid for all states:
 502         //checkAccess( MID_REQUEST_ID );
 503         /*
 504          * NOTE: The request id in server interceptors is NOT the
 505          * same as the GIOP request id.  The ORB may be servicing several
 506          * connections, each with possibly overlapping sets of request ids.
 507          * Therefore we create a request id specific to interceptors.
 508          */
 509         return serverRequestId;
 510     }
 511 
 512     /**
 513      * See ServerRequestInfo for javadocs.
 514      */
 515     public String operation (){
 516         // access is currently valid for all states:
 517         //checkAccess( MID_OPERATION );
 518         return request.getOperationName();
 519     }
 520 
 521     /**
 522      * See ServerRequestInfo for javadocs.
 523      */
 524     public Parameter[] arguments (){
 525         checkAccess( MID_ARGUMENTS );
 526 
 527         if( cachedArguments == null ) {
 528             if( !isDynamic ) {
 529                 throw stdWrapper.piOperationNotSupported1() ;
 530             }
 531 
 532             if( dsiArguments == null ) {
 533                 throw stdWrapper.piOperationNotSupported8() ;
 534             }
 535 
 536             // If it is a DSI request then get the arguments from the DSI req
 537             // and convert that into parameters.
 538             cachedArguments = nvListToParameterArray( dsiArguments );
 539         }
 540 
 541         // Good citizen: In the interest of efficiency, we assume
 542         // interceptors will be "good citizens" in that they will not
 543         // modify the contents of the Parameter[] array.  We also assume
 544         // they will not change the values of the containing Anys.
 545 
 546         return cachedArguments;
 547     }
 548 
 549     /**
 550      * See ServerRequestInfo for javadocs.
 551      */
 552     public TypeCode[] exceptions (){
 553         checkAccess( MID_EXCEPTIONS );
 554 
 555         // _REVISIT_ PI RTF Issue: No exception list on server side.
 556 
 557         throw stdWrapper.piOperationNotSupported2() ;
 558     }
 559 
 560     /**
 561      * See ServerRequestInfo for javadocs.
 562      */
 563     public String[] contexts (){
 564         checkAccess( MID_CONTEXTS );
 565 
 566         // We do not support this because our ORB does not send contexts.
 567 
 568         throw stdWrapper.piOperationNotSupported3() ;
 569     }
 570 
 571     /**
 572      * See ServerRequestInfo for javadocs.
 573      */
 574     public String[] operation_context (){
 575         checkAccess( MID_OPERATION_CONTEXT );
 576 
 577         // We do not support this because our ORB does not send
 578         // operation_context.
 579 
 580         throw stdWrapper.piOperationNotSupported4() ;
 581     }
 582 
 583     /**
 584      * See ServerRequestInfo for javadocs.
 585      */
 586     public Any result (){
 587         checkAccess( MID_RESULT );
 588 
 589         if( !isDynamic ) {
 590             throw stdWrapper.piOperationNotSupported5() ;
 591         }
 592 
 593         if( dsiResult == null ) {
 594             throw wrapper.piDsiResultIsNull() ;
 595         }
 596 
 597         // Good citizen: In the interest of efficiency, we assume that
 598         // interceptors will not modify the contents of the result Any.
 599         // Otherwise, we would need to create a deep copy of the Any.
 600 
 601         return dsiResult;
 602     }
 603 
 604     /**
 605      * See ServerRequestInfo for javadocs.
 606      */
 607     public boolean response_expected (){
 608         // access is currently valid for all states:
 609         //checkAccess( MID_RESPONSE_EXPECTED );
 610         return !request.isOneWay();
 611     }
 612 
 613     /**
 614      * See ServerRequestInfo for javadocs.
 615      */
 616     public Object forward_reference (){
 617         checkAccess( MID_FORWARD_REFERENCE );
 618         // Check to make sure we are in LOCATION_FORWARD
 619         // state as per ptc/00-08-06, table 21-2
 620         // footnote 2.
 621         if( replyStatus != LOCATION_FORWARD.value ) {
 622             throw stdWrapper.invalidPiCall1() ;
 623         }
 624 
 625         return getForwardRequestException().forward;
 626     }
 627 
 628     /**
 629      * See ServerRequestInfo for javadocs.
 630      */
 631     public org.omg.IOP.ServiceContext get_request_service_context( int id ) {
 632         checkAccess( MID_GET_REQUEST_SERVICE_CONTEXT );
 633 
 634         if( cachedRequestServiceContexts == null ) {
 635             cachedRequestServiceContexts = new HashMap();
 636         }
 637 
 638         return getServiceContext( cachedRequestServiceContexts,
 639                                   request.getRequestServiceContexts(), id );
 640     }
 641 
 642     /**
 643      * See ServerRequestInfo for javadocs.
 644      */
 645     public org.omg.IOP.ServiceContext get_reply_service_context( int id ) {
 646         checkAccess( MID_GET_REPLY_SERVICE_CONTEXT );
 647 
 648         if( cachedReplyServiceContexts == null ) {
 649             cachedReplyServiceContexts = new HashMap();
 650         }
 651 
 652         return getServiceContext( cachedReplyServiceContexts,
 653                                   replyMessage.getServiceContexts(), id );
 654     }
 655 
 656     /*
 657      **********************************************************************
 658      * Private-scope classes and methods
 659      **********************************************************************/
 660 
 661     // A command encapsulating a request to add a reply service context.
 662     // These commands are enqueued until we have a handle on the actual
 663     // reply service context, at which point they are executed.
 664     private class AddReplyServiceContextCommand {
 665         ServiceContext service_context;
 666         boolean replace;
 667     }
 668 
 669     // Adds the given add reply service context command to the queue of
 670     // such commands.  If a command is detected to have the same id as
 671     // the service context in this command, and replace is false,
 672     // BAD_INV_ORDER is thrown.  If replace is true, the original command
 673     // in the queue is replaced by this command.
 674     private void enqueue( AddReplyServiceContextCommand addReply ) {
 675         int size = addReplyServiceContextQueue.size();
 676         boolean found = false;
 677 
 678         for( int i = 0; i < size; i++ ) {
 679             AddReplyServiceContextCommand cmd =
 680                 (AddReplyServiceContextCommand)
 681                 addReplyServiceContextQueue.get( i );
 682 
 683             if( cmd.service_context.context_id ==
 684                 addReply.service_context.context_id )
 685             {
 686                 found = true;
 687                 if( addReply.replace ) {
 688                     addReplyServiceContextQueue.set( i, addReply );
 689                 } else {
 690                     throw stdWrapper.serviceContextAddFailed(
 691                         new Integer( cmd.service_context.context_id ) ) ;
 692                 }
 693                 break;
 694             }
 695         }
 696 
 697         if( !found ) {
 698             addReplyServiceContextQueue.add( addReply );
 699         }
 700     }
 701 
 702     /*
 703      **********************************************************************
 704      * Package and protected-scope methods
 705      **********************************************************************/
 706 
 707     /**
 708      * Overridden from RequestInfoImpl.  This version calls the super
 709      * and then, if we are changing to ending points, executes all
 710      * enqueued AddReplyServiceContextCommands.
 711      */
 712     protected void setCurrentExecutionPoint( int executionPoint ) {
 713         super.setCurrentExecutionPoint( executionPoint );
 714 
 715         // If we are transitioning to ending point, we will now have a pointer
 716         // to the reply service contexts, so we can execute all queued
 717         // add reply service context requests.
 718         if( (executionPoint == EXECUTION_POINT_ENDING) &&
 719             (addReplyServiceContextQueue != null) )
 720         {
 721             int size = addReplyServiceContextQueue.size();
 722             for( int i = 0; i < size; i++ ) {
 723                 AddReplyServiceContextCommand addReply =
 724                     (AddReplyServiceContextCommand)
 725                     addReplyServiceContextQueue.get( i );
 726                 try {
 727                     add_reply_service_context( addReply.service_context,
 728                                                addReply.replace );
 729                 }
 730                 catch( BAD_INV_ORDER e ) {
 731                     // _REVISIT_  The only way this can happen is if during
 732                     // rrsc or rr, the interceptor tried to add with
 733                     // replace=false to a service context that is present in
 734                     // the reply message.  At that time there was no way for
 735                     // us to check for this, so the best we can do is ignore
 736                     // the original request.
 737                 }
 738             }
 739 
 740             // We specifically do not empty the SC queue so that if
 741             // the interceptor raises an exception the queued service contexts
 742             // will be put in the exception response.
 743         }
 744     }
 745 
 746     /**
 747      * Stores the various sources of information used for this info object.
 748      */
 749     protected void setInfo( CorbaMessageMediator request, ObjectAdapter oa,
 750         byte[] objectId, ObjectKeyTemplate oktemp )
 751     {
 752         this.request = request;
 753         this.objectId = objectId;
 754         this.oktemp = oktemp;
 755         this.objectAdapter = oa ;
 756         this.connection = (com.sun.corba.se.spi.legacy.connection.Connection)
 757             request.getConnection();
 758     }
 759 
 760     /**
 761      * Stores the various sources of information used for this info object.
 762      */
 763     protected void setDSIArguments( NVList arguments ) {
 764         this.dsiArguments = arguments;
 765     }
 766 
 767     /**
 768      * Stores the various sources of information used for this info object.
 769      */
 770     protected void setDSIException( Any exception ) {
 771         this.dsiException = exception;
 772 
 773         // Clear cached exception value:
 774         cachedSendingException = null;
 775     }
 776 
 777     /**
 778      * Stores the various sources of information used for this info object.
 779      */
 780     protected void setDSIResult( Any result ) {
 781         this.dsiResult = result;
 782     }
 783 
 784     /**
 785      * Sets the exception to be returned by received_exception and
 786      * received_exception_id.
 787      */
 788     protected void setException( Exception exception ) {
 789         super.setException( exception );
 790 
 791         // Make sure DSIException is null because this is the more recent one.
 792         this.dsiException = null;
 793 
 794         // Clear cached exception value:
 795         cachedSendingException = null;
 796     }
 797 
 798     /**
 799      * Stores the various sources of information used for this info object.
 800      */
 801     protected void setInfo( java.lang.Object servant,
 802                             String targetMostDerivedInterface )
 803     {
 804         this.servant = servant;
 805         this.targetMostDerivedInterface = targetMostDerivedInterface;
 806         this.isDynamic =
 807             (servant instanceof
 808             org.omg.PortableServer.DynamicImplementation) ||
 809             (servant instanceof org.omg.CORBA.DynamicImplementation);
 810     }
 811 
 812     /**
 813      * Set reply message
 814      */
 815     void setReplyMessage( ReplyMessage replyMessage ) {
 816         this.replyMessage = replyMessage;
 817     }
 818 
 819     /**
 820      * Overridden from RequestInfoImpl.  Calls the super class, then
 821      * sets the ending point call depending on the reply status.
 822      */
 823     protected void setReplyStatus( short replyStatus ) {
 824         super.setReplyStatus( replyStatus );
 825         switch( replyStatus ) {
 826         case SUCCESSFUL.value:
 827             endingPointCall = CALL_SEND_REPLY;
 828             break;
 829         case SYSTEM_EXCEPTION.value:
 830         case USER_EXCEPTION.value:
 831             endingPointCall = CALL_SEND_EXCEPTION;
 832             break;
 833         case LOCATION_FORWARD.value:
 834         case TRANSPORT_RETRY.value:
 835             endingPointCall = CALL_SEND_OTHER;
 836             break;
 837         }
 838     }
 839 
 840     /**
 841      * Release the servant object so the user has control over its lifetime.
 842      * Called after receive_request is finished executing.
 843      */
 844     void releaseServant() {
 845         this.servant = null;
 846     }
 847 
 848     /**
 849      * Sets the forwardRequestRaisedInEnding flag to true, indicating that
 850      * a server ending point has raised location forward at some point.
 851      */
 852     void setForwardRequestRaisedInEnding() {
 853         this.forwardRequestRaisedInEnding = true;
 854     }
 855 
 856     /**
 857      * Returns true if ForwardRequest was raised by a server ending point
 858      * or false otherwise.
 859      */
 860     boolean isForwardRequestRaisedInEnding() {
 861         return this.forwardRequestRaisedInEnding;
 862     }
 863 
 864     /**
 865      * Returns true if this is a dynamic invocation, or false if not
 866      */
 867     boolean isDynamic() {
 868       return this.isDynamic;
 869     }
 870 
 871     /**
 872      * See description for RequestInfoImpl.checkAccess
 873      */
 874     protected void checkAccess( int methodID )
 875     {
 876         // Make sure currentPoint matches the appropriate index in the
 877         // validCall table:
 878         int validCallIndex = 0;
 879         switch( currentExecutionPoint ) {
 880         case EXECUTION_POINT_STARTING:
 881             validCallIndex = 0;
 882             break;
 883         case EXECUTION_POINT_INTERMEDIATE:
 884             validCallIndex = 1;
 885             break;
 886         case EXECUTION_POINT_ENDING:
 887             switch( endingPointCall ) {
 888             case CALL_SEND_REPLY:
 889                 validCallIndex = 2;
 890                 break;
 891             case CALL_SEND_EXCEPTION:
 892                 validCallIndex = 3;
 893                 break;
 894             case CALL_SEND_OTHER:
 895                 validCallIndex = 4;
 896                 break;
 897             }
 898             break;
 899         }
 900 
 901         // Check the validCall table:
 902         if( !validCall[methodID][validCallIndex] ) {
 903             throw stdWrapper.invalidPiCall2() ;
 904         }
 905     }
 906 
 907 }