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