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