Source for gnu.CORBA.OrbFunctional

   1: /* OrbFunctional.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.UnknownExceptionCtxHandler;
  42: import gnu.CORBA.CDR.BufferredCdrInput;
  43: import gnu.CORBA.CDR.BufferedCdrOutput;
  44: import gnu.CORBA.GIOP.CloseMessage;
  45: import gnu.CORBA.GIOP.ErrorMessage;
  46: import gnu.CORBA.GIOP.MessageHeader;
  47: import gnu.CORBA.GIOP.ReplyHeader;
  48: import gnu.CORBA.GIOP.RequestHeader;
  49: import gnu.CORBA.NamingService.NameParser;
  50: import gnu.CORBA.NamingService.NamingServiceTransient;
  51: import gnu.CORBA.Poa.gnuForwardRequest;
  52: import gnu.CORBA.interfaces.SocketFactory;
  53: 
  54: import org.omg.CORBA.BAD_OPERATION;
  55: import org.omg.CORBA.BAD_PARAM;
  56: import org.omg.CORBA.CompletionStatus;
  57: import org.omg.CORBA.MARSHAL;
  58: import org.omg.CORBA.NO_RESOURCES;
  59: import org.omg.CORBA.OBJECT_NOT_EXIST;
  60: import org.omg.CORBA.Request;
  61: import org.omg.CORBA.SystemException;
  62: import org.omg.CORBA.UNKNOWN;
  63: import org.omg.CORBA.WrongTransaction;
  64: import org.omg.CORBA.ORBPackage.InvalidName;
  65: import org.omg.CORBA.portable.Delegate;
  66: import org.omg.CORBA.portable.InvokeHandler;
  67: import org.omg.CORBA.portable.ObjectImpl;
  68: import org.omg.CORBA.portable.UnknownException;
  69: import org.omg.CosNaming.NamingContextExt;
  70: import org.omg.CosNaming.NamingContextExtHelper;
  71: 
  72: import java.applet.Applet;
  73: import java.io.IOException;
  74: import java.io.InputStream;
  75: import java.io.OutputStream;
  76: import java.net.InetAddress;
  77: import java.net.ServerSocket;
  78: import java.net.Socket;
  79: import java.net.SocketException;
  80: import java.net.UnknownHostException;
  81: import java.util.ArrayList;
  82: import java.util.Enumeration;
  83: import java.util.Hashtable;
  84: import java.util.Iterator;
  85: import java.util.LinkedList;
  86: import java.util.Map;
  87: import java.util.Properties;
  88: import java.util.Random;
  89: import java.util.StringTokenizer;
  90: import java.util.TreeMap;
  91: 
  92: /**
  93:  * The ORB implementation, capable to handle remote invocations on the
  94:  * registered object. This class implements all features, required till the jdk
  95:  * 1.3 inclusive, but does not support the POA that appears since 1.4. The POA
  96:  * is supported by {@link gnu.CORBA.Poa.ORB_1_4}.
  97:  *
  98:  * @author Audrius Meskauskas (AudriusA@Bioinformatics.org)
  99:  */
 100: public class OrbFunctional extends OrbRestricted
 101: {
 102:   /**
 103:    * A server, responsible for listening on requests on some local port. The ORB
 104:    * may listen on multiple ports and process the requests in separate threads.
 105:    * Normally the server takes one port per object being served.
 106:    */
 107:   protected class portServer
 108:     extends Thread
 109:   {
 110:     /**
 111:      * The number of the currently running parallel threads.
 112:      */
 113:     int running_threads;
 114: 
 115:     /**
 116:      * The port on that this portServer is listening for requests.
 117:      */
 118:     int s_port;
 119: 
 120:     /**
 121:      * The server socket of this portServer.
 122:      */
 123:     ServerSocket service;
 124: 
 125:     /**
 126:      * True if the serving node must shutdown due call of the close_now().
 127:      */
 128:     boolean terminated;
 129: 
 130:     /**
 131:      * Create a new portServer, serving on specific port.
 132:      */
 133:     portServer(int _port)
 134:     {
 135:       s_port = _port;
 136:       setDaemon(true);
 137:       try
 138:         {
 139:           service = socketFactory.createServerSocket(s_port);
 140:         }
 141:       catch (IOException ex)
 142:         {
 143:           BAD_OPERATION bad = new BAD_OPERATION(
 144:             "Unable to open the server socket at " + s_port);
 145:           bad.minor = Minor.Socket;
 146:           bad.initCause(ex);
 147:           throw bad;
 148:         }
 149:     }
 150: 
 151:     /**
 152:      * Enter the serving loop (get request/process it). All portServer normally
 153:      * terminate thy threads when the OrbFunctional.running is set to false.
 154:      */
 155:     public void run()
 156:     {
 157:       while (running)
 158:         {
 159:           try
 160:             {
 161:               tick();
 162:             }
 163:           catch (SocketException ex)
 164:             {
 165:               // May be thrown when the service is closed by
 166:               // the close_now().
 167:               if (terminated)
 168:                 return;
 169:             }
 170:           catch (Exception iex)
 171:             {
 172:               // Wait. Do not terminate the
 173:               // service due potentially transient error.
 174:               try
 175:                 {
 176:                   Thread.sleep(TWAIT_SERVER_ERROR_PAUSE);
 177:                 }
 178:               catch (InterruptedException ex)
 179:                 {
 180:                 }
 181:             }
 182:         }
 183:     }
 184: 
 185:     /**
 186:      * Perform a single serving step.
 187:      *
 188:      * @throws java.lang.Exception
 189:      */
 190:     void tick()
 191:       throws Exception
 192:     {
 193:       serve(this, service);
 194:     }
 195: 
 196:     /**
 197:      * Forcibly close the server socket and mark this port as free.
 198:      */
 199:     public void close_now()
 200:     {
 201:       try
 202:         {
 203:           terminated = true;
 204:           service.close();
 205:         }
 206:       catch (Exception ex)
 207:         {
 208:           // This may happen if the service has not been opened or
 209:           // cannot be closed. Return without action.
 210:         }
 211:     }
 212: 
 213:     /**
 214:      * If the thread is no longer in use, close the socket (if opened).
 215:      */
 216:     protected void finalize()
 217:     {
 218:       close_now();
 219:     }
 220:   }
 221: 
 222:   /**
 223:    * A server, responsible for listening on requests on some local port and
 224:    * serving multiple requests (probably to the different objects) on the same
 225:    * thread.
 226:    */
 227:   protected class sharedPortServer extends portServer
 228:   {
 229:     /**
 230:      * Create a new portServer, serving on specific port.
 231:      */
 232:     sharedPortServer(int _port)
 233:     {
 234:       super(_port);
 235:     }
 236: 
 237:     /**
 238:      * Perform a single serving step.
 239:      *
 240:      * @throws java.lang.Exception
 241:      */
 242:     void tick() throws Exception
 243:     {
 244:       Socket request = service.accept();
 245:       serveStep(request, false);
 246:     }
 247:   }
 248: 
 249:   /**
 250:    * The default value where the first instance of this ORB will start looking
 251:    * for a free port.
 252:    */
 253:   public static int DEFAULT_INITIAL_PORT = 1126;
 254: 
 255:   /**
 256:    * When trying to open the socket on a random port, start of the interval to
 257:    * try.
 258:    */
 259:   public static int RANDOM_PORT_FROM = 1024;
 260: 
 261:   /**
 262:    * When trying to open the socket on a random port, end of the interval to
 263:    * try.
 264:    */
 265:   public static int RANDOM_PORT_TO = 4024;
 266: 
 267:   /**
 268:    * The number of attempts to try when opening random port.
 269:    */
 270:   public static int RANDOM_PORT_ATTEMPTS = 64;
 271: 
 272:   /**
 273:    * The property of port, on that this ORB is listening for requests from
 274:    * clients. This class supports one port per ORB only.
 275:    */
 276:   public static final String LISTEN_ON = "gnu.classpath.CORBA.ListenOn";
 277: 
 278:   /**
 279:    * The property, defining the IOR of the intial reference to resolve.
 280:    */
 281:   public static final String REFERENCE = "org.omg.CORBA.ORBInitRef";
 282: 
 283:   /**
 284:    * The property, defining the port on that the default name service is
 285:    * running.
 286:    */
 287:   public static final String NS_PORT = "org.omg.CORBA.ORBInitialPort";
 288: 
 289:   /**
 290:    * The property, defining the host on that the default name service is
 291:    * running.
 292:    */
 293:   public static final String NS_HOST = "org.omg.CORBA.ORBInitialHost";
 294: 
 295:   /**
 296:    * The string, defining the naming service initial reference.
 297:    */
 298:   public static final String NAME_SERVICE = "NameService";
 299: 
 300:   /**
 301:    * Defines the ORB ID that is accessible by IOR interceptors.
 302:    */
 303:   public static final String ORB_ID = "org.omg.CORBA.ORBid";
 304: 
 305: 
 306:   /**
 307:    * Defines the SERVER ID that is accessible by IOR interceptors.
 308:    */
 309:   public static final String SERVER_ID = "org.omg.CORBA.ServerId";
 310: 
 311:   /**
 312:    * The if the client has once opened a socket, it should start sending the
 313:    * message header in a given time. Otherwise the server will close the socket.
 314:    * This prevents server hang when the client opens the socket, but does not
 315:    * send any message, usually due crash on the client side.
 316:    */
 317:   public static String START_READING_MESSAGE =
 318:     "gnu.classpath.CORBA.TOUT_START_READING_MESSAGE";
 319: 
 320:   /**
 321:    * If the client has started to send the request message, the socket time out
 322:    * changes to the specified value.
 323:    */
 324:   public static String WHILE_READING =
 325:     "gnu.classpath.CORBA.TOUT_WHILE_READING";
 326: 
 327:   /**
 328:    * If the message body is received, the time out changes to the specifice
 329:    * value. This must be longer, as includes time, required to process the
 330:    * received task. We make it 40 minutes.
 331:    */
 332:   public static String AFTER_RECEIVING =
 333:     "gnu.classpath.CORBA.TOUT_AFTER_RECEIVING";
 334: 
 335:   /**
 336:    * The server waits for this duration after the potentially transient error
 337:    * during its servicing cycle.
 338:    */
 339:   public static String SERVER_ERROR_PAUSE =
 340:     "gnu.classpath.CORBA.SERVER_ERROR_PAUSE";
 341: 
 342:   /**
 343:    * The address of the local host.
 344:    */
 345:   public final String LOCAL_HOST;
 346: 
 347:   /**
 348:    * The if the client has once opened a socket, it should start sending the
 349:    * message header in a given time. Otherwise the server will close the socket.
 350:    * This prevents server hang when the client opens the socket, but does not
 351:    * send any message, usually due crash on the client side.
 352:    */
 353:   public int TOUT_START_READING_MESSAGE = 20 * 1000;
 354: 
 355:   // (Here and below, we use * to make the meaning of the constant clearler).
 356: 
 357:   /**
 358:    * If the client has started to send the request message, the socket time out
 359:    * changes to the specified value.
 360:    */
 361:   public int TOUT_WHILE_READING = 2 * 60 * 1000;
 362: 
 363:   /**
 364:    * If the message body is received, the time out changes to the specifice
 365:    * value. This must be longer, as includes time, required to process the
 366:    * received task. We make it 40 minutes.
 367:    */
 368:   public int TOUT_AFTER_RECEIVING = 40 * 60 * 1000;
 369: 
 370:   /**
 371:    * The server waits for this duration after the potentially transient error
 372:    * during its servicing cycle.
 373:    */
 374:   public int TWAIT_SERVER_ERROR_PAUSE = 5000;
 375: 
 376:   /**
 377:    * Some clients tend to submit multiple requests over the same socket. The
 378:    * server waits for the next request on the same socket for the duration,
 379:    * specified below. In additions, the request of this implementation also
 380:    * waits for the same duration before closing the socket. The default time is
 381:    * seven seconds.
 382:    */
 383:   public static int TANDEM_REQUESTS = 7000;
 384: 
 385:   /**
 386:    * The Id of this ORB.
 387:    */
 388:   public String orb_id = "orb_"+hashCode();
 389: 
 390:   /**
 391:    * The Id of this Server. This field is defined static to ensure it has
 392:    * the same value over all ORB's in this machine.
 393:    */
 394:   public static String server_id = "server_"+OrbFunctional.class.hashCode();
 395: 
 396:   /**
 397:    * The map of the already conncted objects.
 398:    */
 399:   protected final Connected_objects connected_objects =
 400:     new Connected_objects();
 401: 
 402:   /**
 403:    * The maximal CORBA version, supported by this ORB. The default value 0 means
 404:    * that the ORB will not check the request version while trying to respond.
 405:    */
 406:   protected Version max_version;
 407: 
 408:   /**
 409:    * Setting this value to false causes the ORB to shutdown after the latest
 410:    * serving operation is complete.
 411:    */
 412:   protected boolean running;
 413: 
 414:   /**
 415:    * The map of the initial references.
 416:    */
 417:   protected Map initial_references = new TreeMap();
 418: 
 419:   /**
 420:    * The currently active portServers.
 421:    */
 422:   protected ArrayList portServers = new ArrayList();
 423: 
 424:   /**
 425:    * The host, on that the name service is expected to be running.
 426:    */
 427:   private String ns_host;
 428: 
 429:   /**
 430:    * Probably free port, under that the ORB will try listening for remote
 431:    * requests first. When the new object is connected, this port is used first,
 432:    * then it is incremented by 1, etc. If the given port is not available, up to
 433:    * 20 subsequent values are tried and then the parameterless server socket
 434:    * contructor is called. The constant is shared between multiple instances of
 435:    * this ORB.
 436:    */
 437:   private static int Port = DEFAULT_INITIAL_PORT;
 438: 
 439:   /**
 440:    * The port, on that the name service is expected to be running.
 441:    */
 442:   private int ns_port = 900;
 443: 
 444:   /**
 445:    * The name parser.
 446:    */
 447:   NameParser nameParser = new NameParser();
 448: 
 449:   /**
 450:    * The instance, stored in this field, handles the asynchronous dynamic
 451:    * invocations.
 452:    */
 453:   protected Asynchron asynchron = new Asynchron();
 454: 
 455:   /**
 456:    * The list of the freed ports. The ORB reuses ports, when possible.
 457:    */
 458:   protected LinkedList freed_ports = new LinkedList();
 459: 
 460:   /**
 461:    * Maps a single-threaded POAs to they sharedPortServants.
 462:    */
 463:   protected Hashtable identities = new Hashtable();
 464: 
 465:   /**
 466:    * The maximal allowed number of the currently running parallel threads per
 467:    * object. For security reasons, this is made private and unchangeable. After
 468:    * exceeding this limit, the NO_RESOURCES is thrown back to the client.
 469:    */
 470:   private int MAX_RUNNING_THREADS = 256;
 471: 
 472:   /**
 473:    * The producer of the client and server sockets for this ORB.
 474:    */
 475:   public SocketFactory socketFactory = DefaultSocketFactory.Singleton;
 476: 
 477:   /**
 478:    * Create the instance of the Functional ORB.
 479:    */
 480:   public OrbFunctional()
 481:   {
 482:     try
 483:       {
 484:         LOCAL_HOST = ns_host = InetAddress.getLocalHost().getHostAddress();
 485:         initial_references.put("CodecFactory", new gnuCodecFactory(this));
 486:       }
 487:     catch (UnknownHostException ex)
 488:       {
 489:         BAD_OPERATION bad =
 490:           new BAD_OPERATION("Unable to open the server socket.");
 491:         bad.initCause(ex);
 492:         throw bad;
 493:       }
 494:   }
 495: 
 496:   /**
 497:    * If the max version is assigned, the orb replies with the error message if
 498:    * the request version is above the supported 1.2 version. This behavior is
 499:    * recommended by OMG, but not all implementations respond that error message
 500:    * by re-sending the request, encoded in the older version.
 501:    */
 502:   public void setMaxVersion(Version max_supported)
 503:   {
 504:     max_version = max_supported;
 505:   }
 506: 
 507:   /**
 508:    * Get the maximal supported GIOP version or null if the version is not
 509:    * checked.
 510:    */
 511:   public Version getMaxVersion()
 512:   {
 513:     return max_version;
 514:   }
 515: 
 516:   /**
 517:    * Get the currently free port, starting from the initially set port and going
 518:    * up max 20 steps, then trying to bind into any free address.
 519:    *
 520:    * @return the currently available free port.
 521:    *
 522:    * @throws NO_RESOURCES if the server socked cannot be opened on the local
 523:    * host.
 524:    */
 525:   public int getFreePort()
 526:     throws BAD_OPERATION
 527:   {
 528:     ServerSocket s;
 529:     int a_port;
 530: 
 531:     try
 532:       {
 533:         // If there are some previously freed ports, use them first.
 534:         if (!freed_ports.isEmpty())
 535:           {
 536:             Integer free = (Integer) freed_ports.getLast();
 537:             freed_ports.removeLast();
 538:             s = socketFactory.createServerSocket(free.intValue());
 539:             s.close();
 540:             return free.intValue();
 541:           }
 542:       }
 543:     catch (Exception ex)
 544:       {
 545:         // This may be thrown if the request for the new port has arrived
 546:         // before the current service is completly shutdown.
 547:         // OK then, use a new port.
 548:       }
 549: 
 550:     for (a_port = Port; a_port < Port + 20; a_port++)
 551:       {
 552:         try
 553:           {
 554:             s = socketFactory.createServerSocket(a_port);
 555:             s.close();
 556:             Port = a_port + 1;
 557:             return a_port;
 558:           }
 559:         catch (IOException ex)
 560:           {
 561:             // Repeat the loop if this exception has been thrown.
 562:           }
 563:       }
 564: 
 565:     Random rand = new Random();
 566:     // Try any random port in the interval RANDOM_PORT_FROM.RANDOM_PORT_TO.
 567:     int range = RANDOM_PORT_TO - RANDOM_PORT_FROM;
 568:     IOException ioex = null;
 569:     for (int i = 0; i < RANDOM_PORT_ATTEMPTS; i++)
 570:       {
 571:         try
 572:           {
 573:             a_port = RANDOM_PORT_FROM + rand.nextInt(range);
 574:             s = socketFactory.createServerSocket(a_port);
 575:             s.close();
 576:             return a_port;
 577:           }
 578:         catch (IOException ex)
 579:           {
 580:             // Repeat the loop if this exception has been thrown.
 581:             ioex = ex;
 582:           }
 583:       }
 584: 
 585:     NO_RESOURCES bad = new NO_RESOURCES("Unable to open the server socket.");
 586:     bad.minor = Minor.Ports;
 587:     if (ioex != null)
 588:       bad.initCause(ioex);
 589:     throw bad;
 590:   }
 591: 
 592:   /**
 593:    * Set the port, on that the server is listening for the client requests. If
 594:    * only one object is connected to the orb, the server will be try listening
 595:    * on this port first. It the port is busy, or if more objects are connected,
 596:    * the subsequent object will receive a larger port values, skipping
 597:    * unavailable ports, if required. The change applies globally.
 598:    *
 599:    * @param a_Port a port, on that the server is listening for requests.
 600:    */
 601:   public static void setPort(int a_Port)
 602:   {
 603:     Port = a_Port;
 604:   }
 605: 
 606:   /**
 607:    * Connect the given CORBA object to this ORB. After the object is connected,
 608:    * it starts receiving remote invocations via this ORB.
 609:    *
 610:    * The ORB tries to connect the object to the port, that has been previously
 611:    * set by {@link setPort(int)}. On failure, it tries 20 subsequent larger
 612:    * values and then calls the parameterless server socked constructor to get
 613:    * any free local port. If this fails, the {@link NO_RESOURCES} is thrown.
 614:    *
 615:    * @param object the object, must implement the {@link InvokeHandler})
 616:    * interface.
 617:    *
 618:    * @throws BAD_PARAM if the object does not implement the
 619:    * {@link InvokeHandler}).
 620:    */
 621:   public void connect(org.omg.CORBA.Object object)
 622:   {
 623:     int a_port = getFreePort();
 624: 
 625:     Connected_objects.cObject ref = connected_objects.add(object, a_port);
 626:     IOR ior = createIOR(ref);
 627:     prepareObject(object, ior);
 628:     if (running)
 629:       startService(ior);
 630:   }
 631: 
 632:   /**
 633:    * Connect the given CORBA object to this ORB, explicitly specifying the
 634:    * object key.
 635:    *
 636:    * The ORB tries to connect the object to the port, that has been previously
 637:    * set by {@link setPort(int)}. On failure, it tries 20 subsequent larger
 638:    * values and then calls the parameterless server socked constructor to get
 639:    * any free local port. If this fails, the {@link NO_RESOURCES} is thrown.
 640:    *
 641:    * @param object the object, must implement the {@link InvokeHandler})
 642:    * interface.
 643:    * @param key the object key, usually used to identify the object from remote
 644:    * side.
 645:    *
 646:    * @throws BAD_PARAM if the object does not implement the
 647:    * {@link InvokeHandler}).
 648:    */
 649:   public void connect(org.omg.CORBA.Object object, byte[] key)
 650:   {
 651:     int a_port = getFreePort();
 652: 
 653:     Connected_objects.cObject ref =
 654:       connected_objects.add(key, object, a_port, null);
 655:     IOR ior = createIOR(ref);
 656:     prepareObject(object, ior);
 657:     if (running)
 658:       startService(ior);
 659:   }
 660: 
 661:   /**
 662:    * Connect the given CORBA object to this ORB, explicitly specifying the
 663:    * object key and the identity of the thread (and port), where the object must
 664:    * be served. The identity is normally the POA.
 665:    *
 666:    * The new port server will be started only if there is no one already running
 667:    * for the same identity. Otherwise, the task of the existing port server will
 668:    * be widened, including duty to serve the given object. All objects,
 669:    * connected to a single identity by this method, will process they requests
 670:    * subsequently in the same thread. The method is used when the expected
 671:    * number of the objects is too large to have a single port and thread per
 672:    * object. This method is used by POAs, having a single thread policy.
 673:    *
 674:    * @param object the object, must implement the {@link InvokeHandler})
 675:    * interface.
 676:    * @param key the object key, usually used to identify the object from remote
 677:    * side.
 678:    * @param port the port, where the object must be connected.
 679:    *
 680:    * @throws BAD_PARAM if the object does not implement the
 681:    * {@link InvokeHandler}).
 682:    */
 683:   public void connect_1_thread(org.omg.CORBA.Object object, byte[] key,
 684:     java.lang.Object identity
 685:   )
 686:   {
 687:     sharedPortServer shared = (sharedPortServer) identities.get(identity);
 688:     if (shared == null)
 689:       {
 690:         int a_port = getFreePort();
 691:         shared = new sharedPortServer(a_port);
 692:         identities.put(identity, shared);
 693:         if (running)
 694:           {
 695:             portServers.add(shared);
 696:             shared.start();
 697:           }
 698:       }
 699: 
 700:     Connected_objects.cObject ref =
 701:       connected_objects.add(key, object, shared.s_port, identity);
 702:     IOR ior = createIOR(ref);
 703:     prepareObject(object, ior);
 704:   }
 705: 
 706:   /**
 707:    * Start the service on the given port of this IOR.
 708:    *
 709:    * @param ior the ior (only Internet.port is used).
 710:    */
 711:   public void startService(IOR ior)
 712:   {
 713:     portServer p = new portServer(ior.Internet.port);
 714:     portServers.add(p);
 715:     p.start();
 716:   }
 717: 
 718:   /**
 719:    * Destroy this server, releasing the occupied resources.
 720:    */
 721:   public void destroy()
 722:   {
 723:     portServer p;
 724:     for (int i = 0; i < portServers.size(); i++)
 725:       {
 726:         p = (portServer) portServers.get(i);
 727:         p.close_now();
 728:       }
 729:     super.destroy();
 730:   }
 731: 
 732:   /**
 733:    * Disconnect the given CORBA object from this ORB. The object will be no
 734:    * longer receiving the remote invocations. In response to the remote
 735:    * invocation on this object, the ORB will send the exception
 736:    * {@link OBJECT_NOT_EXIST}. The object, however, is not destroyed and can
 737:    * receive the local invocations.
 738:    *
 739:    * @param object the object to disconnect.
 740:    */
 741:   public void disconnect(org.omg.CORBA.Object object)
 742:   {
 743:     Connected_objects.cObject rmKey = null;
 744: 
 745:     // Handle the case when it is possible to get the object key.
 746:     // Handle the case when the object is known, but not local.
 747:     if (object instanceof ObjectImpl)
 748:       {
 749:         Delegate delegate = ((ObjectImpl) object)._get_delegate();
 750:         if (delegate instanceof SimpleDelegate)
 751:           {
 752:             byte[] key = ((SimpleDelegate) delegate).getIor().key;
 753:             rmKey = connected_objects.get(key);
 754:           }
 755:       }
 756: 
 757:     // Try to find and disconned the object that is not an instance of the
 758:     // object implementation.
 759:     if (rmKey == null)
 760:       rmKey = connected_objects.getKey(object);
 761:     if (rmKey != null)
 762:       {
 763:         // Find and stop the corresponding portServer.
 764:         portServer p;
 765:         StopService:
 766:         for (int i = 0; i < portServers.size(); i++)
 767:           {
 768:             p = (portServer) portServers.get(i);
 769:             if (p.s_port == rmKey.port && !(p instanceof sharedPortServer))
 770:               {
 771:                 p.close_now();
 772:                 freed_ports.addFirst(new Integer(rmKey.port));
 773:                 break StopService;
 774:               }
 775:             connected_objects.remove(rmKey.key);
 776:           }
 777:       }
 778:   }
 779: 
 780:   /**
 781:    * Notifies ORB that the shared service indentity (usually POA) is destroyed.
 782:    * The matching shared port server is terminated and the identity table entry
 783:    * is deleted. If this identity is not known for this ORB, the method returns
 784:    * without action.
 785:    *
 786:    * @param identity the identity that has been destroyed.
 787:    */
 788:   public void identityDestroyed(java.lang.Object identity)
 789:   {
 790:     if (identity == null)
 791:       return;
 792: 
 793:     sharedPortServer ise = (sharedPortServer) identities.get(identity);
 794:     if (ise != null)
 795:       {
 796:         synchronized (connected_objects)
 797:           {
 798:             ise.close_now();
 799:             identities.remove(identity);
 800: 
 801:             Connected_objects.cObject obj;
 802:             Map.Entry m;
 803:             Iterator iter = connected_objects.entrySet().iterator();
 804:             while (iter.hasNext())
 805:               {
 806:                 m = (Map.Entry) iter.next();
 807:                 obj = (Connected_objects.cObject) m.getValue();
 808:                 if (obj.identity == identity)
 809:                   iter.remove();
 810:               }
 811:           }
 812:       }
 813:   }
 814: 
 815:   /**
 816:    * Find the local object, connected to this ORB.
 817:    *
 818:    * @param ior the ior of the potentially local object.
 819:    *
 820:    * @return the local object, represented by the given IOR, or null if this is
 821:    * not a local connected object.
 822:    */
 823:   public org.omg.CORBA.Object find_local_object(IOR ior)
 824:   {
 825:     // Must be the same host.
 826:     if (!ior.Internet.host.equals(LOCAL_HOST))
 827:       return null;
 828: 
 829:     return find_connected_object(ior.key, ior.Internet.port);
 830:   }
 831: 
 832:   /**
 833:    * List the initially available CORBA objects (services).
 834:    *
 835:    * @return a list of services.
 836:    *
 837:    * @see resolve_initial_references(String)
 838:    */
 839:   public String[] list_initial_services()
 840:   {
 841:     String[] refs = new String[ initial_references.size() ];
 842:     int p = 0;
 843: 
 844:     Iterator iter = initial_references.keySet().iterator();
 845:     while (iter.hasNext())
 846:       {
 847:         refs [ p++ ] = (String) iter.next();
 848:       }
 849:     return refs;
 850:   }
 851: 
 852:   /**
 853:    * Get the IOR reference string for the given object. The string embeds
 854:    * information about the object repository Id, its access key and the server
 855:    * internet address and port. With this information, the object can be found
 856:    * by another ORB, possibly located on remote computer.
 857:    *
 858:    * @param forObject CORBA object
 859:    * @return the object IOR representation.
 860:    *
 861:    * @throws BAD_PARAM if the object has not been previously connected to this
 862:    * ORB.
 863:    *
 864:    * @throws BAD_OPERATION in the unlikely case if the local host address cannot
 865:    * be resolved.
 866:    *
 867:    * @see string_to_object(String)
 868:    */
 869:   public String object_to_string(org.omg.CORBA.Object forObject)
 870:   {
 871:     // Handle the case when the object is known, but not local.
 872:     if (forObject instanceof ObjectImpl)
 873:       {
 874:         Delegate delegate = ((ObjectImpl) forObject)._get_delegate();
 875:         if (delegate instanceof SimpleDelegate)
 876:           return ((SimpleDelegate) delegate).getIor().toStringifiedReference();
 877:       }
 878: 
 879:     // Handle the case when the object is local.
 880:     Connected_objects.cObject rec = connected_objects.getKey(forObject);
 881: 
 882:     if (rec == null)
 883:       throw new BAD_PARAM("The object " + forObject +
 884:         " has not been previously connected to this ORB"
 885:       );
 886: 
 887:     IOR ior = createIOR(rec);
 888: 
 889:     return ior.toStringifiedReference();
 890:   }
 891: 
 892:   /**
 893:    * Get the local IOR for the given object, null if the object is not local.
 894:    */
 895:   public IOR getLocalIor(org.omg.CORBA.Object forObject)
 896:   {
 897:     Connected_objects.cObject rec = connected_objects.getKey(forObject);
 898:     if (rec == null)
 899:       return null;
 900:     else
 901:       return createIOR(rec);
 902:   }
 903: 
 904:   /**
 905:    * Find and return the easily accessible CORBA object, addressed by name.
 906:    *
 907:    * @param name the object name.
 908:    * @return the object
 909:    *
 910:    * @throws org.omg.CORBA.ORBPackage.InvalidName if the given name is not
 911:    * associated with the known object.
 912:    */
 913:   public org.omg.CORBA.Object resolve_initial_references(String name)
 914:     throws InvalidName
 915:   {
 916:     org.omg.CORBA.Object object = null;
 917:     try
 918:       {
 919:         object = (org.omg.CORBA.Object) initial_references.get(name);
 920:         if (object == null && name.equals(NAME_SERVICE))
 921:           {
 922:             object = getDefaultNameService();
 923:             if (object != null)
 924:               initial_references.put(NAME_SERVICE, object);
 925:           }
 926:       }
 927:     catch (Exception ex)
 928:       {
 929:         InvalidName err = new InvalidName(name);
 930:         err.initCause(ex);
 931:         throw err;
 932:       }
 933:     if (object != null)
 934:       return object;
 935:     else
 936:       throw new InvalidName("Not found: '" + name + "'");
 937:   }
 938: 
 939:   /**
 940:    * Start the ORBs main working cycle (receive invocation - invoke on the local
 941:    * object - send response - wait for another invocation). The method only
 942:    * returns after calling {@link #shutdown(boolean)}.
 943:    */
 944:   public void run()
 945:   {
 946:     CollocatedOrbs.registerOrb(this);
 947:     try
 948:       {
 949:         running = true;
 950: 
 951:         // Instantiate the port server for each socket.
 952:         Iterator iter = connected_objects.entrySet().iterator();
 953:         Map.Entry m;
 954:         Connected_objects.cObject obj;
 955: 
 956:         while (iter.hasNext())
 957:           {
 958:             m = (Map.Entry) iter.next();
 959:             obj = (Connected_objects.cObject) m.getValue();
 960: 
 961:             portServer subserver;
 962: 
 963:             if (obj.identity == null)
 964:               {
 965:                 subserver = new portServer(obj.port);
 966:                 portServers.add(subserver);
 967:               }
 968:             else
 969:               subserver = (portServer) identities.get(obj.identity);
 970: 
 971:             if (! subserver.isAlive())
 972:               {
 973:                 // Reuse the current thread for the last portServer.
 974:                 if (! iter.hasNext())
 975:                   {
 976:                     // Discard the iterator, eliminating lock checks.
 977:                     iter = null;
 978:                     subserver.run();
 979:                     return;
 980:                   }
 981:                 else
 982:                   subserver.start();
 983:               }
 984:           }
 985:       }
 986:     finally
 987:       {
 988:         CollocatedOrbs.unregisterOrb(this);
 989:       }
 990:   }
 991: 
 992:   /**
 993:    * Start the server in a new thread, if not already running. This method is
 994:    * used to ensure that the objects being transfered will be served from the
 995:    * remote side, if required. If the ORB is started using this method, it
 996:    * starts as a daemon thread.
 997:    */
 998:   public void ensureRunning()
 999:   {
1000:     final OrbFunctional THIS = this;
1001: 
1002:     if (!running)
1003:       {
1004:         Thread t = new Thread()
1005:         {
1006:           public void run()
1007:           {
1008:             THIS.run();
1009:           }
1010:         };
1011:         t.setDaemon(true);
1012:         t.start();
1013:       }
1014:   }
1015: 
1016:   /**
1017:    * Shutdown the ORB server.
1018:    *
1019:    * @param wait_for_completion if true, the current thread is suspended until
1020:    * the shutdown process is complete.
1021:    */
1022:   public void shutdown(boolean wait_for_completion)
1023:   {
1024:     super.shutdown(wait_for_completion);
1025:     running = false;
1026: 
1027:     if (!wait_for_completion)
1028:       {
1029:         for (int i = 0; i < portServers.size(); i++)
1030:           {
1031:             portServer p = (portServer) portServers.get(i);
1032:             p.close_now();
1033:           }
1034:       }
1035:   }
1036: 
1037:   /**
1038:    * Find and return the CORBA object, addressed by the given IOR string
1039:    * representation. The object can (an usually is) located on a remote
1040:    * computer, possibly running a different (not necessary java) CORBA
1041:    * implementation.
1042:    *
1043:    * @param an_ior the object IOR representation string.
1044:    *
1045:    * @return the found CORBA object.
1046:    * @see object_to_string(org.omg.CORBA.Object)
1047:    */
1048:   public org.omg.CORBA.Object string_to_object(String an_ior)
1049:   {
1050:     return nameParser.corbaloc(an_ior, this);
1051:   }
1052: 
1053:   /**
1054:    * Convert ior reference to CORBA object.
1055:    */
1056:   public org.omg.CORBA.Object ior_to_object(IOR ior)
1057:   {
1058:     org.omg.CORBA.Object object = find_local_object(ior);
1059:     if (object == null)
1060:       {
1061:         // Check maybe the local object on another ORB, but same VM.
1062:         object = CollocatedOrbs.searchLocalObject(ior);
1063:         if (object == null)
1064:           {
1065:             // Surely remote object.
1066:             ObjectImpl impl = StubLocator.search(this, ior);
1067:             try
1068:               {
1069:                 if (impl._get_delegate() == null)
1070:                   impl._set_delegate(new IorDelegate(this, ior));
1071:               }
1072:             catch (BAD_OPERATION ex)
1073:               {
1074:                 // Some colaborants may throw this exception
1075:                 // in response to the attempt to get the unset delegate.
1076:                 impl._set_delegate(new IorDelegate(this, ior));
1077:               }
1078: 
1079:             object = impl;
1080:           }
1081:       }
1082:     return object;
1083:   }
1084: 
1085:   /**
1086:    * Get the default naming service for the case when there no NameService
1087:    * entries.
1088:    */
1089:   protected org.omg.CORBA.Object getDefaultNameService()
1090:   {
1091:     if (initial_references.containsKey(NAME_SERVICE))
1092:       return (org.omg.CORBA.Object) initial_references.get(NAME_SERVICE);
1093: 
1094:     IOR ior = new IOR();
1095:     ior.Id = NamingContextExtHelper.id();
1096:     ior.Internet.host = ns_host;
1097:     ior.Internet.port = ns_port;
1098:     ior.key = NamingServiceTransient.getDefaultKey();
1099: 
1100:     IorObject iorc = new IorObject(this, ior);
1101:     NamingContextExt namer = NamingContextExtHelper.narrow(iorc);
1102:     initial_references.put(NAME_SERVICE, namer);
1103:     return namer;
1104:   }
1105: 
1106:   /**
1107:    * Find and return the object, that must be previously connected to this ORB.
1108:    * Return null if no such object is available.
1109:    *
1110:    * @param key the object key.
1111:    * @param port the port where the object is connected.
1112:    *
1113:    * @return the connected object, null if none.
1114:    */
1115:   protected org.omg.CORBA.Object find_connected_object(byte[] key, int port)
1116:   {
1117:     Connected_objects.cObject ref = connected_objects.get(key);
1118:     if (ref == null)
1119:       return null;
1120:     if (port >= 0 && ref.port != port)
1121:       return null;
1122:     else
1123:       return ref.object;
1124:   }
1125: 
1126:   /**
1127:    * Set the ORB parameters. This method is normally called from
1128:    * {@link #init(Applet, Properties)}.
1129:    *
1130:    * @param app the current applet.
1131:    *
1132:    * @param props application specific properties, passed as the second
1133:    * parameter in {@link #init(Applet, Properties)}. Can be <code>null</code>.
1134:    */
1135:   protected void set_parameters(Applet app, Properties props)
1136:   {
1137:     useProperties(props);
1138: 
1139:     String[][] para = app.getParameterInfo();
1140:     if (para != null)
1141:       {
1142:         for (int i = 0; i < para.length; i++)
1143:           {
1144:             if (para[i][0].equals(LISTEN_ON))
1145:               Port = Integer.parseInt(para[i][1]);
1146:             if (para[i][0].equals(REFERENCE))
1147:               {
1148:                 StringTokenizer st = new StringTokenizer(para[i][1], "=");
1149:                 initial_references.put(st.nextToken(),
1150:                   string_to_object(st.nextToken()));
1151:               }
1152: 
1153:             if (para[i][0].equals(ORB_ID))
1154:               orb_id = para[i][1];
1155: 
1156:             if (para[i][0].equals(SERVER_ID))
1157:               server_id = para[i][1];
1158: 
1159:             if (para[i][0].equals(NS_HOST))
1160:               ns_host = para[i][1];
1161:             if (para[i][0].equals(START_READING_MESSAGE))
1162:               TOUT_START_READING_MESSAGE = Integer.parseInt(para[i][1]);
1163:             if (para[i][0].equals(WHILE_READING))
1164:               TOUT_WHILE_READING = Integer.parseInt(para[i][1]);
1165:             if (para[i][0].equals(AFTER_RECEIVING))
1166:               TOUT_AFTER_RECEIVING = Integer.parseInt(para[i][1]);
1167:             try
1168:               {
1169:                 if (para[i][0].equals(NS_PORT))
1170:                   ns_port = Integer.parseInt(para[i][1]);
1171:               }
1172:             catch (NumberFormatException ex)
1173:               {
1174:                 BAD_PARAM bad = new BAD_PARAM("Invalid " + NS_PORT
1175:                   + "property, unable to parse '" + props.getProperty(NS_PORT)
1176:                   + "'");
1177:                 bad.initCause(ex);
1178:                 throw bad;
1179:               }
1180:           }
1181:       }
1182:   }
1183: 
1184:   /**
1185:    * Set the ORB parameters. This method is normally called from
1186:    * {@link #init(String[], Properties)}.
1187:    *
1188:    * @param para the parameters, that were passed as the parameters to the
1189:    * <code>main(String[] args)</code> method of the current standalone
1190:    * application.
1191:    *
1192:    * @param props application specific properties that were passed as a second
1193:    * parameter in {@link init(String[], Properties)}). Can be <code>null</code>.
1194:    */
1195:   protected void set_parameters(String[] para, Properties props)
1196:   {
1197:     if ((para != null) && para.length > 1)
1198:       {
1199:         for (int i = 0; i < para.length - 1; i++)
1200:           {
1201:             if (para[i].endsWith("ListenOn"))
1202:               Port = Integer.parseInt(para[i + 1]);
1203:             if (para[i].endsWith("ORBInitRef"))
1204:               {
1205:                 StringTokenizer st = new StringTokenizer(para[i + 1], "=");
1206:                 initial_references.put(st.nextToken(),
1207:                   string_to_object(st.nextToken()));
1208:               }
1209: 
1210:             if (para[i].endsWith("ORBInitialHost"))
1211:               ns_host = para[i + 1];
1212: 
1213:             if (para[i].endsWith("ServerId"))
1214:               server_id = para[i++];
1215:             else if (para[i].endsWith("ORBid"))
1216:               orb_id = para[i++];
1217: 
1218:             try
1219:               {
1220:                 if (para[i].endsWith("ORBInitialPort"))
1221:                   ns_port = Integer.parseInt(para[i + 1]);
1222:               }
1223:             catch (NumberFormatException ex)
1224:               {
1225:                 throw new BAD_PARAM("Invalid " + para[i]
1226:                   + "parameter, unable to parse '"
1227:                   + props.getProperty(para[i + 1]) + "'");
1228:               }
1229:           }
1230:       }
1231: 
1232:     useProperties(props);
1233:   }
1234: 
1235:   /**
1236:    * Create IOR for the given object references.
1237:    */
1238:   protected IOR createIOR(Connected_objects.cObject ref)
1239:     throws BAD_OPERATION
1240:   {
1241:     IOR ior = new IOR();
1242:     ior.key = ref.key;
1243:     ior.Internet.port = ref.port;
1244: 
1245:     if (ref.object instanceof ObjectImpl)
1246:       {
1247:         ObjectImpl imp = (ObjectImpl) ref.object;
1248:         if (imp._ids().length > 0)
1249:           ior.Id = imp._ids() [ 0 ];
1250:       }
1251:     if (ior.Id == null)
1252:       ior.Id = ref.object.getClass().getName();
1253: 
1254:     ior.Internet.host = CollocatedOrbs.localHost;
1255:     ior.Internet.port = ref.port;
1256: 
1257:     return ior;
1258:   }
1259: 
1260:   /**
1261:    * Prepare object for connecting it to this ORB.
1262:    *
1263:    * @param object the object being connected.
1264:    *
1265:    * @throws BAD_PARAM if the object does not implement the
1266:    * {@link InvokeHandler}).
1267:    */
1268:   protected void prepareObject(org.omg.CORBA.Object object, IOR ior)
1269:     throws BAD_PARAM
1270:   {
1271:     /*
1272:      * if (!(object instanceof InvokeHandler)) throw new
1273:      * BAD_PARAM(object.getClass().getName() + " does not implement
1274:      * InvokeHandler. " );
1275:      */
1276: 
1277:     // If no delegate is set, set the default delegate.
1278:     if (object instanceof ObjectImpl)
1279:       {
1280:         ObjectImpl impl = (ObjectImpl) object;
1281:         try
1282:           {
1283:             if (impl._get_delegate() == null)
1284:               impl._set_delegate(new SimpleDelegate(this, ior));
1285:           }
1286:         catch (BAD_OPERATION ex)
1287:           {
1288:             // Some colaborants may throw this exception.
1289:             impl._set_delegate(new SimpleDelegate(this, ior));
1290:           }
1291:       }
1292:   }
1293: 
1294:   /**
1295:    * Write the response message.
1296:    *
1297:    * @param net_out the stream to write response into
1298:    * @param msh_request the request message header
1299:    * @param rh_request the request header
1300:    * @param handler the invocation handler that has been used to invoke the
1301:    * operation
1302:    * @param sysEx the system exception, thrown during the invocation, null if
1303:    * none.
1304:    *
1305:    * @throws IOException
1306:    */
1307:   private void respond_to_client(OutputStream net_out,
1308:     MessageHeader msh_request, RequestHeader rh_request,
1309:     ResponseHandlerImpl handler, SystemException sysEx
1310:   ) throws IOException
1311:   {
1312:     // Set the reply header properties.
1313:     ReplyHeader reply = handler.reply_header;
1314: 
1315:     if (sysEx != null)
1316:       reply.reply_status = ReplyHeader.SYSTEM_EXCEPTION;
1317:     else if (handler.isExceptionReply())
1318:       reply.reply_status = ReplyHeader.USER_EXCEPTION;
1319:     else
1320:       reply.reply_status = ReplyHeader.NO_EXCEPTION;
1321:     reply.request_id = rh_request.request_id;
1322: 
1323:     BufferedCdrOutput out =
1324:       new BufferedCdrOutput(50 + handler.getBuffer().buffer.size());
1325:     out.setOrb(this);
1326: 
1327:     out.setOffset(msh_request.getHeaderSize());
1328: 
1329:     reply.write(out);
1330: 
1331:     if (msh_request.version.since_inclusive(1, 2))
1332:       {
1333:         out.align(8);
1334: 
1335:         // Write the reply data from the handler. The handler data already
1336:         // include the necessary heading zeroes for alignment.
1337:       }
1338:     handler.getBuffer().buffer.writeTo(out);
1339: 
1340:     MessageHeader msh_reply = new MessageHeader();
1341: 
1342:     msh_reply.version = msh_request.version;
1343:     msh_reply.message_type = MessageHeader.REPLY;
1344:     msh_reply.message_size = out.buffer.size();
1345: 
1346:     // Write the reply.
1347:     msh_reply.write(net_out);
1348:     out.buffer.writeTo(net_out);
1349:     net_out.flush();
1350:   }
1351: 
1352:   /**
1353:    * Forward request to another target, as indicated by the passed exception.
1354:    */
1355:   private void forward_request(OutputStream net_out,
1356:     MessageHeader msh_request, RequestHeader rh_request, gnuForwardRequest info
1357:   ) throws IOException
1358:   {
1359:     MessageHeader msh_forward = new MessageHeader();
1360:     msh_forward.version = msh_request.version;
1361: 
1362:     ReplyHeader rh_forward = msh_forward.create_reply_header();
1363:     msh_forward.message_type = MessageHeader.REPLY;
1364:     rh_forward.reply_status = info.forwarding_code;
1365:     rh_forward.request_id = rh_request.request_id;
1366: 
1367:     // The forwarding code is either LOCATION_FORWARD or LOCATION_FORWARD_PERM.
1368:     BufferedCdrOutput out = new BufferedCdrOutput();
1369:     out.setOrb(this);
1370:     out.setOffset(msh_forward.getHeaderSize());
1371: 
1372:     rh_forward.write(out);
1373: 
1374:     if (msh_forward.version.since_inclusive(1, 2))
1375:       out.align(8);
1376:     out.write_Object(info.forward_reference);
1377: 
1378:     msh_forward.message_size = out.buffer.size();
1379: 
1380:     // Write the forwarding instruction.
1381:     msh_forward.write(net_out);
1382:     out.buffer.writeTo(net_out);
1383:     net_out.flush();
1384:   }
1385: 
1386:   /**
1387:    * Contains a single servicing task.
1388:    *
1389:    * Normally, each task matches a single remote invocation. However under
1390:    * frequent tandem submissions the same task may span over several
1391:    * invocations.
1392:    *
1393:    * @param serverSocket the ORB server socket.
1394:    *
1395:    * @throws MARSHAL
1396:    * @throws IOException
1397:    */
1398:   void serve(final portServer p, ServerSocket serverSocket)
1399:     throws MARSHAL, IOException
1400:   {
1401:     final Socket service;
1402:     service = serverSocket.accept();
1403: 
1404:     // Tell the server there are no more resources.
1405:     if (p.running_threads >= MAX_RUNNING_THREADS)
1406:       {
1407:         serveStep(service, true);
1408:         return;
1409:       }
1410: 
1411:     new Thread()
1412:       {
1413:         public void run()
1414:         {
1415:           try
1416:             {
1417:               synchronized (p)
1418:                 {
1419:                   p.running_threads++;
1420:                 }
1421:               serveStep(service, false);
1422:             }
1423:           finally
1424:             {
1425:               synchronized (p)
1426:                 {
1427:                   p.running_threads--;
1428:                 }
1429:             }
1430:         }
1431:       }.start();
1432:   }
1433: 
1434:   /**
1435:    * A single servicing step, when the client socket is alrady open.
1436:    *
1437:    * Normally, each task matches a single remote invocation. However under
1438:    * frequent tandem submissions the same task may span over several
1439:    * invocations.
1440:    *
1441:    * @param service the opened client socket.
1442:    * @param no_resources if true, the "NO RESOURCES" exception is thrown to the
1443:    * client.
1444:    */
1445:   void serveStep(Socket service, boolean no_resources)
1446:   {
1447:     try
1448:       {
1449:         Serving: while (true)
1450:           {
1451:             InputStream in = service.getInputStream();
1452:             service.setSoTimeout(TOUT_START_READING_MESSAGE);
1453: 
1454:             MessageHeader msh_request = new MessageHeader();
1455: 
1456:             try
1457:               {
1458:                 msh_request.read(in);
1459:               }
1460:             catch (MARSHAL ex)
1461:               {
1462:                 // This exception may be thrown due closing the connection.
1463:                 return;
1464:               }
1465: 
1466:             if (max_version != null)
1467:               {
1468:                 if (!msh_request.version.until_inclusive(max_version.major,
1469:                   max_version.minor))
1470:                   {
1471:                     OutputStream out = service.getOutputStream();
1472:                     new ErrorMessage(max_version).write(out);
1473:                     return;
1474:                   }
1475:               }
1476: 
1477:             byte[] r = msh_request.readMessage(in, service, TOUT_WHILE_READING,
1478:               TOUT_AFTER_RECEIVING);
1479: 
1480:             if (msh_request.message_type == MessageHeader.REQUEST)
1481:               {
1482:                 RequestHeader rh_request;
1483: 
1484:                 BufferredCdrInput cin = new BufferredCdrInput(r);
1485:                 cin.setOrb(this);
1486:                 cin.setVersion(msh_request.version);
1487:                 cin.setOffset(msh_request.getHeaderSize());
1488:                 cin.setBigEndian(msh_request.isBigEndian());
1489: 
1490:                 rh_request = msh_request.create_request_header();
1491: 
1492:                 // Read header and auto set the charset.
1493:                 rh_request.read(cin);
1494: 
1495:                 // in 1.2 and higher, align the current position at
1496:                 // 8 octet boundary.
1497:                 if (msh_request.version.since_inclusive(1, 2))
1498:                   {
1499:                     cin.align(8);
1500: 
1501:                     // find the target object.
1502:                   }
1503: 
1504:                 InvokeHandler target = (InvokeHandler) find_connected_object(
1505:                   rh_request.object_key, -1);
1506: 
1507:                 // Prepare the reply header. This must be done in advance,
1508:                 // as the size must be known for handler to set alignments
1509:                 // correctly.
1510:                 ReplyHeader rh_reply = msh_request.create_reply_header();
1511: 
1512:                 // TODO log errors about not existing objects and methods.
1513:                 ResponseHandlerImpl handler = new ResponseHandlerImpl(
1514:                   this, msh_request, rh_reply, rh_request);
1515: 
1516:                 SystemException sysEx = null;
1517: 
1518:                 try
1519:                   {
1520:                     if (no_resources)
1521:                       {
1522:                         NO_RESOURCES no = new NO_RESOURCES("Too many parallel calls");
1523:                         no.minor = Minor.Threads;
1524:                         throw no;
1525:                       }
1526:                     if (target == null)
1527:                       throw new OBJECT_NOT_EXIST();
1528:                     target._invoke(rh_request.operation, cin, handler);
1529:                   }
1530:                 catch (gnuForwardRequest forwarded)
1531:                   {
1532:                     OutputStream sou = service.getOutputStream();
1533:                     forward_request(sou, msh_request, rh_request, forwarded);
1534:                     if (service != null && !service.isClosed())
1535:                       {
1536:                         // Wait for the subsequent invocations on the
1537:                         // same socket for the TANDEM_REQUEST duration.
1538:                         service.setSoTimeout(TANDEM_REQUESTS);
1539:                         continue Serving;
1540:                       }
1541:                   }
1542:                 catch (UnknownException uex)
1543:                   {
1544:                     sysEx = new UNKNOWN("Unknown", 2,
1545:                       CompletionStatus.COMPLETED_MAYBE);
1546:                     sysEx.initCause(uex.originalEx);
1547: 
1548:                     org.omg.CORBA.portable.OutputStream ech = handler.createExceptionReply();
1549: 
1550:                     rh_reply.service_context = UnknownExceptionCtxHandler.addExceptionContext(
1551:                       rh_reply.service_context, uex.originalEx, ech);
1552: 
1553:                     ObjectCreator.writeSystemException(ech, sysEx);
1554:                   }
1555:                 catch (SystemException ex)
1556:                   {
1557:                     sysEx = ex;
1558: 
1559:                     org.omg.CORBA.portable.OutputStream ech = handler.createExceptionReply();
1560: 
1561:                     rh_reply.service_context = UnknownExceptionCtxHandler.addExceptionContext(
1562:                       rh_reply.service_context, ex, ech);
1563: 
1564:                     ObjectCreator.writeSystemException(ech, ex);
1565:                   }
1566:                 catch (Exception except)
1567:                   {
1568:                     // This should never happen under normal operation and
1569:                     // can only indicate errors in user object implementation.
1570:                     // We inform the user.
1571:                     except.printStackTrace();
1572: 
1573:                     sysEx = new UNKNOWN("Unknown", 2,
1574:                       CompletionStatus.COMPLETED_MAYBE);
1575:                     sysEx.initCause(except);
1576: 
1577:                     org.omg.CORBA.portable.OutputStream ech = handler.createExceptionReply();
1578: 
1579:                     rh_reply.service_context = UnknownExceptionCtxHandler.addExceptionContext(
1580:                       rh_reply.service_context, except, ech);
1581: 
1582:                     ObjectCreator.writeSystemException(ech, sysEx);
1583:                   }
1584: 
1585:                 // Write the response.
1586:                 if (rh_request.isResponseExpected())
1587:                   {
1588:                     OutputStream sou = service.getOutputStream();
1589:                     respond_to_client(sou, msh_request, rh_request, handler,
1590:                       sysEx);
1591:                   }
1592:               }
1593:             else if (msh_request.message_type == MessageHeader.CLOSE_CONNECTION
1594:               || msh_request.message_type == MessageHeader.MESSAGE_ERROR)
1595:               {
1596:                 CloseMessage.close(service.getOutputStream());
1597:                 service.close();
1598:                 return;
1599:               }
1600: 
1601:             if (service != null && !service.isClosed())
1602: 
1603:               // Wait for the subsequent invocations on the
1604:               // same socket for the TANDEM_REQUEST duration.
1605:               service.setSoTimeout(TANDEM_REQUESTS);
1606:             else
1607:               return;
1608:           }
1609:       }
1610:     catch (SocketException ex)
1611:       {
1612:         // OK.
1613:         return;
1614:       }
1615:     catch (IOException ioex)
1616:       {
1617:         // Network error, probably transient.
1618:         // TODO log it.
1619:         return;
1620:       }
1621:     finally
1622:       {
1623:         try
1624:           {
1625:             if (service!=null && !service.isClosed())
1626:               service.close();
1627:           }
1628:         catch (IOException ioex)
1629:           {
1630:             // OK.
1631:           }
1632:       }
1633:   }
1634: 
1635:   /**
1636:    * Set the ORB parameters from the properties that were accumulated
1637:    * from several locations.
1638:    */
1639:   protected void useProperties(Properties props)
1640:   {
1641:     if (props != null)
1642:       {
1643:         if (props.containsKey(LISTEN_ON))
1644:           Port = Integer.parseInt(props.getProperty(LISTEN_ON));
1645:         if (props.containsKey(NS_HOST))
1646:           ns_host = props.getProperty(NS_HOST);
1647:         try
1648:           {
1649:             if (props.containsKey(NS_PORT))
1650:               ns_port = Integer.parseInt(props.getProperty(NS_PORT));
1651:             if (props.containsKey(START_READING_MESSAGE))
1652:               TOUT_START_READING_MESSAGE =
1653:                 Integer.parseInt(props.getProperty(START_READING_MESSAGE));
1654:             if (props.containsKey(WHILE_READING))
1655:               TOUT_WHILE_READING =
1656:                 Integer.parseInt(props.getProperty(WHILE_READING));
1657:             if (props.containsKey(AFTER_RECEIVING))
1658:               TOUT_AFTER_RECEIVING =
1659:                 Integer.parseInt(props.getProperty(AFTER_RECEIVING));
1660:             if (props.containsKey(SERVER_ERROR_PAUSE))
1661:               TWAIT_SERVER_ERROR_PAUSE =
1662:                 Integer.parseInt(props.getProperty(SERVER_ERROR_PAUSE));
1663:           }
1664:         catch (NumberFormatException ex)
1665:           {
1666:             throw new BAD_PARAM("Invalid " + NS_PORT +
1667:               "property, unable to parse '" + props.getProperty(NS_PORT) +
1668:               "'"
1669:             );
1670:           }
1671: 
1672:         if (props.containsKey(SocketFactory.PROPERTY))
1673:           {
1674:             String factory = null;
1675:             try
1676:               {
1677:                 factory = props.getProperty(SocketFactory.PROPERTY);
1678:                 if (factory!=null)
1679:                   socketFactory = (SocketFactory)
1680:                     ObjectCreator.forName(factory).newInstance();
1681:               }
1682:             catch (Exception ex)
1683:               {
1684:                 BAD_PARAM p = new BAD_PARAM("Bad socket factory "+factory);
1685:                 p.initCause(ex);
1686:                 throw p;
1687:               }
1688:           }
1689: 
1690:         if (props.containsKey(ORB_ID))
1691:           orb_id = props.getProperty(ORB_ID);
1692: 
1693:         if (props.containsKey(SERVER_ID))
1694:           server_id = props.getProperty(SERVER_ID);
1695: 
1696:         Enumeration en = props.elements();
1697:         while (en.hasMoreElements())
1698:           {
1699:             String item = (String) en.nextElement();
1700:             if (item.equals(REFERENCE))
1701:               initial_references.put(item,
1702:                 string_to_object(props.getProperty(item))
1703:               );
1704:           }
1705:       }
1706:   }
1707: 
1708:   /**
1709:    * Get the next instance with a response being received. If all currently sent
1710:    * responses not yet processed, this method pauses till at least one of them
1711:    * is complete. If there are no requests currently sent, the method pauses
1712:    * till some request is submitted and the response is received. This strategy
1713:    * is identical to the one accepted by Suns 1.4 ORB implementation.
1714:    *
1715:    * The returned response is removed from the list of the currently submitted
1716:    * responses and is never returned again.
1717:    *
1718:    * @return the previously sent request that now contains the received
1719:    * response.
1720:    *
1721:    * @throws WrongTransaction If the method was called from the transaction
1722:    * scope different than the one, used to send the request. The exception can
1723:    * be raised only if the request is implicitly associated with some particular
1724:    * transaction.
1725:    */
1726:   public Request get_next_response() throws org.omg.CORBA.WrongTransaction
1727:   {
1728:     return asynchron.get_next_response();
1729:   }
1730: 
1731:   /**
1732:    * Find if any of the requests that have been previously sent with
1733:    * {@link #send_multiple_requests_deferred}, have a response yet.
1734:    *
1735:    * @return true if there is at least one response to the previously sent
1736:    * request, false otherwise.
1737:    */
1738:   public boolean poll_next_response()
1739:   {
1740:     return asynchron.poll_next_response();
1741:   }
1742: 
1743:   /**
1744:    * Send multiple prepared requests expecting to get a reply. All requests are
1745:    * send in parallel, each in its own separate thread. When the reply arrives,
1746:    * it is stored in the agreed fields of the corresponing request data
1747:    * structure. If this method is called repeatedly, the new requests are added
1748:    * to the set of the currently sent requests, but the old set is not
1749:    * discarded.
1750:    *
1751:    * @param requests the prepared array of requests.
1752:    *
1753:    * @see #poll_next_response()
1754:    * @see #get_next_response()
1755:    * @see Request#send_deferred()
1756:    */
1757:   public void send_multiple_requests_deferred(Request[] requests)
1758:   {
1759:     asynchron.send_multiple_requests_deferred(requests);
1760:   }
1761: 
1762:   /**
1763:    * Send multiple prepared requests one way, do not caring about the answer.
1764:    * The messages, containing requests, will be marked, indicating that the
1765:    * sender is not expecting to get a reply.
1766:    *
1767:    * @param requests the prepared array of requests.
1768:    *
1769:    * @see Request#send_oneway()
1770:    */
1771:   public void send_multiple_requests_oneway(Request[] requests)
1772:   {
1773:     asynchron.send_multiple_requests_oneway(requests);
1774:   }
1775: 
1776:   /**
1777:    * Set the flag, forcing all server threads to terminate.
1778:    */
1779:   protected void finalize() throws java.lang.Throwable
1780:   {
1781:     running = false;
1782:     super.finalize();
1783:   }
1784: 
1785:   /**
1786:    * Get the number of objects that are connected to this ORB.
1787:    *
1788:    * @return the number of objects, connected to this ORB.
1789:    */
1790:   public int countConnectedObjects()
1791:   {
1792:     return connected_objects.size();
1793:   }
1794: }