1 /* 2 * Copyright (c) 1999, 2016, Oracle and/or its affiliates. All rights reserved. 3 * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. 4 * 5 * This code is free software; you can redistribute it and/or modify it 6 * under the terms of the GNU General Public License version 2 only, as 7 * published by the Free Software Foundation. Oracle designates this 8 * particular file as subject to the "Classpath" exception as provided 9 * by Oracle in the LICENSE file that accompanied this code. 10 * 11 * This code is distributed in the hope that it will be useful, but WITHOUT 12 * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or 13 * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License 14 * version 2 for more details (a copy is included in the LICENSE file that 15 * accompanied this code). 16 * 17 * You should have received a copy of the GNU General Public License version 18 * 2 along with this work; if not, write to the Free Software Foundation, 19 * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. 20 * 21 * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA 22 * or visit www.oracle.com if you need additional information or have any 23 * questions. 24 */ 25 26 package sun.applet; 27 28 import java.io.BufferedInputStream; 29 import java.io.File; 30 import java.io.FileInputStream; 31 import java.io.FileOutputStream; 32 import java.io.IOException; 33 import java.net.URL; 34 import java.net.MalformedURLException; 35 import java.util.Enumeration; 36 import java.util.Properties; 37 import java.util.Vector; 38 import sun.net.www.ParseUtil; 39 40 /** 41 * The main entry point into AppletViewer. 42 * 43 * @deprecated The Applet API is deprecated. See the 44 * <a href="../../java/applet/package-summary.html"> java.applet package 45 * documentation</a> for further information. 46 */ 47 @Deprecated(since = "9") 48 public class Main { 49 /** 50 * The file which contains all of the AppletViewer specific properties. 51 */ 52 static File theUserPropertiesFile; 53 54 /** 55 * The default key/value pairs for the required user-specific properties. 56 */ 57 static final String [][] avDefaultUserProps = { 58 // There's a bootstrapping problem here. If we don't have a proxyHost, 59 // then we will not be able to connect to a URL outside the firewall; 60 // however, there's no way for us to set the proxyHost without starting 61 // AppletViewer. This problem existed before the re-write. 62 {"http.proxyHost", ""}, 63 {"http.proxyPort", "80"}, 64 {"package.restrict.access.sun", "true"} 65 }; 66 67 static { 68 File userHome = new File(System.getProperty("user.home")); 69 // make sure we can write to this location 70 userHome.canWrite(); 71 72 theUserPropertiesFile = new File(userHome, ".appletviewer"); 73 } 74 75 // i18n 76 private static AppletMessageHandler amh = new AppletMessageHandler("appletviewer"); 77 78 /** 79 * Member variables set according to options passed in to AppletViewer. 80 */ 81 private boolean helpFlag = false; 82 private String encoding = null; 83 private boolean noSecurityFlag = false; 84 private static boolean cmdLineTestFlag = false; 85 86 /** 87 * The list of valid URLs passed in to AppletViewer. 88 */ 89 private static Vector<URL> urlList = new Vector<>(1); 90 91 // This is used in init(). Getting rid of this is desirable but depends 92 // on whether the property that uses it is necessary/standard. 93 public static final String theVersion = System.getProperty("java.version"); 94 95 /** 96 * The main entry point into AppletViewer. 97 */ 98 public static void main(String [] args) { 99 Main m = new Main(); 100 int ret = m.run(args); 101 102 // Exit immediately if we got some sort of error along the way. 103 // For debugging purposes, if we have passed in "-XcmdLineTest" we 104 // force a premature exit. 105 if ((ret != 0) || (cmdLineTestFlag)) 106 System.exit(ret); 107 } 108 109 private int run(String [] args) { 110 // DECODE ARGS 111 try { 112 System.err.println(lookup("deprecated")); 113 System.err.flush(); 114 if (args.length == 0) { 115 usage(); 116 return 0; 117 } 118 for (int i = 0; i < args.length; ) { 119 int j = decodeArg(args, i); 120 if (j == 0) { 121 throw new ParseException(lookup("main.err.unrecognizedarg", 122 args[i])); 123 } 124 i += j; 125 } 126 } catch (ParseException e) { 127 System.err.println(e.getMessage()); 128 return 1; 129 } 130 131 // CHECK ARGUMENTS 132 if (helpFlag) { 133 usage(); 134 return 0; 135 } 136 137 if (urlList.size() == 0) { 138 System.err.println(lookup("main.err.inputfile")); 139 return 1; 140 } 141 142 // INSTALL THE SECURITY MANAGER (if necessary) 143 if (!noSecurityFlag && (System.getSecurityManager() == null)) 144 init(); 145 146 // LAUNCH APPLETVIEWER FOR EACH URL 147 for (int i = 0; i < urlList.size(); i++) { 148 try { 149 // XXX 5/17 this parsing method should be changed/fixed so that 150 // it doesn't do both parsing of the html file and launching of 151 // the AppletPanel 152 AppletViewer.parse(urlList.elementAt(i), encoding); 153 } catch (IOException e) { 154 System.err.println(lookup("main.err.io", e.getMessage())); 155 return 1; 156 } 157 } 158 return 0; 159 } 160 161 private static void usage() { 162 System.out.println(lookup("usage")); 163 } 164 165 /** 166 * Decode a single argument in an array and return the number of elements 167 * used. 168 * 169 * @param args The array of arguments. 170 * @param i The argument to decode. 171 * @return The number of array elements used when the argument was 172 * decoded. 173 * @exception ParseException 174 * Thrown when there is a problem with something in the 175 * argument array. 176 */ 177 private int decodeArg(String [] args, int i) throws ParseException { 178 String arg = args[i]; 179 int argc = args.length; 180 181 if ("-help".equalsIgnoreCase(arg) || "-?".equals(arg)) { 182 helpFlag = true; 183 return 1; 184 } else if ("-encoding".equals(arg) && (i < argc - 1)) { 185 if (encoding != null) 186 throw new ParseException(lookup("main.err.dupoption", arg)); 187 encoding = args[++i]; 188 return 2; 189 } else if ("-Xnosecurity".equals(arg)) { 190 // This is an undocumented (and, in the future, unsupported) 191 // flag which prevents AppletViewer from installing its own 192 // SecurityManager. 193 194 System.err.println(); 195 System.err.println(lookup("main.warn.nosecmgr")); 196 System.err.println(); 197 198 noSecurityFlag = true; 199 return 1; 200 } else if ("-XcmdLineTest".equals(arg)) { 201 // This is an internal flag which should be used for command-line 202 // testing. It instructs AppletViewer to force a premature exit 203 // immediately after the applet has been launched. 204 cmdLineTestFlag = true; 205 return 1; 206 } else if (arg.startsWith("-")) { 207 throw new ParseException(lookup("main.err.unsupportedopt", arg)); 208 } else { 209 // we found what we hope is a url 210 URL url = parseURL(arg); 211 if (url != null) { 212 urlList.addElement(url); 213 return 1; 214 } 215 } 216 return 0; 217 } 218 219 /** 220 * Following the relevant RFC, construct a valid URL based on the passed in 221 * string. 222 * 223 * @param url a string which represents either a relative or absolute URL. 224 * @return a URL when the passed in string can be interpreted according 225 * to the RFC, {@code null} otherwise. 226 * @exception ParseException 227 * Thrown when we are unable to construct a proper URL from the 228 * passed in string. 229 */ 230 private URL parseURL(String url) throws ParseException { 231 URL u = null; 232 // prefix of the urls with 'file' scheme 233 String prefix = "file:"; 234 235 try { 236 if (url.indexOf(':') <= 1) 237 { 238 // appletviewer accepts only unencoded filesystem paths 239 u = ParseUtil.fileToEncodedURL(new File(url)); 240 } else if (url.startsWith(prefix) && 241 url.length() != prefix.length() && 242 !(new File(url.substring(prefix.length())).isAbsolute())) 243 { 244 // relative file URL, like this "file:index.html" 245 // ensure that this file URL is absolute 246 // ParseUtil.fileToEncodedURL should be done last (see 6329251) 247 String path = ParseUtil.fileToEncodedURL(new File(System.getProperty("user.dir"))).getPath() + 248 url.substring(prefix.length()); 249 u = new URL("file", "", path); 250 } else { 251 // appletviewer accepts only encoded urls 252 u = new URL(url); 253 } 254 } catch (MalformedURLException e) { 255 throw new ParseException(lookup("main.err.badurl", 256 url, e.getMessage())); 257 } 258 259 return u; 260 } 261 262 private void init() { 263 // GET APPLETVIEWER USER-SPECIFIC PROPERTIES 264 Properties avProps = getAVProps(); 265 266 // ADD OTHER RANDOM PROPERTIES 267 // XXX 5/18 need to revisit why these are here, is there some 268 // standard for what is available? 269 270 // Standard browser properties 271 avProps.put("browser", "sun.applet.AppletViewer"); 272 avProps.put("browser.version", "1.06"); 273 avProps.put("browser.vendor", "Oracle Corporation"); 274 avProps.put("http.agent", "Java(tm) 2 SDK, Standard Edition v" + theVersion); 275 276 // Define which packages can be extended by applets 277 // XXX 5/19 probably not needed, not checked in AppletSecurity 278 avProps.put("package.restrict.definition.java", "true"); 279 avProps.put("package.restrict.definition.sun", "true"); 280 281 // Define which properties can be read by applets. 282 // A property named by "key" can be read only when its twin 283 // property "key.applet" is true. The following ten properties 284 // are open by default. Any other property can be explicitly 285 // opened up by the browser user by calling appletviewer with 286 // -J-Dkey.applet=true 287 avProps.put("java.version.applet", "true"); 288 avProps.put("java.vendor.applet", "true"); 289 avProps.put("java.vendor.url.applet", "true"); 290 avProps.put("java.class.version.applet", "true"); 291 avProps.put("os.name.applet", "true"); 292 avProps.put("os.version.applet", "true"); 293 avProps.put("os.arch.applet", "true"); 294 avProps.put("file.separator.applet", "true"); 295 avProps.put("path.separator.applet", "true"); 296 avProps.put("line.separator.applet", "true"); 297 298 // Read in the System properties. If something is going to be 299 // over-written, warn about it. 300 Properties sysProps = System.getProperties(); 301 for (Enumeration<?> e = sysProps.propertyNames(); e.hasMoreElements(); ) { 302 String key = (String) e.nextElement(); 303 String val = sysProps.getProperty(key); 304 String oldVal; 305 if ((oldVal = (String) avProps.setProperty(key, val)) != null) 306 System.err.println(lookup("main.warn.prop.overwrite", key, 307 oldVal, val)); 308 } 309 310 // INSTALL THE PROPERTY LIST 311 System.setProperties(avProps); 312 313 // Create and install the security manager 314 if (!noSecurityFlag) { 315 System.setSecurityManager(new AppletSecurity()); 316 } else { 317 System.err.println(lookup("main.nosecmgr")); 318 } 319 320 // REMIND: Create and install a socket factory! 321 } 322 323 /** 324 * Read the AppletViewer user-specific properties. Typically, these 325 * properties should reside in the file $USER/.appletviewer. If this file 326 * does not exist, one will be created. Information for this file will 327 * be gleaned from $USER/.hotjava/properties. If that file does not exist, 328 * then default values will be used. 329 * 330 * @return A Properties object containing all of the AppletViewer 331 * user-specific properties. 332 */ 333 private Properties getAVProps() { 334 Properties avProps = new Properties(); 335 336 File dotAV = theUserPropertiesFile; 337 if (dotAV.exists()) { 338 // we must have already done the conversion 339 if (dotAV.canRead()) { 340 // just read the file 341 avProps = getAVProps(dotAV); 342 } else { 343 // send out warning and use defaults 344 System.err.println(lookup("main.warn.cantreadprops", 345 dotAV.toString())); 346 avProps = setDefaultAVProps(); 347 } 348 } else { 349 // create the $USER/.appletviewer file 350 351 // see if $USER/.hotjava/properties exists 352 File userHome = new File(System.getProperty("user.home")); 353 File dotHJ = new File(userHome, ".hotjava"); 354 dotHJ = new File(dotHJ, "properties"); 355 if (dotHJ.exists()) { 356 // just read the file 357 avProps = getAVProps(dotHJ); 358 } else { 359 // send out warning and use defaults 360 System.err.println(lookup("main.warn.cantreadprops", 361 dotHJ.toString())); 362 avProps = setDefaultAVProps(); 363 } 364 365 // SAVE THE FILE 366 try (FileOutputStream out = new FileOutputStream(dotAV)) { 367 avProps.store(out, lookup("main.prop.store")); 368 } catch (IOException e) { 369 System.err.println(lookup("main.err.prop.cantsave", 370 dotAV.toString())); 371 } 372 } 373 return avProps; 374 } 375 376 /** 377 * Set the AppletViewer user-specific properties to be the default values. 378 * 379 * @return A Properties object containing all of the AppletViewer 380 * user-specific properties, set to the default values. 381 */ 382 private Properties setDefaultAVProps() { 383 Properties avProps = new Properties(); 384 for (int i = 0; i < avDefaultUserProps.length; i++) { 385 avProps.setProperty(avDefaultUserProps[i][0], 386 avDefaultUserProps[i][1]); 387 } 388 return avProps; 389 } 390 391 /** 392 * Given a file, find only the properties that are setable by AppletViewer. 393 * 394 * @param inFile A Properties file from which we select the properties of 395 * interest. 396 * @return A Properties object containing all of the AppletViewer 397 * user-specific properties. 398 */ 399 private Properties getAVProps(File inFile) { 400 Properties avProps = new Properties(); 401 402 // read the file 403 Properties tmpProps = new Properties(); 404 try (FileInputStream in = new FileInputStream(inFile)) { 405 tmpProps.load(new BufferedInputStream(in)); 406 } catch (IOException e) { 407 System.err.println(lookup("main.err.prop.cantread", inFile.toString())); 408 } 409 410 // pick off the properties we care about 411 for (int i = 0; i < avDefaultUserProps.length; i++) { 412 String value = tmpProps.getProperty(avDefaultUserProps[i][0]); 413 if (value != null) { 414 // the property exists in the file, so replace the default 415 avProps.setProperty(avDefaultUserProps[i][0], value); 416 } else { 417 // just use the default 418 avProps.setProperty(avDefaultUserProps[i][0], 419 avDefaultUserProps[i][1]); 420 } 421 } 422 return avProps; 423 } 424 425 /** 426 * Methods for easier i18n handling. 427 */ 428 429 private static String lookup(String key) { 430 return amh.getMessage(key); 431 } 432 433 private static String lookup(String key, String arg0) { 434 return amh.getMessage(key, arg0); 435 } 436 437 private static String lookup(String key, String arg0, String arg1) { 438 return amh.getMessage(key, arg0, arg1); 439 } 440 441 private static String lookup(String key, String arg0, String arg1, 442 String arg2) { 443 return amh.getMessage(key, arg0, arg1, arg2); 444 } 445 446 @SuppressWarnings("serial") // JDK implementation class 447 class ParseException extends RuntimeException 448 { 449 public ParseException(String msg) { 450 super(msg); 451 } 452 453 public ParseException(Throwable t) { 454 super(t.getMessage()); 455 this.t = t; 456 } 457 458 Throwable t = null; 459 } 460 }