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 the 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).
 942:    *
 943:    * The method only returns after calling {@link #shutdown(boolean)}.
 944:    */
 945:   public void run()
 946:   {
 947:     running = true;
 948: 
 949:     // Instantiate the port server for each socket.
 950:     Iterator iter = connected_objects.entrySet().iterator();
 951:     Map.Entry m;
 952:     Connected_objects.cObject obj;
 953: 
 954:     while (iter.hasNext())
 955:       {
 956:         m = (Map.Entry) iter.next();
 957:         obj = (Connected_objects.cObject) m.getValue();
 958: 
 959:         portServer subserver;
 960: 
 961:         if (obj.identity == null)
 962:           {
 963:             subserver = new portServer(obj.port);
 964:             portServers.add(subserver);
 965:           }
 966:         else
 967:           subserver = (portServer) identities.get(obj.identity);
 968:         
 969:         if (!subserver.isAlive())
 970:           {
 971:             // Reuse the current thread for the last portServer.
 972:             if (!iter.hasNext())
 973:               {
 974:                 // Discard the iterator, eliminating lock checks.
 975:                 iter = null;
 976:                 subserver.run();
 977:                 return;
 978:               }
 979:             else
 980:               subserver.start();
 981:           }
 982:       }
 983:   }
 984:   
 985:   /**
 986:    * Start the server in a new thread, if not already running. This method is
 987:    * used to ensure that the objects being transfered will be served from the 
 988:    * remote side, if required. If the ORB is started using this method, it
 989:    * starts as a daemon thread.
 990:    */
 991:   public void ensureRunning()
 992:   {
 993:     final OrbFunctional THIS = this;
 994:     
 995:     if (!running)
 996:       {
 997:         Thread t = new Thread()
 998:         {
 999:           public void run()
1000:           {
1001:             THIS.run();
1002:           }
1003:         };
1004:         t.setDaemon(true);
1005:         t.start();
1006:       }
1007:   }
1008: 
1009:   /**
1010:    * Shutdown the ORB server.
1011:    *
1012:    * @param wait_for_completion if true, the current thread is suspended until
1013:    * the shutdown process is complete.
1014:    */
1015:   public void shutdown(boolean wait_for_completion)
1016:   {
1017:     super.shutdown(wait_for_completion);
1018:     running = false;
1019: 
1020:     if (!wait_for_completion)
1021:       {
1022:         for (int i = 0; i < portServers.size(); i++)
1023:           {
1024:             portServer p = (portServer) portServers.get(i);
1025:             p.close_now();
1026:           }
1027:       }
1028:   }
1029: 
1030:   /**
1031:    * Find and return the CORBA object, addressed by the given IOR string
1032:    * representation. The object can (an usually is) located on a remote
1033:    * computer, possibly running a different (not necessary java) CORBA
1034:    * implementation.
1035:    * 
1036:    * @param ior the object IOR representation string.
1037:    * 
1038:    * @return the found CORBA object.
1039:    * @see object_to_string(org.omg.CORBA.Object)
1040:    */
1041:   public org.omg.CORBA.Object string_to_object(String an_ior)
1042:   {
1043:     return nameParser.corbaloc(an_ior, this);
1044:   }
1045:   
1046:   /**
1047:    * Convert ior reference to CORBA object.
1048:    */
1049:   public org.omg.CORBA.Object ior_to_object(IOR ior)
1050:   {
1051:     org.omg.CORBA.Object object = find_local_object(ior);
1052:     if (object == null)
1053:       {
1054:         ObjectImpl impl = StubLocator.search(this, ior);
1055:         try
1056:           {
1057:             if (impl._get_delegate() == null)
1058:               impl._set_delegate(new IorDelegate(this, ior));
1059:           }
1060:         catch (BAD_OPERATION ex)
1061:           {
1062:             // Some colaborants may throw this exception
1063:             // in response to the attempt to get the unset delegate.
1064:             impl._set_delegate(new IorDelegate(this, ior));
1065:           }
1066: 
1067:         object = impl;
1068:         // TODO remove commented out code below.
1069:         // connected_objects.add(ior.key, impl, ior.Internet.port, null);
1070:       }
1071:     return object;
1072:   }
1073: 
1074:   /**
1075:    * Get the default naming service for the case when there no NameService
1076:    * entries.
1077:    */
1078:   protected org.omg.CORBA.Object getDefaultNameService()
1079:   {
1080:     if (initial_references.containsKey(NAME_SERVICE))
1081:       return (org.omg.CORBA.Object) initial_references.get(NAME_SERVICE);
1082: 
1083:     IOR ior = new IOR();
1084:     ior.Id = NamingContextExtHelper.id();
1085:     ior.Internet.host = ns_host;
1086:     ior.Internet.port = ns_port;
1087:     ior.key = NamingServiceTransient.getDefaultKey();
1088: 
1089:     IorObject iorc = new IorObject(this, ior);
1090:     NamingContextExt namer = NamingContextExtHelper.narrow(iorc);
1091:     initial_references.put(NAME_SERVICE, namer);
1092:     return namer;
1093:   }
1094: 
1095:   /**
1096:    * Find and return the object, that must be previously connected to this ORB.
1097:    * Return null if no such object is available.
1098:    * 
1099:    * @param key the object key.
1100:    * @param port the port where the object is connected.
1101:    * 
1102:    * @return the connected object, null if none.
1103:    */
1104:   protected org.omg.CORBA.Object find_connected_object(byte[] key, int port)
1105:   {
1106:     Connected_objects.cObject ref = connected_objects.get(key);
1107:     if (ref == null)
1108:       return null;
1109:     if (port >= 0 && ref.port != port)
1110:       return null;
1111:     else
1112:       return ref.object;
1113:   }
1114: 
1115:   /**
1116:    * Set the ORB parameters. This method is normally called from
1117:    * {@link #init(Applet, Properties)}.
1118:    * 
1119:    * @param app the current applet.
1120:    * 
1121:    * @param props application specific properties, passed as the second
1122:    * parameter in {@link #init(Applet, Properties)}. Can be <code>null</code>.
1123:    */
1124:   protected void set_parameters(Applet app, Properties props)
1125:   {
1126:     useProperties(props);
1127: 
1128:     String[][] para = app.getParameterInfo();
1129:     if (para != null)
1130:       {
1131:         for (int i = 0; i < para.length; i++)
1132:           {
1133:             if (para[i][0].equals(LISTEN_ON))
1134:               Port = Integer.parseInt(para[i][1]);
1135:             if (para[i][0].equals(REFERENCE))
1136:               {
1137:                 StringTokenizer st = new StringTokenizer(para[i][1], "=");
1138:                 initial_references.put(st.nextToken(),
1139:                   string_to_object(st.nextToken()));
1140:               }
1141: 
1142:             if (para[i][0].equals(ORB_ID))
1143:               orb_id = para[i][1];
1144: 
1145:             if (para[i][0].equals(SERVER_ID))
1146:               server_id = para[i][1];
1147: 
1148:             if (para[i][0].equals(NS_HOST))
1149:               ns_host = para[i][1];
1150:             if (para[i][0].equals(START_READING_MESSAGE))
1151:               TOUT_START_READING_MESSAGE = Integer.parseInt(para[i][1]);
1152:             if (para[i][0].equals(WHILE_READING))
1153:               TOUT_WHILE_READING = Integer.parseInt(para[i][1]);
1154:             if (para[i][0].equals(AFTER_RECEIVING))
1155:               TOUT_AFTER_RECEIVING = Integer.parseInt(para[i][1]);
1156:             try
1157:               {
1158:                 if (para[i][0].equals(NS_PORT))
1159:                   ns_port = Integer.parseInt(para[i][1]);
1160:               }
1161:             catch (NumberFormatException ex)
1162:               {
1163:                 BAD_PARAM bad = new BAD_PARAM("Invalid " + NS_PORT
1164:                   + "property, unable to parse '" + props.getProperty(NS_PORT)
1165:                   + "'");
1166:                 bad.initCause(ex);
1167:                 throw bad;
1168:               }
1169:           }
1170:       }
1171:   }
1172: 
1173:   /**
1174:    * Set the ORB parameters. This method is normally called from
1175:    * {@link #init(String[], Properties)}.
1176:    * 
1177:    * @param para the parameters, that were passed as the parameters to the
1178:    * <code>main(String[] args)</code> method of the current standalone
1179:    * application.
1180:    * 
1181:    * @param props application specific properties that were passed as a second
1182:    * parameter in {@link init(String[], Properties)}). Can be <code>null</code>.
1183:    */
1184:   protected void set_parameters(String[] para, Properties props)
1185:   {
1186:     if (para.length > 1)
1187:       {
1188:         for (int i = 0; i < para.length - 1; i++)
1189:           {
1190:             if (para[i].endsWith("ListenOn"))
1191:               Port = Integer.parseInt(para[i + 1]);
1192:             if (para[i].endsWith("ORBInitRef"))
1193:               {
1194:                 StringTokenizer st = new StringTokenizer(para[i + 1], "=");
1195:                 initial_references.put(st.nextToken(),
1196:                   string_to_object(st.nextToken()));
1197:               }
1198: 
1199:             if (para[i].endsWith("ORBInitialHost"))
1200:               ns_host = para[i + 1];
1201: 
1202:             if (para[i].endsWith("ServerId"))
1203:               server_id = para[i++];
1204:             else if (para[i].endsWith("ORBid"))
1205:               orb_id = para[i++];
1206: 
1207:             try
1208:               {
1209:                 if (para[i].endsWith("ORBInitialPort"))
1210:                   ns_port = Integer.parseInt(para[i + 1]);
1211:               }
1212:             catch (NumberFormatException ex)
1213:               {
1214:                 throw new BAD_PARAM("Invalid " + para[i]
1215:                   + "parameter, unable to parse '"
1216:                   + props.getProperty(para[i + 1]) + "'");
1217:               }
1218:           }
1219:       }
1220: 
1221:     useProperties(props);
1222:   }
1223: 
1224:   /**
1225:    * Create IOR for the given object references.
1226:    */
1227:   protected IOR createIOR(Connected_objects.cObject ref)
1228:     throws BAD_OPERATION
1229:   {
1230:     IOR ior = new IOR();
1231:     ior.key = ref.key;
1232:     ior.Internet.port = ref.port;
1233: 
1234:     if (ref.object instanceof ObjectImpl)
1235:       {
1236:         ObjectImpl imp = (ObjectImpl) ref.object;
1237:         if (imp._ids().length > 0)
1238:           ior.Id = imp._ids() [ 0 ];
1239:       }
1240:     if (ior.Id == null)
1241:       ior.Id = ref.object.getClass().getName();
1242:     try
1243:       {
1244:         ior.Internet.host = InetAddress.getLocalHost().getHostAddress();
1245:         ior.Internet.port = ref.port;
1246:       }
1247:     catch (UnknownHostException ex)
1248:       {
1249:         throw new BAD_OPERATION("Cannot resolve the local host address");
1250:       }
1251:     return ior;
1252:   }
1253: 
1254:   /**
1255:    * Prepare object for connecting it to this ORB.
1256:    *
1257:    * @param object the object being connected.
1258:    *
1259:    * @throws BAD_PARAM if the object does not implement the
1260:    * {@link InvokeHandler}).
1261:    */
1262:   protected void prepareObject(org.omg.CORBA.Object object, IOR ior)
1263:     throws BAD_PARAM
1264:   {
1265:     /*
1266:      * if (!(object instanceof InvokeHandler)) throw new
1267:      * BAD_PARAM(object.getClass().getName() + " does not implement
1268:      * InvokeHandler. " );
1269:      */
1270: 
1271:     // If no delegate is set, set the default delegate.
1272:     if (object instanceof ObjectImpl)
1273:       {
1274:         ObjectImpl impl = (ObjectImpl) object;
1275:         try
1276:           {
1277:             if (impl._get_delegate() == null)
1278:               impl._set_delegate(new SimpleDelegate(this, ior));
1279:           }
1280:         catch (BAD_OPERATION ex)
1281:           {
1282:             // Some colaborants may throw this exception.
1283:             impl._set_delegate(new SimpleDelegate(this, ior));
1284:           }
1285:       }
1286:   }
1287: 
1288:   /**
1289:    * Write the response message.
1290:    *
1291:    * @param net_out the stream to write response into
1292:    * @param msh_request the request message header
1293:    * @param rh_request the request header
1294:    * @param handler the invocation handler that has been used to invoke the
1295:    * operation
1296:    * @param sysEx the system exception, thrown during the invocation, null if
1297:    * none.
1298:    *
1299:    * @throws IOException
1300:    */
1301:   private void respond_to_client(OutputStream net_out,
1302:     MessageHeader msh_request, RequestHeader rh_request,
1303:     ResponseHandlerImpl handler, SystemException sysEx
1304:   ) throws IOException
1305:   {
1306:     // Set the reply header properties.
1307:     ReplyHeader reply = handler.reply_header;
1308: 
1309:     if (sysEx != null)
1310:       reply.reply_status = ReplyHeader.SYSTEM_EXCEPTION;
1311:     else if (handler.isExceptionReply())
1312:       reply.reply_status = ReplyHeader.USER_EXCEPTION;
1313:     else
1314:       reply.reply_status = ReplyHeader.NO_EXCEPTION;
1315:     reply.request_id = rh_request.request_id;
1316: 
1317:     BufferedCdrOutput out =
1318:       new BufferedCdrOutput(50 + handler.getBuffer().buffer.size());
1319:     out.setOrb(this);
1320: 
1321:     out.setOffset(msh_request.getHeaderSize());
1322: 
1323:     reply.write(out);
1324: 
1325:     if (msh_request.version.since_inclusive(1, 2))
1326:       {
1327:         out.align(8);
1328: 
1329:         // Write the reply data from the handler. The handler data already
1330:         // include the necessary heading zeroes for alignment.
1331:       }
1332:     handler.getBuffer().buffer.writeTo(out);
1333: 
1334:     MessageHeader msh_reply = new MessageHeader();
1335: 
1336:     msh_reply.version = msh_request.version;
1337:     msh_reply.message_type = MessageHeader.REPLY;
1338:     msh_reply.message_size = out.buffer.size();
1339: 
1340:     // Write the reply.
1341:     msh_reply.write(net_out);
1342:     out.buffer.writeTo(net_out);
1343:     net_out.flush();
1344:   }
1345: 
1346:   /**
1347:    * Forward request to another target, as indicated by the passed exception.
1348:    */
1349:   private void forward_request(OutputStream net_out,
1350:     MessageHeader msh_request, RequestHeader rh_request, gnuForwardRequest info
1351:   ) throws IOException
1352:   {
1353:     MessageHeader msh_forward = new MessageHeader();
1354:     msh_forward.version = msh_request.version;
1355: 
1356:     ReplyHeader rh_forward = msh_forward.create_reply_header();
1357:     msh_forward.message_type = MessageHeader.REPLY;
1358:     rh_forward.reply_status = info.forwarding_code;
1359:     rh_forward.request_id = rh_request.request_id;
1360: 
1361:     // The forwarding code is either LOCATION_FORWARD or LOCATION_FORWARD_PERM.
1362:     BufferedCdrOutput out = new BufferedCdrOutput();
1363:     out.setOrb(this);
1364:     out.setOffset(msh_forward.getHeaderSize());
1365: 
1366:     rh_forward.write(out);
1367: 
1368:     if (msh_forward.version.since_inclusive(1, 2))
1369:       out.align(8);
1370:     out.write_Object(info.forward_reference);
1371: 
1372:     msh_forward.message_size = out.buffer.size();
1373: 
1374:     // Write the forwarding instruction.
1375:     msh_forward.write(net_out);
1376:     out.buffer.writeTo(net_out);
1377:     net_out.flush();
1378:   }
1379: 
1380:   /**
1381:    * Contains a single servicing task.
1382:    *
1383:    * Normally, each task matches a single remote invocation. However under
1384:    * frequent tandem submissions the same task may span over several
1385:    * invocations.
1386:    *
1387:    * @param serverSocket the ORB server socket.
1388:    *
1389:    * @throws MARSHAL
1390:    * @throws IOException
1391:    */
1392:   void serve(final portServer p, ServerSocket serverSocket)
1393:     throws MARSHAL, IOException
1394:   {
1395:     final Socket service;
1396:     service = serverSocket.accept();
1397: 
1398:     // Tell the server there are no more resources.
1399:     if (p.running_threads >= MAX_RUNNING_THREADS)
1400:       {
1401:         serveStep(service, true);
1402:         return;
1403:       }
1404: 
1405:     new Thread()
1406:       {
1407:         public void run()
1408:         {
1409:           try
1410:             {
1411:               synchronized (p)
1412:                 {
1413:                   p.running_threads++;
1414:                 }
1415:               serveStep(service, false);
1416:             }
1417:           finally
1418:             {
1419:               synchronized (p)
1420:                 {
1421:                   p.running_threads--;
1422:                 }
1423:             }
1424:         }
1425:       }.start();
1426:   }
1427: 
1428:   /**
1429:    * A single servicing step, when the client socket is alrady open.
1430:    * 
1431:    * Normally, each task matches a single remote invocation. However under
1432:    * frequent tandem submissions the same task may span over several
1433:    * invocations.
1434:    * 
1435:    * @param service the opened client socket.
1436:    * @param no_resources if true, the "NO RESOURCES" exception is thrown to the
1437:    * client.
1438:    */
1439:   void serveStep(Socket service, boolean no_resources)
1440:   {
1441:     try
1442:       {
1443:         Serving: while (true)
1444:           {
1445:             InputStream in = service.getInputStream();
1446:             service.setSoTimeout(TOUT_START_READING_MESSAGE);
1447: 
1448:             MessageHeader msh_request = new MessageHeader();
1449: 
1450:             try
1451:               {
1452:                 msh_request.read(in);
1453:               }
1454:             catch (MARSHAL ex)
1455:               {
1456:                 // This exception may be thrown due closing the connection.
1457:                 return;
1458:               }
1459: 
1460:             if (max_version != null)
1461:               {
1462:                 if (!msh_request.version.until_inclusive(max_version.major,
1463:                   max_version.minor))
1464:                   {
1465:                     OutputStream out = service.getOutputStream();
1466:                     new ErrorMessage(max_version).write(out);
1467:                     return;
1468:                   }
1469:               }
1470: 
1471:             byte[] r = msh_request.readMessage(in, service, TOUT_WHILE_READING,
1472:               TOUT_AFTER_RECEIVING);
1473: 
1474:             if (msh_request.message_type == MessageHeader.REQUEST)
1475:               {
1476:                 RequestHeader rh_request;
1477: 
1478:                 BufferredCdrInput cin = new BufferredCdrInput(r);
1479:                 cin.setOrb(this);
1480:                 cin.setVersion(msh_request.version);
1481:                 cin.setOffset(msh_request.getHeaderSize());
1482:                 cin.setBigEndian(msh_request.isBigEndian());
1483: 
1484:                 rh_request = msh_request.create_request_header();
1485: 
1486:                 // Read header and auto set the charset.
1487:                 rh_request.read(cin);
1488: 
1489:                 // in 1.2 and higher, align the current position at
1490:                 // 8 octet boundary.
1491:                 if (msh_request.version.since_inclusive(1, 2))
1492:                   {
1493:                     cin.align(8);
1494: 
1495:                     // find the target object.
1496:                   }
1497: 
1498:                 InvokeHandler target = (InvokeHandler) find_connected_object(
1499:                   rh_request.object_key, -1);
1500: 
1501:                 // Prepare the reply header. This must be done in advance,
1502:                 // as the size must be known for handler to set alignments
1503:                 // correctly.
1504:                 ReplyHeader rh_reply = msh_request.create_reply_header();
1505: 
1506:                 // TODO log errors about not existing objects and methods.
1507:                 ResponseHandlerImpl handler = new ResponseHandlerImpl(
1508:                   this, msh_request, rh_reply, rh_request);
1509: 
1510:                 SystemException sysEx = null;
1511: 
1512:                 try
1513:                   {
1514:                     if (no_resources)
1515:                       {
1516:                         NO_RESOURCES no = new NO_RESOURCES("Too many parallel calls");
1517:                         no.minor = Minor.Threads;
1518:                         throw no;
1519:                       }
1520:                     if (target == null)
1521:                       throw new OBJECT_NOT_EXIST();
1522:                     target._invoke(rh_request.operation, cin, handler);
1523:                   }
1524:                 catch (gnuForwardRequest forwarded)
1525:                   {
1526:                     OutputStream sou = service.getOutputStream();
1527:                     forward_request(sou, msh_request, rh_request, forwarded);
1528:                     if (service != null && !service.isClosed())
1529:                       {
1530:                         // Wait for the subsequent invocations on the
1531:                         // same socket for the TANDEM_REQUEST duration.
1532:                         service.setSoTimeout(TANDEM_REQUESTS);
1533:                         continue Serving;
1534:                       }
1535:                   }
1536:                 catch (UnknownException uex)
1537:                   {
1538:                     sysEx = new UNKNOWN("Unknown", 2,
1539:                       CompletionStatus.COMPLETED_MAYBE);
1540:                     sysEx.initCause(uex.originalEx);
1541: 
1542:                     org.omg.CORBA.portable.OutputStream ech = handler.createExceptionReply();
1543: 
1544:                     rh_reply.service_context = UnknownExceptionCtxHandler.addExceptionContext(
1545:                       rh_reply.service_context, uex.originalEx, ech);
1546: 
1547:                     ObjectCreator.writeSystemException(ech, sysEx);
1548:                   }
1549:                 catch (SystemException ex)
1550:                   {
1551:                     sysEx = ex;
1552:                     
1553:                     org.omg.CORBA.portable.OutputStream ech = handler.createExceptionReply();
1554:                     
1555:                     rh_reply.service_context = UnknownExceptionCtxHandler.addExceptionContext(
1556:                       rh_reply.service_context, ex, ech);
1557:                     
1558:                     ObjectCreator.writeSystemException(ech, ex);
1559:                   }
1560:                 catch (Exception except)
1561:                   {
1562:                     // This should never happen under normal operation and
1563:                     // can only indicate errors in user object implementation.
1564:                     // We inform the user.
1565:                     except.printStackTrace();
1566: 
1567:                     sysEx = new UNKNOWN("Unknown", 2,
1568:                       CompletionStatus.COMPLETED_MAYBE);
1569:                     sysEx.initCause(except);
1570: 
1571:                     org.omg.CORBA.portable.OutputStream ech = handler.createExceptionReply();
1572: 
1573:                     rh_reply.service_context = UnknownExceptionCtxHandler.addExceptionContext(
1574:                       rh_reply.service_context, except, ech);
1575: 
1576:                     ObjectCreator.writeSystemException(ech, sysEx);
1577:                   }
1578: 
1579:                 // Write the response.
1580:                 if (rh_request.isResponseExpected())
1581:                   {
1582:                     OutputStream sou = service.getOutputStream();
1583:                     respond_to_client(sou, msh_request, rh_request, handler,
1584:                       sysEx);
1585:                   }
1586:               }
1587:             else if (msh_request.message_type == MessageHeader.CLOSE_CONNECTION
1588:               || msh_request.message_type == MessageHeader.MESSAGE_ERROR)
1589:               {
1590:                 CloseMessage.close(service.getOutputStream());
1591:                 service.close();
1592:                 return;
1593:               }
1594: 
1595:             if (service != null && !service.isClosed())
1596: 
1597:               // Wait for the subsequent invocations on the
1598:               // same socket for the TANDEM_REQUEST duration.
1599:               service.setSoTimeout(TANDEM_REQUESTS);
1600:             else
1601:               return;
1602:           }
1603:       }
1604:     catch (SocketException ex)
1605:       {
1606:         // OK.
1607:         return;
1608:       }
1609:     catch (IOException ioex)
1610:       {
1611:         // Network error, probably transient.
1612:         // TODO log it.
1613:         return;
1614:       }
1615:     finally
1616:       {
1617:         try 
1618:           {
1619:             if (service!=null && !service.isClosed())
1620:               service.close();
1621:           }
1622:         catch (IOException ioex)
1623:           {
1624:             // OK.
1625:           }
1626:       }
1627:   }
1628:   
1629:   /**
1630:    * Set the ORB parameters from the properties that were accumulated
1631:    * from several locations.
1632:    */
1633:   protected void useProperties(Properties props)
1634:   {
1635:     if (props != null)
1636:       {
1637:         if (props.containsKey(LISTEN_ON))
1638:           Port = Integer.parseInt(props.getProperty(LISTEN_ON));
1639:         if (props.containsKey(NS_HOST))
1640:           ns_host = props.getProperty(NS_HOST);
1641:         try
1642:           {
1643:             if (props.containsKey(NS_PORT))
1644:               ns_port = Integer.parseInt(props.getProperty(NS_PORT));
1645:             if (props.containsKey(START_READING_MESSAGE))
1646:               TOUT_START_READING_MESSAGE =
1647:                 Integer.parseInt(props.getProperty(START_READING_MESSAGE));
1648:             if (props.containsKey(WHILE_READING))
1649:               TOUT_WHILE_READING =
1650:                 Integer.parseInt(props.getProperty(WHILE_READING));
1651:             if (props.containsKey(AFTER_RECEIVING))
1652:               TOUT_AFTER_RECEIVING =
1653:                 Integer.parseInt(props.getProperty(AFTER_RECEIVING));
1654:             if (props.containsKey(SERVER_ERROR_PAUSE))
1655:               TWAIT_SERVER_ERROR_PAUSE = 
1656:                 Integer.parseInt(props.getProperty(SERVER_ERROR_PAUSE));
1657:           }
1658:         catch (NumberFormatException ex)
1659:           {
1660:             throw new BAD_PARAM("Invalid " + NS_PORT +
1661:               "property, unable to parse '" + props.getProperty(NS_PORT) +
1662:               "'"
1663:             );
1664:           }
1665:         
1666:         if (props.containsKey(SocketFactory.PROPERTY))
1667:           {
1668:             String factory = null;
1669:             try
1670:               {
1671:                 factory = props.getProperty(SocketFactory.PROPERTY);
1672:                 if (factory!=null)
1673:                   socketFactory = (SocketFactory) 
1674:                     ObjectCreator.forName(factory).newInstance();
1675:               }
1676:             catch (Exception ex)
1677:               {
1678:                 BAD_PARAM p = new BAD_PARAM("Bad socket factory "+factory);
1679:                 p.initCause(ex);
1680:                 throw p;
1681:               }
1682:           }
1683:         
1684:         if (props.containsKey(ORB_ID))
1685:           orb_id = props.getProperty(ORB_ID);
1686:         
1687:         if (props.containsKey(SERVER_ID))
1688:           server_id = props.getProperty(SERVER_ID);
1689:         
1690:         Enumeration en = props.elements();
1691:         while (en.hasMoreElements())
1692:           {
1693:             String item = (String) en.nextElement();
1694:             if (item.equals(REFERENCE))
1695:               initial_references.put(item,
1696:                 string_to_object(props.getProperty(item))
1697:               );
1698:           }
1699:       }
1700:   }
1701: 
1702:   /**
1703:    * Get the next instance with a response being received. If all currently sent
1704:    * responses not yet processed, this method pauses till at least one of them
1705:    * is complete. If there are no requests currently sent, the method pauses
1706:    * till some request is submitted and the response is received. This strategy
1707:    * is identical to the one accepted by Suns 1.4 ORB implementation.
1708:    *
1709:    * The returned response is removed from the list of the currently submitted
1710:    * responses and is never returned again.
1711:    *
1712:    * @return the previously sent request that now contains the received
1713:    * response.
1714:    *
1715:    * @throws WrongTransaction If the method was called from the transaction
1716:    * scope different than the one, used to send the request. The exception can
1717:    * be raised only if the request is implicitly associated with some particular
1718:    * transaction.
1719:    */
1720:   public Request get_next_response() throws org.omg.CORBA.WrongTransaction
1721:   {
1722:     return asynchron.get_next_response();
1723:   }
1724: 
1725:   /**
1726:    * Find if any of the requests that have been previously sent with
1727:    * {@link #send_multiple_requests_deferred}, have a response yet.
1728:    *
1729:    * @return true if there is at least one response to the previously sent
1730:    * request, false otherwise.
1731:    */
1732:   public boolean poll_next_response()
1733:   {
1734:     return asynchron.poll_next_response();
1735:   }
1736: 
1737:   /**
1738:    * Send multiple prepared requests expecting to get a reply. All requests are
1739:    * send in parallel, each in its own separate thread. When the reply arrives,
1740:    * it is stored in the agreed fields of the corresponing request data
1741:    * structure. If this method is called repeatedly, the new requests are added
1742:    * to the set of the currently sent requests, but the old set is not
1743:    * discarded.
1744:    *
1745:    * @param requests the prepared array of requests.
1746:    *
1747:    * @see #poll_next_response()
1748:    * @see #get_next_response()
1749:    * @see Request#send_deferred()
1750:    */
1751:   public void send_multiple_requests_deferred(Request[] requests)
1752:   {
1753:     asynchron.send_multiple_requests_deferred(requests);
1754:   }
1755: 
1756:   /**
1757:    * Send multiple prepared requests one way, do not caring about the answer.
1758:    * The messages, containing requests, will be marked, indicating that the
1759:    * sender is not expecting to get a reply.
1760:    *
1761:    * @param requests the prepared array of requests.
1762:    *
1763:    * @see Request#send_oneway()
1764:    */
1765:   public void send_multiple_requests_oneway(Request[] requests)
1766:   {
1767:     asynchron.send_multiple_requests_oneway(requests);
1768:   }
1769: 
1770:   /**
1771:    * Set the flag, forcing all server threads to terminate.
1772:    */
1773:   protected void finalize() throws java.lang.Throwable
1774:   {
1775:     running = false;
1776:     super.finalize();
1777:   }