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