Source for gnu.CORBA.gnuRequest

   1: /* gnuRequest.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;
  40: 
  41: import gnu.CORBA.CDR.BufferredCdrInput;
  42: import gnu.CORBA.CDR.BufferedCdrOutput;
  43: import gnu.CORBA.GIOP.MessageHeader;
  44: import gnu.CORBA.GIOP.ReplyHeader;
  45: import gnu.CORBA.GIOP.RequestHeader;
  46: import gnu.CORBA.GIOP.CodeSetServiceContext;
  47: import gnu.CORBA.Interceptor.gnuClientRequestInfo;
  48: import gnu.CORBA.Poa.ORB_1_4;
  49: 
  50: import org.omg.CORBA.ARG_IN;
  51: import org.omg.CORBA.ARG_INOUT;
  52: import org.omg.CORBA.ARG_OUT;
  53: import org.omg.CORBA.Any;
  54: import org.omg.CORBA.BAD_INV_ORDER;
  55: import org.omg.CORBA.BAD_PARAM;
  56: import org.omg.CORBA.Bounds;
  57: import org.omg.CORBA.COMM_FAILURE;
  58: import org.omg.CORBA.CompletionStatus;
  59: import org.omg.CORBA.Context;
  60: import org.omg.CORBA.ContextList;
  61: import org.omg.CORBA.Environment;
  62: import org.omg.CORBA.ExceptionList;
  63: import org.omg.CORBA.INV_POLICY;
  64: import org.omg.CORBA.MARSHAL;
  65: import org.omg.CORBA.NO_IMPLEMENT;
  66: import org.omg.CORBA.NO_RESOURCES;
  67: import org.omg.CORBA.NVList;
  68: import org.omg.CORBA.NamedValue;
  69: import org.omg.CORBA.ORB;
  70: import org.omg.CORBA.Policy;
  71: import org.omg.CORBA.Request;
  72: import org.omg.CORBA.SystemException;
  73: import org.omg.CORBA.TypeCode;
  74: import org.omg.CORBA.UnknownUserException;
  75: import org.omg.CORBA.portable.ObjectImpl;
  76: import org.omg.IOP.ServiceContext;
  77: import org.omg.IOP.TAG_CODE_SETS;
  78: import org.omg.IOP.TAG_INTERNET_IOP;
  79: import org.omg.IOP.TaggedComponent;
  80: import org.omg.IOP.TaggedProfile;
  81: import org.omg.PortableInterceptor.ClientRequestInfo;
  82: import org.omg.PortableInterceptor.ClientRequestInterceptorOperations;
  83: import org.omg.PortableInterceptor.ForwardRequest;
  84: import org.omg.PortableInterceptor.InvalidSlot;
  85: 
  86: import java.io.EOFException;
  87: import java.io.IOException;
  88: import java.io.InputStream;
  89: import java.io.OutputStream;
  90: 
  91: import java.net.BindException;
  92: import java.net.Socket;
  93: 
  94: import java.util.ArrayList;
  95: 
  96: /**
  97:  * The implementation of the CORBA request.
  98:  *
  99:  * @author Audrius Meskauskas (AudriusA@Bioinformatics.org)
 100:  */
 101: public class gnuRequest extends Request implements Cloneable
 102: {
 103:   /**
 104:    * The maximal supported GIOP version.
 105:    */
 106:   public static Version MAX_SUPPORTED = new Version(1, 2);
 107: 
 108:   /**
 109:    * The initial pause that the Request makes when the required port is not
 110:    * available.
 111:    */
 112:   public static int PAUSE_INITIAL = 50;
 113: 
 114:   /**
 115:    * The number of repretetive attempts to get a required port, if it is not
 116:    * immediately available.
 117:    */
 118:   public static int PAUSE_STEPS = 12;
 119: 
 120:   /**
 121:    * The maximal pausing interval between two repetetive attempts. The interval
 122:    * doubles after each unsuccessful attempt, but will not exceed this value.
 123:    */
 124:   public static int PAUSE_MAX = 1000;
 125: 
 126:   /**
 127:    * The interceptor, listening the major request submission points.
 128:    */
 129:   ClientRequestInterceptorOperations m_interceptor;
 130: 
 131:   /**
 132:    * The request info, used by interceptor.
 133:    */
 134:   ClientRequestInfo m_info = new gnuClientRequestInfo(this);
 135: 
 136:   /**
 137:    * The empty byte array.
 138:    */
 139:   private static final RawReply EMPTY =
 140:     new RawReply(null, new MessageHeader(), new byte[ 0 ]);
 141: 
 142:   /**
 143:    * The context holder for methods ctx(Context) and ctx().
 144:    */
 145:   protected Context m_context;
 146: 
 147:   /**
 148:    * The context list for method contexts().
 149:    */
 150:   protected ContextList m_context_list;
 151: 
 152:   /**
 153:    * The request environment for holding the exception the has possibly been
 154:    * thrown by the method being invoked.
 155:    */
 156:   protected Environment m_environment = new gnuEnvironment();
 157: 
 158:   /**
 159:    * The list of all exceptions that can be thrown by the method being invoked.
 160:    */
 161:   protected ExceptionList m_exceptions = new gnuExceptionList();
 162: 
 163:   /**
 164:    * The result, returned by the invoked method (function).
 165:    */
 166:   protected NamedValue m_result = new gnuNamedValue();
 167: 
 168:   /**
 169:    * The exception id, received from the server, null if none.
 170:    */
 171:   protected String m_exception_id;
 172: 
 173:   /**
 174:    * The thrown system exception.
 175:    */
 176:   protected SystemException m_sys_ex;
 177: 
 178:   /**
 179:    * The invocation target.
 180:    */
 181:   protected org.omg.CORBA.Object m_target;
 182: 
 183:   /**
 184:    * The name of the method being invoked.
 185:    */
 186:   protected String m_operation;
 187: 
 188:   /**
 189:    * This field temporary remembers the value of the forwarded ior reference. If
 190:    * it is not null, the request was forwarded and the effective target is not
 191:    * the same as the default target.
 192:    */
 193:   public IOR m_forward_ior;
 194: 
 195:   /**
 196:    * Is set when object, and not IOR is directly available.
 197:    */
 198:   public org.omg.CORBA.Object m_forwarding_target;
 199: 
 200:   /**
 201:    * The flag, indicating that the request has been sent and the result is
 202:    * already received.
 203:    */
 204:   protected boolean complete;
 205: 
 206:   /**
 207:    * The flag, indicating that the response to this request must be ignored
 208:    * (used with {@link #send_oneway()}).
 209:    */
 210:   protected boolean oneWay;
 211: 
 212:   /**
 213:    * The flag, indicating that the request has been sent and no result is yet
 214:    * received.
 215:    */
 216:   protected boolean running;
 217: 
 218:   /**
 219:    * The request arguments.
 220:    */
 221:   protected gnuNVList m_args = new gnuNVList();
 222: 
 223:   /**
 224:    * The request arguments in the case when they are directly written into the
 225:    * parameter buffer.
 226:    */
 227:   protected StreamBasedRequest m_parameter_buffer;
 228: 
 229:   /**
 230:    * The array of slots.
 231:    */
 232:   protected Any[] m_slots;
 233: 
 234:   /**
 235:    * The request header currently in use.
 236:    */
 237:   protected RequestHeader m_rqh;
 238: 
 239:   /**
 240:    * The reply header currently in use.
 241:    */
 242:   protected ReplyHeader m_rph;
 243: 
 244:   /**
 245:    * The IOR of the target.
 246:    */
 247:   private IOR ior;
 248: 
 249:   /**
 250:    * The ORB of the target.
 251:    */
 252:   private ORB orb;
 253: 
 254:   /**
 255:    * The encoding, used to send the message.
 256:    *
 257:    * The default encoding is inherited from the set IOR (that string reference
 258:    * can be encoded in either Big or Little endian). If the IOR encoding is not
 259:    * known (for example, by obtaining the reference from the naming service),
 260:    * the Big Endian is used.
 261:    */
 262:   private boolean Big_endian = true;
 263: 
 264:   /**
 265:    * Set the IOR data, sufficient to find the invocation target. This also sets
 266:    * default endian encoding for invocations.
 267:    *
 268:    * @see IOR.parse(String)
 269:    */
 270:   public void setIor(IOR an_ior)
 271:   {
 272:     ior = an_ior;
 273:     setBigEndian(ior.Big_Endian);
 274:   }
 275: 
 276:   /**
 277:    * Used when redirecting request to another target.
 278:    */
 279:   gnuRequest redirected;
 280: 
 281:   /**
 282:    * Get the IOR data, sufficient to find the invocation target.
 283:    *
 284:    * @return the IOR data.
 285:    */
 286:   public IOR getIor()
 287:   {
 288:     return ior;
 289:   }
 290: 
 291:   /**
 292:    * Set the ORB, related to the invocation target.
 293:    */
 294:   public void setORB(ORB an_orb)
 295:   {
 296:     orb = an_orb;
 297: 
 298:     // Take the interceptor from the ORB.
 299:     if (orb instanceof OrbRestricted)
 300:       m_interceptor = ((OrbRestricted) orb).iClient;
 301: 
 302:     if (m_interceptor != null && orb instanceof ORB_1_4)
 303:       {
 304:         m_slots = ((ORB_1_4) orb).ic_current.clone_slots();
 305:       }
 306:   }
 307: 
 308:   /**
 309:    * Set the encoding that will be used to send the message. The default
 310:    * encoding is inherited from the set IOR (that string reference can be
 311:    * encoded in either Big or Little endian). If the IOR encoding is not known
 312:    * (for example, by obtaining the reference from the naming service), the Big
 313:    * Endian is used.
 314:    *
 315:    * @param use_big_endian true to use the Big Endian, false to use the Little
 316:    * Endian encoding.
 317:    */
 318:   public void setBigEndian(boolean use_big_endian)
 319:   {
 320:     Big_endian = use_big_endian;
 321:   }
 322: 
 323:   /**
 324:    * The the method name to invoke.
 325:    *
 326:    * @param operation the method name.
 327:    */
 328:   public void setOperation(String operation)
 329:   {
 330:     m_operation = operation;
 331:   }
 332: 
 333:   /**
 334:    * Get the parameter stream, where the invocation arguments should be written
 335:    * if they are written into the stream directly.
 336:    */
 337:   public StreamBasedRequest getParameterStream()
 338:   {
 339:     m_parameter_buffer = new StreamBasedRequest();
 340:     m_parameter_buffer.request = this;
 341:     m_parameter_buffer.setVersion(ior.Internet.version);
 342:     m_parameter_buffer.setCodeSet(CodeSetServiceContext.negotiate(ior.Internet.CodeSets));
 343:     m_parameter_buffer.setOrb(orb);
 344:     m_parameter_buffer.setBigEndian(Big_endian);
 345: 
 346:     // For the old iiop versions, it is important to set the size
 347:     // correctly.
 348:     if (ior.Internet.version.until_inclusive(1, 1))
 349:       {
 350:         BufferedCdrOutput measure = new BufferedCdrOutput();
 351:         measure.setOffset(12);
 352:         if (m_rqh == null)
 353:           m_rqh = new gnu.CORBA.GIOP.v1_0.RequestHeader();
 354:         m_rqh.operation = m_operation;
 355:         m_rqh.object_key = ior.key;
 356:         m_rqh.write(measure);
 357:         m_parameter_buffer.setOffset(12 + measure.buffer.size());
 358:       }
 359: 
 360:     return m_parameter_buffer;
 361:   }
 362: 
 363:   /**
 364:    * Creates a shallow copy of this request.
 365:    */
 366:   public gnuRequest Clone()
 367:   {
 368:     try
 369:       {
 370:         return (gnuRequest) clone();
 371:       }
 372:     catch (CloneNotSupportedException ex)
 373:       {
 374:         throw new Unexpected(ex);
 375:       }
 376:   }
 377: 
 378:   /** {@inheritDoc} */
 379:   public Any add_in_arg()
 380:   {
 381:     gnuNamedValue v = new gnuNamedValue();
 382:     v.setFlags(ARG_IN.value);
 383:     m_args.add(v);
 384:     return v.value();
 385:   }
 386: 
 387:   /** {@inheritDoc} */
 388:   public Any add_inout_arg()
 389:   {
 390:     gnuNamedValue v = new gnuNamedValue();
 391:     v.setFlags(ARG_INOUT.value);
 392:     m_args.add(v);
 393:     return v.value();
 394:   }
 395: 
 396:   /** {@inheritDoc} */
 397:   public Any add_named_in_arg(String name)
 398:   {
 399:     gnuNamedValue v = new gnuNamedValue();
 400:     v.setFlags(ARG_IN.value);
 401:     v.setName(name);
 402:     m_args.add(v);
 403:     return v.value();
 404:   }
 405: 
 406:   /** {@inheritDoc} */
 407:   public Any add_named_inout_arg(String name)
 408:   {
 409:     gnuNamedValue v = new gnuNamedValue();
 410:     v.setFlags(ARG_INOUT.value);
 411:     v.setName(name);
 412:     m_args.add(v);
 413:     return v.value();
 414:   }
 415: 
 416:   /** {@inheritDoc} */
 417:   public Any add_named_out_arg(String name)
 418:   {
 419:     gnuNamedValue v = new gnuNamedValue();
 420:     v.setFlags(ARG_OUT.value);
 421:     v.setName(name);
 422:     m_args.add(v);
 423:     return v.value();
 424:   }
 425: 
 426:   /** {@inheritDoc} */
 427:   public Any add_out_arg()
 428:   {
 429:     gnuNamedValue v = new gnuNamedValue();
 430:     v.setFlags(ARG_OUT.value);
 431:     m_args.add(v);
 432:     return v.value();
 433:   }
 434: 
 435:   /** {@inheritDoc} */
 436:   public NVList arguments()
 437:   {
 438:     return m_args;
 439:   }
 440: 
 441:   /** {@inheritDoc} */
 442:   public ContextList contexts()
 443:   {
 444:     return m_context_list;
 445:   }
 446: 
 447:   /** {@inheritDoc} */
 448:   public Context ctx()
 449:   {
 450:     return m_context;
 451:   }
 452: 
 453:   /** {@inheritDoc} */
 454:   public void ctx(Context a_context)
 455:   {
 456:     m_context = a_context;
 457:   }
 458: 
 459:   /** {@inheritDoc} */
 460:   public Environment env()
 461:   {
 462:     return m_environment;
 463:   }
 464: 
 465:   /** {@inheritDoc} */
 466:   public ExceptionList exceptions()
 467:   {
 468:     return m_exceptions;
 469:   }
 470: 
 471:   /** {@inheritDoc} */
 472:   public void get_response() throws org.omg.CORBA.WrongTransaction
 473:   {
 474:     /**
 475:      * The response is ready after it is received. FIXME implement context
 476:      * checks and any other functionality, if required.
 477:      */
 478:   }
 479: 
 480:   /**
 481:    * Submit the request, suspending the current thread until the answer is
 482:    * received.
 483:    *
 484:    * This implementation requires to set the IOR property ({@link #setIOR(IOR)}
 485:    * before calling this method.
 486:    *
 487:    * @throws BAD_INV_ORDER, minor code 0, if the IOR has not been previously
 488:    * set.
 489:    *
 490:    * @throws SystemException if this exception has been thrown on remote side.
 491:    * The exact exception type and the minor code are the same as they have been
 492:    * for the exception, thrown on remoted side.
 493:    */
 494:   public synchronized void invoke() throws BAD_INV_ORDER
 495:   {
 496:     waitWhileBusy();
 497:     complete = false;
 498:     running = true;
 499: 
 500:     if (ior == null)
 501:       throw new BAD_INV_ORDER("Set IOR property first");
 502: 
 503:     try
 504:       {
 505:         Forwardings:
 506:         while (true)
 507:           {
 508:             try
 509:               {
 510:                 p_invoke();
 511:                 break Forwardings;
 512:               }
 513:             catch (ForwardRequest e)
 514:               {
 515:                 try
 516:                   {
 517:                     ObjectImpl impl = (ObjectImpl) e.forward;
 518:                     SimpleDelegate delegate =
 519:                       (SimpleDelegate) impl._get_delegate();
 520:                     ior = delegate.getIor();
 521:                   }
 522:                 catch (Exception ex)
 523:                   {
 524:                     BAD_PARAM bad =
 525:                       new BAD_PARAM("Unsupported forwarding target");
 526:                     bad.initCause(ex);
 527:                     throw bad;
 528:                   }
 529:               }
 530:           }
 531:       }
 532:     finally
 533:       {
 534:         running = false;
 535:         complete = true;
 536:       }
 537:   }
 538: 
 539:   /** {@inheritDoc} */
 540:   public String operation()
 541:   {
 542:     return m_operation;
 543:   }
 544: 
 545:   /**
 546:    * Get the orb, related to the invocation target.
 547:    */
 548:   public ORB orb()
 549:   {
 550:     return orb;
 551:   }
 552: 
 553:   /** {@inheritDoc} */
 554:   public boolean poll_response()
 555:   {
 556:     return complete && !running;
 557:   }
 558: 
 559:   /** {@inheritDoc} */
 560:   public NamedValue result()
 561:   {
 562:     return m_result;
 563:   }
 564: 
 565:   /**
 566:    * {@inheritDoc}
 567:    *
 568:    */
 569:   public Any return_value()
 570:   {
 571:     return m_result.value();
 572:   }
 573: 
 574:   /** {@inheritDoc} */
 575:   public synchronized void send_deferred()
 576:   {
 577:     waitWhileBusy();
 578:     new Thread()
 579:       {
 580:         public void run()
 581:         {
 582:           invoke();
 583:         }
 584:       }.start();
 585:   }
 586: 
 587:   /**
 588:    * Send a request and forget about it, not waiting for a response. This can be
 589:    * done also for methods that normally are expected to return some values.
 590:    *
 591:    * TODO It is generally recommended to reuse the threads. Reuse?
 592:    */
 593:   public void send_oneway()
 594:   {
 595:     final gnuRequest cloned = Clone();
 596:     cloned.oneWay = true;
 597:     
 598:     new Thread()
 599:       {
 600:         public void run()
 601:         {
 602:           cloned.invoke();
 603:         }
 604:       }.start();
 605:   }
 606: 
 607:   /**
 608:    * Set the argument list. This field is initialised as empty non null instance
 609:    * by default, so the method is only used in cases when the direct replacement
 610:    * is desired.
 611:    *
 612:    * @param a_args the argument list.
 613:    */
 614:   public void set_args(NVList a_args)
 615:   {
 616:     if (a_args instanceof gnuNVList)
 617:       m_args = (gnuNVList) a_args;
 618:     else
 619:       {
 620:         try
 621:           {
 622:             // In case if this is another implementation of the NVList.
 623:             m_args.list.clear();
 624:             for (int i = 0; i < a_args.count(); i++)
 625:               {
 626:                 m_args.add(a_args.item(i));
 627:               }
 628:           }
 629:         catch (Bounds ex)
 630:           {
 631:             Unexpected.error(ex);
 632:           }
 633:       }
 634:   }
 635: 
 636:   /**
 637:    * Set the context list that is later returned by the method
 638:    * {@link #contexts()}.
 639:    *
 640:    * @param a_context_list a new context list.
 641:    */
 642:   public void set_context_list(ContextList a_context_list)
 643:   {
 644:     m_context_list = a_context_list;
 645:   }
 646: 
 647:   /**
 648:    * Set the exception container. This field is initialised as empty non null
 649:    * instance by default, so the method is only used in cases when the direct
 650:    * replacement is desired.
 651:    *
 652:    * @param a_environment the new exception container.
 653:    */
 654:   public void set_environment(Environment a_environment)
 655:   {
 656:     m_environment = a_environment;
 657:   }
 658: 
 659:   /**
 660:    * Set the list of exceptions. This field is initialised as empty non null
 661:    * instance by default, so the method is only used in cases when the direct
 662:    * replacement is desired.
 663:    *
 664:    * @param a_exceptions a list of exceptions.
 665:    */
 666:   public void set_exceptions(ExceptionList a_exceptions)
 667:   {
 668:     m_exceptions = a_exceptions;
 669:   }
 670: 
 671:   /**
 672:    * Set the operation name.
 673:    *
 674:    * @param a_operation the operation name.
 675:    */
 676:   public void set_operation(String a_operation)
 677:   {
 678:     m_operation = a_operation;
 679:   }
 680: 
 681:   /**
 682:    * Set the named value, returned as result. This field is initialised as empty
 683:    * non null instance by default, so the method is only used in cases when the
 684:    * direct replacement is desired.
 685:    *
 686:    * @param a_result the result keeper.
 687:    */
 688:   public void set_result(NamedValue a_result)
 689:   {
 690:     m_result = a_result;
 691:   }
 692: 
 693:   /**
 694:    * Set the type of the named value, returned as a result. Instantiates a new
 695:    * instance of the result value.
 696:    */
 697:   public void set_return_type(TypeCode returns)
 698:   {
 699:     if (m_result == null || !returns.equal(m_result.value().type()))
 700:       {
 701:         m_result = new gnuNamedValue();
 702:         m_result.value().type(returns);
 703:       }
 704:   }
 705: 
 706:   /**
 707:    * Set the invocation target.
 708:    *
 709:    * @param a_target the CORBA object for that the method will be invoked.
 710:    */
 711:   public void set_target(org.omg.CORBA.Object a_target)
 712:   {
 713:     m_target = a_target;
 714:   }
 715: 
 716:   /**
 717:    * Do the actual invocation. This implementation requires to set the IOR
 718:    * property ({@link #setIOR(IOR)} before calling this method.
 719:    * 
 720:    * @throws BAD_INV_ORDER, minor code 0, if the IOR has not been previously set
 721:    *           or if the direct argument addition is mixed with the direct
 722:    *           argument writing into the output stream.
 723:    * @return the server response in binary form.
 724:    */
 725: public synchronized RawReply submit()
 726:     throws ForwardRequest
 727:   {
 728:     gnu.CORBA.GIOP.MessageHeader header = new gnu.CORBA.GIOP.MessageHeader();
 729: 
 730:     header.setBigEndian(Big_endian);
 731: 
 732:     // The byte order will be Big Endian by default.
 733:     header.message_type = gnu.CORBA.GIOP.MessageHeader.REQUEST;
 734:     header.version = useVersion(ior.Internet.version);
 735: 
 736:     RequestHeader rh = header.create_request_header();
 737:     rh.operation = m_operation;
 738:     rh.object_key = ior.key;
 739: 
 740:     // Update interceptor.
 741:     m_rqh = rh;
 742: 
 743:     if (m_interceptor != null)
 744:       m_interceptor.send_request(m_info);
 745: 
 746:     // Prepare the submission.
 747:     BufferedCdrOutput request_part = new BufferedCdrOutput();
 748: 
 749:     request_part.setOffset(header.getHeaderSize());
 750:     request_part.setVersion(header.version);
 751:     request_part.setCodeSet(CodeSetServiceContext.negotiate(ior.Internet.CodeSets));
 752:     request_part.setOrb(orb);
 753:     request_part.setBigEndian(header.isBigEndian());
 754: 
 755:     // This also sets the stream encoding to the encoding, specified
 756:     // in the header.
 757:     rh.write(request_part);
 758: 
 759:     if (m_args != null && m_args.count() > 0)
 760:       {
 761:         write_parameters(header, request_part);
 762: 
 763:         if (m_parameter_buffer != null)
 764:           throw new BAD_INV_ORDER("Please either add parameters or "
 765:             + "write them into stream, but not both " + "at once.");
 766:       }
 767: 
 768:     if (m_parameter_buffer != null)
 769:       {
 770:         write_parameter_buffer(header, request_part);
 771:       }
 772: 
 773:     // Now the message size is available.
 774:     header.message_size = request_part.buffer.size();
 775: 
 776:     Socket socket = null;
 777: 
 778:     java.lang.Object key = ior.Internet.host + ":" + ior.Internet.port;
 779: 
 780:     synchronized (SocketRepository.class)
 781:       {
 782:         socket = SocketRepository.get_socket(key);
 783:       }
 784: 
 785:     try
 786:       {
 787:         long pause = PAUSE_INITIAL;
 788: 
 789:         if (socket == null)
 790:           {
 791:             // The IOException may be thrown under very heavy parallel
 792:             // load. For some time, just wait, exceptiong the socket to free.
 793:             Open: for (int i = 0; i < PAUSE_STEPS; i++)
 794:               {
 795:                 try
 796:                   {
 797:                     if (orb instanceof OrbFunctional)
 798:                       socket = ((OrbFunctional) orb).socketFactory.
 799:                         createClientSocket(
 800:                           ior.Internet.host, ior.Internet.port);
 801:                     else
 802:                       socket = new Socket(ior.Internet.host, ior.Internet.port);
 803:                     break Open;
 804:                   }
 805:                 catch (IOException ex)
 806:                   {
 807:                     try
 808:                       {
 809:                         // Expecting to free a socket via finaliser.
 810:                         System.gc();
 811:                         Thread.sleep(pause);
 812:                         pause = pause * 2;
 813:                         if (pause > PAUSE_MAX)
 814:                           pause = PAUSE_MAX;
 815:                       }
 816:                     catch (InterruptedException iex)
 817:                       {
 818:                       }
 819:                   }
 820:               }
 821:           }
 822: 
 823:         if (socket == null)
 824:           throw new NO_RESOURCES(ior.Internet.host + ":" + ior.Internet.port
 825:             + " in use");
 826:         socket.setKeepAlive(true);
 827: 
 828:         OutputStream socketOutput = socket.getOutputStream();
 829: 
 830:         // Write the message header.
 831:         header.write(socketOutput);
 832: 
 833:         // Write the request header and parameters (if present).
 834:         request_part.buffer.writeTo(socketOutput);
 835: 
 836:         socketOutput.flush();
 837:         if (!socket.isClosed() && !oneWay)
 838:           {
 839:             MessageHeader response_header = new MessageHeader();
 840:             InputStream socketInput = socket.getInputStream();
 841:             response_header.read(socketInput);
 842: 
 843:             byte[] r;
 844:             if (orb instanceof OrbFunctional)
 845:               {
 846:                 OrbFunctional fo = (OrbFunctional) orb;
 847:                 r = response_header.readMessage(socketInput, socket,
 848:                   fo.TOUT_WHILE_READING, fo.TOUT_AFTER_RECEIVING);
 849:               }
 850:             else
 851:               r = response_header.readMessage(socketInput, null, 0, 0);
 852: 
 853:             return new RawReply(orb, response_header, r);
 854:           }
 855:         else
 856:           return EMPTY;
 857:       }
 858:     catch (IOException io_ex)
 859:       {
 860:         COMM_FAILURE m = new COMM_FAILURE("Unable to open a socket at "
 861:           + ior.Internet.host + ":" + ior.Internet.port, 0xC9,
 862:           CompletionStatus.COMPLETED_NO);
 863:         m.initCause(io_ex);
 864:         throw m;
 865:       }
 866:     finally
 867:       {
 868:         try
 869:           {
 870:             if (socket != null && !socket.isClosed())
 871:               {
 872:                 socket.setSoTimeout(OrbFunctional.TANDEM_REQUESTS);
 873:                 SocketRepository.put_socket(key, socket);
 874:               }
 875:           }
 876:         catch (IOException scx)
 877:           {
 878:             InternalError ierr = new InternalError();
 879:             ierr.initCause(scx);
 880:             throw ierr;
 881:           }
 882:       }
 883:   }
 884: 
 885:   /** {@inheritDoc} */
 886:   public org.omg.CORBA.Object target()
 887:   {
 888:     return m_target;
 889:   }
 890: 
 891:   /**
 892:    * Get the used version. Normally, it is better to respond using the same
 893:    * version as it is specified in IOR, but not above the maximal supported
 894:    * version.
 895:    */
 896:   public Version useVersion(Version desired)
 897:   {
 898:     if (desired.until_inclusive(MAX_SUPPORTED.major, MAX_SUPPORTED.minor))
 899:       return desired;
 900:     else
 901:       return MAX_SUPPORTED;
 902:   }
 903: 
 904:   /**
 905:    * Wait while the response to request, submitted using
 906:    * {@link #send_deferred()} or {@link #invoke()} (from other thread) is
 907:    * returned.
 908:    *
 909:    * FIXME It is possible to rewrite this using Object.wait() and
 910:    * Object.notify(), but be sure to prepare the test as well.
 911:    */
 912:   public synchronized void waitWhileBusy()
 913:   {
 914:     // Waiting constants.
 915:     long wait = 10;
 916:     long increment = 2;
 917:     long max = 5000;
 918: 
 919:     while (running)
 920:       {
 921:         try
 922:           {
 923:             Thread.sleep(wait);
 924:             if (wait < max)
 925:               wait = wait * increment;
 926:           }
 927:         catch (InterruptedException ex)
 928:           {
 929:           }
 930:       }
 931:   }
 932: 
 933:   /**
 934:    * Do actual invocation. This method recursively calls itself if the
 935:    * redirection is detected.
 936:    */
 937:   private void p_invoke()
 938:     throws SystemException, ForwardRequest
 939:   {
 940:     RawReply response = submit();
 941:     
 942:     // If this is a one way message, do not care about the response.
 943:     if (oneWay && response == EMPTY)
 944:       return;
 945: 
 946:     if (m_rph == null)
 947:       m_rph = response.header.create_reply_header();
 948: 
 949:     BufferredCdrInput input = response.getStream();
 950:     input.setOrb(orb);
 951: 
 952:     m_rph.read(input);
 953: 
 954:     // The stream must be aligned sinve v1.2, but only once.
 955:     boolean align = response.header.version.since_inclusive(1, 2);
 956: 
 957:     switch (m_rph.reply_status)
 958:       {
 959:         case ReplyHeader.NO_EXCEPTION:
 960: 
 961:           NamedValue arg;
 962: 
 963:           // Read return value, if set.
 964:           if (m_result != null)
 965:             {
 966:               if (align)
 967:                 {
 968:                   input.align(8);
 969:                   align = false;
 970:                 }
 971:               m_result.value().read_value(input, m_result.value().type());
 972:             }
 973: 
 974:           // Read returned parameters, if set.
 975:           if (m_args != null)
 976:             for (int i = 0; i < m_args.count(); i++)
 977:               {
 978:                 try
 979:                   {
 980:                     arg = m_args.item(i);
 981: 
 982:                     // Both ARG_INOUT and ARG_OUT have this binary flag set.
 983:                     if ((arg.flags() & ARG_OUT.value) != 0)
 984:                       {
 985:                         if (align)
 986:                           {
 987:                             input.align(8);
 988:                             align = false;
 989:                           }
 990: 
 991:                         arg.value().read_value(input, arg.value().type());
 992:                       }
 993:                   }
 994:                 catch (Bounds ex)
 995:                   {
 996:                     Unexpected.error(ex);
 997:                   }
 998:               }
 999: 
1000:           if (m_interceptor != null)
1001:             m_interceptor.receive_reply(m_info);
1002: 
1003:           break;
1004: 
1005:         case ReplyHeader.SYSTEM_EXCEPTION:
1006:           if (align)
1007:             {
1008:               input.align(8);
1009:               align = false;
1010:             }
1011:           readExceptionId(input);
1012: 
1013:           m_sys_ex = ObjectCreator.readSystemException(input,
1014:             m_rph.service_context);
1015:           m_environment.exception(m_sys_ex);
1016: 
1017:           if (m_interceptor != null)
1018:             m_interceptor.receive_exception(m_info);
1019: 
1020:           throw m_sys_ex;
1021: 
1022:         case ReplyHeader.USER_EXCEPTION:
1023:           if (align)
1024:             {
1025:               input.align(8);
1026:               align = false;
1027:             }
1028:           readExceptionId(input);
1029: 
1030:           // Prepare an Any that will hold the exception.
1031:           gnuAny exc = new gnuAny();
1032:           exc.setOrb(orb);
1033: 
1034:           exc.insert_Streamable(new StreamHolder(input));
1035: 
1036:           UnknownUserException unuex = new UnknownUserException(exc);
1037:           m_environment.exception(unuex);
1038: 
1039:           if (m_interceptor != null)
1040:             m_interceptor.receive_exception(m_info);
1041: 
1042:           break;
1043: 
1044:         case ReplyHeader.LOCATION_FORWARD_PERM:
1045:         case ReplyHeader.LOCATION_FORWARD:
1046:           if (response.header.version.since_inclusive(1, 2))
1047:             input.align(8);
1048: 
1049:           IOR forwarded = new IOR();
1050:           try
1051:             {
1052:               forwarded._read_no_endian(input);
1053:             }
1054:           catch (IOException ex)
1055:             {
1056:               new MARSHAL("Cant read forwarding info", 5103,
1057:                 CompletionStatus.COMPLETED_NO);
1058:             }
1059: 
1060:           setIor(forwarded);
1061: 
1062:           m_forward_ior = forwarded;
1063: 
1064:           if (m_interceptor != null)
1065:             m_interceptor.receive_other(m_info);
1066: 
1067:           // Repeat with the forwarded information.
1068:           p_invoke();
1069:           return;
1070: 
1071:         default:
1072:           throw new MARSHAL("Unknow reply status", 8100 + m_rph.reply_status,
1073:             CompletionStatus.COMPLETED_NO);
1074:       }
1075:   }
1076: 
1077:   /**
1078:    * Read exception id without changing the stream pointer position.
1079:    */
1080:   void readExceptionId(BufferredCdrInput input)
1081:   {
1082:     input.mark(2048);
1083:     m_exception_id = input.read_string();
1084:     input.reset();
1085:   }
1086: 
1087:   /**
1088:    * Write the operation parameters.
1089:    *
1090:    * @param header the message header
1091:    * @param request_part the stream to write parameters into
1092:    *
1093:    * @throws MARSHAL if the attempt to write the parameters has failde.
1094:    */
1095:   protected void write_parameter_buffer(MessageHeader header,
1096:     BufferedCdrOutput request_part
1097:   ) throws MARSHAL
1098:   {
1099:     try
1100:       {
1101:         if (header.version.since_inclusive(1, 2))
1102:           {
1103:             request_part.align(8);
1104:           }
1105:         m_parameter_buffer.buffer.writeTo(request_part);
1106:       }
1107:     catch (IOException ex)
1108:       {
1109:         MARSHAL m = new MARSHAL("Unable to write method arguments to CDR output.");
1110:         m.minor = Minor.CDR;
1111:         throw m;
1112:       }
1113:   }
1114: 
1115:   /**
1116:    * Write the operation parameters.
1117:    *
1118:    * @param header the message header
1119:    * @param request_part the stream to write parameters into
1120:    *
1121:    * @throws MARSHAL if the attempt to write the parameters has failde.
1122:    */
1123:   protected void write_parameters(MessageHeader header,
1124:     BufferedCdrOutput request_part
1125:   ) throws MARSHAL
1126:   {
1127:     // Align after 1.2, but only once.
1128:     boolean align = header.version.since_inclusive(1, 2);
1129:     NamedValue para;
1130: 
1131:     try
1132:       {
1133:         // Write parameters now.
1134:         for (int i = 0; i < m_args.count(); i++)
1135:           {
1136:             para = m_args.item(i);
1137: 
1138:             // This bit is set both for ARG_IN and ARG_INOUT
1139:             if ((para.flags() & ARG_IN.value) != 0)
1140:               {
1141:                 if (align)
1142:                   {
1143:                     request_part.align(8);
1144:                     align = false;
1145:                   }
1146:                 para.value().write_value(request_part);
1147:               }
1148:           }
1149:       }
1150:     catch (Bounds ex)
1151:       {
1152:         InternalError ierr = new InternalError();
1153:         ierr.initCause(ex);
1154:         throw ierr;
1155:       }
1156:   }
1157: 
1158:   /* **************Implementation of the request info operations. ***** */
1159: 
1160:   /**
1161:    * Add context to request.
1162:    */
1163:   public void add_request_service_context(ServiceContext service_context,
1164:     boolean replace
1165:   )
1166:   {
1167:     m_rqh.addContext(service_context, replace);
1168:   }
1169: 
1170:   /**
1171:    * Get the Internet profile as an effective profile.
1172:    */
1173:   public TaggedProfile effective_profile()
1174:   {
1175:     BufferedCdrOutput buf = new BufferedCdrOutput(512);
1176:     buf.setOrb(orb);
1177:     ior.Internet.write(buf);
1178: 
1179:     TaggedProfile p = new TaggedProfile();
1180:     p.tag = TAG_INTERNET_IOP.value;
1181:     p.profile_data = buf.buffer.toByteArray();
1182:     return p;
1183:   }
1184: 
1185:   /**
1186:    * Return either target or forwarded targed.
1187:    */
1188:   public org.omg.CORBA.Object effective_target()
1189:   {
1190:     return new IorObject(orb, ior);
1191:   }
1192: 
1193:   /**
1194:    * Get effective component with the give id from the Internet profile.
1195:    */
1196:   public TaggedComponent get_effective_component(int id)
1197:     throws BAD_PARAM
1198:   {
1199:     if (id == TAG_CODE_SETS.value)
1200:       {
1201:         // Codesets are encoded separately.
1202:         BufferedCdrOutput buf = new BufferedCdrOutput(512);
1203:         buf.setOrb(orb);
1204:         ior.Internet.CodeSets.write(buf);
1205: 
1206:         TaggedComponent t = new TaggedComponent();
1207:         t.tag = TAG_CODE_SETS.value;
1208:         t.component_data = buf.buffer.toByteArray();
1209:         return t;
1210:       }
1211:     else
1212:       {
1213:         for (int i = 0; i < ior.Internet.components.size(); i++)
1214:           {
1215:             TaggedComponent c =
1216:               (TaggedComponent) ior.Internet.components.get(i);
1217:             if (c.tag == id)
1218:               return c;
1219:           }
1220:       }
1221:     throw new BAD_PARAM("No component " + id + " in the Internet profile", 28,
1222:       CompletionStatus.COMPLETED_MAYBE
1223:     );
1224:   }
1225: 
1226:   /**
1227:    * Get all components with the given id from the internet profile.
1228:    */
1229:   public TaggedComponent[] get_effective_components(int id)
1230:     throws BAD_PARAM
1231:   {
1232:     if (id == TAG_CODE_SETS.value)
1233:       return new TaggedComponent[] { get_effective_component(TAG_CODE_SETS.value) };
1234:     else
1235:       {
1236:         ArrayList components = new ArrayList(ior.Internet.components.size());
1237:         for (int i = 0; i < ior.Internet.components.size(); i++)
1238:           {
1239:             TaggedComponent c =
1240:               (TaggedComponent) ior.Internet.components.get(i);
1241:             if (c.tag == id)
1242:               components.add(c);
1243:           }
1244:         if (components.size() == 0)
1245:           throw new BAD_PARAM("No component " + id +
1246:             " in the Internet profile", 28, CompletionStatus.COMPLETED_MAYBE
1247:           );
1248:         else
1249:           {
1250:             TaggedComponent[] t = new TaggedComponent[ components.size() ];
1251:             for (int i = 0; i < t.length; i++)
1252:               t [ i ] = (TaggedComponent) components.get(i);
1253:             return t;
1254:           }
1255:       }
1256:   }
1257: 
1258:   /**
1259:    * This should be not implemented up till jdk 1.5 inclusive.
1260:    */
1261:   public Policy get_request_policy(int type) throws INV_POLICY
1262:   {
1263:     throw new NO_IMPLEMENT();
1264:   }
1265: 
1266:   /** @inheritDoc */
1267:   public String received_exception_id()
1268:   {
1269:     return m_exception_id;
1270:   }
1271: 
1272:   /** @inheritDoc */
1273:   public Any received_exception()
1274:   {
1275:     if (m_exception_id == null)
1276:       return null;
1277: 
1278:     if (m_sys_ex != null)
1279:       {
1280:         Any a = orb.create_any();
1281:         ObjectCreator.insertSysException(a, m_sys_ex);
1282:         return a;
1283:       }
1284: 
1285:     Exception mex = m_environment.exception();
1286: 
1287:     UnknownUserException ex = (UnknownUserException) mex;
1288:     if (ex == null)
1289:       return null;
1290:     else
1291:       return ex.except;
1292:   }
1293: 
1294:   /**
1295:    * Return the forwarded reference, null if none.
1296:    */
1297:   public org.omg.CORBA.Object forward_reference()
1298:   {
1299:     if (m_forwarding_target != null)
1300:       return m_forwarding_target;
1301: 
1302:     if (m_forward_ior != null)
1303:       return new IorObject(orb, m_forward_ior);
1304:     else
1305:       return null;
1306:   }
1307: 
1308:   /**
1309:    * Get the slot from the slot array inside this request.
1310:    */
1311:   public Any get_slot(int id) throws InvalidSlot
1312:   {
1313:     try
1314:       {
1315:         return m_slots [ id ];
1316:       }
1317:     catch (Exception e)
1318:       {
1319:         throw new InvalidSlot("slot id " + id + ":" + e);
1320:       }
1321:   }
1322: 
1323:   /**
1324:    * Get the reply status.
1325:    */
1326:   public short reply_status()
1327:   {
1328:     if (m_rph == null)
1329:       throw new BAD_INV_ORDER("Request not yet sent", 14,
1330:         CompletionStatus.COMPLETED_NO
1331:       );
1332:     return (short) m_rph.reply_status;
1333:   }
1334: 
1335:   /**
1336:    * Get the request id.
1337:    */
1338:   public int request_id()
1339:   {
1340:     return m_rqh.request_id;
1341:   }
1342: 
1343:   /**
1344:    * Return true if the response is expected.
1345:    */
1346:   public boolean response_expected()
1347:   {
1348:     return !oneWay;
1349:   }
1350: 
1351:   /**
1352:    * Determines how far the request shall progress before control is returned to
1353:    * the client. However up till JDK 1.5 inclusive this method always returns
1354:    * SYNC_WITH_TRANSPORT.
1355:    *
1356:    * @return {@link org.omg.Messaging.SYNC_WITH_TRANSPORT.value (1), always.
1357:    *
1358:    * @specnote as defined in the Suns 1.5 JDK API.
1359:    */
1360:   public short sync_scope()
1361:   {
1362:     return org.omg.Messaging.SYNC_WITH_TRANSPORT.value;
1363:   }
1364: 
1365:   /** @inheritDoc */
1366:   public ServiceContext get_request_service_context(int ctx_name)
1367:     throws BAD_PARAM
1368:   {
1369:     return gnu.CORBA.GIOP.ServiceContext.findContext(ctx_name,
1370:       m_rqh.service_context
1371:     );
1372:   }
1373: 
1374:   /** @inheritDoc */
1375:   public ServiceContext get_reply_service_context(int ctx_name)
1376:     throws BAD_PARAM
1377:   {
1378:     if (m_rph == null)
1379:       throw new BAD_INV_ORDER("Reply context not yet available");
1380:     return gnu.CORBA.GIOP.ServiceContext.findContext(ctx_name,
1381:       m_rph.service_context
1382:     );
1383:   }
1384: 
1385:   /** @inheritDoc */
1386:   public String[] operation_context()
1387:   {
1388:     return ice_contexts();
1389:   }
1390: 
1391:   /**
1392:    * Get contexts as required by interceptor.
1393:    */
1394:   public String[] ice_contexts()
1395:   {
1396:     if (m_context_list == null)
1397:       return new String[ 0 ];
1398:     else
1399:       {
1400:         try
1401:           {
1402:             String[] cn = new String[ m_context_list.count() ];
1403:             for (int i = 0; i < cn.length; i++)
1404:               cn [ i ] = m_context_list.item(i);
1405:             return cn;
1406:           }
1407:         catch (Bounds e)
1408:           {
1409:             throw new Unexpected(e);
1410:           }
1411:       }
1412:   }
1413: 
1414:   /**
1415:    * Check if the call is done via DII.
1416:    */
1417:   public void checkDii()
1418:   {
1419:     if (m_parameter_buffer != null)
1420:       throw new NO_RESOURCES("The invocation method provides " +
1421:         "no access to this resource. DII call required.", 1,
1422:         CompletionStatus.COMPLETED_MAYBE
1423:       );
1424:   }