libjava/ChangeLog:
[official-gcc.git] / libjava / classpath / gnu / CORBA / OrbFunctional.java
blob25344cb2ec0226b99c3ab8e419383de19e659289
1 /* OrbFunctional.java --
2 Copyright (C) 2005 Free Software Foundation, Inc.
4 This file is part of GNU Classpath.
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.
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.
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.
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.
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. */
39 package gnu.CORBA;
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;
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;
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;
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}.
98 * @author Audrius Meskauskas (AudriusA@Bioinformatics.org)
100 public class OrbFunctional extends OrbRestricted
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.
107 protected class portServer
108 extends Thread
111 * The number of the currently running parallel threads.
113 int running_threads;
116 * The port on that this portServer is listening for requests.
118 int s_port;
121 * The server socket of this portServer.
123 ServerSocket service;
126 * True if the serving node must shutdown due call of the close_now().
128 boolean terminated;
131 * Create a new portServer, serving on specific port.
133 portServer(int _port)
135 s_port = _port;
136 setDaemon(true);
139 service = socketFactory.createServerSocket(s_port);
141 catch (IOException ex)
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;
152 * Enter the serving loop (get request/process it). All portServer normally
153 * terminate thy threads when the OrbFunctional.running is set to false.
155 public void run()
157 while (running)
161 tick();
163 catch (SocketException ex)
165 // May be thrown when the service is closed by
166 // the close_now().
167 if (terminated)
168 return;
170 catch (Exception iex)
172 // Wait. Do not terminate the
173 // service due potentially transient error.
176 Thread.sleep(TWAIT_SERVER_ERROR_PAUSE);
178 catch (InterruptedException ex)
186 * Perform a single serving step.
188 * @throws java.lang.Exception
190 void tick()
191 throws Exception
193 serve(this, service);
197 * Forcibly close the server socket and mark this port as free.
199 public void close_now()
203 terminated = true;
204 service.close();
206 catch (Exception ex)
208 // This may happen if the service has not been opened or
209 // cannot be closed. Return without action.
214 * If the thread is no longer in use, close the socket (if opened).
216 protected void finalize()
218 close_now();
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.
227 protected class sharedPortServer extends portServer
230 * Create a new portServer, serving on specific port.
232 sharedPortServer(int _port)
234 super(_port);
238 * Perform a single serving step.
240 * @throws java.lang.Exception
242 void tick() throws Exception
244 Socket request = service.accept();
245 serveStep(request, false);
250 * The default value where the first instance of this ORB will start looking
251 * for a free port.
253 public static int DEFAULT_INITIAL_PORT = 1126;
256 * When trying to open the socket on a random port, start of the interval to
257 * try.
259 public static int RANDOM_PORT_FROM = 1024;
262 * When trying to open the socket on a random port, end of the interval to
263 * try.
265 public static int RANDOM_PORT_TO = 4024;
268 * The number of attempts to try when opening random port.
270 public static int RANDOM_PORT_ATTEMPTS = 64;
273 * The property of port, on that this ORB is listening for requests from
274 * clients. This class supports one port per ORB only.
276 public static final String LISTEN_ON = "gnu.classpath.CORBA.ListenOn";
279 * The property, defining the IOR of the intial reference to resolve.
281 public static final String REFERENCE = "org.omg.CORBA.ORBInitRef";
284 * The property, defining the port on that the default name service is
285 * running.
287 public static final String NS_PORT = "org.omg.CORBA.ORBInitialPort";
290 * The property, defining the host on that the default name service is
291 * running.
293 public static final String NS_HOST = "org.omg.CORBA.ORBInitialHost";
296 * The string, defining the naming service initial reference.
298 public static final String NAME_SERVICE = "NameService";
301 * Defines the ORB ID that is accessible by IOR interceptors.
303 public static final String ORB_ID = "org.omg.CORBA.ORBid";
307 * Defines the SERVER ID that is accessible by IOR interceptors.
309 public static final String SERVER_ID = "org.omg.CORBA.ServerId";
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.
317 public static String START_READING_MESSAGE =
318 "gnu.classpath.CORBA.TOUT_START_READING_MESSAGE";
321 * If the client has started to send the request message, the socket time out
322 * changes to the specified value.
324 public static String WHILE_READING =
325 "gnu.classpath.CORBA.TOUT_WHILE_READING";
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.
332 public static String AFTER_RECEIVING =
333 "gnu.classpath.CORBA.TOUT_AFTER_RECEIVING";
336 * The server waits for this duration after the potentially transient error
337 * during its servicing cycle.
339 public static String SERVER_ERROR_PAUSE =
340 "gnu.classpath.CORBA.SERVER_ERROR_PAUSE";
343 * The address of the local host.
345 public final String LOCAL_HOST;
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.
353 public int TOUT_START_READING_MESSAGE = 20 * 1000;
355 // (Here and below, we use * to make the meaning of the constant clearler).
358 * If the client has started to send the request message, the socket time out
359 * changes to the specified value.
361 public int TOUT_WHILE_READING = 2 * 60 * 1000;
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.
368 public int TOUT_AFTER_RECEIVING = 40 * 60 * 1000;
371 * The server waits for this duration after the potentially transient error
372 * during its servicing cycle.
374 public int TWAIT_SERVER_ERROR_PAUSE = 5000;
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.
383 public static int TANDEM_REQUESTS = 7000;
386 * The Id of this ORB.
388 public String orb_id = "orb_"+hashCode();
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.
394 public static String server_id = "server_"+OrbFunctional.class.hashCode();
397 * The map of the already conncted objects.
399 protected final Connected_objects connected_objects =
400 new Connected_objects();
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.
406 protected Version max_version;
409 * Setting this value to false causes the ORB to shutdown after the latest
410 * serving operation is complete.
412 protected boolean running;
415 * The map of the initial references.
417 protected Map initial_references = new TreeMap();
420 * The currently active portServers.
422 protected ArrayList portServers = new ArrayList();
425 * The host, on that the name service is expected to be running.
427 private String ns_host;
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.
437 private static int Port = DEFAULT_INITIAL_PORT;
440 * The port, on that the name service is expected to be running.
442 private int ns_port = 900;
445 * The name parser.
447 NameParser nameParser = new NameParser();
450 * The instance, stored in this field, handles the asynchronous dynamic
451 * invocations.
453 protected Asynchron asynchron = new Asynchron();
456 * The list of the freed ports. The ORB reuses ports, when possible.
458 protected LinkedList freed_ports = new LinkedList();
461 * Maps a single-threaded POAs to they sharedPortServants.
463 protected Hashtable identities = new Hashtable();
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.
470 private int MAX_RUNNING_THREADS = 256;
473 * The producer of the client and server sockets for this ORB.
475 public SocketFactory socketFactory = DefaultSocketFactory.Singleton;
478 * Create the instance of the Functional ORB.
480 public OrbFunctional()
484 LOCAL_HOST = ns_host = InetAddress.getLocalHost().getHostAddress();
485 initial_references.put("CodecFactory", new gnuCodecFactory(this));
487 catch (UnknownHostException ex)
489 BAD_OPERATION bad =
490 new BAD_OPERATION("Unable to open the server socket.");
491 bad.initCause(ex);
492 throw bad;
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.
502 public void setMaxVersion(Version max_supported)
504 max_version = max_supported;
508 * Get the maximal supported GIOP version or null if the version is not
509 * checked.
511 public Version getMaxVersion()
513 return max_version;
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.
520 * @return the currently available free port.
522 * @throws NO_RESOURCES if the server socked cannot be opened on the local
523 * host.
525 public int getFreePort()
526 throws BAD_OPERATION
528 ServerSocket s;
529 int a_port;
533 // If there are some previously freed ports, use them first.
534 if (!freed_ports.isEmpty())
536 Integer free = (Integer) freed_ports.getLast();
537 freed_ports.removeLast();
538 s = socketFactory.createServerSocket(free.intValue());
539 s.close();
540 return free.intValue();
543 catch (Exception ex)
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.
550 for (a_port = Port; a_port < Port + 20; a_port++)
554 s = socketFactory.createServerSocket(a_port);
555 s.close();
556 Port = a_port + 1;
557 return a_port;
559 catch (IOException ex)
561 // Repeat the loop if this exception has been thrown.
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++)
573 a_port = RANDOM_PORT_FROM + rand.nextInt(range);
574 s = socketFactory.createServerSocket(a_port);
575 s.close();
576 return a_port;
578 catch (IOException ex)
580 // Repeat the loop if this exception has been thrown.
581 ioex = ex;
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;
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.
599 * @param a_Port a port, on that the server is listening for requests.
601 public static void setPort(int a_Port)
603 Port = a_Port;
607 * Connect the given CORBA object to this ORB. After the object is connected,
608 * it starts receiving remote invocations via this ORB.
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.
615 * @param object the object, must implement the {@link InvokeHandler})
616 * interface.
618 * @throws BAD_PARAM if the object does not implement the
619 * {@link InvokeHandler}).
621 public void connect(org.omg.CORBA.Object object)
623 int a_port = getFreePort();
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);
633 * Connect the given CORBA object to this ORB, explicitly specifying the
634 * object key.
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.
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.
646 * @throws BAD_PARAM if the object does not implement the
647 * {@link InvokeHandler}).
649 public void connect(org.omg.CORBA.Object object, byte[] key)
651 int a_port = getFreePort();
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);
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.
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.
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.
680 * @throws BAD_PARAM if the object does not implement the
681 * {@link InvokeHandler}).
683 public void connect_1_thread(org.omg.CORBA.Object object, byte[] key,
684 java.lang.Object identity
687 sharedPortServer shared = (sharedPortServer) identities.get(identity);
688 if (shared == null)
690 int a_port = getFreePort();
691 shared = new sharedPortServer(a_port);
692 identities.put(identity, shared);
693 if (running)
695 portServers.add(shared);
696 shared.start();
700 Connected_objects.cObject ref =
701 connected_objects.add(key, object, shared.s_port, identity);
702 IOR ior = createIOR(ref);
703 prepareObject(object, ior);
707 * Start the service on the given port of this IOR.
709 * @param ior the ior (only Internet.port is used).
711 public void startService(IOR ior)
713 portServer p = new portServer(ior.Internet.port);
714 portServers.add(p);
715 p.start();
719 * Destroy this server, releasing the occupied resources.
721 public void destroy()
723 portServer p;
724 for (int i = 0; i < portServers.size(); i++)
726 p = (portServer) portServers.get(i);
727 p.close_now();
729 super.destroy();
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.
739 * @param object the object to disconnect.
741 public void disconnect(org.omg.CORBA.Object object)
743 Connected_objects.cObject rmKey = null;
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)
749 Delegate delegate = ((ObjectImpl) object)._get_delegate();
750 if (delegate instanceof SimpleDelegate)
752 byte[] key = ((SimpleDelegate) delegate).getIor().key;
753 rmKey = connected_objects.get(key);
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)
763 // Find and stop the corresponding portServer.
764 portServer p;
765 StopService:
766 for (int i = 0; i < portServers.size(); i++)
768 p = (portServer) portServers.get(i);
769 if (p.s_port == rmKey.port && !(p instanceof sharedPortServer))
771 p.close_now();
772 freed_ports.addFirst(new Integer(rmKey.port));
773 break StopService;
775 connected_objects.remove(rmKey.key);
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.
786 * @param identity the identity that has been destroyed.
788 public void identityDestroyed(java.lang.Object identity)
790 if (identity == null)
791 return;
793 sharedPortServer ise = (sharedPortServer) identities.get(identity);
794 if (ise != null)
796 synchronized (connected_objects)
798 ise.close_now();
799 identities.remove(identity);
801 Connected_objects.cObject obj;
802 Map.Entry m;
803 Iterator iter = connected_objects.entrySet().iterator();
804 while (iter.hasNext())
806 m = (Map.Entry) iter.next();
807 obj = (Connected_objects.cObject) m.getValue();
808 if (obj.identity == identity)
809 iter.remove();
816 * Find the local object, connected to this ORB.
818 * @param ior the ior of the potentially local object.
820 * @return the local object, represented by the given IOR, or null if this is
821 * not a local connected object.
823 public org.omg.CORBA.Object find_local_object(IOR ior)
825 // Must be the same host.
826 if (!ior.Internet.host.equals(LOCAL_HOST))
827 return null;
829 return find_connected_object(ior.key, ior.Internet.port);
833 * List the initially available CORBA objects (services).
835 * @return a list of services.
837 * @see resolve_initial_references(String)
839 public String[] list_initial_services()
841 String[] refs = new String[ initial_references.size() ];
842 int p = 0;
844 Iterator iter = initial_references.keySet().iterator();
845 while (iter.hasNext())
847 refs [ p++ ] = (String) iter.next();
849 return refs;
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.
858 * @param forObject CORBA object
859 * @return the object IOR representation.
861 * @throws BAD_PARAM if the object has not been previously connected to this
862 * ORB.
864 * @throws BAD_OPERATION in the unlikely case if the local host address cannot
865 * be resolved.
867 * @see string_to_object(String)
869 public String object_to_string(org.omg.CORBA.Object forObject)
871 // Handle the case when the object is known, but not local.
872 if (forObject instanceof ObjectImpl)
874 Delegate delegate = ((ObjectImpl) forObject)._get_delegate();
875 if (delegate instanceof SimpleDelegate)
876 return ((SimpleDelegate) delegate).getIor().toStringifiedReference();
879 // Handle the case when the object is local.
880 Connected_objects.cObject rec = connected_objects.getKey(forObject);
882 if (rec == null)
883 throw new BAD_PARAM("The object " + forObject +
884 " has not been previously connected to this ORB"
887 IOR ior = createIOR(rec);
889 return ior.toStringifiedReference();
893 * Get the local IOR for the given object, null if the object is not local.
895 public IOR getLocalIor(org.omg.CORBA.Object forObject)
897 Connected_objects.cObject rec = connected_objects.getKey(forObject);
898 if (rec == null)
899 return null;
900 else
901 return createIOR(rec);
905 * Find and return the easily accessible CORBA object, addressed by name.
907 * @param name the object name.
908 * @return the object
910 * @throws org.omg.CORBA.ORBPackage.InvalidName if the given name is not
911 * associated with the known object.
913 public org.omg.CORBA.Object resolve_initial_references(String name)
914 throws InvalidName
916 org.omg.CORBA.Object object = null;
919 object = (org.omg.CORBA.Object) initial_references.get(name);
920 if (object == null && name.equals(NAME_SERVICE))
922 object = getDefaultNameService();
923 if (object != null)
924 initial_references.put(NAME_SERVICE, object);
927 catch (Exception ex)
929 InvalidName err = new InvalidName(name);
930 err.initCause(ex);
931 throw err;
933 if (object != null)
934 return object;
935 else
936 throw new InvalidName("Not found: '" + name + "'");
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)}.
944 public void run()
946 CollocatedOrbs.registerOrb(this);
949 running = true;
951 // Instantiate the port server for each socket.
952 Iterator iter = connected_objects.entrySet().iterator();
953 Map.Entry m;
954 Connected_objects.cObject obj;
956 while (iter.hasNext())
958 m = (Map.Entry) iter.next();
959 obj = (Connected_objects.cObject) m.getValue();
961 portServer subserver;
963 if (obj.identity == null)
965 subserver = new portServer(obj.port);
966 portServers.add(subserver);
968 else
969 subserver = (portServer) identities.get(obj.identity);
971 if (! subserver.isAlive())
973 // Reuse the current thread for the last portServer.
974 if (! iter.hasNext())
976 // Discard the iterator, eliminating lock checks.
977 iter = null;
978 subserver.run();
979 return;
981 else
982 subserver.start();
986 finally
988 CollocatedOrbs.unregisterOrb(this);
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.
998 public void ensureRunning()
1000 final OrbFunctional THIS = this;
1002 if (!running)
1004 Thread t = new Thread()
1006 public void run()
1008 THIS.run();
1011 t.setDaemon(true);
1012 t.start();
1017 * Shutdown the ORB server.
1019 * @param wait_for_completion if true, the current thread is suspended until
1020 * the shutdown process is complete.
1022 public void shutdown(boolean wait_for_completion)
1024 super.shutdown(wait_for_completion);
1025 running = false;
1027 if (!wait_for_completion)
1029 for (int i = 0; i < portServers.size(); i++)
1031 portServer p = (portServer) portServers.get(i);
1032 p.close_now();
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.
1043 * @param an_ior the object IOR representation string.
1045 * @return the found CORBA object.
1046 * @see object_to_string(org.omg.CORBA.Object)
1048 public org.omg.CORBA.Object string_to_object(String an_ior)
1050 return nameParser.corbaloc(an_ior, this);
1054 * Convert ior reference to CORBA object.
1056 public org.omg.CORBA.Object ior_to_object(IOR ior)
1058 org.omg.CORBA.Object object = find_local_object(ior);
1059 if (object == null)
1061 // Check maybe the local object on another ORB, but same VM.
1062 object = CollocatedOrbs.searchLocalObject(ior);
1063 if (object == null)
1065 // Surely remote object.
1066 ObjectImpl impl = StubLocator.search(this, ior);
1069 if (impl._get_delegate() == null)
1070 impl._set_delegate(new IorDelegate(this, ior));
1072 catch (BAD_OPERATION ex)
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));
1079 object = impl;
1082 return object;
1086 * Get the default naming service for the case when there no NameService
1087 * entries.
1089 protected org.omg.CORBA.Object getDefaultNameService()
1091 if (initial_references.containsKey(NAME_SERVICE))
1092 return (org.omg.CORBA.Object) initial_references.get(NAME_SERVICE);
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();
1100 IorObject iorc = new IorObject(this, ior);
1101 NamingContextExt namer = NamingContextExtHelper.narrow(iorc);
1102 initial_references.put(NAME_SERVICE, namer);
1103 return namer;
1107 * Find and return the object, that must be previously connected to this ORB.
1108 * Return null if no such object is available.
1110 * @param key the object key.
1111 * @param port the port where the object is connected.
1113 * @return the connected object, null if none.
1115 protected org.omg.CORBA.Object find_connected_object(byte[] key, int port)
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;
1127 * Set the ORB parameters. This method is normally called from
1128 * {@link #init(Applet, Properties)}.
1130 * @param app the current applet.
1132 * @param props application specific properties, passed as the second
1133 * parameter in {@link #init(Applet, Properties)}. Can be <code>null</code>.
1135 protected void set_parameters(Applet app, Properties props)
1137 useProperties(props);
1139 String[][] para = app.getParameterInfo();
1140 if (para != null)
1142 for (int i = 0; i < para.length; i++)
1144 if (para[i][0].equals(LISTEN_ON))
1145 Port = Integer.parseInt(para[i][1]);
1146 if (para[i][0].equals(REFERENCE))
1148 StringTokenizer st = new StringTokenizer(para[i][1], "=");
1149 initial_references.put(st.nextToken(),
1150 string_to_object(st.nextToken()));
1153 if (para[i][0].equals(ORB_ID))
1154 orb_id = para[i][1];
1156 if (para[i][0].equals(SERVER_ID))
1157 server_id = para[i][1];
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]);
1169 if (para[i][0].equals(NS_PORT))
1170 ns_port = Integer.parseInt(para[i][1]);
1172 catch (NumberFormatException ex)
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;
1185 * Set the ORB parameters. This method is normally called from
1186 * {@link #init(String[], Properties)}.
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.
1192 * @param props application specific properties that were passed as a second
1193 * parameter in {@link init(String[], Properties)}). Can be <code>null</code>.
1195 protected void set_parameters(String[] para, Properties props)
1197 if ((para != null) && para.length > 1)
1199 for (int i = 0; i < para.length - 1; i++)
1201 if (para[i].endsWith("ListenOn"))
1202 Port = Integer.parseInt(para[i + 1]);
1203 if (para[i].endsWith("ORBInitRef"))
1205 StringTokenizer st = new StringTokenizer(para[i + 1], "=");
1206 initial_references.put(st.nextToken(),
1207 string_to_object(st.nextToken()));
1210 if (para[i].endsWith("ORBInitialHost"))
1211 ns_host = para[i + 1];
1213 if (para[i].endsWith("ServerId"))
1214 server_id = para[i++];
1215 else if (para[i].endsWith("ORBid"))
1216 orb_id = para[i++];
1220 if (para[i].endsWith("ORBInitialPort"))
1221 ns_port = Integer.parseInt(para[i + 1]);
1223 catch (NumberFormatException ex)
1225 throw new BAD_PARAM("Invalid " + para[i]
1226 + "parameter, unable to parse '"
1227 + props.getProperty(para[i + 1]) + "'");
1232 useProperties(props);
1236 * Create IOR for the given object references.
1238 protected IOR createIOR(Connected_objects.cObject ref)
1239 throws BAD_OPERATION
1241 IOR ior = new IOR();
1242 ior.key = ref.key;
1243 ior.Internet.port = ref.port;
1245 if (ref.object instanceof ObjectImpl)
1247 ObjectImpl imp = (ObjectImpl) ref.object;
1248 if (imp._ids().length > 0)
1249 ior.Id = imp._ids() [ 0 ];
1251 if (ior.Id == null)
1252 ior.Id = ref.object.getClass().getName();
1254 ior.Internet.host = CollocatedOrbs.localHost;
1255 ior.Internet.port = ref.port;
1257 return ior;
1261 * Prepare object for connecting it to this ORB.
1263 * @param object the object being connected.
1265 * @throws BAD_PARAM if the object does not implement the
1266 * {@link InvokeHandler}).
1268 protected void prepareObject(org.omg.CORBA.Object object, IOR ior)
1269 throws BAD_PARAM
1272 * if (!(object instanceof InvokeHandler)) throw new
1273 * BAD_PARAM(object.getClass().getName() + " does not implement
1274 * InvokeHandler. " );
1277 // If no delegate is set, set the default delegate.
1278 if (object instanceof ObjectImpl)
1280 ObjectImpl impl = (ObjectImpl) object;
1283 if (impl._get_delegate() == null)
1284 impl._set_delegate(new SimpleDelegate(this, ior));
1286 catch (BAD_OPERATION ex)
1288 // Some colaborants may throw this exception.
1289 impl._set_delegate(new SimpleDelegate(this, ior));
1295 * Write the response message.
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.
1305 * @throws IOException
1307 private void respond_to_client(OutputStream net_out,
1308 MessageHeader msh_request, RequestHeader rh_request,
1309 ResponseHandlerImpl handler, SystemException sysEx
1310 ) throws IOException
1312 // Set the reply header properties.
1313 ReplyHeader reply = handler.reply_header;
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;
1323 BufferedCdrOutput out =
1324 new BufferedCdrOutput(50 + handler.getBuffer().buffer.size());
1325 out.setOrb(this);
1327 out.setOffset(msh_request.getHeaderSize());
1329 reply.write(out);
1331 if (msh_request.version.since_inclusive(1, 2))
1333 out.align(8);
1335 // Write the reply data from the handler. The handler data already
1336 // include the necessary heading zeroes for alignment.
1338 handler.getBuffer().buffer.writeTo(out);
1340 MessageHeader msh_reply = new MessageHeader();
1342 msh_reply.version = msh_request.version;
1343 msh_reply.message_type = MessageHeader.REPLY;
1344 msh_reply.message_size = out.buffer.size();
1346 // Write the reply.
1347 msh_reply.write(net_out);
1348 out.buffer.writeTo(net_out);
1349 net_out.flush();
1353 * Forward request to another target, as indicated by the passed exception.
1355 private void forward_request(OutputStream net_out,
1356 MessageHeader msh_request, RequestHeader rh_request, gnuForwardRequest info
1357 ) throws IOException
1359 MessageHeader msh_forward = new MessageHeader();
1360 msh_forward.version = msh_request.version;
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;
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());
1372 rh_forward.write(out);
1374 if (msh_forward.version.since_inclusive(1, 2))
1375 out.align(8);
1376 out.write_Object(info.forward_reference);
1378 msh_forward.message_size = out.buffer.size();
1380 // Write the forwarding instruction.
1381 msh_forward.write(net_out);
1382 out.buffer.writeTo(net_out);
1383 net_out.flush();
1387 * Contains a single servicing task.
1389 * Normally, each task matches a single remote invocation. However under
1390 * frequent tandem submissions the same task may span over several
1391 * invocations.
1393 * @param serverSocket the ORB server socket.
1395 * @throws MARSHAL
1396 * @throws IOException
1398 void serve(final portServer p, ServerSocket serverSocket)
1399 throws MARSHAL, IOException
1401 final Socket service;
1402 service = serverSocket.accept();
1404 // Tell the server there are no more resources.
1405 if (p.running_threads >= MAX_RUNNING_THREADS)
1407 serveStep(service, true);
1408 return;
1411 new Thread()
1413 public void run()
1417 synchronized (p)
1419 p.running_threads++;
1421 serveStep(service, false);
1423 finally
1425 synchronized (p)
1427 p.running_threads--;
1431 }.start();
1435 * A single servicing step, when the client socket is alrady open.
1437 * Normally, each task matches a single remote invocation. However under
1438 * frequent tandem submissions the same task may span over several
1439 * invocations.
1441 * @param service the opened client socket.
1442 * @param no_resources if true, the "NO RESOURCES" exception is thrown to the
1443 * client.
1445 void serveStep(Socket service, boolean no_resources)
1449 Serving: while (true)
1451 InputStream in = service.getInputStream();
1452 service.setSoTimeout(TOUT_START_READING_MESSAGE);
1454 MessageHeader msh_request = new MessageHeader();
1458 msh_request.read(in);
1460 catch (MARSHAL ex)
1462 // This exception may be thrown due closing the connection.
1463 return;
1466 if (max_version != null)
1468 if (!msh_request.version.until_inclusive(max_version.major,
1469 max_version.minor))
1471 OutputStream out = service.getOutputStream();
1472 new ErrorMessage(max_version).write(out);
1473 return;
1477 byte[] r = msh_request.readMessage(in, service, TOUT_WHILE_READING,
1478 TOUT_AFTER_RECEIVING);
1480 if (msh_request.message_type == MessageHeader.REQUEST)
1482 RequestHeader rh_request;
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());
1490 rh_request = msh_request.create_request_header();
1492 // Read header and auto set the charset.
1493 rh_request.read(cin);
1495 // in 1.2 and higher, align the current position at
1496 // 8 octet boundary.
1497 if (msh_request.version.since_inclusive(1, 2))
1499 cin.align(8);
1501 // find the target object.
1504 InvokeHandler target = (InvokeHandler) find_connected_object(
1505 rh_request.object_key, -1);
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();
1512 // TODO log errors about not existing objects and methods.
1513 ResponseHandlerImpl handler = new ResponseHandlerImpl(
1514 this, msh_request, rh_reply, rh_request);
1516 SystemException sysEx = null;
1520 if (no_resources)
1522 NO_RESOURCES no = new NO_RESOURCES("Too many parallel calls");
1523 no.minor = Minor.Threads;
1524 throw no;
1526 if (target == null)
1527 throw new OBJECT_NOT_EXIST();
1528 target._invoke(rh_request.operation, cin, handler);
1530 catch (gnuForwardRequest forwarded)
1532 OutputStream sou = service.getOutputStream();
1533 forward_request(sou, msh_request, rh_request, forwarded);
1534 if (service != null && !service.isClosed())
1536 // Wait for the subsequent invocations on the
1537 // same socket for the TANDEM_REQUEST duration.
1538 service.setSoTimeout(TANDEM_REQUESTS);
1539 continue Serving;
1542 catch (UnknownException uex)
1544 sysEx = new UNKNOWN("Unknown", 2,
1545 CompletionStatus.COMPLETED_MAYBE);
1546 sysEx.initCause(uex.originalEx);
1548 org.omg.CORBA.portable.OutputStream ech = handler.createExceptionReply();
1550 rh_reply.service_context = UnknownExceptionCtxHandler.addExceptionContext(
1551 rh_reply.service_context, uex.originalEx, ech);
1553 ObjectCreator.writeSystemException(ech, sysEx);
1555 catch (SystemException ex)
1557 sysEx = ex;
1559 org.omg.CORBA.portable.OutputStream ech = handler.createExceptionReply();
1561 rh_reply.service_context = UnknownExceptionCtxHandler.addExceptionContext(
1562 rh_reply.service_context, ex, ech);
1564 ObjectCreator.writeSystemException(ech, ex);
1566 catch (Exception except)
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();
1573 sysEx = new UNKNOWN("Unknown", 2,
1574 CompletionStatus.COMPLETED_MAYBE);
1575 sysEx.initCause(except);
1577 org.omg.CORBA.portable.OutputStream ech = handler.createExceptionReply();
1579 rh_reply.service_context = UnknownExceptionCtxHandler.addExceptionContext(
1580 rh_reply.service_context, except, ech);
1582 ObjectCreator.writeSystemException(ech, sysEx);
1585 // Write the response.
1586 if (rh_request.isResponseExpected())
1588 OutputStream sou = service.getOutputStream();
1589 respond_to_client(sou, msh_request, rh_request, handler,
1590 sysEx);
1593 else if (msh_request.message_type == MessageHeader.CLOSE_CONNECTION
1594 || msh_request.message_type == MessageHeader.MESSAGE_ERROR)
1596 CloseMessage.close(service.getOutputStream());
1597 service.close();
1598 return;
1601 if (service != null && !service.isClosed())
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;
1610 catch (SocketException ex)
1612 // OK.
1613 return;
1615 catch (IOException ioex)
1617 // Network error, probably transient.
1618 // TODO log it.
1619 return;
1621 finally
1623 try
1625 if (service!=null && !service.isClosed())
1626 service.close();
1628 catch (IOException ioex)
1630 // OK.
1636 * Set the ORB parameters from the properties that were accumulated
1637 * from several locations.
1639 protected void useProperties(Properties props)
1641 if (props != null)
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);
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));
1664 catch (NumberFormatException ex)
1666 throw new BAD_PARAM("Invalid " + NS_PORT +
1667 "property, unable to parse '" + props.getProperty(NS_PORT) +
1672 if (props.containsKey(SocketFactory.PROPERTY))
1674 String factory = null;
1677 factory = props.getProperty(SocketFactory.PROPERTY);
1678 if (factory!=null)
1679 socketFactory = (SocketFactory)
1680 ObjectCreator.forName(factory).newInstance();
1682 catch (Exception ex)
1684 BAD_PARAM p = new BAD_PARAM("Bad socket factory "+factory);
1685 p.initCause(ex);
1686 throw p;
1690 if (props.containsKey(ORB_ID))
1691 orb_id = props.getProperty(ORB_ID);
1693 if (props.containsKey(SERVER_ID))
1694 server_id = props.getProperty(SERVER_ID);
1696 Enumeration en = props.elements();
1697 while (en.hasMoreElements())
1699 String item = (String) en.nextElement();
1700 if (item.equals(REFERENCE))
1701 initial_references.put(item,
1702 string_to_object(props.getProperty(item))
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.
1715 * The returned response is removed from the list of the currently submitted
1716 * responses and is never returned again.
1718 * @return the previously sent request that now contains the received
1719 * response.
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.
1726 public Request get_next_response() throws org.omg.CORBA.WrongTransaction
1728 return asynchron.get_next_response();
1732 * Find if any of the requests that have been previously sent with
1733 * {@link #send_multiple_requests_deferred}, have a response yet.
1735 * @return true if there is at least one response to the previously sent
1736 * request, false otherwise.
1738 public boolean poll_next_response()
1740 return asynchron.poll_next_response();
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.
1751 * @param requests the prepared array of requests.
1753 * @see #poll_next_response()
1754 * @see #get_next_response()
1755 * @see Request#send_deferred()
1757 public void send_multiple_requests_deferred(Request[] requests)
1759 asynchron.send_multiple_requests_deferred(requests);
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.
1767 * @param requests the prepared array of requests.
1769 * @see Request#send_oneway()
1771 public void send_multiple_requests_oneway(Request[] requests)
1773 asynchron.send_multiple_requests_oneway(requests);
1777 * Set the flag, forcing all server threads to terminate.
1779 protected void finalize() throws java.lang.Throwable
1781 running = false;
1782 super.finalize();
1786 * Get the number of objects that are connected to this ORB.
1788 * @return the number of objects, connected to this ORB.
1790 public int countConnectedObjects()
1792 return connected_objects.size();