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