1 /*
   2  * Copyright (c) 2000, 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 package com.sun.corba.se.impl.interceptors;
  26 
  27 import java.io.IOException ;
  28 
  29 import java.lang.reflect.Method ;
  30 import java.lang.reflect.InvocationTargetException ;
  31 
  32 import java.util.HashMap ;
  33 
  34 import org.omg.PortableInterceptor.ForwardRequest;
  35 import org.omg.PortableInterceptor.InvalidSlot;
  36 import org.omg.PortableInterceptor.RequestInfo;
  37 import org.omg.PortableInterceptor.LOCATION_FORWARD;
  38 import org.omg.IOP.TaggedProfile;
  39 import org.omg.IOP.TaggedComponent;
  40 import org.omg.IOP.ServiceContextHelper;
  41 import org.omg.Messaging.SYNC_WITH_TRANSPORT;
  42 import org.omg.CORBA.ParameterMode;
  43 
  44 import org.omg.CORBA.Any;
  45 import org.omg.CORBA.BAD_INV_ORDER;
  46 import org.omg.CORBA.BAD_PARAM;
  47 import org.omg.CORBA.CompletionStatus;
  48 import org.omg.CORBA.Context;
  49 import org.omg.CORBA.ContextList;
  50 import org.omg.CORBA.CTX_RESTRICT_SCOPE;
  51 import org.omg.CORBA.ExceptionList;
  52 import org.omg.CORBA.INTERNAL;
  53 import org.omg.CORBA.LocalObject;
  54 import org.omg.CORBA.NamedValue;
  55 import org.omg.CORBA.NO_IMPLEMENT;
  56 import org.omg.CORBA.NO_RESOURCES;
  57 import org.omg.CORBA.NVList;
  58 import org.omg.CORBA.Object;
  59 import org.omg.CORBA.Policy;
  60 import org.omg.CORBA.SystemException;
  61 import org.omg.CORBA.TypeCode;
  62 import org.omg.CORBA.UNKNOWN;
  63 import org.omg.CORBA.UserException;
  64 import org.omg.CORBA.portable.ApplicationException;
  65 import org.omg.CORBA.portable.Delegate;
  66 import org.omg.CORBA.portable.InputStream;
  67 
  68 import org.omg.Dynamic.Parameter;
  69 
  70 import com.sun.corba.se.spi.legacy.connection.Connection;
  71 
  72 import com.sun.corba.se.spi.legacy.interceptor.RequestInfoExt;
  73 
  74 import com.sun.corba.se.spi.ior.IOR;
  75 
  76 import com.sun.corba.se.spi.ior.iiop.GIOPVersion;
  77 
  78 import com.sun.corba.se.spi.orb.ORB;
  79 
  80 import com.sun.corba.se.spi.logging.CORBALogDomains;
  81 
  82 import com.sun.corba.se.spi.servicecontext.ServiceContexts;
  83 import com.sun.corba.se.spi.servicecontext.UnknownServiceContext;
  84 
  85 import com.sun.corba.se.impl.encoding.CDRInputStream_1_0;
  86 import com.sun.corba.se.impl.encoding.EncapsOutputStream;
  87 
  88 import com.sun.corba.se.impl.orbutil.ORBUtility;
  89 import com.sun.corba.se.impl.orbutil.ORBClassLoader;
  90 
  91 import com.sun.corba.se.impl.util.RepositoryId;
  92 
  93 import com.sun.corba.se.impl.logging.InterceptorsSystemException;
  94 import com.sun.corba.se.impl.logging.OMGSystemException;
  95 
  96 /**
  97  * Implementation of the RequestInfo interface as specified in
  98  * orbos/99-12-02 section 5.4.1.
  99  */
 100 public abstract class RequestInfoImpl
 101     extends LocalObject
 102     implements RequestInfo, RequestInfoExt
 103 {
 104     //////////////////////////////////////////////////////////////////////
 105     //
 106     // NOTE: IF AN ATTRIBUTE IS ADDED, PLEASE UPDATE RESET();
 107     //
 108     //////////////////////////////////////////////////////////////////////
 109 
 110     // The ORB from which to get PICurrent and other info
 111     protected ORB myORB;
 112     protected InterceptorsSystemException wrapper ;
 113     protected OMGSystemException stdWrapper ;
 114 
 115     // The number of interceptors actually invoked for this client request.
 116     // See setFlowStackIndex for a detailed description.
 117     protected int flowStackIndex = 0;
 118 
 119     // The type of starting point call to make to the interceptors
 120     // See ClientRequestInfoImpl and ServerRequestInfoImpl for a list of
 121     // appropriate constants.
 122     protected int startingPointCall;
 123 
 124     // The type of intermediate point call to make to the interceptors
 125     // See ServerRequestInfoImpl for a list of appropriate constants.
 126     // This does not currently apply to client request interceptors but is
 127     // here in case intermediate points are introduced in the future.
 128     protected int intermediatePointCall;
 129 
 130     // The type of ending point call to make to the interceptors
 131     // See ClientRequestInfoImpl and ServerRequestInfoImpl for a list of
 132     // appropriate constants.
 133     protected int endingPointCall;
 134 
 135     // The reply status to return in reply_status.  This is initialized
 136     // to UNINITIALIZED so that we can tell if this has been set or not.
 137     protected short replyStatus = UNINITIALIZED;
 138 
 139     // Constant for an uninitizlied reply status.
 140     protected static final short UNINITIALIZED = -1;
 141 
 142     // Which points we are currently executing (so we can implement the
 143     // validity table).
 144     protected int currentExecutionPoint;
 145     protected static final int EXECUTION_POINT_STARTING = 0;
 146     protected static final int EXECUTION_POINT_INTERMEDIATE = 1;
 147     protected static final int EXECUTION_POINT_ENDING = 2;
 148 
 149     // Set to true if all interceptors have had all their points
 150     // executed.
 151     protected boolean alreadyExecuted;
 152 
 153     // Sources of request information
 154     protected Connection     connection;
 155     protected ServiceContexts serviceContexts;
 156 
 157     // The ForwardRequest object if this request is being forwarded.
 158     // Either the forwardRequest or the forwardRequestIOR field is set.
 159     // When set, the other field is set to null initially.  If the other
 160     // field is queried, it is lazily calculated and cached.  These
 161     // two attributes are always kept in sync.
 162     protected ForwardRequest forwardRequest;
 163     protected IOR forwardRequestIOR;
 164 
 165     // PICurrent's  SlotTable
 166     protected SlotTable slotTable;
 167 
 168     // The exception to be returned by received_exception and
 169     // received_exception_id
 170     protected Exception exception;
 171 
 172     //////////////////////////////////////////////////////////////////////
 173     //
 174     // NOTE: IF AN ATTRIBUTE IS ADDED, PLEASE UPDATE RESET();
 175     //
 176     //////////////////////////////////////////////////////////////////////
 177 
 178     /**
 179      * Reset the info object so that it can be reused for a retry,
 180      * for example.
 181      */
 182     void reset() {
 183 
 184         // Please keep these in the same order as declared above.
 185 
 186         flowStackIndex = 0;
 187         startingPointCall = 0;
 188         intermediatePointCall = 0;
 189         endingPointCall = 0;
 190         // 6763340
 191         setReplyStatus( UNINITIALIZED ) ;
 192         currentExecutionPoint = EXECUTION_POINT_STARTING;
 193         alreadyExecuted = false;
 194         connection = null;
 195         serviceContexts = null;
 196         forwardRequest = null;
 197         forwardRequestIOR = null;
 198         exception = null;
 199 
 200         // We don't need to reset the Slots because they are
 201         // already in the clean state after recieve_<point> interceptor
 202         // are called.
 203     }
 204 
 205     /*
 206      **********************************************************************
 207      * Access protection
 208      **********************************************************************/
 209 
 210     // Method IDs for all methods in RequestInfo.  This allows for a
 211     // convenient O(1) lookup for checkAccess().
 212     protected static final int MID_REQUEST_ID                   =  0;
 213     protected static final int MID_OPERATION                    =  1;
 214     protected static final int MID_ARGUMENTS                    =  2;
 215     protected static final int MID_EXCEPTIONS                   =  3;
 216     protected static final int MID_CONTEXTS                     =  4;
 217     protected static final int MID_OPERATION_CONTEXT            =  5;
 218     protected static final int MID_RESULT                       =  6;
 219     protected static final int MID_RESPONSE_EXPECTED            =  7;
 220     protected static final int MID_SYNC_SCOPE                   =  8;
 221     protected static final int MID_REPLY_STATUS                 =  9;
 222     protected static final int MID_FORWARD_REFERENCE            = 10;
 223     protected static final int MID_GET_SLOT                     = 11;
 224     protected static final int MID_GET_REQUEST_SERVICE_CONTEXT  = 12;
 225     protected static final int MID_GET_REPLY_SERVICE_CONTEXT    = 13;
 226     // The last value from RequestInfo (be sure to update this):
 227     protected static final int MID_RI_LAST                      = 13;
 228 
 229     /*
 230      **********************************************************************
 231      * Public interfaces
 232      **********************************************************************/
 233 
 234     /**
 235      * Creates a new RequestInfoImpl object.
 236      */
 237     public RequestInfoImpl( ORB myORB ) {
 238         super();
 239 
 240         this.myORB = myORB;
 241         wrapper = InterceptorsSystemException.get( myORB,
 242             CORBALogDomains.RPC_PROTOCOL ) ;
 243         stdWrapper = OMGSystemException.get( myORB,
 244             CORBALogDomains.RPC_PROTOCOL ) ;
 245 
 246         // Capture the current TSC and make it the RSC of this request.
 247         PICurrent current = (PICurrent)(myORB.getPIHandler().getPICurrent());
 248         slotTable = current.getSlotTable( );
 249     }
 250 
 251     /**
 252      * Implementation for request_id() differs for client and server
 253      * implementations.
 254      *
 255      * Uniquely identifies an active request/reply sequence.  Once a
 256      * request/reply sequence is concluded this ID may be reused.  (this
 257      * is NOT necessarily the same as the GIOP request_id).
 258      */
 259     abstract public int request_id ();
 260 
 261     /**
 262      * Implementation for operation() differs for client and server
 263      * implementations.
 264      *
 265      * The name of the operation being invoked.
 266      */
 267     abstract public String operation ();
 268 
 269 
 270     /**
 271      * This method returns the list of arguments for the operation that was
 272      * invoked. It raises NO_RESOURCES exception if the operation is not invoked
 273      * by using DII mechanism.
 274      */
 275     abstract public Parameter[] arguments ();
 276 
 277     /**
 278      * This method returns the list of exceptios  that was raised when the
 279      * operation was invoked. It raises NO_RESOURCES exception if the operation
 280      * is not invoked by using DII mechanism.
 281      */
 282     abstract public TypeCode[] exceptions ();
 283 
 284     /**
 285      * This method returns the list of contexts for the DII operation.
 286      * It raises NO_RESOURCES exception if the operation is not invoked by
 287      * using DII mechanism.
 288      */
 289     abstract public String[] contexts ();
 290 
 291     /**
 292      * This method returns the list of operation_context for the DII operation.
 293      * It raises NO_RESOURCES exception if the operation is not invoked by
 294      * using DII mechanism.
 295      */
 296     abstract public String[] operation_context ();
 297 
 298     /**
 299      * This method returns the result from the invoked DII operation.
 300      * It raises NO_RESOURCES exception if the operation is not invoked by
 301      * using DII mechanism.
 302      */
 303     abstract public Any result ();
 304 
 305     /**
 306      * Implementation for response_expected() differs for client and server
 307      * implementations.
 308      *
 309      * Indicates whether a response is expected.  On the client, a reply is
 310      * not returned when response_expected is false, so receive_reply cannot
 311      * be called.  receive_other is called unless an exception occurs, in
 312      * which case receive_exception is called.  On the client, within
 313      * send_poll, this attribute is true.
 314      */
 315     abstract public boolean response_expected ();
 316 
 317     /**
 318      * Defined in the Messaging specification.  Pertinent only when
 319      * response_expected is false.  If response_expected is true, the value
 320      * of sync_scope is undefined.  It defines how far the request shall
 321      * progress before control is returned to the client.  This attribute may
 322      * have one of the follwing values:
 323      * <ul>
 324      *   <li>Messaging::SYNC_NONE</li>
 325      *   <li>Messaging::SYNC_WITH_TRANSPORT</li>
 326      *   <li>Messaging::SYNC_WITH_SERVER</li>
 327      *   <li>Messaging::SYNC_WITH_TARGET</li>
 328      * </ul>
 329      */
 330     public short sync_scope (){
 331         checkAccess( MID_SYNC_SCOPE );
 332         return SYNC_WITH_TRANSPORT.value; // REVISIT - get from MessageMediator
 333     }
 334 
 335     /**
 336      * Describes the state of the result of the operation invocation.  Its
 337      * value can be one of the following:
 338      * <ul>
 339      *   <li>PortableInterceptor::SUCCESSFUL</li>
 340      *   <li>PortableInterceptor::SYSTEM_EXCEPTION</li>
 341      *   <li>PortableInterceptor::USER_EXCEPTION</li>
 342      *   <li>PortableInterceptor::LOCATION_FORWARD</li>
 343      *   <li>PortableInterceptor::TRANSPORT_RETRY</li>
 344      * </ul>
 345      */
 346     public short reply_status (){
 347         checkAccess( MID_REPLY_STATUS );
 348         return replyStatus;
 349     }
 350 
 351     /**
 352      * Implementation for forward_reference() differs for client and server
 353      * implementations.
 354      *
 355      * If the reply_status attribute is LOCATION_FORWARD
 356      * then this attribute will contain the object
 357      * to which the request will be forwarded.  It is indeterminate whether a
 358      * forwarded request will actually occur.
 359      */
 360     abstract public Object forward_reference ();
 361 
 362 
 363     /**
 364      * Returns the data from the given slot of the PortableInterceptor::Current
 365      * that is in the scope of the request.
 366      * <p>
 367      * If the given slot has not been set, then an any containing a type code
 368      * with a TCKind value of tk_null is returned.
 369      * <p>
 370      * If the ID does not define an allocated slot, InvalidSlot is raised.
 371      */
 372     public Any get_slot (int id)
 373         throws InvalidSlot
 374     {
 375         // access is currently valid for all states:
 376         //checkAccess( MID_GET_SLOT );
 377         // Delegate the call to the slotTable which was set when RequestInfo was
 378         // created.
 379         return slotTable.get_slot( id );
 380     }
 381 
 382     /**
 383      * Implementation for get_request_service_context() differs for client
 384      * and server implementations.
 385      *
 386      * This operation returns a copy of the service context with the given ID
 387      * that is associated with the request.  If the request's service context
 388      * does not contain an etry for that ID, BAD_PARAM with a minor code of
 389      * TBD_BP is raised.
 390      */
 391     abstract public org.omg.IOP.ServiceContext
 392         get_request_service_context(int id);
 393 
 394     /**
 395      * Implementation for get_reply_service_context() differs for client
 396      * and server implementations.
 397      *
 398      * This operation returns a copy of the service context with the given ID
 399      * that is associated with the reply.  IF the request's service context
 400      * does not contain an entry for that ID, BAD_PARAM with a minor code of
 401      * TBD_BP is raised.
 402      */
 403     abstract public org.omg.IOP.ServiceContext
 404         get_reply_service_context (int id);
 405 
 406 
 407     // NOTE: When adding a method, be sure to:
 408     // 1. Add a MID_* constant for that method
 409     // 2. Call checkAccess at the start of the method
 410     // 3. Define entries in the validCall[][] table for interception points
 411     //    in both ClientRequestInfoImpl and ServerRequestInfoImpl.
 412 
 413 
 414 
 415     /*
 416      **********************************************************************
 417      * Proprietary methods
 418      **********************************************************************/
 419 
 420     /**
 421      * @return The connection on which the request is made.
 422      *
 423      * Note: we store the connection as an internal type but
 424      * expose it here as an external type.
 425      */
 426     public com.sun.corba.se.spi.legacy.connection.Connection connection()
 427     {
 428         return connection;
 429     }
 430 
 431     /*
 432      **********************************************************************
 433      * Private utility methods
 434      **********************************************************************/
 435 
 436     /**
 437      * Inserts the UserException inside the given ApplicationException
 438      * into the given Any.  Throws an UNKNOWN with minor code
 439      * OMGSYstemException.UNKNOWN_USER_EXCEPTION if the Helper class could not be
 440      * found to insert it with.
 441      */
 442     private void insertApplicationException( ApplicationException appException,
 443                                              Any result )
 444         throws UNKNOWN
 445     {
 446         try {
 447             // Extract the UserException from the ApplicationException.
 448             // Look up class name from repository id:
 449             RepositoryId repId = RepositoryId.cache.getId(
 450                 appException.getId() );
 451             String className = repId.getClassName();
 452 
 453             // Find the read method on the helper class:
 454             String helperClassName = className + "Helper";
 455             Class helperClass = ORBClassLoader.loadClass( helperClassName );
 456             Class[] readParams = new Class[1];
 457             readParams[0] = org.omg.CORBA.portable.InputStream.class;
 458             Method readMethod = helperClass.getMethod( "read", readParams );
 459 
 460             // Invoke the read method, passing in the input stream to
 461             // retrieve the user exception.  Mark and reset the stream
 462             // as to not disturb it.
 463             InputStream ueInputStream = appException.getInputStream();
 464             ueInputStream.mark( 0 );
 465             UserException userException = null;
 466             try {
 467                 java.lang.Object[] readArguments = new java.lang.Object[1];
 468                 readArguments[0] = ueInputStream;
 469                 userException = (UserException)readMethod.invoke(
 470                     null, readArguments );
 471             }
 472             finally {
 473                 try {
 474                     ueInputStream.reset();
 475                 }
 476                 catch( IOException e ) {
 477                     throw wrapper.markAndResetFailed( e ) ;
 478                 }
 479             }
 480 
 481             // Insert this UserException into the provided Any using the
 482             // helper class.
 483             insertUserException( userException, result );
 484         } catch( ClassNotFoundException e ) {
 485             throw stdWrapper.unknownUserException( CompletionStatus.COMPLETED_MAYBE, e ) ;
 486         } catch( NoSuchMethodException e ) {
 487             throw stdWrapper.unknownUserException( CompletionStatus.COMPLETED_MAYBE, e ) ;
 488         } catch( SecurityException e ) {
 489             throw stdWrapper.unknownUserException( CompletionStatus.COMPLETED_MAYBE, e ) ;
 490         } catch( IllegalAccessException e ) {
 491             throw stdWrapper.unknownUserException( CompletionStatus.COMPLETED_MAYBE, e ) ;
 492         } catch( IllegalArgumentException e ) {
 493             throw stdWrapper.unknownUserException( CompletionStatus.COMPLETED_MAYBE, e ) ;
 494         } catch( InvocationTargetException e ) {
 495             throw stdWrapper.unknownUserException( CompletionStatus.COMPLETED_MAYBE, e ) ;
 496         }
 497     }
 498 
 499     /**
 500      * Inserts the UserException into the given Any.
 501      * Throws an UNKNOWN with minor code
 502      * OMGSYstemException.UNKNOWN_USER_EXCEPTION if the Helper class could not be
 503      * found to insert it with.
 504      */
 505     private void insertUserException( UserException userException, Any result )
 506         throws UNKNOWN
 507     {
 508         try {
 509             // Insert this UserException into the provided Any using the
 510             // helper class.
 511             if( userException != null ) {
 512                 Class exceptionClass = userException.getClass();
 513                 String className = exceptionClass.getName();
 514                 String helperClassName = className + "Helper";
 515                 Class helperClass = ORBClassLoader.loadClass( helperClassName );
 516 
 517                 // Find insert( Any, class ) method
 518                 Class[] insertMethodParams = new Class[2];
 519                 insertMethodParams[0] = org.omg.CORBA.Any.class;
 520                 insertMethodParams[1] = exceptionClass;
 521                 Method insertMethod = helperClass.getMethod(
 522                     "insert", insertMethodParams );
 523 
 524                 // Call helper.insert( result, userException ):
 525                 java.lang.Object[] insertMethodArguments =
 526                     new java.lang.Object[2];
 527                 insertMethodArguments[0] = result;
 528                 insertMethodArguments[1] = userException;
 529                 insertMethod.invoke( null, insertMethodArguments );
 530             }
 531         } catch( ClassNotFoundException e ) {
 532             throw stdWrapper.unknownUserException( CompletionStatus.COMPLETED_MAYBE, e );
 533         } catch( NoSuchMethodException e ) {
 534             throw stdWrapper.unknownUserException( CompletionStatus.COMPLETED_MAYBE, e );
 535         } catch( SecurityException e ) {
 536             throw stdWrapper.unknownUserException( CompletionStatus.COMPLETED_MAYBE, e );
 537         } catch( IllegalAccessException e ) {
 538             throw stdWrapper.unknownUserException( CompletionStatus.COMPLETED_MAYBE, e );
 539         } catch( IllegalArgumentException e ) {
 540             throw stdWrapper.unknownUserException( CompletionStatus.COMPLETED_MAYBE, e );
 541         } catch( InvocationTargetException e ) {
 542             throw stdWrapper.unknownUserException( CompletionStatus.COMPLETED_MAYBE, e );
 543         }
 544     }
 545 
 546     /*
 547      **********************************************************************
 548      * Protected utility methods
 549      **********************************************************************/
 550 
 551     /**
 552      * Internal utility method to convert an NVList into a PI Parameter[]
 553      */
 554     protected Parameter[] nvListToParameterArray( NVList parNVList ) {
 555 
 556         // _REVISIT_ This utility method should probably be doing a deep
 557         // copy so interceptor can't accidentally change the arguments.
 558 
 559         int count = parNVList.count();
 560         Parameter[] plist = new Parameter[count];
 561         try {
 562             for( int i = 0; i < count; i++ ) {
 563                 Parameter p = new Parameter();
 564                 plist[i] = p;
 565                 NamedValue nv = parNVList.item( i );
 566                 plist[i].argument = nv.value();
 567                 // ParameterMode spec can be found in 99-10-07.pdf
 568                 // Section:10.5.22
 569                 // nv.flags spec can be found in 99-10-07.pdf
 570                 // Section 7.1.1
 571                 // nv.flags has ARG_IN as 1, ARG_OUT as 2 and ARG_INOUT as 3
 572                 // To convert this into enum PARAM_IN, PARAM_OUT and
 573                 // PARAM_INOUT the value is subtracted by 1.
 574                 plist[i].mode = ParameterMode.from_int( nv.flags() - 1 );
 575             }
 576         } catch ( Exception e ) {
 577             throw wrapper.exceptionInArguments( e ) ;
 578         }
 579 
 580         return plist;
 581     }
 582 
 583     /**
 584      * Utility to wrap the given Exception in an Any object and return it.
 585      * If the exception is a UserException which cannot be inserted into
 586      * an any, then this returns an Any containing the system exception
 587      * UNKNOWN.
 588      */
 589     protected Any exceptionToAny( Exception exception ){
 590         Any result = myORB.create_any();
 591 
 592         if( exception == null ) {
 593             // Note: exception should never be null here since we will throw
 594             // a BAD_INV_ORDER if this is not called from receive_exception.
 595             throw wrapper.exceptionWasNull2() ;
 596         } else if( exception instanceof SystemException ) {
 597             ORBUtility.insertSystemException(
 598                 (SystemException)exception, result );
 599         } else if( exception instanceof ApplicationException ) {
 600             // Use the Helper class for this exception to insert it into an
 601             // Any.
 602             try {
 603                 // Insert the user exception inside the application exception
 604                 // into the Any result:
 605                 ApplicationException appException =
 606                     (ApplicationException)exception;
 607                 insertApplicationException( appException, result );
 608             } catch( UNKNOWN e ) {
 609                 // As per ptc/00-08-06, 21.3.13.4. if we cannot find the
 610                 // appropriate class, then return an any containing UNKNOWN,
 611                 // with a minor code of 1.  This is conveniently the same
 612                 // exception that is returned from the
 613                 // insertApplicationException utility method.
 614                 ORBUtility.insertSystemException( e, result );
 615             }
 616         } else if( exception instanceof UserException ) {
 617             try {
 618                 UserException userException = (UserException)exception;
 619                 insertUserException( userException, result );
 620             } catch( UNKNOWN e ) {
 621                 ORBUtility.insertSystemException( e, result );
 622             }
 623         }
 624 
 625 
 626         return result;
 627     }
 628 
 629     /**
 630      * Utility method to look up a service context with the given id and
 631      * convert it to an IOP.ServiceContext.  Uses the given HashMap as
 632      * a cache.  If not found in cache, the result is inserted in the cache.
 633      */
 634     protected org.omg.IOP.ServiceContext
 635         getServiceContext ( HashMap cachedServiceContexts,
 636                             ServiceContexts serviceContexts, int id )
 637     {
 638         org.omg.IOP.ServiceContext result = null;
 639         Integer integerId = new Integer( id );
 640 
 641         // Search cache first:
 642         result = (org.omg.IOP.ServiceContext)
 643             cachedServiceContexts.get( integerId );
 644 
 645         // null could normally mean that either we cached the value null
 646         // or it's not in the cache.  However, there is no way for us to
 647         // cache the value null in the following code.
 648         if( result == null ) {
 649             // Not in cache.  Find it and put in cache.
 650             // Get the desired "core" service context.
 651             com.sun.corba.se.spi.servicecontext.ServiceContext context =
 652                 serviceContexts.get( id );
 653             if (context == null)
 654                 throw stdWrapper.invalidServiceContextId() ;
 655 
 656             // Convert the "core" service context to an
 657             // "IOP" ServiceContext by writing it to a
 658             // CDROutputStream and reading it back.
 659             EncapsOutputStream out = new EncapsOutputStream(myORB);
 660 
 661             context.write( out, GIOPVersion.V1_2 );
 662             InputStream inputStream = out.create_input_stream();
 663             result = ServiceContextHelper.read( inputStream );
 664 
 665             cachedServiceContexts.put( integerId, result );
 666         }
 667 
 668         // Good citizen: For increased efficiency, we assume that interceptors
 669         // will not modify the returned ServiceContext.  Otherwise, we would
 670         // have to make a deep copy.
 671 
 672         return result;
 673     }
 674 
 675 
 676     /**
 677      * Utility method to add an IOP.ServiceContext to a core.ServiceContexts
 678      * object.  If replace is true, any service context with the given id
 679      * is replaced.
 680      * <p>
 681      * Raises BAD_INV_ORDER if replace is false and a service context with
 682      * the given id already exists.
 683      * <p>
 684      * Uses the given HashMap as a cache.  If a service context is placed
 685      * in the container, it goes in the HashMap as well.
 686      */
 687     protected void addServiceContext(
 688         HashMap cachedServiceContexts,
 689         ServiceContexts serviceContexts,
 690         org.omg.IOP.ServiceContext service_context,
 691         boolean replace )
 692     {
 693         int id = 0 ;
 694         // Convert IOP.service_context to core.ServiceContext:
 695         EncapsOutputStream outputStream = new EncapsOutputStream(
 696             myORB );
 697         InputStream inputStream = null;
 698         UnknownServiceContext coreServiceContext = null;
 699         ServiceContextHelper.write( outputStream, service_context );
 700         inputStream = outputStream.create_input_stream();
 701 
 702         // Constructor expects id to already have been read from stream.
 703         coreServiceContext = new UnknownServiceContext(
 704             inputStream.read_long(),
 705             (org.omg.CORBA_2_3.portable.InputStream)inputStream );
 706 
 707         id = coreServiceContext.getId();
 708 
 709         if (serviceContexts.get(id) != null)
 710             if (replace)
 711                 serviceContexts.delete( id );
 712             else
 713                 throw stdWrapper.serviceContextAddFailed( new Integer(id) ) ;
 714 
 715         serviceContexts.put( coreServiceContext );
 716 
 717         // Place IOP.ServiceContext in cache as well:
 718         cachedServiceContexts.put( new Integer( id ), service_context );
 719     }
 720 
 721     /**
 722      * Sets the number of interceptors whose starting interception
 723      * points were successfully invoked on this client call.  As specified
 724      * in orbos/99-12-02, section 5.2.1., not all interceptors will
 725      * be invoked if a ForwardRequest exception or a system exception
 726      * is raised.  This keeps track of how many were successfully executed
 727      * so we know not to execute the corresponding ending interception
 728      * points for the interceptors whose starting interception points
 729      * were not completed.  This simulates the "Flow Stack Visual Model"
 730      * presented in section 5.1.3.*/
 731     protected void setFlowStackIndex(int num ) {
 732         this.flowStackIndex = num;
 733     }
 734 
 735     /**
 736      * Returns the number of interceptors whose starting interception
 737      * points were actually invoked on this client request.  See
 738      * setFlowStackIndex for more details.
 739      */
 740     protected int getFlowStackIndex() {
 741         return this.flowStackIndex;
 742     }
 743 
 744     /**
 745      * Sets which ending interception point should be called
 746      * for each interceptor in the virtual flow stack.
 747      */
 748     protected void setEndingPointCall( int call ) {
 749         this.endingPointCall = call;
 750     }
 751 
 752     /**
 753      * Retrieves the current ending point call type (see
 754      * setEndingPointCall for more details).
 755      */
 756     protected int getEndingPointCall() {
 757         return this.endingPointCall;
 758     }
 759 
 760     /**
 761      * Sets which intermediate interception point should be called
 762      * for each interceptor in the virtual flow stack.
 763      */
 764     protected void setIntermediatePointCall( int call ) {
 765         this.intermediatePointCall = call;
 766     }
 767 
 768     /**
 769      * Retrieves the current intermediate point call type (see
 770      * setEndingPointCall for more details).
 771      */
 772     protected int getIntermediatePointCall() {
 773         return this.intermediatePointCall;
 774     }
 775 
 776     /**
 777      * Sets which starting interception point should be called
 778      * for each interceptor in the virtual flow stack.
 779      */
 780     protected void setStartingPointCall( int call ) {
 781         this.startingPointCall = call;
 782     }
 783 
 784     /**
 785      * Retrieves the current starting point call type (see
 786      * setStartingPointCall for more details).
 787      */
 788     protected int getStartingPointCall() {
 789         return this.startingPointCall;
 790     }
 791 
 792     /**
 793      * Returns true if all interceptors' starting and ending points
 794      * have already executed to completion, or false if not yet.
 795      */
 796     protected boolean getAlreadyExecuted() {
 797         return this.alreadyExecuted;
 798     }
 799 
 800     /**
 801      * Sets whether all interceotrs' starting and ending points
 802      * have already been executed to completion.
 803      */
 804     protected void setAlreadyExecuted( boolean alreadyExecuted ) {
 805         this.alreadyExecuted = alreadyExecuted;
 806     }
 807 
 808     /**
 809      * Sets the value to be returned by reply_status
 810      */
 811     protected void setReplyStatus( short replyStatus ) {
 812         this.replyStatus = replyStatus;
 813     }
 814 
 815     /**
 816      * Gets the current reply_status without doing an access check
 817      * (available only to package and subclasses)
 818      */
 819     protected short getReplyStatus() {
 820         return this.replyStatus;
 821     }
 822 
 823     /**
 824      * Stores the given ForwardRequest object for later analysis.
 825      * This version supplements setForwardRequest( IOR );
 826      */
 827     protected void setForwardRequest( ForwardRequest forwardRequest ) {
 828         this.forwardRequest = forwardRequest;
 829         this.forwardRequestIOR = null;
 830     }
 831 
 832     /**
 833      * Stores the given IOR for later forward request analysis.
 834      * This version supplements setForwardRequest( ForwardRequest );
 835      */
 836     protected void setForwardRequest( IOR ior ) {
 837         this.forwardRequestIOR = ior;
 838         this.forwardRequest = null;
 839     }
 840 
 841     /**
 842      * Retrieves the ForwardRequest object as a ForwardRequest exception.
 843      */
 844     protected ForwardRequest getForwardRequestException() {
 845         if( this.forwardRequest == null ) {
 846             if( this.forwardRequestIOR != null ) {
 847                 // Convert the internal IOR to a forward request exception
 848                 // by creating an object reference.
 849                 org.omg.CORBA.Object obj = iorToObject(this.forwardRequestIOR);
 850                 this.forwardRequest = new ForwardRequest( obj );
 851             }
 852         }
 853 
 854         return this.forwardRequest;
 855     }
 856 
 857     /**
 858      * Retrieves the IOR of the ForwardRequest exception.
 859      */
 860     protected IOR getForwardRequestIOR() {
 861         if( this.forwardRequestIOR == null ) {
 862             if( this.forwardRequest != null ) {
 863                 this.forwardRequestIOR = ORBUtility.getIOR(
 864                     this.forwardRequest.forward ) ;
 865             }
 866         }
 867 
 868         return this.forwardRequestIOR;
 869     }
 870 
 871     /**
 872      * Sets the exception to be returned by received_exception and
 873      * received_exception_id.
 874      */
 875     protected void setException( Exception exception ) {
 876         this.exception = exception;
 877     }
 878 
 879     /**
 880      * Returns the exception to be returned by received_exception and
 881      * received_exception_id.
 882      */
 883     Exception getException() {
 884         return this.exception;
 885     }
 886 
 887     /**
 888      * Sets the execution point that we are currently executing
 889      * (starting points, intermediate points, or ending points).
 890      * This allows us to enforce the validity table.
 891      */
 892     protected void setCurrentExecutionPoint( int executionPoint ) {
 893         this.currentExecutionPoint = executionPoint;
 894     }
 895 
 896     /**
 897      * Check whether the caller is allowed to access this method at
 898      * this particular time.  This is overridden in subclasses to implement
 899      * the validity table specified in ptc/00-04-05, table 21-1 and 21-2.
 900      * The currentExecutionPoint attribute is checked, and if access is
 901      * forbidden at this time, BAD_INV_ORDER is raised with a minor code of
 902      * TBD_BIO.
 903      *
 904      * @param methodID The ID of this method, one of the MID_* constants.
 905      *     This allows us to easily look up the method access in a table.
 906      *     Note that method ids may overlap between subclasses.
 907      */
 908     protected abstract void checkAccess( int methodID )
 909         throws BAD_INV_ORDER;
 910 
 911     /**
 912      * The server side does an explicit set rather than taking the
 913      * current PICurrent table as is done in the general RequestInfoImpl
 914      * constructor.
 915      */
 916     void setSlotTable(SlotTable slotTable)
 917     {
 918         this.slotTable = slotTable;
 919     }
 920 
 921     protected org.omg.CORBA.Object iorToObject( IOR ior )
 922     {
 923         return ORBUtility.makeObjectReference( ior ) ;
 924     }
 925 }