1 /*
   2  * Copyright (c) 2002, 2010, 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.util.*;
  28 import java.io.IOException;
  29 
  30 import org.omg.CORBA.Any;
  31 import org.omg.CORBA.BAD_PARAM;
  32 import org.omg.CORBA.BAD_POLICY;
  33 import org.omg.CORBA.BAD_INV_ORDER;
  34 import org.omg.CORBA.COMM_FAILURE;
  35 import org.omg.CORBA.CompletionStatus;
  36 import org.omg.CORBA.INTERNAL;
  37 import org.omg.CORBA.NVList;
  38 import org.omg.CORBA.OBJECT_NOT_EXIST;
  39 import org.omg.CORBA.ORBPackage.InvalidName;
  40 import org.omg.CORBA.SystemException;
  41 import org.omg.CORBA.UserException;
  42 import org.omg.CORBA.UNKNOWN;
  43 
  44 import org.omg.CORBA.portable.ApplicationException;
  45 import org.omg.CORBA.portable.RemarshalException;
  46 
  47 import org.omg.IOP.CodecFactory;
  48 
  49 import org.omg.PortableInterceptor.ForwardRequest;
  50 import org.omg.PortableInterceptor.Current;
  51 import org.omg.PortableInterceptor.Interceptor;
  52 import org.omg.PortableInterceptor.LOCATION_FORWARD;
  53 import org.omg.PortableInterceptor.ORBInitializer;
  54 import org.omg.PortableInterceptor.ORBInitInfo;
  55 import org.omg.PortableInterceptor.ORBInitInfoPackage.DuplicateName;
  56 import org.omg.PortableInterceptor.SUCCESSFUL;
  57 import org.omg.PortableInterceptor.SYSTEM_EXCEPTION;
  58 import org.omg.PortableInterceptor.TRANSPORT_RETRY;
  59 import org.omg.PortableInterceptor.USER_EXCEPTION;
  60 import org.omg.PortableInterceptor.PolicyFactory;
  61 import org.omg.PortableInterceptor.ObjectReferenceTemplate ;
  62 
  63 import com.sun.corba.se.pept.encoding.OutputObject;
  64 
  65 import com.sun.corba.se.spi.ior.IOR;
  66 import com.sun.corba.se.spi.ior.ObjectKeyTemplate;
  67 import com.sun.corba.se.spi.oa.ObjectAdapter;
  68 import com.sun.corba.se.spi.orb.ORB;
  69 import com.sun.corba.se.spi.orbutil.closure.ClosureFactory;
  70 import com.sun.corba.se.spi.protocol.CorbaMessageMediator;
  71 import com.sun.corba.se.spi.protocol.ForwardException;
  72 import com.sun.corba.se.spi.protocol.PIHandler;
  73 import com.sun.corba.se.spi.protocol.RetryType;
  74 import com.sun.corba.se.spi.logging.CORBALogDomains;
  75 
  76 import com.sun.corba.se.impl.logging.InterceptorsSystemException;
  77 import com.sun.corba.se.impl.logging.ORBUtilSystemException;
  78 import com.sun.corba.se.impl.logging.OMGSystemException;
  79 import com.sun.corba.se.impl.corba.RequestImpl;
  80 import com.sun.corba.se.impl.orbutil.ORBClassLoader;
  81 import com.sun.corba.se.impl.orbutil.ORBConstants;
  82 import com.sun.corba.se.impl.orbutil.ORBUtility;
  83 import com.sun.corba.se.impl.orbutil.StackImpl;
  84 import com.sun.corba.se.impl.protocol.giopmsgheaders.ReplyMessage;
  85 
  86 /**
  87  * Provides portable interceptor functionality.
  88  */
  89 public class PIHandlerImpl implements PIHandler
  90 {
  91     // REVISIT - delete these after framework merging.
  92     boolean printPushPopEnabled = false;
  93     int pushLevel = 0;
  94     private void printPush()
  95     {
  96         if (! printPushPopEnabled) return;
  97         printSpaces(pushLevel);
  98         pushLevel++;
  99         System.out.println("PUSH");
 100     }
 101     private void printPop()
 102     {
 103         if (! printPushPopEnabled) return;
 104         pushLevel--;
 105         printSpaces(pushLevel);
 106         System.out.println("POP");
 107     }
 108     private void printSpaces(int n)
 109     {
 110         for (int i = 0; i < n; i++) {
 111             System.out.print(" ");
 112         }
 113     }
 114 
 115     private ORB orb ;
 116     InterceptorsSystemException wrapper ;
 117     ORBUtilSystemException orbutilWrapper ;
 118     OMGSystemException omgWrapper ;
 119 
 120     // A unique id used in ServerRequestInfo.
 121     // This does not correspond to the GIOP request id.
 122     private int serverRequestIdCounter = 0;
 123 
 124     // Stores the codec factory for producing codecs
 125     CodecFactory codecFactory = null;
 126 
 127     // The arguments passed to the application's main method.  May be null.
 128     // This is used for ORBInitializers and set from set_parameters.
 129     String[] arguments = null;
 130 
 131     // The list of portable interceptors, organized by type:
 132     private InterceptorList interceptorList;
 133 
 134     // Cached information for optimization - do we have any interceptors
 135     // registered of the given types?  Set during ORB initialization.
 136     private boolean hasIORInterceptors;
 137     private boolean hasClientInterceptors;  // temp always true
 138     private boolean hasServerInterceptors;
 139 
 140     // The class responsible for invoking interceptors
 141     private InterceptorInvoker interceptorInvoker;
 142 
 143     // There will be one PICurrent instantiated for every ORB.
 144     private PICurrent current;
 145 
 146     // This table contains a list of PolicyFactories registered using
 147     // ORBInitInfo.registerPolicyFactory() method.
 148     // Key for the table is PolicyType which is an Integer
 149     // Value is PolicyFactory.
 150     private HashMap policyFactoryTable;
 151 
 152     // Table to convert from a ReplyMessage.? to a PI replyStatus short.
 153     // Note that this table relies on the order and constants of
 154     // ReplyMessage not to change.
 155     private final static short REPLY_MESSAGE_TO_PI_REPLY_STATUS[] = {
 156         SUCCESSFUL.value,       // = ReplyMessage.NO_EXCEPTION
 157         USER_EXCEPTION.value,   // = ReplyMessage.USER_EXCEPTION
 158         SYSTEM_EXCEPTION.value, // = ReplyMessage.SYSTEM_EXCEPTION
 159         LOCATION_FORWARD.value, // = ReplyMessage.LOCATION_FORWARD
 160         LOCATION_FORWARD.value, // = ReplyMessage.LOCATION_FORWARD_PERM
 161         TRANSPORT_RETRY.value   // = ReplyMessage.NEEDS_ADDRESSING_MODE
 162     };
 163 
 164     // ThreadLocal containing a stack to store client request info objects
 165     // and a disable count.
 166     private ThreadLocal threadLocalClientRequestInfoStack =
 167         new ThreadLocal() {
 168             protected Object initialValue() {
 169                 return new RequestInfoStack();
 170             }
 171         };
 172 
 173     // ThreadLocal containing the current server request info object.
 174     private ThreadLocal threadLocalServerRequestInfoStack =
 175         new ThreadLocal() {
 176             protected Object initialValue() {
 177                 return new RequestInfoStack();
 178             }
 179         };
 180 
 181     // Class to contain all ThreadLocal data for ClientRequestInfo
 182     // maintenance.
 183     //
 184     // We use an ArrayList instead since it is not thread-safe.
 185     // RequestInfoStack is used quite frequently.
 186     private final class RequestInfoStack extends Stack {
 187         // Number of times a request has been made to disable interceptors.
 188         // When this reaches 0, interception hooks are disabled.  Any higher
 189         // value indicates they are enabled.
 190         // NOTE: The is only currently used on the client side.
 191         public int disableCount = 0;
 192     }
 193 
 194     public PIHandlerImpl( ORB orb, String[] args ) {
 195         this.orb = orb ;
 196         wrapper = InterceptorsSystemException.get( orb,
 197             CORBALogDomains.RPC_PROTOCOL ) ;
 198         orbutilWrapper = ORBUtilSystemException.get( orb,
 199             CORBALogDomains.RPC_PROTOCOL ) ;
 200         omgWrapper = OMGSystemException.get( orb,
 201             CORBALogDomains.RPC_PROTOCOL ) ;
 202         arguments = args ;
 203 
 204         // Create codec factory:
 205         codecFactory = new CodecFactoryImpl( orb );
 206 
 207         // Create new interceptor list:
 208         interceptorList = new InterceptorList( wrapper );
 209 
 210         // Create a new PICurrent.
 211         current = new PICurrent( orb );
 212 
 213         // Create new interceptor invoker, initially disabled:
 214         interceptorInvoker = new InterceptorInvoker( orb, interceptorList,
 215                                                      current );
 216 
 217         // Register the PI current and Codec factory objects
 218         orb.getLocalResolver().register( ORBConstants.PI_CURRENT_NAME,
 219             ClosureFactory.makeConstant( current ) ) ;
 220         orb.getLocalResolver().register( ORBConstants.CODEC_FACTORY_NAME,
 221             ClosureFactory.makeConstant( codecFactory ) ) ;
 222     }
 223 
 224     public void initialize() {
 225         // If we have any orb initializers, make use of them:
 226         if( orb.getORBData().getORBInitializers() != null ) {
 227             // Create the ORBInitInfo object to pass to ORB intializers:
 228             ORBInitInfoImpl orbInitInfo = createORBInitInfo();
 229 
 230             // Make sure get_slot and set_slot are not called from within
 231             // ORB initializers:
 232             current.setORBInitializing( true );
 233 
 234             // Call pre_init on all ORB initializers:
 235             preInitORBInitializers( orbInitInfo );
 236 
 237             // Call post_init on all ORB initializers:
 238             postInitORBInitializers( orbInitInfo );
 239 
 240             // Proprietary: sort interceptors:
 241             interceptorList.sortInterceptors();
 242 
 243             // Re-enable get_slot and set_slot to be called from within
 244             // ORB initializers:
 245             current.setORBInitializing( false );
 246 
 247             // Ensure nobody makes any more calls on this object.
 248             orbInitInfo.setStage( ORBInitInfoImpl.STAGE_CLOSED );
 249 
 250             // Set cached flags indicating whether we have interceptors
 251             // registered of a given type.
 252             hasIORInterceptors = interceptorList.hasInterceptorsOfType(
 253                 InterceptorList.INTERCEPTOR_TYPE_IOR );
 254             // XXX This must always be true, so that using the new generic
 255             // RPC framework can pass info between the PI stack and the
 256             // framework invocation stack.  Temporary until Harold fixes
 257             // this.  Note that this must never be true until after the
 258             // ORBInitializer instances complete executing.
 259             //hasClientInterceptors = interceptorList.hasInterceptorsOfType(
 260                 //InterceptorList.INTERCEPTOR_TYPE_CLIENT );
 261             hasClientInterceptors = true;
 262             hasServerInterceptors = interceptorList.hasInterceptorsOfType(
 263                 InterceptorList.INTERCEPTOR_TYPE_SERVER );
 264 
 265             // Enable interceptor invoker (not necessary if no interceptors
 266             // are registered).  This should be the last stage of ORB
 267             // initialization.
 268             interceptorInvoker.setEnabled( true );
 269         }
 270     }
 271 
 272     /**
 273      *  ptc/00-08-06 p 205: "When an application calls ORB::destroy, the ORB
 274      *  1) waits for all requests in progress to complete
 275      *  2) calls the Interceptor::destroy operation for each interceptor
 276      *  3) completes destruction of the ORB"
 277      *
 278      * This must be called at the end of ORB.destroy.  Note that this is not
 279      * part of the PIHandler interface, since ORBImpl implements the ORB interface.
 280      */
 281     public void destroyInterceptors() {
 282         interceptorList.destroyAll();
 283     }
 284 
 285     public void objectAdapterCreated( ObjectAdapter oa )
 286     {
 287         if (!hasIORInterceptors)
 288             return ;
 289 
 290         interceptorInvoker.objectAdapterCreated( oa ) ;
 291     }
 292 
 293     public void adapterManagerStateChanged( int managerId,
 294         short newState )
 295     {
 296         if (!hasIORInterceptors)
 297             return ;
 298 
 299         interceptorInvoker.adapterManagerStateChanged( managerId, newState ) ;
 300     }
 301 
 302     public void adapterStateChanged( ObjectReferenceTemplate[]
 303         templates, short newState )
 304     {
 305         if (!hasIORInterceptors)
 306             return ;
 307 
 308         interceptorInvoker.adapterStateChanged( templates, newState ) ;
 309     }
 310 
 311     /*
 312      *****************
 313      * Client PI hooks
 314      *****************/
 315 
 316     public void disableInterceptorsThisThread() {
 317         if( !hasClientInterceptors ) return;
 318 
 319         RequestInfoStack infoStack =
 320             (RequestInfoStack)threadLocalClientRequestInfoStack.get();
 321         infoStack.disableCount++;
 322     }
 323 
 324     public void enableInterceptorsThisThread() {
 325         if( !hasClientInterceptors ) return;
 326 
 327         RequestInfoStack infoStack =
 328             (RequestInfoStack)threadLocalClientRequestInfoStack.get();
 329         infoStack.disableCount--;
 330     }
 331 
 332     public void invokeClientPIStartingPoint()
 333         throws RemarshalException
 334     {
 335         if( !hasClientInterceptors ) return;
 336         if( !isClientPIEnabledForThisThread() ) return;
 337 
 338         // Invoke the starting interception points and record exception
 339         // and reply status info in the info object:
 340         ClientRequestInfoImpl info = peekClientRequestInfoImplStack();
 341         interceptorInvoker.invokeClientInterceptorStartingPoint( info );
 342 
 343         // Check reply status.  If we will not have another chance later
 344         // to invoke the client ending points, do it now.
 345         short replyStatus = info.getReplyStatus();
 346         if( (replyStatus == SYSTEM_EXCEPTION.value) ||
 347             (replyStatus == LOCATION_FORWARD.value) )
 348         {
 349             // Note: Transport retry cannot happen here since this happens
 350             // before the request hits the wire.
 351 
 352             Exception exception = invokeClientPIEndingPoint(
 353                 convertPIReplyStatusToReplyMessage( replyStatus ),
 354                 info.getException() );
 355             if( exception == null ) {
 356                 // Do not throw anything.  Otherwise, it must be a
 357                 // SystemException, UserException or RemarshalException.
 358             } if( exception instanceof SystemException ) {
 359                 throw (SystemException)exception;
 360             } else if( exception instanceof RemarshalException ) {
 361                 throw (RemarshalException)exception;
 362             } else if( (exception instanceof UserException) ||
 363                      (exception instanceof ApplicationException) ) {
 364                 // It should not be possible for an interceptor to throw
 365                 // a UserException.  By asserting instead of throwing the
 366                 // UserException, we need not declare anything but
 367                 // RemarshalException in the throws clause.
 368                 throw wrapper.exceptionInvalid() ;
 369             }
 370         }
 371         else if( replyStatus != ClientRequestInfoImpl.UNINITIALIZED ) {
 372             throw wrapper.replyStatusNotInit() ;
 373         }
 374     }
 375 
 376     // Needed when an error forces a retry AFTER initiateClientPIRequest
 377     // but BEFORE invokeClientPIStartingPoint.
 378     public Exception makeCompletedClientRequest( int replyStatus,
 379         Exception exception ) {
 380 
 381         // 6763340
 382         return handleClientPIEndingPoint( replyStatus, exception, false ) ;
 383     }
 384 
 385     public Exception invokeClientPIEndingPoint( int replyStatus,
 386         Exception exception ) {
 387 
 388         // 6763340
 389         return handleClientPIEndingPoint( replyStatus, exception, true ) ;
 390     }
 391 
 392     public Exception handleClientPIEndingPoint(
 393         int replyStatus, Exception exception, boolean invokeEndingPoint ) {
 394         if( !hasClientInterceptors ) return exception;
 395         if( !isClientPIEnabledForThisThread() ) return exception;
 396 
 397         // Translate ReplyMessage.replyStatus into PI replyStatus:
 398         // Note: this is also an assertion to make sure a valid replyStatus
 399         // is passed in (IndexOutOfBoundsException will be thrown otherwise)
 400         short piReplyStatus = REPLY_MESSAGE_TO_PI_REPLY_STATUS[replyStatus];
 401 
 402         // Invoke the ending interception points and record exception
 403         // and reply status info in the info object:
 404         ClientRequestInfoImpl info = peekClientRequestInfoImplStack();
 405         info.setReplyStatus( piReplyStatus );
 406         info.setException( exception );
 407 
 408         if (invokeEndingPoint) {
 409             // 6763340
 410             interceptorInvoker.invokeClientInterceptorEndingPoint( info );
 411             piReplyStatus = info.getReplyStatus();
 412         }
 413 
 414         // Check reply status:
 415         if( (piReplyStatus == LOCATION_FORWARD.value) ||
 416             (piReplyStatus == TRANSPORT_RETRY.value) ) {
 417             // If this is a forward or a retry, reset and reuse
 418             // info object:
 419             info.reset();
 420 
 421             // fix for 6763340:
 422             if (invokeEndingPoint) {
 423                 info.setRetryRequest( RetryType.AFTER_RESPONSE ) ;
 424             } else {
 425                 info.setRetryRequest( RetryType.BEFORE_RESPONSE ) ;
 426             }
 427 
 428             // ... and return a RemarshalException so the orb internals know
 429             exception = new RemarshalException();
 430         } else if( (piReplyStatus == SYSTEM_EXCEPTION.value) ||
 431                  (piReplyStatus == USER_EXCEPTION.value) ) {
 432             exception = info.getException();
 433         }
 434 
 435         return exception;
 436     }
 437 
 438     public void initiateClientPIRequest( boolean diiRequest ) {
 439         if( !hasClientInterceptors ) return;
 440         if( !isClientPIEnabledForThisThread() ) return;
 441 
 442         // Get the most recent info object from the thread local
 443         // ClientRequestInfoImpl stack:
 444         RequestInfoStack infoStack =
 445             (RequestInfoStack)threadLocalClientRequestInfoStack.get();
 446         ClientRequestInfoImpl info = null;
 447 
 448         if (!infoStack.empty() ) {
 449             info = (ClientRequestInfoImpl)infoStack.peek();
 450         }
 451 
 452         if (!diiRequest && (info != null) && info.isDIIInitiate() ) {
 453             // In RequestImpl.doInvocation we already called
 454             // initiateClientPIRequest( true ), so ignore this initiate.
 455             info.setDIIInitiate( false );
 456         } else {
 457             // If there is no info object or if we are not retrying a request,
 458             // push a new ClientRequestInfoImpl on the stack:
 459 
 460             // 6763340: don't push unless this is not a retry
 461             if( (info == null) || !info.getRetryRequest().isRetry() ) {
 462                 info = new ClientRequestInfoImpl( orb );
 463                 infoStack.push( info );
 464                 printPush();
 465                 // Note: the entry count is automatically initialized to 0.
 466             }
 467 
 468             // Reset the retry request flag so that recursive calls will
 469             // push a new info object, and bump up entry count so we know
 470             // when to pop this info object:
 471             info.setRetryRequest( RetryType.NONE );
 472             info.incrementEntryCount();
 473 
 474             // KMC 6763340: I don't know why this wasn't set earlier,
 475             // but we do not want a retry to pick up the previous
 476             // reply status, so clear it here.  Most likely a new
 477             // info was pushed before, so that this was not a problem.
 478             info.setReplyStatus( RequestInfoImpl.UNINITIALIZED ) ;
 479 
 480             // If this is a DII request, make sure we ignore the next initiate.
 481             if( diiRequest ) {
 482                 info.setDIIInitiate( true );
 483             }
 484         }
 485     }
 486 
 487     public void cleanupClientPIRequest() {
 488         if( !hasClientInterceptors ) return;
 489         if( !isClientPIEnabledForThisThread() ) return;
 490 
 491         ClientRequestInfoImpl info = peekClientRequestInfoImplStack();
 492         RetryType rt = info.getRetryRequest() ;
 493 
 494         // fix for 6763340
 495         if (!rt.equals( RetryType.BEFORE_RESPONSE )) {
 496 
 497             // If the replyStatus has not yet been set, this is an indication
 498             // that the ORB threw an exception before we had a chance to
 499             // invoke the client interceptor ending points.
 500             //
 501             // _REVISIT_ We cannot handle any exceptions or ForwardRequests
 502             // flagged by the ending points here because there is no way
 503             // to gracefully handle this in any of the calling code.
 504             // This is a rare corner case, so we will ignore this for now.
 505             short replyStatus = info.getReplyStatus();
 506             if (replyStatus == info.UNINITIALIZED ) {
 507                 invokeClientPIEndingPoint( ReplyMessage.SYSTEM_EXCEPTION,
 508                     wrapper.unknownRequestInvoke(
 509                         CompletionStatus.COMPLETED_MAYBE ) ) ;
 510             }
 511         }
 512 
 513         // Decrement entry count, and if it is zero, pop it from the stack.
 514         info.decrementEntryCount();
 515 
 516         // fix for 6763340, and probably other cases (non-recursive retry)
 517         if (info.getEntryCount() == 0 && !info.getRetryRequest().isRetry()) {
 518             // RequestInfoStack<ClientRequestInfoImpl> infoStack =
 519             //     threadLocalClientRequestInfoStack.get();
 520             RequestInfoStack infoStack =
 521                 (RequestInfoStack)threadLocalClientRequestInfoStack.get();
 522             infoStack.pop();
 523             printPop();
 524         }
 525     }
 526 
 527     public void setClientPIInfo(CorbaMessageMediator messageMediator)
 528     {
 529         if( !hasClientInterceptors ) return;
 530         if( !isClientPIEnabledForThisThread() ) return;
 531 
 532         peekClientRequestInfoImplStack().setInfo(messageMediator);
 533     }
 534 
 535     public void setClientPIInfo( RequestImpl requestImpl ) {
 536         if( !hasClientInterceptors ) return;
 537         if( !isClientPIEnabledForThisThread() ) return;
 538 
 539         peekClientRequestInfoImplStack().setDIIRequest( requestImpl );
 540     }
 541 
 542     /*
 543      *****************
 544      * Server PI hooks
 545      *****************/
 546 
 547     public void invokeServerPIStartingPoint()
 548     {
 549         if( !hasServerInterceptors ) return;
 550 
 551         ServerRequestInfoImpl info = peekServerRequestInfoImplStack();
 552         interceptorInvoker.invokeServerInterceptorStartingPoint( info );
 553 
 554         // Handle SystemException or ForwardRequest:
 555         serverPIHandleExceptions( info );
 556     }
 557 
 558     public void invokeServerPIIntermediatePoint()
 559     {
 560         if( !hasServerInterceptors ) return;
 561 
 562         ServerRequestInfoImpl info = peekServerRequestInfoImplStack();
 563         interceptorInvoker.invokeServerInterceptorIntermediatePoint( info );
 564 
 565         // Clear servant from info object so that the user has control over
 566         // its lifetime:
 567         info.releaseServant();
 568 
 569         // Handle SystemException or ForwardRequest:
 570         serverPIHandleExceptions( info );
 571     }
 572 
 573     public void invokeServerPIEndingPoint( ReplyMessage replyMessage )
 574     {
 575         if( !hasServerInterceptors ) return;
 576         ServerRequestInfoImpl info = peekServerRequestInfoImplStack();
 577 
 578         // REVISIT: This needs to be done "early" for the following workaround.
 579         info.setReplyMessage( replyMessage );
 580 
 581         // REVISIT: This was done inside of invokeServerInterceptorEndingPoint
 582         // but needs to be here for now.  See comment in that method for why.
 583         info.setCurrentExecutionPoint( info.EXECUTION_POINT_ENDING );
 584 
 585         // It is possible we might have entered this method more than
 586         // once (e.g. if an ending point threw a SystemException, then
 587         // a new ServerResponseImpl is created).
 588         if( !info.getAlreadyExecuted() ) {
 589             int replyStatus = replyMessage.getReplyStatus();
 590 
 591             // Translate ReplyMessage.replyStatus into PI replyStatus:
 592             // Note: this is also an assertion to make sure a valid
 593             // replyStatus is passed in (IndexOutOfBoundsException will be
 594             // thrown otherwise)
 595             short piReplyStatus =
 596                 REPLY_MESSAGE_TO_PI_REPLY_STATUS[replyStatus];
 597 
 598             // Make forwarded IOR available to interceptors, if applicable:
 599             if( ( piReplyStatus == LOCATION_FORWARD.value ) ||
 600                 ( piReplyStatus == TRANSPORT_RETRY.value ) )
 601             {
 602                 info.setForwardRequest( replyMessage.getIOR() );
 603             }
 604 
 605             // REVISIT: Do early above for now.
 606             // Make reply message available to interceptors:
 607             //info.setReplyMessage( replyMessage );
 608 
 609             // Remember exception so we can tell if an interceptor changed it.
 610             Exception prevException = info.getException();
 611 
 612             // _REVISIT_ We do not have access to the User Exception at
 613             // this point, so treat it as an UNKNOWN for now.
 614             // Note that if this is a DSI call, we do have the user exception.
 615             if( !info.isDynamic() &&
 616                 (piReplyStatus == USER_EXCEPTION.value) )
 617             {
 618                 info.setException( omgWrapper.unknownUserException(
 619                     CompletionStatus.COMPLETED_MAYBE ) ) ;
 620             }
 621 
 622             // Invoke the ending interception points:
 623             info.setReplyStatus( piReplyStatus );
 624             interceptorInvoker.invokeServerInterceptorEndingPoint( info );
 625             short newPIReplyStatus = info.getReplyStatus();
 626             Exception newException = info.getException();
 627 
 628             // Check reply status.  If an interceptor threw a SystemException
 629             // and it is different than the one that we came in with,
 630             // rethrow it so the proper response can be constructed:
 631             if( ( newPIReplyStatus == SYSTEM_EXCEPTION.value ) &&
 632                 ( newException != prevException ) )
 633             {
 634                 throw (SystemException)newException;
 635             }
 636 
 637             // If we are to forward the location:
 638             if( newPIReplyStatus == LOCATION_FORWARD.value ) {
 639                 if( piReplyStatus != LOCATION_FORWARD.value ) {
 640                     // Treat a ForwardRequest as a ForwardException.
 641                     IOR ior = info.getForwardRequestIOR();
 642                     throw new ForwardException( orb, ior ) ;
 643                 }
 644                 else if( info.isForwardRequestRaisedInEnding() ) {
 645                     // Treat a ForwardRequest by changing the IOR.
 646                     replyMessage.setIOR( info.getForwardRequestIOR() );
 647                 }
 648             }
 649         }
 650     }
 651 
 652     public void setServerPIInfo( Exception exception ) {
 653         if( !hasServerInterceptors ) return;
 654 
 655         ServerRequestInfoImpl info = peekServerRequestInfoImplStack();
 656         info.setException( exception );
 657     }
 658 
 659     public void setServerPIInfo( NVList arguments )
 660     {
 661         if( !hasServerInterceptors ) return;
 662 
 663         ServerRequestInfoImpl info = peekServerRequestInfoImplStack();
 664         info.setDSIArguments( arguments );
 665     }
 666 
 667     public void setServerPIExceptionInfo( Any exception )
 668     {
 669         if( !hasServerInterceptors ) return;
 670 
 671         ServerRequestInfoImpl info = peekServerRequestInfoImplStack();
 672         info.setDSIException( exception );
 673     }
 674 
 675     public void setServerPIInfo( Any result )
 676     {
 677         if( !hasServerInterceptors ) return;
 678 
 679         ServerRequestInfoImpl info = peekServerRequestInfoImplStack();
 680         info.setDSIResult( result );
 681     }
 682 
 683     public void initializeServerPIInfo( CorbaMessageMediator request,
 684         ObjectAdapter oa, byte[] objectId, ObjectKeyTemplate oktemp )
 685     {
 686         if( !hasServerInterceptors ) return;
 687 
 688         RequestInfoStack infoStack =
 689             (RequestInfoStack)threadLocalServerRequestInfoStack.get();
 690         ServerRequestInfoImpl info = new ServerRequestInfoImpl( orb );
 691         infoStack.push( info );
 692         printPush();
 693 
 694         // Notify request object that once response is constructed, make
 695         // sure we execute ending points.
 696         request.setExecutePIInResponseConstructor( true );
 697 
 698         info.setInfo( request, oa, objectId, oktemp );
 699     }
 700 
 701     public void setServerPIInfo( java.lang.Object servant,
 702                                           String targetMostDerivedInterface )
 703     {
 704         if( !hasServerInterceptors ) return;
 705 
 706         ServerRequestInfoImpl info = peekServerRequestInfoImplStack();
 707         info.setInfo( servant, targetMostDerivedInterface );
 708     }
 709 
 710     public void cleanupServerPIRequest() {
 711         if( !hasServerInterceptors ) return;
 712 
 713         RequestInfoStack infoStack =
 714             (RequestInfoStack)threadLocalServerRequestInfoStack.get();
 715         infoStack.pop();
 716         printPop();
 717     }
 718 
 719     /*
 720      **********************************************************************
 721      *  The following methods are private utility methods.
 722      ************************************************************************/
 723 
 724     /**
 725      * Handles exceptions for the starting and intermediate points for
 726      * server request interceptors.  This is common code that has been
 727      * factored out into this utility method.
 728      * <p>
 729      * This method will NOT work for ending points.
 730      */
 731     private void serverPIHandleExceptions( ServerRequestInfoImpl info )
 732     {
 733         int endingPointCall = info.getEndingPointCall();
 734         if(endingPointCall == ServerRequestInfoImpl.CALL_SEND_EXCEPTION) {
 735             // If a system exception was thrown, throw it to caller:
 736             throw (SystemException)info.getException();
 737         }
 738         else if( (endingPointCall == ServerRequestInfoImpl.CALL_SEND_OTHER) &&
 739                  (info.getForwardRequestException() != null) )
 740         {
 741             // If an interceptor throws a forward request, convert it
 742             // into a ForwardException for easier handling:
 743             IOR ior = info.getForwardRequestIOR();
 744             throw new ForwardException( orb, ior );
 745         }
 746     }
 747 
 748     /**
 749      * Utility method to convert a PI reply status short to a ReplyMessage
 750      * constant.  This is a reverse lookup on the table defined in
 751      * REPLY_MESSAGE_TO_PI_REPLY_STATUS.  The reverse lookup need not be
 752      * performed as quickly since it is only executed in exception
 753      * conditions.
 754      */
 755     private int convertPIReplyStatusToReplyMessage( short replyStatus ) {
 756         int result = 0;
 757         for( int i = 0; i < REPLY_MESSAGE_TO_PI_REPLY_STATUS.length; i++ ) {
 758             if( REPLY_MESSAGE_TO_PI_REPLY_STATUS[i] == replyStatus ) {
 759                 result = i;
 760                 break;
 761             }
 762         }
 763         return result;
 764     }
 765 
 766     /**
 767      * Convenience method to get the ClientRequestInfoImpl object off the
 768      * top of the ThreadLocal stack.  Throws an INTERNAL exception if
 769      * the Info stack is empty.
 770      */
 771     private ClientRequestInfoImpl peekClientRequestInfoImplStack() {
 772         RequestInfoStack infoStack =
 773             (RequestInfoStack)threadLocalClientRequestInfoStack.get();
 774         ClientRequestInfoImpl info = null;
 775         if( !infoStack.empty() ) {
 776             info = (ClientRequestInfoImpl)infoStack.peek();
 777         } else {
 778             throw wrapper.clientInfoStackNull() ;
 779         }
 780 
 781         return info;
 782     }
 783 
 784     /**
 785      * Convenience method to get the ServerRequestInfoImpl object off the
 786      * top of the ThreadLocal stack.  Returns null if there are none.
 787      */
 788     private ServerRequestInfoImpl peekServerRequestInfoImplStack() {
 789         RequestInfoStack infoStack =
 790             (RequestInfoStack)threadLocalServerRequestInfoStack.get();
 791         ServerRequestInfoImpl info = null;
 792 
 793         if( !infoStack.empty() ) {
 794             info = (ServerRequestInfoImpl)infoStack.peek();
 795         } else {
 796             throw wrapper.serverInfoStackNull() ;
 797         }
 798 
 799         return info;
 800     }
 801 
 802     /**
 803      * Convenience method to determine whether Client PI is enabled
 804      * for requests on this thread.
 805      */
 806     private boolean isClientPIEnabledForThisThread() {
 807         RequestInfoStack infoStack =
 808             (RequestInfoStack)threadLocalClientRequestInfoStack.get();
 809         return (infoStack.disableCount == 0);
 810     }
 811 
 812     /**
 813      * Call pre_init on all ORB initializers
 814      */
 815     private void preInitORBInitializers( ORBInitInfoImpl info ) {
 816 
 817         // Inform ORBInitInfo we are in pre_init stage
 818         info.setStage( ORBInitInfoImpl.STAGE_PRE_INIT );
 819 
 820         // Step through each initializer instantiation and call its
 821         // pre_init.  Ignore any exceptions.
 822         for( int i = 0; i < orb.getORBData().getORBInitializers().length;
 823             i++ ) {
 824             ORBInitializer init = orb.getORBData().getORBInitializers()[i];
 825             if( init != null ) {
 826                 try {
 827                     init.pre_init( info );
 828                 }
 829                 catch( Exception e ) {
 830                     // As per orbos/99-12-02, section 9.3.1.2, "If there are
 831                     // any exceptions, the ORB shall ignore them and proceed."
 832                 }
 833             }
 834         }
 835     }
 836 
 837     /**
 838      * Call post_init on all ORB initializers
 839      */
 840     private void postInitORBInitializers( ORBInitInfoImpl info ) {
 841 
 842         // Inform ORBInitInfo we are in post_init stage
 843         info.setStage( ORBInitInfoImpl.STAGE_POST_INIT );
 844 
 845         // Step through each initializer instantiation and call its post_init.
 846         // Ignore any exceptions.
 847         for( int i = 0; i < orb.getORBData().getORBInitializers().length;
 848             i++ ) {
 849             ORBInitializer init = orb.getORBData().getORBInitializers()[i];
 850             if( init != null ) {
 851                 try {
 852                     init.post_init( info );
 853                 }
 854                 catch( Exception e ) {
 855                     // As per orbos/99-12-02, section 9.3.1.2, "If there are
 856                     // any exceptions, the ORB shall ignore them and proceed."
 857                 }
 858             }
 859         }
 860     }
 861 
 862     /**
 863      * Creates the ORBInitInfo object to be passed to ORB intializers'
 864      * pre_init and post_init methods
 865      */
 866     private ORBInitInfoImpl createORBInitInfo() {
 867         ORBInitInfoImpl result = null;
 868 
 869         // arguments comes from set_parameters.  May be null.
 870 
 871         // _REVISIT_ The spec does not specify which ID this is to be.
 872         // We currently get this from the corba.ORB, which reads it from
 873         // the ORB_ID_PROPERTY property.
 874         String orbId = orb.getORBData().getORBId() ;
 875 
 876         result = new ORBInitInfoImpl( orb, arguments, orbId, codecFactory );
 877 
 878         return result;
 879     }
 880 
 881     /**
 882      * Called by ORBInitInfo when an interceptor needs to be registered.
 883      * The type is one of:
 884      * <ul>
 885      *   <li>INTERCEPTOR_TYPE_CLIENT - ClientRequestInterceptor
 886      *   <li>INTERCEPTOR_TYPE_SERVER - ServerRequestInterceptor
 887      *   <li>INTERCEPTOR_TYPE_IOR - IORInterceptor
 888      * </ul>
 889      *
 890      * @exception DuplicateName Thrown if an interceptor of the given
 891      *     name already exists for the given type.
 892      */
 893     public void register_interceptor( Interceptor interceptor, int type )
 894         throws DuplicateName
 895     {
 896         // We will assume interceptor is not null, since it is called
 897         // internally.
 898         if( (type >= InterceptorList.NUM_INTERCEPTOR_TYPES) || (type < 0) ) {
 899             throw wrapper.typeOutOfRange( new Integer( type ) ) ;
 900         }
 901 
 902         String interceptorName = interceptor.name();
 903 
 904         if( interceptorName == null ) {
 905             throw wrapper.nameNull() ;
 906         }
 907 
 908         // Register with interceptor list:
 909         interceptorList.register_interceptor( interceptor, type );
 910     }
 911 
 912     public Current getPICurrent( ) {
 913         return current;
 914     }
 915 
 916     /**
 917      * Called when an invalid null parameter was passed.  Throws a
 918      * BAD_PARAM with a minor code of 1
 919      */
 920     private void nullParam()
 921         throws BAD_PARAM
 922     {
 923         throw orbutilWrapper.nullParam() ;
 924     }
 925 
 926     /** This is the implementation of standard API defined in org.omg.CORBA.ORB
 927      *  class. This method finds the Policy Factory for the given Policy Type
 928      *  and instantiates the Policy object from the Factory. It will throw
 929      *  PolicyError exception, If the PolicyFactory for the given type is
 930      *  not registered.
 931      *  _REVISIT_, Once Policy Framework work is completed, Reorganize
 932      *  this method to com.sun.corba.se.spi.orb.ORB.
 933      */
 934     public org.omg.CORBA.Policy create_policy(int type, org.omg.CORBA.Any val)
 935         throws org.omg.CORBA.PolicyError
 936     {
 937         if( val == null ) {
 938             nullParam( );
 939         }
 940         if( policyFactoryTable == null ) {
 941             throw new org.omg.CORBA.PolicyError(
 942                 "There is no PolicyFactory Registered for type " + type,
 943                 BAD_POLICY.value );
 944         }
 945         PolicyFactory factory = (PolicyFactory)policyFactoryTable.get(
 946             new Integer(type) );
 947         if( factory == null ) {
 948             throw new org.omg.CORBA.PolicyError(
 949                 " Could Not Find PolicyFactory for the Type " + type,
 950                 BAD_POLICY.value);
 951         }
 952         org.omg.CORBA.Policy policy = factory.create_policy( type, val );
 953         return policy;
 954     }
 955 
 956     /** This method registers the Policy Factory in the policyFactoryTable,
 957      *  which is a HashMap. This method is made package private, because
 958      *  it is used internally by the  Interceptors.
 959      */
 960     public void registerPolicyFactory( int type, PolicyFactory factory ) {
 961         if( policyFactoryTable == null ) {
 962             policyFactoryTable = new HashMap();
 963         }
 964         Integer key = new Integer( type );
 965         java.lang.Object val = policyFactoryTable.get( key );
 966         if( val == null ) {
 967             policyFactoryTable.put( key, factory );
 968         }
 969         else {
 970             throw omgWrapper.policyFactoryRegFailed( new Integer( type ) ) ;
 971         }
 972     }
 973 
 974     public synchronized int allocateServerRequestId ()
 975     {
 976         return serverRequestIdCounter++;
 977     }
 978 }