// Copyright (C) 2001-2003 Jon A. Maxwell (JAM) // // This library is free software; you can redistribute it and/or // modify it under the terms of the GNU Lesser General Public // License as published by the Free Software Foundation; either // version 2.1 of the License, or (at your option) any later version. // // This library is distributed in the hope that it will be useful, // but WITHOUT ANY WARRANTY; without even the implied warranty of // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU // Lesser General Public License for more details. // // You should have received a copy of the GNU Lesser General Public // License along with this library; if not, write to the Free Software // Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. package net.sourceforge.jnlp.runtime; import static net.sourceforge.jnlp.runtime.Translator.R; import java.io.File; import java.net.URL; import java.security.AccessController; import java.security.PrivilegedAction; import java.util.ArrayList; import java.util.Arrays; import java.util.HashMap; import java.util.List; import java.util.Map; import net.sourceforge.jnlp.LaunchException; import net.sourceforge.jnlp.Launcher; import net.sourceforge.jnlp.ParserSettings; import net.sourceforge.jnlp.cache.CacheUtil; import net.sourceforge.jnlp.cache.UpdatePolicy; import net.sourceforge.jnlp.security.viewer.CertificateViewer; import net.sourceforge.jnlp.services.ServiceUtil; /** * This is the main entry point for the JNLP client. The main * method parses the command line parameters and loads a JNLP * file into the secure runtime environment. This class is meant * to be called from the command line or file association; to * initialize the netx engine from other code invoke the * JNLPRuntime.initialize method after configuring * the runtime. * * @author Jon A. Maxwell (JAM) - initial author * @version $Revision: 1.21 $ */ public final class Boot implements PrivilegedAction { // todo: decide whether a spawned netx (external launch) // should inherit the same options as this instance (store argv?) private static final String name = Boot.class.getPackage().getImplementationTitle(); private static final String version = Boot.class.getPackage().getImplementationVersion(); /** the text to display before launching the about link */ private static final String aboutMessage = "" + name + " " + version + "\n" + R("BLaunchAbout"); private static final String miniLicense = "\n" + " netx - an open-source JNLP client.\n" + " Copyright (C) 2001-2003 Jon A. Maxwell (JAM)\n" + "\n" + " // This library is free software; you can redistribute it and/or\n" + " modify it under the terms of the GNU Lesser General Public\n" + " License as published by the Free Software Foundation; either\n" + " version 2.1 of the License, or (at your option) any later version.\n" + "\n" + " This library is distributed in the hope that it will be useful,\n" + " but WITHOUT ANY WARRANTY; without even the implied warranty of\n" + " MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU\n" + " Lesser General Public License for more details.\n" + "\n" + " You should have received a copy of the GNU Lesser General Public\n" + " License along with this library; if not, write to the Free Software\n" + " Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.\n" + "\n"; private static final String helpMessage = "\n" + "Usage: " + R("BOUsage") + "\n" + " " + R("BOUsage2") + "\n" + "\n" + "control-options:" + "\n" + " -about " + R("BOAbout") + "\n" + " -viewer " + R("BOViewer") + "\n" + "\n" + "run-options:" + "\n" + " -arg arg " + R("BOArg") + "\n" + " -param name=value " + R("BOParam") + "\n" + " -property name=value " + R("BOProperty") + "\n" + " -update seconds " + R("BOUpdate") + "\n" + " -license " + R("BOLicense") + "\n" + " -verbose " + R("BOVerbose") + "\n" + " -nosecurity " + R("BONosecurity") + "\n" + " -noupdate " + R("BONoupdate") + "\n" + " -headless " + R("BOHeadless") + "\n" + " -strict " + R("BOStrict") + "\n" + " -Xnofork " + R("BXnofork") + "\n" + " -Xclearcache " + R("BXclearcache") + "\n" + " -help " + R("BOHelp") + "\n"; private static final String doubleArgs = "-basedir -jnlp -arg -param -property -update"; private static String args[]; // avoid the hot potato /** * Launch the JNLP file specified by the command-line arguments. */ public static void main(String[] argsIn) { args = argsIn; if (null != getOption("-viewer")) { try { CertificateViewer.main(null); System.exit(0); } catch (Exception e) { // TODO Auto-generated catch block e.printStackTrace(); } } if (null != getOption("-license")) { System.out.println(miniLicense); System.exit(0); } if (null != getOption("-help")) { System.out.println(helpMessage); System.exit(0); } if (null != getOption("-about")) System.out.println(aboutMessage); if (null != getOption("-verbose")) JNLPRuntime.setDebug(true); if (null != getOption("-update")) { int value = Integer.parseInt(getOption("-update")); JNLPRuntime.setDefaultUpdatePolicy(new UpdatePolicy(value * 1000l)); } if (null != getOption("-headless")) JNLPRuntime.setHeadless(true); if (null != getOption("-noupdate")) JNLPRuntime.setDefaultUpdatePolicy(UpdatePolicy.NEVER); if (null != getOption("-Xnofork")) { JNLPRuntime.setForksAllowed(false); } if (null != getOption("-Xtrustall")) { JNLPRuntime.setTrustAll(true); } JNLPRuntime.setInitialArgments(Arrays.asList(argsIn)); // do in a privileged action to clear the security context of // the Boot13 class, which doesn't have any privileges in // JRE1.3; JRE1.4 works without Boot13 or this PrivilegedAction. AccessController.doPrivileged(new Boot()); } /** * The privileged part (jdk1.3 compatibility). */ public Void run() { JNLPRuntime.setSecurityEnabled(null == getOption("-nosecurity")); JNLPRuntime.initialize(true); /* * FIXME * This should have been done with the rest of the argument parsing * code. But we need to know what the cache and base directories are, * and baseDir is initialized here */ if (null != getOption("-Xclearcache")) { CacheUtil.clearCache(); return null; } Map extra = new HashMap(); extra.put("arguments", getOptions("-arg")); extra.put("parameters", getOptions("-param")); extra.put("properties", getOptions("-property")); boolean strict = (null != getOption("-strict")); ParserSettings settings = new ParserSettings(strict); try { Launcher launcher = new Launcher(false); launcher.setParserSettings(settings); launcher.setInformationToMerge(extra); launcher.launch(getFileLocation(), true); } catch (LaunchException ex) { // default handler prints this } catch (Exception ex) { if (JNLPRuntime.isDebug()) ex.printStackTrace(); fatalError(R("RUnexpected", ex.toString(), ex.getStackTrace()[0])); } return null; } private static void fatalError(String message) { System.err.println("netx: " + message); System.exit(1); } /** * Returns the location of the about.jnlp file or null if this file * does not exist. */ private static String getAboutFile() { ClassLoader cl = Boot.class.getClassLoader(); if (cl == null) { cl = ClassLoader.getSystemClassLoader(); } try { //extracts full path to about.jnlp String s = cl.getResource("net/sourceforge/jnlp/runtime/Boot.class").toString(); s=s.substring(0,s.indexOf("!")); s=s.substring(s.indexOf(":")+1); s=s.substring(s.indexOf(":")+1); s="file://"+s.replace("netx.jar","about.jnlp"); if (JNLPRuntime.isDebug()){ System.out.println("Using " + s + " as about.jnlp URL"); } return s; } catch (Exception e) { e.printStackTrace(); return null; } } /** * Returns the url of file to open; does not return if no file was * specified, or if the file location was invalid. */ private static URL getFileLocation() { String location = getJNLPFile(); // override -jnlp with aboutFile if (getOption("-about") != null) { location = getAboutFile(); if (location == null) fatalError(R("RNoAboutJnlp")); } else { location = getJNLPFile(); } if (location == null) { System.out.println(helpMessage); System.exit(1); } if (JNLPRuntime.isDebug()) System.out.println(R("BFileLoc") + ": " + location); URL url = null; try { if (new File(location).exists()) // TODO: Should be toURI().toURL() url = new File(location).toURL(); // Why use file.getCanonicalFile? else url = new URL(ServiceUtil.getBasicService().getCodeBase(), location); } catch (Exception e) { fatalError("Invalid jnlp file " + location); if (JNLPRuntime.isDebug()) e.printStackTrace(); } return url; } /** * Gets the JNLP file from the command line arguments, or exits upon error. */ private static String getJNLPFile() { if (args.length == 0) { System.out.println(helpMessage); System.exit(0); } else if (args.length == 1) { return args[args.length - 1]; } else { String lastArg = args[args.length - 1]; String secondLastArg = args[args.length - 2]; if (doubleArgs.indexOf(secondLastArg) == -1) { return lastArg; } else { System.out.println(helpMessage); System.exit(0); } } return null; } /** * Return value of the first occurence of the specified * option, or null if the option is not present. If the * option is a flag (0-parameter) and is present then the * option name is returned. */ private static String getOption(String option) { String result[] = getOptions(option); if (result.length == 0) return null; else return result[0]; } /** * Return all the values of the specified option, or an empty * array if the option is not present. If the option is a * flag (0-parameter) and is present then the option name is * returned once for each occurrence. */ private static String[] getOptions(String option) { List result = new ArrayList(); for (int i = 0; i < args.length; i++) { if (option.equals(args[i])) { if (-1 == doubleArgs.indexOf(option)) result.add(option); else if (i + 1 < args.length) result.add(args[i + 1]); } if (args[i].startsWith("-") && -1 != doubleArgs.indexOf(args[i])) i++; } return result.toArray(new String[result.size()]); } }