1 /*
   2  * Copyright (c) 2000, 2003, 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.CompletionStatus;
  28 import org.omg.CORBA.INTERNAL;
  29 import org.omg.CORBA.SystemException;
  30 import org.omg.CORBA.portable.Delegate;
  31 import org.omg.PortableInterceptor.LOCATION_FORWARD;
  32 import org.omg.PortableInterceptor.SUCCESSFUL;
  33 import org.omg.PortableInterceptor.SYSTEM_EXCEPTION;
  34 import org.omg.PortableInterceptor.TRANSPORT_RETRY;
  35 import org.omg.PortableInterceptor.USER_EXCEPTION;
  36 import org.omg.PortableInterceptor.ClientRequestInfo;
  37 import org.omg.PortableInterceptor.ClientRequestInterceptor;
  38 import org.omg.PortableInterceptor.ForwardRequest;
  39 import org.omg.PortableInterceptor.IORInterceptor;
  40 import org.omg.PortableInterceptor.IORInterceptor_3_0;
  41 import org.omg.PortableInterceptor.ServerRequestInfo;
  42 import org.omg.PortableInterceptor.ServerRequestInterceptor;
  43 import org.omg.PortableInterceptor.ObjectReferenceTemplate;
  44 
  45 import com.sun.corba.se.spi.ior.IOR;
  46 import com.sun.corba.se.spi.oa.ObjectAdapter;
  47 import com.sun.corba.se.spi.orb.ORB;
  48 import com.sun.corba.se.impl.orbutil.ORBUtility;
  49 
  50 /**
  51  * Handles invocation of interceptors.  Has specific knowledge of how to
  52  * invoke IOR, ClientRequest, and ServerRequest interceptors.
  53  * Makes use of the InterceptorList to retrieve the list of interceptors to
  54  * be invoked.  Most methods in this class are package scope so that they
  55  * may only be called from the PIHandlerImpl.
  56  */
  57 public class InterceptorInvoker {
  58 
  59     // The ORB
  60     private ORB orb;
  61 
  62     // The list of interceptors to be invoked
  63     private InterceptorList interceptorList;
  64 
  65     // True if interceptors are to be invoked, or false if not
  66     // Note: This is a global enable/disable flag, whereas the enable flag
  67     // in the RequestInfoStack in PIHandlerImpl is only for a particular Thread.
  68     private boolean enabled = false;
  69 
  70     // PICurrent variable.
  71     private PICurrent current;
  72 
  73     // NOTE: Be careful about adding additional attributes to this class.
  74     // Multiple threads may be calling methods on this invoker at the same
  75     // time.
  76 
  77     /**
  78      * Creates a new Interceptor Invoker.  Constructor is package scope so
  79      * only the ORB can create it.  The invoker is initially disabled, and
  80      * must be explicitly enabled using setEnabled().
  81      */
  82     InterceptorInvoker( ORB orb, InterceptorList interceptorList,
  83                         PICurrent piCurrent )
  84     {
  85         this.orb = orb;
  86         this.interceptorList = interceptorList;
  87         this.enabled = false;
  88         this.current = piCurrent;
  89     }
  90 
  91     /**
  92      * Enables or disables the interceptor invoker
  93      */
  94     void setEnabled( boolean enabled ) {
  95         this.enabled = enabled;
  96     }
  97 
  98     /*
  99      **********************************************************************
 100      * IOR Interceptor invocation
 101      **********************************************************************/
 102 
 103     /**
 104      * Called when a new POA is created.
 105      *
 106      * @param oa The Object Adapter associated with the IOR interceptor.
 107      */
 108     void objectAdapterCreated( ObjectAdapter oa ) {
 109         // If invocation is not yet enabled, don't do anything.
 110         if( enabled ) {
 111             // Create IORInfo object to pass to IORInterceptors:
 112             IORInfoImpl info = new IORInfoImpl( oa );
 113 
 114             // Call each IORInterceptor:
 115             IORInterceptor[] iorInterceptors =
 116                 (IORInterceptor[])interceptorList.getInterceptors(
 117                 InterceptorList.INTERCEPTOR_TYPE_IOR );
 118             int size = iorInterceptors.length;
 119 
 120             // Implementation note:
 121             // This loop counts backwards for greater efficiency.
 122             // Benchmarks have shown that counting down is more efficient
 123             // than counting up in Java for loops, as a compare to zero is
 124             // faster than a subtract and compare to zero.  In this case,
 125             // it doesn't really matter much, but it's simply a force of habit.
 126 
 127             for( int i = (size - 1); i >= 0; i-- ) {
 128                 IORInterceptor interceptor = iorInterceptors[i];
 129                 try {
 130                     interceptor.establish_components( info );
 131                 }
 132                 catch( Exception e ) {
 133                     // as per PI spec (orbos/99-12-02 sec 7.2.1), if
 134                     // establish_components throws an exception, ignore it.
 135                 }
 136             }
 137 
 138             // Change the state so that only template operations are valid
 139             info.makeStateEstablished() ;
 140 
 141             for( int i = (size - 1); i >= 0; i-- ) {
 142                 IORInterceptor interceptor = iorInterceptors[i];
 143                 if (interceptor instanceof IORInterceptor_3_0) {
 144                     IORInterceptor_3_0 interceptor30 = (IORInterceptor_3_0)interceptor ;
 145                     // Note that exceptions here are NOT ignored, as per the
 146                     // ORT spec (orbos/01-01-04)
 147                     interceptor30.components_established( info );
 148                 }
 149             }
 150 
 151             // Change the state so that no operations are valid,
 152             // in case a reference to info escapes this scope.
 153             // This also completes the actions associated with the
 154             // template interceptors on this POA.
 155             info.makeStateDone() ;
 156         }
 157     }
 158 
 159     void adapterManagerStateChanged( int managerId, short newState )
 160     {
 161         if (enabled) {
 162             IORInterceptor[] interceptors =
 163                 (IORInterceptor[])interceptorList.getInterceptors(
 164                 InterceptorList.INTERCEPTOR_TYPE_IOR );
 165             int size = interceptors.length;
 166 
 167             for( int i = (size - 1); i >= 0; i-- ) {
 168                 try {
 169                     IORInterceptor interceptor = interceptors[i];
 170                     if (interceptor instanceof IORInterceptor_3_0) {
 171                         IORInterceptor_3_0 interceptor30 = (IORInterceptor_3_0)interceptor ;
 172                         interceptor30.adapter_manager_state_changed( managerId,
 173                             newState );
 174                     }
 175                 } catch (Exception exc) {
 176                     // No-op: ignore exception in this case
 177                 }
 178             }
 179         }
 180     }
 181 
 182     void adapterStateChanged( ObjectReferenceTemplate[] templates,
 183         short newState )
 184     {
 185         if (enabled) {
 186             IORInterceptor[] interceptors =
 187                 (IORInterceptor[])interceptorList.getInterceptors(
 188                 InterceptorList.INTERCEPTOR_TYPE_IOR );
 189             int size = interceptors.length;
 190 
 191             for( int i = (size - 1); i >= 0; i-- ) {
 192                 try {
 193                     IORInterceptor interceptor = interceptors[i];
 194                     if (interceptor instanceof IORInterceptor_3_0) {
 195                         IORInterceptor_3_0 interceptor30 = (IORInterceptor_3_0)interceptor ;
 196                         interceptor30.adapter_state_changed( templates, newState );
 197                     }
 198                 } catch (Exception exc) {
 199                     // No-op: ignore exception in this case
 200                 }
 201             }
 202         }
 203     }
 204 
 205     /*
 206      **********************************************************************
 207      * Client Interceptor invocation
 208      **********************************************************************/
 209 
 210     /**
 211      * Invokes either send_request, or send_poll, depending on the value
 212      * of info.getStartingPointCall()
 213      */
 214     void invokeClientInterceptorStartingPoint( ClientRequestInfoImpl info ) {
 215         // If invocation is not yet enabled, don't do anything.
 216         if( enabled ) {
 217             try {
 218                 // Make a a fresh slot table available to TSC in case
 219                 // interceptors need to make out calls.
 220                 // Client's TSC is now RSC via RequestInfo.
 221                 current.pushSlotTable( );
 222                 info.setPICurrentPushed( true );
 223                 info.setCurrentExecutionPoint( info.EXECUTION_POINT_STARTING );
 224 
 225                 // Get all ClientRequestInterceptors:
 226                 ClientRequestInterceptor[] clientInterceptors =
 227                     (ClientRequestInterceptor[])interceptorList.
 228                     getInterceptors( InterceptorList.INTERCEPTOR_TYPE_CLIENT );
 229                 int size = clientInterceptors.length;
 230 
 231                 // We will assume that all interceptors returned successfully,
 232                 // and adjust the flowStackIndex to the appropriate value if
 233                 // we later discover otherwise.
 234                 int flowStackIndex = size;
 235                 boolean continueProcessing = true;
 236 
 237                 // Determine whether we are calling send_request or send_poll:
 238                 // (This is currently commented out because our ORB does not
 239                 // yet support the Messaging specification, so send_poll will
 240                 // never occur.  Once we have implemented messaging, this may
 241                 // be uncommented.)
 242                 // int startingPointCall = info.getStartingPointCall();
 243                 for( int i = 0; continueProcessing && (i < size); i++ ) {
 244                     try {
 245                         clientInterceptors[i].send_request( info );
 246 
 247                         // Again, it is not necessary for a switch here, since
 248                         // there is only one starting point call type (see
 249                         // above comment).
 250 
 251                         //switch( startingPointCall ) {
 252                         //case ClientRequestInfoImpl.CALL_SEND_REQUEST:
 253                             //clientInterceptors[i].send_request( info );
 254                             //break;
 255                         //case ClientRequestInfoImpl.CALL_SEND_POLL:
 256                             //clientInterceptors[i].send_poll( info );
 257                             //break;
 258                         //}
 259 
 260                     }
 261                     catch( ForwardRequest e ) {
 262                         // as per PI spec (orbos/99-12-02 sec 5.2.1.), if
 263                         // interception point throws a ForwardRequest,
 264                         // no other Interceptors' send_request operations are
 265                         // called.
 266                         flowStackIndex = i;
 267                         info.setForwardRequest( e );
 268                         info.setEndingPointCall(
 269                             ClientRequestInfoImpl.CALL_RECEIVE_OTHER );
 270                         info.setReplyStatus( LOCATION_FORWARD.value );
 271 
 272                         updateClientRequestDispatcherForward( info );
 273 
 274                         // For some reason, using break here causes the VM on
 275                         // NT to lose track of the value of flowStackIndex
 276                         // after exiting the for loop.  I changed this to
 277                         // check a boolean value instead and it seems to work
 278                         // fine.
 279                         continueProcessing = false;
 280                     }
 281                     catch( SystemException e ) {
 282                         // as per PI spec (orbos/99-12-02 sec 5.2.1.), if
 283                         // interception point throws a SystemException,
 284                         // no other Interceptors' send_request operations are
 285                         // called.
 286                         flowStackIndex = i;
 287                         info.setEndingPointCall(
 288                             ClientRequestInfoImpl.CALL_RECEIVE_EXCEPTION );
 289                         info.setReplyStatus( SYSTEM_EXCEPTION.value );
 290                         info.setException( e );
 291 
 292                         // For some reason, using break here causes the VM on
 293                         // NT to lose track of the value of flowStackIndex
 294                         // after exiting the for loop.  I changed this to
 295                         // check a boolean value instead and it seems to
 296                         // work fine.
 297                         continueProcessing = false;
 298                     }
 299                 }
 300 
 301                 // Remember where we left off in the flow stack:
 302                 info.setFlowStackIndex( flowStackIndex );
 303             }
 304             finally {
 305                 // Make the SlotTable fresh for the next interception point.
 306                 current.resetSlotTable( );
 307             }
 308         } // end enabled check
 309     }
 310 
 311     /**
 312      * Invokes either receive_reply, receive_exception, or receive_other,
 313      * depending on the value of info.getEndingPointCall()
 314      */
 315     void invokeClientInterceptorEndingPoint( ClientRequestInfoImpl info ) {
 316         // If invocation is not yet enabled, don't do anything.
 317         if( enabled ) {
 318             try {
 319                 // NOTE: It is assumed someplace else prepared a
 320                 // fresh TSC slot table.
 321 
 322                 info.setCurrentExecutionPoint( info.EXECUTION_POINT_ENDING );
 323 
 324                 // Get all ClientRequestInterceptors:
 325                 ClientRequestInterceptor[] clientInterceptors =
 326                     (ClientRequestInterceptor[])interceptorList.
 327                     getInterceptors( InterceptorList.INTERCEPTOR_TYPE_CLIENT );
 328                 int flowStackIndex = info.getFlowStackIndex();
 329 
 330                 // Determine whether we are calling receive_reply,
 331                 // receive_exception, or receive_other:
 332                 int endingPointCall = info.getEndingPointCall();
 333 
 334                 // If we would be calling RECEIVE_REPLY, but this is a
 335                 // one-way call, override this and call receive_other:
 336                 if( ( endingPointCall ==
 337                       ClientRequestInfoImpl.CALL_RECEIVE_REPLY ) &&
 338                     info.getIsOneWay() )
 339                 {
 340                     endingPointCall = ClientRequestInfoImpl.CALL_RECEIVE_OTHER;
 341                     info.setEndingPointCall( endingPointCall );
 342                 }
 343 
 344                 // Only step through the interceptors whose starting points
 345                 // have successfully returned.
 346                 // Unlike the previous loop, this one counts backwards for a
 347                 // reason - we must execute these in the reverse order of the
 348                 // starting points.
 349                 for( int i = (flowStackIndex - 1); i >= 0; i-- ) {
 350 
 351                     try {
 352                         switch( endingPointCall ) {
 353                         case ClientRequestInfoImpl.CALL_RECEIVE_REPLY:
 354                             clientInterceptors[i].receive_reply( info );
 355                             break;
 356                         case ClientRequestInfoImpl.CALL_RECEIVE_EXCEPTION:
 357                             clientInterceptors[i].receive_exception( info );
 358                             break;
 359                         case ClientRequestInfoImpl.CALL_RECEIVE_OTHER:
 360                             clientInterceptors[i].receive_other( info );
 361                             break;
 362                         }
 363                     }
 364                     catch( ForwardRequest e ) {
 365 
 366                         // as per PI spec (orbos/99-12-02 sec 5.2.1.), if
 367                         // interception point throws a ForwardException,
 368                         // ending point call changes to receive_other.
 369                         endingPointCall =
 370                             ClientRequestInfoImpl.CALL_RECEIVE_OTHER;
 371                         info.setEndingPointCall( endingPointCall );
 372                         info.setReplyStatus( LOCATION_FORWARD.value );
 373                         info.setForwardRequest( e );
 374                         updateClientRequestDispatcherForward( info );
 375                     }
 376                     catch( SystemException e ) {
 377 
 378                         // as per PI spec (orbos/99-12-02 sec 5.2.1.), if
 379                         // interception point throws a SystemException,
 380                         // ending point call changes to receive_exception.
 381                         endingPointCall =
 382                             ClientRequestInfoImpl.CALL_RECEIVE_EXCEPTION;
 383                         info.setEndingPointCall( endingPointCall );
 384                         info.setReplyStatus( SYSTEM_EXCEPTION.value );
 385                         info.setException( e );
 386                     }
 387                 }
 388             }
 389             finally {
 390                 // See doc for setPICurrentPushed as to why this is necessary.
 391                 // Check info for null in case errors happen before initiate.
 392                 if (info != null && info.isPICurrentPushed()) {
 393                     current.popSlotTable( );
 394                     // After the pop, original client's TSC slot table
 395                     // remains avaiable via PICurrent.
 396                 }
 397             }
 398         } // end enabled check
 399     }
 400 
 401     /*
 402      **********************************************************************
 403      * Server Interceptor invocation
 404      **********************************************************************/
 405 
 406     /**
 407      * Invokes receive_request_service_context interception points.
 408      */
 409     void invokeServerInterceptorStartingPoint( ServerRequestInfoImpl info ) {
 410         // If invocation is not yet enabled, don't do anything.
 411         if( enabled ) {
 412             try {
 413                 // Make a fresh slot table for RSC.
 414                 current.pushSlotTable();
 415                 info.setSlotTable(current.getSlotTable());
 416 
 417                 // Make a fresh slot table for TSC in case
 418                 // interceptors need to make out calls.
 419                 current.pushSlotTable( );
 420 
 421                 info.setCurrentExecutionPoint( info.EXECUTION_POINT_STARTING );
 422 
 423                 // Get all ServerRequestInterceptors:
 424                 ServerRequestInterceptor[] serverInterceptors =
 425                     (ServerRequestInterceptor[])interceptorList.
 426                     getInterceptors( InterceptorList.INTERCEPTOR_TYPE_SERVER );
 427                 int size = serverInterceptors.length;
 428 
 429                 // We will assume that all interceptors returned successfully,
 430                 // and adjust the flowStackIndex to the appropriate value if
 431                 // we later discover otherwise.
 432                 int flowStackIndex = size;
 433                 boolean continueProcessing = true;
 434 
 435                 // Currently, there is only one server-side starting point
 436                 // interceptor called receive_request_service_contexts.
 437                 for( int i = 0; continueProcessing && (i < size); i++ ) {
 438 
 439                     try {
 440                         serverInterceptors[i].
 441                             receive_request_service_contexts( info );
 442                     }
 443                     catch( ForwardRequest e ) {
 444                         // as per PI spec (orbos/99-12-02 sec 5.3.1.), if
 445                         // interception point throws a ForwardRequest,
 446                         // no other Interceptors' starting points are
 447                         // called and send_other is called.
 448                         flowStackIndex = i;
 449                         info.setForwardRequest( e );
 450                         info.setIntermediatePointCall(
 451                             ServerRequestInfoImpl.CALL_INTERMEDIATE_NONE );
 452                         info.setEndingPointCall(
 453                             ServerRequestInfoImpl.CALL_SEND_OTHER );
 454                         info.setReplyStatus( LOCATION_FORWARD.value );
 455 
 456                         // For some reason, using break here causes the VM on
 457                         // NT to lose track of the value of flowStackIndex
 458                         // after exiting the for loop.  I changed this to
 459                         // check a boolean value instead and it seems to work
 460                         // fine.
 461                         continueProcessing = false;
 462                     }
 463                     catch( SystemException e ) {
 464 
 465                         // as per PI spec (orbos/99-12-02 sec 5.3.1.), if
 466                         // interception point throws a SystemException,
 467                         // no other Interceptors' starting points are
 468                         // called.
 469                         flowStackIndex = i;
 470                         info.setException( e );
 471                         info.setIntermediatePointCall(
 472                             ServerRequestInfoImpl.CALL_INTERMEDIATE_NONE );
 473                         info.setEndingPointCall(
 474                             ServerRequestInfoImpl.CALL_SEND_EXCEPTION );
 475                         info.setReplyStatus( SYSTEM_EXCEPTION.value );
 476 
 477                         // For some reason, using break here causes the VM on
 478                         // NT to lose track of the value of flowStackIndex
 479                         // after exiting the for loop.  I changed this to
 480                         // check a boolean value instead and it seems to
 481                         // work fine.
 482                         continueProcessing = false;
 483                     }
 484 
 485                 }
 486 
 487                 // Remember where we left off in the flow stack:
 488                 info.setFlowStackIndex( flowStackIndex );
 489             }
 490             finally {
 491                 // The remaining points, ServantManager and Servant
 492                 // all run in the same logical thread.
 493                 current.popSlotTable( );
 494                 // Now TSC and RSC are equivalent.
 495             }
 496         } // end enabled check
 497     }
 498 
 499     /**
 500      * Invokes receive_request interception points
 501      */
 502     void invokeServerInterceptorIntermediatePoint(
 503         ServerRequestInfoImpl info )
 504     {
 505         int intermediatePointCall = info.getIntermediatePointCall();
 506         // If invocation is not yet enabled, don't do anything.
 507         if( enabled && ( intermediatePointCall !=
 508                          ServerRequestInfoImpl.CALL_INTERMEDIATE_NONE ) )
 509         {
 510             // NOTE: do not touch the slotStack.  The RSC and TSC are
 511             // equivalent at this point.
 512 
 513             info.setCurrentExecutionPoint( info.EXECUTION_POINT_INTERMEDIATE );
 514 
 515             // Get all ServerRequestInterceptors:
 516             ServerRequestInterceptor[] serverInterceptors =
 517                 (ServerRequestInterceptor[])
 518                 interceptorList.getInterceptors(
 519                 InterceptorList.INTERCEPTOR_TYPE_SERVER );
 520             int size = serverInterceptors.length;
 521 
 522             // Currently, there is only one server-side intermediate point
 523             // interceptor called receive_request.
 524             for( int i = 0; i < size; i++ ) {
 525 
 526                 try {
 527                     serverInterceptors[i].receive_request( info );
 528                 }
 529                 catch( ForwardRequest e ) {
 530 
 531                     // as per PI spec (orbos/99-12-02 sec 5.3.1.), if
 532                     // interception point throws a ForwardRequest,
 533                     // no other Interceptors' intermediate points are
 534                     // called and send_other is called.
 535                     info.setForwardRequest( e );
 536                     info.setEndingPointCall(
 537                         ServerRequestInfoImpl.CALL_SEND_OTHER );
 538                     info.setReplyStatus( LOCATION_FORWARD.value );
 539                     break;
 540                 }
 541                 catch( SystemException e ) {
 542 
 543                     // as per PI spec (orbos/99-12-02 sec 5.3.1.), if
 544                     // interception point throws a SystemException,
 545                     // no other Interceptors' starting points are
 546                     // called.
 547                     info.setException( e );
 548                     info.setEndingPointCall(
 549                         ServerRequestInfoImpl.CALL_SEND_EXCEPTION );
 550                     info.setReplyStatus( SYSTEM_EXCEPTION.value );
 551                     break;
 552                 }
 553             }
 554         } // end enabled check
 555     }
 556 
 557     /**
 558      * Invokes either send_reply, send_exception, or send_other,
 559      * depending on the value of info.getEndingPointCall()
 560      */
 561     void invokeServerInterceptorEndingPoint( ServerRequestInfoImpl info ) {
 562         // If invocation is not yet enabled, don't do anything.
 563         if( enabled ) {
 564             try {
 565                 // NOTE: do not touch the slotStack.  The RSC and TSC are
 566                 // equivalent at this point.
 567 
 568                 // REVISIT: This is moved out to PIHandlerImpl until dispatch
 569                 // path is rearchitected.  It must be there so that
 570                 // it always gets executed so if an interceptor raises
 571                 // an exception any service contexts added in earlier points
 572                 // this point get put in the exception reply (via the SC Q).
 573                 //info.setCurrentExecutionPoint( info.EXECUTION_POINT_ENDING );
 574 
 575                 // Get all ServerRequestInterceptors:
 576                 ServerRequestInterceptor[] serverInterceptors =
 577                     (ServerRequestInterceptor[])interceptorList.
 578                     getInterceptors( InterceptorList.INTERCEPTOR_TYPE_SERVER );
 579                 int flowStackIndex = info.getFlowStackIndex();
 580 
 581                 // Determine whether we are calling
 582                 // send_exception, or send_other:
 583                 int endingPointCall = info.getEndingPointCall();
 584 
 585                 // Only step through the interceptors whose starting points
 586                 // have successfully returned.
 587                 for( int i = (flowStackIndex - 1); i >= 0; i-- ) {
 588                     try {
 589                         switch( endingPointCall ) {
 590                         case ServerRequestInfoImpl.CALL_SEND_REPLY:
 591                             serverInterceptors[i].send_reply( info );
 592                             break;
 593                         case ServerRequestInfoImpl.CALL_SEND_EXCEPTION:
 594                             serverInterceptors[i].send_exception( info );
 595                             break;
 596                         case ServerRequestInfoImpl.CALL_SEND_OTHER:
 597                             serverInterceptors[i].send_other( info );
 598                             break;
 599                         }
 600                     }
 601                     catch( ForwardRequest e ) {
 602                         // as per PI spec (orbos/99-12-02 sec 5.3.1.), if
 603                         // interception point throws a ForwardException,
 604                         // ending point call changes to receive_other.
 605                         endingPointCall =
 606                             ServerRequestInfoImpl.CALL_SEND_OTHER;
 607                         info.setEndingPointCall( endingPointCall );
 608                         info.setForwardRequest( e );
 609                         info.setReplyStatus( LOCATION_FORWARD.value );
 610                         info.setForwardRequestRaisedInEnding();
 611                     }
 612                     catch( SystemException e ) {
 613                         // as per PI spec (orbos/99-12-02 sec 5.3.1.), if
 614                         // interception point throws a SystemException,
 615                         // ending point call changes to send_exception.
 616                         endingPointCall =
 617                             ServerRequestInfoImpl.CALL_SEND_EXCEPTION;
 618                         info.setEndingPointCall( endingPointCall );
 619                         info.setException( e );
 620                         info.setReplyStatus( SYSTEM_EXCEPTION.value );
 621                     }
 622                 }
 623 
 624                 // Remember that all interceptors' starting and ending points
 625                 // have already been executed so we need not do anything.
 626                 info.setAlreadyExecuted( true );
 627             }
 628             finally {
 629                 // Get rid of the Server side RSC.
 630                 current.popSlotTable();
 631             }
 632         } // end enabled check
 633     }
 634 
 635     /*
 636      **********************************************************************
 637      * Private utility methods
 638      **********************************************************************/
 639 
 640     /**
 641      * Update the client delegate in the event of a ForwardRequest, given the
 642      * information in the passed-in info object.
 643      */
 644     private void updateClientRequestDispatcherForward(
 645         ClientRequestInfoImpl info )
 646     {
 647         ForwardRequest forwardRequest = info.getForwardRequestException();
 648 
 649         // ForwardRequest may be null if the forwarded IOR is set internal
 650         // to the ClientRequestDispatcher rather than explicitly through Portable
 651         // Interceptors.  In this case, we need not update the client
 652         // delegate ForwardRequest object.
 653         if( forwardRequest != null ) {
 654             org.omg.CORBA.Object object = forwardRequest.forward;
 655 
 656             // Convert the forward object into an IOR:
 657             IOR ior = ORBUtility.getIOR( object ) ;
 658             info.setLocatedIOR( ior );
 659         }
 660     }
 661 
 662 }