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