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 */ portServer(int _port)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 */ run()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 */ tick()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 */ close_now()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 */ finalize()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 */ sharedPortServer(int _port)232 sharedPortServer(int _port) 233 { 234 super(_port); 235 } 236 237 /** 238 * Perform a single serving step. 239 * 240 * @throws java.lang.Exception 241 */ tick()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 */ OrbFunctional()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 */ setMaxVersion(Version max_supported)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 */ getMaxVersion()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 */ getFreePort()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 */ setPort(int a_Port)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 */ connect(org.omg.CORBA.Object object)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 */ connect(org.omg.CORBA.Object object, byte[] key)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 */ connect_1_thread(org.omg.CORBA.Object object, byte[] key, java.lang.Object identity )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 */ startService(IOR ior)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 */ destroy()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 */ disconnect(org.omg.CORBA.Object object)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 */ identityDestroyed(java.lang.Object identity)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 */ find_local_object(IOR ior)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 */ list_initial_services()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 */ object_to_string(org.omg.CORBA.Object forObject)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 */ getLocalIor(org.omg.CORBA.Object forObject)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 */ resolve_initial_references(String name)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 */ run()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 */ ensureRunning()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 */ shutdown(boolean wait_for_completion)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 */ string_to_object(String an_ior)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 */ ior_to_object(IOR ior)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 */ getDefaultNameService()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 */ find_connected_object(byte[] key, int port)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 */ set_parameters(Applet app, Properties props)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 */ set_parameters(String[] para, Properties props)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 */ createIOR(Connected_objects.cObject ref)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 */ prepareObject(org.omg.CORBA.Object object, IOR ior)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 */ respond_to_client(OutputStream net_out, MessageHeader msh_request, RequestHeader rh_request, ResponseHandlerImpl handler, SystemException sysEx )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 */ forward_request(OutputStream net_out, MessageHeader msh_request, RequestHeader rh_request, gnuForwardRequest info )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 */ serve(final portServer p, ServerSocket serverSocket)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 */ serveStep(Socket service, boolean no_resources)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 */ useProperties(Properties props)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 */ get_next_response()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 */ poll_next_response()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 */ send_multiple_requests_deferred(Request[] requests)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 */ send_multiple_requests_oneway(Request[] requests)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 */ finalize()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 */ countConnectedObjects()1790 public int countConnectedObjects() 1791 { 1792 return connected_objects.size(); 1793 } 1794 } 1795