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 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:     // Local request must be intercepted both by server and request
 202:     // interceptors.
 203:     boolean s_intercept = false;
 204:     ServerRequestInterceptorOperations s_interceptor = null;
 205:     gnuServerRequestInfo s_info = null;
 206: 
 207:     boolean c_intercept = false;
 208:     ClientRequestInterceptorOperations c_interceptor = null;
 209:     gnuClientRequestInfo c_info = null;
 210: 
 211:     try
 212:       {
 213:         if (poa.m_orb.iServer != null || poa.m_orb.iClient != null)
 214:           {
 215:             setORB(poa.m_orb);
 216: 
 217:             // These two are only needed with interceptors.
 218:             m_rqh = new RequestHeader();
 219:             m_rqh.operation = m_operation;
 220:             m_rph = new ReplyHeader();
 221: 
 222:             m_rqh.object_key = object.Id;
 223:             m_rph.request_id = m_rqh.request_id;
 224:           }
 225: 
 226:         if (poa.m_orb.iClient != null)
 227:           {
 228:             c_interceptor = poa.m_orb.iClient;
 229: 
 230:             c_info = new gnuClientRequestInfo(this);
 231:             c_intercept = true;
 232: 
 233:             c_interceptor.send_request(c_info);
 234: 
 235:             m_target = object;
 236:           }
 237: 
 238:         if (poa.m_orb.iServer != null)
 239:           {
 240:             s_interceptor = poa.m_orb.iServer;
 241: 
 242:             s_info = new gnuServerRequestInfo(object, m_rqh, m_rph);
 243:             s_info.m_request = this;
 244: 
 245:             s_intercept = true;
 246: 
 247:             s_interceptor.receive_request_service_contexts(s_info);
 248:           }
 249: 
 250:         if (handler == null)
 251:           {
 252:             handler = object.getHandler(operation(), cookie, false);
 253:           }
 254: 
 255:         BufferedCdrOutput request_part = new BufferedCdrOutput();
 256: 
 257:         request_part.setOrb(orb());
 258: 
 259:         if (m_args != null && m_args.count() > 0)
 260:           {
 261:             write_parameters(header, request_part);
 262: 
 263:             if (m_parameter_buffer != null)
 264:               {
 265:                 throw new BAD_INV_ORDER("Please either add parameters or " +
 266:                   "write them into stream, but not both " + "at once."
 267:                 );
 268:               }
 269:           }
 270: 
 271:         if (m_parameter_buffer != null)
 272:           {
 273:             write_parameter_buffer(header, request_part);
 274:           }
 275: 
 276:         Servant servant;
 277: 
 278:         if (handler instanceof Servant)
 279:           {
 280:             servant = (Servant) handler;
 281:           }
 282:         else
 283:           {
 284:             throw new BAD_OPERATION("Unexpected handler type " + handler);
 285:           }
 286: 
 287:         org.omg.CORBA.portable.InputStream input =
 288:           request_part.create_input_stream();
 289: 
 290:         // Ensure the servant (handler) has a delegate set.
 291:         ServantDelegateImpl sd = null;
 292: 
 293:         Delegate d = null;
 294: 
 295:         try
 296:           {
 297:             d = servant._get_delegate();
 298:           }
 299:         catch (Exception ex)
 300:           {
 301:             // In some cases exception is thrown if the delegate is not set.
 302:           }
 303:         if (d instanceof ServantDelegateImpl)
 304:           {
 305:             // If the delegate is already set, try to reuse the existing
 306:             // instance.
 307:             sd = (ServantDelegateImpl) d;
 308:             if (sd.object != object)
 309:               {
 310:                 sd = new ServantDelegateImpl(servant, poa, Id);
 311:               }
 312:           }
 313:         else
 314:           {
 315:             sd = new ServantDelegateImpl(servant, poa, Id);
 316:           }
 317:         servant._set_delegate(sd);
 318: 
 319:         try
 320:           {
 321:             ORB o = orb();
 322:             if (o instanceof ORB_1_4)
 323:               {
 324:                 ((ORB_1_4) o).currents.put(Thread.currentThread(), this);
 325:               }
 326: 
 327:             try
 328:               {
 329:                 if (s_intercept)
 330:                   {
 331:                     s_interceptor.receive_request(s_info);
 332:                   }
 333:                 handler._invoke(m_operation, input, this);
 334: 
 335:                 // Handler is casted into i_handler.
 336:                 if ((s_intercept || c_intercept) && isExceptionReply())
 337:                   {
 338:                     s_info.m_reply_header.reply_status =
 339:                       ReplyHeader.USER_EXCEPTION;
 340:                     m_rph.reply_status = ReplyHeader.USER_EXCEPTION;
 341: 
 342:                     // Make Any, holding the user exception.
 343:                     Any a = new gnuAny();
 344:                     OutputStream buf = getBuffer();
 345:                     InputStream in = buf.create_input_stream();
 346:                     String uex_idl = "unknown";
 347:                     try
 348:                       {
 349:                         in.mark(Integer.MAX_VALUE);
 350:                         uex_idl = in.read_string();
 351:                         m_exception_id = uex_idl;
 352:                         in.reset();
 353:                       }
 354:                     catch (IOException e)
 355:                       {
 356:                         throw new Unexpected(e);
 357:                       }
 358: 
 359:                     try
 360:                       {
 361:                         UserException exception =
 362:                           ObjectCreator.readUserException(uex_idl, in);
 363: 
 364:                         m_environment.exception(exception);
 365:                         ObjectCreator.insertWithHelper(a, exception);
 366:                       }
 367:                     catch (Exception e)
 368:                       {
 369:                         // Failed due any reason, insert without
 370:                         // helper.
 371:                         a.insert_Streamable(new StreamHolder(
 372:                             buf.create_input_stream()
 373:                           )
 374:                         );
 375: 
 376:                         RecordTypeCode r =
 377:                           new RecordTypeCode(TCKind.tk_except);
 378:                         r.setId(uex_idl);
 379:                         r.setName(ObjectCreator.getDefaultName(uex_idl));
 380:                       }
 381: 
 382:                     s_info.m_usr_exception = a;
 383:                     c_info.m_wrapped_exception = a;
 384:                     s_interceptor.send_exception(s_info);
 385:                     c_interceptor.receive_exception(c_info);
 386:                   }
 387:                 else
 388:                   {
 389:                     if (s_intercept)
 390:                       {
 391:                         s_info.m_reply_header.reply_status =
 392:                           ReplyHeader.NO_EXCEPTION;
 393:                         s_interceptor.send_reply(s_info);
 394:                       }
 395:                     if (c_intercept)
 396:                       {
 397:                         m_rph.reply_status = ReplyHeader.NO_EXCEPTION;
 398:                         c_interceptor.receive_reply(c_info);
 399:                       }
 400:                   }
 401:               }
 402:             catch (SystemException sys_ex)
 403:               {
 404:                 if (s_intercept)
 405:                   {
 406:                     s_info.m_reply_header.reply_status =
 407:                       ReplyHeader.SYSTEM_EXCEPTION;
 408:                     s_info.m_sys_exception = sys_ex;
 409:                     s_interceptor.send_exception(s_info);
 410:                   }
 411: 
 412:                 if (c_intercept)
 413:                   {
 414:                     m_rph.reply_status = ReplyHeader.SYSTEM_EXCEPTION;
 415: 
 416:                     Any a = new gnuAny();
 417:                     if (ObjectCreator.insertSysException(a, sys_ex))
 418:                       {
 419:                         c_info.m_wrapped_exception = a;
 420:                       }
 421:                     c_interceptor.receive_exception(c_info);
 422:                   }
 423: 
 424:                 throw sys_ex;
 425:               }
 426:           }
 427:         finally
 428:           {
 429:             ORB o = orb();
 430:             if (o instanceof ORB_1_4)
 431:               {
 432:                 ((ORB_1_4) o).currents.remove(Thread.currentThread());
 433:               }
 434:           }
 435: 
 436:         if (poa.servant_locator != null)
 437:           {
 438:             poa.servant_locator.postinvoke(object.Id, poa, operation(),
 439:               cookie.value, object.getServant()
 440:             );
 441:           }
 442:         return buffer.create_input_stream();
 443:       }
 444: 
 445:     catch (ForwardRequest fex)
 446:       {
 447:         // May be thrown by interceptor.
 448:         if (s_intercept)
 449:           {
 450:             Forwarding:
 451:             while (true)
 452:               {
 453:                 s_info.m_reply_header.reply_status =
 454:                   ReplyHeader.LOCATION_FORWARD;
 455:                 s_info.m_forward_reference = fex.forward;
 456:                 try
 457:                   {
 458:                     s_interceptor.send_other(s_info);
 459:                     break Forwarding;
 460:                   }
 461:                 catch (ForwardRequest fex2)
 462:                   {
 463:                     s_info.m_forward_reference = fex2.forward;
 464:                     fex.forward = s_info.m_forward_reference;
 465:                   }
 466:               }
 467:           }
 468: 
 469:         if (c_intercept)
 470:           {
 471:             this.m_rph.reply_status = ReplyHeader.LOCATION_FORWARD;
 472:             this.m_forwarding_target = fex.forward;
 473:             try
 474:               {
 475:                 c_interceptor.receive_other(c_info);
 476:               }
 477:             catch (ForwardRequest fex2)
 478:               {
 479:                 fex.forward = fex2.forward;
 480:               }
 481:           }
 482:         throw new gnuForwardRequest(fex.forward);
 483:       }
 484:     catch (gnuForwardRequest fex)
 485:       {
 486:         // May be thrown during activation.
 487:         // May be thrown during activation.
 488:         if (s_intercept)
 489:           {
 490:             Forwarding:
 491:             while (true)
 492:               {
 493:                 s_info.m_reply_header.reply_status =
 494:                   ReplyHeader.LOCATION_FORWARD;
 495:                 s_info.m_forward_reference = fex.forward_reference;
 496:                 try
 497:                   {
 498:                     s_interceptor.send_other(s_info);
 499:                     break Forwarding;
 500:                   }
 501:                 catch (ForwardRequest fex2)
 502:                   {
 503:                     s_info.m_forward_reference = fex2.forward;
 504:                     fex.forward_reference = (ObjectImpl) fex2.forward;
 505:                   }
 506:               }
 507:           }
 508: 
 509:         if (c_intercept)
 510:           {
 511:             this.m_rph.reply_status = ReplyHeader.LOCATION_FORWARD;
 512:             this.m_forwarding_target = fex.forward_reference;
 513:             try
 514:               {
 515:                 c_interceptor.receive_other(c_info);
 516:               }
 517:             catch (ForwardRequest fex2)
 518:               {
 519:                 fex.forward_reference = (ObjectImpl) fex2.forward;
 520:               }
 521:           }
 522:         throw fex;
 523:       }
 524:   }
 525: 
 526:   /**
 527:    * Make an invocation and store the result in the fields of this Request. Used
 528:    * with DII only.
 529:    */
 530:   public void invoke()
 531:   {
 532:     InvokeHandler handler = object.getHandler(operation(), cookie, false);
 533: 
 534:     if (handler instanceof DynamicImpHandler)
 535:       {
 536:         DynamicImplementation dyn = ((DynamicImpHandler) handler).servant;
 537:         if (serverRequest == null)
 538:           {
 539:             serverRequest = new LocalServerRequest(this);
 540:           }
 541:         try
 542:           {
 543:             poa.m_orb.currents.put(Thread.currentThread(), this);
 544:             dyn.invoke(serverRequest);
 545:           }
 546:         finally
 547:           {
 548:             poa.m_orb.currents.remove(Thread.currentThread());
 549:           }
 550:       }
 551:     else
 552:       {
 553:         org.omg.CORBA.portable.InputStream input = v_invoke(handler);
 554: 
 555:         if (!exceptionReply)
 556:           {
 557:             NamedValue arg;
 558: 
 559:             // Read return value, if set.
 560:             if (m_result != null)
 561:               {
 562:                 m_result.value().read_value(input, m_result.value().type());
 563:               }
 564: 
 565:             // Read returned parameters, if set.
 566:             if (m_args != null)
 567:               {
 568:                 for (int i = 0; i < m_args.count(); i++)
 569:                   {
 570:                     try
 571:                       {
 572:                         arg = m_args.item(i);
 573: 
 574:                         // Both ARG_INOUT and ARG_OUT have this binary flag set.
 575:                         if ((arg.flags() & ARG_OUT.value) != 0)
 576:                           {
 577:                             arg.value().read_value(input, arg.value().type());
 578:                           }
 579:                       }
 580:                     catch (Bounds ex)
 581:                       {
 582:                         Unexpected.error(ex);
 583:                       }
 584:                   }
 585:               }
 586:           }
 587:         else// User exception reply
 588:           {
 589:             // Prepare an Any that will hold the exception.
 590:             gnuAny exc = new gnuAny();
 591: 
 592:             exc.insert_Streamable(new StreamHolder(input));
 593: 
 594:             UnknownUserException unuex = new UnknownUserException(exc);
 595:             m_environment.exception(unuex);
 596:           }
 597:       }
 598:   }
 599: 
 600:   /**
 601:    * Get an output stream for providing details about the exception. Before
 602:    * returning the stream, the handler automatically writes the message header
 603:    * and the reply about exception header, but not the message header.
 604:    *
 605:    * @return the stream to write exception details into.
 606:    */
 607:   public OutputStream createExceptionReply()
 608:   {
 609:     exceptionReply = true;
 610:     prepareStream();
 611:     return buffer;
 612:   }
 613: 
 614:   /**
 615:    * Get an output stream for writing a regular reply (not an exception).
 616:    *
 617:    * Before returning the stream, the handler automatically writes the regular
 618:    * reply header, but not the message header.
 619:    *
 620:    * @return the output stream for writing a regular reply.
 621:    */
 622:   public OutputStream createReply()
 623:   {
 624:     exceptionReply = false;
 625:     prepareStream();
 626:     return buffer;
 627:   }
 628: 
 629:   /**
 630:    * Get the buffer, normally containing the written reply. The reply includes
 631:    * the reply header (or the exception header) but does not include the message
 632:    * header.
 633:    *
 634:    * The stream buffer can also be empty if no data have been written into
 635:    * streams, returned by {@link #createReply()} or
 636:    * {@link #createExceptionReply()}.
 637:    *
 638:    * @return the CDR output stream, containing the written output.
 639:    */
 640:   BufferedCdrOutput getBuffer()
 641:   {
 642:     return buffer;
 643:   }
 644: 
 645:   /**
 646:    * True if the stream was obtained by invoking {@link #createExceptionReply()},
 647:    * false otherwise (usually no-exception reply).
 648:    */
 649:   boolean isExceptionReply()
 650:   {
 651:     return exceptionReply;
 652:   }
 653: 
 654:   /**
 655:    * Compute the header offset, set the correct version number and codeset.
 656:    */
 657:   private void prepareStream()
 658:   {
 659:     buffer = new BufferedCdrOutput();
 660:     buffer.setOrb(orb());
 661:   }
 662: 
 663:   /**
 664:    * Get the parameter stream, where the invocation arguments should be written
 665:    * if they are written into the stream directly.
 666:    */
 667:   public StreamBasedRequest getParameterStream()
 668:   {
 669:     m_parameter_buffer = new StreamBasedRequest();
 670:     m_parameter_buffer.request = this;
 671:     m_parameter_buffer.setOrb(poa.orb());
 672:     return m_parameter_buffer;
 673:   }
 674: 
 675:   public byte[] get_object_id() throws NoContext
 676:   {
 677:     return Id;
 678:   }
 679: 
 680:   public POA get_POA() throws NoContext
 681:   {
 682:     return poa;
 683:   }