1. /*
  2. * @(#)BootstrapServer.java 1.36 03/01/23
  3. *
  4. * Copyright 2003 Sun Microsystems, Inc. All rights reserved.
  5. * SUN PROPRIETARY/CONFIDENTIAL. Use is subject to license terms.
  6. */
  7. package com.sun.corba.se.internal.CosNaming;
  8. import java.lang.Thread;
  9. import java.util.Enumeration;
  10. import java.util.Properties;
  11. import java.io.File;
  12. import java.io.FileInputStream;
  13. import java.io.FileOutputStream;
  14. import org.omg.CORBA.*;
  15. import com.sun.corba.se.internal.iiop.*;
  16. import com.sun.corba.se.internal.core.*;
  17. import com.sun.corba.se.internal.orbutil.CorbaResourceUtil;
  18. /**
  19. * Class BootstrapServer is the main loop for the bootstrap server
  20. * implementation, listening for new connections and spawning threads
  21. * to handle requests on each new connection.
  22. * It uses BootstrapRequestHandler objects to actually
  23. * serve requests on the connections. The supported services is a
  24. * special properties object that ensures all accesses are synchronized;
  25. * if a file is supplied then the properties are loaded from and stored to
  26. * that file. The properties object is shared among all threads.
  27. * @see BootstrapServiceProperties
  28. * @see BootstrapRequestHandler
  29. */
  30. public class BootstrapServer
  31. {
  32. /**
  33. * Constructs a new BootstrapServer object and the
  34. * BootstrapServiceProperties object shared among all threads.
  35. * @param port the port on which the server will listen.
  36. * @parma file a file containing the supported properties
  37. * @param svcs a Properties defining the set of supported services.
  38. */
  39. public BootstrapServer(com.sun.corba.se.internal.iiop.ORB orb, int port,
  40. File file, Properties svcs)
  41. {
  42. listenerPort = port;
  43. this.orb = orb;
  44. // Create a properties object with the file and properties
  45. supportedServices = new BootstrapServiceProperties(file,svcs);
  46. // Create the server SC
  47. serverSC = new BootstrapRequestHandler(orb,supportedServices);
  48. // Register it with the orb for big and little indians.. eh, endians.
  49. orb.getSubcontractRegistry().registerBootstrapServer(serverSC);
  50. }
  51. /**
  52. * Start the BootstrapServer. It creates a listener thread on
  53. * the specified listenerport which will serve requests.
  54. */
  55. public void start() {
  56. // Create a listener thread on the port - this will process requests
  57. orb.getServerGIOP().getBootstrapEndpoint(listenerPort);
  58. }
  59. /**
  60. * Adds a service to the supported set of services. Delegates to
  61. * the shared BootstrapServiceProperties object.
  62. * @param key the key under which the service is known.
  63. * @param val the stringified object reference for the service.
  64. * @param save a boolean which is true if the key,value pair should be saved.
  65. * @return any previously bound value under the key.
  66. */
  67. public String addService(String key, String val, boolean save) {
  68. // Don't hesitate - delegate.
  69. return supportedServices.put(key,val,save);
  70. }
  71. /**
  72. * Accessor method to get the Initial Service based on the Key.
  73. * @param key the service name.
  74. *
  75. * @return stringified IOR previously registered or null if none registered
  76. */
  77. public String getService( String key ) {
  78. return supportedServices.get( key );
  79. }
  80. /**
  81. * Main startup routine in case the bootstrap server is run standalone.
  82. * It first determines the port on which to listen, checks that the
  83. * specified file is available, and then creates the BootstrapServer object
  84. * that will service the requests.
  85. * @param args the command-line arguments to the main program.
  86. */
  87. public static final void main(String[] args)
  88. {
  89. String propertiesFilename = null;
  90. // Get an orb object. Narrow to specific ORB so we can use Wait().
  91. Properties props = new Properties() ;
  92. props.put( "org.omg.CORBA.ORBClass", "com.sun.corba.se.internal.iiop.ORB" ) ;
  93. com.sun.corba.se.internal.iiop.ORB orb = (com.sun.corba.se.internal.iiop.ORB)
  94. org.omg.CORBA.ORB.init(args,props);
  95. // Determine the initial bootstrap port to use
  96. int initialPort = 900; // by convention
  97. try {
  98. // Try environment
  99. String ips = System.getProperty("org.omg.CORBA.ORBInitialPort");
  100. if (ips != null && ips.length() > 0)
  101. initialPort = java.lang.Integer.parseInt(ips);
  102. } catch (java.lang.NumberFormatException e) {
  103. // do nothing
  104. }
  105. // Process arguments
  106. for (int i=0;i<args.length;i++) {
  107. // Look for the filename
  108. if (args[i].equals("-InitialServicesFile") && i < args.length -1) {
  109. propertiesFilename = args[i+1];
  110. }
  111. // Was the initial port specified? If so, override
  112. if (args[i].equals("-ORBInitialPort") && i < args.length-1) {
  113. initialPort = java.lang.Integer.parseInt(args[i+1]);
  114. }
  115. }
  116. if (propertiesFilename == null) {
  117. System.out.println(CorbaResourceUtil.getText("bootstrap.usage", "BootstrapServer"));
  118. return;
  119. }
  120. // Create a file
  121. File file = new File(propertiesFilename);
  122. // Verify that if it exists, it is readable
  123. if (file.exists() == true && file.canRead() == false) {
  124. System.err.println(CorbaResourceUtil.getText("bootstrap.filenotreadable", file.getAbsolutePath()));
  125. return;
  126. }
  127. // Success: start up
  128. System.out.println(CorbaResourceUtil.getText("bootstrap.success", Integer.toString(initialPort), file.getAbsolutePath()));
  129. // We are ready: start the server with the computed file and
  130. // with an empty set of properties: it will be read from the file.
  131. BootstrapServer server = new BootstrapServer(orb,
  132. initialPort,
  133. file,
  134. new Properties());
  135. // Start it
  136. server.start();
  137. // Stick around
  138. java.lang.Object sync = new java.lang.Object();
  139. try {
  140. synchronized (sync) { sync.wait();}
  141. } catch (Exception ex) {}
  142. }
  143. public final static boolean debug = false;
  144. private int listenerPort;
  145. private Thread listenerThread;
  146. private BootstrapServiceProperties supportedServices;
  147. private BootstrapRequestHandler serverSC;
  148. private com.sun.corba.se.internal.iiop.ORB orb;
  149. }
  150. /**
  151. * Class BootstrapServiceProperties implements a synchronized properties set
  152. * that automatically gets loaded from the supplied file if the modification
  153. * timestamp changes, or stored to the file when updated. Not providing a
  154. * file implies running in memory with no persistent storage.
  155. * It only implements get(), put() and keys(); all of
  156. * these methods are synchronized to ensure correct updates.
  157. */
  158. final class BootstrapServiceProperties
  159. {
  160. /**
  161. * Constructs a BootstrapServiceProperties object.
  162. * The file and properties object reference are stored; loading is
  163. * done on demand.
  164. * @param pFile a file object which is the file containing the Properties.
  165. */
  166. public BootstrapServiceProperties(File pFile, Properties props) {
  167. // Do not bother loading now; wait for first request
  168. propFile = pFile;
  169. savedProps = props;
  170. allProps = new Properties(savedProps);
  171. }
  172. /**
  173. * Returns the value associated with the key, if any.
  174. * First the check() method is called to make sure we have an up to
  175. * date copy, and then the getProperty() method is called on the
  176. * Properties object. This method is synchronized so access gets
  177. * serialized.
  178. * @param key a string which is the key to look up.
  179. * @return a string which is the value associated with the key, or null
  180. * if no such key exists.
  181. */
  182. public synchronized String get(String key) {
  183. // Check first, then call properties
  184. this.check();
  185. return allProps.getProperty(key);
  186. }
  187. /**
  188. * Stores a value associated with a key, and optionally writes the
  189. * key,value pair to a file.
  190. * This method is synchronized so access gets
  191. * serialized.
  192. * @param key a string which is the key to store the value under.
  193. * @param val a string which is the value to store.
  194. * @param save a boolean which is true if the key,value pair should be saved.
  195. * @return any previously bound value.
  196. */
  197. public synchronized String put(String key,String val, boolean save) {
  198. // If we're not supposed to save it, just put it in and be done
  199. if (!save)
  200. return (String)allProps.put(key,val);
  201. // Check first, then call properties
  202. String s = (String)savedProps.put(key,val);
  203. if (propFile != null) {
  204. try {
  205. // Store file
  206. FileOutputStream fileOS = new FileOutputStream(propFile);
  207. // Clear and reload
  208. savedProps.save(fileOS,null);
  209. fileOS.close();
  210. // Update timestamp
  211. fileModified = propFile.lastModified();
  212. } catch (java.io.FileNotFoundException e) {
  213. System.err.println(CorbaResourceUtil.getText("bootstrap.filenotfound", propFile.getAbsolutePath()));
  214. } catch (java.io.IOException e) {
  215. System.err.println(CorbaResourceUtil.getText("bootstrap.exception",propFile.getAbsolutePath(), e.toString()));
  216. }
  217. }
  218. return s;
  219. }
  220. /**
  221. * Returns an array of strings containing the list of available keys.
  222. * First the check() method is called to make sure we have an up to
  223. * date copy, and then an enumeration is created to iterate through
  224. * the properties object, collecting all keys in a string array.
  225. * @return an array of strings containing the available keys in the
  226. * Properties object.
  227. */
  228. public synchronized String[] keys() {
  229. // Ensure up to date
  230. this.check();
  231. // Compute list of keys
  232. String[] services = null;
  233. int size = allProps.size() + savedProps.size();
  234. if (size > 0) {
  235. services = new String[size];
  236. // Obtain all the keys from the property object
  237. Enumeration theKeys = allProps.propertyNames();
  238. for (int index=0;theKeys.hasMoreElements();index++) {
  239. services[index] = (String)theKeys.nextElement();
  240. }
  241. }
  242. return services;
  243. }
  244. /**
  245. * Checks the lastModified() timestamp of the file and optionally
  246. * re-reads the Properties object from the file if newer.
  247. */
  248. protected void check() {
  249. // Is there a file to read?
  250. if (propFile == null)
  251. return;
  252. // Assume we already have the object lock
  253. long lastMod = propFile.lastModified();
  254. // Up to date?
  255. if (lastMod > fileModified) {
  256. try {
  257. // No, load it again.
  258. FileInputStream fileIS = new FileInputStream(propFile);
  259. // Clear and reload
  260. savedProps.clear();
  261. savedProps.load(fileIS);
  262. fileIS.close();
  263. // Set new timestamp
  264. fileModified = lastMod;
  265. } catch (java.io.FileNotFoundException e) {
  266. System.err.println(CorbaResourceUtil.getText("bootstrap.filenotfound", propFile.getAbsolutePath()));
  267. } catch (java.io.IOException e) {
  268. System.err.println(CorbaResourceUtil.getText("bootstrap.exception",propFile.getAbsolutePath(), e.toString()));
  269. }
  270. }
  271. }
  272. private File propFile;
  273. private long fileModified;
  274. private Properties savedProps;
  275. private Properties allProps;
  276. }
  277. /**
  278. * Class BootstrapRequestHandler handles the requests coming to the
  279. * BootstrapServer. It implements Server so that it can be registered
  280. * as a subcontract. It is passed a BootstrapServiceProperties object
  281. * which contains
  282. * the supported ids and their values for the bootstrap service. This
  283. * Properties object is only read from, never written to, and is shared
  284. * among all threads.
  285. * <p>
  286. * The BootstrapRequestHandler responds primarily to GIOP requests,
  287. * but LocateRequests are (reluctantly) handled for graceful interoperability.
  288. * The BootstrapRequestHandler handles one request at a time.
  289. */
  290. final class BootstrapRequestHandler implements ServerSubcontract
  291. {
  292. public static final int OBJECT_KEY_BAD_LEN = 10000;
  293. public static final int OPERATION_NOT_GET_OR_LIST = 10001;
  294. public static final int JAVA_RUNTIME_EXC_CAUGHT = 10002;
  295. public static final int JAVA_EXC_CAUGHT = 10003;
  296. private com.sun.corba.se.internal.iiop.ORB orb;
  297. private BootstrapServiceProperties props;
  298. private static final boolean debug = false;
  299. public BootstrapRequestHandler(com.sun.corba.se.internal.iiop.ORB orb,
  300. BootstrapServiceProperties props) {
  301. this.orb = orb;
  302. this.props = props;
  303. }
  304. public void destroyObjref(java.lang.Object objref)
  305. {
  306. }
  307. /**
  308. * Dispatch is called by the ORB and will serve get(key) and list()
  309. * invocations on the initial object key.
  310. */
  311. public com.sun.corba.se.internal.core.ServerResponse dispatch(
  312. com.sun.corba.se.internal.core.ServerRequest request)
  313. {
  314. com.sun.corba.se.internal.core.ServerResponse response = null;
  315. try {
  316. MarshalInputStream is = (MarshalInputStream) request;
  317. String method = request.getOperationName();
  318. response = request.createResponse(null);
  319. MarshalOutputStream os = (MarshalOutputStream) response;
  320. if (method.equals("get")) {
  321. // Get the name of the requested service
  322. String service_key = is.read_string();
  323. // Look it up
  324. String service_value = props.get(service_key);
  325. org.omg.CORBA.Object service_obj = null;
  326. if (service_value != null) {
  327. try {
  328. service_obj = orb.string_to_object(service_value);
  329. } catch (org.omg.CORBA.SystemException e) {}
  330. }
  331. if (debug)
  332. System.out.println("BootstrapRequestHandler: get(" +
  333. service_key + ") -> " + service_value);
  334. // Write reply value
  335. os.write_Object(service_obj);
  336. } else if (method.equals("list")) {
  337. // Get all known keys
  338. String keys[] = props.keys();
  339. int keys_len = 0;
  340. if (keys == null) keys = new String[0];
  341. else keys_len = keys.length;
  342. if (debug)
  343. System.out.println("BootstrapRequestHandler: list() -> " +
  344. keys_len + " entries.");
  345. // Write length of sequence
  346. os.write_long(keys_len);
  347. // Write each string in the sequence
  348. for (int i=0;i<keys_len;i++) {
  349. os.write_string(keys[i]);
  350. }
  351. } else {
  352. // Bad operation
  353. if (debug) System.out.println(method);
  354. throw new BAD_OPERATION(OPERATION_NOT_GET_OR_LIST,
  355. CompletionStatus.COMPLETED_NO);
  356. }
  357. } catch (org.omg.CORBA.SystemException ex) {
  358. // Marshal the exception thrown
  359. if (debug) ex.printStackTrace();
  360. response = request.createSystemExceptionResponse(ex, null);
  361. } catch (java.lang.RuntimeException ex) {
  362. // Unknown exception
  363. if (debug) ex.printStackTrace();
  364. response = request.createSystemExceptionResponse(
  365. new UNKNOWN(ex.toString(),
  366. JAVA_RUNTIME_EXC_CAUGHT,
  367. CompletionStatus.COMPLETED_NO),
  368. null);
  369. } catch (java.lang.Exception ex) {
  370. // Unknown exception
  371. if (debug) ex.printStackTrace();
  372. response = request.createSystemExceptionResponse(
  373. new UNKNOWN(ex.toString(),
  374. JAVA_EXC_CAUGHT,
  375. CompletionStatus.COMPLETED_NO),
  376. null);
  377. }
  378. return response;
  379. }
  380. /**
  381. * Locates the object mentioned in the locate requests, and returns
  382. * object here iff the object is the initial object key. A SystemException
  383. * thrown if the object key is not the initial object key.
  384. */
  385. public com.sun.corba.se.internal.core.IOR locate(
  386. com.sun.corba.se.internal.ior.ObjectKey objectKey) {
  387. return null;
  388. }
  389. /**
  390. * Not implemented; throws org.omg.CORBA.NO_IMPLEMENT().
  391. */
  392. public java.lang.Object createObjref( IOR ior )
  393. {
  394. throw new NO_IMPLEMENT();
  395. }
  396. /**
  397. * Not implemented; throws org.omg.CORBA.NO_IMPLEMENT().
  398. */
  399. public java.lang.Object createObjref(byte[] key,
  400. java.lang.Object servant)
  401. {
  402. throw new NO_IMPLEMENT();
  403. }
  404. /**
  405. * Not implemented; throws org.omg.CORBA.NO_IMPLEMENT().
  406. */
  407. public byte[] getKey(org.omg.CORBA.Object objref)
  408. {
  409. throw new NO_IMPLEMENT();
  410. }
  411. /**
  412. * Not implemented; throws org.omg.CORBA.NO_IMPLEMENT().
  413. */
  414. public int getImplId(org.omg.CORBA.Object objref)
  415. {
  416. throw new NO_IMPLEMENT();
  417. }
  418. /**
  419. * isServantSupported should return null
  420. */
  421. public boolean isServantSupported()
  422. {
  423. return false;
  424. }
  425. /**
  426. * Not implemented; throws org.omg.CORBA.NO_IMPLEMENT().
  427. */
  428. public java.lang.Object getServant(IOR ior) {
  429. throw new NO_IMPLEMENT();
  430. }
  431. /**
  432. * Not implemented; throws org.omg.CORBA.NO_IMPLEMENT().
  433. */
  434. public void setOrb(com.sun.corba.se.internal.core.ORB orb) {
  435. throw new NO_IMPLEMENT();
  436. }
  437. /**
  438. * Not implemented; throws org.omg.CORBA.NO_IMPLEMENT().
  439. */
  440. public void setId(int scid) {
  441. throw new NO_IMPLEMENT();
  442. }
  443. /**
  444. * Not implemented; throws org.omg.CORBA.NO_IMPLEMENT().
  445. */
  446. public int getId() {
  447. throw new NO_IMPLEMENT();
  448. }
  449. /**
  450. * Not implemented; throws org.omg.CORBA.NO_IMPLEMENT().
  451. */
  452. public java.lang.Class getClientSubcontractClass() {
  453. throw new NO_IMPLEMENT();
  454. }
  455. }