PageRenderTime 46ms CodeModel.GetById 18ms RepoModel.GetById 0ms app.codeStats 0ms

/ev/endrov/starter/Start.java

https://github.com/mahogny/Endrov
Java | 531 lines | 360 code | 71 blank | 100 comment | 88 complexity | 314fb633243de47222f6c056f921bb11 MD5 | raw file
  1. /***
  2. * Copyright (C) 2010 Johan Henriksson
  3. * This code is under the Endrov / BSD license. See www.endrov.net
  4. * for the full text and how to cite.
  5. */
  6. package endrov.starter;
  7. import java.io.*;
  8. import java.lang.reflect.Method;
  9. import java.net.URL;
  10. import java.util.*;
  11. import javax.swing.*;
  12. import endrov.core.EvBuild;
  13. /**
  14. * Start Endrov
  15. *
  16. * @author Johan Henriksson
  17. */
  18. public class Start
  19. {
  20. public static void main(String[] args)
  21. {
  22. new Start().run(args);
  23. }
  24. public String mainClass="";
  25. private final String javaver=System.getProperty("java.specification.version");
  26. private final String arch=System.getProperty("os.arch").toLowerCase();
  27. private final int javaVerMajor=Integer.parseInt(javaver.substring(0,javaver.indexOf('.')));
  28. private final int javaVerMinor=Integer.parseInt(javaver.substring(javaver.indexOf('.')+1));
  29. private String OS=System.getProperty("os.name").toLowerCase();
  30. private String javaexe="java";
  31. private LinkedList<String> platformExt=new LinkedList<String>();
  32. public LinkedList<String> jarfiles=new LinkedList<String>();
  33. public LinkedList<String> binfiles=new LinkedList<String>();
  34. public void collectSystemInfo(String path)
  35. {
  36. collectSystemInfo(new File(path));
  37. }
  38. /**
  39. * Collection information such as location of JAR-files etc
  40. */
  41. public void collectSystemInfo(File path)
  42. {
  43. platformExt.clear();
  44. //Detect architecture
  45. if(arch.equals("ppc")) //PowerPC (mac G4 and G5)
  46. platformExt.add("ppc");
  47. else if(arch.equals("x86_64") || arch.equals("amd64"))
  48. platformExt.add("amd64");
  49. else if(arch.equals("sparc"))
  50. platformExt.add("sparc");
  51. else
  52. platformExt.add("x86");
  53. //Detect OS
  54. if(OS.equals("mac os x"))
  55. platformExt.add("mac");
  56. else if(OS.startsWith("windows"))
  57. {
  58. platformExt.add("windows");
  59. File jrejava=new File("c:\\Program Files\\Java\\jre6\\bin\\java.exe");
  60. if(jrejava.exists())
  61. {
  62. javaexe="\""+jrejava.toString()+"\"";
  63. System.out.println("Using JRE java");
  64. }
  65. }
  66. else if(OS.startsWith("linux"))
  67. platformExt.add("linux");
  68. else if(OS.startsWith("sunos"))
  69. platformExt.add("solaris");
  70. else
  71. {
  72. JOptionPane.showMessageDialog(null,
  73. "Your OS + CPU combination is not supported at this moment. We would be happy if you got in\n" +
  74. "touch so we can support for your platform. If you want to do it yourself it is easy: Get\n" +
  75. "libraries for your platform (JAI and JOGL), edit endrov/starter/StartGUI.java and recompile.");
  76. System.exit(1);
  77. }
  78. /**
  79. * Have to add system extensions and libraries as well when the system class loader is not used
  80. */
  81. String libpath=System.getProperty("java.library.path");
  82. if(libpath!=null)
  83. {
  84. StringTokenizer stok=new StringTokenizer(libpath,File.pathSeparator);
  85. while(stok.hasMoreTokens())
  86. {
  87. String s=stok.nextToken();
  88. if(!s.equals(".")) //TODO: or path?
  89. {
  90. File root=new File(s);
  91. if(root.exists())
  92. for(File f:root.listFiles())
  93. if(f.getName().endsWith(".jar") || f.getName().endsWith(".zip")) //QTJava is .zip
  94. jarfiles.add(f.getAbsolutePath());
  95. }
  96. }
  97. }
  98. //Collect jarfiles
  99. jarfiles.add(path.getAbsolutePath());
  100. collectJarsAndBins(jarfiles, binfiles, new File(path,"libs"), platformExt);
  101. //Collect DLLs/equivalent from java.library.path
  102. if(libpath!=null)
  103. {
  104. StringTokenizer stok=new StringTokenizer(libpath,File.pathSeparator);
  105. while(stok.hasMoreTokens())
  106. {
  107. String s=stok.nextToken();
  108. if(!s.equals(".")) //TODO: or path?
  109. {
  110. //jarfiles.add(s);
  111. binfiles.add(s);
  112. }
  113. }
  114. }
  115. }
  116. /**
  117. * Produce a :-string out of all jars
  118. */
  119. public String getJarString()
  120. {
  121. String jarstring="";//endrovRoot.getAbsolutePath();
  122. for(String s:jarfiles)
  123. {
  124. if(!jarstring.equals(""))
  125. jarstring+=File.pathSeparatorChar;
  126. jarstring+=s;
  127. }
  128. return jarstring;
  129. }
  130. /**
  131. * Produce a :-string out of all binary directories
  132. */
  133. public String getBinString()
  134. {
  135. String binstring="";
  136. for(String s:binfiles)
  137. {
  138. if(!binstring.equals(""))
  139. binstring=binstring+File.pathSeparatorChar;
  140. binstring=binstring+s;
  141. }
  142. return binstring;
  143. }
  144. /**
  145. * Add jar file to list. Show it if requested
  146. */
  147. private static void addJar(LinkedList<String> v, String toadd)
  148. {
  149. v.addFirst(toadd);
  150. }
  151. /**
  152. * Get all jars and add them with path to vector.
  153. * Recurses when it finds a directory ending with _inc.
  154. */
  155. private static void collectJarsAndBins(LinkedList<String> v,LinkedList<String> binfiles,File p, Collection<String> platformExt)
  156. {
  157. if(p.exists())
  158. for(File sub:p.listFiles())
  159. {
  160. if(sub.isFile() && (sub.getName().endsWith(".jar") || sub.getName().endsWith(".zip")))
  161. addJar(v,sub.getAbsolutePath());
  162. else if(sub.isFile() && (sub.getName().endsWith(".paths")))
  163. {
  164. //File containing list of jars or libraries to include.
  165. //This is used on systems where jars are present already e.g. Debian, and packaging scripts
  166. //can provide links. An alternative would be to let these tools provide symlinks instead
  167. try
  168. {
  169. BufferedReader input = new BufferedReader(new FileReader(sub));
  170. String line;
  171. while((line=input.readLine())!=null)
  172. {
  173. if(line.startsWith("j:"))
  174. addJar(v,line.substring(2)); //j:
  175. else if(line.startsWith("b:"))
  176. {
  177. binfiles.add(line.substring(2)); //b:
  178. }
  179. }
  180. input.close();
  181. }
  182. catch (Exception e)
  183. {
  184. e.printStackTrace();
  185. }
  186. }
  187. else if(sub.isDirectory() && sub.getName().endsWith("_inc") && !sub.getName().startsWith(".") && !sub.getName().equals("unused"))
  188. collectJarsAndBins(v,binfiles, sub, platformExt);
  189. else
  190. {
  191. for(String oneExt:platformExt)
  192. if(sub.isDirectory() && sub.getName().equals("bin_"+oneExt))
  193. {
  194. collectJarsAndBins(v,binfiles, sub, platformExt);
  195. String toadd=sub.getAbsolutePath();
  196. binfiles.add(toadd);
  197. addJar(v,toadd);
  198. }
  199. }
  200. }
  201. }
  202. /**
  203. * Run Endrov given command line.
  204. */
  205. public void run(String[] argsa)
  206. {
  207. //boolean printMacStarter=false;
  208. boolean hasSpecifiedLibdir=false;
  209. boolean printCommand=false;
  210. boolean useClassLoader=false;
  211. boolean printClassPath=false;
  212. File javaenvFile=null;
  213. File basedir=new File(".");
  214. // int numNonflagArg=0;
  215. List<String> args=new LinkedList<String>();
  216. for(int argi=0;argi<argsa.length;argi++)
  217. {
  218. String curarg=argsa[argi];
  219. if(curarg.equals("--printcommand"))
  220. printCommand=true;
  221. else if(args.contains("--version"))
  222. {
  223. //Print current version. need to be put in starter jar to work
  224. System.out.println("Endrov "+EvBuild.version);
  225. System.exit(0);
  226. }
  227. else if(curarg.equals("--cp2"))
  228. {
  229. //Additional jars to add to classpath
  230. jarfiles.add(argsa[argi+1]);
  231. argi++;
  232. }
  233. else if(curarg.equals("--libpath2"))
  234. {
  235. binfiles.add(argsa[argi+1]);
  236. argi++;
  237. }
  238. else if(curarg.equals("--basedir"))
  239. {
  240. //Override current directory
  241. basedir=new File(argsa[argi+1]);
  242. argi++;
  243. }
  244. else if(curarg.equals("--main"))
  245. {
  246. //Override current directory
  247. mainClass=argsa[argi+1];
  248. argi++;
  249. }
  250. else if(curarg.equals("--javaenv"))
  251. {
  252. //Override current directory
  253. javaenvFile=new File(argsa[argi+1]);
  254. argi++;
  255. }
  256. else if(curarg.equals("--archinfo"))
  257. {
  258. //Show info about the system
  259. System.out.println("This system runs OS:"+OS+" with java:"+javaver+" on arch:"+arch);
  260. System.exit(0);
  261. }
  262. else if(curarg.equals("--classload"))
  263. useClassLoader=true;
  264. else if(curarg.equals("--printcp"))
  265. printClassPath=true;
  266. else if(curarg.equals("--help"))
  267. {
  268. System.out.println("--printcommand, version, cp2, libpath2, basedir, main, javaenv, archinfo, classload, printcp, help");
  269. System.exit(0);
  270. }
  271. else
  272. {
  273. // if(!curarg.startsWith("--"))
  274. // numNonflagArg++;
  275. args.add(curarg);
  276. }
  277. }
  278. collectSystemInfo(basedir);
  279. if(printClassPath)
  280. {
  281. String out=".";
  282. for(String s:jarfiles)
  283. out=out+":"+s;
  284. System.out.print(out);
  285. System.exit(0);
  286. }
  287. if(javaVerMajor>1 || (javaVerMajor==1 && javaVerMinor>=5))
  288. {
  289. if(useClassLoader)
  290. runWithClassLoader(args.toArray(new String[]{}));
  291. else
  292. runBootstrap(hasSpecifiedLibdir,printCommand, javaenvFile, basedir, args.toArray(new String[]{}));
  293. }
  294. else
  295. JOptionPane.showMessageDialog(null, "Your version of Java is too old. It must be at least 1.5");
  296. }
  297. /**
  298. * This is for convenience, those who run the .jar-file straight without a wrapper script. It reinvokes Endrov by running
  299. * a command, now with proper VM settings (memory), and tells it to run the classloader
  300. */
  301. private void runBootstrap(boolean hasSpecifiedLibdir, boolean printCommand, File javaenvFile, File basedir, String[] argsa)
  302. {
  303. try
  304. {
  305. //Generate command
  306. LinkedList<String> cmdarg=new LinkedList<String>();
  307. cmdarg.add(javaexe);
  308. cmdarg.add("-cp");
  309. //cmdarg.add(".");
  310. cmdarg.add(basedir.toString());
  311. //Find java env file
  312. if(javaenvFile==null)
  313. {
  314. for(String s:platformExt)
  315. {
  316. javaenvFile=new File(new File("config"),"javaenv."+s+".txt");
  317. if(javaenvFile.exists())
  318. break;
  319. }
  320. }
  321. //Add arguments from environment file
  322. if(javaenvFile.exists())
  323. {
  324. System.out.println("Using environment from "+javaenvFile);
  325. BufferedReader envReader=new BufferedReader(new FileReader(javaenvFile));
  326. String line=envReader.readLine();
  327. if(line!=null)
  328. {
  329. StringTokenizer envTokenizer=new StringTokenizer(line," ");
  330. while(envTokenizer.hasMoreTokens())
  331. {
  332. String tok=envTokenizer.nextToken();
  333. cmdarg.add(tok);
  334. System.out.println("Java environment flag: "+tok);
  335. }
  336. }
  337. envReader.close();
  338. }
  339. System.out.println("Using environment: "+javaenvFile);
  340. //What to run? Doesn't matter because we specify the main class
  341. cmdarg.add("endrov.starter.StartGUI");
  342. //Run the same main class
  343. cmdarg.add("--main");
  344. cmdarg.add(mainClass);
  345. //Change to classloading mode
  346. cmdarg.add("--classload");
  347. //additional arguments?
  348. for(String s:argsa)
  349. cmdarg.add(s);
  350. //Run process
  351. ProcessBuilder pb=new ProcessBuilder("");
  352. pb.command(cmdarg);
  353. if(printCommand)
  354. {
  355. String totalCmd="";
  356. for(String s:pb.command())
  357. totalCmd+=s+" ";
  358. System.out.println(totalCmd);
  359. }
  360. final Process p=pb.start();
  361. //Pass on errors
  362. new Thread()
  363. {
  364. public synchronized void run()
  365. {
  366. BufferedReader br = new BufferedReader(new InputStreamReader(p.getErrorStream()));
  367. String line;
  368. try
  369. {
  370. while ( (line = br.readLine()) != null)
  371. {
  372. if(line.startsWith("Could not create the Java Virtual Machine"))
  373. {
  374. JOptionPane.showMessageDialog(null, "Trouble creating virtual machine. Try to reduce the ammount of memory allocated");
  375. //normal output follows
  376. //Error occurred during initialization of VM
  377. //Could not reserve enough space for object heap
  378. }
  379. System.err.println(line);
  380. }
  381. }
  382. catch (IOException e)
  383. {
  384. e.printStackTrace();
  385. }
  386. }
  387. }.start();
  388. //Pass on output
  389. BufferedReader br = new BufferedReader(new InputStreamReader(p.getInputStream()));
  390. String line;
  391. while ( (line = br.readLine()) != null)
  392. System.out.println(line);
  393. try
  394. {
  395. p.waitFor();
  396. }
  397. catch (InterruptedException e)
  398. {
  399. e.printStackTrace();
  400. }
  401. System.out.println("Process exited");
  402. }
  403. catch (IOException e)
  404. {
  405. JOptionPane.showMessageDialog(null, "Was unable to exec command. Full error:\n"+e.getMessage());
  406. e.printStackTrace();
  407. }
  408. }
  409. /**
  410. * Start Endrov through class loader. This is how the final step should be done.
  411. * * it allows better control of where files are loaded from and when, needed for plugin architecture
  412. * * single process - killing this process will kill everything, unlike when Endrov runs as a subprocess
  413. * * jar-files and shared objects need not be passed on the command line which makes Endrov difficult to start on Mac
  414. * and creates a shitty ps -ax
  415. * but:
  416. * * memory settings cannot be changed since it is a VM option. This requires a startup script or the bootstrap run
  417. */
  418. private void runWithClassLoader(String[] argsa)
  419. {
  420. try
  421. {
  422. LinkedList<URL> urls=new LinkedList<URL>();
  423. for(String s:jarfiles)
  424. urls.add(new File(s).toURI().toURL());
  425. //Important: Must NOT use the system class loader - it will take over for current directory
  426. //and fail to load JAR files
  427. System.out.println("Bin files: "+binfiles);
  428. ResourceClassLoader cload=new ResourceClassLoader(urls.toArray(new URL[]{}),binfiles, null);
  429. Class<?> cl=cload.loadClass(mainClass);
  430. Method mMethod=cl.getMethod("main", String[].class);
  431. mMethod.invoke(null, new Object[]{argsa});
  432. // cload.close(); only java7
  433. }
  434. catch (Exception e)
  435. {
  436. e.printStackTrace();
  437. System.out.println("Failing to load \""+mainClass+"\"");
  438. }
  439. }
  440. }
  441. /*
  442. AIX
  443. Digital Unix
  444. FreeBSD
  445. HP UX
  446. Irix
  447. Linux
  448. Mac OS
  449. MPE/iX
  450. Netware 4.11
  451. OS/2
  452. Solaris
  453. Windows 2000
  454. Windows 95
  455. Windows 98
  456. Windows NT
  457. Windows XP*/
  458. //### Detect OS
  459. //UNAME=$(uname)
  460. //if [[ "$UNAME" = Darwin ]]; then