InterceptorInvoker.java revision 608:7e06bf1dcb09
1/* 2 * Copyright (c) 2000, 2003, 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 org.omg.CORBA.CompletionStatus; 28import org.omg.CORBA.INTERNAL; 29import org.omg.CORBA.SystemException; 30import org.omg.CORBA.portable.Delegate; 31import org.omg.PortableInterceptor.LOCATION_FORWARD; 32import org.omg.PortableInterceptor.SUCCESSFUL; 33import org.omg.PortableInterceptor.SYSTEM_EXCEPTION; 34import org.omg.PortableInterceptor.TRANSPORT_RETRY; 35import org.omg.PortableInterceptor.USER_EXCEPTION; 36import org.omg.PortableInterceptor.ClientRequestInfo; 37import org.omg.PortableInterceptor.ClientRequestInterceptor; 38import org.omg.PortableInterceptor.ForwardRequest; 39import org.omg.PortableInterceptor.IORInterceptor; 40import org.omg.PortableInterceptor.IORInterceptor_3_0; 41import org.omg.PortableInterceptor.ServerRequestInfo; 42import org.omg.PortableInterceptor.ServerRequestInterceptor; 43import org.omg.PortableInterceptor.ObjectReferenceTemplate; 44 45import com.sun.corba.se.spi.ior.IOR; 46import com.sun.corba.se.spi.oa.ObjectAdapter; 47import com.sun.corba.se.spi.orb.ORB; 48import com.sun.corba.se.impl.orbutil.ORBUtility; 49 50/** 51 * Handles invocation of interceptors. Has specific knowledge of how to 52 * invoke IOR, ClientRequest, and ServerRequest interceptors. 53 * Makes use of the InterceptorList to retrieve the list of interceptors to 54 * be invoked. Most methods in this class are package scope so that they 55 * may only be called from the PIHandlerImpl. 56 */ 57public class InterceptorInvoker { 58 59 // The ORB 60 private ORB orb; 61 62 // The list of interceptors to be invoked 63 private InterceptorList interceptorList; 64 65 // True if interceptors are to be invoked, or false if not 66 // Note: This is a global enable/disable flag, whereas the enable flag 67 // in the RequestInfoStack in PIHandlerImpl is only for a particular Thread. 68 private boolean enabled = false; 69 70 // PICurrent variable. 71 private PICurrent current; 72 73 // NOTE: Be careful about adding additional attributes to this class. 74 // Multiple threads may be calling methods on this invoker at the same 75 // time. 76 77 /** 78 * Creates a new Interceptor Invoker. Constructor is package scope so 79 * only the ORB can create it. The invoker is initially disabled, and 80 * must be explicitly enabled using setEnabled(). 81 */ 82 InterceptorInvoker( ORB orb, InterceptorList interceptorList, 83 PICurrent piCurrent ) 84 { 85 this.orb = orb; 86 this.interceptorList = interceptorList; 87 this.enabled = false; 88 this.current = piCurrent; 89 } 90 91 /** 92 * Enables or disables the interceptor invoker 93 */ 94 void setEnabled( boolean enabled ) { 95 this.enabled = enabled; 96 } 97 98 /* 99 ********************************************************************** 100 * IOR Interceptor invocation 101 **********************************************************************/ 102 103 /** 104 * Called when a new POA is created. 105 * 106 * @param oa The Object Adapter associated with the IOR interceptor. 107 */ 108 void objectAdapterCreated( ObjectAdapter oa ) { 109 // If invocation is not yet enabled, don't do anything. 110 if( enabled ) { 111 // Create IORInfo object to pass to IORInterceptors: 112 IORInfoImpl info = new IORInfoImpl( oa ); 113 114 // Call each IORInterceptor: 115 IORInterceptor[] iorInterceptors = 116 (IORInterceptor[])interceptorList.getInterceptors( 117 InterceptorList.INTERCEPTOR_TYPE_IOR ); 118 int size = iorInterceptors.length; 119 120 // Implementation note: 121 // This loop counts backwards for greater efficiency. 122 // Benchmarks have shown that counting down is more efficient 123 // than counting up in Java for loops, as a compare to zero is 124 // faster than a subtract and compare to zero. In this case, 125 // it doesn't really matter much, but it's simply a force of habit. 126 127 for( int i = (size - 1); i >= 0; i-- ) { 128 IORInterceptor interceptor = iorInterceptors[i]; 129 try { 130 interceptor.establish_components( info ); 131 } 132 catch( Exception e ) { 133 // as per PI spec (orbos/99-12-02 sec 7.2.1), if 134 // establish_components throws an exception, ignore it. 135 } 136 } 137 138 // Change the state so that only template operations are valid 139 info.makeStateEstablished() ; 140 141 for( int i = (size - 1); i >= 0; i-- ) { 142 IORInterceptor interceptor = iorInterceptors[i]; 143 if (interceptor instanceof IORInterceptor_3_0) { 144 IORInterceptor_3_0 interceptor30 = (IORInterceptor_3_0)interceptor ; 145 // Note that exceptions here are NOT ignored, as per the 146 // ORT spec (orbos/01-01-04) 147 interceptor30.components_established( info ); 148 } 149 } 150 151 // Change the state so that no operations are valid, 152 // in case a reference to info escapes this scope. 153 // This also completes the actions associated with the 154 // template interceptors on this POA. 155 info.makeStateDone() ; 156 } 157 } 158 159 void adapterManagerStateChanged( int managerId, short newState ) 160 { 161 if (enabled) { 162 IORInterceptor[] interceptors = 163 (IORInterceptor[])interceptorList.getInterceptors( 164 InterceptorList.INTERCEPTOR_TYPE_IOR ); 165 int size = interceptors.length; 166 167 for( int i = (size - 1); i >= 0; i-- ) { 168 try { 169 IORInterceptor interceptor = interceptors[i]; 170 if (interceptor instanceof IORInterceptor_3_0) { 171 IORInterceptor_3_0 interceptor30 = (IORInterceptor_3_0)interceptor ; 172 interceptor30.adapter_manager_state_changed( managerId, 173 newState ); 174 } 175 } catch (Exception exc) { 176 // No-op: ignore exception in this case 177 } 178 } 179 } 180 } 181 182 void adapterStateChanged( ObjectReferenceTemplate[] templates, 183 short newState ) 184 { 185 if (enabled) { 186 IORInterceptor[] interceptors = 187 (IORInterceptor[])interceptorList.getInterceptors( 188 InterceptorList.INTERCEPTOR_TYPE_IOR ); 189 int size = interceptors.length; 190 191 for( int i = (size - 1); i >= 0; i-- ) { 192 try { 193 IORInterceptor interceptor = interceptors[i]; 194 if (interceptor instanceof IORInterceptor_3_0) { 195 IORInterceptor_3_0 interceptor30 = (IORInterceptor_3_0)interceptor ; 196 interceptor30.adapter_state_changed( templates, newState ); 197 } 198 } catch (Exception exc) { 199 // No-op: ignore exception in this case 200 } 201 } 202 } 203 } 204 205 /* 206 ********************************************************************** 207 * Client Interceptor invocation 208 **********************************************************************/ 209 210 /** 211 * Invokes either send_request, or send_poll, depending on the value 212 * of info.getStartingPointCall() 213 */ 214 void invokeClientInterceptorStartingPoint( ClientRequestInfoImpl info ) { 215 // If invocation is not yet enabled, don't do anything. 216 if( enabled ) { 217 try { 218 // Make a a fresh slot table available to TSC in case 219 // interceptors need to make out calls. 220 // Client's TSC is now RSC via RequestInfo. 221 current.pushSlotTable( ); 222 info.setPICurrentPushed( true ); 223 info.setCurrentExecutionPoint( info.EXECUTION_POINT_STARTING ); 224 225 // Get all ClientRequestInterceptors: 226 ClientRequestInterceptor[] clientInterceptors = 227 (ClientRequestInterceptor[])interceptorList. 228 getInterceptors( InterceptorList.INTERCEPTOR_TYPE_CLIENT ); 229 int size = clientInterceptors.length; 230 231 // We will assume that all interceptors returned successfully, 232 // and adjust the flowStackIndex to the appropriate value if 233 // we later discover otherwise. 234 int flowStackIndex = size; 235 boolean continueProcessing = true; 236 237 // Determine whether we are calling send_request or send_poll: 238 // (This is currently commented out because our ORB does not 239 // yet support the Messaging specification, so send_poll will 240 // never occur. Once we have implemented messaging, this may 241 // be uncommented.) 242 // int startingPointCall = info.getStartingPointCall(); 243 for( int i = 0; continueProcessing && (i < size); i++ ) { 244 try { 245 clientInterceptors[i].send_request( info ); 246 247 // Again, it is not necessary for a switch here, since 248 // there is only one starting point call type (see 249 // above comment). 250 251 //switch( startingPointCall ) { 252 //case ClientRequestInfoImpl.CALL_SEND_REQUEST: 253 //clientInterceptors[i].send_request( info ); 254 //break; 255 //case ClientRequestInfoImpl.CALL_SEND_POLL: 256 //clientInterceptors[i].send_poll( info ); 257 //break; 258 //} 259 260 } 261 catch( ForwardRequest e ) { 262 // as per PI spec (orbos/99-12-02 sec 5.2.1.), if 263 // interception point throws a ForwardRequest, 264 // no other Interceptors' send_request operations are 265 // called. 266 flowStackIndex = i; 267 info.setForwardRequest( e ); 268 info.setEndingPointCall( 269 ClientRequestInfoImpl.CALL_RECEIVE_OTHER ); 270 info.setReplyStatus( LOCATION_FORWARD.value ); 271 272 updateClientRequestDispatcherForward( info ); 273 274 // For some reason, using break here causes the VM on 275 // NT to lose track of the value of flowStackIndex 276 // after exiting the for loop. I changed this to 277 // check a boolean value instead and it seems to work 278 // fine. 279 continueProcessing = false; 280 } 281 catch( SystemException e ) { 282 // as per PI spec (orbos/99-12-02 sec 5.2.1.), if 283 // interception point throws a SystemException, 284 // no other Interceptors' send_request operations are 285 // called. 286 flowStackIndex = i; 287 info.setEndingPointCall( 288 ClientRequestInfoImpl.CALL_RECEIVE_EXCEPTION ); 289 info.setReplyStatus( SYSTEM_EXCEPTION.value ); 290 info.setException( e ); 291 292 // For some reason, using break here causes the VM on 293 // NT to lose track of the value of flowStackIndex 294 // after exiting the for loop. I changed this to 295 // check a boolean value instead and it seems to 296 // work fine. 297 continueProcessing = false; 298 } 299 } 300 301 // Remember where we left off in the flow stack: 302 info.setFlowStackIndex( flowStackIndex ); 303 } 304 finally { 305 // Make the SlotTable fresh for the next interception point. 306 current.resetSlotTable( ); 307 } 308 } // end enabled check 309 } 310 311 /** 312 * Invokes either receive_reply, receive_exception, or receive_other, 313 * depending on the value of info.getEndingPointCall() 314 */ 315 void invokeClientInterceptorEndingPoint( ClientRequestInfoImpl info ) { 316 // If invocation is not yet enabled, don't do anything. 317 if( enabled ) { 318 try { 319 // NOTE: It is assumed someplace else prepared a 320 // fresh TSC slot table. 321 322 info.setCurrentExecutionPoint( info.EXECUTION_POINT_ENDING ); 323 324 // Get all ClientRequestInterceptors: 325 ClientRequestInterceptor[] clientInterceptors = 326 (ClientRequestInterceptor[])interceptorList. 327 getInterceptors( InterceptorList.INTERCEPTOR_TYPE_CLIENT ); 328 int flowStackIndex = info.getFlowStackIndex(); 329 330 // Determine whether we are calling receive_reply, 331 // receive_exception, or receive_other: 332 int endingPointCall = info.getEndingPointCall(); 333 334 // If we would be calling RECEIVE_REPLY, but this is a 335 // one-way call, override this and call receive_other: 336 if( ( endingPointCall == 337 ClientRequestInfoImpl.CALL_RECEIVE_REPLY ) && 338 info.getIsOneWay() ) 339 { 340 endingPointCall = ClientRequestInfoImpl.CALL_RECEIVE_OTHER; 341 info.setEndingPointCall( endingPointCall ); 342 } 343 344 // Only step through the interceptors whose starting points 345 // have successfully returned. 346 // Unlike the previous loop, this one counts backwards for a 347 // reason - we must execute these in the reverse order of the 348 // starting points. 349 for( int i = (flowStackIndex - 1); i >= 0; i-- ) { 350 351 try { 352 switch( endingPointCall ) { 353 case ClientRequestInfoImpl.CALL_RECEIVE_REPLY: 354 clientInterceptors[i].receive_reply( info ); 355 break; 356 case ClientRequestInfoImpl.CALL_RECEIVE_EXCEPTION: 357 clientInterceptors[i].receive_exception( info ); 358 break; 359 case ClientRequestInfoImpl.CALL_RECEIVE_OTHER: 360 clientInterceptors[i].receive_other( info ); 361 break; 362 } 363 } 364 catch( ForwardRequest e ) { 365 366 // as per PI spec (orbos/99-12-02 sec 5.2.1.), if 367 // interception point throws a ForwardException, 368 // ending point call changes to receive_other. 369 endingPointCall = 370 ClientRequestInfoImpl.CALL_RECEIVE_OTHER; 371 info.setEndingPointCall( endingPointCall ); 372 info.setReplyStatus( LOCATION_FORWARD.value ); 373 info.setForwardRequest( e ); 374 updateClientRequestDispatcherForward( info ); 375 } 376 catch( SystemException e ) { 377 378 // as per PI spec (orbos/99-12-02 sec 5.2.1.), if 379 // interception point throws a SystemException, 380 // ending point call changes to receive_exception. 381 endingPointCall = 382 ClientRequestInfoImpl.CALL_RECEIVE_EXCEPTION; 383 info.setEndingPointCall( endingPointCall ); 384 info.setReplyStatus( SYSTEM_EXCEPTION.value ); 385 info.setException( e ); 386 } 387 } 388 } 389 finally { 390 // See doc for setPICurrentPushed as to why this is necessary. 391 // Check info for null in case errors happen before initiate. 392 if (info != null && info.isPICurrentPushed()) { 393 current.popSlotTable( ); 394 // After the pop, original client's TSC slot table 395 // remains avaiable via PICurrent. 396 } 397 } 398 } // end enabled check 399 } 400 401 /* 402 ********************************************************************** 403 * Server Interceptor invocation 404 **********************************************************************/ 405 406 /** 407 * Invokes receive_request_service_context interception points. 408 */ 409 void invokeServerInterceptorStartingPoint( ServerRequestInfoImpl info ) { 410 // If invocation is not yet enabled, don't do anything. 411 if( enabled ) { 412 try { 413 // Make a fresh slot table for RSC. 414 current.pushSlotTable(); 415 info.setSlotTable(current.getSlotTable()); 416 417 // Make a fresh slot table for TSC in case 418 // interceptors need to make out calls. 419 current.pushSlotTable( ); 420 421 info.setCurrentExecutionPoint( info.EXECUTION_POINT_STARTING ); 422 423 // Get all ServerRequestInterceptors: 424 ServerRequestInterceptor[] serverInterceptors = 425 (ServerRequestInterceptor[])interceptorList. 426 getInterceptors( InterceptorList.INTERCEPTOR_TYPE_SERVER ); 427 int size = serverInterceptors.length; 428 429 // We will assume that all interceptors returned successfully, 430 // and adjust the flowStackIndex to the appropriate value if 431 // we later discover otherwise. 432 int flowStackIndex = size; 433 boolean continueProcessing = true; 434 435 // Currently, there is only one server-side starting point 436 // interceptor called receive_request_service_contexts. 437 for( int i = 0; continueProcessing && (i < size); i++ ) { 438 439 try { 440 serverInterceptors[i]. 441 receive_request_service_contexts( info ); 442 } 443 catch( ForwardRequest e ) { 444 // as per PI spec (orbos/99-12-02 sec 5.3.1.), if 445 // interception point throws a ForwardRequest, 446 // no other Interceptors' starting points are 447 // called and send_other is called. 448 flowStackIndex = i; 449 info.setForwardRequest( e ); 450 info.setIntermediatePointCall( 451 ServerRequestInfoImpl.CALL_INTERMEDIATE_NONE ); 452 info.setEndingPointCall( 453 ServerRequestInfoImpl.CALL_SEND_OTHER ); 454 info.setReplyStatus( LOCATION_FORWARD.value ); 455 456 // For some reason, using break here causes the VM on 457 // NT to lose track of the value of flowStackIndex 458 // after exiting the for loop. I changed this to 459 // check a boolean value instead and it seems to work 460 // fine. 461 continueProcessing = false; 462 } 463 catch( SystemException e ) { 464 465 // as per PI spec (orbos/99-12-02 sec 5.3.1.), if 466 // interception point throws a SystemException, 467 // no other Interceptors' starting points are 468 // called. 469 flowStackIndex = i; 470 info.setException( e ); 471 info.setIntermediatePointCall( 472 ServerRequestInfoImpl.CALL_INTERMEDIATE_NONE ); 473 info.setEndingPointCall( 474 ServerRequestInfoImpl.CALL_SEND_EXCEPTION ); 475 info.setReplyStatus( SYSTEM_EXCEPTION.value ); 476 477 // For some reason, using break here causes the VM on 478 // NT to lose track of the value of flowStackIndex 479 // after exiting the for loop. I changed this to 480 // check a boolean value instead and it seems to 481 // work fine. 482 continueProcessing = false; 483 } 484 485 } 486 487 // Remember where we left off in the flow stack: 488 info.setFlowStackIndex( flowStackIndex ); 489 } 490 finally { 491 // The remaining points, ServantManager and Servant 492 // all run in the same logical thread. 493 current.popSlotTable( ); 494 // Now TSC and RSC are equivalent. 495 } 496 } // end enabled check 497 } 498 499 /** 500 * Invokes receive_request interception points 501 */ 502 void invokeServerInterceptorIntermediatePoint( 503 ServerRequestInfoImpl info ) 504 { 505 int intermediatePointCall = info.getIntermediatePointCall(); 506 // If invocation is not yet enabled, don't do anything. 507 if( enabled && ( intermediatePointCall != 508 ServerRequestInfoImpl.CALL_INTERMEDIATE_NONE ) ) 509 { 510 // NOTE: do not touch the slotStack. The RSC and TSC are 511 // equivalent at this point. 512 513 info.setCurrentExecutionPoint( info.EXECUTION_POINT_INTERMEDIATE ); 514 515 // Get all ServerRequestInterceptors: 516 ServerRequestInterceptor[] serverInterceptors = 517 (ServerRequestInterceptor[]) 518 interceptorList.getInterceptors( 519 InterceptorList.INTERCEPTOR_TYPE_SERVER ); 520 int size = serverInterceptors.length; 521 522 // Currently, there is only one server-side intermediate point 523 // interceptor called receive_request. 524 for( int i = 0; i < size; i++ ) { 525 526 try { 527 serverInterceptors[i].receive_request( info ); 528 } 529 catch( ForwardRequest e ) { 530 531 // as per PI spec (orbos/99-12-02 sec 5.3.1.), if 532 // interception point throws a ForwardRequest, 533 // no other Interceptors' intermediate points are 534 // called and send_other is called. 535 info.setForwardRequest( e ); 536 info.setEndingPointCall( 537 ServerRequestInfoImpl.CALL_SEND_OTHER ); 538 info.setReplyStatus( LOCATION_FORWARD.value ); 539 break; 540 } 541 catch( SystemException e ) { 542 543 // as per PI spec (orbos/99-12-02 sec 5.3.1.), if 544 // interception point throws a SystemException, 545 // no other Interceptors' starting points are 546 // called. 547 info.setException( e ); 548 info.setEndingPointCall( 549 ServerRequestInfoImpl.CALL_SEND_EXCEPTION ); 550 info.setReplyStatus( SYSTEM_EXCEPTION.value ); 551 break; 552 } 553 } 554 } // end enabled check 555 } 556 557 /** 558 * Invokes either send_reply, send_exception, or send_other, 559 * depending on the value of info.getEndingPointCall() 560 */ 561 void invokeServerInterceptorEndingPoint( ServerRequestInfoImpl info ) { 562 // If invocation is not yet enabled, don't do anything. 563 if( enabled ) { 564 try { 565 // NOTE: do not touch the slotStack. The RSC and TSC are 566 // equivalent at this point. 567 568 // REVISIT: This is moved out to PIHandlerImpl until dispatch 569 // path is rearchitected. It must be there so that 570 // it always gets executed so if an interceptor raises 571 // an exception any service contexts added in earlier points 572 // this point get put in the exception reply (via the SC Q). 573 //info.setCurrentExecutionPoint( info.EXECUTION_POINT_ENDING ); 574 575 // Get all ServerRequestInterceptors: 576 ServerRequestInterceptor[] serverInterceptors = 577 (ServerRequestInterceptor[])interceptorList. 578 getInterceptors( InterceptorList.INTERCEPTOR_TYPE_SERVER ); 579 int flowStackIndex = info.getFlowStackIndex(); 580 581 // Determine whether we are calling 582 // send_exception, or send_other: 583 int endingPointCall = info.getEndingPointCall(); 584 585 // Only step through the interceptors whose starting points 586 // have successfully returned. 587 for( int i = (flowStackIndex - 1); i >= 0; i-- ) { 588 try { 589 switch( endingPointCall ) { 590 case ServerRequestInfoImpl.CALL_SEND_REPLY: 591 serverInterceptors[i].send_reply( info ); 592 break; 593 case ServerRequestInfoImpl.CALL_SEND_EXCEPTION: 594 serverInterceptors[i].send_exception( info ); 595 break; 596 case ServerRequestInfoImpl.CALL_SEND_OTHER: 597 serverInterceptors[i].send_other( info ); 598 break; 599 } 600 } 601 catch( ForwardRequest e ) { 602 // as per PI spec (orbos/99-12-02 sec 5.3.1.), if 603 // interception point throws a ForwardException, 604 // ending point call changes to receive_other. 605 endingPointCall = 606 ServerRequestInfoImpl.CALL_SEND_OTHER; 607 info.setEndingPointCall( endingPointCall ); 608 info.setForwardRequest( e ); 609 info.setReplyStatus( LOCATION_FORWARD.value ); 610 info.setForwardRequestRaisedInEnding(); 611 } 612 catch( SystemException e ) { 613 // as per PI spec (orbos/99-12-02 sec 5.3.1.), if 614 // interception point throws a SystemException, 615 // ending point call changes to send_exception. 616 endingPointCall = 617 ServerRequestInfoImpl.CALL_SEND_EXCEPTION; 618 info.setEndingPointCall( endingPointCall ); 619 info.setException( e ); 620 info.setReplyStatus( SYSTEM_EXCEPTION.value ); 621 } 622 } 623 624 // Remember that all interceptors' starting and ending points 625 // have already been executed so we need not do anything. 626 info.setAlreadyExecuted( true ); 627 } 628 finally { 629 // Get rid of the Server side RSC. 630 current.popSlotTable(); 631 } 632 } // end enabled check 633 } 634 635 /* 636 ********************************************************************** 637 * Private utility methods 638 **********************************************************************/ 639 640 /** 641 * Update the client delegate in the event of a ForwardRequest, given the 642 * information in the passed-in info object. 643 */ 644 private void updateClientRequestDispatcherForward( 645 ClientRequestInfoImpl info ) 646 { 647 ForwardRequest forwardRequest = info.getForwardRequestException(); 648 649 // ForwardRequest may be null if the forwarded IOR is set internal 650 // to the ClientRequestDispatcher rather than explicitly through Portable 651 // Interceptors. In this case, we need not update the client 652 // delegate ForwardRequest object. 653 if( forwardRequest != null ) { 654 org.omg.CORBA.Object object = forwardRequest.forward; 655 656 // Convert the forward object into an IOR: 657 IOR ior = ORBUtility.getIOR( object ) ; 658 info.setLocatedIOR( ior ); 659 } 660 } 661 662} 663