/* * @(#)InterceptorInvoker.java 1.32 03/12/19 * * Copyright 2004 Sun Microsystems, Inc. All rights reserved. * SUN PROPRIETARY/CONFIDENTIAL. Use is subject to license terms. */ package com.sun.corba.se.impl.interceptors; import org.omg.CORBA.CompletionStatus; import org.omg.CORBA.INTERNAL; import org.omg.CORBA.SystemException; import org.omg.CORBA.portable.Delegate; import org.omg.PortableInterceptor.LOCATION_FORWARD; import org.omg.PortableInterceptor.SUCCESSFUL; import org.omg.PortableInterceptor.SYSTEM_EXCEPTION; import org.omg.PortableInterceptor.TRANSPORT_RETRY; import org.omg.PortableInterceptor.USER_EXCEPTION; import org.omg.PortableInterceptor.ClientRequestInfo; import org.omg.PortableInterceptor.ClientRequestInterceptor; import org.omg.PortableInterceptor.ForwardRequest; import org.omg.PortableInterceptor.IORInterceptor; import org.omg.PortableInterceptor.IORInterceptor_3_0; import org.omg.PortableInterceptor.ServerRequestInfo; import org.omg.PortableInterceptor.ServerRequestInterceptor; import org.omg.PortableInterceptor.ObjectReferenceTemplate; import com.sun.corba.se.spi.ior.IOR; import com.sun.corba.se.spi.oa.ObjectAdapter; import com.sun.corba.se.spi.orb.ORB; import com.sun.corba.se.impl.orbutil.ORBUtility; /** * Handles invocation of interceptors. Has specific knowledge of how to * invoke IOR, ClientRequest, and ServerRequest interceptors. * Makes use of the InterceptorList to retrieve the list of interceptors to * be invoked. Most methods in this class are package scope so that they * may only be called from the PIHandlerImpl. */ public class InterceptorInvoker { // The ORB private ORB orb; // The list of interceptors to be invoked private InterceptorList interceptorList; // True if interceptors are to be invoked, or false if not // Note: This is a global enable/disable flag, whereas the enable flag // in the RequestInfoStack in PIHandlerImpl is only for a particular Thread. private boolean enabled = false; // PICurrent variable. private PICurrent current; // NOTE: Be careful about adding additional attributes to this class. // Multiple threads may be calling methods on this invoker at the same // time. /** * Creates a new Interceptor Invoker. Constructor is package scope so * only the ORB can create it. The invoker is initially disabled, and * must be explicitly enabled using setEnabled(). */ InterceptorInvoker( ORB orb, InterceptorList interceptorList, PICurrent piCurrent ) { this.orb = orb; this.interceptorList = interceptorList; this.enabled = false; this.current = piCurrent; } /** * Enables or disables the interceptor invoker */ void setEnabled( boolean enabled ) { this.enabled = enabled; } /* ********************************************************************** * IOR Interceptor invocation **********************************************************************/ /** * Called when a new POA is created. * * @param oa The Object Adapter associated with the IOR interceptor. */ void objectAdapterCreated( ObjectAdapter oa ) { // If invocation is not yet enabled, don't do anything. if( enabled ) { // Create IORInfo object to pass to IORInterceptors: IORInfoImpl info = new IORInfoImpl( oa ); // Call each IORInterceptor: IORInterceptor[] iorInterceptors = (IORInterceptor[])interceptorList.getInterceptors( InterceptorList.INTERCEPTOR_TYPE_IOR ); int size = iorInterceptors.length; // Implementation note: // This loop counts backwards for greater efficiency. // Benchmarks have shown that counting down is more efficient // than counting up in Java for loops, as a compare to zero is // faster than a subtract and compare to zero. In this case, // it doesn't really matter much, but it's simply a force of habit. for( int i = (size - 1); i >= 0; i-- ) { IORInterceptor interceptor = iorInterceptors[i]; try { interceptor.establish_components( info ); } catch( Exception e ) { // as per PI spec (orbos/99-12-02 sec 7.2.1), if // establish_components throws an exception, ignore it. } } // Change the state so that only template operations are valid info.makeStateEstablished() ; for( int i = (size - 1); i >= 0; i-- ) { IORInterceptor interceptor = iorInterceptors[i]; if (interceptor instanceof IORInterceptor_3_0) { IORInterceptor_3_0 interceptor30 = (IORInterceptor_3_0)interceptor ; // Note that exceptions here are NOT ignored, as per the // ORT spec (orbos/01-01-04) interceptor30.components_established( info ); } } // Change the state so that no operations are valid, // in case a reference to info escapes this scope. // This also completes the actions associated with the // template interceptors on this POA. info.makeStateDone() ; } } void adapterManagerStateChanged( int managerId, short newState ) { if (enabled) { IORInterceptor[] interceptors = (IORInterceptor[])interceptorList.getInterceptors( InterceptorList.INTERCEPTOR_TYPE_IOR ); int size = interceptors.length; for( int i = (size - 1); i >= 0; i-- ) { try { IORInterceptor interceptor = interceptors[i]; if (interceptor instanceof IORInterceptor_3_0) { IORInterceptor_3_0 interceptor30 = (IORInterceptor_3_0)interceptor ; interceptor30.adapter_manager_state_changed( managerId, newState ); } } catch (Exception exc) { // No-op: ignore exception in this case } } } } void adapterStateChanged( ObjectReferenceTemplate[] templates, short newState ) { if (enabled) { IORInterceptor[] interceptors = (IORInterceptor[])interceptorList.getInterceptors( InterceptorList.INTERCEPTOR_TYPE_IOR ); int size = interceptors.length; for( int i = (size - 1); i >= 0; i-- ) { try { IORInterceptor interceptor = interceptors[i]; if (interceptor instanceof IORInterceptor_3_0) { IORInterceptor_3_0 interceptor30 = (IORInterceptor_3_0)interceptor ; interceptor30.adapter_state_changed( templates, newState ); } } catch (Exception exc) { // No-op: ignore exception in this case } } } } /* ********************************************************************** * Client Interceptor invocation **********************************************************************/ /** * Invokes either send_request, or send_poll, depending on the value * of info.getStartingPointCall() */ void invokeClientInterceptorStartingPoint( ClientRequestInfoImpl info ) { // If invocation is not yet enabled, don't do anything. if( enabled ) { try { // Make a a fresh slot table available to TSC in case // interceptors need to make out calls. // Client's TSC is now RSC via RequestInfo. current.pushSlotTable( ); info.setPICurrentPushed( true ); info.setCurrentExecutionPoint( info.EXECUTION_POINT_STARTING ); // Get all ClientRequestInterceptors: ClientRequestInterceptor[] clientInterceptors = (ClientRequestInterceptor[])interceptorList. getInterceptors( InterceptorList.INTERCEPTOR_TYPE_CLIENT ); int size = clientInterceptors.length; // We will assume that all interceptors returned successfully, // and adjust the flowStackIndex to the appropriate value if // we later discover otherwise. int flowStackIndex = size; boolean continueProcessing = true; // Determine whether we are calling send_request or send_poll: // (This is currently commented out because our ORB does not // yet support the Messaging specification, so send_poll will // never occur. Once we have implemented messaging, this may // be uncommented.) // int startingPointCall = info.getStartingPointCall(); for( int i = 0; continueProcessing && (i < size); i++ ) { try { clientInterceptors[i].send_request( info ); // Again, it is not necessary for a switch here, since // there is only one starting point call type (see // above comment). //switch( startingPointCall ) { //case ClientRequestInfoImpl.CALL_SEND_REQUEST: //clientInterceptors[i].send_request( info ); //break; //case ClientRequestInfoImpl.CALL_SEND_POLL: //clientInterceptors[i].send_poll( info ); //break; //} } catch( ForwardRequest e ) { // as per PI spec (orbos/99-12-02 sec 5.2.1.), if // interception point throws a ForwardRequest, // no other Interceptors' send_request operations are // called. flowStackIndex = i; info.setForwardRequest( e ); info.setEndingPointCall( ClientRequestInfoImpl.CALL_RECEIVE_OTHER ); info.setReplyStatus( LOCATION_FORWARD.value ); updateClientRequestDispatcherForward( info ); // For some reason, using break here causes the VM on // NT to lose track of the value of flowStackIndex // after exiting the for loop. I changed this to // check a boolean value instead and it seems to work // fine. continueProcessing = false; } catch( SystemException e ) { // as per PI spec (orbos/99-12-02 sec 5.2.1.), if // interception point throws a SystemException, // no other Interceptors' send_request operations are // called. flowStackIndex = i; info.setEndingPointCall( ClientRequestInfoImpl.CALL_RECEIVE_EXCEPTION ); info.setReplyStatus( SYSTEM_EXCEPTION.value ); info.setException( e ); // For some reason, using break here causes the VM on // NT to lose track of the value of flowStackIndex // after exiting the for loop. I changed this to // check a boolean value instead and it seems to // work fine. continueProcessing = false; } } // Remember where we left off in the flow stack: info.setFlowStackIndex( flowStackIndex ); } finally { // Make the SlotTable fresh for the next interception point. current.resetSlotTable( ); } } // end enabled check } /** * Invokes either receive_reply, receive_exception, or receive_other, * depending on the value of info.getEndingPointCall() */ void invokeClientInterceptorEndingPoint( ClientRequestInfoImpl info ) { // If invocation is not yet enabled, don't do anything. if( enabled ) { try { // NOTE: It is assumed someplace else prepared a // fresh TSC slot table. info.setCurrentExecutionPoint( info.EXECUTION_POINT_ENDING ); // Get all ClientRequestInterceptors: ClientRequestInterceptor[] clientInterceptors = (ClientRequestInterceptor[])interceptorList. getInterceptors( InterceptorList.INTERCEPTOR_TYPE_CLIENT ); int flowStackIndex = info.getFlowStackIndex(); // Determine whether we are calling receive_reply, // receive_exception, or receive_other: int endingPointCall = info.getEndingPointCall(); // If we would be calling RECEIVE_REPLY, but this is a // one-way call, override this and call receive_other: if( ( endingPointCall == ClientRequestInfoImpl.CALL_RECEIVE_REPLY ) && info.getIsOneWay() ) { endingPointCall = ClientRequestInfoImpl.CALL_RECEIVE_OTHER; info.setEndingPointCall( endingPointCall ); } // Only step through the interceptors whose starting points // have successfully returned. // Unlike the previous loop, this one counts backwards for a // reason - we must execute these in the reverse order of the // starting points. for( int i = (flowStackIndex - 1); i >= 0; i-- ) { try { switch( endingPointCall ) { case ClientRequestInfoImpl.CALL_RECEIVE_REPLY: clientInterceptors[i].receive_reply( info ); break; case ClientRequestInfoImpl.CALL_RECEIVE_EXCEPTION: clientInterceptors[i].receive_exception( info ); break; case ClientRequestInfoImpl.CALL_RECEIVE_OTHER: clientInterceptors[i].receive_other( info ); break; } } catch( ForwardRequest e ) { // as per PI spec (orbos/99-12-02 sec 5.2.1.), if // interception point throws a ForwardException, // ending point call changes to receive_other. endingPointCall = ClientRequestInfoImpl.CALL_RECEIVE_OTHER; info.setEndingPointCall( endingPointCall ); info.setReplyStatus( LOCATION_FORWARD.value ); info.setForwardRequest( e ); updateClientRequestDispatcherForward( info ); } catch( SystemException e ) { // as per PI spec (orbos/99-12-02 sec 5.2.1.), if // interception point throws a SystemException, // ending point call changes to receive_exception. endingPointCall = ClientRequestInfoImpl.CALL_RECEIVE_EXCEPTION; info.setEndingPointCall( endingPointCall ); info.setReplyStatus( SYSTEM_EXCEPTION.value ); info.setException( e ); } } } finally { // See doc for setPICurrentPushed as to why this is necessary. // Check info for null in case errors happen before initiate. if (info != null && info.isPICurrentPushed()) { current.popSlotTable( ); // After the pop, original client's TSC slot table // remains avaiable via PICurrent. } } } // end enabled check } /* ********************************************************************** * Server Interceptor invocation **********************************************************************/ /** * Invokes receive_request_service_context interception points. */ void invokeServerInterceptorStartingPoint( ServerRequestInfoImpl info ) { // If invocation is not yet enabled, don't do anything. if( enabled ) { try { // Make a fresh slot table for RSC. current.pushSlotTable(); info.setSlotTable(current.getSlotTable()); // Make a fresh slot table for TSC in case // interceptors need to make out calls. current.pushSlotTable( ); info.setCurrentExecutionPoint( info.EXECUTION_POINT_STARTING ); // Get all ServerRequestInterceptors: ServerRequestInterceptor[] serverInterceptors = (ServerRequestInterceptor[])interceptorList. getInterceptors( InterceptorList.INTERCEPTOR_TYPE_SERVER ); int size = serverInterceptors.length; // We will assume that all interceptors returned successfully, // and adjust the flowStackIndex to the appropriate value if // we later discover otherwise. int flowStackIndex = size; boolean continueProcessing = true; // Currently, there is only one server-side starting point // interceptor called receive_request_service_contexts. for( int i = 0; continueProcessing && (i < size); i++ ) { try { serverInterceptors[i]. receive_request_service_contexts( info ); } catch( ForwardRequest e ) { // as per PI spec (orbos/99-12-02 sec 5.3.1.), if // interception point throws a ForwardRequest, // no other Interceptors' starting points are // called and send_other is called. flowStackIndex = i; info.setForwardRequest( e ); info.setIntermediatePointCall( ServerRequestInfoImpl.CALL_INTERMEDIATE_NONE ); info.setEndingPointCall( ServerRequestInfoImpl.CALL_SEND_OTHER ); info.setReplyStatus( LOCATION_FORWARD.value ); // For some reason, using break here causes the VM on // NT to lose track of the value of flowStackIndex // after exiting the for loop. I changed this to // check a boolean value instead and it seems to work // fine. continueProcessing = false; } catch( SystemException e ) { // as per PI spec (orbos/99-12-02 sec 5.3.1.), if // interception point throws a SystemException, // no other Interceptors' starting points are // called. flowStackIndex = i; info.setException( e ); info.setIntermediatePointCall( ServerRequestInfoImpl.CALL_INTERMEDIATE_NONE ); info.setEndingPointCall( ServerRequestInfoImpl.CALL_SEND_EXCEPTION ); info.setReplyStatus( SYSTEM_EXCEPTION.value ); // For some reason, using break here causes the VM on // NT to lose track of the value of flowStackIndex // after exiting the for loop. I changed this to // check a boolean value instead and it seems to // work fine. continueProcessing = false; } } // Remember where we left off in the flow stack: info.setFlowStackIndex( flowStackIndex ); } finally { // The remaining points, ServantManager and Servant // all run in the same logical thread. current.popSlotTable( ); // Now TSC and RSC are equivalent. } } // end enabled check } /** * Invokes receive_request interception points */ void invokeServerInterceptorIntermediatePoint( ServerRequestInfoImpl info ) { int intermediatePointCall = info.getIntermediatePointCall(); // If invocation is not yet enabled, don't do anything. if( enabled && ( intermediatePointCall != ServerRequestInfoImpl.CALL_INTERMEDIATE_NONE ) ) { // NOTE: do not touch the slotStack. The RSC and TSC are // equivalent at this point. info.setCurrentExecutionPoint( info.EXECUTION_POINT_INTERMEDIATE ); // Get all ServerRequestInterceptors: ServerRequestInterceptor[] serverInterceptors = (ServerRequestInterceptor[]) interceptorList.getInterceptors( InterceptorList.INTERCEPTOR_TYPE_SERVER ); int size = serverInterceptors.length; // Currently, there is only one server-side intermediate point // interceptor called receive_request. for( int i = 0; i < size; i++ ) { try { serverInterceptors[i].receive_request( info ); } catch( ForwardRequest e ) { // as per PI spec (orbos/99-12-02 sec 5.3.1.), if // interception point throws a ForwardRequest, // no other Interceptors' intermediate points are // called and send_other is called. info.setForwardRequest( e ); info.setEndingPointCall( ServerRequestInfoImpl.CALL_SEND_OTHER ); info.setReplyStatus( LOCATION_FORWARD.value ); break; } catch( SystemException e ) { // as per PI spec (orbos/99-12-02 sec 5.3.1.), if // interception point throws a SystemException, // no other Interceptors' starting points are // called. info.setException( e ); info.setEndingPointCall( ServerRequestInfoImpl.CALL_SEND_EXCEPTION ); info.setReplyStatus( SYSTEM_EXCEPTION.value ); break; } } } // end enabled check } /** * Invokes either send_reply, send_exception, or send_other, * depending on the value of info.getEndingPointCall() */ void invokeServerInterceptorEndingPoint( ServerRequestInfoImpl info ) { // If invocation is not yet enabled, don't do anything. if( enabled ) { try { // NOTE: do not touch the slotStack. The RSC and TSC are // equivalent at this point. // REVISIT: This is moved out to PIHandlerImpl until dispatch // path is rearchitected. It must be there so that // it always gets executed so if an interceptor raises // an exception any service contexts added in earlier points // this point get put in the exception reply (via the SC Q). //info.setCurrentExecutionPoint( info.EXECUTION_POINT_ENDING ); // Get all ServerRequestInterceptors: ServerRequestInterceptor[] serverInterceptors = (ServerRequestInterceptor[])interceptorList. getInterceptors( InterceptorList.INTERCEPTOR_TYPE_SERVER ); int flowStackIndex = info.getFlowStackIndex(); // Determine whether we are calling // send_exception, or send_other: int endingPointCall = info.getEndingPointCall(); // Only step through the interceptors whose starting points // have successfully returned. for( int i = (flowStackIndex - 1); i >= 0; i-- ) { try { switch( endingPointCall ) { case ServerRequestInfoImpl.CALL_SEND_REPLY: serverInterceptors[i].send_reply( info ); break; case ServerRequestInfoImpl.CALL_SEND_EXCEPTION: serverInterceptors[i].send_exception( info ); break; case ServerRequestInfoImpl.CALL_SEND_OTHER: serverInterceptors[i].send_other( info ); break; } } catch( ForwardRequest e ) { // as per PI spec (orbos/99-12-02 sec 5.3.1.), if // interception point throws a ForwardException, // ending point call changes to receive_other. endingPointCall = ServerRequestInfoImpl.CALL_SEND_OTHER; info.setEndingPointCall( endingPointCall ); info.setForwardRequest( e ); info.setReplyStatus( LOCATION_FORWARD.value ); info.setForwardRequestRaisedInEnding(); } catch( SystemException e ) { // as per PI spec (orbos/99-12-02 sec 5.3.1.), if // interception point throws a SystemException, // ending point call changes to send_exception. endingPointCall = ServerRequestInfoImpl.CALL_SEND_EXCEPTION; info.setEndingPointCall( endingPointCall ); info.setException( e ); info.setReplyStatus( SYSTEM_EXCEPTION.value ); } } // Remember that all interceptors' starting and ending points // have already been executed so we need not do anything. info.setAlreadyExecuted( true ); } finally { // Get rid of the Server side RSC. current.popSlotTable(); } } // end enabled check } /* ********************************************************************** * Private utility methods **********************************************************************/ /** * Update the client delegate in the event of a ForwardRequest, given the * information in the passed-in info object. */ private void updateClientRequestDispatcherForward( ClientRequestInfoImpl info ) { ForwardRequest forwardRequest = info.getForwardRequestException(); // ForwardRequest may be null if the forwarded IOR is set internal // to the ClientRequestDispatcher rather than explicitly through Portable // Interceptors. In this case, we need not update the client // delegate ForwardRequest object. if( forwardRequest != null ) { org.omg.CORBA.Object object = forwardRequest.forward; // Convert the forward object into an IOR: IOR ior = ORBUtility.getIOR( object ) ; info.setLocatedIOR( ior ); } } }