001 /* 002 Copyright (C) 2001 Lionel Seinturier 003 004 This program is free software; you can redistribute it and/or modify 005 it under the terms of the GNU Lesser General Public License as 006 published by the Free Software Foundation; either version 2 of the 007 License, or (at your option) any later version. 008 009 This program is distributed in the hope that it will be useful, 010 but WITHOUT ANY WARRANTY; without even the implied warranty of 011 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 012 GNU Lesser General Public License for more details. 013 014 You should have received a copy of the GNU Lesser Generaly Public License 015 along with this program; if not, write to the Free Software 016 Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA */ 017 018 package org.objectweb.jac.core.dist; 019 020 import java.net.InetAddress; 021 import java.util.Arrays; 022 import java.util.Hashtable; 023 import org.apache.log4j.Logger; 024 025 /** 026 * Distd is an abstract class for all daemon objects. 027 * Its implementation is protocol dependent (eg CORBA or RMI). 028 * 029 * This is an abstract class that needs to be subclassed 030 * (see org.objectweb.jac.dist.rmi.RMIDistd). 031 * 032 * Daemons hold containers which themselves hold remote objects. 033 * 034 * @see org.objectweb.jac.core.dist.Distd#init() 035 * @see org.objectweb.jac.core.dist.Distd#newContainer(String) 036 * @see org.objectweb.jac.core.dist.Distd#newContainer(String,String) 037 * @see org.objectweb.jac.core.dist.Distd#run() 038 * 039 * @author <a href="http://www-src.lip6.fr/homepages/Lionel.Seinturier/index-eng.html">Lionel Seinturier</a> 040 */ 041 042 abstract public class Distd { 043 static final Logger logger = Logger.getLogger("dist"); 044 045 /** The number of bytes that have been transmitted to the output of 046 this deamon. */ 047 public static long outputCount = 0; 048 /** The number of bytes that have been transmitted to the input of 049 this deamon. */ 050 public static long inputCount = 0; 051 052 /** 053 * Store a string array into a hashtable. 054 * 055 * @param strs the string array 056 * @return the hashtable 057 */ 058 public static Hashtable stringArrayToHashtable(String[] strs) { 059 060 Hashtable ret = new Hashtable(); 061 062 for ( int i=0 ; i < strs.length ; i++ ) { 063 ret.put( strs[i], "" ); 064 } 065 066 return ret; 067 } 068 069 /** 070 * This abstract method initializes the underlying communication 071 * protocol. 072 */ 073 abstract public void init(); 074 075 /** 076 * This abstract method creates a new container. 077 * 078 * @param name the container name 079 * @return the container reference 080 */ 081 abstract protected RemoteContainer newContainer(String name) 082 throws Exception; 083 084 /** 085 * This abstract method creates a new container and 086 * instantiates a given class. 087 * 088 * @param name the container name 089 * @param className the name of the class to instantiate 090 * @return the container reference 091 */ 092 abstract protected RemoteContainer newContainer(String name, String className) 093 throws Exception; 094 095 /** 096 * This abstract method enters the event loop of the underlying 097 * communication protocol. 098 */ 099 abstract public void run(); 100 101 /** 102 * The is the main constructor of Distd. 103 * 104 * @param args command line arguments 105 */ 106 public Distd(String[] args) { 107 108 /** Parse command line arguments */ 109 Hashtable hArgs = parseArguments(args, flags, options); 110 111 112 /** Initialize the underlying communication protocol */ 113 init(); 114 115 try { 116 117 /** Check the flags and options */ 118 verbose = 119 (hArgs.get("v") == null && hArgs.get("-verbose") == null) ? 120 false : true ; 121 122 Object oNames = hArgs.get("_files"); 123 if (oNames == null) 124 usage(); 125 126 String[] names = (String[])oNames; 127 if (names.length != 1) 128 usage(); 129 String name = names[0]; 130 131 132 /** Instantiates a container. */ 133 RemoteContainer container = null; 134 135 if (getClass().getClassLoader() instanceof DistdClassLoader) { 136 logger.debug("DistdClassLoader..."); 137 Object classRepositoryName = hArgs.get("r"); 138 if (classRepositoryName == null) 139 classRepositoryName = hArgs.get("-repository"); 140 if (classRepositoryName == null) 141 classRepositoryName = "s0"; 142 classRepositoryName = getFullHostName((String)classRepositoryName); 143 DistdClassLoader.classRepositoryName = (String)classRepositoryName; 144 referenceContainerName = (String) classRepositoryName; 145 } else { 146 //System.out.println("NOT DistdClassLoader"); 147 } 148 149 Object className = hArgs.get("i"); 150 if (className == null) 151 className = hArgs.get("-init"); 152 153 // we try 20 times to launch it because protocol 154 // initialization may take some time 155 int ok = 20; 156 while (ok>0) { 157 try { 158 if (className == null) { 159 container = newContainer(name); 160 } else { 161 container = newContainer(name, (String)className); 162 } 163 logger.info("--- Distd started."); 164 ok = 0; 165 } catch(Exception e) { 166 ok--; 167 if (ok == 0) { 168 logger.error("ERROR: distd did not start",e); 169 } else { 170 logger.debug("--- Distd starting try, "+ok+" left..."); 171 Thread.sleep(200); 172 } 173 } 174 } 175 176 containers.put(name, container); 177 localContainerName = container.getName(); 178 179 /** Enter the daemon event loop. */ 180 run(); 181 182 if (getClass().getClassLoader() instanceof DistdClassLoader) { 183 ((DistdClassLoader)getClass().getClassLoader()) 184 .bootstrapping = false; 185 } 186 187 } catch(Exception e) { 188 logger.error("Distd "+Arrays.asList(args),e); 189 } 190 } 191 192 /** Store the reference container. */ 193 public static String referenceContainerName = null; 194 195 /** 196 * Get the full host name from an incomplete host name.<p> 197 * 198 * For instance, if the local host name is h1:<p> 199 * 200 * <ul> 201 * <li>"s0" → "//h1/s0"</li> 202 * <li> "//localhost/s1" → "//h1/s0</li> 203 * <li>"//h2/s0" → "//h2/s0"</li> 204 * <li>"\\h2\s0" → "//h2/s0" (for Windows command line compatibility)</li> 205 * </ul> 206 * 207 * @param name the incomplete host name 208 * @return the complete host name 209 */ 210 public static String getFullHostName(String name) { 211 String fullname = ""; 212 name = name.replace('\\','/'); 213 if (!name.startsWith("//")) { 214 try { 215 fullname = "//"+InetAddress.getLocalHost().getHostName()+"/"+name; 216 } catch(Exception e) { 217 logger.error("getFullHostName "+name,e); 218 } 219 } 220 if (name.startsWith("//localhost/")) { 221 try { 222 fullname = "//" + InetAddress.getLocalHost().getHostName() + 223 "/" + name.substring(12); 224 } catch(Exception e) { 225 logger.error("getFullHostName "+name,e); 226 } 227 } 228 if (fullname.equals("")) 229 fullname = name; 230 return fullname; 231 } 232 233 /** Store the reference container name. */ 234 //public static String reference_container_name = null; 235 236 /** Returns the reference container. */ 237 //public static RemoteContainer getReferenceContainer () { 238 // // System.out.println ( "resolving container " + reference_container_name ); 239 // if ( reference_container == null && reference_container_name != null ) { 240 // reference_container = RemoteContainer.resolve( reference_container_name ); 241 // } 242 // return reference_container; 243 //} 244 245 /** Store the local container name. */ 246 protected static String localContainerName = ""; 247 248 /** Get the local container name. */ 249 public static String getLocalContainerName () { 250 return localContainerName; 251 } 252 253 /** Registered flags. */ 254 protected static final String[] flags = {"v","-verbose"}; 255 256 /** Registered options. */ 257 protected static final String[] options = {"i","-init","r","-repository"}; 258 259 /** verbose tells whether information message should be printed or not */ 260 protected static boolean verbose = false; 261 262 263 /** Display command line arguments. */ 264 265 protected static void usage() { 266 System.out.println( 267 "Usage: java org.objectweb.jac.core.dist.Distd [options] name\n" + 268 "\n" + 269 "-v --verbose: display system informations\n" + 270 "-i --init classname: create an instance of classname\n" + 271 "-r --repository sitename: the site where the classes repository is located (the loader will load the classes from this site if possible -- else from the local file system)\n" + 272 "name: the daemon identifier" 273 ); 274 System.exit(1); 275 } 276 277 /** 278 * Parse command line arguments composed of flags, options and files. 279 * 280 * @param args command line arguments 281 * @param flags registered flags (e.g. -verbose, -quiet, etc.) 282 * @param options registered options (e.g. -d classes, etc.) 283 * @return a hashtable containing 3 types of entries: 284 * one for each flag and option, and one for the files. 285 * If an unregistered flag or option is encountered the 286 * usage method is called. 287 * The value associated to the entries is a empty string 288 * for flags, 289 * and the option value (e.g. classes/) for options. 290 * Files are stored with an entry whose key is "_files", 291 * and whose value is an array of strings. 292 */ 293 protected static Hashtable parseArguments(String[] args, 294 String[] flags, 295 String[] options) { 296 297 /** Store flags and options in hashtables */ 298 299 Hashtable hFlags = stringArrayToHashtable(flags); 300 Hashtable hOptions = stringArrayToHashtable(options); 301 302 303 /** Scan the arguments */ 304 305 Hashtable result = new Hashtable(); 306 307 String flagOrOption; 308 Object flag, option; 309 310 for (int i=0; i<args.length; i++) { 311 if (args[i].startsWith("-")) { 312 // This is either a flag or an option 313 flagOrOption = args[i].substring(1); 314 flag = hFlags.get(flagOrOption); 315 option = hOptions.get(flagOrOption); 316 317 if (flag != null) { 318 result.put(flagOrOption, ""); 319 } else if (option != null) { 320 // Move to the value of the option 321 i++; 322 if (i >= args.length) { 323 usage(); 324 } 325 result.put(flagOrOption,args[i]); 326 } else { 327 usage(); 328 } 329 } else { 330 // This is neither a flag, nor an option. 331 // This must be the begining of file names. 332 int numberOfFiles = args.length - i; 333 String[] files = new String[numberOfFiles]; 334 System.arraycopy(args, i, files, 0, numberOfFiles); 335 336 result.put("_files", files); 337 338 return result; 339 } 340 } 341 342 return result; 343 } 344 345 /** Containers hold by the current daemon. */ 346 protected static Hashtable containers = new Hashtable(); 347 348 349 /** 350 * Test whether the daemon contains a given container. 351 * 352 * @param container the container's name 353 * @return true if the container is contained in the current daemon 354 */ 355 public static boolean containsContainer(RemoteContainer container) { 356 return containers.values().contains(container); 357 } 358 }