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