Source for gnu.CORBA.OrbFocused

   1: /* OrbFocused.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.Poa.ORB_1_4;
  42: 
  43: import org.omg.CORBA.BAD_INV_ORDER;
  44: import org.omg.CORBA.BAD_OPERATION;
  45: import org.omg.CORBA.BAD_PARAM;
  46: import org.omg.CORBA.CompletionStatus;
  47: import org.omg.CORBA.NO_RESOURCES;
  48: import org.omg.CORBA.portable.InvokeHandler;
  49: 
  50: import java.applet.Applet;
  51: import java.net.ServerSocket;
  52: import java.util.Iterator;
  53: import java.util.Properties;
  54: import java.util.Random;
  55: import java.util.StringTokenizer;
  56: 
  57: /**
  58:  * This class implements the ORB that uses a single port or the restricted port
  59:  * range for all its objects. It is required to for use together with various
  60:  * firewalls that does not allow opening multiple randomly selected ports, as
  61:  * the defauld CORBA implementation used to do. The firewal must be configured
  62:  * to allow CORBA to work on one fixed port or (for better performance) on a
  63:  * small fixed range of ports. This does not restrict the maximal number of the
  64:  * connected objects as the objects can share the same port.
  65:  *
  66:  * The used port or the used port range can be specified via property
  67:  * gnu.CORBA.ListenerPort. The value of this property is a single port or range
  68:  * of ports, boundary values (inclusive) being separeted by dash (for instance,
  69:  * "1245-1250").
  70:  *
  71:  * It is possible to instantiate multiple instances of the focused ORBs and
  72:  * combine them with the ordinary ORBs. If you instantiate several instances of
  73:  * the focused ORBs on the same host, they used port sets should not overlap.
  74:  *
  75:  * @author Audrius Meskauskas, Lithuania (AudriusA@Bioinformatics.org)
  76:  */
  77: public class OrbFocused
  78:   extends ORB_1_4
  79: {
  80:   /**
  81:    * The name of the fixed port range property. The presence of this property
  82:    * indicates that the default focused ORB must be used.
  83:    */
  84:   public static final String LISTENER_PORT = "gnu.CORBA.ListenerPort";
  85: 
  86:   /**
  87:    * The start of the range of the available ports, inclusive.
  88:    */
  89:   int m_ports_from = -1;
  90: 
  91:   /**
  92:    * The end of the range of the available ports, inclusive.
  93:    */
  94:   int m_ports_to = -1;
  95: 
  96:   /**
  97:    * The requests to port are served in parallel threads.
  98:    */
  99:   static final int PARALLEL = 0;
 100: 
 101:   /**
 102:    * The requests to port are served in the same thread.
 103:    */
 104:   static final int SEQUENTIAL = 1;
 105: 
 106:   /**
 107:    * The random number generator to get a random port in the valid range.
 108:    */
 109:   Random m_random = new Random();
 110: 
 111:   /**
 112:    * Parse the "gnu.CORBA.ListenerPort" property and initialize the valid port
 113:    * set range.
 114:    */
 115:   public void setPortRange(String property)
 116:   {
 117:     int from, to;
 118:     try
 119:       {
 120:         StringTokenizer st = new StringTokenizer(property, " -");
 121:         if (st.countTokens() == 1)
 122:           from = to = Integer.parseInt(st.nextToken());
 123:         else
 124:           {
 125:             from = Integer.parseInt(st.nextToken());
 126:             to = Integer.parseInt(st.nextToken());
 127:             m_random = new Random();
 128:           }
 129:         setPortRange(from, to);
 130:       }
 131:     catch (Exception ex)
 132:       {
 133:         throw new BAD_PARAM("Unable to parse port range '" + property + "'");
 134:       }
 135:   }
 136: 
 137:   /**
 138:    * Set the port range.
 139:    *
 140:    * @param from - start of the port range, inclusive.
 141:    * @param to - end of the port range, inclusive.
 142:    */
 143:   public void setPortRange(int from, int to)
 144:   {
 145:     if (from < 0 || to < 0 || to < from)
 146:       throw new BAD_PARAM("Invalid range");
 147:     m_ports_from = from;
 148:     m_ports_to = to;
 149:   }
 150: 
 151:   /**
 152:    * Get the port from the previously specified usage range.
 153:    */
 154:   int getPortFromRange(int attempt)
 155:   {
 156:     if (m_ports_from == m_ports_to)
 157:       return m_ports_from;
 158:     else if (m_ports_to - m_ports_from < RANDOM_PORT_ATTEMPTS)
 159:       return m_ports_from + (attempt % (m_ports_to - m_ports_from + 1));
 160:     else
 161:       return m_random.nextInt(m_ports_to - m_ports_from + 1) + m_ports_from;
 162:   }
 163: 
 164:   /**
 165:    * Get the shared port server where the new object can be added. This may
 166:    * result reusing the existing server or instantiating a new server. If the
 167:    * new server is instantiated and the ORB is already running, the server is
 168:    * started.
 169:    */
 170:   protected portServer getPortServer(int type)
 171:   {
 172:     portServer p;
 173: 
 174:     int n;
 175:     if (m_ports_from < m_ports_to)
 176:       n = RANDOM_PORT_ATTEMPTS;
 177:     else
 178:       n = 1;
 179: 
 180:     Ports: for (int a = 0; a < n; a++)
 181:       {
 182:         int port = getPortFromRange(a);
 183:         for (int i = 0; i < portServers.size(); i++)
 184:           {
 185:             p = (portServer) portServers.get(i);
 186:             if (p.s_port == port)
 187:               {
 188:                 return p;
 189:               }
 190:           }
 191:         // The server is not yet instantiated. Instantiate.
 192:         try
 193:           {
 194:             // Check if the port is ok:
 195:             ServerSocket s = socketFactory.createServerSocket(port);
 196:             s.close();
 197: 
 198:             portServer shared;
 199: 
 200:             switch (type)
 201:               {
 202:                 case PARALLEL:
 203:                   shared = new portServer(port);
 204:                   break;
 205: 
 206:                 case SEQUENTIAL:
 207:                   shared = new sharedPortServer(port);
 208:                   break;
 209: 
 210:                 default:
 211:                   throw new InternalError("Invalid server type " + type);
 212:               }
 213: 
 214:             portServers.add(shared);
 215: 
 216:             if (running)
 217:               shared.start();
 218: 
 219:             return shared;
 220:           }
 221:         catch (Exception ex)
 222:           {
 223:             // Port is taken or probably other problems.
 224:             continue Ports;
 225:           }
 226:       }
 227:     throw new NO_RESOURCES("No free port available at " + m_ports_from + "-"
 228:       + m_ports_to, Minor.Ports, CompletionStatus.COMPLETED_NO);
 229:   }
 230: 
 231:   /**
 232:    * Start the ORBs main working cycle (receive invocation - invoke on the local
 233:    * object - send response - wait for another invocation).
 234:    *
 235:    * The method only returns after calling {@link #shutdown(boolean)}.
 236:    */
 237:   public void run()
 238:   {
 239:     if (m_ports_from < 0 || m_ports_to < 0)
 240:       throw new BAD_INV_ORDER("For " + getClass().getName() + " "
 241:         + LISTENER_PORT + " property must be set");
 242: 
 243:     running = true;
 244: 
 245:     // Start all port servers. In the current subclass, the portServers
 246:     // collection must be already filled in.
 247:     Iterator iter = portServers.iterator();
 248: 
 249:     while (iter.hasNext())
 250:       {
 251:         portServer subserver = (portServer) iter.next();
 252: 
 253:         if (!subserver.isAlive())
 254:           {
 255:             // Reuse the current thread for the last portServer.
 256:             if (!iter.hasNext())
 257:               {
 258:                 // Discard the iterator.
 259:                 iter = null;
 260:                 subserver.run();
 261:                 return;
 262:               }
 263:             else
 264:               subserver.start();
 265:           }
 266:       }
 267:   }
 268: 
 269:   /**
 270:    * Get free port from the allowed range. This method instantiates the port
 271:    * server for the returned port.
 272:    */
 273:   public int getFreePort()
 274:     throws BAD_OPERATION
 275:   {
 276:     portServer s = getPortServer(PARALLEL);
 277:     return s.s_port;
 278:   }
 279: 
 280:   /**
 281:    * Connect the given CORBA object to this ORB, explicitly specifying the
 282:    * object key and the identity of the thread (and port), where the object must
 283:    * be served. The identity is normally the POA.
 284:    *
 285:    * The new port server will be started only if there is no one already running
 286:    * for the same identity. Otherwise, the task of the existing port server will
 287:    * be widened, including duty to serve the given object. All objects,
 288:    * connected to a single identity by this method, will process they requests
 289:    * subsequently in the same thread. The method is used when the expected
 290:    * number of the objects is too large to have a single port and thread per
 291:    * object. This method is used by POAs, having a single thread policy.
 292:    *
 293:    * @param object the object, must implement the {@link InvokeHandler})
 294:    * interface.
 295:    * @param key the object key, usually used to identify the object from remote
 296:    * side.
 297:    * @param port the port, where the object must be connected.
 298:    *
 299:    * @throws BAD_PARAM if the object does not implement the
 300:    * {@link InvokeHandler}).
 301:    */
 302:   public void connect_1_thread(org.omg.CORBA.Object object, byte[] key,
 303:     java.lang.Object identity)
 304:   {
 305:     sharedPortServer shared = (sharedPortServer) identities.get(identity);
 306:     if (shared == null)
 307:       {
 308:         shared = (sharedPortServer) getPortServer(SEQUENTIAL);
 309:         identities.put(identity, shared);
 310:         if (running)
 311:           {
 312:             shared.start();
 313:           }
 314:       }
 315: 
 316:     Connected_objects.cObject ref = connected_objects.add(key, object,
 317:       shared.s_port, identity);
 318:     IOR ior = createIOR(ref);
 319:     prepareObject(object, ior);
 320:   }
 321: 
 322:   /**
 323:    * In this type of ORB, the service is started by {@link #getPortServer}. The
 324:    * method below is not in use and should return without action.
 325:    */
 326:   public void startService(IOR ior)
 327:   {
 328:   }
 329: 
 330:   /**
 331:    * Set parameters (additionally search for the port range property).
 332:    */
 333:   protected void set_parameters(Applet applet, Properties props)
 334:   {
 335:     super.set_parameters(applet, props);
 336:     String lp = applet.getParameter(LISTENER_PORT);
 337:     if (lp != null)
 338:       setPortRange(lp);
 339:   }
 340: 
 341:   /**
 342:    * Set parameters (additionally search for the port range property).
 343:    */
 344:   protected void set_parameters(String[] args, Properties props)
 345:   {
 346:     super.set_parameters(args, props);
 347:     String lp = null;
 348: 
 349:     String lpKey = "-" + LISTENER_PORT;
 350: 
 351:     if (args != null)
 352:       if (args.length >= 2)
 353:         {
 354:           for (int i = 0; i < args.length - 1; i++)
 355:             if (args[i].equals(lpKey))
 356:               lp = args[i + 1];
 357:         }
 358: 
 359:     if (lp != null)
 360:       setPortRange(lp);
 361: 
 362:   }
 363: 
 364:   /**
 365:    * Additionally set the port range property, when applicable.
 366:    */
 367:   protected void useProperties(Properties props)
 368:   {
 369:     super.useProperties(props);
 370:     String lp = props.getProperty(LISTENER_PORT);
 371:     if (lp != null)
 372:       setPortRange(lp);
 373:   }
 374: 
 375: }