| /* OrbFunctional.java -- |
| Copyright (C) 2005 Free Software Foundation, Inc. |
| |
| This file is part of GNU Classpath. |
| |
| GNU Classpath is free software; you can redistribute it and/or modify |
| it under the terms of the GNU General Public License as published by |
| the Free Software Foundation; either version 2, or (at your option) |
| any later version. |
| |
| GNU Classpath is distributed in the hope that it will be useful, but |
| WITHOUT ANY WARRANTY; without even the implied warranty of |
| MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU |
| General Public License for more details. |
| |
| You should have received a copy of the GNU General Public License |
| along with GNU Classpath; see the file COPYING. If not, write to the |
| Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA |
| 02110-1301 USA. |
| |
| Linking this library statically or dynamically with other modules is |
| making a combined work based on this library. Thus, the terms and |
| conditions of the GNU General Public License cover the whole |
| combination. |
| |
| As a special exception, the copyright holders of this library give you |
| permission to link this library with independent modules to produce an |
| executable, regardless of the license terms of these independent |
| modules, and to copy and distribute the resulting executable under |
| terms of your choice, provided that you also meet, for each linked |
| independent module, the terms and conditions of the license of that |
| module. An independent module is a module which is not derived from |
| or based on this library. If you modify this library, you may extend |
| this exception to your version of the library, but you are not |
| obligated to do so. If you do not wish to do so, delete this |
| exception statement from your version. */ |
| |
| |
| package gnu.CORBA; |
| |
| import gnu.CORBA.CDR.UnknownExceptionCtxHandler; |
| import gnu.CORBA.CDR.BufferredCdrInput; |
| import gnu.CORBA.CDR.BufferedCdrOutput; |
| import gnu.CORBA.GIOP.CloseMessage; |
| import gnu.CORBA.GIOP.ErrorMessage; |
| import gnu.CORBA.GIOP.MessageHeader; |
| import gnu.CORBA.GIOP.ReplyHeader; |
| import gnu.CORBA.GIOP.RequestHeader; |
| import gnu.CORBA.NamingService.NameParser; |
| import gnu.CORBA.NamingService.NamingServiceTransient; |
| import gnu.CORBA.Poa.gnuForwardRequest; |
| import gnu.CORBA.interfaces.SocketFactory; |
| |
| import org.omg.CORBA.BAD_OPERATION; |
| import org.omg.CORBA.BAD_PARAM; |
| import org.omg.CORBA.CompletionStatus; |
| import org.omg.CORBA.MARSHAL; |
| import org.omg.CORBA.NO_RESOURCES; |
| import org.omg.CORBA.OBJECT_NOT_EXIST; |
| import org.omg.CORBA.Request; |
| import org.omg.CORBA.SystemException; |
| import org.omg.CORBA.UNKNOWN; |
| import org.omg.CORBA.WrongTransaction; |
| import org.omg.CORBA.ORBPackage.InvalidName; |
| import org.omg.CORBA.portable.Delegate; |
| import org.omg.CORBA.portable.InvokeHandler; |
| import org.omg.CORBA.portable.ObjectImpl; |
| import org.omg.CORBA.portable.UnknownException; |
| import org.omg.CosNaming.NamingContextExt; |
| import org.omg.CosNaming.NamingContextExtHelper; |
| |
| import java.applet.Applet; |
| import java.io.IOException; |
| import java.io.InputStream; |
| import java.io.OutputStream; |
| import java.net.InetAddress; |
| import java.net.ServerSocket; |
| import java.net.Socket; |
| import java.net.SocketException; |
| import java.net.UnknownHostException; |
| import java.util.ArrayList; |
| import java.util.Enumeration; |
| import java.util.Hashtable; |
| import java.util.Iterator; |
| import java.util.LinkedList; |
| import java.util.Map; |
| import java.util.Properties; |
| import java.util.Random; |
| import java.util.StringTokenizer; |
| import java.util.TreeMap; |
| |
| /** |
| * The ORB implementation, capable to handle remote invocations on the |
| * registered object. This class implements all features, required till the jdk |
| * 1.3 inclusive, but does not support the POA that appears since 1.4. The POA |
| * is supported by {@link gnu.CORBA.Poa.ORB_1_4}. |
| * |
| * @author Audrius Meskauskas (AudriusA@Bioinformatics.org) |
| */ |
| public class OrbFunctional extends OrbRestricted |
| { |
| /** |
| * A server, responsible for listening on requests on some local port. The ORB |
| * may listen on multiple ports and process the requests in separate threads. |
| * Normally the server takes one port per object being served. |
| */ |
| protected class portServer |
| extends Thread |
| { |
| /** |
| * The number of the currently running parallel threads. |
| */ |
| int running_threads; |
| |
| /** |
| * The port on that this portServer is listening for requests. |
| */ |
| int s_port; |
| |
| /** |
| * The server socket of this portServer. |
| */ |
| ServerSocket service; |
| |
| /** |
| * True if the serving node must shutdown due call of the close_now(). |
| */ |
| boolean terminated; |
| |
| /** |
| * Create a new portServer, serving on specific port. |
| */ |
| portServer(int _port) |
| { |
| s_port = _port; |
| setDaemon(true); |
| try |
| { |
| service = socketFactory.createServerSocket(s_port); |
| } |
| catch (IOException ex) |
| { |
| BAD_OPERATION bad = new BAD_OPERATION( |
| "Unable to open the server socket at " + s_port); |
| bad.minor = Minor.Socket; |
| bad.initCause(ex); |
| throw bad; |
| } |
| } |
| |
| /** |
| * Enter the serving loop (get request/process it). All portServer normally |
| * terminate thy threads when the OrbFunctional.running is set to false. |
| */ |
| public void run() |
| { |
| while (running) |
| { |
| try |
| { |
| tick(); |
| } |
| catch (SocketException ex) |
| { |
| // May be thrown when the service is closed by |
| // the close_now(). |
| if (terminated) |
| return; |
| } |
| catch (Exception iex) |
| { |
| // Wait. Do not terminate the |
| // service due potentially transient error. |
| try |
| { |
| Thread.sleep(TWAIT_SERVER_ERROR_PAUSE); |
| } |
| catch (InterruptedException ex) |
| { |
| } |
| } |
| } |
| } |
| |
| /** |
| * Perform a single serving step. |
| * |
| * @throws java.lang.Exception |
| */ |
| void tick() |
| throws Exception |
| { |
| serve(this, service); |
| } |
| |
| /** |
| * Forcibly close the server socket and mark this port as free. |
| */ |
| public void close_now() |
| { |
| try |
| { |
| terminated = true; |
| service.close(); |
| } |
| catch (Exception ex) |
| { |
| // This may happen if the service has not been opened or |
| // cannot be closed. Return without action. |
| } |
| } |
| |
| /** |
| * If the thread is no longer in use, close the socket (if opened). |
| */ |
| protected void finalize() |
| { |
| close_now(); |
| } |
| } |
| |
| /** |
| * A server, responsible for listening on requests on some local port and |
| * serving multiple requests (probably to the different objects) on the same |
| * thread. |
| */ |
| protected class sharedPortServer extends portServer |
| { |
| /** |
| * Create a new portServer, serving on specific port. |
| */ |
| sharedPortServer(int _port) |
| { |
| super(_port); |
| } |
| |
| /** |
| * Perform a single serving step. |
| * |
| * @throws java.lang.Exception |
| */ |
| void tick() throws Exception |
| { |
| Socket request = service.accept(); |
| serveStep(request, false); |
| } |
| } |
| |
| /** |
| * The default value where the first instance of this ORB will start looking |
| * for a free port. |
| */ |
| public static int DEFAULT_INITIAL_PORT = 1126; |
| |
| /** |
| * When trying to open the socket on a random port, start of the interval to |
| * try. |
| */ |
| public static int RANDOM_PORT_FROM = 1024; |
| |
| /** |
| * When trying to open the socket on a random port, end of the interval to |
| * try. |
| */ |
| public static int RANDOM_PORT_TO = 4024; |
| |
| /** |
| * The number of attempts to try when opening random port. |
| */ |
| public static int RANDOM_PORT_ATTEMPTS = 64; |
| |
| /** |
| * The property of port, on that this ORB is listening for requests from |
| * clients. This class supports one port per ORB only. |
| */ |
| public static final String LISTEN_ON = "gnu.classpath.CORBA.ListenOn"; |
| |
| /** |
| * The property, defining the IOR of the intial reference to resolve. |
| */ |
| public static final String REFERENCE = "org.omg.CORBA.ORBInitRef"; |
| |
| /** |
| * The property, defining the port on that the default name service is |
| * running. |
| */ |
| public static final String NS_PORT = "org.omg.CORBA.ORBInitialPort"; |
| |
| /** |
| * The property, defining the host on that the default name service is |
| * running. |
| */ |
| public static final String NS_HOST = "org.omg.CORBA.ORBInitialHost"; |
| |
| /** |
| * The string, defining the naming service initial reference. |
| */ |
| public static final String NAME_SERVICE = "NameService"; |
| |
| /** |
| * Defines the ORB ID that is accessible by IOR interceptors. |
| */ |
| public static final String ORB_ID = "org.omg.CORBA.ORBid"; |
| |
| |
| /** |
| * Defines the SERVER ID that is accessible by IOR interceptors. |
| */ |
| public static final String SERVER_ID = "org.omg.CORBA.ServerId"; |
| |
| /** |
| * The if the client has once opened a socket, it should start sending the |
| * message header in a given time. Otherwise the server will close the socket. |
| * This prevents server hang when the client opens the socket, but does not |
| * send any message, usually due crash on the client side. |
| */ |
| public static String START_READING_MESSAGE = |
| "gnu.classpath.CORBA.TOUT_START_READING_MESSAGE"; |
| |
| /** |
| * If the client has started to send the request message, the socket time out |
| * changes to the specified value. |
| */ |
| public static String WHILE_READING = |
| "gnu.classpath.CORBA.TOUT_WHILE_READING"; |
| |
| /** |
| * If the message body is received, the time out changes to the specifice |
| * value. This must be longer, as includes time, required to process the |
| * received task. We make it 40 minutes. |
| */ |
| public static String AFTER_RECEIVING = |
| "gnu.classpath.CORBA.TOUT_AFTER_RECEIVING"; |
| |
| /** |
| * The server waits for this duration after the potentially transient error |
| * during its servicing cycle. |
| */ |
| public static String SERVER_ERROR_PAUSE = |
| "gnu.classpath.CORBA.SERVER_ERROR_PAUSE"; |
| |
| /** |
| * The address of the local host. |
| */ |
| public final String LOCAL_HOST; |
| |
| /** |
| * The if the client has once opened a socket, it should start sending the |
| * message header in a given time. Otherwise the server will close the socket. |
| * This prevents server hang when the client opens the socket, but does not |
| * send any message, usually due crash on the client side. |
| */ |
| public int TOUT_START_READING_MESSAGE = 20 * 1000; |
| |
| // (Here and below, we use * to make the meaning of the constant clearler). |
| |
| /** |
| * If the client has started to send the request message, the socket time out |
| * changes to the specified value. |
| */ |
| public int TOUT_WHILE_READING = 2 * 60 * 1000; |
| |
| /** |
| * If the message body is received, the time out changes to the specifice |
| * value. This must be longer, as includes time, required to process the |
| * received task. We make it 40 minutes. |
| */ |
| public int TOUT_AFTER_RECEIVING = 40 * 60 * 1000; |
| |
| /** |
| * The server waits for this duration after the potentially transient error |
| * during its servicing cycle. |
| */ |
| public int TWAIT_SERVER_ERROR_PAUSE = 5000; |
| |
| /** |
| * Some clients tend to submit multiple requests over the same socket. The |
| * server waits for the next request on the same socket for the duration, |
| * specified below. In additions, the request of this implementation also |
| * waits for the same duration before closing the socket. The default time is |
| * seven seconds. |
| */ |
| public static int TANDEM_REQUESTS = 7000; |
| |
| /** |
| * The Id of this ORB. |
| */ |
| public String orb_id = "orb_"+hashCode(); |
| |
| /** |
| * The Id of this Server. This field is defined static to ensure it has |
| * the same value over all ORB's in this machine. |
| */ |
| public static String server_id = "server_"+OrbFunctional.class.hashCode(); |
| |
| /** |
| * The map of the already conncted objects. |
| */ |
| protected final Connected_objects connected_objects = |
| new Connected_objects(); |
| |
| /** |
| * The maximal CORBA version, supported by this ORB. The default value 0 means |
| * that the ORB will not check the request version while trying to respond. |
| */ |
| protected Version max_version; |
| |
| /** |
| * Setting this value to false causes the ORB to shutdown after the latest |
| * serving operation is complete. |
| */ |
| protected boolean running; |
| |
| /** |
| * The map of the initial references. |
| */ |
| protected Map initial_references = new TreeMap(); |
| |
| /** |
| * The currently active portServers. |
| */ |
| protected ArrayList portServers = new ArrayList(); |
| |
| /** |
| * The host, on that the name service is expected to be running. |
| */ |
| private String ns_host; |
| |
| /** |
| * Probably free port, under that the ORB will try listening for remote |
| * requests first. When the new object is connected, this port is used first, |
| * then it is incremented by 1, etc. If the given port is not available, up to |
| * 20 subsequent values are tried and then the parameterless server socket |
| * contructor is called. The constant is shared between multiple instances of |
| * this ORB. |
| */ |
| private static int Port = DEFAULT_INITIAL_PORT; |
| |
| /** |
| * The port, on that the name service is expected to be running. |
| */ |
| private int ns_port = 900; |
| |
| /** |
| * The name parser. |
| */ |
| NameParser nameParser = new NameParser(); |
| |
| /** |
| * The instance, stored in this field, handles the asynchronous dynamic |
| * invocations. |
| */ |
| protected Asynchron asynchron = new Asynchron(); |
| |
| /** |
| * The list of the freed ports. The ORB reuses ports, when possible. |
| */ |
| protected LinkedList freed_ports = new LinkedList(); |
| |
| /** |
| * Maps a single-threaded POAs to they sharedPortServants. |
| */ |
| protected Hashtable identities = new Hashtable(); |
| |
| /** |
| * The maximal allowed number of the currently running parallel threads per |
| * object. For security reasons, this is made private and unchangeable. After |
| * exceeding this limit, the NO_RESOURCES is thrown back to the client. |
| */ |
| private int MAX_RUNNING_THREADS = 256; |
| |
| /** |
| * The producer of the client and server sockets for this ORB. |
| */ |
| public SocketFactory socketFactory = DefaultSocketFactory.Singleton; |
| |
| /** |
| * Create the instance of the Functional ORB. |
| */ |
| public OrbFunctional() |
| { |
| try |
| { |
| LOCAL_HOST = ns_host = InetAddress.getLocalHost().getHostAddress(); |
| initial_references.put("CodecFactory", new gnuCodecFactory(this)); |
| } |
| catch (UnknownHostException ex) |
| { |
| BAD_OPERATION bad = |
| new BAD_OPERATION("Unable to open the server socket."); |
| bad.initCause(ex); |
| throw bad; |
| } |
| } |
| |
| /** |
| * If the max version is assigned, the orb replies with the error message if |
| * the request version is above the supported 1.2 version. This behavior is |
| * recommended by OMG, but not all implementations respond that error message |
| * by re-sending the request, encoded in the older version. |
| */ |
| public void setMaxVersion(Version max_supported) |
| { |
| max_version = max_supported; |
| } |
| |
| /** |
| * Get the maximal supported GIOP version or null if the version is not |
| * checked. |
| */ |
| public Version getMaxVersion() |
| { |
| return max_version; |
| } |
| |
| /** |
| * Get the currently free port, starting from the initially set port and going |
| * up max 20 steps, then trying to bind into any free address. |
| * |
| * @return the currently available free port. |
| * |
| * @throws NO_RESOURCES if the server socked cannot be opened on the local |
| * host. |
| */ |
| public int getFreePort() |
| throws BAD_OPERATION |
| { |
| ServerSocket s; |
| int a_port; |
| |
| try |
| { |
| // If there are some previously freed ports, use them first. |
| if (!freed_ports.isEmpty()) |
| { |
| Integer free = (Integer) freed_ports.getLast(); |
| freed_ports.removeLast(); |
| s = socketFactory.createServerSocket(free.intValue()); |
| s.close(); |
| return free.intValue(); |
| } |
| } |
| catch (Exception ex) |
| { |
| // This may be thrown if the request for the new port has arrived |
| // before the current service is completly shutdown. |
| // OK then, use a new port. |
| } |
| |
| for (a_port = Port; a_port < Port + 20; a_port++) |
| { |
| try |
| { |
| s = socketFactory.createServerSocket(a_port); |
| s.close(); |
| Port = a_port + 1; |
| return a_port; |
| } |
| catch (IOException ex) |
| { |
| // Repeat the loop if this exception has been thrown. |
| } |
| } |
| |
| Random rand = new Random(); |
| // Try any random port in the interval RANDOM_PORT_FROM.RANDOM_PORT_TO. |
| int range = RANDOM_PORT_TO - RANDOM_PORT_FROM; |
| IOException ioex = null; |
| for (int i = 0; i < RANDOM_PORT_ATTEMPTS; i++) |
| { |
| try |
| { |
| a_port = RANDOM_PORT_FROM + rand.nextInt(range); |
| s = socketFactory.createServerSocket(a_port); |
| s.close(); |
| return a_port; |
| } |
| catch (IOException ex) |
| { |
| // Repeat the loop if this exception has been thrown. |
| ioex = ex; |
| } |
| } |
| |
| NO_RESOURCES bad = new NO_RESOURCES("Unable to open the server socket."); |
| bad.minor = Minor.Ports; |
| if (ioex != null) |
| bad.initCause(ioex); |
| throw bad; |
| } |
| |
| /** |
| * Set the port, on that the server is listening for the client requests. If |
| * only one object is connected to the orb, the server will be try listening |
| * on this port first. It the port is busy, or if more objects are connected, |
| * the subsequent object will receive a larger port values, skipping |
| * unavailable ports, if required. The change applies globally. |
| * |
| * @param a_Port a port, on that the server is listening for requests. |
| */ |
| public static void setPort(int a_Port) |
| { |
| Port = a_Port; |
| } |
| |
| /** |
| * Connect the given CORBA object to this ORB. After the object is connected, |
| * it starts receiving remote invocations via this ORB. |
| * |
| * The ORB tries to connect the object to the port, that has been previously |
| * set by {@link setPort(int)}. On failure, it tries 20 subsequent larger |
| * values and then calls the parameterless server socked constructor to get |
| * any free local port. If this fails, the {@link NO_RESOURCES} is thrown. |
| * |
| * @param object the object, must implement the {@link InvokeHandler}) |
| * interface. |
| * |
| * @throws BAD_PARAM if the object does not implement the |
| * {@link InvokeHandler}). |
| */ |
| public void connect(org.omg.CORBA.Object object) |
| { |
| int a_port = getFreePort(); |
| |
| Connected_objects.cObject ref = connected_objects.add(object, a_port); |
| IOR ior = createIOR(ref); |
| prepareObject(object, ior); |
| if (running) |
| startService(ior); |
| } |
| |
| /** |
| * Connect the given CORBA object to this ORB, explicitly specifying the |
| * object key. |
| * |
| * The ORB tries to connect the object to the port, that has been previously |
| * set by {@link setPort(int)}. On failure, it tries 20 subsequent larger |
| * values and then calls the parameterless server socked constructor to get |
| * any free local port. If this fails, the {@link NO_RESOURCES} is thrown. |
| * |
| * @param object the object, must implement the {@link InvokeHandler}) |
| * interface. |
| * @param key the object key, usually used to identify the object from remote |
| * side. |
| * |
| * @throws BAD_PARAM if the object does not implement the |
| * {@link InvokeHandler}). |
| */ |
| public void connect(org.omg.CORBA.Object object, byte[] key) |
| { |
| int a_port = getFreePort(); |
| |
| Connected_objects.cObject ref = |
| connected_objects.add(key, object, a_port, null); |
| IOR ior = createIOR(ref); |
| prepareObject(object, ior); |
| if (running) |
| startService(ior); |
| } |
| |
| /** |
| * Connect the given CORBA object to this ORB, explicitly specifying the |
| * object key and the identity of the thread (and port), where the object must |
| * be served. The identity is normally the POA. |
| * |
| * The new port server will be started only if there is no one already running |
| * for the same identity. Otherwise, the task of the existing port server will |
| * be widened, including duty to serve the given object. All objects, |
| * connected to a single identity by this method, will process they requests |
| * subsequently in the same thread. The method is used when the expected |
| * number of the objects is too large to have a single port and thread per |
| * object. This method is used by POAs, having a single thread policy. |
| * |
| * @param object the object, must implement the {@link InvokeHandler}) |
| * interface. |
| * @param key the object key, usually used to identify the object from remote |
| * side. |
| * @param port the port, where the object must be connected. |
| * |
| * @throws BAD_PARAM if the object does not implement the |
| * {@link InvokeHandler}). |
| */ |
| public void connect_1_thread(org.omg.CORBA.Object object, byte[] key, |
| java.lang.Object identity |
| ) |
| { |
| sharedPortServer shared = (sharedPortServer) identities.get(identity); |
| if (shared == null) |
| { |
| int a_port = getFreePort(); |
| shared = new sharedPortServer(a_port); |
| identities.put(identity, shared); |
| if (running) |
| { |
| portServers.add(shared); |
| shared.start(); |
| } |
| } |
| |
| Connected_objects.cObject ref = |
| connected_objects.add(key, object, shared.s_port, identity); |
| IOR ior = createIOR(ref); |
| prepareObject(object, ior); |
| } |
| |
| /** |
| * Start the service on the given port of this IOR. |
| * |
| * @param ior the ior (only Internet.port is used). |
| */ |
| public void startService(IOR ior) |
| { |
| portServer p = new portServer(ior.Internet.port); |
| portServers.add(p); |
| p.start(); |
| } |
| |
| /** |
| * Destroy this server, releasing the occupied resources. |
| */ |
| public void destroy() |
| { |
| portServer p; |
| for (int i = 0; i < portServers.size(); i++) |
| { |
| p = (portServer) portServers.get(i); |
| p.close_now(); |
| } |
| super.destroy(); |
| } |
| |
| /** |
| * Disconnect the given CORBA object from this ORB. The object will be no |
| * longer receiving the remote invocations. In response to the remote |
| * invocation on this object, the ORB will send the exception |
| * {@link OBJECT_NOT_EXIST}. The object, however, is not destroyed and can |
| * receive the local invocations. |
| * |
| * @param object the object to disconnect. |
| */ |
| public void disconnect(org.omg.CORBA.Object object) |
| { |
| Connected_objects.cObject rmKey = null; |
| |
| // Handle the case when it is possible to get the object key. |
| // Handle the case when the object is known, but not local. |
| if (object instanceof ObjectImpl) |
| { |
| Delegate delegate = ((ObjectImpl) object)._get_delegate(); |
| if (delegate instanceof SimpleDelegate) |
| { |
| byte[] key = ((SimpleDelegate) delegate).getIor().key; |
| rmKey = connected_objects.get(key); |
| } |
| } |
| |
| // Try to find and disconned the object that is not an instance of the |
| // object implementation. |
| if (rmKey == null) |
| rmKey = connected_objects.getKey(object); |
| if (rmKey != null) |
| { |
| // Find and stop the corresponding portServer. |
| portServer p; |
| StopService: |
| for (int i = 0; i < portServers.size(); i++) |
| { |
| p = (portServer) portServers.get(i); |
| if (p.s_port == rmKey.port && !(p instanceof sharedPortServer)) |
| { |
| p.close_now(); |
| freed_ports.addFirst(new Integer(rmKey.port)); |
| break StopService; |
| } |
| connected_objects.remove(rmKey.key); |
| } |
| } |
| } |
| |
| /** |
| * Notifies ORB that the shared service indentity (usually POA) is destroyed. |
| * The matching shared port server is terminated and the identity table entry |
| * is deleted. If this identity is not known for this ORB, the method returns |
| * without action. |
| * |
| * @param identity the identity that has been destroyed. |
| */ |
| public void identityDestroyed(java.lang.Object identity) |
| { |
| if (identity == null) |
| return; |
| |
| sharedPortServer ise = (sharedPortServer) identities.get(identity); |
| if (ise != null) |
| { |
| synchronized (connected_objects) |
| { |
| ise.close_now(); |
| identities.remove(identity); |
| |
| Connected_objects.cObject obj; |
| Map.Entry m; |
| Iterator iter = connected_objects.entrySet().iterator(); |
| while (iter.hasNext()) |
| { |
| m = (Map.Entry) iter.next(); |
| obj = (Connected_objects.cObject) m.getValue(); |
| if (obj.identity == identity) |
| iter.remove(); |
| } |
| } |
| } |
| } |
| |
| /** |
| * Find the local object, connected to this ORB. |
| * |
| * @param ior the ior of the potentially local object. |
| * |
| * @return the local object, represented by the given IOR, or null if this is |
| * not a local connected object. |
| */ |
| public org.omg.CORBA.Object find_local_object(IOR ior) |
| { |
| // Must be the same host. |
| if (!ior.Internet.host.equals(LOCAL_HOST)) |
| return null; |
| |
| return find_connected_object(ior.key, ior.Internet.port); |
| } |
| |
| /** |
| * List the initially available CORBA objects (services). |
| * |
| * @return a list of services. |
| * |
| * @see resolve_initial_references(String) |
| */ |
| public String[] list_initial_services() |
| { |
| String[] refs = new String[ initial_references.size() ]; |
| int p = 0; |
| |
| Iterator iter = initial_references.keySet().iterator(); |
| while (iter.hasNext()) |
| { |
| refs [ p++ ] = (String) iter.next(); |
| } |
| return refs; |
| } |
| |
| /** |
| * Get the IOR reference string for the given object. The string embeds |
| * information about the object repository Id, its access key and the server |
| * internet address and port. With this information, the object can be found |
| * by another ORB, possibly located on remote computer. |
| * |
| * @param the CORBA object |
| * @return the object IOR representation. |
| * |
| * @throws BAD_PARAM if the object has not been previously connected to this |
| * ORB. |
| * |
| * @throws BAD_OPERATION in the unlikely case if the local host address cannot |
| * be resolved. |
| * |
| * @see string_to_object(String) |
| */ |
| public String object_to_string(org.omg.CORBA.Object forObject) |
| { |
| // Handle the case when the object is known, but not local. |
| if (forObject instanceof ObjectImpl) |
| { |
| Delegate delegate = ((ObjectImpl) forObject)._get_delegate(); |
| if (delegate instanceof SimpleDelegate) |
| return ((SimpleDelegate) delegate).getIor().toStringifiedReference(); |
| } |
| |
| // Handle the case when the object is local. |
| Connected_objects.cObject rec = connected_objects.getKey(forObject); |
| |
| if (rec == null) |
| throw new BAD_PARAM("The object " + forObject + |
| " has not been previously connected to this ORB" |
| ); |
| |
| IOR ior = createIOR(rec); |
| |
| return ior.toStringifiedReference(); |
| } |
| |
| /** |
| * Get the local IOR for the given object, null if the object is not local. |
| */ |
| public IOR getLocalIor(org.omg.CORBA.Object forObject) |
| { |
| Connected_objects.cObject rec = connected_objects.getKey(forObject); |
| if (rec == null) |
| return null; |
| else |
| return createIOR(rec); |
| } |
| |
| /** |
| * Find and return the easily accessible CORBA object, addressed by name. |
| * |
| * @param name the object name. |
| * @return the object |
| * |
| * @throws org.omg.CORBA.ORBPackage.InvalidName if the given name is not |
| * associated with the known object. |
| */ |
| public org.omg.CORBA.Object resolve_initial_references(String name) |
| throws InvalidName |
| { |
| org.omg.CORBA.Object object = null; |
| try |
| { |
| object = (org.omg.CORBA.Object) initial_references.get(name); |
| if (object == null && name.equals(NAME_SERVICE)) |
| { |
| object = getDefaultNameService(); |
| if (object != null) |
| initial_references.put(NAME_SERVICE, object); |
| } |
| } |
| catch (Exception ex) |
| { |
| InvalidName err = new InvalidName(name); |
| err.initCause(ex); |
| throw err; |
| } |
| if (object != null) |
| return object; |
| else |
| throw new InvalidName("Not found: '" + name + "'"); |
| } |
| |
| /** |
| * Start the ORBs main working cycle (receive invocation - invoke on the local |
| * object - send response - wait for another invocation). The method only |
| * returns after calling {@link #shutdown(boolean)}. |
| */ |
| public void run() |
| { |
| CollocatedOrbs.registerOrb(this); |
| try |
| { |
| running = true; |
| |
| // Instantiate the port server for each socket. |
| Iterator iter = connected_objects.entrySet().iterator(); |
| Map.Entry m; |
| Connected_objects.cObject obj; |
| |
| while (iter.hasNext()) |
| { |
| m = (Map.Entry) iter.next(); |
| obj = (Connected_objects.cObject) m.getValue(); |
| |
| portServer subserver; |
| |
| if (obj.identity == null) |
| { |
| subserver = new portServer(obj.port); |
| portServers.add(subserver); |
| } |
| else |
| subserver = (portServer) identities.get(obj.identity); |
| |
| if (! subserver.isAlive()) |
| { |
| // Reuse the current thread for the last portServer. |
| if (! iter.hasNext()) |
| { |
| // Discard the iterator, eliminating lock checks. |
| iter = null; |
| subserver.run(); |
| return; |
| } |
| else |
| subserver.start(); |
| } |
| } |
| } |
| finally |
| { |
| CollocatedOrbs.unregisterOrb(this); |
| } |
| } |
| |
| /** |
| * Start the server in a new thread, if not already running. This method is |
| * used to ensure that the objects being transfered will be served from the |
| * remote side, if required. If the ORB is started using this method, it |
| * starts as a daemon thread. |
| */ |
| public void ensureRunning() |
| { |
| final OrbFunctional THIS = this; |
| |
| if (!running) |
| { |
| Thread t = new Thread() |
| { |
| public void run() |
| { |
| THIS.run(); |
| } |
| }; |
| t.setDaemon(true); |
| t.start(); |
| } |
| } |
| |
| /** |
| * Shutdown the ORB server. |
| * |
| * @param wait_for_completion if true, the current thread is suspended until |
| * the shutdown process is complete. |
| */ |
| public void shutdown(boolean wait_for_completion) |
| { |
| super.shutdown(wait_for_completion); |
| running = false; |
| |
| if (!wait_for_completion) |
| { |
| for (int i = 0; i < portServers.size(); i++) |
| { |
| portServer p = (portServer) portServers.get(i); |
| p.close_now(); |
| } |
| } |
| } |
| |
| /** |
| * Find and return the CORBA object, addressed by the given IOR string |
| * representation. The object can (an usually is) located on a remote |
| * computer, possibly running a different (not necessary java) CORBA |
| * implementation. |
| * |
| * @param ior the object IOR representation string. |
| * |
| * @return the found CORBA object. |
| * @see object_to_string(org.omg.CORBA.Object) |
| */ |
| public org.omg.CORBA.Object string_to_object(String an_ior) |
| { |
| return nameParser.corbaloc(an_ior, this); |
| } |
| |
| /** |
| * Convert ior reference to CORBA object. |
| */ |
| public org.omg.CORBA.Object ior_to_object(IOR ior) |
| { |
| org.omg.CORBA.Object object = find_local_object(ior); |
| if (object == null) |
| { |
| // Check maybe the local object on another ORB, but same VM. |
| object = CollocatedOrbs.searchLocalObject(ior); |
| if (object == null) |
| { |
| // Surely remote object. |
| ObjectImpl impl = StubLocator.search(this, ior); |
| try |
| { |
| if (impl._get_delegate() == null) |
| impl._set_delegate(new IorDelegate(this, ior)); |
| } |
| catch (BAD_OPERATION ex) |
| { |
| // Some colaborants may throw this exception |
| // in response to the attempt to get the unset delegate. |
| impl._set_delegate(new IorDelegate(this, ior)); |
| } |
| |
| object = impl; |
| } |
| } |
| return object; |
| } |
| |
| /** |
| * Get the default naming service for the case when there no NameService |
| * entries. |
| */ |
| protected org.omg.CORBA.Object getDefaultNameService() |
| { |
| if (initial_references.containsKey(NAME_SERVICE)) |
| return (org.omg.CORBA.Object) initial_references.get(NAME_SERVICE); |
| |
| IOR ior = new IOR(); |
| ior.Id = NamingContextExtHelper.id(); |
| ior.Internet.host = ns_host; |
| ior.Internet.port = ns_port; |
| ior.key = NamingServiceTransient.getDefaultKey(); |
| |
| IorObject iorc = new IorObject(this, ior); |
| NamingContextExt namer = NamingContextExtHelper.narrow(iorc); |
| initial_references.put(NAME_SERVICE, namer); |
| return namer; |
| } |
| |
| /** |
| * Find and return the object, that must be previously connected to this ORB. |
| * Return null if no such object is available. |
| * |
| * @param key the object key. |
| * @param port the port where the object is connected. |
| * |
| * @return the connected object, null if none. |
| */ |
| protected org.omg.CORBA.Object find_connected_object(byte[] key, int port) |
| { |
| Connected_objects.cObject ref = connected_objects.get(key); |
| if (ref == null) |
| return null; |
| if (port >= 0 && ref.port != port) |
| return null; |
| else |
| return ref.object; |
| } |
| |
| /** |
| * Set the ORB parameters. This method is normally called from |
| * {@link #init(Applet, Properties)}. |
| * |
| * @param app the current applet. |
| * |
| * @param props application specific properties, passed as the second |
| * parameter in {@link #init(Applet, Properties)}. Can be <code>null</code>. |
| */ |
| protected void set_parameters(Applet app, Properties props) |
| { |
| useProperties(props); |
| |
| String[][] para = app.getParameterInfo(); |
| if (para != null) |
| { |
| for (int i = 0; i < para.length; i++) |
| { |
| if (para[i][0].equals(LISTEN_ON)) |
| Port = Integer.parseInt(para[i][1]); |
| if (para[i][0].equals(REFERENCE)) |
| { |
| StringTokenizer st = new StringTokenizer(para[i][1], "="); |
| initial_references.put(st.nextToken(), |
| string_to_object(st.nextToken())); |
| } |
| |
| if (para[i][0].equals(ORB_ID)) |
| orb_id = para[i][1]; |
| |
| if (para[i][0].equals(SERVER_ID)) |
| server_id = para[i][1]; |
| |
| if (para[i][0].equals(NS_HOST)) |
| ns_host = para[i][1]; |
| if (para[i][0].equals(START_READING_MESSAGE)) |
| TOUT_START_READING_MESSAGE = Integer.parseInt(para[i][1]); |
| if (para[i][0].equals(WHILE_READING)) |
| TOUT_WHILE_READING = Integer.parseInt(para[i][1]); |
| if (para[i][0].equals(AFTER_RECEIVING)) |
| TOUT_AFTER_RECEIVING = Integer.parseInt(para[i][1]); |
| try |
| { |
| if (para[i][0].equals(NS_PORT)) |
| ns_port = Integer.parseInt(para[i][1]); |
| } |
| catch (NumberFormatException ex) |
| { |
| BAD_PARAM bad = new BAD_PARAM("Invalid " + NS_PORT |
| + "property, unable to parse '" + props.getProperty(NS_PORT) |
| + "'"); |
| bad.initCause(ex); |
| throw bad; |
| } |
| } |
| } |
| } |
| |
| /** |
| * Set the ORB parameters. This method is normally called from |
| * {@link #init(String[], Properties)}. |
| * |
| * @param para the parameters, that were passed as the parameters to the |
| * <code>main(String[] args)</code> method of the current standalone |
| * application. |
| * |
| * @param props application specific properties that were passed as a second |
| * parameter in {@link init(String[], Properties)}). Can be <code>null</code>. |
| */ |
| protected void set_parameters(String[] para, Properties props) |
| { |
| if (para.length > 1) |
| { |
| for (int i = 0; i < para.length - 1; i++) |
| { |
| if (para[i].endsWith("ListenOn")) |
| Port = Integer.parseInt(para[i + 1]); |
| if (para[i].endsWith("ORBInitRef")) |
| { |
| StringTokenizer st = new StringTokenizer(para[i + 1], "="); |
| initial_references.put(st.nextToken(), |
| string_to_object(st.nextToken())); |
| } |
| |
| if (para[i].endsWith("ORBInitialHost")) |
| ns_host = para[i + 1]; |
| |
| if (para[i].endsWith("ServerId")) |
| server_id = para[i++]; |
| else if (para[i].endsWith("ORBid")) |
| orb_id = para[i++]; |
| |
| try |
| { |
| if (para[i].endsWith("ORBInitialPort")) |
| ns_port = Integer.parseInt(para[i + 1]); |
| } |
| catch (NumberFormatException ex) |
| { |
| throw new BAD_PARAM("Invalid " + para[i] |
| + "parameter, unable to parse '" |
| + props.getProperty(para[i + 1]) + "'"); |
| } |
| } |
| } |
| |
| useProperties(props); |
| } |
| |
| /** |
| * Create IOR for the given object references. |
| */ |
| protected IOR createIOR(Connected_objects.cObject ref) |
| throws BAD_OPERATION |
| { |
| IOR ior = new IOR(); |
| ior.key = ref.key; |
| ior.Internet.port = ref.port; |
| |
| if (ref.object instanceof ObjectImpl) |
| { |
| ObjectImpl imp = (ObjectImpl) ref.object; |
| if (imp._ids().length > 0) |
| ior.Id = imp._ids() [ 0 ]; |
| } |
| if (ior.Id == null) |
| ior.Id = ref.object.getClass().getName(); |
| |
| ior.Internet.host = CollocatedOrbs.localHost; |
| ior.Internet.port = ref.port; |
| |
| return ior; |
| } |
| |
| /** |
| * Prepare object for connecting it to this ORB. |
| * |
| * @param object the object being connected. |
| * |
| * @throws BAD_PARAM if the object does not implement the |
| * {@link InvokeHandler}). |
| */ |
| protected void prepareObject(org.omg.CORBA.Object object, IOR ior) |
| throws BAD_PARAM |
| { |
| /* |
| * if (!(object instanceof InvokeHandler)) throw new |
| * BAD_PARAM(object.getClass().getName() + " does not implement |
| * InvokeHandler. " ); |
| */ |
| |
| // If no delegate is set, set the default delegate. |
| if (object instanceof ObjectImpl) |
| { |
| ObjectImpl impl = (ObjectImpl) object; |
| try |
| { |
| if (impl._get_delegate() == null) |
| impl._set_delegate(new SimpleDelegate(this, ior)); |
| } |
| catch (BAD_OPERATION ex) |
| { |
| // Some colaborants may throw this exception. |
| impl._set_delegate(new SimpleDelegate(this, ior)); |
| } |
| } |
| } |
| |
| /** |
| * Write the response message. |
| * |
| * @param net_out the stream to write response into |
| * @param msh_request the request message header |
| * @param rh_request the request header |
| * @param handler the invocation handler that has been used to invoke the |
| * operation |
| * @param sysEx the system exception, thrown during the invocation, null if |
| * none. |
| * |
| * @throws IOException |
| */ |
| private void respond_to_client(OutputStream net_out, |
| MessageHeader msh_request, RequestHeader rh_request, |
| ResponseHandlerImpl handler, SystemException sysEx |
| ) throws IOException |
| { |
| // Set the reply header properties. |
| ReplyHeader reply = handler.reply_header; |
| |
| if (sysEx != null) |
| reply.reply_status = ReplyHeader.SYSTEM_EXCEPTION; |
| else if (handler.isExceptionReply()) |
| reply.reply_status = ReplyHeader.USER_EXCEPTION; |
| else |
| reply.reply_status = ReplyHeader.NO_EXCEPTION; |
| reply.request_id = rh_request.request_id; |
| |
| BufferedCdrOutput out = |
| new BufferedCdrOutput(50 + handler.getBuffer().buffer.size()); |
| out.setOrb(this); |
| |
| out.setOffset(msh_request.getHeaderSize()); |
| |
| reply.write(out); |
| |
| if (msh_request.version.since_inclusive(1, 2)) |
| { |
| out.align(8); |
| |
| // Write the reply data from the handler. The handler data already |
| // include the necessary heading zeroes for alignment. |
| } |
| handler.getBuffer().buffer.writeTo(out); |
| |
| MessageHeader msh_reply = new MessageHeader(); |
| |
| msh_reply.version = msh_request.version; |
| msh_reply.message_type = MessageHeader.REPLY; |
| msh_reply.message_size = out.buffer.size(); |
| |
| // Write the reply. |
| msh_reply.write(net_out); |
| out.buffer.writeTo(net_out); |
| net_out.flush(); |
| } |
| |
| /** |
| * Forward request to another target, as indicated by the passed exception. |
| */ |
| private void forward_request(OutputStream net_out, |
| MessageHeader msh_request, RequestHeader rh_request, gnuForwardRequest info |
| ) throws IOException |
| { |
| MessageHeader msh_forward = new MessageHeader(); |
| msh_forward.version = msh_request.version; |
| |
| ReplyHeader rh_forward = msh_forward.create_reply_header(); |
| msh_forward.message_type = MessageHeader.REPLY; |
| rh_forward.reply_status = info.forwarding_code; |
| rh_forward.request_id = rh_request.request_id; |
| |
| // The forwarding code is either LOCATION_FORWARD or LOCATION_FORWARD_PERM. |
| BufferedCdrOutput out = new BufferedCdrOutput(); |
| out.setOrb(this); |
| out.setOffset(msh_forward.getHeaderSize()); |
| |
| rh_forward.write(out); |
| |
| if (msh_forward.version.since_inclusive(1, 2)) |
| out.align(8); |
| out.write_Object(info.forward_reference); |
| |
| msh_forward.message_size = out.buffer.size(); |
| |
| // Write the forwarding instruction. |
| msh_forward.write(net_out); |
| out.buffer.writeTo(net_out); |
| net_out.flush(); |
| } |
| |
| /** |
| * Contains a single servicing task. |
| * |
| * Normally, each task matches a single remote invocation. However under |
| * frequent tandem submissions the same task may span over several |
| * invocations. |
| * |
| * @param serverSocket the ORB server socket. |
| * |
| * @throws MARSHAL |
| * @throws IOException |
| */ |
| void serve(final portServer p, ServerSocket serverSocket) |
| throws MARSHAL, IOException |
| { |
| final Socket service; |
| service = serverSocket.accept(); |
| |
| // Tell the server there are no more resources. |
| if (p.running_threads >= MAX_RUNNING_THREADS) |
| { |
| serveStep(service, true); |
| return; |
| } |
| |
| new Thread() |
| { |
| public void run() |
| { |
| try |
| { |
| synchronized (p) |
| { |
| p.running_threads++; |
| } |
| serveStep(service, false); |
| } |
| finally |
| { |
| synchronized (p) |
| { |
| p.running_threads--; |
| } |
| } |
| } |
| }.start(); |
| } |
| |
| /** |
| * A single servicing step, when the client socket is alrady open. |
| * |
| * Normally, each task matches a single remote invocation. However under |
| * frequent tandem submissions the same task may span over several |
| * invocations. |
| * |
| * @param service the opened client socket. |
| * @param no_resources if true, the "NO RESOURCES" exception is thrown to the |
| * client. |
| */ |
| void serveStep(Socket service, boolean no_resources) |
| { |
| try |
| { |
| Serving: while (true) |
| { |
| InputStream in = service.getInputStream(); |
| service.setSoTimeout(TOUT_START_READING_MESSAGE); |
| |
| MessageHeader msh_request = new MessageHeader(); |
| |
| try |
| { |
| msh_request.read(in); |
| } |
| catch (MARSHAL ex) |
| { |
| // This exception may be thrown due closing the connection. |
| return; |
| } |
| |
| if (max_version != null) |
| { |
| if (!msh_request.version.until_inclusive(max_version.major, |
| max_version.minor)) |
| { |
| OutputStream out = service.getOutputStream(); |
| new ErrorMessage(max_version).write(out); |
| return; |
| } |
| } |
| |
| byte[] r = msh_request.readMessage(in, service, TOUT_WHILE_READING, |
| TOUT_AFTER_RECEIVING); |
| |
| if (msh_request.message_type == MessageHeader.REQUEST) |
| { |
| RequestHeader rh_request; |
| |
| BufferredCdrInput cin = new BufferredCdrInput(r); |
| cin.setOrb(this); |
| cin.setVersion(msh_request.version); |
| cin.setOffset(msh_request.getHeaderSize()); |
| cin.setBigEndian(msh_request.isBigEndian()); |
| |
| rh_request = msh_request.create_request_header(); |
| |
| // Read header and auto set the charset. |
| rh_request.read(cin); |
| |
| // in 1.2 and higher, align the current position at |
| // 8 octet boundary. |
| if (msh_request.version.since_inclusive(1, 2)) |
| { |
| cin.align(8); |
| |
| // find the target object. |
| } |
| |
| InvokeHandler target = (InvokeHandler) find_connected_object( |
| rh_request.object_key, -1); |
| |
| // Prepare the reply header. This must be done in advance, |
| // as the size must be known for handler to set alignments |
| // correctly. |
| ReplyHeader rh_reply = msh_request.create_reply_header(); |
| |
| // TODO log errors about not existing objects and methods. |
| ResponseHandlerImpl handler = new ResponseHandlerImpl( |
| this, msh_request, rh_reply, rh_request); |
| |
| SystemException sysEx = null; |
| |
| try |
| { |
| if (no_resources) |
| { |
| NO_RESOURCES no = new NO_RESOURCES("Too many parallel calls"); |
| no.minor = Minor.Threads; |
| throw no; |
| } |
| if (target == null) |
| throw new OBJECT_NOT_EXIST(); |
| target._invoke(rh_request.operation, cin, handler); |
| } |
| catch (gnuForwardRequest forwarded) |
| { |
| OutputStream sou = service.getOutputStream(); |
| forward_request(sou, msh_request, rh_request, forwarded); |
| if (service != null && !service.isClosed()) |
| { |
| // Wait for the subsequent invocations on the |
| // same socket for the TANDEM_REQUEST duration. |
| service.setSoTimeout(TANDEM_REQUESTS); |
| continue Serving; |
| } |
| } |
| catch (UnknownException uex) |
| { |
| sysEx = new UNKNOWN("Unknown", 2, |
| CompletionStatus.COMPLETED_MAYBE); |
| sysEx.initCause(uex.originalEx); |
| |
| org.omg.CORBA.portable.OutputStream ech = handler.createExceptionReply(); |
| |
| rh_reply.service_context = UnknownExceptionCtxHandler.addExceptionContext( |
| rh_reply.service_context, uex.originalEx, ech); |
| |
| ObjectCreator.writeSystemException(ech, sysEx); |
| } |
| catch (SystemException ex) |
| { |
| sysEx = ex; |
| |
| org.omg.CORBA.portable.OutputStream ech = handler.createExceptionReply(); |
| |
| rh_reply.service_context = UnknownExceptionCtxHandler.addExceptionContext( |
| rh_reply.service_context, ex, ech); |
| |
| ObjectCreator.writeSystemException(ech, ex); |
| } |
| catch (Exception except) |
| { |
| // This should never happen under normal operation and |
| // can only indicate errors in user object implementation. |
| // We inform the user. |
| except.printStackTrace(); |
| |
| sysEx = new UNKNOWN("Unknown", 2, |
| CompletionStatus.COMPLETED_MAYBE); |
| sysEx.initCause(except); |
| |
| org.omg.CORBA.portable.OutputStream ech = handler.createExceptionReply(); |
| |
| rh_reply.service_context = UnknownExceptionCtxHandler.addExceptionContext( |
| rh_reply.service_context, except, ech); |
| |
| ObjectCreator.writeSystemException(ech, sysEx); |
| } |
| |
| // Write the response. |
| if (rh_request.isResponseExpected()) |
| { |
| OutputStream sou = service.getOutputStream(); |
| respond_to_client(sou, msh_request, rh_request, handler, |
| sysEx); |
| } |
| } |
| else if (msh_request.message_type == MessageHeader.CLOSE_CONNECTION |
| || msh_request.message_type == MessageHeader.MESSAGE_ERROR) |
| { |
| CloseMessage.close(service.getOutputStream()); |
| service.close(); |
| return; |
| } |
| |
| if (service != null && !service.isClosed()) |
| |
| // Wait for the subsequent invocations on the |
| // same socket for the TANDEM_REQUEST duration. |
| service.setSoTimeout(TANDEM_REQUESTS); |
| else |
| return; |
| } |
| } |
| catch (SocketException ex) |
| { |
| // OK. |
| return; |
| } |
| catch (IOException ioex) |
| { |
| // Network error, probably transient. |
| // TODO log it. |
| return; |
| } |
| finally |
| { |
| try |
| { |
| if (service!=null && !service.isClosed()) |
| service.close(); |
| } |
| catch (IOException ioex) |
| { |
| // OK. |
| } |
| } |
| } |
| |
| /** |
| * Set the ORB parameters from the properties that were accumulated |
| * from several locations. |
| */ |
| protected void useProperties(Properties props) |
| { |
| if (props != null) |
| { |
| if (props.containsKey(LISTEN_ON)) |
| Port = Integer.parseInt(props.getProperty(LISTEN_ON)); |
| if (props.containsKey(NS_HOST)) |
| ns_host = props.getProperty(NS_HOST); |
| try |
| { |
| if (props.containsKey(NS_PORT)) |
| ns_port = Integer.parseInt(props.getProperty(NS_PORT)); |
| if (props.containsKey(START_READING_MESSAGE)) |
| TOUT_START_READING_MESSAGE = |
| Integer.parseInt(props.getProperty(START_READING_MESSAGE)); |
| if (props.containsKey(WHILE_READING)) |
| TOUT_WHILE_READING = |
| Integer.parseInt(props.getProperty(WHILE_READING)); |
| if (props.containsKey(AFTER_RECEIVING)) |
| TOUT_AFTER_RECEIVING = |
| Integer.parseInt(props.getProperty(AFTER_RECEIVING)); |
| if (props.containsKey(SERVER_ERROR_PAUSE)) |
| TWAIT_SERVER_ERROR_PAUSE = |
| Integer.parseInt(props.getProperty(SERVER_ERROR_PAUSE)); |
| } |
| catch (NumberFormatException ex) |
| { |
| throw new BAD_PARAM("Invalid " + NS_PORT + |
| "property, unable to parse '" + props.getProperty(NS_PORT) + |
| "'" |
| ); |
| } |
| |
| if (props.containsKey(SocketFactory.PROPERTY)) |
| { |
| String factory = null; |
| try |
| { |
| factory = props.getProperty(SocketFactory.PROPERTY); |
| if (factory!=null) |
| socketFactory = (SocketFactory) |
| ObjectCreator.forName(factory).newInstance(); |
| } |
| catch (Exception ex) |
| { |
| BAD_PARAM p = new BAD_PARAM("Bad socket factory "+factory); |
| p.initCause(ex); |
| throw p; |
| } |
| } |
| |
| if (props.containsKey(ORB_ID)) |
| orb_id = props.getProperty(ORB_ID); |
| |
| if (props.containsKey(SERVER_ID)) |
| server_id = props.getProperty(SERVER_ID); |
| |
| Enumeration en = props.elements(); |
| while (en.hasMoreElements()) |
| { |
| String item = (String) en.nextElement(); |
| if (item.equals(REFERENCE)) |
| initial_references.put(item, |
| string_to_object(props.getProperty(item)) |
| ); |
| } |
| } |
| } |
| |
| /** |
| * Get the next instance with a response being received. If all currently sent |
| * responses not yet processed, this method pauses till at least one of them |
| * is complete. If there are no requests currently sent, the method pauses |
| * till some request is submitted and the response is received. This strategy |
| * is identical to the one accepted by Suns 1.4 ORB implementation. |
| * |
| * The returned response is removed from the list of the currently submitted |
| * responses and is never returned again. |
| * |
| * @return the previously sent request that now contains the received |
| * response. |
| * |
| * @throws WrongTransaction If the method was called from the transaction |
| * scope different than the one, used to send the request. The exception can |
| * be raised only if the request is implicitly associated with some particular |
| * transaction. |
| */ |
| public Request get_next_response() throws org.omg.CORBA.WrongTransaction |
| { |
| return asynchron.get_next_response(); |
| } |
| |
| /** |
| * Find if any of the requests that have been previously sent with |
| * {@link #send_multiple_requests_deferred}, have a response yet. |
| * |
| * @return true if there is at least one response to the previously sent |
| * request, false otherwise. |
| */ |
| public boolean poll_next_response() |
| { |
| return asynchron.poll_next_response(); |
| } |
| |
| /** |
| * Send multiple prepared requests expecting to get a reply. All requests are |
| * send in parallel, each in its own separate thread. When the reply arrives, |
| * it is stored in the agreed fields of the corresponing request data |
| * structure. If this method is called repeatedly, the new requests are added |
| * to the set of the currently sent requests, but the old set is not |
| * discarded. |
| * |
| * @param requests the prepared array of requests. |
| * |
| * @see #poll_next_response() |
| * @see #get_next_response() |
| * @see Request#send_deferred() |
| */ |
| public void send_multiple_requests_deferred(Request[] requests) |
| { |
| asynchron.send_multiple_requests_deferred(requests); |
| } |
| |
| /** |
| * Send multiple prepared requests one way, do not caring about the answer. |
| * The messages, containing requests, will be marked, indicating that the |
| * sender is not expecting to get a reply. |
| * |
| * @param requests the prepared array of requests. |
| * |
| * @see Request#send_oneway() |
| */ |
| public void send_multiple_requests_oneway(Request[] requests) |
| { |
| asynchron.send_multiple_requests_oneway(requests); |
| } |
| |
| /** |
| * Set the flag, forcing all server threads to terminate. |
| */ |
| protected void finalize() throws java.lang.Throwable |
| { |
| running = false; |
| super.finalize(); |
| } |
| |
| /** |
| * Get the number of objects that are connected to this ORB. |
| * |
| * @return the number of objects, connected to this ORB. |
| */ |
| public int countConnectedObjects() |
| { |
| return connected_objects.size(); |
| } |
| } |