Source for gnu.CORBA.Poa.LocalRequest

   1: /* LocalRequest.java --
   2:    Copyright (C) 2005 Free Software Foundation, Inc.
   3: 
   4: This file is part of GNU Classpath.
   5: 
   6: GNU Classpath is free software; you can redistribute it and/or modify
   7: it under the terms of the GNU General Public License as published by
   8: the Free Software Foundation; either version 2, or (at your option)
   9: any later version.
  10: 
  11: GNU Classpath is distributed in the hope that it will be useful, but
  12: WITHOUT ANY WARRANTY; without even the implied warranty of
  13: MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
  14: General Public License for more details.
  15: 
  16: You should have received a copy of the GNU General Public License
  17: along with GNU Classpath; see the file COPYING.  If not, write to the
  18: Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
  19: 02110-1301 USA.
  20: 
  21: Linking this library statically or dynamically with other modules is
  22: making a combined work based on this library.  Thus, the terms and
  23: conditions of the GNU General Public License cover the whole
  24: combination.
  25: 
  26: As a special exception, the copyright holders of this library give you
  27: permission to link this library with independent modules to produce an
  28: executable, regardless of the license terms of these independent
  29: modules, and to copy and distribute the resulting executable under
  30: terms of your choice, provided that you also meet, for each linked
  31: independent module, the terms and conditions of the license of that
  32: module.  An independent module is a module which is not derived from
  33: or based on this library.  If you modify this library, you may extend
  34: this exception to your version of the library, but you are not
  35: obligated to do so.  If you do not wish to do so, delete this
  36: exception statement from your version. */
  37: 
  38: 
  39: package gnu.CORBA.Poa;
  40: 
  41: import gnu.CORBA.CDR.BufferedCdrOutput;
  42: import gnu.CORBA.GIOP.MessageHeader;
  43: import gnu.CORBA.GIOP.v1_2.ReplyHeader;
  44: import gnu.CORBA.GIOP.v1_2.RequestHeader;
  45: import gnu.CORBA.Interceptor.gnuClientRequestInfo;
  46: import gnu.CORBA.Interceptor.gnuServerRequestInfo;
  47: import gnu.CORBA.typecodes.RecordTypeCode;
  48: import gnu.CORBA.ObjectCreator;
  49: import gnu.CORBA.Unexpected;
  50: import gnu.CORBA.gnuAny;
  51: import gnu.CORBA.gnuRequest;
  52: import gnu.CORBA.StreamHolder;
  53: import gnu.CORBA.StreamBasedRequest;
  54: 
  55: import org.omg.CORBA.ARG_OUT;
  56: import org.omg.CORBA.Any;
  57: import org.omg.CORBA.BAD_INV_ORDER;
  58: import org.omg.CORBA.BAD_OPERATION;
  59: import org.omg.CORBA.Bounds;
  60: import org.omg.CORBA.NamedValue;
  61: import org.omg.CORBA.ORB;
  62: import org.omg.CORBA.SystemException;
  63: import org.omg.CORBA.TCKind;
  64: import org.omg.CORBA.UnknownUserException;
  65: import org.omg.CORBA.UserException;
  66: import org.omg.CORBA.portable.ApplicationException;
  67: import org.omg.CORBA.portable.InputStream;
  68: import org.omg.CORBA.portable.InvokeHandler;
  69: import org.omg.CORBA.portable.ObjectImpl;
  70: import org.omg.CORBA.portable.OutputStream;
  71: import org.omg.CORBA.portable.ResponseHandler;
  72: import org.omg.PortableInterceptor.ClientRequestInterceptorOperations;
  73: import org.omg.PortableInterceptor.ForwardRequest;
  74: import org.omg.PortableInterceptor.ServerRequestInterceptorOperations;
  75: import org.omg.PortableServer.CurrentOperations;
  76: import org.omg.PortableServer.CurrentPackage.NoContext;
  77: import org.omg.PortableServer.DynamicImplementation;
  78: import org.omg.PortableServer.POA;
  79: import org.omg.PortableServer.Servant;
  80: import org.omg.PortableServer.ServantLocatorPackage.CookieHolder;
  81: import org.omg.PortableServer.portable.Delegate;
  82: 
  83: import java.io.IOException;
  84: 
  85: /**
  86:  * Directs the invocation to the locally available servant. The POA servant does
  87:  * not longer implement the CORBA object and cannot be substituted directly.
  88:  *
  89:  * @author Audrius Meskauskas, Lithuania (AudriusA@Bioinformatics.org)
  90:  */
  91: public class LocalRequest extends gnuRequest implements ResponseHandler,
  92:   CurrentOperations
  93: {
  94:   /**
  95:    * Used by servant locator, if involved.
  96:    */
  97:   CookieHolder cookie;
  98: 
  99:   /**
 100:    * The object Id.
 101:    */
 102:   final byte[] Id;
 103: 
 104:   /**
 105:    * The message header (singleton is sufficient).
 106:    */
 107:   private static final MessageHeader header = new MessageHeader();
 108: 
 109:   /**
 110:        * True if the stream was obtained by invoking {@link #createExceptionReply()},
 111:    * false otherwise.
 112:    */
 113:   boolean exceptionReply;
 114: 
 115:   /**
 116:    * The buffer to write into.
 117:    */
 118:   BufferedCdrOutput buffer;
 119: 
 120:   /**
 121:    * The responsible POA.
 122:    */
 123:   final gnuPOA poa;
 124: 
 125:   /**
 126:    * The servant delegate to obtain the handler.
 127:    */
 128:   gnuServantObject object;
 129: 
 130:   /**
 131:    * Used (reused) with dynamic implementation.
 132:    */
 133:   LocalServerRequest serverRequest;
 134: 
 135:   /**
 136:    * Create an instance of the local request.
 137:    */
 138:   public LocalRequest(gnuServantObject local_object, gnuPOA a_poa, byte[] an_id)
 139:   {
 140:     Id = an_id;
 141:     poa = a_poa;
 142: 
 143:     // Instantiate the cookie holder only if required.
 144:     if (poa.servant_locator != null)
 145:       {
 146:         cookie = new CookieHolder();
 147:       }
 148:     object = local_object;
 149:     prepareStream();
 150:   }
 151: 
 152:   /**
 153:    * Make an invocation and return a stream from where the results can be read
 154:    * and throw ApplicationException, where applicable.
 155:    */
 156:   org.omg.CORBA.portable.InputStream s_invoke(InvokeHandler handler)
 157:     throws ApplicationException
 158:   {
 159:     try
 160:       {
 161:         poa.m_orb.currents.put(Thread.currentThread(), this);
 162: 
 163:         org.omg.CORBA.portable.InputStream input = v_invoke(handler);
 164: 
 165:         if (!exceptionReply)
 166:           {
 167:             return input;
 168:           }
 169:         else
 170:           {
 171:             input.mark(500);
 172: 
 173:             String id = input.read_string();
 174:             try
 175:               {
 176:                 input.reset();
 177:               }
 178:             catch (IOException ex)
 179:               {
 180:                 InternalError ierr = new InternalError();
 181:                 ierr.initCause(ex);
 182:                 throw ierr;
 183:               }
 184:             throw new ApplicationException(id, input);
 185:           }
 186:       }
 187:     finally
 188:       {
 189:         poa.m_orb.currents.remove(Thread.currentThread());
 190:       }
 191:   }
 192: 
 193:   /**
 194:    * Make an invocation and return a stream from where the results can be read.
 195:    *
 196:    * @param handler the invoke handler (can be null, then it is obtained self
 197:    * dependently).
 198:    */
 199:   public org.omg.CORBA.portable.InputStream v_invoke(InvokeHandler handler)
 200:   {
 201:     // Check maybe POA is in the discarding mode (will throw TRANSIENT if it is).
 202:     poa.checkDiscarding();
 203: 
 204:     // Local request must be intercepted both by server and request
 205:     // interceptors.
 206:     boolean s_intercept = false;
 207:     ServerRequestInterceptorOperations s_interceptor = null;
 208:     gnuServerRequestInfo s_info = null;
 209: 
 210:     boolean c_intercept = false;
 211:     ClientRequestInterceptorOperations c_interceptor = null;
 212:     gnuClientRequestInfo c_info = null;
 213: 
 214:     try
 215:       {
 216:         if (poa.m_orb.iServer != null || poa.m_orb.iClient != null)
 217:           {
 218:             setORB(poa.m_orb);
 219: 
 220:             // These two are only needed with interceptors.
 221:             m_rqh = new RequestHeader();
 222:             m_rqh.operation = m_operation;
 223:             m_rph = new ReplyHeader();
 224: 
 225:             m_rqh.object_key = object.Id;
 226:             m_rph.request_id = m_rqh.request_id;
 227:           }
 228: 
 229:         if (poa.m_orb.iClient != null)
 230:           {
 231:             c_interceptor = poa.m_orb.iClient;
 232: 
 233:             c_info = new gnuClientRequestInfo(this);
 234:             c_intercept = true;
 235: 
 236:             c_interceptor.send_request(c_info);
 237: 
 238:             m_target = object;
 239:           }
 240: 
 241:         if (poa.m_orb.iServer != null)
 242:           {
 243:             s_interceptor = poa.m_orb.iServer;
 244: 
 245:             s_info = new gnuServerRequestInfo(object, m_rqh, m_rph);
 246:             s_info.m_request = this;
 247: 
 248:             s_intercept = true;
 249: 
 250:             s_interceptor.receive_request_service_contexts(s_info);
 251:           }
 252: 
 253:         if (handler == null)
 254:           {
 255:             handler = object.getHandler(operation(), cookie, false);
 256:           }
 257: 
 258:         BufferedCdrOutput request_part = new BufferedCdrOutput();
 259: 
 260:         request_part.setOrb(orb());
 261: 
 262:         if (m_args != null && m_args.count() > 0)
 263:           {
 264:             write_parameters(header, request_part);
 265: 
 266:             if (m_parameter_buffer != null)
 267:               {
 268:                 throw new BAD_INV_ORDER("Please either add parameters or " +
 269:                   "write them into stream, but not both " + "at once."
 270:                 );
 271:               }
 272:           }
 273: 
 274:         if (m_parameter_buffer != null)
 275:           {
 276:             write_parameter_buffer(header, request_part);
 277:           }
 278: 
 279:         Servant servant;
 280: 
 281:         if (handler instanceof Servant)
 282:           {
 283:             servant = (Servant) handler;
 284:           }
 285:         else
 286:           {
 287:             throw new BAD_OPERATION("Unexpected handler type " + handler);
 288:           }
 289: 
 290:         org.omg.CORBA.portable.InputStream input =
 291:           request_part.create_input_stream();
 292: 
 293:         // Ensure the servant (handler) has a delegate set.
 294:         ServantDelegateImpl sd = null;
 295: 
 296:         Delegate d = null;
 297: 
 298:         try
 299:           {
 300:             d = servant._get_delegate();
 301:           }
 302:         catch (Exception ex)
 303:           {
 304:             // In some cases exception is thrown if the delegate is not set.
 305:           }
 306:         if (d instanceof ServantDelegateImpl)
 307:           {
 308:             // If the delegate is already set, try to reuse the existing
 309:             // instance.
 310:             sd = (ServantDelegateImpl) d;
 311:             if (sd.object != object)
 312:               {
 313:                 sd = new ServantDelegateImpl(servant, poa, Id);
 314:               }
 315:           }
 316:         else
 317:           {
 318:             sd = new ServantDelegateImpl(servant, poa, Id);
 319:           }
 320:         servant._set_delegate(sd);
 321: 
 322:         try
 323:           {
 324:             ORB o = orb();
 325:             if (o instanceof ORB_1_4)
 326:               {
 327:                 ((ORB_1_4) o).currents.put(Thread.currentThread(), this);
 328:               }
 329: 
 330:             try
 331:               {
 332:                 if (s_intercept)
 333:                   {
 334:                     s_interceptor.receive_request(s_info);
 335:                   }
 336:                 handler._invoke(m_operation, input, this);
 337: 
 338:                 // Handler is casted into i_handler.
 339:                 if ((s_intercept || c_intercept) && isExceptionReply())
 340:                   {
 341:                     s_info.m_reply_header.reply_status =
 342:                       ReplyHeader.USER_EXCEPTION;
 343:                     m_rph.reply_status = ReplyHeader.USER_EXCEPTION;
 344: 
 345:                     // Make Any, holding the user exception.
 346:                     Any a = new gnuAny();
 347:                     OutputStream buf = getBuffer();
 348:                     InputStream in = buf.create_input_stream();
 349:                     String uex_idl = "unknown";
 350:                     try
 351:                       {
 352:                         in.mark(Integer.MAX_VALUE);
 353:                         uex_idl = in.read_string();
 354:                         m_exception_id = uex_idl;
 355:                         in.reset();
 356:                       }
 357:                     catch (IOException e)
 358:                       {
 359:                         throw new Unexpected(e);
 360:                       }
 361: 
 362:                     try
 363:                       {
 364:                         UserException exception =
 365:                           ObjectCreator.readUserException(uex_idl, in);
 366: 
 367:                         m_environment.exception(exception);
 368:                         ObjectCreator.insertWithHelper(a, exception);
 369:                       }
 370:                     catch (Exception e)
 371:                       {
 372:                         // Failed due any reason, insert without
 373:                         // helper.
 374:                         a.insert_Streamable(new StreamHolder(
 375:                             buf.create_input_stream()
 376:                           )
 377:                         );
 378: 
 379:                         RecordTypeCode r =
 380:                           new RecordTypeCode(TCKind.tk_except);
 381:                         r.setId(uex_idl);
 382:                         r.setName(ObjectCreator.getDefaultName(uex_idl));
 383:                       }
 384: 
 385:                     s_info.m_usr_exception = a;
 386:                     c_info.m_wrapped_exception = a;
 387:                     s_interceptor.send_exception(s_info);
 388:                     c_interceptor.receive_exception(c_info);
 389:                   }
 390:                 else
 391:                   {
 392:                     if (s_intercept)
 393:                       {
 394:                         s_info.m_reply_header.reply_status =
 395:                           ReplyHeader.NO_EXCEPTION;
 396:                         s_interceptor.send_reply(s_info);
 397:                       }
 398:                     if (c_intercept)
 399:                       {
 400:                         m_rph.reply_status = ReplyHeader.NO_EXCEPTION;
 401:                         c_interceptor.receive_reply(c_info);
 402:                       }
 403:                   }
 404:               }
 405:             catch (SystemException sys_ex)
 406:               {
 407:                 if (s_intercept)
 408:                   {
 409:                     s_info.m_reply_header.reply_status =
 410:                       ReplyHeader.SYSTEM_EXCEPTION;
 411:                     s_info.m_sys_exception = sys_ex;
 412:                     s_interceptor.send_exception(s_info);
 413:                   }
 414: 
 415:                 if (c_intercept)
 416:                   {
 417:                     m_rph.reply_status = ReplyHeader.SYSTEM_EXCEPTION;
 418: 
 419:                     Any a = new gnuAny();
 420:                     if (ObjectCreator.insertSysException(a, sys_ex))
 421:                       {
 422:                         c_info.m_wrapped_exception = a;
 423:                       }
 424:                     c_interceptor.receive_exception(c_info);
 425:                   }
 426: 
 427:                 throw sys_ex;
 428:               }
 429:           }
 430:         finally
 431:           {
 432:             ORB o = orb();
 433:             if (o instanceof ORB_1_4)
 434:               {
 435:                 ((ORB_1_4) o).currents.remove(Thread.currentThread());
 436:               }
 437:           }
 438: 
 439:         if (poa.servant_locator != null)
 440:           {
 441:             poa.servant_locator.postinvoke(object.Id, poa, operation(),
 442:               cookie.value, object.getServant()
 443:             );
 444:           }
 445:         return buffer.create_input_stream();
 446:       }
 447: 
 448:     catch (ForwardRequest fex)
 449:       {
 450:         // May be thrown by interceptor.
 451:         if (s_intercept)
 452:           {
 453:             Forwarding:
 454:             while (true)
 455:               {
 456:                 s_info.m_reply_header.reply_status =
 457:                   ReplyHeader.LOCATION_FORWARD;
 458:                 s_info.m_forward_reference = fex.forward;
 459:                 try
 460:                   {
 461:                     s_interceptor.send_other(s_info);
 462:                     break Forwarding;
 463:                   }
 464:                 catch (ForwardRequest fex2)
 465:                   {
 466:                     s_info.m_forward_reference = fex2.forward;
 467:                     fex.forward = s_info.m_forward_reference;
 468:                   }
 469:               }
 470:           }
 471: 
 472:         if (c_intercept)
 473:           {
 474:             this.m_rph.reply_status = ReplyHeader.LOCATION_FORWARD;
 475:             this.m_forwarding_target = fex.forward;
 476:             try
 477:               {
 478:                 c_interceptor.receive_other(c_info);
 479:               }
 480:             catch (ForwardRequest fex2)
 481:               {
 482:                 fex.forward = fex2.forward;
 483:               }
 484:           }
 485:         throw new gnuForwardRequest(fex.forward);
 486:       }
 487:     catch (gnuForwardRequest fex)
 488:       {
 489:         // May be thrown during activation.
 490:         // May be thrown during activation.
 491:         if (s_intercept)
 492:           {
 493:             Forwarding:
 494:             while (true)
 495:               {
 496:                 s_info.m_reply_header.reply_status =
 497:                   ReplyHeader.LOCATION_FORWARD;
 498:                 s_info.m_forward_reference = fex.forward_reference;
 499:                 try
 500:                   {
 501:                     s_interceptor.send_other(s_info);
 502:                     break Forwarding;
 503:                   }
 504:                 catch (ForwardRequest fex2)
 505:                   {
 506:                     s_info.m_forward_reference = fex2.forward;
 507:                     fex.forward_reference = (ObjectImpl) fex2.forward;
 508:                   }
 509:               }
 510:           }
 511: 
 512:         if (c_intercept)
 513:           {
 514:             this.m_rph.reply_status = ReplyHeader.LOCATION_FORWARD;
 515:             this.m_forwarding_target = fex.forward_reference;
 516:             try
 517:               {
 518:                 c_interceptor.receive_other(c_info);
 519:               }
 520:             catch (ForwardRequest fex2)
 521:               {
 522:                 fex.forward_reference = (ObjectImpl) fex2.forward;
 523:               }
 524:           }
 525:         throw fex;
 526:       }
 527:   }
 528: 
 529:   /**
 530:    * Make an invocation and store the result in the fields of this Request. Used
 531:    * with DII only.
 532:    */
 533:   public void invoke()
 534:   {
 535:     InvokeHandler handler = object.getHandler(operation(), cookie, false);
 536: 
 537:     if (handler instanceof DynamicImpHandler)
 538:       {
 539:         DynamicImplementation dyn = ((DynamicImpHandler) handler).servant;
 540:         if (serverRequest == null)
 541:           {
 542:             serverRequest = new LocalServerRequest(this);
 543:           }
 544:         try
 545:           {
 546:             poa.m_orb.currents.put(Thread.currentThread(), this);
 547:             dyn.invoke(serverRequest);
 548:           }
 549:         finally
 550:           {
 551:             poa.m_orb.currents.remove(Thread.currentThread());
 552:           }
 553:       }
 554:     else
 555:       {
 556:         org.omg.CORBA.portable.InputStream input = v_invoke(handler);
 557: 
 558:         if (!exceptionReply)
 559:           {
 560:             NamedValue arg;
 561: 
 562:             // Read return value, if set.
 563:             if (m_result != null)
 564:               {
 565:                 m_result.value().read_value(input, m_result.value().type());
 566:               }
 567: 
 568:             // Read returned parameters, if set.
 569:             if (m_args != null)
 570:               {
 571:                 for (int i = 0; i < m_args.count(); i++)
 572:                   {
 573:                     try
 574:                       {
 575:                         arg = m_args.item(i);
 576: 
 577:                         // Both ARG_INOUT and ARG_OUT have this binary flag set.
 578:                         if ((arg.flags() & ARG_OUT.value) != 0)
 579:                           {
 580:                             arg.value().read_value(input, arg.value().type());
 581:                           }
 582:                       }
 583:                     catch (Bounds ex)
 584:                       {
 585:                         Unexpected.error(ex);
 586:                       }
 587:                   }
 588:               }
 589:           }
 590:         else// User exception reply
 591:           {
 592:             // Prepare an Any that will hold the exception.
 593:             gnuAny exc = new gnuAny();
 594: 
 595:             exc.insert_Streamable(new StreamHolder(input));
 596: 
 597:             UnknownUserException unuex = new UnknownUserException(exc);
 598:             m_environment.exception(unuex);
 599:           }
 600:       }
 601:   }
 602: 
 603:   /**
 604:    * Get an output stream for providing details about the exception. Before
 605:    * returning the stream, the handler automatically writes the message header
 606:    * and the reply about exception header, but not the message header.
 607:    *
 608:    * @return the stream to write exception details into.
 609:    */
 610:   public OutputStream createExceptionReply()
 611:   {
 612:     exceptionReply = true;
 613:     prepareStream();
 614:     return buffer;
 615:   }
 616: 
 617:   /**
 618:    * Get an output stream for writing a regular reply (not an exception).
 619:    *
 620:    * Before returning the stream, the handler automatically writes the regular
 621:    * reply header, but not the message header.
 622:    *
 623:    * @return the output stream for writing a regular reply.
 624:    */
 625:   public OutputStream createReply()
 626:   {
 627:     exceptionReply = false;
 628:     prepareStream();
 629:     return buffer;
 630:   }
 631: 
 632:   /**
 633:    * Get the buffer, normally containing the written reply. The reply includes
 634:    * the reply header (or the exception header) but does not include the message
 635:    * header.
 636:    *
 637:    * The stream buffer can also be empty if no data have been written into
 638:    * streams, returned by {@link #createReply()} or
 639:    * {@link #createExceptionReply()}.
 640:    *
 641:    * @return the CDR output stream, containing the written output.
 642:    */
 643:   BufferedCdrOutput getBuffer()
 644:   {
 645:     return buffer;
 646:   }
 647: 
 648:   /**
 649:    * True if the stream was obtained by invoking {@link #createExceptionReply()},
 650:    * false otherwise (usually no-exception reply).
 651:    */
 652:   boolean isExceptionReply()
 653:   {
 654:     return exceptionReply;
 655:   }
 656: 
 657:   /**
 658:    * Compute the header offset, set the correct version number and codeset.
 659:    */
 660:   private void prepareStream()
 661:   {
 662:     buffer = new BufferedCdrOutput();
 663:     buffer.setOrb(orb());
 664:   }
 665: 
 666:   /**
 667:    * Get the parameter stream, where the invocation arguments should be written
 668:    * if they are written into the stream directly.
 669:    */
 670:   public StreamBasedRequest getParameterStream()
 671:   {
 672:     m_parameter_buffer = new StreamBasedRequest();
 673:     m_parameter_buffer.request = this;
 674:     m_parameter_buffer.setOrb(poa.orb());
 675:     return m_parameter_buffer;
 676:   }
 677: 
 678:   public byte[] get_object_id() throws NoContext
 679:   {
 680:     return Id;
 681:   }
 682: 
 683:   public POA get_POA() throws NoContext
 684:   {
 685:     return poa;
 686:   }
 687: }