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