Save This Page
Home » openjdk-7 » sun » applet » [javadoc | source]
    1   /*
    2    * Copyright 1999-2006 Sun Microsystems, Inc.  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.  Sun designates this
    8    * particular file as subject to the "Classpath" exception as provided
    9    * by Sun 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 Sun Microsystems, Inc., 4150 Network Circle, Santa Clara,
   22    * CA 95054 USA or visit www.sun.com if you need additional information or
   23    * have any 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.lang.reflect.Method;
   34   import java.lang.reflect.InvocationTargetException;
   35   import java.net.URL;
   36   import java.net.MalformedURLException;
   37   import java.util.Enumeration;
   38   import java.util.Properties;
   39   import java.util.Vector;
   40   import sun.net.www.ParseUtil;
   41   
   42   /**
   43    * The main entry point into AppletViewer.
   44    */
   45   public class Main {
   46       /**
   47        * The file which contains all of the AppletViewer specific properties.
   48        */
   49       static File theUserPropertiesFile;
   50   
   51       /**
   52        * The default key/value pairs for the required user-specific properties.
   53        */
   54       static final String [][] avDefaultUserProps = {
   55           // There's a bootstrapping problem here.  If we don't have a proxyHost,
   56           // then we will not be able to connect to a URL outside the firewall;
   57           // however, there's no way for us to set the proxyHost without starting
   58           // AppletViewer.  This problem existed before the re-write.
   59           {"http.proxyHost", ""},
   60           {"http.proxyPort", "80"},
   61           {"package.restrict.access.sun", "true"}
   62       };
   63   
   64       static {
   65           File userHome = new File(System.getProperty("user.home"));
   66           // make sure we can write to this location
   67           userHome.canWrite();
   68   
   69           theUserPropertiesFile = new File(userHome, ".appletviewer");
   70       }
   71   
   72       // i18n
   73       private static AppletMessageHandler amh = new AppletMessageHandler("appletviewer");
   74   
   75       /**
   76        * Member variables set according to options passed in to AppletViewer.
   77        */
   78       private boolean debugFlag = false;
   79       private boolean helpFlag  = false;
   80       private String  encoding  = null;
   81       private boolean noSecurityFlag  = false;
   82       private static boolean cmdLineTestFlag = false;
   83   
   84       /**
   85        * The list of valid URLs passed in to AppletViewer.
   86        */
   87       private static Vector urlList = new Vector(1);
   88   
   89       // This is used in init().  Getting rid of this is desirable but depends
   90       // on whether the property that uses it is necessary/standard.
   91       public static final String theVersion = System.getProperty("java.version");
   92   
   93       /**
   94        * The main entry point into AppletViewer.
   95        */
   96       public static void main(String [] args) {
   97           Main m = new Main();
   98           int ret = m.run(args);
   99   
  100           // Exit immediately if we got some sort of error along the way.
  101           // For debugging purposes, if we have passed in "-XcmdLineTest" we
  102           // force a premature exit.
  103           if ((ret != 0) || (cmdLineTestFlag))
  104               System.exit(ret);
  105       }
  106   
  107       private int run(String [] args) {
  108           // DECODE ARGS
  109           try {
  110               if (args.length == 0) {
  111                   usage();
  112                   return 0;
  113               }
  114               for (int i = 0; i < args.length; ) {
  115                   int j = decodeArg(args, i);
  116                   if (j == 0) {
  117                       throw new ParseException(lookup("main.err.unrecognizedarg",
  118                                                       args[i]));
  119                   }
  120                   i += j;
  121               }
  122           } catch (ParseException e) {
  123               System.err.println(e.getMessage());
  124               return 1;
  125           }
  126   
  127           // CHECK ARGUMENTS
  128           if (helpFlag) {
  129               usage();
  130               return 0;
  131           }
  132   
  133           if (urlList.size() == 0) {
  134               System.err.println(lookup("main.err.inputfile"));
  135               return 1;
  136           }
  137   
  138           if (debugFlag) {
  139               // START A DEBUG SESSION
  140               // Given the current architecture, we will end up decoding the
  141               // arguments again, but at least we are guaranteed to have
  142               // arguments which are valid.
  143               return invokeDebugger(args);
  144           }
  145   
  146           // INSTALL THE SECURITY MANAGER (if necessary)
  147           if (!noSecurityFlag && (System.getSecurityManager() == null))
  148               init();
  149   
  150           // LAUNCH APPLETVIEWER FOR EACH URL
  151           for (int i = 0; i < urlList.size(); i++) {
  152               try {
  153                   // XXX 5/17 this parsing method should be changed/fixed so that
  154                   // it doesn't do both parsing of the html file and launching of
  155                   // the AppletPanel
  156                   AppletViewer.parse((URL) urlList.elementAt(i), encoding);
  157               } catch (IOException e) {
  158                   System.err.println(lookup("main.err.io", e.getMessage()));
  159                   return 1;
  160               }
  161           }
  162           return 0;
  163       }
  164   
  165       private static void usage() {
  166           System.out.println(lookup("usage"));
  167       }
  168   
  169       /**
  170        * Decode a single argument in an array and return the number of elements
  171        * used.
  172        *
  173        * @param args The array of arguments.
  174        * @param i    The argument to decode.
  175        * @return     The number of array elements used when the argument was
  176        *             decoded.
  177        * @exception ParseException
  178        *             Thrown when there is a problem with something in the
  179        *             argument array.
  180        */
  181       private int decodeArg(String [] args, int i) throws ParseException {
  182           String arg = args[i];
  183           int argc = args.length;
  184   
  185           if ("-help".equalsIgnoreCase(arg) || "-?".equals(arg)) {
  186               helpFlag = true;
  187               return 1;
  188           } else if ("-encoding".equals(arg) && (i < argc - 1)) {
  189               if (encoding != null)
  190                   throw new ParseException(lookup("main.err.dupoption", arg));
  191               encoding = args[++i];
  192               return 2;
  193           } else if ("-debug".equals(arg)) {
  194               debugFlag = true;
  195               return 1;
  196           } else if ("-Xnosecurity".equals(arg)) {
  197               // This is an undocumented (and, in the future, unsupported)
  198               // flag which prevents AppletViewer from installing its own
  199               // SecurityManager.
  200   
  201               System.err.println();
  202               System.err.println(lookup("main.warn.nosecmgr"));
  203               System.err.println();
  204   
  205               noSecurityFlag = true;
  206               return 1;
  207           } else if ("-XcmdLineTest".equals(arg)) {
  208               // This is an internal flag which should be used for command-line
  209               // testing.  It instructs AppletViewer to force a premature exit
  210               // immediately after the applet has been launched.
  211               cmdLineTestFlag = true;
  212               return 1;
  213           } else if (arg.startsWith("-")) {
  214               throw new ParseException(lookup("main.err.unsupportedopt", arg));
  215           } else {
  216               // we found what we hope is a url
  217               URL url = parseURL(arg);
  218               if (url != null) {
  219                   urlList.addElement(url);
  220                   return 1;
  221               }
  222           }
  223           return 0;
  224       }
  225   
  226       /**
  227        * Following the relevant RFC, construct a valid URL based on the passed in
  228        * string.
  229        *
  230        * @param url  a string which represents either a relative or absolute URL.
  231        * @return     a URL when the passed in string can be interpreted according
  232        *             to the RFC, <code>null</code> otherwise.
  233        * @exception  ParseException
  234        *             Thrown when we are unable to construct a proper URL from the
  235        *             passed in string.
  236        */
  237       private URL parseURL(String url) throws ParseException {
  238           URL u = null;
  239           // prefix of the urls with 'file' scheme
  240           String prefix = "file:";
  241   
  242           try {
  243               if (url.indexOf(':') <= 1)
  244               {
  245                   // appletviewer accepts only unencoded filesystem paths
  246                   u = ParseUtil.fileToEncodedURL(new File(url));
  247               } else if (url.startsWith(prefix) &&
  248                          url.length() != prefix.length() &&
  249                          !(new File(url.substring(prefix.length())).isAbsolute()))
  250               {
  251                   // relative file URL, like this "file:index.html"
  252                   // ensure that this file URL is absolute
  253                   // ParseUtil.fileToEncodedURL should be done last (see 6329251)
  254                   String path = ParseUtil.fileToEncodedURL(new File(System.getProperty("user.dir"))).getPath() +
  255                       url.substring(prefix.length());
  256                   u = new URL("file", "", path);
  257               } else {
  258                   // appletviewer accepts only encoded urls
  259                   u = new URL(url);
  260               }
  261           } catch (MalformedURLException e) {
  262               throw new ParseException(lookup("main.err.badurl",
  263                                               url, e.getMessage()));
  264           }
  265   
  266           return u;
  267       }
  268   
  269       /**
  270        * Invoke the debugger with the arguments passed in to appletviewer.
  271        *
  272        * @param args The arguments passed into the debugger.
  273        * @return     <code>0</code> if the debugger is invoked successfully,
  274        *             <code>1</code> otherwise.
  275        */
  276       private int invokeDebugger(String [] args) {
  277           // CONSTRUCT THE COMMAND LINE
  278           String [] newArgs = new String[args.length + 1];
  279           int current = 0;
  280   
  281           // Add a -classpath argument that prevents
  282           // the debugger from launching appletviewer with the default of
  283           // ".". appletviewer's classpath should never contain valid
  284           // classes since they will result in security exceptions.
  285           // Ideally, the classpath should be set to "", but the VM won't
  286           // allow an empty classpath, so a phony directory name is used.
  287           String phonyDir = System.getProperty("java.home") +
  288                             File.separator + "phony";
  289           newArgs[current++] = "-Djava.class.path=" + phonyDir;
  290   
  291           // Appletviewer's main class is the debuggee
  292           newArgs[current++] = "sun.applet.Main";
  293   
  294           // Append all the of the original appletviewer arguments,
  295           // leaving out the "-debug" option.
  296           for (int i = 0; i < args.length; i++) {
  297               if (!("-debug".equals(args[i]))) {
  298                   newArgs[current++] = args[i];
  299               }
  300           }
  301   
  302           // LAUNCH THE DEBUGGER
  303           // Reflection is used for two reasons:
  304           // 1) The debugger classes are on classpath and thus must be loaded
  305           // by the application class loader. (Currently, appletviewer are
  306           // loaded through the boot class path out of rt.jar.)
  307           // 2) Reflection removes any build dependency between appletviewer
  308           // and jdb.
  309           try {
  310               Class c = Class.forName("com.sun.tools.example.debug.tty.TTY", true,
  311                                       ClassLoader.getSystemClassLoader());
  312               Method m = c.getDeclaredMethod("main",
  313                                              new Class[] { String[].class });
  314               m.invoke(null, new Object[] { newArgs });
  315           } catch (ClassNotFoundException cnfe) {
  316               System.err.println(lookup("main.debug.cantfinddebug"));
  317               return 1;
  318           } catch (NoSuchMethodException nsme) {
  319               System.err.println(lookup("main.debug.cantfindmain"));
  320               return 1;
  321           } catch (InvocationTargetException ite) {
  322               System.err.println(lookup("main.debug.exceptionindebug"));
  323               return 1;
  324           } catch (IllegalAccessException iae) {
  325               System.err.println(lookup("main.debug.cantaccess"));
  326               return 1;
  327           }
  328           return 0;
  329       }
  330   
  331       private void init() {
  332           // GET APPLETVIEWER USER-SPECIFIC PROPERTIES
  333           Properties avProps = getAVProps();
  334   
  335           // ADD OTHER RANDOM PROPERTIES
  336           // XXX 5/18 need to revisit why these are here, is there some
  337           // standard for what is available?
  338   
  339           // Standard browser properties
  340           avProps.put("browser", "sun.applet.AppletViewer");
  341           avProps.put("browser.version", "1.06");
  342           avProps.put("browser.vendor", "Sun Microsystems Inc.");
  343           avProps.put("http.agent", "Java(tm) 2 SDK, Standard Edition v" + theVersion);
  344   
  345           // Define which packages can be extended by applets
  346           // XXX 5/19 probably not needed, not checked in AppletSecurity
  347           avProps.put("package.restrict.definition.java", "true");
  348           avProps.put("package.restrict.definition.sun", "true");
  349   
  350           // Define which properties can be read by applets.
  351           // A property named by "key" can be read only when its twin
  352           // property "key.applet" is true.  The following ten properties
  353           // are open by default.  Any other property can be explicitly
  354           // opened up by the browser user by calling appletviewer with
  355           // -J-Dkey.applet=true
  356           avProps.put("java.version.applet", "true");
  357           avProps.put("java.vendor.applet", "true");
  358           avProps.put("java.vendor.url.applet", "true");
  359           avProps.put("java.class.version.applet", "true");
  360           avProps.put("os.name.applet", "true");
  361           avProps.put("os.version.applet", "true");
  362           avProps.put("os.arch.applet", "true");
  363           avProps.put("file.separator.applet", "true");
  364           avProps.put("path.separator.applet", "true");
  365           avProps.put("line.separator.applet", "true");
  366   
  367           // Read in the System properties.  If something is going to be
  368           // over-written, warn about it.
  369           Properties sysProps = System.getProperties();
  370           for (Enumeration e = sysProps.propertyNames(); e.hasMoreElements(); ) {
  371               String key = (String) e.nextElement();
  372               String val = (String) sysProps.getProperty(key);
  373               String oldVal;
  374               if ((oldVal = (String) avProps.setProperty(key, val)) != null)
  375                   System.err.println(lookup("main.warn.prop.overwrite", key,
  376                                             oldVal, val));
  377           }
  378   
  379           // INSTALL THE PROPERTY LIST
  380           System.setProperties(avProps);
  381   
  382           // Create and install the security manager
  383           if (!noSecurityFlag) {
  384               System.setSecurityManager(new AppletSecurity());
  385           } else {
  386               System.err.println(lookup("main.nosecmgr"));
  387           }
  388   
  389           // REMIND: Create and install a socket factory!
  390       }
  391   
  392       /**
  393        * Read the AppletViewer user-specific properties.  Typically, these
  394        * properties should reside in the file $USER/.appletviewer.  If this file
  395        * does not exist, one will be created.  Information for this file will
  396        * be gleaned from $USER/.hotjava/properties.  If that file does not exist,
  397        * then default values will be used.
  398        *
  399        * @return     A Properties object containing all of the AppletViewer
  400        *             user-specific properties.
  401        */
  402       private Properties getAVProps() {
  403           Properties avProps = new Properties();
  404   
  405           File dotAV = theUserPropertiesFile;
  406           if (dotAV.exists()) {
  407               // we must have already done the conversion
  408               if (dotAV.canRead()) {
  409                   // just read the file
  410                   avProps = getAVProps(dotAV);
  411               } else {
  412                   // send out warning and use defaults
  413                   System.err.println(lookup("main.warn.cantreadprops",
  414                                             dotAV.toString()));
  415                   avProps = setDefaultAVProps();
  416               }
  417           } else {
  418               // create the $USER/.appletviewer file
  419   
  420               // see if $USER/.hotjava/properties exists
  421               File userHome = new File(System.getProperty("user.home"));
  422               File dotHJ = new File(userHome, ".hotjava");
  423               dotHJ = new File(dotHJ, "properties");
  424               if (dotHJ.exists()) {
  425                   // just read the file
  426                   avProps = getAVProps(dotHJ);
  427               } else {
  428                   // send out warning and use defaults
  429                   System.err.println(lookup("main.warn.cantreadprops",
  430                                             dotHJ.toString()));
  431                   avProps = setDefaultAVProps();
  432               }
  433   
  434               // SAVE THE FILE
  435               try {
  436                   FileOutputStream out = new FileOutputStream(dotAV);
  437                   avProps.store(out, lookup("main.prop.store"));
  438                   out.close();
  439               } catch (IOException e) {
  440                   System.err.println(lookup("main.err.prop.cantsave",
  441                                             dotAV.toString()));
  442               }
  443           }
  444           return avProps;
  445       }
  446   
  447       /**
  448        * Set the AppletViewer user-specific properties to be the default values.
  449        *
  450        * @return     A Properties object containing all of the AppletViewer
  451        *             user-specific properties, set to the default values.
  452        */
  453       private Properties setDefaultAVProps() {
  454           Properties avProps = new Properties();
  455           for (int i = 0; i < avDefaultUserProps.length; i++) {
  456               avProps.setProperty(avDefaultUserProps[i][0],
  457                                   avDefaultUserProps[i][1]);
  458           }
  459           return avProps;
  460       }
  461   
  462       /**
  463        * Given a file, find only the properties that are setable by AppletViewer.
  464        *
  465        * @param inFile A Properties file from which we select the properties of
  466        *             interest.
  467        * @return     A Properties object containing all of the AppletViewer
  468        *             user-specific properties.
  469        */
  470       private Properties getAVProps(File inFile) {
  471           Properties avProps  = new Properties();
  472   
  473           // read the file
  474           Properties tmpProps = new Properties();
  475           try {
  476               FileInputStream in = new FileInputStream(inFile);
  477               tmpProps.load(new BufferedInputStream(in));
  478               in.close();
  479           } catch (IOException e) {
  480               System.err.println(lookup("main.err.prop.cantread",
  481                                         inFile.toString()));
  482           }
  483   
  484           // pick off the properties we care about
  485           for (int i = 0; i < avDefaultUserProps.length; i++) {
  486               String value = tmpProps.getProperty(avDefaultUserProps[i][0]);
  487               if (value != null) {
  488                   // the property exists in the file, so replace the default
  489                   avProps.setProperty(avDefaultUserProps[i][0], value);
  490               } else {
  491                   // just use the default
  492                   avProps.setProperty(avDefaultUserProps[i][0],
  493                                       avDefaultUserProps[i][1]);
  494               }
  495           }
  496           return avProps;
  497       }
  498   
  499       /**
  500        * Methods for easier i18n handling.
  501        */
  502   
  503       private static String lookup(String key) {
  504           return amh.getMessage(key);
  505       }
  506   
  507       private static String lookup(String key, String arg0) {
  508           return amh.getMessage(key, arg0);
  509       }
  510   
  511       private static String lookup(String key, String arg0, String arg1) {
  512           return amh.getMessage(key, arg0, arg1);
  513       }
  514   
  515       private static String lookup(String key, String arg0, String arg1,
  516                                    String arg2) {
  517           return amh.getMessage(key, arg0, arg1, arg2);
  518       }
  519   
  520       class ParseException extends RuntimeException
  521       {
  522           public ParseException(String msg) {
  523               super(msg);
  524           }
  525   
  526           public ParseException(Throwable t) {
  527               super(t.getMessage());
  528               this.t = t;
  529           }
  530   
  531           Throwable t = null;
  532       }
  533   }

Save This Page
Home » openjdk-7 » sun » applet » [javadoc | source]