|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
*/ |
|
|
|
package sun.applet; |
|
|
|
import java.io.BufferedInputStream; |
|
import java.io.File; |
|
import java.io.FileInputStream; |
|
import java.io.FileOutputStream; |
|
import java.io.IOException; |
|
import java.lang.reflect.Method; |
|
import java.lang.reflect.InvocationTargetException; |
|
import java.net.URL; |
|
import java.net.MalformedURLException; |
|
import java.util.Enumeration; |
|
import java.util.Properties; |
|
import java.util.Vector; |
|
import sun.net.www.ParseUtil; |
|
|
|
|
|
|
|
*/ |
|
public class Main { |
|
|
|
|
|
*/ |
|
static File theUserPropertiesFile; |
|
|
|
|
|
|
|
*/ |
|
static final String [][] avDefaultUserProps = { |
|
// There's a bootstrapping problem here. If we don't have a proxyHost, |
|
// then we will not be able to connect to a URL outside the firewall; |
|
// however, there's no way for us to set the proxyHost without starting |
|
|
|
{"http.proxyHost", ""}, |
|
{"http.proxyPort", "80"}, |
|
{"package.restrict.access.sun", "true"} |
|
}; |
|
|
|
static { |
|
File userHome = new File(System.getProperty("user.home")); |
|
|
|
userHome.canWrite(); |
|
|
|
theUserPropertiesFile = new File(userHome, ".appletviewer"); |
|
} |
|
|
|
|
|
private static AppletMessageHandler amh = new AppletMessageHandler("appletviewer"); |
|
|
|
|
|
|
|
*/ |
|
private boolean debugFlag = false; |
|
private boolean helpFlag = false; |
|
private String encoding = null; |
|
private boolean noSecurityFlag = false; |
|
private static boolean cmdLineTestFlag = false; |
|
|
|
|
|
|
|
*/ |
|
private static Vector urlList = new Vector(1); |
|
|
|
// This is used in init(). Getting rid of this is desirable but depends |
|
|
|
public static final String theVersion = System.getProperty("java.version"); |
|
|
|
|
|
|
|
*/ |
|
public static void main(String [] args) { |
|
Main m = new Main(); |
|
int ret = m.run(args); |
|
|
|
// Exit immediately if we got some sort of error along the way. |
|
// For debugging purposes, if we have passed in "-XcmdLineTest" we |
|
|
|
if ((ret != 0) || (cmdLineTestFlag)) |
|
System.exit(ret); |
|
} |
|
|
|
private int run(String [] args) { |
|
|
|
try { |
|
if (args.length == 0) { |
|
usage(); |
|
return 0; |
|
} |
|
for (int i = 0; i < args.length; ) { |
|
int j = decodeArg(args, i); |
|
if (j == 0) { |
|
throw new ParseException(lookup("main.err.unrecognizedarg", |
|
args[i])); |
|
} |
|
i += j; |
|
} |
|
} catch (ParseException e) { |
|
System.err.println(e.getMessage()); |
|
return 1; |
|
} |
|
|
|
|
|
if (helpFlag) { |
|
usage(); |
|
return 0; |
|
} |
|
|
|
if (urlList.size() == 0) { |
|
System.err.println(lookup("main.err.inputfile")); |
|
return 1; |
|
} |
|
|
|
if (debugFlag) { |
|
// START A DEBUG SESSION |
|
// Given the current architecture, we will end up decoding the |
|
// arguments again, but at least we are guaranteed to have |
|
|
|
return invokeDebugger(args); |
|
} |
|
|
|
|
|
if (!noSecurityFlag && (System.getSecurityManager() == null)) |
|
init(); |
|
|
|
|
|
for (int i = 0; i < urlList.size(); i++) { |
|
try { |
|
// XXX 5/17 this parsing method should be changed/fixed so that |
|
// it doesn't do both parsing of the html file and launching of |
|
|
|
AppletViewer.parse((URL) urlList.elementAt(i), encoding); |
|
} catch (IOException e) { |
|
System.err.println(lookup("main.err.io", e.getMessage())); |
|
return 1; |
|
} |
|
} |
|
return 0; |
|
} |
|
|
|
private static void usage() { |
|
System.out.println(lookup("usage")); |
|
} |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
*/ |
|
private int decodeArg(String [] args, int i) throws ParseException { |
|
String arg = args[i]; |
|
int argc = args.length; |
|
|
|
if ("-help".equalsIgnoreCase(arg) || "-?".equals(arg)) { |
|
helpFlag = true; |
|
return 1; |
|
} else if ("-encoding".equals(arg) && (i < argc - 1)) { |
|
if (encoding != null) |
|
throw new ParseException(lookup("main.err.dupoption", arg)); |
|
encoding = args[++i]; |
|
return 2; |
|
} else if ("-debug".equals(arg)) { |
|
debugFlag = true; |
|
return 1; |
|
} else if ("-Xnosecurity".equals(arg)) { |
|
// This is an undocumented (and, in the future, unsupported) |
|
// flag which prevents AppletViewer from installing its own |
|
// SecurityManager. |
|
|
|
System.err.println(); |
|
System.err.println(lookup("main.warn.nosecmgr")); |
|
System.err.println(); |
|
|
|
noSecurityFlag = true; |
|
return 1; |
|
} else if ("-XcmdLineTest".equals(arg)) { |
|
// This is an internal flag which should be used for command-line |
|
// testing. It instructs AppletViewer to force a premature exit |
|
|
|
cmdLineTestFlag = true; |
|
return 1; |
|
} else if (arg.startsWith("-")) { |
|
throw new ParseException(lookup("main.err.unsupportedopt", arg)); |
|
} else { |
|
|
|
URL url = parseURL(arg); |
|
if (url != null) { |
|
urlList.addElement(url); |
|
return 1; |
|
} |
|
} |
|
return 0; |
|
} |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
*/ |
|
private URL parseURL(String url) throws ParseException { |
|
URL u = null; |
|
|
|
String prefix = "file:"; |
|
|
|
try { |
|
if (url.indexOf(':') <= 1) |
|
{ |
|
|
|
u = ParseUtil.fileToEncodedURL(new File(url)); |
|
} else if (url.startsWith(prefix) && |
|
url.length() != prefix.length() && |
|
!(new File(url.substring(prefix.length())).isAbsolute())) |
|
{ |
|
// relative file URL, like this "file:index.html" |
|
// ensure that this file URL is absolute |
|
|
|
String path = ParseUtil.fileToEncodedURL(new File(System.getProperty("user.dir"))).getPath() + |
|
url.substring(prefix.length()); |
|
u = new URL("file", "", path); |
|
} else { |
|
|
|
u = new URL(url); |
|
} |
|
} catch (MalformedURLException e) { |
|
throw new ParseException(lookup("main.err.badurl", |
|
url, e.getMessage())); |
|
} |
|
|
|
return u; |
|
} |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
*/ |
|
private int invokeDebugger(String [] args) { |
|
|
|
String [] newArgs = new String[args.length + 1]; |
|
int current = 0; |
|
|
|
// Add a -classpath argument that prevents |
|
// the debugger from launching appletviewer with the default of |
|
// ".". appletviewer's classpath should never contain valid |
|
// classes since they will result in security exceptions. |
|
// Ideally, the classpath should be set to "", but the VM won't |
|
|
|
String phonyDir = System.getProperty("java.home") + |
|
File.separator + "phony"; |
|
newArgs[current++] = "-Djava.class.path=" + phonyDir; |
|
|
|
|
|
newArgs[current++] = "sun.applet.Main"; |
|
|
|
// Append all the of the original appletviewer arguments, |
|
|
|
for (int i = 0; i < args.length; i++) { |
|
if (!("-debug".equals(args[i]))) { |
|
newArgs[current++] = args[i]; |
|
} |
|
} |
|
|
|
// LAUNCH THE DEBUGGER |
|
// Reflection is used for two reasons: |
|
// 1) The debugger classes are on classpath and thus must be loaded |
|
// by the application class loader. (Currently, appletviewer are |
|
// loaded through the boot class path out of rt.jar.) |
|
// 2) Reflection removes any build dependency between appletviewer |
|
|
|
try { |
|
Class c = Class.forName("com.sun.tools.example.debug.tty.TTY", true, |
|
ClassLoader.getSystemClassLoader()); |
|
Method m = c.getDeclaredMethod("main", |
|
new Class[] { String[].class }); |
|
m.invoke(null, new Object[] { newArgs }); |
|
} catch (ClassNotFoundException cnfe) { |
|
System.err.println(lookup("main.debug.cantfinddebug")); |
|
return 1; |
|
} catch (NoSuchMethodException nsme) { |
|
System.err.println(lookup("main.debug.cantfindmain")); |
|
return 1; |
|
} catch (InvocationTargetException ite) { |
|
System.err.println(lookup("main.debug.exceptionindebug")); |
|
return 1; |
|
} catch (IllegalAccessException iae) { |
|
System.err.println(lookup("main.debug.cantaccess")); |
|
return 1; |
|
} |
|
return 0; |
|
} |
|
|
|
private void init() { |
|
|
|
Properties avProps = getAVProps(); |
|
|
|
// ADD OTHER RANDOM PROPERTIES |
|
// XXX 5/18 need to revisit why these are here, is there some |
|
// standard for what is available? |
|
|
|
|
|
avProps.put("browser", "sun.applet.AppletViewer"); |
|
avProps.put("browser.version", "1.06"); |
|
avProps.put("browser.vendor", "Oracle Corporation"); |
|
avProps.put("http.agent", "Java(tm) 2 SDK, Standard Edition v" + theVersion); |
|
|
|
// Define which packages can be extended by applets |
|
|
|
avProps.put("package.restrict.definition.java", "true"); |
|
avProps.put("package.restrict.definition.sun", "true"); |
|
|
|
// Define which properties can be read by applets. |
|
// A property named by "key" can be read only when its twin |
|
// property "key.applet" is true. The following ten properties |
|
// are open by default. Any other property can be explicitly |
|
// opened up by the browser user by calling appletviewer with |
|
|
|
avProps.put("java.version.applet", "true"); |
|
avProps.put("java.vendor.applet", "true"); |
|
avProps.put("java.vendor.url.applet", "true"); |
|
avProps.put("java.class.version.applet", "true"); |
|
avProps.put("os.name.applet", "true"); |
|
avProps.put("os.version.applet", "true"); |
|
avProps.put("os.arch.applet", "true"); |
|
avProps.put("file.separator.applet", "true"); |
|
avProps.put("path.separator.applet", "true"); |
|
avProps.put("line.separator.applet", "true"); |
|
|
|
// Read in the System properties. If something is going to be |
|
|
|
Properties sysProps = System.getProperties(); |
|
for (Enumeration e = sysProps.propertyNames(); e.hasMoreElements(); ) { |
|
String key = (String) e.nextElement(); |
|
String val = (String) sysProps.getProperty(key); |
|
String oldVal; |
|
if ((oldVal = (String) avProps.setProperty(key, val)) != null) |
|
System.err.println(lookup("main.warn.prop.overwrite", key, |
|
oldVal, val)); |
|
} |
|
|
|
|
|
System.setProperties(avProps); |
|
|
|
|
|
if (!noSecurityFlag) { |
|
System.setSecurityManager(new AppletSecurity()); |
|
} else { |
|
System.err.println(lookup("main.nosecmgr")); |
|
} |
|
|
|
// REMIND: Create and install a socket factory! |
|
} |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
*/ |
|
private Properties getAVProps() { |
|
Properties avProps = new Properties(); |
|
|
|
File dotAV = theUserPropertiesFile; |
|
if (dotAV.exists()) { |
|
|
|
if (dotAV.canRead()) { |
|
|
|
avProps = getAVProps(dotAV); |
|
} else { |
|
|
|
System.err.println(lookup("main.warn.cantreadprops", |
|
dotAV.toString())); |
|
avProps = setDefaultAVProps(); |
|
} |
|
} else { |
|
// create the $USER/.appletviewer file |
|
|
|
|
|
File userHome = new File(System.getProperty("user.home")); |
|
File dotHJ = new File(userHome, ".hotjava"); |
|
dotHJ = new File(dotHJ, "properties"); |
|
if (dotHJ.exists()) { |
|
|
|
avProps = getAVProps(dotHJ); |
|
} else { |
|
|
|
System.err.println(lookup("main.warn.cantreadprops", |
|
dotHJ.toString())); |
|
avProps = setDefaultAVProps(); |
|
} |
|
|
|
|
|
try (FileOutputStream out = new FileOutputStream(dotAV)) { |
|
avProps.store(out, lookup("main.prop.store")); |
|
} catch (IOException e) { |
|
System.err.println(lookup("main.err.prop.cantsave", |
|
dotAV.toString())); |
|
} |
|
} |
|
return avProps; |
|
} |
|
|
|
|
|
|
|
|
|
|
|
|
|
*/ |
|
private Properties setDefaultAVProps() { |
|
Properties avProps = new Properties(); |
|
for (int i = 0; i < avDefaultUserProps.length; i++) { |
|
avProps.setProperty(avDefaultUserProps[i][0], |
|
avDefaultUserProps[i][1]); |
|
} |
|
return avProps; |
|
} |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
*/ |
|
private Properties getAVProps(File inFile) { |
|
Properties avProps = new Properties(); |
|
|
|
|
|
Properties tmpProps = new Properties(); |
|
try (FileInputStream in = new FileInputStream(inFile)) { |
|
tmpProps.load(new BufferedInputStream(in)); |
|
} catch (IOException e) { |
|
System.err.println(lookup("main.err.prop.cantread", inFile.toString())); |
|
} |
|
|
|
|
|
for (int i = 0; i < avDefaultUserProps.length; i++) { |
|
String value = tmpProps.getProperty(avDefaultUserProps[i][0]); |
|
if (value != null) { |
|
|
|
avProps.setProperty(avDefaultUserProps[i][0], value); |
|
} else { |
|
|
|
avProps.setProperty(avDefaultUserProps[i][0], |
|
avDefaultUserProps[i][1]); |
|
} |
|
} |
|
return avProps; |
|
} |
|
|
|
/** |
|
* Methods for easier i18n handling. |
|
*/ |
|
|
|
private static String lookup(String key) { |
|
return amh.getMessage(key); |
|
} |
|
|
|
private static String lookup(String key, String arg0) { |
|
return amh.getMessage(key, arg0); |
|
} |
|
|
|
private static String lookup(String key, String arg0, String arg1) { |
|
return amh.getMessage(key, arg0, arg1); |
|
} |
|
|
|
private static String lookup(String key, String arg0, String arg1, |
|
String arg2) { |
|
return amh.getMessage(key, arg0, arg1, arg2); |
|
} |
|
|
|
class ParseException extends RuntimeException |
|
{ |
|
public ParseException(String msg) { |
|
super(msg); |
|
} |
|
|
|
public ParseException(Throwable t) { |
|
super(t.getMessage()); |
|
this.t = t; |
|
} |
|
|
|
Throwable t = null; |
|
} |
|
} |