Ignore:
Timestamp:
Sep 24, 2014, 9:34:21 PM (11 years ago)
Author:
dmik
Message:

icedtea-web: Merge version 1.5.1 from vendor to trunk.

Location:
trunk/icedtea-web/netx/net/sourceforge
Files:
19 deleted
103 edited
50 copied

Legend:

Unmodified
Added
Removed
  • trunk/icedtea-web/netx/net/sourceforge/jnlp/AbstractLaunchHandler.java

    r418 r429  
    3838package net.sourceforge.jnlp;
    3939
    40 import java.io.PrintStream;
    4140
    42 import net.sourceforge.jnlp.runtime.JNLPRuntime;
     41import net.sourceforge.jnlp.util.logging.OutputController;
    4342
    4443public abstract class AbstractLaunchHandler implements LaunchHandler {
    4544
    46     protected final PrintStream outputStream;
     45    protected final OutputController logger;
    4746
    48     public AbstractLaunchHandler(PrintStream outputStream) {
    49         this.outputStream = outputStream;
     47    public AbstractLaunchHandler(OutputController logger) {
     48        this.logger = logger;
    5049    }
    5150
     
    6463            result.append(recursiveDescription(ex.getCause()));
    6564        }
    66         outputStream.println(result);
     65        logger.log(OutputController.Level.MESSAGE_ALL, result.toString());
    6766
    68         if (JNLPRuntime.isDebug()) {
    69             ex.printStackTrace(outputStream);
    70         }
     67        logger.log(ex);
     68       
    7169    }
    7270
  • trunk/icedtea-web/netx/net/sourceforge/jnlp/DefaultLaunchHandler.java

    r418 r429  
    1717package net.sourceforge.jnlp;
    1818
    19 import java.io.PrintStream;
    2019
    2120import net.sourceforge.jnlp.runtime.*;
     21import net.sourceforge.jnlp.util.logging.OutputController;
    2222
    2323/**
     
    3131public class DefaultLaunchHandler extends AbstractLaunchHandler {
    3232
    33     public DefaultLaunchHandler(PrintStream out) {
     33    public DefaultLaunchHandler(OutputController out) {
    3434        super(out);
    3535    }
  • trunk/icedtea-web/netx/net/sourceforge/jnlp/ExtensionDesc.java

    r348 r429  
    2424
    2525import net.sourceforge.jnlp.runtime.JNLPRuntime;
     26import net.sourceforge.jnlp.util.logging.OutputController;
    2627
    2728/**
     
    123124            file = new JNLPFile(location);
    124125
    125             if (JNLPRuntime.isDebug())
    126                 System.out.println("Resolve: " + file.getInformation().getTitle());
     126            OutputController.getLogger().log("Resolve: " + file.getInformation().getTitle());
    127127
    128128            // check for it being an extension descriptor
  • trunk/icedtea-web/netx/net/sourceforge/jnlp/GuiLaunchHandler.java

    r418 r429  
    11/* GuiLaunchHandler.java
    2    Copyright (C) 2011 Red Hat, Inc.
     2   Copyright (C) 2012 Red Hat, Inc.
    33
    44This file is part of IcedTea.
     
    3838package net.sourceforge.jnlp;
    3939
    40 import java.io.PrintStream;
    4140import java.lang.reflect.InvocationTargetException;
    4241import java.net.URL;
     
    4847import net.sourceforge.jnlp.runtime.ApplicationInstance;
    4948import net.sourceforge.jnlp.util.BasicExceptionDialog;
     49import net.sourceforge.jnlp.util.logging.OutputController;
    5050
    5151/**
     
    5555public class GuiLaunchHandler extends AbstractLaunchHandler {
    5656
    57     private JNLPSplashScreen splashScreen = null;
     57    private volatile JNLPSplashScreen splashScreen = null;
    5858    private final Object mutex = new Object();
    5959    private UpdatePolicy policy = UpdatePolicy.ALWAYS;
    6060
    61     public GuiLaunchHandler(PrintStream outputStream) {
     61    public GuiLaunchHandler(OutputController outputStream) {
    6262        super(outputStream);
    6363    }
     
    8181
    8282    private void closeSplashScreen() {
    83         synchronized(mutex) {
     83        synchronized (mutex) {
    8484            if (splashScreen != null) {
    8585                if (splashScreen.isSplashScreenValid()) {
    8686                    splashScreen.setVisible(false);
     87                    splashScreen.stopAnimation();
    8788                }
    8889                splashScreen.dispose();
     
    103104    @Override
    104105    public void launchInitialized(final JNLPFile file) {
    105        
     106
    106107        int preferredWidth = 500;
    107108        int preferredHeight = 400;
     
    110111                IconDesc.SPLASH, preferredWidth, preferredHeight);
    111112
     113        final ResourceTracker resourceTracker = new ResourceTracker(true);
    112114        if (splashImageURL != null) {
    113             final ResourceTracker resourceTracker = new ResourceTracker(true);
    114115            resourceTracker.addResource(splashImageURL, file.getFileVersion(), null, policy);
    115             synchronized(mutex) {
    116                 try {
    117                     SwingUtilities.invokeAndWait(new Runnable() {
    118                         @Override
    119                         public void run() {
    120                             splashScreen = new JNLPSplashScreen(resourceTracker, null, null);
    121                         }
    122                     });
    123                 } catch (InterruptedException ie) {
    124                     // Wait till splash screen is created
    125                     while (splashScreen == null);
    126                 } catch (InvocationTargetException ite) {
    127                     ite.printStackTrace();
    128                 }
     116        }
     117        synchronized (mutex) {
     118            try {
     119                SwingUtilities.invokeAndWait(new Runnable() {
    129120
    130                 splashScreen.setSplashImageURL(splashImageURL);
     121                    @Override
     122                    public void run() {
     123                        splashScreen = new JNLPSplashScreen(resourceTracker, file);
     124                    }
     125                });
     126            } catch (InterruptedException ie) {
     127                // Wait till splash screen is created
     128                while (splashScreen == null);
     129            } catch (InvocationTargetException ite) {
     130                OutputController.getLogger().log(OutputController.Level.ERROR_ALL, ite);
    131131            }
     132            try {
     133                SwingUtilities.invokeAndWait(new Runnable() {
     134
     135                    @Override
     136                    public void run() {
     137                        splashScreen.setSplashImageURL(splashImageURL);
     138                    }
     139                });
     140            } catch (InterruptedException ie) {
     141                // Wait till splash screen is created
     142                while (!splashScreen.isSplashImageLoaded());
     143            } catch (InvocationTargetException ite) {
     144                OutputController.getLogger().log(OutputController.Level.ERROR_ALL, ite);
     145            }
     146
     147
    132148        }
    133        
     149
    134150        SwingUtilities.invokeLater(new Runnable() {
     151
    135152            @Override
    136153            public void run() {
    137                 if (splashImageURL != null) {
    138                     synchronized(mutex) {
     154                if (splashScreen != null) {
     155                    synchronized (mutex) {
    139156                        if (splashScreen.isSplashScreenValid()) {
    140157                            splashScreen.setVisible(true);
  • trunk/icedtea-web/netx/net/sourceforge/jnlp/InformationDesc.java

    r348 r429  
    2222
    2323/**
    24  * The information element.<p>
     24 * The information element.
    2525 *
    2626 * @author <a href="mailto:jmaxwell@users.sourceforge.net">Jon A. Maxwell (JAM)</a> - initial author
     
    3535
    3636    /** one-line description */
    37     public static final Object ONE_LINE = "oneline";
     37    /**http://docs.oracle.com/javase/6/docs/technotes/guides/javaws/developersguide/syntax.html**/
     38    public static final Object ONE_LINE = "one-line";
    3839
    3940    /** short description */
     
    5253    private List<Object> info;
    5354
    54     /** the JNLPFile this information is for */
    55     private JNLPFile jnlpFile;
    5655
    5756    /**
    5857     * Create an information element object.
    5958     *
    60      * @param jnlpFile file that the information is for
    6159     * @param locales the locales the information is for
    6260     */
    63     public InformationDesc(JNLPFile jnlpFile, Locale locales[]) {
    64         this.jnlpFile = jnlpFile;
     61    public InformationDesc(Locale locales[]) {
    6562        this.locales = locales;
    6663    }
     
    111108     */
    112109    public String getDescription(Object kind) {
    113         String result = (String) getItem("description-" + kind);
     110        String result = getDescriptionStrict(kind);
    114111        if (result == null)
    115112            return (String) getItem("description-" + DEFAULT);
    116113        else
    117114            return result;
     115    }
     116
     117      /**
     118     * Returns the application's description of the specified type.
     119     *
     120     * @param kind one of Information.SHORT, Information.ONE_LINE,
     121     * Information.TOOLTIP, Information.DEFAULT
     122     */
     123    public String getDescriptionStrict(Object kind) {
     124        return (String) getItem("description-" + kind);
     125       
    118126    }
    119127
     
    160168        }
    161169
     170        // FIXME if there's no larger icon, choose the closest smaller icon
     171        // instead of the first
    162172        if (best == null)
    163173            best = icons[0];
     
    171181    public Locale[] getLocales() {
    172182        return locales;
    173     }
    174 
    175     /**
    176      * Returns the JNLPFile the information is for.
    177      */
    178     public JNLPFile getJNLPFile() {
    179         return jnlpFile;
    180183    }
    181184
  • trunk/icedtea-web/netx/net/sourceforge/jnlp/JARDesc.java

    r348 r429  
    2222 * The JAR element.
    2323 *
     24 * This class is immutable and thread safe
    2425 * @author <a href="mailto:jmaxwell@users.sourceforge.net">Jon A. Maxwell (JAM)</a> - initial author
    2526 * @version $Revision: 1.6 $
     
    2829
    2930    /** the location of the JAR file */
    30     private URL location;
     31    private final URL location;
    3132
    3233    /** the required JAR versions, or null */
    33     private Version version;
     34    private final Version version;
    3435
    3536    /** the part name */
    36     private String part;
     37    private final String part;
    3738
    3839    /** whether to load the JAR on demand */
    39     private boolean lazy;
     40    private final boolean lazy;
    4041
    4142    /** whether the JAR contains the main class */
    42     private boolean main;
     43    private final boolean main;
    4344
    4445    /** whether the JAR contains native libraries */
    45     private boolean nativeJar;
     46    private final boolean nativeJar;
    4647
    4748    /** whether the JAR can be cached */
    48     private boolean cacheable;
     49    private final boolean cacheable;
    4950
    5051    /**
  • trunk/icedtea-web/netx/net/sourceforge/jnlp/JNLPCreator.java

    r418 r429  
    2929
    3030public class JNLPCreator {
    31     public JNLPFile create(URL location, Version version, boolean strict,
     31    public JNLPFile create(URL location, Version version, ParserSettings settings,
    3232            UpdatePolicy policy, URL forceCodebase) throws IOException, ParseException {
    33         return new JNLPFile(location, version, strict, policy, forceCodebase);
     33        return new JNLPFile(location, version, settings, policy, forceCodebase);
    3434    }
    3535}
  • trunk/icedtea-web/netx/net/sourceforge/jnlp/JNLPFile.java

    r418 r429  
    1717package net.sourceforge.jnlp;
    1818
     19import java.io.File;
     20import java.io.FileInputStream;
    1921import static net.sourceforge.jnlp.runtime.Translator.R;
    2022
    2123import java.io.IOException;
    2224import java.io.InputStream;
    23 import java.io.Reader;
    2425import java.net.URL;
    2526import java.util.ArrayList;
     
    2930import java.util.List;
    3031import java.util.Locale;
    31 
     32import java.util.jar.Attributes;
     33
     34import net.sourceforge.jnlp.SecurityDesc.RequestedPermissionLevel;
    3235import net.sourceforge.jnlp.cache.ResourceTracker;
    3336import net.sourceforge.jnlp.cache.UpdatePolicy;
     37import net.sourceforge.jnlp.runtime.JNLPClassLoader;
    3438import net.sourceforge.jnlp.runtime.JNLPRuntime;
     39import net.sourceforge.jnlp.util.ClasspathMatcher;
     40import net.sourceforge.jnlp.util.logging.OutputController;
    3541
    3642/**
     43 * <p>
    3744 * Provides methods to access the information in a Java Network
    3845 * Launching Protocol (JNLP) file.  The Java Network Launching
    3946 * Protocol specifies in an XML file the information needed to
    4047 * load, cache, and run Java code over the network and in a secure
    41  * environment.<p>
    42  *
     48 * environment.
     49 * </p>
     50 * <p>
    4351 * This class represents the overall information about a JNLP file
    4452 * from the jnlp element.  Other information is accessed through
     
    4654 * (information, resources, application-desc, etc).  References to
    4755 * these objects are obtained by calling the getInformation,
    48  * getResources, getSecurity, etc methods.<p>
     56 * getResources, getSecurity, etc methods.
     57 * </p>
    4958 *
    5059 * @author <a href="mailto:jmaxwell@users.sourceforge.net">Jon A. Maxwell (JAM)</a> - initial author
     
    5261 */
    5362public class JNLPFile {
     63
     64    public static enum ManifestBoolean {
     65        TRUE, FALSE, UNDEFINED;
     66    }
     67   
    5468
    5569    // todo: save the update policy, then if file was not updated
     
    6882    protected URL fileLocation;
    6983
     84    /** the ParserSettings which were used to parse this file */
     85    protected ParserSettings parserSettings = null;
     86
    7087    /** A key that uniquely identifies connected instances (main jnlp+ext) */
    7188    protected String uniqueKey = null;
     
    119136     */
    120137    private String[] generalProperties = SecurityDesc.getJnlpRIAPermissions();
     138   
     139    /** important manifests' attributes */
     140    private final ManifestsAttributes manifestsAttributes = new ManifestsAttributes();
     141
     142    public static final String TITLE_NOT_FOUND = "Application title was not found in manifest. Check with application vendor";
     143
    121144
    122145    { // initialize defaults if security allows
     
    146169     */
    147170    public JNLPFile(URL location) throws IOException, ParseException {
    148         this(location, false); // not strict
     171        this(location, new ParserSettings());
    149172    }
    150173
     
    154177     *
    155178     * @param location the location of the JNLP file
    156      * @param strict whether to enforce the spec when
     179     * @param settings the parser settings to use while parsing the file
    157180     * @throws IOException if an IO exception occurred
    158181     * @throws ParseException if the JNLP file was invalid
    159182     */
    160     public JNLPFile(URL location, boolean strict) throws IOException, ParseException {
    161         this(location, (Version) null, strict);
     183    public JNLPFile(URL location, ParserSettings settings) throws IOException, ParseException {
     184        this(location, (Version) null, settings);
    162185    }
    163186
     
    168191     * @param location the location of the JNLP file
    169192     * @param version the version of the JNLP file
    170      * @param strict whether to enforce the spec when
     193     * @param settings the parser settings to use while parsing the file
    171194     * @throws IOException if an IO exception occurred
    172195     * @throws ParseException if the JNLP file was invalid
    173196     */
    174     public JNLPFile(URL location, Version version, boolean strict) throws IOException, ParseException {
    175         this(location, version, strict, JNLPRuntime.getDefaultUpdatePolicy());
     197    public JNLPFile(URL location, Version version, ParserSettings settings) throws IOException, ParseException {
     198        this(location, version, settings, JNLPRuntime.getDefaultUpdatePolicy());
    176199    }
    177200
     
    182205     * @param location the location of the JNLP file
    183206     * @param version the version of the JNLP file
    184      * @param strict whether to enforce the spec when
     207     * @param settings the {@link ParserSettings} to use when parsing the {@code location}
    185208     * @param policy the update policy
    186209     * @throws IOException if an IO exception occurred
    187210     * @throws ParseException if the JNLP file was invalid
    188211     */
    189     public JNLPFile(URL location, Version version, boolean strict, UpdatePolicy policy) throws IOException, ParseException {
    190         this(location, version, strict, policy, null);
     212    public JNLPFile(URL location, Version version, ParserSettings settings, UpdatePolicy policy) throws IOException, ParseException {
     213            this(location, version, settings, policy, null);
    191214    }
    192215
     
    197220     * @param location the location of the JNLP file
    198221     * @param version the version of the JNLP file
    199      * @param strict whether to enforce the spec when
     222     * @param settings the parser settings to use while parsing the file
    200223     * @param policy the update policy
    201224     * @param forceCodebase codebase to use if not specified in JNLP file.
     
    203226     * @throws ParseException if the JNLP file was invalid
    204227     */
    205     protected JNLPFile(URL location, Version version, boolean strict, UpdatePolicy policy, URL forceCodebase) throws IOException, ParseException {
    206         Node root = Parser.getRootNode(openURL(location, version, policy));
    207         parse(root, strict, location, forceCodebase);
     228    protected JNLPFile(URL location, Version version, ParserSettings settings, UpdatePolicy policy, URL forceCodebase) throws IOException, ParseException {
     229        InputStream input = openURL(location, version, policy);
     230        this.parserSettings = settings;
     231        parse(input, location, forceCodebase);
    208232
    209233        //Downloads the original jnlp file into the cache if possible
     
    221245                         location;
    222246
    223         if (JNLPRuntime.isDebug())
    224             System.err.println("UNIQUEKEY=" + this.uniqueKey);
     247        OutputController.getLogger().log(OutputController.Level.ERROR_DEBUG, "UNIQUEKEY=" + this.uniqueKey);
    225248    }
    226249
     
    232255     * @param uniqueKey A string that uniquely identifies connected instances
    233256     * @param version the version of the JNLP file
    234      * @param strict whether to enforce the spec when
     257     * @param settings the parser settings to use while parsing the file
    235258     * @param policy the update policy
    236259     * @throws IOException if an IO exception occurred
    237260     * @throws ParseException if the JNLP file was invalid
    238261     */
    239     public JNLPFile(URL location, String uniqueKey, Version version, boolean strict, UpdatePolicy policy) throws IOException, ParseException {
    240         this(location, version, strict, policy);
     262    public JNLPFile(URL location, String uniqueKey, Version version, ParserSettings settings, UpdatePolicy policy) throws IOException, ParseException {
     263        this(location, version, settings, policy);
    241264        this.uniqueKey = uniqueKey;
    242265
    243         if (JNLPRuntime.isDebug())
    244             System.err.println("UNIQUEKEY (override) =" + this.uniqueKey);
     266        OutputController.getLogger().log(OutputController.Level.ERROR_DEBUG, "UNIQUEKEY (override) =" + this.uniqueKey);
    245267    }
    246268
     
    251273     * @throws ParseException if the JNLP file was invalid
    252274     */
    253     public JNLPFile(InputStream input, boolean strict) throws ParseException {
    254         parse(Parser.getRootNode(input), strict, null, null);
    255     }
    256 
    257     /**
    258      * Create a JNLPFile from a character stream.
    259      *
    260      * @param input the stream
    261      * @param strict whether to enforce the spec when
     275    public JNLPFile(InputStream input, ParserSettings settings) throws ParseException {
     276        this.parserSettings = settings;
     277        parse(input, null, null);
     278    }
     279
     280    /**
     281     * Create a JNLPFile from an input stream.
     282     *
     283     * @param input input stream of JNLP file.
     284     * @param codebase codebase to use if not specified in JNLP file..
     285     * @param settings the {@link ParserSettings} to use when parsing
    262286     * @throws IOException if an IO exception occurred
    263287     * @throws ParseException if the JNLP file was invalid
    264288     */
    265     private JNLPFile(Reader input, boolean strict) throws ParseException {
    266         // todo: now that we are using NanoXML we can use a Reader
    267         //parse(Parser.getRootNode(input), strict, null);
    268     }
     289    public JNLPFile(InputStream input, URL codebase, ParserSettings settings) throws ParseException {
     290        this.parserSettings = settings;
     291        parse(input, null, codebase);
     292    }
     293
    269294
    270295    /**
     
    279304            ResourceTracker tracker = new ResourceTracker(false); // no prefetch
    280305            tracker.addResource(location, version, null, policy);
    281 
    282             return tracker.getInputStream(location);
     306            File f = tracker.getCacheFile(location);
     307            return new FileInputStream(f);
    283308        } catch (Exception ex) {
    284309            throw new IOException(ex.getMessage());
     
    289314     * Returns the JNLP file's best localized title. This method returns the same
    290315     * value as InformationDesc.getTitle().
     316     *
     317     * Since jdk7 u45, also manifest title, and mainclass are taken to consideration;
     318     * See PluginBridge
    291319     */
    292320    public String getTitle() {
     321        String jnlpTitle = getTitleFromJnlp();
     322        String manifestTitle = getTitleFromManifest();
     323        if (jnlpTitle != null && manifestTitle != null) {
     324            if (jnlpTitle.equals(manifestTitle)) {
     325                return jnlpTitle;
     326            }
     327            return jnlpTitle+" ("+manifestTitle+")";
     328        }
     329        if (jnlpTitle != null && manifestTitle == null) {
     330            return jnlpTitle;
     331        }
     332        if (jnlpTitle == null && manifestTitle != null) {
     333            return manifestTitle;
     334        }
     335        String mainClass = getManifestsAttributes().getMainClass();
     336        return mainClass;       
     337    }
     338   
     339    /**
     340     * Returns the JNLP file's best localized title. This method returns the same
     341     * value as InformationDesc.getTitle().
     342     */
     343    public String getTitleFromJnlp() {
    293344        return getInformation().getTitle();
    294345    }
     346   
     347    public String getTitleFromManifest() {
     348        String inManifestTitle = getManifestsAttributes().getApplicationName();
     349        if (inManifestTitle == null && getManifestsAttributes().isLoader()){
     350            OutputController.getLogger().log(OutputController.Level.WARNING_ALL, TITLE_NOT_FOUND);
     351        }
     352        return inManifestTitle;
     353    }
     354   
     355   
    295356
    296357    /**
     
    326387
    327388    /**
     389     * Returns the ParserSettings that was used to parse this file
     390     */
     391    public ParserSettings getParserSettings() {
     392        return parserSettings;
     393    }
     394
     395    /**
    328396     * Returns the JNLP file's version.
    329397     */
     
    359427     */
    360428    public InformationDesc getInformation(final Locale locale) {
    361         return new InformationDesc(this, new Locale[] { locale }) {
     429        return new InformationDesc(new Locale[] { locale }) {
    362430            @Override
    363431            protected List<Object> getItems(Object key) {
     
    424492    }
    425493
     494    public RequestedPermissionLevel getRequestedPermissionLevel() {
     495        return this.security.getRequestedPermissionLevel();
     496    }
     497
    426498    /**
    427499     * Returns the resources section of the JNLP file as viewed
     
    597669    /**
    598670     * Returns whether a locale is matched by one of more other
    599      * locales.  Only the non-empty language, country, and variant
     671     * locales. Only the non-empty language, country, and variant
    600672     * codes are compared; for example, a requested locale of
    601673     * Locale("","","") would always return true.
    602674     *
    603      * @param requested the local
     675     * @param requested the requested locale
    604676     * @param available the available locales
    605      * @param precision the depth with which to match locales. 1 checks only
    606      * language, 2 checks language and country, 3 checks language, country and
    607      * variant for matches. Passing 0 will always return true.
    608      * @return true if requested matches any of available, or if
    609      * available is empty or null.
    610      */
    611     public boolean localeMatches(Locale requested, Locale available[], Match matchLevel) {
     677     * @param matchLevel the depth with which to match locales.
     678     * @return {@code true} if {@code requested} matches any of {@code available}, or if
     679     * {@code available} is empty or {@code null}.
     680     * @see Locale
     681     * @see Match
     682     */
     683    public boolean localeMatches(Locale requested, Locale[] available, Match matchLevel) {
    612684
    613685        if (matchLevel == Match.GENERALIZED)
     
    672744     * from the constructor.
    673745     *
    674      * @param root the root node
    675      * @param strict whether to enforce the spec when
    676      * @param location the file location or null
    677      */
    678     private void parse(Node root, boolean strict, URL location, URL forceCodebase) throws ParseException {
     746     * @param location the file location or {@code null}
     747     */
     748    private void parse(InputStream input, URL location, URL forceCodebase) throws ParseException {
    679749        try {
    680750            //if (location != null)
    681751            //  location = new URL(location, "."); // remove filename
    682752
    683             Parser parser = new Parser(this, location, root, strict, true, forceCodebase); // true == allow extensions
     753            Node root = Parser.getRootNode(input, parserSettings);
     754            Parser parser = new Parser(this, location, root, parserSettings, forceCodebase); // true == allow extensions
    684755
    685756            // JNLP tag information
     
    701772            throw ex;
    702773        } catch (Exception ex) {
    703             if (JNLPRuntime.isDebug())
    704                 ex.printStackTrace();
    705 
     774            OutputController.getLogger().log(ex);
    706775            throw new RuntimeException(ex.toString());
    707776        }
     
    777846
    778847    /**
    779      * XXX: this method does a "==" comparison between the input JARDesc and
    780      * jars it finds through getResourcesDescs(). If ever the implementation
    781      * of that function should change to return copies of JARDescs objects,
    782      * then the "jar == aJar" comparison below should change accordingly.
    783      * @param jar: the jar whose download options to get.
    784      * @return the download options.
    785      */
    786     public DownloadOptions getDownloadOptionsForJar(JARDesc jar) {
     848     * @return the download options to use for downloading jars listed in this jnlp file.
     849     */
     850    public DownloadOptions getDownloadOptions() {
    787851        boolean usePack = false;
    788852        boolean useVersion = false;
    789         ResourcesDesc[] descs = getResourcesDescs();
    790         for (ResourcesDesc desc: descs) {
    791             JARDesc[] jars = desc.getJARs();
    792             for (JARDesc aJar: jars) {
    793                 if (jar == aJar) {
    794                     if (Boolean.valueOf(desc.getPropertiesMap().get("jnlp.packEnabled"))) {
    795                         usePack = true;
    796                     }
    797                     if (Boolean.valueOf(desc.getPropertiesMap().get("jnlp.versionEnabled"))) {
    798                         useVersion = true;
    799                     }
    800                 }
    801             }
     853        ResourcesDesc desc = getResources();
     854        if (Boolean.valueOf(desc.getPropertiesMap().get("jnlp.packEnabled"))) {
     855            usePack = true;
     856        }
     857        if (Boolean.valueOf(desc.getPropertiesMap().get("jnlp.versionEnabled"))) {
     858            useVersion = true;
    802859        }
    803860        return new DownloadOptions(usePack, useVersion);
     
    820877        missingSignedJNLP = true;
    821878    }
     879
     880    public ManifestsAttributes getManifestsAttributes() {
     881        return manifestsAttributes;
     882    }
     883   
     884   
     885    public class ManifestsAttributes {
     886
     887        public static final String APP_NAME = "Application-Name";
     888        public static final String CALLER_ALLOWABLE = "Caller-Allowable-Codebase";
     889        public static final String APP_LIBRARY_ALLOWABLE = "Application-Library-Allowable-Codebase";
     890        public static final String PERMISSIONS = "Permissions";
     891        public static final String CODEBASE = "Codebase";
     892        public static final String TRUSTED_ONLY = "Trusted-Only";
     893        public static final String TRUSTED_LIBRARY = "Trusted-Library";
     894        private JNLPClassLoader loader;
     895
     896
     897        public void setLoader(JNLPClassLoader loader) {
     898            this.loader = loader;
     899        }
     900
     901        public boolean isLoader() {
     902            return loader != null;
     903        }
     904       
     905       
     906
     907        /**
     908         * main class can be defined outside of manifest.
     909         * This method is mostly for completeness
     910         */
     911        public String getMainClass(){
     912            if (loader == null) {
     913                OutputController.getLogger().log(OutputController.Level.ERROR_DEBUG, "Jars not ready to provide main class");
     914                return null;   
     915            }
     916            return loader.getMainClass();
     917        }
     918       
     919        /**
     920         * http://docs.oracle.com/javase/7/docs/technotes/guides/jweb/manifest.html#app_name
     921         */
     922        public String getApplicationName(){
     923            return getAttribute(APP_NAME);
     924        }
     925       
     926        /**
     927         * http://docs.oracle.com/javase/7/docs/technotes/guides/jweb/manifest.html#caller_allowable
     928         */
     929        public ClasspathMatcher.ClasspathMatchers getCallerAllowableCodebase() {
     930            return getCodeBaseMatchersAttribute(CALLER_ALLOWABLE, false);
     931        }
     932
     933        /**
     934         * http://docs.oracle.com/javase/7/docs/technotes/guides/jweb/manifest.html#app_library
     935         */
     936        public ClasspathMatcher.ClasspathMatchers getApplicationLibraryAllowableCodebase() {
     937            return getCodeBaseMatchersAttribute(APP_LIBRARY_ALLOWABLE, true);
     938        }
     939
     940        /**
     941         * http://docs.oracle.com/javase/7/docs/technotes/guides/jweb/manifest.html#codebase
     942         */
     943        public ClasspathMatcher.ClasspathMatchers getCodebase() {
     944            return getCodeBaseMatchersAttribute(CODEBASE, false);
     945        }
     946
     947        /**
     948         * http://docs.oracle.com/javase/7/docs/technotes/guides/jweb/manifest.html#trusted_only
     949         */
     950        public ManifestBoolean isTrustedOnly() {
     951            return processBooleanAttribute(TRUSTED_ONLY);
     952
     953        }
     954
     955        /**
     956         * http://docs.oracle.com/javase/7/docs/technotes/guides/jweb/manifest.html#trusted_library
     957         */
     958        public ManifestBoolean isTrustedLibrary() {
     959            return processBooleanAttribute(TRUSTED_LIBRARY);
     960
     961        }
     962
     963        /**
     964         * http://docs.oracle.com/javase/7/docs/technotes/guides/jweb/manifest.html#permissions
     965         */
     966        public ManifestBoolean isSandboxForced() {
     967            String s = getAttribute(PERMISSIONS);
     968            if (s == null) {
     969                return ManifestBoolean.UNDEFINED;
     970            } else if (s.trim().equalsIgnoreCase(SecurityDesc.RequestedPermissionLevel.SANDBOX.toHtmlString())) {
     971                return ManifestBoolean.TRUE;
     972            } else if (s.trim().equalsIgnoreCase(SecurityDesc.RequestedPermissionLevel.ALL.toHtmlString())) {
     973                return ManifestBoolean.FALSE;
     974            } else {
     975                throw new IllegalArgumentException("Unknown value of " + PERMISSIONS + " attribute " + s + ". Expected "+SecurityDesc.RequestedPermissionLevel.SANDBOX.toHtmlString()+" or "+SecurityDesc.RequestedPermissionLevel.ALL.toHtmlString());
     976            }
     977
     978
     979        }
     980        /**
     981         * http://docs.oracle.com/javase/7/docs/technotes/guides/jweb/manifest.html#permissions
     982         */
     983        public String permissionsToString() {
     984            String s = getAttribute(PERMISSIONS);
     985            if (s == null) {
     986                return "Not defined";
     987            } else if (s.trim().equalsIgnoreCase(SecurityDesc.RequestedPermissionLevel.SANDBOX.toHtmlString())) {
     988                return s.trim();
     989            } else if (s.trim().equalsIgnoreCase(SecurityDesc.RequestedPermissionLevel.ALL.toHtmlString())) {
     990                return s.trim();
     991            } else {
     992                return "illegal";
     993            }
     994        }
     995
     996        /**
     997         * get custom attribute.
     998         */
     999        public String getAttribute(String name) {
     1000            return getAttribute(new Attributes.Name(name));
     1001        }
     1002
     1003        /**
     1004         * get standard attribute
     1005         */
     1006        public String getAttribute(Attributes.Name name) {
     1007            if (loader == null) {
     1008                OutputController.getLogger().log(OutputController.Level.ERROR_DEBUG, "Jars not ready to provide attribute " + name);
     1009                return null;
     1010            }
     1011            return loader.checkForAttributeInJars(Arrays.asList(getResources().getJARs()), name);
     1012        }
     1013
     1014        public ClasspathMatcher.ClasspathMatchers getCodeBaseMatchersAttribute(String s, boolean includePath) {
     1015            return getCodeBaseMatchersAttribute(new Attributes.Name(s), includePath);
     1016        }
     1017
     1018        public ClasspathMatcher.ClasspathMatchers getCodeBaseMatchersAttribute(Attributes.Name name, boolean includePath) {
     1019            String s = getAttribute(name);
     1020            if (s == null) {
     1021                return null;
     1022            }
     1023            return ClasspathMatcher.ClasspathMatchers.compile(s, includePath);
     1024        }
     1025
     1026        private ManifestBoolean processBooleanAttribute(String id) throws IllegalArgumentException {
     1027            String s = getAttribute(id);
     1028            if (s == null) {
     1029                return ManifestBoolean.UNDEFINED;
     1030            } else {
     1031                s = s.toLowerCase().trim();
     1032                if (s.equals("true")) {
     1033                    return  ManifestBoolean.TRUE;
     1034                } else if (s.equals("false")) {
     1035                    return ManifestBoolean.FALSE;
     1036                } else {
     1037                    throw new IllegalArgumentException("Unknown value of " + id + " attribute " + s + ". Expected true or false");
     1038                }
     1039            }
     1040        }
     1041    }
    8221042}
     1043
  • trunk/icedtea-web/netx/net/sourceforge/jnlp/JNLPMatcher.java

    r418 r429  
    4848import java.util.Collections;
    4949import java.util.LinkedList;
     50import net.sourceforge.jnlp.util.logging.OutputController;
    5051import net.sourceforge.nanoxml.XMLElement;
    5152
     
    203204
    204205    /**
    205      * Compares attributes of two Nodes regardless of order
    206      *
    207      * @param appTemplateNode
    208      *            signed application or template's Node with attributes
    209      * @param launchJNLPNode
    210      *            launching JNLP file's Node with attributes
    211      *
    212      * @return true if both Nodes have 'matched' attributes, otherwise false
     206     * Compares attributes of two {@link Node Nodes} regardless of order
     207     *
     208     * @param templateNode signed application or template's {@link Node} with attributes
     209     * @param launchNode launching JNLP file's {@link Node} with attributes
     210     *
     211     * @return {@code true} if both {@link Node Nodes} have 'matched' attributes, otherwise {@code false}
    213212     */
    214213    private boolean matchAttributes(Node templateNode, Node launchNode) {
     
    262261                stream.close();
    263262            } catch (Exception e) {
    264                 e.printStackTrace(System.err);
     263                OutputController.getLogger().log(OutputController.Level.ERROR_ALL, e);
    265264            }
    266265    }
     
    277276                stream.close();
    278277            } catch (Exception e) {
    279                 e.printStackTrace(System.err);
     278                OutputController.getLogger().log(OutputController.Level.ERROR_ALL, e);
    280279            }
    281280    }
  • trunk/icedtea-web/netx/net/sourceforge/jnlp/JNLPMatcherException.java

    r418 r429  
     1/* JNLPMatcherException.java
     2   Copyright (C) 2011 Red Hat, Inc.
     3
     4This file is part of IcedTea.
     5
     6IcedTea is free software; you can redistribute it and/or
     7modify it under the terms of the GNU General Public License as published by
     8the Free Software Foundation, version 2.
     9
     10IcedTea is distributed in the hope that it will be useful,
     11but WITHOUT ANY WARRANTY; without even the implied warranty of
     12MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
     13General Public License for more details.
     14
     15You should have received a copy of the GNU General Public License
     16along with IcedTea; see the file COPYING.  If not, write to
     17the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
     1802110-1301 USA.
     19
     20Linking this library statically or dynamically with other modules is
     21making a combined work based on this library.  Thus, the terms and
     22conditions of the GNU General Public License cover the whole
     23combination.
     24
     25As a special exception, the copyright holders of this library give you
     26permission to link this library with independent modules to produce an
     27executable, regardless of the license terms of these independent
     28modules, and to copy and distribute the resulting executable under
     29terms of your choice, provided that you also meet, for each linked
     30independent module, the terms and conditions of the license of that
     31module.  An independent module is a module which is not derived from
     32or based on this library.  If you modify this library, you may extend
     33this exception to your version of the library, but you are not
     34obligated to do so.  If you do not wish to do so, delete this
     35exception statement from your version.
     36 */
     37
    138package net.sourceforge.jnlp;
    239
  • trunk/icedtea-web/netx/net/sourceforge/jnlp/JNLPSplashScreen.java

    r418 r429  
     1/* JNLPSplashScreen.java
     2   Copyright (C) 2012 Red Hat, Inc.
     3
     4This file is part of IcedTea.
     5
     6IcedTea is free software; you can redistribute it and/or modify
     7it under the terms of the GNU General Public License as published by
     8the Free Software Foundation; either version 2, or (at your option)
     9any later version.
     10
     11IcedTea is distributed in the hope that it will be useful, but
     12WITHOUT ANY WARRANTY; without even the implied warranty of
     13MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
     14General Public License for more details.
     15
     16You should have received a copy of the GNU General Public License
     17along with IcedTea; see the file COPYING.  If not, write to the
     18Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
     1902110-1301 USA.
     20
     21Linking this library statically or dynamically with other modules is
     22making a combined work based on this library.  Thus, the terms and
     23conditions of the GNU General Public License cover the whole
     24combination.
     25
     26As a special exception, the copyright holders of this library give you
     27permission to link this library with independent modules to produce an
     28executable, regardless of the license terms of these independent
     29modules, and to copy and distribute the resulting executable under
     30terms of your choice, provided that you also meet, for each linked
     31independent module, the terms and conditions of the license of that
     32module.  An independent module is a module which is not derived from
     33or based on this library.  If you modify this library, you may extend
     34this exception to your version of the library, but you are not
     35obligated to do so.  If you do not wish to do so, delete this
     36exception statement from your version. */
     37
    138package net.sourceforge.jnlp;
    239
     40import java.awt.BorderLayout;
    341import java.awt.Dimension;
    442import java.awt.Graphics;
     
    644import java.awt.Image;
    745import java.awt.Insets;
    8 import java.awt.Toolkit;
     46import java.awt.Rectangle;
    947import java.io.IOException;
    1048import java.net.URL;
    11 
    1249import javax.imageio.ImageIO;
    1350import javax.swing.JDialog;
    14 
    1551import net.sourceforge.jnlp.cache.ResourceTracker;
    1652import net.sourceforge.jnlp.runtime.JNLPRuntime;
     53import net.sourceforge.jnlp.splashscreen.SplashPanel;
     54import net.sourceforge.jnlp.splashscreen.SplashUtils;
     55import net.sourceforge.jnlp.splashscreen.parts.InformationElement;
    1756import net.sourceforge.jnlp.util.ImageResources;
     57import net.sourceforge.jnlp.util.logging.OutputController;
     58import net.sourceforge.jnlp.util.ScreenFinder;
    1859
    1960public class JNLPSplashScreen extends JDialog {
    2061
    21     String applicationTitle;
    22     String applicationVendor;
    2362
    2463    ResourceTracker resourceTracker;
     
    2665    URL splashImageUrl;
    2766    Image splashImage;
     67    private final JNLPFile file;
     68    public static final  int DEF_WIDTH=635;
     69    public static final  int DEF_HEIGHT=480;
     70    private SplashPanel componetSplash;
     71    private boolean splashImageLoaded=false;
    2872
    29     public JNLPSplashScreen(ResourceTracker resourceTracker,
    30             String applicationTitle, String applicationVendor) {
     73    public JNLPSplashScreen(ResourceTracker resourceTracker, final JNLPFile file) {
    3174
    3275        setIconImages(ImageResources.INSTANCE.getApplicationImages());
     
    3780
    3881        this.resourceTracker = resourceTracker;
    39         this.applicationTitle = applicationTitle;
    40         this.applicationVendor = applicationVendor;
     82        this.file=file;
    4183
    4284    }
    4385
    4486    public void setSplashImageURL(URL url) {
    45         splashImageUrl = url;
    46         splashImage = null;
     87        splashImageLoaded = false;
    4788        try {
    48             splashImage = ImageIO.read(resourceTracker
    49                     .getCacheFile(splashImageUrl));
     89            if (url != null) {
     90                splashImageUrl = url;
     91                splashImage = null;
     92                try {
     93                    splashImage = ImageIO.read(resourceTracker.getCacheFile(splashImageUrl));
     94                    if (splashImage == null) {
     95                        OutputController.getLogger().log(OutputController.Level.ERROR_DEBUG, "Error loading splash image: " + url);
     96                    }
     97                } catch (IOException e) {
     98                    OutputController.getLogger().log(OutputController.Level.ERROR_DEBUG, "Error loading splash image: " + url);
     99                    splashImage = null;
     100                } catch (IllegalArgumentException argumentException) {
     101                    OutputController.getLogger().log(OutputController.Level.ERROR_DEBUG, "Error loading splash image: " + url);
     102                    splashImage = null;
     103                }
     104            }
     105
    50106            if (splashImage == null) {
    51                 if (JNLPRuntime.isDebug()) {
    52                     System.err.println("Error loading splash image: " + url);
     107                this.setLayout(new BorderLayout());
     108                SplashPanel splash = SplashUtils.getSplashScreen(DEF_WIDTH, DEF_HEIGHT);
     109                if (splash != null) {
     110                    splash.startAnimation();
     111                    splash.setInformationElement(InformationElement.createFromJNLP(file));
     112                    this.add(splash.getSplashComponent());
     113                    this.componetSplash = splash;
    53114                }
    54                 return;
    55115            }
    56         } catch (IOException e) {
    57             if (JNLPRuntime.isDebug()) {
    58                 System.err.println("Error loading splash image: " + url);
    59             }
    60             splashImage = null;
    61             return;
    62         } catch (IllegalArgumentException argumentException) {
    63             if (JNLPRuntime.isDebug()) {
    64                 System.err.println("Error loading splash image: " + url);
    65             }
    66             splashImage = null;
    67             return;
     116            correctSize();
     117        } finally {
     118            splashImageLoaded = true;
    68119        }
    69 
    70         correctSize();
    71120    }
    72121
     122    public boolean isSplashImageLoaded() {
     123        return splashImageLoaded;
     124    }
     125
     126
    73127    public boolean isSplashScreenValid() {
    74         return (splashImage != null);
     128        return (splashImage != null) || (componetSplash != null);
    75129    }
    76130
    77131    private void correctSize() {
    78 
    79         Insets insets = getInsets();
    80         int minimumWidth = splashImage.getWidth(null) + insets.left
    81                 + insets.right;
    82         int minimumHeight = splashImage.getHeight(null) + insets.top
    83                 + insets.bottom;
    84         setMinimumSize(new Dimension(minimumWidth, minimumHeight));
    85 
    86         Dimension screenSize = Toolkit.getDefaultToolkit().getScreenSize();
    87         setLocation((screenSize.width - minimumWidth) / 2,
    88                 (screenSize.height - minimumHeight) / 2);
     132        int minimumWidth = DEF_WIDTH;
     133        int minimumHeight = DEF_HEIGHT;
     134        if (splashImage != null) {
     135            Insets insets = getInsets();
     136            minimumWidth = splashImage.getWidth(null) + insets.left
     137                    + insets.right;
     138            minimumHeight = splashImage.getHeight(null) + insets.top
     139                    + insets.bottom;
     140        }
     141        setMinimumSize(new Dimension(0, 0));
     142        setMaximumSize(new Dimension(Integer.MAX_VALUE, Integer.MAX_VALUE));
     143        setSize(new Dimension(minimumWidth, minimumHeight));
     144        setPreferredSize(new Dimension(minimumWidth, minimumHeight));
     145        ScreenFinder.centerWindowsToCurrentScreen(this);
    89146    }
    90147
     
    92149    public void paint(Graphics g) {
    93150        if (splashImage == null) {
     151            super.paint(g);
    94152            return;
    95153        }
     
    100158
    101159    }
     160
     161    public boolean isCustomSplashscreen() {
     162       return (componetSplash!=null);
     163    }
     164
     165    public void stopAnimation() {
     166        if (isCustomSplashscreen()) componetSplash.stopAnimation();
     167    }
    102168}
  • trunk/icedtea-web/netx/net/sourceforge/jnlp/JREDesc.java

    r348 r429  
    2121import java.net.*;
    2222import java.util.*;
     23import java.util.regex.Matcher;
     24import java.util.regex.Pattern;
    2325
    2426/**
     
    2931 */
    3032public class JREDesc {
     33   
     34    private static final Pattern heapPattern= Pattern.compile("\\d+[kmg]?");
    3135
    3236    /** the platform version or the product version if location is not null */
    33     private Version version;
     37    final private Version version;
    3438
    3539    /** the location of a JRE product or null */
    36     private URL location;
     40    final private URL location;
    3741
    3842    /** inital heap size */
    39     private String initialHeapSize;
     43    final private String initialHeapSize;
    4044
    4145    /** maximum head size */
    42     private String maximumHeapSize;
     46    final private String maximumHeapSize;
    4347
    4448    /** args to pass to the vm */
    45     private String vmArgs;
     49    final private String vmArgs;
    4650
    4751    /** list of ResourceDesc objects */
    48     private List resources;
     52    final private List<ResourcesDesc> resources;
    4953
    5054    /**
     
    6064    public JREDesc(Version version, URL location,
    6165            String vmArgs, String initialHeapSize,
    62             String maximumHeapSize, List resources) throws ParseException {
     66            String maximumHeapSize, List<ResourcesDesc> resources) throws ParseException {
    6367        this.version = version;
    6468        this.location = location;
    6569        this.vmArgs = vmArgs;
    66         checkHeapSize(initialHeapSize);
    67         this.initialHeapSize = initialHeapSize;
    68         checkHeapSize(maximumHeapSize);
    69         this.maximumHeapSize = maximumHeapSize;
     70        this.initialHeapSize = checkHeapSize(initialHeapSize);
     71        this.maximumHeapSize = checkHeapSize(maximumHeapSize);
    7072        this.resources = resources;
    7173    }
     
    113115     * Returns the resources defined for this JRE.
    114116     */
    115     public List getResourcesDesc() {
     117    public List<ResourcesDesc> getResourcesDesc() {
    116118        return resources;
    117119    }
     
    127129    /**
    128130     * Check for valid heap size string
     131     * @return trimed heapSize if correct
    129132     * @throws ParseException if heapSize is invalid
    130133     */
    131     static private void checkHeapSize(String heapSize) throws ParseException {
     134    static String checkHeapSize(String heapSize) throws ParseException {
    132135        // need to implement for completeness even though not used in netx
    133136        if (heapSize == null) {
    134             return;
     137            return null;
    135138        }
    136 
    137         boolean lastCharacterIsDigit = true;
    138         // the last character must be 0-9 or k/K/m/M
    139         char lastChar = Character.toLowerCase(heapSize.charAt(heapSize.length() - 1));
    140         if ((lastChar < '0' || lastChar > '9')) {
    141             lastCharacterIsDigit = false;
    142             if (lastChar != 'k' && lastChar != 'm') {
    143                 throw new ParseException(R("PBadHeapSize", heapSize));
    144             }
     139        heapSize = heapSize.trim();
     140        // the last character must be 0-9 or k/K/m/M/g/G
     141        //0 or 0k/m/g is also accepted value
     142        String heapSizeLower = heapSize.toLowerCase();
     143        Matcher heapMatcher = heapPattern.matcher(heapSizeLower);
     144        if (!heapMatcher.matches()) {
     145            throw new ParseException(R("PBadHeapSize", heapSize));
    145146        }
    146 
    147         int indexOfLastDigit = heapSize.length() - 1;
    148         if (!lastCharacterIsDigit) {
    149             indexOfLastDigit = indexOfLastDigit - 1;
    150         }
    151 
    152         String size = heapSize.substring(0, indexOfLastDigit);
    153         try {
    154             // check that the number is a number!
    155             Integer.valueOf(size);
    156         } catch (NumberFormatException numberFormat) {
    157             throw new ParseException(R("PBadHeapSize", heapSize), numberFormat);
    158         }
    159 
     147        return heapSize;
     148       
    160149    }
    161150
  • trunk/icedtea-web/netx/net/sourceforge/jnlp/LaunchException.java

    r418 r429  
    1717package net.sourceforge.jnlp;
    1818
     19import java.util.Collections;
     20import java.util.Date;
     21import java.util.LinkedList;
     22import java.util.List;
     23
    1924/**
    2025 * Thrown when a JNLP application, applet, or installer could not
     
    2530 */
    2631public class LaunchException extends Exception {
     32
     33
     34    public static class LaunchExceptionWithStamp{
     35        private final LaunchException ex;
     36        private final Date stamp;
     37
     38        private LaunchExceptionWithStamp(LaunchException ex) {
     39            this.ex=ex;
     40            this.stamp=new Date();
     41        }
     42
     43        public LaunchException getEx() {
     44            return ex;
     45        }
     46
     47        public Date getStamp() {
     48            return stamp;
     49        }
     50
     51
     52
     53    }
     54    private static final List<LaunchExceptionWithStamp> launchExceptionChain = Collections.synchronizedList(new LinkedList<LaunchExceptionWithStamp>());
    2755
    2856    private static final long serialVersionUID = 7283827853612357423L;
     
    5583        this.description = description;
    5684        this.severity = severity;
     85        saveLaunchException(this);
    5786    }
    5887
     
    6291    public LaunchException(Throwable cause) {
    6392        super(cause);
     93        saveLaunchException(this);
    6494    }
    6595
     
    6999    public LaunchException(String message, Throwable cause) {
    70100        super(message, cause);
     101        saveLaunchException(this);
    71102    }
    72103
     
    79110    public LaunchException(String message) {
    80111        super(message);
     112        saveLaunchException(this);
    81113    }
    82114
     
    118150    }
    119151
     152    private synchronized void saveLaunchException(LaunchException ex) {
     153        launchExceptionChain.add(new LaunchExceptionWithStamp(ex));
     154
     155    }
     156
     157    public synchronized static List<LaunchExceptionWithStamp> getLaunchExceptionChain() {
     158        return launchExceptionChain;
     159    }
     160   
     161   
     162
    120163}
  • trunk/icedtea-web/netx/net/sourceforge/jnlp/LaunchHandler.java

    r418 r429  
    6262     * splash screen.
    6363     *
    64      * @param application the application instance that is starting
     64     * @param file the JNLP file of the instance that is starting
    6565     */
    6666    public void launchInitialized(JNLPFile file);
  • trunk/icedtea-web/netx/net/sourceforge/jnlp/Launcher.java

    r418 r429  
    2020
    2121import java.applet.Applet;
     22import java.applet.AppletStub;
    2223import java.awt.Container;
     24import java.awt.SplashScreen;
    2325import java.io.File;
    2426import java.lang.reflect.Method;
     
    3032import java.util.List;
    3133import java.util.Map;
    32 import java.util.jar.JarFile;
     34import net.sourceforge.jnlp.util.JarFile;
    3335
    3436import net.sourceforge.jnlp.cache.CacheUtil;
     
    4345import javax.swing.SwingUtilities;
    4446import javax.swing.text.html.parser.ParserDelegator;
     47import net.sourceforge.jnlp.splashscreen.SplashUtils;
     48import net.sourceforge.jnlp.util.logging.OutputController;
    4549
    4650import sun.awt.SunToolkit;
    4751
    4852/**
    49  * Launches JNLPFiles either in the foreground or background.<p>
    50  *
     53 * Launches JNLPFiles either in the foreground or background.
     54 * <p>
    5155 * An optional LaunchHandler can be specified that is notified of
    5256 * warning and error condition while launching and that indicates
    5357 * whether a launch may proceed after a warning has occurred.  If
    5458 * specified, the LaunchHandler is notified regardless of whether
    55  * the file is launched in the foreground or background.<p>
     59 * the file is launched in the foreground or background.
     60 * </p>
    5661 *
    5762 * @author <a href="mailto:jmaxwell@users.sourceforge.net">Jon A. Maxwell (JAM)</a> - initial author
     
    7479    private boolean context = true;
    7580
    76     /** If the application should call System.exit on fatal errors */
     81    /** If the application should call JNLPRuntime.exit on fatal errors */
    7782    private boolean exitOnFailure = true;
    7883
     
    8893        this(null, null);
    8994
    90         if (handler == null)
     95        if (handler == null) {
    9196            handler = JNLPRuntime.getDefaultLaunchHandler();
     97        }
    9298    }
    9399
     
    101107        this(null, null);
    102108
    103         if (handler == null)
     109        if (handler == null) {
    104110            handler = JNLPRuntime.getDefaultLaunchHandler();
     111        }
    105112
    106113        this.exitOnFailure = exitOnFailure;
     
    137144     */
    138145    public void setUpdatePolicy(UpdatePolicy policy) {
    139         if (policy == null)
     146        if (policy == null) {
    140147            throw new IllegalArgumentException(R("LNullUpdatePolicy"));
     148        }
    141149
    142150        this.updatePolicy = policy;
     
    220228        //file.
    221229        if (!file.getInformation().isOfflineAllowed()) {
    222             try {
    223                 //Checks the offline/online status of the system.
    224                 //If system is offline do not launch.
    225                 InetAddress.getByName(file.getSourceLocation().getHost());
    226 
    227             } catch (UnknownHostException ue) {
    228                 System.err.println("File cannot be launched because offline-allowed tag not specified and system currently offline.");
     230            //offline status should be already known from jnlp downloading
     231            if (!JNLPRuntime.isOnlineDetected()) {
     232                OutputController.getLogger().log(OutputController.Level.ERROR_ALL, "File cannot be launched because offline-allowed tag not specified and system currently offline.");
    229233                return null;
    230             } catch (Exception e) {
    231                 System.err.println(e);
    232             }
    233         }
    234 
    235         if (file instanceof PluginBridge && cont != null)
     234            }
     235        }
     236
     237        if (file instanceof PluginBridge && cont != null) {
    236238            tg = new TgThread(file, cont, true);
    237         else if (cont == null)
     239        }
     240        else if (cont == null) {
    238241            tg = new TgThread(file);
    239         else
     242        }
     243        else {
    240244            tg = new TgThread(file, cont);
     245        }
    241246
    242247        tg.start();
     
    249254        }
    250255
    251         if (tg.getException() != null)
    252             throw tg.getException(); // passed to handler when first created
    253 
    254         if (handler != null)
     256        if (tg.getException() != null) {
     257            throw tg.getException();
     258        } // passed to handler when first created
     259
     260        if (handler != null) {
    255261            handler.launchCompleted(tg.getApplication());
     262        }
    256263
    257264        return tg.getApplication();
    258265    }
     266
    259267
    260268    /**
     
    263271     *
    264272     * @param location the URL of the JNLP file to launch
    265      * @throws LaunchException if there was an exception
    266      * @return the application instance
    267      */
    268     public ApplicationInstance launch(URL location) throws LaunchException {
    269         return launch(toFile(location));
    270     }
    271 
    272     /**
    273      * Launches a JNLP file by calling the launch method for the
    274      * appropriate file type.
    275      *
    276      * @param location the URL of the JNLP file to launch
    277      * @param fromSource if true, the JNLP file will be re-read from the source
    278273     * location to get the pristine version
    279274     * @throws LaunchException if there was an exception
    280275     * @return the application instance
    281276     */
    282     public ApplicationInstance launch(URL location, boolean fromSource) throws LaunchException {
    283         return launch(fromUrl(location, fromSource));
     277    public ApplicationInstance launch(URL location) throws LaunchException {
     278        JNLPRuntime.saveHistory(location.toExternalForm());
     279        return launch(fromUrl(location));
    284280    }
    285281
     
    370366    }
    371367
    372     /**
    373      * Launches a JNLP file by calling the launch method for the
    374      * appropriate file type in a different thread.
    375      *
    376      * @param file the JNLP file to launch
    377      */
    378     public void launchBackground(JNLPFile file) {
    379         BgRunner runner = new BgRunner(file, null);
    380         new Thread(runner).start();
    381     }
    382 
    383     /**
    384      * Launches the JNLP file at the specified location in the
    385      * background by calling the launch method for its file type.
    386      *
    387      * @param location the location of the JNLP file
    388      */
    389     public void launchBackground(URL location) {
    390         BgRunner runner = new BgRunner(null, location);
    391         new Thread(runner).start();
    392     }
    393 
     368 
    394369    /**
    395370     * Launches the JNLP file in a new JVM instance.  The launched
     
    407382        List<String> updatedArgs = new LinkedList<String>(javawsArgs);
    408383
    409         if (file.getFileLocation() != null)
     384        if (file.getFileLocation() != null) {
    410385            updatedArgs.add(file.getFileLocation().toString());
    411         else if (file.getSourceLocation() != null)
     386        }
     387        else if (file.getSourceLocation() != null) {
    412388            updatedArgs.add(file.getFileLocation().toString());
    413         else
     389        }
     390        else {
    414391            launchError(new LaunchException(file, null, R("LSFatal"), R("LCExternalLaunch"), R("LNullLocation"), R("LNullLocationInfo")));
     392        }
    415393
    416394        launchExternal(vmArgs, updatedArgs);
     
    471449     * Returns the JNLPFile for the URL, with error handling.
    472450     */
    473     private JNLPFile fromUrl(URL location, boolean fromSource) throws LaunchException {
     451    private JNLPFile fromUrl(URL location) throws LaunchException {
    474452        try {
    475             JNLPFile file = null;
    476 
    477             file = new JNLPFile(location, parserSettings.isStrict());
    478 
    479             if (fromSource) {
    480                 // Launches the jnlp file where this file originated.
    481                 if (file.getSourceLocation() != null) {
    482                     file = new JNLPFile(file.getSourceLocation(), parserSettings.isStrict());
     453            JNLPFile file = new JNLPFile(location, parserSettings);
     454           
     455            boolean isLocal = false;
     456            boolean haveHref = false;
     457            if ("file".equalsIgnoreCase(location.getProtocol()) && new File(location.getFile()).exists()) {
     458                isLocal = true;
     459            }
     460            if (file.getSourceLocation() != null) {
     461                haveHref = true;
     462            }
     463            if (!isLocal && haveHref){
     464                //this is case when remote file have href to different file
     465                if (!location.equals(file.getSourceLocation())){
     466                    //mark local true, so the folowing condition will be true and
     467                    //new jnlp file will be downlaoded
     468                    isLocal = true;
     469                    //maybe this check is to strict, and will force redownlaod to often
     470                    //another check can be just on jnlp name. But it will not work
     471                    //if the href will be the file of same name, but on diferent path (or even domain)
    483472                }
     473            }
     474
     475            if (isLocal && haveHref) {
     476                file = new JNLPFile(file.getSourceLocation(), parserSettings);
    484477            }
    485478            return file;
    486479        } catch (Exception ex) {
    487             if (ex instanceof LaunchException)
     480            if (ex instanceof LaunchException) {
    488481                throw (LaunchException) ex; // already sent to handler when first thrown
    489             else
     482            } else {
    490483                // IO and Parse
    491484                throw launchError(new LaunchException(null, ex, R("LSFatal"), R("LCReadError"), R("LCantRead"), R("LCantReadInfo")));
    492         }
    493     }
    494 
    495     /**
    496      * Returns the JNLPFile for the URL, with error handling.
    497      */
    498     @Deprecated
    499     private JNLPFile toFile(URL location) throws LaunchException {
    500         try {
    501             JNLPFile file = null;
    502 
    503             try {
    504                 file = new JNLPFile(location, (Version) null, true, updatePolicy); // strict
    505             } catch (ParseException ex) {
    506                 file = new JNLPFile(location, (Version) null, false, updatePolicy);
    507 
    508                 // only here if strict failed but lax did not fail
    509                 LaunchException lex =
    510                         launchWarning(new LaunchException(file, ex, R("LSMinor"), R("LCFileFormat"), R("LNotToSpec"), R("LNotToSpecInfo")));
    511 
    512                 if (lex != null)
    513                     throw lex;
    514             }
    515 
    516             return file;
    517         } catch (Exception ex) {
    518             if (ex instanceof LaunchException)
    519                 throw (LaunchException) ex; // already sent to handler when first thrown
    520             else
    521                 // IO and Parse
    522                 throw launchError(new LaunchException(null, ex, R("LSFatal"), R("LCReadError"), R("LCantRead"), R("LCantReadInfo")));
    523         }
    524     }
    525 
    526     /**
     485            }
     486        }
     487    }
     488
     489   /**
    527490     * Launches a JNLP application.  This method should be called
    528491     * from a thread in the application's thread group.
    529492     */
    530493    protected ApplicationInstance launchApplication(JNLPFile file) throws LaunchException {
    531         if (!file.isApplication())
     494        if (!file.isApplication()) {
    532495            throw launchError(new LaunchException(file, null, R("LSFatal"), R("LCClient"), R("LNotApplication"), R("LNotApplicationInfo")));
     496        }
    533497
    534498        try {
     
    537501                ServiceUtil.checkExistingSingleInstance(file);
    538502            } catch (InstanceExistsException e) {
     503                OutputController.getLogger().log("Single instance application is already running.");
    539504                return null;
    540505            }
    541506
    542507            if (JNLPRuntime.getForksAllowed() && file.needsNewVM()) {
     508                if (!JNLPRuntime.isHeadless()){
     509                    SplashScreen sp = SplashScreen.getSplashScreen();
     510                    if (sp!=null) {
     511                        sp.close();
     512                    }
     513                }
    543514                List<String> netxArguments = new LinkedList<String>();
    544515                netxArguments.add("-Xnofork");
     
    567538            }
    568539
    569             if (mainName == null)
     540            if (mainName == null) {
    570541                throw launchError(new LaunchException(file, null,
    571542                        R("LSFatal"), R("LCClient"), R("LCantDetermineMainClass"),
    572543                        R("LCantDetermineMainClassInfo")));
     544            }
    573545
    574546            Class<?> mainClass = app.getClassLoader().loadClass(mainName);
     
    579551            SwingUtilities.invokeAndWait(new Runnable() {
    580552                // dummy method to force Event Dispatch Thread creation
     553                @Override
    581554                public void run() {
    582555                }
     
    589562            main.setAccessible(true);
    590563
    591             if (JNLPRuntime.isDebug()) {
    592                 System.out.println("Invoking main() with args: " + Arrays.toString(args));
    593             }
     564            OutputController.getLogger().log("Invoking main() with args: " + Arrays.toString(args));
    594565            main.invoke(null, new Object[] { args });
    595566
     
    625596        for (Thread thread : threads) {
    626597            if (thread != null) {
    627                 if (JNLPRuntime.isDebug()) {
    628                     System.err.println("Setting " + classLoader + " as the classloader for thread " + thread.getName());
    629                 }
     598                OutputController.getLogger().log(OutputController.Level.ERROR_DEBUG, "Setting " + classLoader + " as the classloader for thread " + thread.getName());
    630599                thread.setContextClassLoader(classLoader);
    631600            }
     
    636605    /**
    637606     * Launches a JNLP applet. This method should be called from a
    638      * thread in the application's thread group.<p>
    639      *
     607     * thread in the application's thread group.
     608     * <p>
    640609     * The enableCodeBase parameter adds the applet's codebase to
    641610     * the locations searched for resources and classes.  This can
     
    644613     * JNLP file.  If the applet JNLP file does not specify any
    645614     * resources then the code base will be enabled regardless of
    646      * the specified value.<p>
     615     * the specified value.
     616     * </p>
    647617     *
    648618     * @param file the JNLP file
     
    650620     */
    651621    protected ApplicationInstance launchApplet(JNLPFile file, boolean enableCodeBase, Container cont) throws LaunchException {
    652         if (!file.isApplet())
     622        if (!file.isApplet()) {
    653623            throw launchError(new LaunchException(file, null, R("LSFatal"), R("LCClient"), R("LNotApplet"), R("LNotAppletInfo")));
    654 
     624        }
     625     
     626        if (JNLPRuntime.getForksAllowed() && file.needsNewVM()) {
     627            if (!JNLPRuntime.isHeadless()) {
     628                SplashScreen sp = SplashScreen.getSplashScreen();
     629                if (sp != null) {
     630                    sp.close();
     631                }
     632            }
     633        }
     634        if (handler != null) {
     635            handler.launchInitialized(file);
     636        }
     637       
     638        AppletInstance applet = null;
    655639        try {
    656             AppletInstance applet = createApplet(file, enableCodeBase, cont);
     640            ServiceUtil.checkExistingSingleInstance(file);
     641            applet = createApplet(file, enableCodeBase, cont);
    657642            applet.initialize();
    658 
    659643            applet.getAppletEnvironment().startApplet(); // this should be a direct call to applet instance
    660644            return applet;
     645        } catch (InstanceExistsException ieex) {
     646            OutputController.getLogger().log("Single instance applet is already running.");
     647            throw launchError(new LaunchException(file, ieex, R("LSFatal"), R("LCLaunching"), R("LCouldNotLaunch"), R("LSingleInstanceExists")), applet);
    661648        } catch (LaunchException lex) {
    662             throw launchError(lex);
     649            throw launchError(lex, applet);
    663650        } catch (Exception ex) {
    664             throw launchError(new LaunchException(file, ex, R("LSFatal"), R("LCLaunching"), R("LCouldNotLaunch"), R("LCouldNotLaunchInfo")));
     651            throw launchError(new LaunchException(file, ex, R("LSFatal"), R("LCLaunching"), R("LCouldNotLaunch"), R("LCouldNotLaunchInfo")), applet);
     652        }finally{
     653            if (handler != null) {
     654                handler.launchStarting(applet);
     655            }
    665656        }
    666657    }
     
    670661     */
    671662    protected ApplicationInstance getApplet(JNLPFile file, boolean enableCodeBase, Container cont) throws LaunchException {
    672         if (!file.isApplet())
     663        if (!file.isApplet()) {
    673664            throw launchError(new LaunchException(file, null, R("LSFatal"), R("LCClient"), R("LNotApplet"), R("LNotAppletInfo")));
    674 
     665        }
     666        AppletInstance applet = null;
    675667        try {
    676             AppletInstance applet = createApplet(file, enableCodeBase, cont);
     668            ServiceUtil.checkExistingSingleInstance(file);
     669            applet = createApplet(file, enableCodeBase, cont);
    677670            applet.initialize();
    678671            return applet;
     672
     673        } catch (InstanceExistsException ieex) {
     674            OutputController.getLogger().log("Single instance applet is already running.");
     675            throw launchError(new LaunchException(file, ieex, R("LSFatal"), R("LCLaunching"), R("LCouldNotLaunch"), R("LSingleInstanceExists")), applet);
    679676        } catch (LaunchException lex) {
    680             throw launchError(lex);
     677            throw launchError(lex, applet);
    681678        } catch (Exception ex) {
    682             throw launchError(new LaunchException(file, ex, R("LSFatal"), R("LCLaunching"), R("LCouldNotLaunch"), R("LCouldNotLaunchInfo")));
     679            throw launchError(new LaunchException(file, ex, R("LSFatal"), R("LCLaunching"), R("LCouldNotLaunch"), R("LCouldNotLaunchInfo")), applet);
    683680        }
    684681    }
     
    689686     */
    690687    protected ApplicationInstance launchInstaller(JNLPFile file) throws LaunchException {
     688        // TODO Check for an existing single instance once implemented.
     689        // ServiceUtil.checkExistingSingleInstance(file);
    691690        throw launchError(new LaunchException(file, null, R("LSFatal"), R("LCNotSupported"), R("LNoInstallers"), R("LNoInstallersInfo")));
    692691    }
     
    697696     * @param enableCodeBase whether to add the code base URL to the classloader
    698697     */
    699     protected AppletInstance createApplet(JNLPFile file, boolean enableCodeBase, Container cont) throws LaunchException {
    700         try {
    701             JNLPClassLoader loader = JNLPClassLoader.getInstance(file, updatePolicy);
     698     //FIXME - when multiple applets are on one page, this method is visited simultaneously
     699    //and then appelts creates in little bit strange manner. This issue is visible with
     700    //randomly showing/notshowing spalshscreens.
     701    //See also PluginAppletViewer.framePanel
     702    protected  AppletInstance createApplet(JNLPFile file, boolean enableCodeBase, Container cont) throws LaunchException {
     703         AppletInstance appletInstance = null;
     704         try {
     705            JNLPClassLoader loader = JNLPClassLoader.getInstance(file, updatePolicy, enableCodeBase);
    702706
    703707            if (enableCodeBase) {
     
    712716            // services. This could potentially be done in applet constructor
    713717            // so initialize appletInstance before creating applet.
    714             AppletInstance appletInstance;
    715             if (cont == null)
    716                 appletInstance = new AppletInstance(file, group, loader, null);
    717             else
    718                 appletInstance = new AppletInstance(file, group, loader, null, cont);
     718            if (cont == null) {
     719                 appletInstance = new AppletInstance(file, group, loader, null);
     720             } else {
     721                 appletInstance = new AppletInstance(file, group, loader, null, cont);
     722             }
    719723
    720724            loader.setApplication(appletInstance);
     
    723727            // appletInstance.
    724728            String appletName = file.getApplet().getMainClass();
    725             Class appletClass = loader.loadClass(appletName);
     729            Class<?> appletClass = loader.loadClass(appletName);
    726730            Applet applet = (Applet) appletClass.newInstance();
     731            applet.setStub((AppletStub)cont);
    727732            // Finish setting up appletInstance.
    728733            appletInstance.setApplet(applet);
     
    733738            return appletInstance;
    734739        } catch (Exception ex) {
    735             throw launchError(new LaunchException(file, ex, R("LSFatal"), R("LCInit"), R("LInitApplet"), R("LInitAppletInfo")));
     740            throw launchError(new LaunchException(file, ex, R("LSFatal"), R("LCInit"), R("LInitApplet"), R("LInitAppletInfo")), appletInstance);
    736741        }
    737742    }
     
    745750    protected Applet createAppletObject(JNLPFile file, boolean enableCodeBase, Container cont) throws LaunchException {
    746751        try {
    747             JNLPClassLoader loader = JNLPClassLoader.getInstance(file, updatePolicy);
     752            JNLPClassLoader loader = JNLPClassLoader.getInstance(file, updatePolicy, enableCodeBase);
    748753
    749754            if (enableCodeBase) {
     
    754759
    755760            String appletName = file.getApplet().getMainClass();
    756             Class appletClass = loader.loadClass(appletName);
     761            Class<?> appletClass = loader.loadClass(appletName);
    757762            Applet applet = (Applet) appletClass.newInstance();
    758763
     
    768773    protected ApplicationInstance createApplication(JNLPFile file) throws LaunchException {
    769774        try {
    770             JNLPClassLoader loader = JNLPClassLoader.getInstance(file, updatePolicy);
     775            JNLPClassLoader loader = JNLPClassLoader.getInstance(file, updatePolicy, false);
    771776            ThreadGroup group = Thread.currentThread().getThreadGroup();
    772777
     
    788793     */
    789794    protected ThreadGroup createThreadGroup(JNLPFile file) {
    790         ThreadGroup tg = null;
     795        final ThreadGroup tg;
    791796
    792797        if (file instanceof PluginBridge) {
     
    804809     */
    805810    private LaunchException launchError(LaunchException ex) {
    806         if (handler != null)
     811        return launchError(ex, null);
     812    }
     813   
     814    private LaunchException launchError(LaunchException ex, AppletInstance applet) {
     815        if (applet != null) {
     816            SplashUtils.showErrorCaught(ex, applet);
     817        }
     818        if (handler != null) {
    807819            handler.launchError(ex);
     820        }
    808821
    809822        return ex;
     
    818831     */
    819832    private LaunchException launchWarning(LaunchException ex) {
    820         if (handler != null)
     833        if (handler != null) {
    821834            if (!handler.launchWarning(ex))
    822835                // no need to destroy the app b/c it hasn't started
    823                 return ex; // chose to abort
     836                return ex;
     837        } // chose to abort
    824838
    825839        return null; // chose to continue, or no handler
     
    843857    }
    844858
    845     /**
     859       /**
    846860     * This runnable is used to call the appropriate launch method
    847861     * for the application, applet, or installer in its thread group.
     
    872886        }
    873887
     888        @Override
    874889        public void run() {
    875890            try {
    876891                // Do not create new AppContext if we're using NetX and icedteaplugin.
    877892                // The plugin needs an AppContext too, but it has to be created earlier.
    878                 if (context && !isPlugin)
     893                if (context && !isPlugin) {
    879894                    SunToolkit.createNewAppContext();
     895                }
    880896
    881897                doPerApplicationAppContextHacks();
     
    886902                    application = getApplet(file, ((PluginBridge)file).codeBaseLookup(), cont);
    887903                } else {
    888                     if (file.isApplication())
     904                    if (file.isApplication()) {
    889905                        application = launchApplication(file);
    890                     else if (file.isApplet())
    891                         application = launchApplet(file, true, cont); // enable applet code base
    892                     else if (file.isInstaller())
     906                    }
     907                    else if (file.isApplet()) {
     908                        application = launchApplet(file, true, cont);
     909                    } // enable applet code base
     910                    else if (file.isInstaller()) {
    893911                        application = launchInstaller(file);
    894                     else
     912                    }
     913                    else {
    895914                        throw launchError(new LaunchException(file, null,
    896915                                                R("LSFatal"), R("LCClient"), R("LNotLaunchable"),
    897916                                                R("LNotLaunchableInfo")));
     917                    }
    898918                }
    899919            } catch (LaunchException ex) {
    900                 ex.printStackTrace();
     920                OutputController.getLogger().log(OutputController.Level.ERROR_ALL, ex);
    901921                exception = ex;
    902922                // Exit if we can't launch the application.
    903                 if (exitOnFailure)
    904                     System.exit(1);
     923                if (exitOnFailure) {
     924                    JNLPRuntime.exit(1);
     925                }
     926            }  catch (Throwable ex) {
     927                OutputController.getLogger().log(OutputController.Level.ERROR_ALL, ex);
     928                throw new RuntimeException(ex);
    905929            }
    906930        }
     
    916940    };
    917941
    918     /**
    919      * This runnable is used by the <code>launchBackground</code>
    920      * methods to launch a JNLP file from a separate thread.
    921      */
    922     private class BgRunner implements Runnable {
    923         private JNLPFile file;
    924         private URL location;
    925 
    926         BgRunner(JNLPFile file, URL location) {
    927             this.file = file;
    928             this.location = location;
    929         }
    930 
    931         public void run() {
    932             try {
    933                 if (file != null)
    934                     launch(file);
    935                 if (location != null)
    936                     launch(location);
    937             } catch (LaunchException ex) {
    938                 // launch method communicates error conditions to the
    939                 // handler if it exists, otherwise we don't care because
    940                 // there's nothing that can be done about the exception.
    941             }
    942         }
    943     };
    944 
    945942}
  • trunk/icedtea-web/netx/net/sourceforge/jnlp/NetxPanel.java

    r418 r429  
    11/*
    2  * Copyright 2007 Red Hat, Inc.
     2 * Copyright 2012 Red Hat, Inc.
    33 * This file is part of IcedTea, http://icedtea.classpath.org
    44 * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
     
    2323package net.sourceforge.jnlp;
    2424
    25 import net.sourceforge.jnlp.AppletLog;
    2625import net.sourceforge.jnlp.runtime.AppletInstance;
    2726import net.sourceforge.jnlp.runtime.JNLPRuntime;
     
    2928import java.net.URL;
    3029import java.util.HashMap;
    31 import java.util.Hashtable;
    3230import java.util.Map;
    3331import java.util.concurrent.ConcurrentHashMap;
    3432import java.util.concurrent.ConcurrentMap;
    35 
    36 import sun.applet.AppletViewerPanel;
     33import net.sourceforge.jnlp.splashscreen.SplashController;
     34import net.sourceforge.jnlp.splashscreen.SplashPanel;
     35import net.sourceforge.jnlp.splashscreen.SplashUtils;
     36import net.sourceforge.jnlp.util.logging.OutputController;
     37
     38import sun.applet.AppletViewerPanelAccess;
    3739import sun.awt.SunToolkit;
    3840
    3941/**
    4042 * This panel calls into netx to run an applet, and pipes the display
    41  * into a panel from gcjwebplugin.
    42  *
    43  * @author      Francis Kung <fkung@redhat.com>
     43 * into a panel from the icedtea-web browser plugin.
     44 *
     45 * @author      Francis Kung &lt;fkung@redhat.com&gt;
    4446 */
    45 public class NetxPanel extends AppletViewerPanel {
     47public class NetxPanel extends AppletViewerPanelAccess implements SplashController {
     48    private final PluginParameters parameters;
    4649    private PluginBridge bridge = null;
    47     private boolean exitOnFailure = true;
    4850    private AppletInstance appInst = null;
    49     private boolean appletAlive;
    50     private final String uKey;
     51    private SplashController splashController;
     52    private volatile boolean initialized;
    5153
    5254    // We use this so that we can create exactly one thread group
     
    6668        new ConcurrentHashMap<String, Boolean>();
    6769
    68     public NetxPanel(URL documentURL, Hashtable<String, String> atts) {
    69         super(documentURL, atts);
    70 
    71         /* According to http://download.oracle.com/javase/6/docs/technotes/guides/deployment/deployment-guide/applet-compatibility.html,
    72          * classloaders are shared iff these properties match:
    73          * codebase, cache_archive, java_archive, archive
    74          *
    75          * To achieve this, we create the uniquekey based on those 4 values,
    76          * always in the same order. The initial "<NAME>=" parts ensure a
    77          * bad tag cannot trick the loader into getting shared with another.
    78          */
    79 
    80         // Firefox sometimes skips the codebase if it is default  -- ".",
    81         // so set it that way if absent
    82         String codebaseAttr =      atts.get("codebase") != null ?
    83                                    atts.get("codebase") : ".";
    84 
    85         String cache_archiveAttr = atts.get("cache_archive") != null ?
    86                                    atts.get("cache_archive") : "";
    87 
    88         String java_archiveAttr =  atts.get("java_archive") != null ?
    89                                    atts.get("java_archive") : "";
    90 
    91         String archiveAttr =       atts.get("archive") != null ?
    92                                    atts.get("archive") : "";
    93 
    94         this.uKey = "codebase=" + codebaseAttr +
    95                     "cache_archive=" + cache_archiveAttr +
    96                     "java_archive=" + java_archiveAttr +
    97                     "archive=" +  archiveAttr;
    98 
    99         // when this was being done (incorrectly) in Launcher, the call was
    100         // new AppThreadGroup(mainGroup, file.getTitle());
     70    public NetxPanel(URL documentURL, PluginParameters params) {
     71        super(documentURL, params.getUnderlyingHashtable());
     72
     73        this.parameters = params;
     74        this.initialized = false;
     75
     76        String uniqueKey = params.getUniqueKey(getCodeBase());
    10177        synchronized(TGMapMutex) {
    102             if (!uKeyToTG.containsKey(this.uKey)) {
    103                 ThreadGroup tg = new ThreadGroup(Launcher.mainGroup, this.documentURL.toString());
    104                 uKeyToTG.put(this.uKey, tg);
     78            if (!uKeyToTG.containsKey(uniqueKey)) {
     79                ThreadGroup tg = new ThreadGroup(Launcher.mainGroup, this.getDocumentURL().toString());
     80                uKeyToTG.put(uniqueKey, tg);
    10581            }
    10682        }
    107     }
    108 
    109     // overloaded constructor, called when initialized via plugin
    110     public NetxPanel(URL documentURL, Hashtable<String, String> atts,
    111                      boolean exitOnFailure) {
    112         this(documentURL, atts);
    113         this.exitOnFailure = exitOnFailure;
    114         this.appletAlive = true;
    11583    }
    11684
     
    12189         * and stopping the applet.
    12290         */
    123         AppletLog.log(t);
     91        OutputController.getLogger().log(OutputController.Level.MESSAGE_ALL, t); //new logger
    12492        super.showAppletException(t);
    12593    }
     
    12795    //Overriding to use Netx classloader. You might need to relax visibility
    12896    //in sun.applet.AppletPanel for runLoader().
    129     protected void runLoader() {
     97    @Override
     98    protected void ourRunLoader() {
    13099
    131100        try {
    132             bridge = new PluginBridge(baseURL,
     101            bridge = new PluginBridge(getBaseURL(),
    133102                                getDocumentBase(),
    134103                                getJarFiles(),
     
    136105                                getWidth(),
    137106                                getHeight(),
    138                                 atts, uKey);
     107                                parameters);
    139108
    140109            doInit = true;
     
    142111            status = APPLET_LOAD;
    143112
    144             Launcher l = new Launcher(exitOnFailure);
    145 
    146             try {
    147                 appInst = (AppletInstance) l.launch(bridge, this);
    148             } catch (LaunchException e) {
    149                 // Assume user has indicated he does not trust the
    150                 // applet.
    151                 if (exitOnFailure)
    152                     System.exit(1);
    153             }
    154             applet = appInst.getApplet();
    155 
    156             //On the other hand, if you create an applet this way, it'll work
    157             //fine. Note that you might to open visibility in sun.applet.AppletPanel
    158             //for this to work (the loader field, and getClassLoader).
    159             //loader = getClassLoader(getCodeBase(), getClassLoaderCacheKey());
    160             //applet = createApplet(loader);
    161 
    162             // This shows that when using NetX's JNLPClassLoader, keyboard input
    163             // won't make it to the applet, whereas using sun.applet.AppletClassLoader
    164             // works just fine.
    165 
    166             dispatchAppletEvent(APPLET_LOADING_COMPLETED, null);
    167 
    168             if (applet != null) {
     113            Launcher l = new Launcher(false);
     114
     115            // May throw LaunchException:
     116            appInst = (AppletInstance) l.launch(bridge, this);
     117            setApplet(appInst.getApplet());
     118
     119            if (getApplet() != null) {
    169120                // Stick it in the frame
    170                 applet.setStub(this);
    171                 applet.setVisible(false);
    172                 add("Center", applet);
     121                getApplet().setStub(this);
     122                getApplet().setVisible(false);
     123                add("Center", getApplet());
    173124                showAppletStatus("loaded");
    174125                validate();
    175126            }
    176127        } catch (Exception e) {
    177             this.appletAlive = false;
    178             e.printStackTrace();
     128            status = APPLET_ERROR;
     129            OutputController.getLogger().log(OutputController.Level.ERROR_ALL, e);
     130            replaceSplash(SplashUtils.getErrorSplashScreen(getWidth(), getHeight(), e));
     131        } finally {
     132            // PR1157: This needs to occur even in the case of an exception
     133            // so that the applet's event listeners are signaled.
     134            // Once PluginAppletViewer.AppletEventListener is signaled PluginAppletViewer can properly stop waiting
     135            // in PluginAppletViewer.waitForAppletInit
     136            this.initialized = true;
     137            dispatchAppletEvent(APPLET_LOADING_COMPLETED, null);
    179138        }
    180139    }
     
    185144     */
    186145    // Reminder: Relax visibility in sun.applet.AppletPanel
     146    @Override
    187147    protected synchronized void createAppletThread() {
    188148        // initialize JNLPRuntime in the main threadgroup
     
    190150            //The custom NetX Policy and SecurityManager are set here.
    191151            if (!JNLPRuntime.isInitialized()) {
    192                 if (JNLPRuntime.isDebug())
    193                     System.out.println("initializing JNLPRuntime...");
     152                OutputController.getLogger().log("initializing JNLPRuntime...");
    194153
    195154                JNLPRuntime.initialize(false);
    196155            } else {
    197                 if (JNLPRuntime.isDebug())
    198                     System.out.println("JNLPRuntime already initialized");
     156                OutputController.getLogger().log("JNLPRuntime already initialized");
    199157            }
    200158        }
    201159
    202         handler = new Thread(getThreadGroup(), this);
     160        handler = new Thread(getThreadGroup(), this, "NetxPanelThread@" + this.getDocumentURL());
    203161        handler.start();
    204162    }
    205163
    206164    public void updateSizeInAtts(int height, int width) {
    207         this.atts.put("height", Integer.toString(height));
    208         this.atts.put("width", Integer.toString(width));
     165        parameters.updateSize(width, height);
    209166    }
    210167
     
    213170    }
    214171
    215     public boolean isAlive() {
    216         return handler != null && handler.isAlive() && this.appletAlive;
     172    public boolean isInitialized() {
     173        return initialized;
    217174    }
    218175
    219176    public ThreadGroup getThreadGroup() {
    220177        synchronized(TGMapMutex) {
    221             return uKeyToTG.get(uKey);
     178            return uKeyToTG.get(parameters.getUniqueKey(getCodeBase()));
    222179        }
    223180    }
     
    229186        // only create a new context if one hasn't already been created for the
    230187        // applets with this unique key.
    231         if (null == appContextCreated.putIfAbsent(uKey, Boolean.TRUE)) {
     188        if (null == appContextCreated.putIfAbsent(parameters.getUniqueKey(getCodeBase()), Boolean.TRUE)) {
    232189            SunToolkit.createNewAppContext();
    233190        }
    234191    }
     192
     193    public void setAppletViewerFrame(SplashController framePanel) {
     194        splashController=framePanel;
     195    }
     196
     197    @Override
     198    public void removeSplash() {
     199        splashController.removeSplash();
     200    }
     201
     202    @Override
     203    public void replaceSplash(SplashPanel r) {
     204        splashController.replaceSplash(r);
     205    }
     206
     207    @Override
     208    public int getSplashWidth() {
     209        return splashController.getSplashWidth();
     210    }
     211
     212    @Override
     213    public int getSplashHeigth() {
     214        return splashController.getSplashHeigth();
     215    }
     216   
    235217}
  • trunk/icedtea-web/netx/net/sourceforge/jnlp/Node.java

    r418 r429  
     1/* Node.java
     2   Copyright (C) 2011 Red Hat, Inc.
     3
     4This file is part of IcedTea.
     5
     6IcedTea is free software; you can redistribute it and/or
     7modify it under the terms of the GNU General Public License as published by
     8the Free Software Foundation, version 2.
     9
     10IcedTea is distributed in the hope that it will be useful,
     11but WITHOUT ANY WARRANTY; without even the implied warranty of
     12MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
     13General Public License for more details.
     14
     15You should have received a copy of the GNU General Public License
     16along with IcedTea; see the file COPYING.  If not, write to
     17the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
     1802110-1301 USA.
     19
     20Linking this library statically or dynamically with other modules is
     21making a combined work based on this library.  Thus, the terms and
     22conditions of the GNU General Public License cover the whole
     23combination.
     24
     25As a special exception, the copyright holders of this library give you
     26permission to link this library with independent modules to produce an
     27executable, regardless of the license terms of these independent
     28modules, and to copy and distribute the resulting executable under
     29terms of your choice, provided that you also meet, for each linked
     30independent module, the terms and conditions of the license of that
     31module.  An independent module is a module which is not derived from
     32or based on this library.  If you modify this library, you may extend
     33this exception to your version of the library, but you are not
     34obligated to do so.  If you do not wish to do so, delete this
     35exception statement from your version.
     36 */
     37
    138package net.sourceforge.jnlp;
    239
     
    2764
    2865    Node getFirstChild() {
    29         if (children == null)
     66        if (children == null) {
    3067            getChildNodes();
    31 
    32         if (children.length == 0)
     68        }
     69
     70        if (children.length == 0) {
    3371            return null;
    34         else
     72        }
     73        else {
    3574            return children[0];
     75        }
    3676    }
    3777
     
    5191            List<Node> list = new ArrayList<Node>();
    5292
    53             for (Enumeration e = xml.enumerateChildren(); e.hasMoreElements();)
    54                 list.add(new Node((XMLElement) e.nextElement()));
     93            for (Enumeration<XMLElement> e = xml.enumerateChildren(); e.hasMoreElements();) {
     94                list.add(new Node(e.nextElement()));
     95            }
    5596
    5697            children = list.toArray(new Node[list.size()]);
    5798
    58             for (int i = 0; i < children.length - 1; i++)
     99            for (int i = 0; i < children.length - 1; i++) {
    59100                children[i].next = children[i + 1];
     101            }
    60102        }
    61103
     
    71113            attributeNames= new ArrayList<String>();
    72114
    73             for (Enumeration e = xml.enumerateAttributeNames(); e.hasMoreElements();)
    74                 attributeNames.add(new String((String) e.nextElement()));
     115            for (Enumeration<String> e = xml.enumerateAttributeNames(); e.hasMoreElements();) {
     116                attributeNames.add(new String(e.nextElement()));
     117            }
    75118        }
    76119
     
    83126
    84127    String getNodeName() {
    85         if (xml.getName() == null)
     128        if (xml.getName() == null) {
    86129            return "";
    87         else
     130        }
     131        else {
    88132            return xml.getName();
    89     }
    90 
     133        }
     134    }
     135
     136    @Override
    91137    public String toString() {
    92138        return getNodeName();
  • trunk/icedtea-web/netx/net/sourceforge/jnlp/ParseException.java

    r348 r429  
    3131    // element, parse position, etc.
    3232
    33     /** the original exception */
    34     private Throwable cause = null;
    35 
     33   
    3634    /**
    3735     * Create a parse exception with the specified message.
     
    4644     */
    4745    public ParseException(String message, Throwable cause) {
    48         super(message);
    49 
    50         // replace with setCause when no longer 1.3 compatible
    51         this.cause = cause;
    52     }
    53 
    54     /**
    55      * Return the cause of the launch exception or null if there
    56      * is no cause exception.
    57      */
    58     public Throwable getCause() {
    59         return cause;
    60     }
    61 
    62     /**
    63      * Print the stack trace and the cause exception (1.3
    64      * compatible)
    65      */
    66     public void printStackTrace(PrintStream stream) {
    67         super.printStackTrace(stream);
    68 
    69         if (cause != null) {
    70             stream.println("Caused by: ");
    71             cause.printStackTrace(stream);
    72         }
    73     }
    74 
    75     /**
    76      * Print the stack trace and the cause exception (1.3
    77      * compatible)
    78      */
    79     public void printStackTrace(PrintWriter stream) {
    80         super.printStackTrace(stream);
    81 
    82         if (cause != null) {
    83             stream.println("Caused by: ");
    84             cause.printStackTrace(stream);
    85         }
    86     }
     46        super(message, cause);
     47    } 
    8748
    8849}
  • trunk/icedtea-web/netx/net/sourceforge/jnlp/Parser.java

    r418 r429  
    11// Copyright (C) 2001-2003 Jon A. Maxwell (JAM)
    2 // Copyright (C) 2012 Red Hat, Inc.
     2// Copyright (C) 2009-2013 Red Hat, Inc.
    33//
    44// This library is free software; you can redistribute it and/or
     
    2121
    2222import java.io.*;
     23import java.lang.reflect.InvocationTargetException;
     24import java.lang.reflect.Method;
    2325import java.net.*;
    2426import java.util.*;
    25 //import javax.xml.parsers.*; // commented to use right Node
    26 //import org.w3c.dom.*;       // class for using Tiny XML | NanoXML
    27 //import org.xml.sax.*;
    28 //import gd.xml.tiny.*;
     27
     28import net.sourceforge.jnlp.SecurityDesc.RequestedPermissionLevel;
    2929import net.sourceforge.jnlp.UpdateDesc.Check;
    3030import net.sourceforge.jnlp.UpdateDesc.Policy;
    3131import net.sourceforge.jnlp.runtime.JNLPRuntime;
    32 import net.sourceforge.nanoxml.*;
     32import net.sourceforge.jnlp.util.logging.OutputController;
    3333
    3434/**
     
    6161        }
    6262        public void warning(SAXParseException exception) {
    63             System.err.println("XML parse warning:");
    64             exception.printStackTrace();
     63            OutputController.getLogger().log(OutputController.Level.WARNING_ALL, "XML parse warning:");
     64            OutputController.getLogger().log(OutputController.Level.ERROR_ALL, exception);
    6565        }
    6666    };
     
    9696
    9797    /**
    98      * Create a parser for the JNLP file.  If the location
     98     * Create a parser for the JNLP file. If the location
    9999     * parameters is not null it is used as the default codebase
    100100     * (does not override value of jnlp element's href
    101      * attribute).<p>
    102      *
     101     * attribute).
     102     * <p>
    103103     * The root node may be normalized as a side effect of this
    104104     * constructor.
    105      *
     105     * </p>
    106106     * @param file the (uninitialized) file reference
    107107     * @param base if codebase is not specified, a default base for relative URLs
    108108     * @param root the root node
    109      * @param strict whether to enforce strict compliance with the JNLP spec
    110      * @param allowExtensions whether to allow extensions to the JNLP spec
    111      * @throws ParseException if the JNLP file is invalid
    112      */
    113     public Parser(JNLPFile file, URL base, Node root, boolean strict, boolean allowExtensions) throws ParseException {
    114         this(file, base, root, strict, allowExtensions, null);
    115     }
    116 
    117     /**
    118      * Create a parser for the JNLP file.  If the location
     109     * @param settings the parser settings to use when parsing the JNLP file
     110     * @throws ParseException if the JNLP file is invalid
     111     */
     112    public Parser(JNLPFile file, URL base, Node root, ParserSettings settings) throws ParseException {
     113        this(file, base, root, settings, null);
     114    }
     115
     116    /**
     117     * Create a parser for the JNLP file. If the location
    119118     * parameters is not null it is used as the default codebase
    120119     * (does not override value of jnlp element's href
    121      * attribute).<p>
    122      *
     120     * attribute).
     121     * <p>
    123122     * The root node may be normalized as a side effect of this
    124123     * constructor.
    125      *
     124     * </p>
    126125     * @param file the (uninitialized) file reference
    127126     * @param base if codebase is not specified, a default base for relative URLs
    128127     * @param root the root node
    129      * @param strict whether to enforce strict compliance with the JNLP spec
    130      * @param allowExtensions whether to allow extensions to the JNLP spec
     128     * @param settings the parser settings to use when parsing the JNLP file
    131129     * @param codebase codebase to use if we did not parse one from JNLP file.
    132130     * @throws ParseException if the JNLP file is invalid
    133131     */
    134     public Parser(JNLPFile file, URL base, Node root, boolean strict, boolean allowExtensions, URL codebase) throws ParseException {
     132    public Parser(JNLPFile file, URL base, Node root, ParserSettings settings, URL codebase) throws ParseException {
    135133        this.file = file;
    136134        this.root = root;
    137         this.strict = strict;
    138         this.allowExtensions = allowExtensions;
     135        this.strict = settings.isStrict();
     136        this.allowExtensions = settings.isExtensionAllowed();
    139137
    140138        // ensure it's a JNLP node
     
    144142        // JNLP tag information
    145143        this.spec = getVersion(root, "spec", "1.0+");
    146         this.codebase = addSlash(getURL(root, "codebase", base));
    147         if (this.codebase == null) // We only override it if it is not specified.
     144
     145        try {
     146            this.codebase = addSlash(getURL(root, "codebase", base));
     147        } catch (ParseException e) {
     148            //If parsing fails, continue by overriding the codebase with the one passed in
     149        }
     150
     151        if (this.codebase == null) // Codebase is overwritten if codebase was not specified in file or if parsing of it failed
    148152            this.codebase = codebase;
     153
    149154        this.base = (this.codebase != null) ? this.codebase : base; // if codebase not specified use default codebase
    150155        fileLocation = getURL(root, "href", this.base);
     
    247252
    248253        // ensure that there are at least one information section present
    249         if (resources.length == 0 && !j2se)
     254        if (resources.length == 0 && !j2se) {
    250255            throw new ParseException(R("PNoResources"));
    251 
     256        }
    252257        // create objects from the resources sections
    253         for (int i = 0; i < resources.length; i++)
     258        for (int i = 0; i < resources.length; i++) {
    254259            result.add(getResourcesDesc(resources[i], j2se));
    255 
     260        }
    256261        return result;
    257262    }
     
    299304                // check for duplicate main entries
    300305                if (jar.isMain()) {
    301                     if (mainFlag == true)
    302                         if (strict)
     306                    if (mainFlag == true) {
     307                        if (strict) {
    303308                            throw new ParseException(R("PTwoMains"));
     309                        }
     310                    }
    304311                    mainFlag = true;
    305312                }
     
    340347        String initialHeap = getAttribute(node, "initial-heap-size", null);
    341348        String maxHeap = getAttribute(node, "max-heap-size", null);
    342         List resources = getResources(node, true);
     349        List<ResourcesDesc> resources = getResources(node, true);
    343350
    344351        // require version attribute
     
    436443     */
    437444    void checkForInformation() throws RequiredElementException {
    438         if (JNLPRuntime.isDebug()) {
    439             System.out.println("Homepage: " + file.getInformation().getHomepage());
    440             System.out.println("Description: " + file.getInformation().getDescription());
    441         }
     445        OutputController.getLogger().log("Homepage: " + file.getInformation().getHomepage());
     446        OutputController.getLogger().log("Description: " + file.getInformation().getDescription());
    442447
    443448        String title = file.getTitle();
     
    446451        if (title == null || title.trim().isEmpty())
    447452            throw new MissingTitleException();
    448         else if (JNLPRuntime.isDebug())
    449             System.out.println("Acceptable title tag found, contains: " + title);
     453        else OutputController.getLogger().log("Acceptable title tag found, contains: " + title);
    450454
    451455        if (vendor == null || vendor.trim().isEmpty())
    452456            throw new MissingVendorException();
    453         else if (JNLPRuntime.isDebug())
    454             System.out.println("Acceptable vendor tag found, contains: " + vendor);
     457        else OutputController.getLogger().log("Acceptable vendor tag found, contains: " + vendor);
    455458    }
    456459
     
    492495
    493496        // create information
    494         InformationDesc info = new InformationDesc(file, locales);
     497        InformationDesc info = new InformationDesc(locales);
    495498
    496499        // step through the elements
     
    594597
    595598        Object type = SecurityDesc.SANDBOX_PERMISSIONS;
    596 
    597         if (nodes.length == 0)
     599        RequestedPermissionLevel requestedPermissionLevel = RequestedPermissionLevel.NONE;
     600
     601        if (nodes.length == 0) {
    598602            type = SecurityDesc.SANDBOX_PERMISSIONS;
    599         else if (null != getChildNode(nodes[0], "all-permissions"))
     603            requestedPermissionLevel = RequestedPermissionLevel.NONE;
     604        } else if (null != getChildNode(nodes[0], "all-permissions")) {
    600605            type = SecurityDesc.ALL_PERMISSIONS;
    601         else if (null != getChildNode(nodes[0], "j2ee-application-client-permissions"))
     606            requestedPermissionLevel = RequestedPermissionLevel.ALL;
     607        } else if (null != getChildNode(nodes[0], "j2ee-application-client-permissions")) {
    602608            type = SecurityDesc.J2EE_PERMISSIONS;
    603         else if (strict)
     609            requestedPermissionLevel = RequestedPermissionLevel.J2EE;
     610        } else if (strict) {
    604611            throw new ParseException(R("PEmptySecurity"));
    605 
    606         if (base != null)
    607             return new SecurityDesc(file, type, base.getHost());
    608         else
    609             return new SecurityDesc(file, type, null);
     612        }
     613
     614        if (base != null) {
     615            return new SecurityDesc(file, requestedPermissionLevel, type, base.getHost());
     616        } else {
     617            return new SecurityDesc(file, requestedPermissionLevel, type, null);
     618        }
    610619    }
    611620
     
    913922
    914923    /**
    915      * Returns a Locale from a single locale.
    916      *
    917      * @param locale the locale string
     924     * Returns a {@link Locale} from a single locale.
     925     *
     926     * @param localeStr the locale string
    918927     */
    919928    public Locale getLocale(String localeStr) {
     
    10471056    /**
    10481057     * Returns a URL object from a href string relative to the
    1049      * code base.  If the href denotes a relative URL, it must
     1058     * code base. If the href denotes a relative URL, it must
    10501059     * reference a location that is a subdirectory of the
    1051      * codebase.<p>
     1060     * codebase.
    10521061     *
    10531062     * @param node the node
     
    10741083
    10751084                // check for going above the codebase
    1076                 if (!result.toString().startsWith(base.toString()))
    1077                     if (strict)
     1085                if (!result.toString().startsWith(base.toString()) &&  !base.toString().startsWith(result.toString())){
     1086                    if (strict) {
    10781087                        throw new ParseException(R("PUrlNotInCodebase", node.getNodeName(), href, base));
    1079 
     1088                    }
     1089                }
    10801090                return result;
    10811091            }
     
    12591269     * @throws ParseException if the JNLP file is invalid
    12601270     */
    1261     public static Node getRootNode(InputStream input) throws ParseException {
     1271    public static Node getRootNode(InputStream input, ParserSettings settings) throws ParseException {
     1272        String className = null;
     1273        if (settings.isMalformedXmlAllowed()) {
     1274            className = "net.sourceforge.jnlp.MalformedXMLParser";
     1275        } else {
     1276            className = "net.sourceforge.jnlp.XMLParser";
     1277        }
     1278
    12621279        try {
    1263             /* SAX
    1264             DocumentBuilderFactory factory = DocumentBuilderFactory.newInstance();
    1265             factory.setValidating(false);
    1266             factory.setNamespaceAware(true);
    1267             DocumentBuilder builder = factory.newDocumentBuilder();
    1268             builder.setErrorHandler(errorHandler);
    1269 
    1270             Document doc = builder.parse(input);
    1271             return doc.getDocumentElement();
    1272             */
    1273 
    1274             /* TINY
    1275             Node document = new Node(TinyParser.parseXML(input));
    1276             Node jnlpNode = getChildNode(document, "jnlp"); // skip comments
    1277             */
    1278 
    1279             //A BufferedInputStream is used to allow marking and reseting
    1280             //of a stream.
    1281             BufferedInputStream bs = new BufferedInputStream(input);
    1282 
    1283             /* NANO */
    1284             final XMLElement xml = new XMLElement();
    1285             final PipedInputStream pin = new PipedInputStream();
    1286             final PipedOutputStream pout = new PipedOutputStream(pin);
    1287             final InputStreamReader isr = new InputStreamReader(bs, getEncoding(bs));
    1288             // Clean the jnlp xml file of all comments before passing
    1289             // it to the parser.
    1290             new Thread(
    1291                     new Runnable() {
    1292                         public void run() {
    1293                             (new XMLElement()).sanitizeInput(isr, pout);
    1294                             try {
    1295                                 pout.close();
    1296                             } catch (IOException ioe) {
    1297                                 ioe.printStackTrace();
    1298                             }
    1299                         }
    1300                     }).start();
    1301             xml.parseFromReader(new InputStreamReader(pin));
    1302             Node jnlpNode = new Node(xml);
    1303             return jnlpNode;
    1304         } catch (Exception ex) {
    1305             throw new ParseException(R("PBadXML"), ex);
    1306         }
    1307     }
    1308 
    1309     /**
    1310      * Returns the name of the encoding used in this InputStream.
    1311      *
    1312      * @param input the InputStream
    1313      * @return a String representation of encoding
    1314      */
    1315     private static String getEncoding(InputStream input) throws IOException {
    1316         //Fixme: This only recognizes UTF-8, UTF-16, and
    1317         //UTF-32, which is enough to parse the prolog portion of xml to
    1318         //find out the exact encoding (if it exists). The reason being
    1319         //there could be other encodings, such as ISO 8859 which is 8-bits
    1320         //but it supports latin characters.
    1321         //So what needs to be done is to parse the prolog and retrieve
    1322         //the exact encoding from it.
    1323 
    1324         int[] s = new int[4];
    1325         String encoding = "UTF-8";
    1326 
    1327         //Determine what the first four bytes are and store
    1328         //them into an int array.
    1329         input.mark(4);
    1330         for (int i = 0; i < 4; i++) {
    1331             s[i] = input.read();
    1332         }
    1333         input.reset();
    1334 
    1335         //Set the encoding base on what the first four bytes of the
    1336         //inputstream turn out to be (following the information from
    1337         //www.w3.org/TR/REC-xml/#sec-guessing).
    1338         if (s[0] == 255) {
    1339             if (s[1] == 254) {
    1340                 if (s[2] != 0 || s[3] != 0) {
    1341                     encoding = "UnicodeLittle";
    1342                 } else {
    1343                     encoding = "X-UTF-32LE-BOM";
    1344                 }
    1345             }
    1346         } else if (s[0] == 254 && s[1] == 255 && (s[2] != 0 ||
    1347                 s[3] != 0)) {
    1348             encoding = "UTF-16";
    1349 
    1350         } else if (s[0] == 0 && s[1] == 0 && s[2] == 254 &&
    1351                 s[3] == 255) {
    1352             encoding = "X-UTF-32BE-BOM";
    1353 
    1354         } else if (s[0] == 0 && s[1] == 0 && s[2] == 0 &&
    1355                 s[3] == 60) {
    1356             encoding = "UTF-32BE";
    1357 
    1358         } else if (s[0] == 60 && s[1] == 0 && s[2] == 0 &&
    1359                 s[3] == 0) {
    1360             encoding = "UTF-32LE";
    1361 
    1362         } else if (s[0] == 0 && s[1] == 60 && s[2] == 0 &&
    1363                 s[3] == 63) {
    1364             encoding = "UTF-16BE";
    1365         } else if (s[0] == 60 && s[1] == 0 && s[2] == 63 &&
    1366                 s[3] == 0) {
    1367             encoding = "UTF-16LE";
    1368         }
    1369 
    1370         return encoding;
     1280            Class<?> klass = null;
     1281            try {
     1282                klass = Class.forName(className);
     1283            } catch (ClassNotFoundException e) {
     1284                klass = Class.forName("net.sourceforge.jnlp.XMLParser");
     1285            }
     1286            Object instance = klass.newInstance();
     1287            Method m = klass.getMethod("getRootNode", InputStream.class);
     1288
     1289            return (Node) m.invoke(instance, input);
     1290        } catch (InvocationTargetException e) {
     1291            if (e.getCause() instanceof ParseException) {
     1292                throw (ParseException)(e.getCause());
     1293            }
     1294            throw new ParseException(R("PBadXML"), e);
     1295        } catch (Exception e) {
     1296            throw new ParseException(R("PBadXML"), e);
     1297        }
    13711298    }
    13721299
  • trunk/icedtea-web/netx/net/sourceforge/jnlp/ParserSettings.java

    r348 r429  
    3636*/
    3737
     38package net.sourceforge.jnlp;
    3839
    39 package net.sourceforge.jnlp;
     40import java.util.Arrays;
     41import java.util.List;
    4042
    4143/**
     
    4648public class ParserSettings {
    4749
     50    private static ParserSettings globalParserSettings = new ParserSettings();
     51
    4852    private final boolean isStrict;
     53    private final boolean extensionAllowed;
     54    private final boolean malformedXmlAllowed;
    4955
     56    /** Create a new ParserSettings with the defautl parser settings */
    5057    public ParserSettings() {
    51         isStrict = false;
     58        this(false, true, true);
    5259    }
    5360
    54     public ParserSettings(boolean strict) {
    55         isStrict = strict;
     61    /** Create a new ParserSettings object */
     62    public ParserSettings(boolean strict, boolean extensionAllowed, boolean malformedXmlAllowed) {
     63        this.isStrict = strict;
     64        this.extensionAllowed = extensionAllowed;
     65        this.malformedXmlAllowed = malformedXmlAllowed;
    5666    }
    5767
     68    /** @return true if extensions to the spec are allowed */
     69    public boolean isExtensionAllowed() {
     70        return extensionAllowed;
     71    }
     72
     73    /** @return true if parsing malformed xml is allowed */
     74    public boolean isMalformedXmlAllowed() {
     75        return malformedXmlAllowed;
     76    }
     77
     78    /** @return true if strict parsing mode is to be used */
    5879    public boolean isStrict() {
    5980        return isStrict;
    6081    }
     82
     83    /**
     84     * Return the global parser settings in use.
     85     */
     86    public static ParserSettings getGlobalParserSettings() {
     87        return globalParserSettings;
     88    }
     89
     90    /**
     91     * Set the global ParserSettings to match the given settings.
     92     */
     93    public static void setGlobalParserSettings(ParserSettings parserSettings) {
     94        globalParserSettings = parserSettings;
     95    }
     96
     97    /**
     98     * Return the ParserSettings to be used according to arguments specified
     99     * at boot on the command line. These settings are also stored so they
     100     * can be retrieved at a later time.
     101     */
     102    public static ParserSettings setGlobalParserSettingsFromArgs(String[] cmdArgs) {
     103        List<String> argList = Arrays.asList(cmdArgs);
     104        boolean strict = argList.contains("-strict");
     105        boolean malformedXmlAllowed = !argList.contains("-xml");
     106
     107        globalParserSettings = new ParserSettings(strict, true, malformedXmlAllowed);
     108        return globalParserSettings;
     109    }
     110
    61111}
  • trunk/icedtea-web/netx/net/sourceforge/jnlp/PluginBridge.java

    r418 r429  
    2323package net.sourceforge.jnlp;
    2424
     25import java.io.ByteArrayInputStream;
    2526import java.io.File;
     27import java.io.IOException;
     28import java.io.InputStream;
     29import java.net.MalformedURLException;
    2630import java.net.URL;
    27 import java.net.MalformedURLException;
     31import java.util.ArrayList;
     32import java.util.Arrays;
    2833import java.util.HashSet;
     34import java.util.List;
    2935import java.util.Locale;
    30 import java.util.List;
    31 import java.util.ArrayList;
    3236import java.util.Map;
    3337import java.util.Set;
    3438
     39import net.sourceforge.jnlp.SecurityDesc.RequestedPermissionLevel;
    3540import net.sourceforge.jnlp.runtime.JNLPRuntime;
     41import net.sourceforge.jnlp.util.logging.OutputController;
     42import net.sourceforge.jnlp.util.replacements.BASE64Decoder;
    3643
    3744/**
     
    4148public class PluginBridge extends JNLPFile {
    4249
    43     private String name;
     50    private PluginParameters params;
    4451    private Set<String> jars = new HashSet<String>();
     52    private List<ExtensionDesc> extensionJars = new ArrayList<ExtensionDesc>();
    4553    //Folders can be added to the code-base through the archive tag
    4654    private List<String> codeBaseFolders = new ArrayList<String>();
    4755    private String[] cacheJars = new String[0];
    4856    private String[] cacheExJars = new String[0];
    49     private Map<String, String> atts;
    5057    private boolean usePack;
    5158    private boolean useVersion;
    52     private boolean codeBaseLookup;
    5359    private boolean useJNLPHref;
    5460
     
    5763     */
    5864    public PluginBridge(URL codebase, URL documentBase, String jar, String main,
    59                         int width, int height, Map<String, String> atts,
    60                         String uKey)
     65                        int width, int height, PluginParameters params)
    6166            throws Exception {
    62         this(codebase, documentBase, jar, main, width, height, atts, uKey, new JNLPCreator());
     67        this(codebase, documentBase, jar, main, width, height, params, new JNLPCreator());
    6368    }
    6469
     
    8287
    8388    public PluginBridge(URL codebase, URL documentBase, String archive, String main,
    84                         int width, int height, Map<String, String> atts,
    85                         String uKey, JNLPCreator jnlpCreator)
     89                        int width, int height, PluginParameters params, JNLPCreator jnlpCreator)
    8690            throws Exception {
    8791        specVersion = new Version("1.0");
     
    8993        this.codeBase = codebase;
    9094        this.sourceLocation = documentBase;
    91         this.atts = atts;
    92 
    93         if (atts.containsKey("jnlp_href")) {
     95        this.params = params;
     96        this.parserSettings = ParserSettings.getGlobalParserSettings();
     97
     98        if (params.getJNLPHref() != null) {
    9499            useJNLPHref = true;
    95100            try {
    96101                // Use codeBase as the context for the URL. If jnlp_href's
    97102                // value is a complete URL, it will replace codeBase's context.
    98                 URL jnlp = new URL(codeBase, atts.get("jnlp_href"));
    99                 JNLPFile jnlpFile = jnlpCreator.create(jnlp, null, false, JNLPRuntime.getDefaultUpdatePolicy(), codeBase);
     103                ParserSettings defaultSettings = new ParserSettings();
     104                URL jnlp = new URL(codeBase, params.getJNLPHref());
     105                if (fileLocation == null){
     106                    fileLocation = jnlp;
     107                }
     108                JNLPFile jnlpFile = null;
     109
     110                if (params.getJNLPEmbedded() != null) {
     111                    InputStream jnlpInputStream = new ByteArrayInputStream(decodeBase64String(params.getJNLPEmbedded()));
     112                    jnlpFile = new JNLPFile(jnlpInputStream, codeBase, defaultSettings);
     113                } else {
     114                    jnlpFile = jnlpCreator.create(jnlp, null, defaultSettings, JNLPRuntime.getDefaultUpdatePolicy(), codeBase);
     115                }
     116
     117                if (jnlpFile.isApplet())
     118                    main = jnlpFile.getApplet().getMainClass();
     119
    100120                Map<String, String> jnlpParams = jnlpFile.getApplet().getParameters();
    101121                info = jnlpFile.info;
     
    103123                // Change the parameter name to lowercase to follow conventions.
    104124                for (Map.Entry<String, String> entry : jnlpParams.entrySet()) {
    105                     this.atts.put(entry.getKey().toLowerCase(), entry.getValue());
     125                    this.params.put(entry.getKey().toLowerCase(), entry.getValue());
    106126                }
    107127                JARDesc[] jarDescs = jnlpFile.getResources().getJARs();
     
    110130                     this.jars.add(fileName);
    111131                 }
     132
     133                // Store any extensions listed in the JNLP file to be returned later on, namely in getResources()
     134                extensionJars = Arrays.asList(jnlpFile.getResources().getExtensions());
    112135            } catch (MalformedURLException e) {
    113136                // Don't fail because we cannot get the jnlp file. Parameters are optional not required.
    114137                // it is the site developer who should ensure that file exist.
    115                 System.err.println("Unable to get JNLP file at: " + atts.get("jnlp_href")
     138                OutputController.getLogger().log(OutputController.Level.ERROR_ALL, "Unable to get JNLP file at: " + params.getJNLPHref()
    116139                        + " with context of URL as: " + codeBase.toExternalForm());
    117140            }
     
    123146
    124147        // also, see if cache_archive is specified
    125         String cacheArchive = atts.get("cache_archive");
    126         if (cacheArchive != null && cacheArchive.length() > 0) {
     148        String cacheArchive = params.getCacheArchive();
     149        if (!cacheArchive.isEmpty()) {
    127150
    128151            String[] versions = new String[0];
    129152
    130153            // are there accompanying versions?
    131             String cacheVersion = atts.get("cache_version");
    132             if (cacheVersion != null) {
     154            String cacheVersion = params.getCacheVersion();
     155            if (!cacheVersion.isEmpty()) {
    133156                versions = cacheVersion.split(",");
    134157            }
     
    147170        }
    148171
    149         String cacheArchiveEx = atts.get("cache_archive_ex");
    150         if (cacheArchiveEx != null && cacheArchiveEx.length() > 0) {
     172        String cacheArchiveEx = params.getCacheArchiveEx();
     173        if (!cacheArchiveEx.isEmpty()) {
    151174            cacheExJars = cacheArchiveEx.split(",");
    152175        }
     
    157180            addArchiveEntries(archives);
    158181
    159             if (JNLPRuntime.isDebug()) {
    160                 System.err.println("Jar string: " + archive);
    161                 System.err.println("jars length: " + archives.length);
    162             }
    163         }
    164 
    165         name = atts.get("name");
    166         if (name == null)
    167             name = "Applet";
    168         else
    169             name = name + " applet";
     182            OutputController.getLogger().log(OutputController.Level.ERROR_DEBUG, "Jar string: " + archive);
     183            OutputController.getLogger().log(OutputController.Level.ERROR_DEBUG, "jars length: " + archives.length);
     184        }
    170185
    171186        if (main.endsWith(".class"))
     
    174189        // the class name should be of the form foo.bar.Baz not foo/bar/Baz
    175190        String mainClass = main.replace('/', '.');
    176         launchType = new AppletDesc(name, mainClass, documentBase, width,
    177                                     height, atts);
     191        launchType = new AppletDesc(getTitle(), mainClass, documentBase, width,
     192                                    height, params.getUnmodifiableMap());
    178193
    179194        if (main.endsWith(".class")) //single class file only
     
    183198            security = null;
    184199
    185         this.uniqueKey = uKey;
     200        this.uniqueKey = params.getUniqueKey(codebase);
    186201        usePack = false;
    187202        useVersion = false;
    188         String jargs = atts.get("java_arguments");
    189         if (jargs != null) {
     203        String jargs = params.getJavaArguments();
     204        if (!jargs.isEmpty()) {
    190205            for (String s : jargs.split(" ")) {
    191206                String[] parts = s.trim().split("=");
     
    199214            }
    200215        }
    201         String cbl = atts.get("codebase_lookup");
    202         codeBaseLookup = cbl == null || (Boolean.valueOf(cbl));
     216    }
     217
     218    public List<String> getArchiveJars() {
     219        return new ArrayList<String>(jars);
    203220    }
    204221
    205222    public boolean codeBaseLookup() {
    206         return codeBaseLookup;
     223        return params.useCodebaseLookup();
    207224    }
    208225
     
    211228    }
    212229
    213     /**
    214      * {@inheritdoc }
    215      */
    216230    @Override
    217     public DownloadOptions getDownloadOptionsForJar(JARDesc jar) {
     231    public RequestedPermissionLevel getRequestedPermissionLevel() {
     232        final String level = params.getPermissions();
     233        if (level == null) {
     234            return RequestedPermissionLevel.NONE;
     235        } else if (level.equals(SecurityDesc.RequestedPermissionLevel.DEFAULT.toHtmlString())) {
     236            return RequestedPermissionLevel.NONE;
     237        } else if (level.equals(SecurityDesc.RequestedPermissionLevel.SANDBOX.toHtmlString())) {
     238            return RequestedPermissionLevel.SANDBOX;
     239        } else if (level.equals(SecurityDesc.RequestedPermissionLevel.ALL.toHtmlString())) {
     240            return RequestedPermissionLevel.ALL;
     241        } else {
     242            return RequestedPermissionLevel.NONE;
     243        }
     244    }
     245
     246    /**
     247     * {@inheritDoc }
     248     */
     249    @Override
     250    public DownloadOptions getDownloadOptions() {
    218251        return new DownloadOptions(usePack, useVersion);
    219252    }
    220253
     254    @Override
    221255    public String getTitle() {
    222         return name;
     256        String inManifestTitle = super.getTitleFromManifest();
     257        if (inManifestTitle != null) {
     258            return inManifestTitle;
     259        }
     260        //specification is recommending  main class instead of html parameter
     261        //http://docs.oracle.com/javase/7/docs/technotes/guides/jweb/manifest.html#app_name
     262        String mainClass = getManifestsAttributes().getMainClass();
     263        if (mainClass != null) {
     264            return mainClass;
     265        }
     266        return params.getAppletTitle();
    223267    }
    224268
     
    243287
    244288                        boolean cacheable = true;
    245 
    246                         String cacheOption = atts.get("cache_option");
    247                         if (cacheOption != null && cacheOption.equalsIgnoreCase("no"))
     289                        if (params.getCacheOption().equalsIgnoreCase("no"))
    248290                            cacheable = false;
    249291
     
    302344                    } catch (MalformedURLException ex) { /* Ignored */
    303345                    }
     346                } else if (launchType.equals(ExtensionDesc.class)) {
     347                    // We hope this is a safe list of JarDesc objects
     348                    @SuppressWarnings("unchecked")
     349                    List<T> castList = (List<T>) extensionJars; // this list is populated when the PluginBridge is first constructed
     350                    return castList;
    304351                }
    305352                return sharedResources.getResources(launchType);
     
    350397        return false;
    351398    }
     399
     400    /**
     401     * Returns the decoded BASE64 string
     402     */
     403    static byte[] decodeBase64String(String encodedString) throws IOException {
     404        BASE64Decoder base64 = new BASE64Decoder();
     405        return base64.decodeBuffer(encodedString);
     406    }
    352407}
  • trunk/icedtea-web/netx/net/sourceforge/jnlp/ResourcesDesc.java

    r418 r429  
    2020
    2121/**
    22  * The resources element.<p>
     22 * The resources element.
    2323 *
    2424 * @author <a href="mailto:jmaxwell@users.sourceforge.net">Jon A. Maxwell (JAM)</a> - initial author
     
    6868    }
    6969
     70    public static JARDesc getMainJAR(JARDesc jars[] ) {
     71        return getMainJAR(Arrays.asList(jars));
     72    }
     73
     74    public static JARDesc getMainJAR(List<JARDesc> jars) {
     75        for (JARDesc jar : jars) {
     76            if (jar.isMain()) {
     77                return jar;
     78            }
     79        }
     80
     81        if (jars.size() > 0) {
     82            return jars.get(0);
     83        } else {
     84            return null;
     85        }
     86    }
    7087    /**
    7188     * Returns the main JAR for these resources.  There first JAR
     
    7491     */
    7592    public JARDesc getMainJAR() {
    76         JARDesc jars[] = getJARs();
    77 
    78         for (JARDesc jar : jars) {
    79             if (jar.isMain())
    80                 return jar;
    81         }
    82 
    83         if (jars.length > 0)
    84             return jars[0];
    85         else
    86             return null;
     93        return getMainJAR(getJARs());
    8794    }
    8895
  • trunk/icedtea-web/netx/net/sourceforge/jnlp/SecurityDesc.java

    r418 r429  
    1717package net.sourceforge.jnlp;
    1818
    19 import java.io.*;
    20 import java.net.*;
    21 import java.util.*;
    22 import java.security.*;
    2319import java.awt.AWTPermission;
     20import java.io.FilePermission;
     21import java.lang.reflect.Constructor;
     22import java.lang.reflect.InvocationTargetException;
     23import java.net.SocketPermission;
     24import java.net.URI;
     25import java.net.URISyntaxException;
     26import java.security.AllPermission;
     27import java.security.CodeSource;
     28import java.security.Permission;
     29import java.security.PermissionCollection;
     30import java.security.Permissions;
     31import java.security.Policy;
     32import java.security.URIParameter;
     33import java.util.Collection;
     34import java.util.Collections;
     35import java.util.HashSet;
     36import java.util.PropertyPermission;
     37import java.util.Set;
    2438
    2539import net.sourceforge.jnlp.config.DeploymentConfiguration;
    2640import net.sourceforge.jnlp.runtime.JNLPRuntime;
     41import net.sourceforge.jnlp.util.logging.OutputController;
    2742
    2843/**
     
    3449public class SecurityDesc {
    3550
     51    /**
     52     * Represents the security level requested by an applet/application, as specified in its JNLP or HTML.
     53     */
     54    public enum RequestedPermissionLevel {
     55        NONE(null, null),
     56        DEFAULT(null, "default"),
     57        SANDBOX(null, "sandbox"),
     58        J2EE("j2ee-application-client-permissions", null),
     59        ALL("all-permissions", "all-permissions");
     60
     61        public static final String PERMISSIONS_NAME = "permissions";
     62        private final String jnlpString, htmlString;
     63
     64        private RequestedPermissionLevel(final String jnlpString, final String htmlString) {
     65            this.jnlpString = jnlpString;
     66            this.htmlString = htmlString;
     67        }
     68
     69        /**
     70         * This permission level, as it would appear requested in a JNLP file. null if this level
     71         * is NONE (unspecified) or cannot be requested in a JNLP file.
     72         * @return the String level
     73         */
     74        public String toJnlpString() {
     75            return this.jnlpString;
     76        }
     77
     78        /**
     79         * This permission level, as it would appear requested in an HTML file. null if this level
     80         * is NONE (unspecified) or cannot be requested in an HTML file.
     81         * @return the String level
     82         */
     83        public String toHtmlString() {
     84            return this.htmlString;
     85        }
     86
     87        /**
     88         * The JNLP permission level corresponding to the given String. If null is given, null comes
     89         * back. If there is no permission level that can be granted in JNLP matching the given String,
     90         * null is also returned.
     91         * @param jnlpString the JNLP permission String
     92         * @return the matching RequestedPermissionLevel
     93         */
     94        public RequestedPermissionLevel fromJnlpString(final String jnlpString) {
     95            for (final RequestedPermissionLevel level : RequestedPermissionLevel.values()) {
     96                if (level.jnlpString != null && level.jnlpString.equals(jnlpString)) {
     97                    return level;
     98                }
     99            }
     100            return null;
     101        }
     102
     103        /**
     104         * The HTML permission level corresponding to the given String. If null is given, null comes
     105         * back. If there is no permission level that can be granted in HTML matching the given String,
     106         * null is also returned.
     107         * @param htmlString the JNLP permission String
     108         * @return the matching RequestedPermissionLevel
     109         */
     110        public RequestedPermissionLevel fromHtmlString(final String htmlString) {
     111            for (final RequestedPermissionLevel level : RequestedPermissionLevel.values()) {
     112                if (level.htmlString != null && level.htmlString.equals(htmlString)) {
     113                    return level;
     114                }
     115            }
     116            return null;
     117        }
     118    }
     119
    36120    /*
    37121     * We do not verify security here, the classloader deals with security
     
    47131    public static final Object J2EE_PERMISSIONS = "J2SE";
    48132
     133    /** requested permissions type according to HTML or JNLP */
     134    private final RequestedPermissionLevel requestedPermissionLevel;
     135
    49136    /** permissions type */
    50137    private Object type;
     
    57144
    58145    /** the JNLP file */
    59     private JNLPFile file;
     146    private final JNLPFile file;
    60147
    61148    private final Policy customTrustedPolicy;
     149
     150    /**
     151     * URLPermission is new in Java 8, so we use reflection to check for it to keep compatibility
     152     * with Java 6/7. If we can't find the class or fail to construct it then we continue as usual
     153     * without.
     154     *
     155     * These are saved as fields so that the reflective lookup only needs to be performed once
     156     * when the SecurityDesc is constructed, rather than every time a call is made to
     157     * {@link SecurityDesc#getSandBoxPermissions()}, which is called frequently.
     158     */
     159    private static Class<Permission> urlPermissionClass = null;
     160    private static Constructor<Permission> urlPermissionConstructor = null;
     161
     162    static {
     163        try {
     164            urlPermissionClass = (Class<Permission>) Class.forName("java.net.URLPermission");
     165            urlPermissionConstructor = urlPermissionClass.getDeclaredConstructor(new Class[] { String.class });
     166        } catch (final SecurityException e) {
     167            OutputController.getLogger().log(OutputController.Level.WARNING_DEBUG, "Exception while reflectively finding URLPermission - host is probably not running Java 8+");
     168            OutputController.getLogger().log(OutputController.Level.WARNING_DEBUG, e);
     169            urlPermissionClass = null;
     170            urlPermissionConstructor = null;
     171        } catch (final ClassNotFoundException e) {
     172            OutputController.getLogger().log(OutputController.Level.WARNING_DEBUG, "Exception while reflectively finding URLPermission - host is probably not running Java 8+");
     173            OutputController.getLogger().log(OutputController.Level.WARNING_DEBUG, e);
     174            urlPermissionClass = null;
     175            urlPermissionConstructor = null;
     176        } catch (final NoSuchMethodException e) {
     177            OutputController.getLogger().log(OutputController.Level.WARNING_DEBUG, "Exception while reflectively finding URLPermission - host is probably not running Java 8+");
     178            OutputController.getLogger().log(OutputController.Level.WARNING_DEBUG, e);
     179            urlPermissionClass = null;
     180            urlPermissionConstructor = null;
     181        }
     182    }
    62183
    63184    // We go by the rules here:
     
    88209            new SocketPermission("localhost:1024-", "listen"),
    89210            // new SocketPermission("<DownloadHost>", "connect, accept"), // added by code
     211            new PropertyPermission("java.util.Arrays.useLegacyMergeSort", "read,write"),
    90212            new PropertyPermission("java.version", "read"),
    91213            new PropertyPermission("java.vendor", "read"),
     
    146268     *
    147269     * @param file the JNLP file
     270     * @param requestedPermissionLevel the permission level specified in the JNLP
    148271     * @param type the type of security
    149272     * @param downloadHost the download host (can always connect to)
    150273     */
    151     public SecurityDesc(JNLPFile file, Object type, String downloadHost) {
     274    public SecurityDesc(JNLPFile file, RequestedPermissionLevel requestedPermissionLevel, Object type, String downloadHost) {
     275        if (file == null) {
     276            throw new NullJnlpFileException();
     277        }
    152278        this.file = file;
     279        this.requestedPermissionLevel = requestedPermissionLevel;
    153280        this.type = type;
    154281        this.downloadHost = downloadHost;
     
    158285
    159286        customTrustedPolicy = getCustomTrustedPolicy();
     287    }
     288
     289    /**
     290     * Create a security descriptor.
     291     *
     292     * @param file the JNLP file
     293     * @param type the type of security
     294     * @param downloadHost the download host (can always connect to)
     295     */
     296    public SecurityDesc(JNLPFile file, Object type, String downloadHost) {
     297        this(file, RequestedPermissionLevel.NONE, type, downloadHost);
    160298    }
    161299
     
    178316                policy = Policy.getInstance("JavaPolicy", new URIParameter(policyUri));
    179317            } catch (Exception e) {
    180                 e.printStackTrace();
     318                OutputController.getLogger().log(OutputController.Level.ERROR_ALL, e);
    181319            }
    182320        }
     
    222360
    223361    /**
     362     * @return the permission level requested in the JNLP
     363     */
     364    public RequestedPermissionLevel getRequestedPermissionLevel() {
     365        return requestedPermissionLevel;
     366    }
     367
     368    /**
    224369     * Returns a PermissionCollection containing the sandbox permissions
    225370     */
    226371    public PermissionCollection getSandBoxPermissions() {
    227 
    228         Permissions permissions = new Permissions();
     372        final Permissions permissions = new Permissions();
    229373
    230374        for (int i = 0; i < sandboxPermissions.length; i++)
     
    234378            permissions.add(new AWTPermission("showWindowWithoutWarningBanner"));
    235379        }
    236 
    237         if (file.isApplication())
    238             for (int i = 0; i < jnlpRIAPermissions.length; i++)
    239                 permissions.add(jnlpRIAPermissions[i]);
     380        if (JNLPRuntime.isWebstartApplication()) {
     381            if (file == null) {
     382                throw new NullJnlpFileException("Can not return sandbox permissions, file is null");
     383            }
     384            if (file.isApplication()) {
     385                for (int i = 0; i < jnlpRIAPermissions.length; i++) {
     386                    permissions.add(jnlpRIAPermissions[i]);
     387                }
     388            }
     389        }
    240390
    241391        if (downloadHost != null && downloadHost.length() > 0)
     
    243393                                                 "connect, accept"));
    244394
     395        final Collection<Permission> urlPermissions = getUrlPermissions();
     396        for (final Permission permission : urlPermissions) {
     397            permissions.add(permission);
     398        }
     399
    245400        return permissions;
    246401    }
    247    
     402
     403    private Set<Permission> getUrlPermissions() {
     404        if (urlPermissionClass == null || urlPermissionConstructor == null) {
     405            return Collections.emptySet();
     406        }
     407        final Set<Permission> permissions = new HashSet<Permission>();
     408        for (final JARDesc jar : file.getResources().getJARs()) {
     409            try {
     410                // Allow applets all HTTP methods (ex POST, GET) with any request headers
     411                // on resources anywhere recursively in or below the applet codebase, only on
     412                // default ports and ports explicitly specified in resource locations
     413                final URI resourceLocation = jar.getLocation().toURI().normalize();
     414                final URI host = getHost(resourceLocation);
     415                final String hostUriString = host.toString();
     416                final String urlPermissionUrlString = appendRecursiveSubdirToCodebaseHostString(hostUriString);
     417                final Permission p = urlPermissionConstructor.newInstance(urlPermissionUrlString);
     418                permissions.add(p);
     419            } catch (final URISyntaxException e) {
     420                OutputController.getLogger().log(OutputController.Level.WARNING_DEBUG, "Could not determine codebase host for resource at " + jar.getLocation() +  " while generating URLPermissions");
     421                OutputController.getLogger().log(e);
     422            } catch (final InvocationTargetException e) {
     423                OutputController.getLogger().log(OutputController.Level.WARNING_DEBUG, "Exception while attempting to reflectively generate a URLPermission, probably not running on Java 8+?");
     424                OutputController.getLogger().log(OutputController.Level.WARNING_DEBUG, e);
     425            } catch (final InstantiationException e) {
     426                OutputController.getLogger().log(OutputController.Level.WARNING_DEBUG, "Exception while attempting to reflectively generate a URLPermission, probably not running on Java 8+?");
     427                OutputController.getLogger().log(OutputController.Level.WARNING_DEBUG, e);
     428            } catch (final IllegalAccessException e) {
     429                OutputController.getLogger().log(OutputController.Level.WARNING_DEBUG, "Exception while attempting to reflectively generate a URLPermission, probably not running on Java 8+?");
     430                OutputController.getLogger().log(OutputController.Level.WARNING_DEBUG, e);
     431            }
     432        }
     433        try {
     434            final URI codebase = file.getCodeBase().toURI().normalize();
     435            final URI host = getHost(codebase);
     436            final String codebaseHostUriString = host.toString();
     437            final String urlPermissionUrlString = appendRecursiveSubdirToCodebaseHostString(codebaseHostUriString);
     438            final Permission p = urlPermissionConstructor.newInstance(urlPermissionUrlString);
     439            permissions.add(p);
     440        } catch (final URISyntaxException e) {
     441            OutputController.getLogger().log(OutputController.Level.WARNING_DEBUG, "Could not determine codebase host for codebase " + file.getCodeBase() +  "  while generating URLPermissions");
     442            OutputController.getLogger().log(e);
     443        } catch (final InvocationTargetException e) {
     444            OutputController.getLogger().log(OutputController.Level.WARNING_DEBUG, "Exception while attempting to reflectively generate a URLPermission, probably not running on Java 8+?");
     445            OutputController.getLogger().log(OutputController.Level.WARNING_DEBUG, e);
     446        } catch (final InstantiationException e) {
     447            OutputController.getLogger().log(OutputController.Level.WARNING_DEBUG, "Exception while attempting to reflectively generate a URLPermission, probably not running on Java 8+?");
     448            OutputController.getLogger().log(OutputController.Level.WARNING_DEBUG, e);
     449        } catch (final IllegalAccessException e) {
     450            OutputController.getLogger().log(OutputController.Level.WARNING_DEBUG, "Exception while attempting to reflectively generate a URLPermission, probably not running on Java 8+?");
     451            OutputController.getLogger().log(OutputController.Level.WARNING_DEBUG, e);
     452        }
     453        return permissions;
     454    }
     455
     456    /**
     457     * Gets the host domain part of an applet's codebase. Removes path, query, and fragment, but preserves scheme,
     458     * user info, and host. The port used is overridden with the specified port.
     459     * @param codebase the applet codebase URL
     460     * @param port
     461     * @return the host domain of the codebase
     462     * @throws URISyntaxException
     463     */
     464    static URI getHostWithSpecifiedPort(final URI codebase, final int port) throws URISyntaxException {
     465        requireNonNull(codebase);
     466        return new URI(codebase.getScheme(), codebase.getUserInfo(), codebase.getHost(), port, null, null, null);
     467    }
     468
     469    /**
     470     * Gets the host domain part of an applet's codebase. Removes path, query, and fragment, but preserves scheme,
     471     * user info, host, and port.
     472     * @param codebase the applet codebase URL
     473     * @return the host domain of the codebase
     474     * @throws URISyntaxException
     475     */
     476    static URI getHost(final URI codebase) throws URISyntaxException {
     477        requireNonNull(codebase);
     478        return getHostWithSpecifiedPort(codebase, codebase.getPort());
     479    }
     480
     481    /**
     482     * Appends a recursive access marker to a codebase host, for granting Java 8 URLPermissions which are no
     483     * more restrictive than the existing SocketPermissions
     484     * See http://docs.oracle.com/javase/8/docs/api/java/net/URLPermission.html
     485     * @param codebaseHost the applet's codebase's host domain URL as a String. Expected to be formatted as eg
     486     *                     "http://example.com:8080" or "http://example.com/"
     487     * @return the resulting String eg "http://example.com:8080/-
     488     */
     489    static String appendRecursiveSubdirToCodebaseHostString(final String codebaseHost) {
     490        requireNonNull(codebaseHost);
     491        String result = codebaseHost;
     492        while (result.endsWith("/")) {
     493            result = result.substring(0, result.length() - 1);
     494        }
     495        // See http://docs.oracle.com/javase/8/docs/api/java/net/URLPermission.html
     496        result = result + "/-"; // allow access to any resources recursively on the host domain
     497        return result;
     498    }
     499
     500    private static void requireNonNull(final Object arg) {
     501        if (arg == null) {
     502            throw new NullPointerException();
     503        }
     504    }
     505
    248506    /**
    249507     * Returns all the names of the basic JNLP system properties accessible by RIAs
  • trunk/icedtea-web/netx/net/sourceforge/jnlp/StreamEater.java

    r348 r429  
    2020import java.io.IOException;
    2121import java.io.InputStream;
     22import net.sourceforge.jnlp.util.logging.OutputController;
    2223
    2324/**
     
    3334    public void run() {
    3435        try {
     36            StringBuilder s = new StringBuilder();
    3537            while (true) {
    3638                int c = stream.read();
    37                 if (c == -1)
     39                if (c == -1){
     40                    OutputController.getLogger().log(OutputController.Level.MESSAGE_ALL, s.toString());
    3841                    break;
    39 
    40                 System.out.write(c);
     42                } else {
     43                    char ch = (char) c;
     44                    if (ch == '\n'){
     45                        OutputController.getLogger().log(OutputController.Level.MESSAGE_ALL, s.toString());
     46                        s = new StringBuilder();
     47                    }else {
     48                        s.append((char) c);
     49                    }
     50                }
     51               
    4152            }
    4253        } catch (IOException ex) {
  • trunk/icedtea-web/netx/net/sourceforge/jnlp/UpdateDesc.java

    r348 r429  
     1/* UpdateDesc.java
     2   Copyright (C) 2010 Red Hat, Inc.
     3
     4This file is part of IcedTea.
     5
     6IcedTea is free software; you can redistribute it and/or
     7modify it under the terms of the GNU General Public License as published by
     8the Free Software Foundation, version 2.
     9
     10IcedTea is distributed in the hope that it will be useful,
     11but WITHOUT ANY WARRANTY; without even the implied warranty of
     12MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
     13General Public License for more details.
     14
     15You should have received a copy of the GNU General Public License
     16along with IcedTea; see the file COPYING.  If not, write to
     17the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
     1802110-1301 USA.
     19
     20Linking this library statically or dynamically with other modules is
     21making a combined work based on this library.  Thus, the terms and
     22conditions of the GNU General Public License cover the whole
     23combination.
     24
     25As a special exception, the copyright holders of this library give you
     26permission to link this library with independent modules to produce an
     27executable, regardless of the license terms of these independent
     28modules, and to copy and distribute the resulting executable under
     29terms of your choice, provided that you also meet, for each linked
     30independent module, the terms and conditions of the license of that
     31module.  An independent module is a module which is not derived from
     32or based on this library.  If you modify this library, you may extend
     33this exception to your version of the library, but you are not
     34obligated to do so.  If you do not wish to do so, delete this
     35exception statement from your version.
     36 */
     37
    138package net.sourceforge.jnlp;
    239
  • trunk/icedtea-web/netx/net/sourceforge/jnlp/Version.java

    r418 r429  
    2020
    2121/**
     22 * <p>
    2223 * A JNLP Version string in the form "1.2-3_abc" followed by an
    2324 * optional + (includes all later versions) or * (matches any
    2425 * suffixes on versions).  More than one version can be included
    25  * in a string by separating them with spaces.<p>
    26  *
     26 * in a string by separating them with spaces.
     27 * </p>
     28 * <p>
    2729 * Version strings are divided by "._-" charecters into parts.
    2830 * These parts are compared numerically if they can be parsed as
     
    3133 * the smaller one is padded with zero or the empty string.  Note
    3234 * that the padding in this version means that 1.2+ matches
    33  * 1.4.0-beta1, but may not in future versions.<p>
     35 * 1.4.0-beta1, but may not in future versions.
     36 * </p>
    3437 *
    3538 * @author <a href="mailto:jmaxwell@users.sourceforge.net">Jon A. Maxwell (JAM)</a> - initial author
     
    309312    public String toString() {
    310313        return versionString;
    311     }
    312 
    313     /**
    314      * Test.
    315      */
    316     /*
    317     public static void main(String args[]) {
    318         Version jvms[] = {
    319             new Version("1.1* 1.3*"),
    320             new Version("1.2+"),
    321         };
    322 
    323         Version versions[] = {
    324             new Version("1.1"),
    325             new Version("1.1.8"),
    326             new Version("1.2"),
    327             new Version("1.3"),
    328             new Version("2.0"),
    329             new Version("1.3.1"),
    330             new Version("1.2.1"),
    331             new Version("1.3.1-beta"),
    332             new Version("1.1 1.2"),
    333             new Version("1.2 1.3"),
    334         };
    335 
    336         for (int j = 0; j < jvms.length; j++) {
    337             for (int v = 0; v < versions.length; v++) {
    338                 System.out.print( jvms[j].toString() + " " );
    339                 if (!jvms[j].matches(versions[v]))
    340                     System.out.print( "!" );
    341                 System.out.println( "matches " + versions[v].toString() );
    342             }
    343         }
    344 
    345         System.out.println("Test completed");
    346     }
    347     */
     314    } 
    348315
    349316}
  • trunk/icedtea-web/netx/net/sourceforge/jnlp/browser/BrowserAwareProxySelector.java

    r348 r429  
    4141import java.io.File;
    4242import java.io.IOException;
    43 import java.net.InetSocketAddress;
    4443import java.net.MalformedURLException;
    4544import java.net.Proxy;
    46 import java.net.SocketAddress;
    4745import java.net.URI;
    4846import java.net.URL;
    49 import java.net.Proxy.Type;
    5047import java.util.ArrayList;
    5148import java.util.Arrays;
     
    5350import java.util.Map;
    5451
     52import net.sourceforge.jnlp.config.DeploymentConfiguration;
    5553import net.sourceforge.jnlp.runtime.JNLPProxySelector;
    5654import net.sourceforge.jnlp.runtime.JNLPRuntime;
    5755import net.sourceforge.jnlp.runtime.PacEvaluator;
    5856import net.sourceforge.jnlp.runtime.PacEvaluatorFactory;
     57import net.sourceforge.jnlp.util.logging.OutputController;
    5958
    6059/**
     
    7877    private int browserProxyType = BROWSER_PROXY_TYPE_NONE;
    7978    private URL browserAutoConfigUrl;
     79    /** Whether the http proxy should be used for http, https, ftp and socket protocols */
    8080    private Boolean browserUseSameProxy;
    8181    private String browserHttpProxyHost;
     
    9393     * Create a new instance of this class, reading configuration fropm the browser
    9494     */
    95     public BrowserAwareProxySelector() {
    96         super();
     95    public BrowserAwareProxySelector(DeploymentConfiguration config) {
     96        super(config);
     97    }
     98
     99    public void initialize() {
    97100        try {
    98101            initFromBrowserConfig();
    99102        } catch (IOException e) {
    100             if (JNLPRuntime.isDebug()) {
    101                 e.printStackTrace();
    102             }
    103             System.err.println(R("RProxyFirefoxNotFound"));
     103            OutputController.getLogger().log(e);
     104            OutputController.getLogger().log(OutputController.Level.ERROR_ALL, R("RProxyFirefoxNotFound"));
    104105            browserProxyType = PROXY_TYPE_NONE;
    105106        }
     
    111112    private void initFromBrowserConfig() throws IOException {
    112113
    113         File preferencesFile = FirefoxPreferencesFinder.find();
    114 
    115         FirefoxPreferencesParser parser = new FirefoxPreferencesParser(preferencesFile);
    116         parser.parse();
    117         Map<String, String> prefs = parser.getPreferences();
     114        Map<String, String> prefs = parseBrowserPreferences();
    118115
    119116        String type = prefs.get("network.proxy.type");
     
    130127            }
    131128        } catch (MalformedURLException e) {
    132             e.printStackTrace();
     129            OutputController.getLogger().log(OutputController.Level.ERROR_ALL, e);
    133130        }
    134131
     
    147144        browserFtpProxyHost = prefs.get("network.proxy.ftp");
    148145        browserFtpProxyPort = stringToPort(prefs.get("network.proxy.ftp_port"));
    149         browserSocks4ProxyHost = prefs.get("networking.proxy.socks");
     146        browserSocks4ProxyHost = prefs.get("network.proxy.socks");
    150147        browserSocks4ProxyPort = stringToPort(prefs.get("network.proxy.socks_port"));
     148    }
     149
     150    Map<String, String> parseBrowserPreferences() throws IOException {
     151        File preferencesFile = FirefoxPreferencesFinder.find();
     152        FirefoxPreferencesParser parser = new FirefoxPreferencesParser(preferencesFile);
     153        parser.parse();
     154        return parser.getPreferences();
    151155    }
    152156
     
    167171
    168172    /**
     173     * <p>
    169174     * The main entry point for {@link BrowserAwareProxySelector}. Based on
    170175     * the browser settings, determines proxy information for a given URI.
     176     * </p>
    171177     * <p>
    172178     * The appropriate proxy may be determined by reading static information
    173179     * from the browser's preferences file, or it may be computed dynamically,
    174180     * by, for example, running javascript code.
     181     * </p>
    175182     */
    176183    @Override
     
    209216                    optionDescription = "Unknown";
    210217                }
    211                 if (JNLPRuntime.isDebug()) {
    212                     System.err.println(R("RProxyFirefoxOptionNotImplemented", browserProxyType, optionDescription));
    213                 }
     218                OutputController.getLogger().log(OutputController.Level.ERROR_DEBUG,R("RProxyFirefoxOptionNotImplemented", browserProxyType, optionDescription));
    214219                proxies.add(Proxy.NO_PROXY);
    215220        }
    216221
    217         if (JNLPRuntime.isDebug()) {
    218             System.out.println("Browser selected proxies: " + proxies.toString());
    219         }
     222        OutputController.getLogger().log("Browser selected proxies: " + proxies.toString());
    220223
    221224        return proxies;
     
    237240            proxies.addAll(getProxiesFromPacResult(proxiesString));
    238241        } catch (MalformedURLException e) {
    239             e.printStackTrace();
     242            OutputController.getLogger().log(OutputController.Level.ERROR_ALL, e);
    240243            proxies.add(Proxy.NO_PROXY);
    241244        }
     
    249252     */
    250253    private List<Proxy> getFromBrowserConfiguration(URI uri) {
    251         List<Proxy> proxies = new ArrayList<Proxy>();
    252 
    253         String scheme = uri.getScheme();
    254 
    255         if (browserUseSameProxy) {
    256             SocketAddress sa = new InetSocketAddress(browserHttpProxyHost, browserHttpProxyPort);
    257             Proxy proxy;
    258             if (scheme.equals("socket")) {
    259                 proxy = new Proxy(Type.SOCKS, sa);
    260             } else {
    261                 proxy = new Proxy(Type.HTTP, sa);
    262             }
    263             proxies.add(proxy);
    264         } else if (scheme.equals("http")) {
    265             SocketAddress sa = new InetSocketAddress(browserHttpProxyHost, browserHttpProxyPort);
    266             proxies.add(new Proxy(Type.HTTP, sa));
    267         } else if (scheme.equals("https")) {
    268             SocketAddress sa = new InetSocketAddress(browserHttpsProxyHost, browserHttpsProxyPort);
    269             proxies.add(new Proxy(Type.HTTP, sa));
    270         } else if (scheme.equals("ftp")) {
    271             SocketAddress sa = new InetSocketAddress(browserFtpProxyHost, browserFtpProxyPort);
    272             proxies.add(new Proxy(Type.HTTP, sa));
    273         } else if (scheme.equals("socket")) {
    274             SocketAddress sa = new InetSocketAddress(browserSocks4ProxyHost, browserSocks4ProxyPort);
    275             proxies.add(new Proxy(Type.SOCKS, sa));
    276         } else {
    277             proxies.add(Proxy.NO_PROXY);
    278         }
    279 
    280         return proxies;
     254        return getFromArguments(uri, browserUseSameProxy, true,
     255                browserHttpsProxyHost, browserHttpsProxyPort,
     256                browserHttpProxyHost, browserHttpProxyPort,
     257                browserFtpProxyHost, browserFtpProxyPort,
     258                browserSocks4ProxyHost, browserSocks4ProxyPort);
    281259    }
    282260
  • trunk/icedtea-web/netx/net/sourceforge/jnlp/browser/FirefoxPreferencesFinder.java

    r398 r429  
    4848import net.sourceforge.jnlp.runtime.JNLPRuntime;
    4949import net.sourceforge.jnlp.config.Defaults;
     50import net.sourceforge.jnlp.util.logging.OutputController;
    5051
    5152/**
     
    7475        }
    7576
    76         if (JNLPRuntime.isDebug()) {
    77             System.out.println("Using firefox's profiles file: " + profilesPath);
    78         }
     77        OutputController.getLogger().log("Using firefox's profiles file: " + profilesPath);
     78
    7979        BufferedReader reader = new BufferedReader(new FileReader(profilesPath));
    8080
     
    133133        } else {
    134134            String fullPath = configPath + path + File.separator + "prefs.js";
    135             if (JNLPRuntime.isDebug()) {
    136                 System.out.println("Found preferences file: " + fullPath);
    137             }
     135            OutputController.getLogger().log("Found preferences file: " + fullPath);
    138136            return new File(fullPath);
    139137        }
  • trunk/icedtea-web/netx/net/sourceforge/jnlp/browser/FirefoxPreferencesParser.java

    r348 r429  
    4646
    4747import net.sourceforge.jnlp.runtime.JNLPRuntime;
     48import net.sourceforge.jnlp.util.logging.OutputController;
    4849
    4950/**
     51 * <p>
    5052 * A parser for Firefox's preferences file. It can 'parse' Firefox's
    5153 * preferences file and expose the prefrences in a simple to use format.
    52  * <p>
     54 * </p>
    5355 * Sample usage:
    54  * <pre>
     56 * <pre><code>
    5557 * FirefoxPreferencesParser p = new FirefoxPreferencesParser(prefsFile);
    5658 * p.parse();
    5759 * Map&lt;String,String&gt; prefs = p.getPreferences();
    5860 * System.out.println("blink allowed: " + prefs.get("browser.blink_allowed"));
    59  * </pre>
     61 * </code></pre>
    6062 */
    6163public final class FirefoxPreferencesParser {
     
    129131
    130132                            if (foundKey && foundValue) {
    131                                 // System.out.println("added (\"" + key + "\", \"" + value + "\")");
     133                                //ItwLogger.getLogger().printOutLn("added (\"" + key + "\", \"" + value + "\")");
    132134                                prefs.put(key, value);
    133135                            }
     
    139141            reader.close();
    140142        }
    141         if (JNLPRuntime.isDebug()) {
    142             System.out.println("Read " + prefs.size() + " entries from Firefox's preferences");
    143         }
     143        OutputController.getLogger().log("Read " + prefs.size() + " entries from Firefox's preferences");
    144144    }
    145145
  • trunk/icedtea-web/netx/net/sourceforge/jnlp/cache/CacheDirectory.java

    r348 r429  
    4141
    4242import net.sourceforge.jnlp.util.FileUtils;
     43import net.sourceforge.jnlp.util.logging.OutputController;
    4344
    4445public final class CacheDirectory {
     
    9495                delete = false;
    9596        }
    96         if (delete)
    97             System.out.println("Delete -- " + root);
     97        if (delete){
     98            OutputController.getLogger().log(OutputController.Level.MESSAGE_ALL, "Delete -- " + root);
     99        }
    98100        //            root.delete();
    99101        return true;
  • trunk/icedtea-web/netx/net/sourceforge/jnlp/cache/CacheEntry.java

    r348 r429  
    1717package net.sourceforge.jnlp.cache;
    1818
     19import net.sourceforge.jnlp.util.logging.OutputController;
    1920import static net.sourceforge.jnlp.runtime.Translator.R;
    2021
     
    2728
    2829/**
    29  * Describes an entry in the cache.<p>
     30 * Describes an entry in the cache.
    3031 *
    3132 * @author <a href="mailto:jmaxwell@users.sourceforge.net">Jon A. Maxwell (JAM)</a> - initial author
     
    122123                return false;
    123124        } catch (Exception ex) {
    124             if (JNLPRuntime.isDebug())
    125                 ex.printStackTrace();
     125            OutputController.getLogger().log(ex);;
    126126
    127127            return cached; // if can't connect return whether already in cache
     
    149149                return true;
    150150        } catch (Exception ex) {
    151             if (JNLPRuntime.isDebug())
    152                 ex.printStackTrace();
     151            OutputController.getLogger().log(ex);
    153152
    154153            return false; // should throw?
  • trunk/icedtea-web/netx/net/sourceforge/jnlp/cache/CacheLRUWrapper.java

    r418 r429  
    5454import net.sourceforge.jnlp.runtime.JNLPRuntime;
    5555import net.sourceforge.jnlp.util.FileUtils;
     56import net.sourceforge.jnlp.util.logging.OutputController;
    5657import net.sourceforge.jnlp.util.PropertiesFile;
    5758
     
    6061 * multiple jvm instances.
    6162 *
    62  * @author Andrew Su (asu@redhat.com, andrew.su@utoronto.ca)
     63 * @author <a href="mailto:Andrew%20Su%20&lt;asu@redhat.com&gt;">Andrew Su (asu@redhat.com</a>, <a href="mailto:Andrew%20Su%20&lt;andrew.su@utoronto.ca&gt;">andrew.su@utoronto.ca)</a>
    6364 *
    6465 */
    65 enum CacheLRUWrapper {
     66public enum CacheLRUWrapper {
    6667    INSTANCE;
    6768
     
    7374    /* location of cache directory */
    7475    private final String setCachePath = JNLPRuntime.getConfiguration().getProperty(DeploymentConfiguration.KEY_USER_CACHE_DIR);
    75     private final String cacheDir = new File(setCachePath != null ? setCachePath : System.getProperty("java.io.tmpdir")).getPath();
     76    String cacheDir = new File(setCachePath != null ? setCachePath : System.getProperty("java.io.tmpdir")).getPath();
    7677
    7778    /*
     
    8081     * accessed) followed by folder of item. value = path to file.
    8182     */
    82     private PropertiesFile cacheOrder = new PropertiesFile(
    83             new File(cacheDir + File.separator + "recently_used"));
    84 
    85     private CacheLRUWrapper(){
     83    PropertiesFile cacheOrder = new PropertiesFile(
     84            new File(cacheDir + File.separator + CACHE_INDEX_FILE_NAME));
     85    public static final String CACHE_INDEX_FILE_NAME = "recently_used";
     86
     87    private CacheLRUWrapper() {
    8688        File f = cacheOrder.getStoreFile();
    8789        if (!f.exists()) {
     
    9092                FileUtils.createRestrictedFile(f, true);
    9193            } catch (IOException e) {
    92                 e.printStackTrace();
     94                OutputController.getLogger().log(OutputController.Level.ERROR_ALL, e);
    9395            }
    9496        }
     
    98100     * Returns an instance of the policy.
    99101     *
    100      * @param propertiesFile
    101      * @return
     102     * @return an instance of the policy
    102103     */
    103104    public static CacheLRUWrapper getInstance() {
     
    114115         */
    115116        if (loaded && checkData()) {
    116             if (JNLPRuntime.isDebug()) {
    117                 new LruCacheException().printStackTrace();
    118             }
    119             System.out.println(R("CFakeCache"));
     117            OutputController.getLogger().log(new LruCacheException());
     118            OutputController.getLogger().log(OutputController.Level.MESSAGE_ALL, R("CFakeCache"));
    120119            store();
    121             System.out.println(R("CFakedCache"));
     120            OutputController.getLogger().log(OutputController.Level.MESSAGE_ALL, R("CFakedCache"));
    122121        }
    123122    }
     
    222221     * @return List of Strings sorted by ascending order.
    223222     */
     223    @SuppressWarnings({"unchecked", "rawtypes"})
     224    //although Properties are pretending to be <object,Object> they are always <String,String>
     225    //bug in jdk?
    224226    public synchronized List<Entry<String, String>> getLRUSortedEntries() {
    225         ArrayList<Entry<String, String>> entries = new ArrayList(cacheOrder.entrySet());
     227        List<Entry<String, String>> entries = new ArrayList(cacheOrder.entrySet());
    226228        // sort by keys in descending order.
    227229        Collections.sort(entries, new Comparator<Entry<String, String>>() {
     
    246248        } catch (OverlappingFileLockException e) { // if overlap we just increase the count.
    247249        } catch (Exception e) { // We didn't get a lock..
    248             e.printStackTrace();
     250            OutputController.getLogger().log(e);
    249251        }
    250252        if (fl != null) lockCount++;
     
    264266                }
    265267            } catch (IOException e) {
    266                 e.printStackTrace();
     268                OutputController.getLogger().log(e);
    267269            }
    268270        }
  • trunk/icedtea-web/netx/net/sourceforge/jnlp/cache/CacheUtil.java

    r418 r429  
    1919import static net.sourceforge.jnlp.runtime.Translator.R;
    2020
    21 import java.io.*;
    22 import java.net.*;
     21import java.io.BufferedInputStream;
     22import java.io.BufferedOutputStream;
     23import java.io.File;
     24import java.io.FileNotFoundException;
     25import java.io.FileOutputStream;
     26import java.io.FilePermission;
     27import java.io.IOException;
     28import java.io.InputStream;
     29import java.io.OutputStream;
     30import java.net.MalformedURLException;
     31import java.net.URL;
     32import java.net.URLConnection;
    2333import java.nio.channels.FileChannel;
    2434import java.nio.channels.FileLock;
    2535import java.nio.channels.OverlappingFileLockException;
     36import java.security.Permission;
    2637import java.util.ArrayList;
    2738import java.util.HashMap;
     
    3041import java.util.Map.Entry;
    3142import java.util.Set;
    32 import java.security.*;
    33 import javax.jnlp.*;
    34 
    35 import net.sourceforge.jnlp.*;
     43
     44import javax.jnlp.DownloadServiceListener;
     45
     46import net.sourceforge.jnlp.Version;
    3647import net.sourceforge.jnlp.config.DeploymentConfiguration;
    37 import net.sourceforge.jnlp.runtime.*;
     48import net.sourceforge.jnlp.runtime.ApplicationInstance;
     49import net.sourceforge.jnlp.runtime.JNLPRuntime;
    3850import net.sourceforge.jnlp.util.FileUtils;
     51import net.sourceforge.jnlp.util.logging.OutputController;
    3952import net.sourceforge.jnlp.util.PropertiesFile;
     53import net.sourceforge.jnlp.util.UrlUtils;
    4054
    4155/**
    4256 * Provides static methods to interact with the cache, download
    43  * indicator, and other utility methods.<p>
     57 * indicator, and other utility methods.
    4458 *
    4559 * @author <a href="mailto:jmaxwell@users.sourceforge.net">Jon A. Maxwell (JAM)</a> - initial author
     
    5569    /**
    5670     * Compares a URL using string compare of its protocol, host,
    57      * port, path, query, and anchor.  This method avoids the host
     71     * port, path, query, and anchor. This method avoids the host
    5872     * name lookup that URL.equals does for http: protocol URLs.
    5973     * It may not return the same value as the URL.equals method
     
    7387        }
    7488        try {
    75             URL nu1 = ResourceTracker.normalizeUrl(u1, false);
    76             URL nu2 = ResourceTracker.normalizeUrl(u2, false);
     89            URL nu1 = UrlUtils.normalizeUrl(u1);
     90            URL nu2 = UrlUtils.normalizeUrl(u2);
    7791            if (notNullUrlEquals(nu1, nu2)) {
    7892                return true;
     
    98112    /**
    99113     * Caches a resource and returns a URL for it in the cache;
    100      * blocks until resource is cached.  If the resource location is
     114     * blocks until resource is cached. If the resource location is
    101115     * not cacheable (points to a local file, etc) then the original
    102      * URL is returned.<p>
     116     * URL is returned.
    103117     *
    104118     * @param location location of the resource
    105      * @param version the version, or null
     119     * @param version the version, or {@code null}
    106120     * @return either the location in the cache or the original location
    107121     */
     
    119133
    120134    /**
    121      * Compare strings that can be null.
     135     * Compare strings that can be {@code null}.
    122136     */
    123137    private static boolean compare(String s1, String s2, boolean ignore) {
     
    135149    /**
    136150     * Returns the Permission object necessary to access the
    137      * resource, or null if no permission is needed.
     151     * resource, or {@code null} if no permission is needed.
    138152     */
    139153    public static Permission getReadPermission(URL location, Version version) {
     
    148162            } catch (java.io.IOException ioe) {
    149163                // should try to figure out the permission
    150                 if (JNLPRuntime.isDebug())
    151                     ioe.printStackTrace();
     164                OutputController.getLogger().log(ioe);
    152165            }
    153166        }
     
    166179
    167180        if (!okToClearCache()) {
    168             System.err.println(R("CCannotClearCache"));
     181            OutputController.getLogger().log(OutputController.Level.ERROR_ALL, R("CCannotClearCache"));
    169182            return false;
    170183        }
     
    175188        }
    176189
    177         if (JNLPRuntime.isDebug()) {
    178             System.err.println("Clearing cache directory: " + cacheDir);
    179         }
     190        OutputController.getLogger().log(OutputController.Level.ERROR_DEBUG, "Clearing cache directory: " + cacheDir);
    180191        try {
    181192            cacheDir = cacheDir.getCanonicalFile();
    182193            FileUtils.recursiveDelete(cacheDir, cacheDir);
     194            cacheDir.mkdir();
    183195        } catch (IOException e) {
    184196            throw new RuntimeException(e);
     
    192204     */
    193205    private static boolean okToClearCache() {
    194         File otherJavawsRunning = new File(JNLPRuntime.getConfiguration()
    195                 .getProperty(DeploymentConfiguration.KEY_USER_NETX_RUNNING_FILE));
     206        File otherJavawsRunning = new File(JNLPRuntime.getConfiguration().getProperty(DeploymentConfiguration.KEY_USER_NETX_RUNNING_FILE));
     207        FileLock locking = null;
    196208        try {
    197209            if (otherJavawsRunning.isFile()) {
     
    199211               
    200212                FileChannel channel = fis.getChannel();
    201                 if (channel.tryLock() == null) {
    202                     if (JNLPRuntime.isDebug()) {
    203                         System.out.println("Other instances of netx are running");
    204                     }
     213                locking  = channel.tryLock();
     214                if (locking == null) {
     215                    OutputController.getLogger().log("Other instances of netx are running");
    205216                    return false;
    206217                }
    207 
    208                 if (JNLPRuntime.isDebug()) {
    209                     System.out.println("No other instances of netx are running");
    210                 }
     218                OutputController.getLogger().log("No other instances of netx are running");
    211219                return true;
    212220
    213221            } else {
    214                 if (JNLPRuntime.isDebug()) {
    215                     System.out.println("No instance file found");
    216                 }
     222                OutputController.getLogger().log("No instance file found");
    217223                return true;
    218224            }
    219225        } catch (IOException e) {
    220226            return false;
     227        } finally {
     228            if (locking != null) {
     229                try {
     230                    locking.release();
     231                } catch (IOException ex) {
     232                    OutputController.getLogger().log(ex);
     233                }
     234            }
    221235        }
    222236    }
     
    227241     * immediately.
    228242     *
    229      * @param source the source URL
     243     * @param source the source {@link URL}
    230244     * @param version the versions to check for
    231      * @param connection a connection to the URL, or null
     245     * @param connection a connection to the {@link URL}, or {@code null}
    232246     * @return whether the cache contains the version
    233247     * @throws IllegalArgumentException if the source is not cacheable
     
    247261            boolean result = entry.isCurrent(connection);
    248262
    249             if (JNLPRuntime.isDebug())
    250                 System.out.println("isCurrent: " + source + " = " + result);
     263            OutputController.getLogger().log("isCurrent: " + source + " = " + result);
    251264
    252265            return result;
    253266        } catch (Exception ex) {
    254             if (JNLPRuntime.isDebug())
    255                 ex.printStackTrace();
    256 
     267            OutputController.getLogger().log(ex);
    257268            return isCached(source, version); // if can't connect return whether already in cache
    258269        }
     
    275286        boolean result = entry.isCached();
    276287
    277         if (JNLPRuntime.isDebug())
    278             System.out.println("isCached: " + source + " = " + result);
     288        OutputController.getLogger().log("isCached: " + source + " = " + result);
    279289
    280290        return result;
     
    305315     * resource that matches the specified version will be returned.
    306316     *
    307      * @param source the source URL
     317     * @param source the source {@link URL}
    308318     * @param version the version id of the local file
    309      * @return the file location in the cache, or null if no versions cached
     319     * @return the file location in the cache, or {@code null} if no versions cached
    310320     * @throws IllegalArgumentException if the source is not cacheable
    311321     */
     
    337347     *
    338348     * @param urlPath Path of cache item within cache directory.
    339      * @return File if we have searched before, null otherwise.
     349     * @return File if we have searched before, {@code null} otherwise.
    340350     */
    341351    private static File getCacheFileIfExist(File urlPath) {
     
    365375        int index = path.indexOf(File.separatorChar, len + 1);
    366376        return path.substring(index);
     377    }
     378
     379    /**
     380     * Returns the parent directory of the cached resource.
     381     * @param filePath The path of the cached resource directory.
     382     */
     383    public static String getCacheParentDirectory(String filePath) {
     384        String path = filePath;
     385        String tempPath = "";
     386
     387        while(path.startsWith(cacheDir) && !path.equals(cacheDir)){
     388                tempPath = new File(path).getParent();
     389
     390                if (tempPath.equals(cacheDir))
     391                    break;
     392
     393                path = tempPath;
     394        }
     395        return path;
    367396    }
    368397
     
    394423                        lruHandler.addEntry(lruHandler.generateKey(cacheFile.getPath()), cacheFile.getPath());
    395424                    } catch (IOException ioe) {
    396                         ioe.printStackTrace();
     425                       OutputController.getLogger().log(ioe);
    397426                    }
    398427
     
    534563            }
    535564        } catch (InterruptedException ex) {
    536             if (JNLPRuntime.isDebug())
    537                 ex.printStackTrace();
     565            OutputController.getLogger().log(ex);
    538566        } finally {
    539567            if (listener != null)
     
    610638                            FileUtils.recursiveDelete(f, f);
    611639                        } catch (IOException e1) {
    612                             e1.printStackTrace();
     640                            OutputController.getLogger().log(OutputController.Level.ERROR_ALL, e1);
    613641                        }
    614642                    }
     
    651679        } catch (OverlappingFileLockException e) {
    652680        } catch (FileNotFoundException e) {
    653             e.printStackTrace();
     681           OutputController.getLogger().log(OutputController.Level.ERROR_ALL, e);
    654682        }
    655683    }
     
    670698            propertiesLockPool.remove(storeFile.getPath());
    671699        } catch (IOException e) {
    672             e.printStackTrace();
     700            OutputController.getLogger().log(OutputController.Level.ERROR_ALL, e);
    673701        }
    674702    }
  • trunk/icedtea-web/netx/net/sourceforge/jnlp/cache/DefaultDownloadIndicator.java

    r418 r429  
    3030import net.sourceforge.jnlp.runtime.*;
    3131import net.sourceforge.jnlp.util.ImageResources;
     32import net.sourceforge.jnlp.util.ScreenFinder;
    3233
    3334/**
     
    6364    /** shared constraint */
    6465    static GridBagConstraints vertical;
     66    static GridBagConstraints verticalNoClean;
    6567    static GridBagConstraints verticalIndent;
    6668    static {
     
    7173        vertical.anchor = GridBagConstraints.WEST;
    7274
     75        verticalNoClean = new GridBagConstraints();
     76        verticalNoClean.weightx = 1.0;
     77
    7378        verticalIndent = (GridBagConstraints) vertical.clone();
    7479        verticalIndent.insets = new Insets(0, 10, 3, 0);
     
    102107        synchronized (frameMutex) {
    103108            if (frame == null) {
    104                 frame = new JFrame(downloading + "...");
    105                 frame.setIconImages(ImageResources.INSTANCE.getApplicationImages());
    106                 frame.getContentPane().setLayout(new GridBagLayout());
     109                frame=createDownloadIndicatorFrame(true);
    107110            }
    108111
     
    110113                for (URL url : resources) {
    111114                    result.addProgressPanel(url, null);
     115       
    112116                }
    113117            }
     
    115119            frame.getContentPane().add(result, vertical);
    116120            frame.pack();
    117 
    118             if (!frame.isVisible()) {
    119                 Dimension screenSize = Toolkit.getDefaultToolkit().getScreenSize();
    120                 Insets insets = Toolkit.getDefaultToolkit().getScreenInsets(frame.getGraphicsConfiguration());
    121                 Dimension screen = new Dimension(screenSize.width - insets.left,
    122                         screenSize.height - insets.top);
    123                 frame.setLocation(screen.width - frame.getWidth(),
    124                         screen.height - frame.getHeight());
    125             }
     121            placeFrameToLowerRight();
     122            result.addComponentListener(new ComponentAdapter() {
     123                @Override
     124                public void componentResized(ComponentEvent e) {
     125                    placeFrameToLowerRight();
     126                }
     127            });
    126128
    127129            frame.setVisible(true);
     
    129131            return result;
    130132        }
     133    }
     134
     135     public static JFrame createDownloadIndicatorFrame(boolean undecorated) throws HeadlessException {
     136        JFrame f = new JFrame(downloading + "...");
     137        f.setUndecorated(undecorated);
     138        f.setIconImages(ImageResources.INSTANCE.getApplicationImages());
     139        f.getContentPane().setLayout(new GridBagLayout());
     140        return f;
     141    }
     142
     143    /**
     144     * This places indicator to lower right corner of active monitor.
     145     */
     146    private static void placeFrameToLowerRight() throws HeadlessException {
     147       Rectangle bounds = ScreenFinder.getCurrentScreenSizeWithoutBounds();
     148        frame.setLocation(bounds.width+bounds.x - frame.getWidth(),
     149                bounds.height+bounds.y - frame.getHeight());
    131150    }
    132151
     
    164183     */
    165184    static class DownloadPanel extends JPanel implements DownloadServiceListener {
    166 
     185        private final DownloadPanel self;
     186
     187        private static enum States{
     188            ONE_JAR, COLLAPSED, DETAILED;
     189         }
     190       
     191        private static final String DETAILS=R("ButShowDetails");
     192        private static final String HIDE_DETAILS=R("ButHideDetails");   
    167193        /** the download name */
    168194        private String downloadName;
    169 
    170195        /** Downloading part: */
    171196        private JLabel header = new JLabel();
    172 
     197        /** Show/hide detailsButton button: */
     198        private final JButton detailsButton;
     199        private static final URL magnifyGlassUrl = ClassLoader.getSystemResource("net/sourceforge/jnlp/resources/showDownloadDetails.png");
     200        private static final URL redCrossUrl = ClassLoader.getSystemResource("net/sourceforge/jnlp/resources/hideDownloadDetails.png");
     201        private static final Icon magnifyGlassIcon = new ImageIcon(magnifyGlassUrl);
     202        private static final Icon redCrossIcon = new ImageIcon(redCrossUrl);
     203        /** used  instead of detailsButton button in case of one jar*/
     204        private JLabel delimiter = new JLabel(""); 
     205        /** all already created progress bars*/
     206        private List<ProgressPanel> progressPanels = new ArrayList<ProgressPanel>();
     207        private States state=States.ONE_JAR;
     208        private ProgressPanel mainProgressPanel;
     209       
    173210        /** list of URLs being downloaded */
    174211        private List<URL> urls = new ArrayList<URL>();
     
    182219         */
    183220        protected DownloadPanel(String downloadName) {
     221            self = this;
    184222            setLayout(new GridBagLayout());
    185 
    186223            this.downloadName = downloadName;
    187             this.add(header, vertical);
     224            this.add(header, verticalNoClean);
    188225            header.setFont(header.getFont().deriveFont(Font.BOLD));
    189 
     226            this.add(delimiter, vertical);
     227            detailsButton = new JButton(magnifyGlassIcon);
     228            int w = magnifyGlassIcon.getIconWidth();
     229            int h = magnifyGlassIcon.getIconHeight();
     230            detailsButton.setPreferredSize(new Dimension(w + 2, h + 2));
     231            detailsButton.addActionListener(new ActionListener() {
     232                @Override
     233                public void actionPerformed(ActionEvent e) {
     234                    if (state == States.DETAILED) {
     235                        state = States.COLLAPSED;
     236                        detailsButton.setToolTipText(DETAILS);
     237                        detailsButton.setIcon(magnifyGlassIcon);
     238                        for (ProgressPanel progressPanel : progressPanels) {
     239                            remove(progressPanel);
     240                        }
     241                        add(mainProgressPanel, verticalIndent);
     242                        recreateFrame(true);
     243                    } else {
     244                        state = States.DETAILED;
     245                        detailsButton.setToolTipText(HIDE_DETAILS);
     246                        detailsButton.setIcon(redCrossIcon);
     247                        remove(mainProgressPanel);
     248                        for (ProgressPanel progressPanel : progressPanels) {
     249                            add(progressPanel, verticalIndent);
     250                        }
     251                        recreateFrame(false);
     252                    }
     253                }
     254
     255                public void recreateFrame(boolean undecorated) throws HeadlessException {
     256                    JFrame oldFrame = frame;
     257                    frame = createDownloadIndicatorFrame(undecorated);
     258                    frame.getContentPane().add(self, vertical);
     259                    synchronized (frameMutex) {
     260                        frame.pack();
     261                        placeFrameToLowerRight();
     262                    }
     263                    frame.setVisible(true);
     264                    oldFrame.dispose();
     265                }
     266            });
    190267            setOverallPercent(0);
    191268        }
     
    197274            if (!urls.contains(url)) {
    198275                ProgressPanel panel = new ProgressPanel(url, version);
    199 
    200                 add(panel, verticalIndent);
     276                if (state != States.COLLAPSED) {
     277                    add(panel, verticalIndent);
     278                }
     279                progressPanels.add(panel);
     280                urls.add(url);
     281                panels.add(panel);
     282                //download indicator does not know about added jars
     283                //When only one jar is added to downlaod queue then its progress is
     284                //shown, and there is no show detail button.
     285                //When second one is added, then it already knows that there will
     286                //be two or more jars, so it swap to collapsed state in count of two.
     287                //no later, no sooner
     288                if (panels.size() == 2){
     289                    remove(panels.get(0));
     290                    remove(panels.get(1));
     291                    remove(delimiter);
     292                    add(detailsButton,vertical);
     293                    mainProgressPanel=new ProgressPanel();
     294                    add(mainProgressPanel, verticalIndent);
     295                    state=States.COLLAPSED;
     296                }
    201297                synchronized (frameMutex) {
    202298                    frame.pack();
    203                 }
    204 
    205                 urls.add(url);
    206                 panels.add(panel);
     299                    placeFrameToLowerRight();
     300                }
     301
    207302            }
    208303        }
     
    220315
    221316                    setOverallPercent(overallPercent);
    222 
    223317                    ProgressPanel panel = panels.get(urls.indexOf(url));
    224318                    panel.setProgress(readSoFar, total);
    225319                    panel.repaint();
     320
    226321                }
    227322            };
     
    231326        /**
    232327         * Sets the overall percent completed.
     328         * should be called via invokeLater
    233329         */
    234330        public void setOverallPercent(int percent) {
     
    237333            // each update.
    238334            header.setText(downloading + " " + downloadName + ": " + percent + "% " + complete + ".");
     335            Container c = header.getParent();
     336            //we need to adapt both panels and also frame to new length of header text
     337            while (c != null) {
     338                c.invalidate();
     339                c.validate();
     340                if (c instanceof  Window){
     341                    ((Window) c).pack();
     342                }
     343                c=c.getParent();
     344            }
     345            if (mainProgressPanel != null) {
     346                mainProgressPanel.setProgress(percent, 100);
     347                mainProgressPanel.repaint();
     348            }
    239349        }
    240350
     
    277387        private long total;
    278388        private long readSoFar;
    279 
     389        private Dimension size = new Dimension(80, 15);
     390
     391        ProgressPanel() {
     392            bar.setMinimumSize(size);
     393            bar.setPreferredSize(size);
     394            bar.setOpaque(false);
     395
     396            setLayout(new GridBagLayout());
     397
     398            GridBagConstraints gbc = new GridBagConstraints();
     399            styleGridBagConstraints(gbc);
     400            add(bar, gbc);
     401        }
     402       
    280403        ProgressPanel(URL url, String version) {
    281             JLabel location = new JLabel(" " + url.getHost() + "/" + url.getFile());
    282 
    283             bar.setMinimumSize(new Dimension(80, 15));
    284             bar.setPreferredSize(new Dimension(80, 15));
     404            this(" " + url.getHost() + "/" + url.getFile(),version);
     405        }
     406        ProgressPanel(String caption, String version) {
     407            JLabel location = new JLabel(caption);
     408
     409            bar.setMinimumSize(size);
     410            bar.setPreferredSize(size);
    285411            bar.setOpaque(false);
    286412
     
    292418            gbc.gridwidth = GridBagConstraints.RELATIVE;
    293419            add(bar, gbc);
    294 
     420           
     421            styleGridBagConstraints(gbc);
     422            add(location, gbc);
     423        }
     424
     425        public void setProgress(long readSoFar, long total) {
     426            this.readSoFar = readSoFar;
     427            this.total = total;
     428        }
     429
     430        public void paintComponent(Graphics g) {
     431            super.paintComponent(g);
     432
     433            int x = bar.getX();
     434            int y = bar.getY();
     435            int h = bar.getHeight();
     436            int w = bar.getWidth();
     437
     438            if (readSoFar <= 0 || total <= 0) {
     439                // make barber pole
     440            } else {
     441                double progress = (double) readSoFar / (double) total;
     442                int divide = (int) (w * progress);
     443
     444                g.setColor(Color.white);
     445                g.fillRect(x, y, w, h);
     446                g.setColor(Color.blue);
     447                g.fillRect(x + 1, y + 1, divide - 1, h - 1);
     448            }
     449        }
     450
     451        private void styleGridBagConstraints(GridBagConstraints gbc) {
    295452            gbc.insets = new Insets(0, 3, 0, 0);
    296453            gbc.weightx = 1.0;
     
    298455            gbc.gridwidth = GridBagConstraints.REMAINDER;
    299456            gbc.anchor = GridBagConstraints.WEST;
    300             add(location, gbc);
    301         }
    302 
    303         public void setProgress(long readSoFar, long total) {
    304             this.readSoFar = readSoFar;
    305             this.total = total;
    306         }
    307 
    308         public void paintComponent(Graphics g) {
    309             super.paintComponent(g);
    310 
    311             int x = bar.getX();
    312             int y = bar.getY();
    313             int h = bar.getHeight();
    314             int w = bar.getWidth();
    315 
    316             if (readSoFar <= 0 || total <= 0) {
    317                 // make barber pole
    318             } else {
    319                 double progress = (double) readSoFar / (double) total;
    320                 int divide = (int) (w * progress);
    321 
    322                 g.setColor(Color.white);
    323                 g.fillRect(x, y, w, h);
    324                 g.setColor(Color.blue);
    325                 g.fillRect(x + 1, y + 1, divide - 1, h - 1);
    326             }
    327457        }
    328458    };
  • trunk/icedtea-web/netx/net/sourceforge/jnlp/cache/DownloadIndicator.java

    r348 r429  
    3333    /**
    3434     * Return a download service listener that displays the progress
    35      * of downloading resources.  Update messages may be reported
    36      * for URLs that are not included initially.<p>
    37      *
     35     * of downloading resources. Update messages may be reported
     36     * for URLs that are not included initially.
     37     * <p>
    3838     * Progress messages are sent as if the DownloadServiceListener
    39      * were listening to a DownloadService request.  The listener
     39     * were listening to a DownloadService request. The listener
    4040     * will receive progress messages from time to time during the
    41      * download. <p>
     41     * download.
     42     * </p>
    4243     *
    4344     * @param app JNLP application downloading the files, or null if not applicable
  • trunk/icedtea-web/netx/net/sourceforge/jnlp/cache/IllegalResourceDescriptorException.java

    r418 r429  
     1/* IllegalResourceDescriptorException.java
     2   Copyright (C) 2012 Red Hat, Inc.
     3
     4This file is part of IcedTea.
     5
     6IcedTea is free software; you can redistribute it and/or
     7modify it under the terms of the GNU General Public License as published by
     8the Free Software Foundation, version 2.
     9
     10IcedTea is distributed in the hope that it will be useful,
     11but WITHOUT ANY WARRANTY; without even the implied warranty of
     12MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
     13General Public License for more details.
     14
     15You should have received a copy of the GNU General Public License
     16along with IcedTea; see the file COPYING.  If not, write to
     17the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
     1802110-1301 USA.
     19
     20Linking this library statically or dynamically with other modules is
     21making a combined work based on this library.  Thus, the terms and
     22conditions of the GNU General Public License cover the whole
     23combination.
     24
     25As a special exception, the copyright holders of this library give you
     26permission to link this library with independent modules to produce an
     27executable, regardless of the license terms of these independent
     28modules, and to copy and distribute the resulting executable under
     29terms of your choice, provided that you also meet, for each linked
     30independent module, the terms and conditions of the license of that
     31module.  An independent module is a module which is not derived from
     32or based on this library.  If you modify this library, you may extend
     33this exception to your version of the library, but you are not
     34obligated to do so.  If you do not wish to do so, delete this
     35exception statement from your version.
     36 */
     37
    138package net.sourceforge.jnlp.cache;
    239
     
    441public class IllegalResourceDescriptorException extends IllegalArgumentException {
    542    /**
    6      * Constructs a <code>IllegalResourceDescriptorException</code> with the
     43     * Constructs a {@code IllegalResourceDescriptorException} with the
    744     * specified detail message.
    845     * @param msg the detail message.
  • trunk/icedtea-web/netx/net/sourceforge/jnlp/cache/Resource.java

    r418 r429  
    1717package net.sourceforge.jnlp.cache;
    1818
     19import net.sourceforge.jnlp.util.logging.OutputController;
    1920import java.io.*;
    2021import java.net.*;
     
    2627
    2728/**
     29 * <p>
    2830 * Information about a single resource to download.
    2931 * This class tracks the downloading of various resources of a
     
    3133 * jnlp and extension files, jars, and jardiff files using the
    3234 * version based protocol or any file using the basic download
    33  * protocol.<p>
    34  *
     35 * protocol.
     36 * </p>
     37 * <p>
    3538 * Resources can be put into download groups by specifying a part
    3639 * name for the resource.  The resource tracker can also be
    3740 * configured to prefetch resources, which are downloaded in the
    38  * order added to the media tracker.<p>
     41 * order added to the media tracker.
     42 * </p>
    3943 *
    4044 * @author <a href="mailto:jmaxwell@users.sourceforge.net">Jon A. Maxwell (JAM)</a> - initial author
     
    110114            Resource resource = new Resource(location, requestVersion, updatePolicy);
    111115
     116            //FIXME - url ignores port during its comparison
     117            //this may affect test-suites
    112118            int index = resources.indexOf(resource);
    113119            if (index >= 0) { // return existing object
     
    225231        }
    226232
    227         if (JNLPRuntime.isDebug())
    228             if (status != orig) {
    229                 System.out.print("Status: " + getStatusString(status));
    230                 if ((status & ~orig) != 0)
    231                     System.out.print(" +(" + getStatusString(status & ~orig) + ")");
    232                 if ((~status & orig) != 0)
    233                     System.out.print(" -(" + getStatusString(~status & orig) + ")");
    234                 System.out.println(" @ " + location.getPath());
     233           if (status != orig) {
     234            OutputController.getLogger().log("Status: " + getStatusString(status));
     235            if ((status & ~orig) != 0) {
     236                OutputController.getLogger().log(" +(" + getStatusString(status & ~orig) + ")");
    235237            }
     238            if ((~status & orig) != 0) {
     239                OutputController.getLogger().log(" -(" + getStatusString(~status & orig) + ")");
     240            }
     241            OutputController.getLogger().log(" @ " + location.getPath());
     242        }
    236243    }
    237244
  • trunk/icedtea-web/netx/net/sourceforge/jnlp/cache/ResourceTracker.java

    r418 r429  
    2525import java.io.InputStream;
    2626import java.io.OutputStream;
    27 import java.io.UnsupportedEncodingException;
    2827import java.net.HttpURLConnection;
     28import java.net.InetAddress;
    2929import java.net.MalformedURLException;
    3030import java.net.URL;
    3131import java.net.URLConnection;
    32 import java.net.URLDecoder;
    33 import java.net.URLEncoder;
     32import java.net.UnknownHostException;
    3433import java.security.AccessController;
    3534import java.security.PrivilegedAction;
    3635import java.util.ArrayList;
     36import java.util.HashMap;
    3737import java.util.List;
     38import java.util.Map;
    3839import java.util.concurrent.ConcurrentHashMap;
    3940import java.util.jar.JarOutputStream;
     
    4748import net.sourceforge.jnlp.event.DownloadListener;
    4849import net.sourceforge.jnlp.runtime.JNLPRuntime;
     50import net.sourceforge.jnlp.util.HttpUtils;
     51import net.sourceforge.jnlp.util.logging.OutputController;
     52import net.sourceforge.jnlp.util.UrlUtils;
    4953import net.sourceforge.jnlp.util.WeakList;
    5054
    5155/**
    5256 * This class tracks the downloading of various resources of a
    53  * JNLP file to local files in the cache.  It can be used to
     57 * JNLP file to local files in the cache. It can be used to
    5458 * download icons, jnlp and extension files, jars, and jardiff
    5559 * files using the version based protocol or any file using the
    5660 * basic download protocol (jardiff and version not implemented
    57  * yet).<p>
    58  *
     61 * yet).
     62 * <p>
    5963 * The resource tracker can be configured to prefetch resources,
    6064 * which are downloaded in the order added to the media
    61  * tracker.<p>
    62  *
     65 * tracker.
     66 * </p>
     67 * <p>
    6368 * Multiple threads are used to download and cache resources that
    6469 * are actively being waited for (blocking a caller) or those that
     
    6873 * This allows the tracker to start downloading many items without
    6974 * using many system resources, but still quickly download items
    70  * as needed.<p>
     75 * as needed.
     76 * </p>
    7177 *
    7278 * @author <a href="mailto:jmaxwell@users.sourceforge.net">Jon A. Maxwell (JAM)</a> - initial author
     
    112118    private static final int STARTED = Resource.STARTED;
    113119
    114     // normalization of url
    115     private static final char PATH_DELIMITER_MARK = '/';
    116     private static final String PATH_DELIMITER = "" + PATH_DELIMITER_MARK;
    117     private static final char QUERY_DELIMITER_MARK = '&';
    118     private static final String QUERY_DELIMITER = "" + QUERY_DELIMITER_MARK;
    119     private static final char QUERY_MARK = '?';
    120     private static final char HREF_MARK = '#';
    121     private static final String UTF8 = "utf-8";
    122 
    123120    /** max threads */
    124121    private static final int maxThreads = 5;
     122   
     123    /** methods used to try individual URLs when choosing best*/
     124    private static final String[] requestMethods = {"HEAD", "GET"};
    125125
    126126    /** running threads */
     
    187187            throw new IllegalResourceDescriptorException("location==null");
    188188        try {
    189             location = normalizeUrl(location, JNLPRuntime.isDebug());
     189            location = UrlUtils.normalizeUrl(location);
    190190        } catch (Exception ex) {
    191             System.err.println("Normalization of " + location.toString() + " have failed");
    192             ex.printStackTrace();
     191            OutputController.getLogger().log(OutputController.Level.ERROR_ALL, "Normalization of " + location.toString() + " have failed");
     192            OutputController.getLogger().log(ex);
    193193        }
    194194        Resource resource = Resource.getResource(location, version, updatePolicy);
     
    243243    /**
    244244     * Check the cache for a resource, and initialize the resource
    245      * as already downloaded if found. <p>
     245     * as already downloaded if found.
    246246     *
    247247     * @param updatePolicy whether to check for updates if already in cache
     
    264264
    265265            if (entry.isCached() && !updatePolicy.shouldUpdate(entry)) {
    266                 if (JNLPRuntime.isDebug())
    267                     System.out.println("not updating: " + resource.location);
     266                OutputController.getLogger().log("not updating: " + resource.location);
    268267
    269268                synchronized (resource) {
     
    291290    /**
    292291     * Adds the listener to the list of objects interested in
    293      * receivind DownloadEvents.<p>
     292     * receivind DownloadEvents.
    294293     *
    295294     * @param listener the listener to add.
     
    345344     * Returns a URL pointing to the cached location of the
    346345     * resource, or the resource itself if it is a non-cacheable
    347      * resource.<p>
    348      *
     346     * resource.
     347     * <p>
    349348     * If the resource has not downloaded yet, the method will block
    350      * until it has been transferred to the cache.<p>
     349     * until it has been transferred to the cache.
     350     * </p>
    351351     *
    352352     * @param location the resource location
     
    362362                return f.toURL();
    363363        } catch (MalformedURLException ex) {
    364             if (JNLPRuntime.isDebug())
    365                 ex.printStackTrace();
     364            OutputController.getLogger().log(ex);
    366365        }
    367366
     
    372371     * Returns a file containing the downloaded resource.  If the
    373372     * resource is non-cacheable then null is returned unless the
    374      * resource is a local file (the original file is returned).<p>
    375      *
     373     * resource is a local file (the original file is returned).
     374     * <p>
    376375     * If the resource has not downloaded yet, the method will block
    377      * until it has been transferred to the cache.<p>
     376     * until it has been transferred to the cache.
     377     * </p>
    378378     *
    379379     * @param location the resource location
     
    395395
    396396            if (location.getProtocol().equalsIgnoreCase("file")) {
    397                 File file = new File(location.getFile());
     397                File file = UrlUtils.decodeUrlAsFile(location);
    398398                if (file.exists())
    399399                    return file;
     
    402402            return null;
    403403        } catch (InterruptedException ex) {
    404             if (JNLPRuntime.isDebug())
    405                 ex.printStackTrace();
    406 
     404            OutputController.getLogger().log(ex);
    407405            return null; // need an error exception to throw
    408406        }
    409407    }
    410408
    411     /**
    412      * Returns an input stream that reads the contents of the
    413      * resource.  For non-cacheable resources, an InputStream that
    414      * reads from the source location is returned.  Otherwise the
    415      * InputStream reads the cached resource.<p>
    416      *
    417      * This method will block while the resource is downloaded to
    418      * the cache.
    419      *
    420      * @throws IOException if there was an error opening the stream
    421      * @throws IllegalResourceDescriptorException if the resource is not being tracked
    422      */
    423     public InputStream getInputStream(URL location) throws IOException {
    424         try {
    425             Resource resource = getResource(location);
    426             if (!resource.isSet(DOWNLOADED | ERROR))
    427                 waitForResource(location, 0);
    428 
    429             if (resource.localFile != null)
    430                 return new FileInputStream(resource.localFile);
    431 
    432             return resource.location.openStream();
    433         } catch (InterruptedException ex) {
    434             throw new IOException("wait was interrupted");
    435         }
    436     }
     409
    437410
    438411    /**
     
    559532    /**
    560533     * Start a new download thread if there are not too many threads
    561      * already running.<p>
    562      *
     534     * already running.
     535     * <p>
    563536     * Calls to this method should be synchronized on lock.
     537     * </p>
    564538     */
    565539    protected void startThread() {
     
    567541            threads++;
    568542
    569             Thread thread = new Thread(new Downloader());
     543            Thread thread = new Thread(new Downloader(), "DownloaderThread" + threads);
    570544            thread.start();
    571545        }
     
    573547
    574548    /**
    575      * A thread is ending, called by the thread itself.<p>
    576      *
     549     * A thread is ending, called by the thread itself.
     550     * <p>
    577551     * Calls to this method should be synchronized.
     552     * </p>
    578553     */
    579554    private void endThread() {
     
    670645            String contentEncoding = con.getContentEncoding();
    671646
    672             if (JNLPRuntime.isDebug()) {
    673                 System.err.println("Downloading" + resource.location + " using " +
     647            OutputController.getLogger().log(OutputController.Level.ERROR_DEBUG, "Downloading" + resource.location + " using " +
    674648                        realLocation + " (encoding : " + contentEncoding + ")");
    675 
    676             }
    677649
    678650            boolean packgz = "pack200-gzip".equals(contentEncoding) ||
     
    765737            resource.fireDownloadEvent(); // fire DOWNLOADED
    766738        } catch (Exception ex) {
    767             if (JNLPRuntime.isDebug())
    768                 ex.printStackTrace();
    769 
     739            OutputController.getLogger().log(ex);
    770740            resource.changeStatus(0, ERROR);
    771741            synchronized (lock) {
     
    783753     */
    784754    private void initializeResource(Resource resource) {
     755        //verify connection
     756        if(!JNLPRuntime.isOfflineForced()){
     757            JNLPRuntime.detectOnline(resource.getLocation()/*or doenloadLocation*/);
     758        }
    785759        resource.fireDownloadEvent(); // fire CONNECTING
    786760
     
    790764        try {
    791765            File localFile = CacheUtil.getCacheFile(resource.location, resource.downloadVersion);
    792 
    793             // connect
    794             URL finalLocation = findBestUrl(resource);
    795             resource.setDownloadLocation(finalLocation);
    796             URLConnection connection = finalLocation.openConnection(); // this won't change so should be okay unsynchronized
    797             connection.addRequestProperty("Accept-Encoding", "pack200-gzip, gzip");
    798 
    799             int size = connection.getContentLength();
    800             boolean current = CacheUtil.isCurrent(resource.location, resource.requestVersion, connection) && resource.getUpdatePolicy() != UpdatePolicy.FORCE;
    801             if (!current) {
    802                 if (entry.isCached()) {
    803                     entry.markForDelete();
    804                     entry.store();
    805                     // Old entry will still exist. (but removed at cleanup)
    806                     localFile = CacheUtil.makeNewCacheFile(resource.location, resource.downloadVersion);
    807                     CacheEntry newEntry = new CacheEntry(resource.location, resource.requestVersion);
    808                     newEntry.lock();
    809                     entry.unlock();
    810                     entry = newEntry;
     766            long size = 0;
     767            boolean current = true;
     768            //this can be null, as it is always filled in online mode, and never read in offline mode
     769            URLConnection connection = null;
     770            if (localFile != null) {
     771                size = localFile.length();
     772            } else if (!JNLPRuntime.isOnline()) {
     773                OutputController.getLogger().log(OutputController.Level.ERROR_ALL, "You are trying to get resource " + resource.getLocation().toExternalForm() + " but you are in offline mode, and it is not in cache. Attempting to continue, but you may expect failure");
     774            }
     775            if (JNLPRuntime.isOnline()) {
     776                // connect
     777                URL finalLocation = findBestUrl(resource);
     778
     779                if (finalLocation == null) {
     780                    OutputController.getLogger().log(OutputController.Level.ERROR_ALL, "Attempted to download " + resource.location + ", but failed to connect!");
     781                    throw new NullPointerException("finalLocation == null"); // Caught below
     782                }
     783
     784                resource.setDownloadLocation(finalLocation);
     785                connection = finalLocation.openConnection(); // this won't change so should be okay unsynchronized
     786                connection.addRequestProperty("Accept-Encoding", "pack200-gzip, gzip");
     787
     788                size = connection.getContentLength();
     789                current = CacheUtil.isCurrent(resource.location, resource.requestVersion, connection) && resource.getUpdatePolicy() != UpdatePolicy.FORCE;
     790                if (!current) {
     791                    if (entry.isCached()) {
     792                        entry.markForDelete();
     793                        entry.store();
     794                        // Old entry will still exist. (but removed at cleanup)
     795                        localFile = CacheUtil.makeNewCacheFile(resource.location, resource.downloadVersion);
     796                        CacheEntry newEntry = new CacheEntry(resource.location, resource.requestVersion);
     797                        newEntry.lock();
     798                        entry.unlock();
     799                        entry = newEntry;
     800                    }
    811801                }
    812802            }
     
    824814
    825815            // update cache entry
    826             if (!current)
     816            if (!current && JNLPRuntime.isOnline())
    827817                entry.initialize(connection);
    828818
     
    839829                ((HttpURLConnection) connection).disconnect();
    840830        } catch (Exception ex) {
    841             if (JNLPRuntime.isDebug())
    842                 ex.printStackTrace();
    843 
     831            OutputController.getLogger().log(ex);
    844832            resource.changeStatus(0, ERROR);
    845833            synchronized (lock) {
     
    851839        }
    852840    }
    853 
    854     /**
    855      * Returns the best URL to use for downloading the resource
     841    /**
     842     * testing wrapper
     843     *
     844     * @param url
     845     * @param requestProperties
     846     * @param requestMethod
     847     * @return
     848     * @throws IOException
     849     */
     850    static int getUrlResponseCode(URL url, Map<String, String> requestProperties, String requestMethod) throws IOException {
     851        return getUrlResponseCodeWithRedirectonResult(url, requestProperties, requestMethod).result;
     852    }
     853
     854    private static class CodeWithRedirect {
     855
     856        int result = HttpURLConnection.HTTP_OK;
     857        URL URL;
     858
     859        public boolean shouldRedirect() {
     860            return (result == 301
     861                    || result == 302
     862                    || result == 303/*?*/
     863                    || result == 307
     864                    || result == 308);
     865        }
     866
     867        public boolean isInvalid() {
     868            return (result < 200 || result >= 300);
     869        }
     870    }
     871
     872    /**
     873     * Connects to the given URL, and grabs a response code and redirecton if
     874     * the URL uses the HTTP protocol, or returns an arbitrary valid HTTP
     875     * response code.
     876     *
     877     * @return the response code if HTTP connection and redirection value, or
     878     * HttpURLConnection.HTTP_OK and null if not.
     879     * @throws IOException
     880     */
     881    static CodeWithRedirect getUrlResponseCodeWithRedirectonResult(URL url, Map<String, String> requestProperties, String requestMethod) throws IOException {
     882        CodeWithRedirect result = new CodeWithRedirect();
     883        URLConnection connection = url.openConnection();
     884
     885        for (Map.Entry<String, String> property : requestProperties.entrySet()) {
     886            connection.addRequestProperty(property.getKey(), property.getValue());
     887        }
     888
     889        if (connection instanceof HttpURLConnection) {
     890            HttpURLConnection httpConnection = (HttpURLConnection) connection;
     891            httpConnection.setRequestMethod(requestMethod);
     892
     893            int responseCode = httpConnection.getResponseCode();
     894
     895            /* Fully consuming current request helps with connection re-use
     896             * See http://docs.oracle.com/javase/1.5.0/docs/guide/net/http-keepalive.html */
     897            HttpUtils.consumeAndCloseConnectionSilently(httpConnection);
     898
     899            result.result = responseCode;
     900        }
     901
     902        Map<String, List<String>> header = connection.getHeaderFields();
     903        for (Map.Entry<String, List<String>> entry : header.entrySet()) {
     904            OutputController.getLogger().log("Key : " + entry.getKey() + " ,Value : " + entry.getValue());
     905        }
     906        /*
     907         * Do this only on 301,302,303(?)307,308>
     908         * Now setting value for all, and lets upper stack to handle it
     909         */
     910        String possibleRedirect = connection.getHeaderField("Location");
     911        if (possibleRedirect != null && possibleRedirect.trim().length() > 0) {
     912            result.URL = new URL(possibleRedirect);
     913        }
     914
     915        return result;
     916
     917    }
     918
     919
     920    /**
     921     * Returns the 'best' valid URL for the given resource.
     922     * This first adjusts the file name to take into account file versioning
     923     * and packing, if possible.
    856924     *
    857925     * @param resource the resource
    858      * @return a URL or null
    859      */
    860     private URL findBestUrl(Resource resource) {
     926     * @return the best URL, or null if all failed to resolve
     927     */
     928    URL findBestUrl(Resource resource) {
    861929        DownloadOptions options = downloadOptions.get(resource);
    862930        if (options == null) {
     
    865933
    866934        List<URL> urls = new ResourceUrlCreator(resource, options).getUrls();
    867         if (JNLPRuntime.isDebug()) {
    868             System.err.println("All possible urls for " +
    869                     resource.toString() + " : " + urls);
    870         }
    871         URL bestUrl = null;
    872         for (URL url : urls) {
    873             try {
    874                 URLConnection connection = url.openConnection();
    875                 connection.addRequestProperty("Accept-Encoding", "pack200-gzip, gzip");
    876                 if (connection instanceof HttpURLConnection) {
    877                     HttpURLConnection con = (HttpURLConnection)connection;
    878                     int responseCode = con.getResponseCode();
    879                     if (responseCode == -1 || responseCode < 200 || responseCode >= 300) {
    880                         continue;
    881                     }
    882                 }
    883                 if (JNLPRuntime.isDebug()) {
    884                     System.err.println("best url for " + resource.toString() + " is " + url.toString());
    885                 }
    886                 bestUrl = url;
    887                 break;
    888             } catch (IOException e) {
    889                 // continue
    890             }
    891         }
    892 
    893         return bestUrl;
    894     }
    895 
    896     /**
    897      * Pick the next resource to download or initialize.  If there
     935         OutputController.getLogger().log(OutputController.Level.ERROR_DEBUG, "All possible urls for "
     936                 + resource.toString() + " : " + urls);
     937       
     938         for (String requestMethod : requestMethods) {
     939             for (int i = 0; i < urls.size(); i++) {
     940                 URL url = urls.get(i);
     941                 try {
     942                     Map<String, String> requestProperties = new HashMap<String, String>();
     943                     requestProperties.put("Accept-Encoding", "pack200-gzip, gzip");
     944
     945                     CodeWithRedirect response = getUrlResponseCodeWithRedirectonResult(url, requestProperties, requestMethod);
     946                     if (response.shouldRedirect()){
     947                         if (response.URL == null) {
     948                             OutputController.getLogger().log(OutputController.Level.ERROR_DEBUG, "Although " + resource.toString() + " got redirect " + response.result + " code for " + requestMethod + " request for " + url.toExternalForm() + " the target was null. Not following");
     949                         } else {
     950                             OutputController.getLogger().log(OutputController.Level.MESSAGE_DEBUG, "Resource " + resource.toString() + " got redirect " + response.result + " code for " + requestMethod + " request for " + url.toExternalForm() + " adding " + response.URL.toExternalForm()+" to list of possible urls");
     951                             if (!JNLPRuntime.isAllowRedirect()){
     952                                 throw new RedirectionException("The resource " + url.toExternalForm() + " is being redirected (" + response.result + ") to " + response.URL.toExternalForm() + ". This is disabled by default. If you wont to allow it, run javaws with -allowredirect parameter.");
     953                             }
     954                             urls.add(response.URL);
     955                         }
     956                     } else if (response.isInvalid()) {
     957                         OutputController.getLogger().log(OutputController.Level.ERROR_DEBUG, "For " + resource.toString() + " the server returned " + response.result + " code for " + requestMethod + " request for " + url.toExternalForm());
     958                     } else {
     959                         OutputController.getLogger().log(OutputController.Level.ERROR_DEBUG, "best url for " + resource.toString() + " is " + url.toString() + " by " + requestMethod);
     960                         return url; /* This is the best URL */
     961                     }
     962                 } catch (IOException e) {
     963                     // continue to next candidate
     964                     OutputController.getLogger().log(OutputController.Level.ERROR_DEBUG, "While processing " + url.toString() + " by " + requestMethod + " for resource " + resource.toString() + " got " + e + ": ");
     965                     OutputController.getLogger().log(e);
     966                 }
     967             }
     968         }
     969
     970        /* No valid URL, return null */
     971        return null;
     972    }
     973
     974    /**
     975     * Pick the next resource to download or initialize. If there
    898976     * are no more resources requested then one is taken from a
    899      * resource tracker with prefetch enabled.<p>
    900      *
     977     * resource tracker with prefetch enabled.
     978     * <p>
    901979     * The resource state is advanced before it is returned
    902      * (CONNECT-&gt;CONNECTING).<p>
    903      *
    904      * Calls to this method should be synchronized on lock.<p>
    905      *
    906      * @return the resource to initialize or download, or null
     980     * (CONNECT-&gt;CONNECTING).
     981     * </p>
     982     * <p>
     983     * Calls to this method should be synchronized on lock.
     984     * </p>
     985     *
     986     * @return the resource to initialize or download, or {@code null}
    907987     */
    908988    private static Resource selectNextResource() {
     
    9421022    /**
    9431023     * Returns the next resource to be prefetched before
    944      * requested.<p>
    945      *
    946      * Calls to this method should be synchronized on lock.<p>
     1024     * requested.
     1025     * <p>
     1026     * Calls to this method should be synchronized on lock.
     1027     * </p>
    9471028     */
    9481029    private static Resource getPrefetch() {
     
    9901071    /**
    9911072     * Selects a resource from the source list that has the
    992      * specified flag set.<p>
    993      *
     1073     * specified flag set.
     1074     * <p>
    9941075     * Calls to this method should be synchronized on lock and
    995      * source list.<p>
     1076     * source list.
     1077     * </p>
    9961078     */
    9971079    private static Resource selectByFlag(List<Resource> source, int flag,
     
    10481130     *
    10491131     * @param resources the resources to wait for
    1050      * @param timeout the timeout, or 0 to wait until completed
    1051      * @returns true if the resources were downloaded or had errors,
    1052      * false if the timeout was reached
     1132     * @param timeout the timeout, or {@code 0} to wait until completed
     1133     * @return {@code true} if the resources were downloaded or had errors,
     1134     * {@code false} if the timeout was reached
    10531135     * @throws InterruptedException if another thread interrupted the wait
    10541136     */
    1055     private boolean wait(Resource resources[], long timeout) throws InterruptedException {
     1137    private boolean wait(Resource[] resources, long timeout) throws InterruptedException {
    10561138        long startTime = System.currentTimeMillis();
    10571139
     
    10941176    }
    10951177
     1178    private static class RedirectionException extends RuntimeException {
     1179
     1180        public RedirectionException(String string) {
     1181            super(string);
     1182        }
     1183
     1184        public RedirectionException(Throwable cause) {
     1185            super(cause);
     1186        }
     1187       
     1188    }
     1189
    10961190    // inner classes
    10971191
     
    11351229
    11361230                } catch (Exception ex) {
    1137                     if (JNLPRuntime.isDebug())
    1138                         ex.printStackTrace();
     1231                    OutputController.getLogger().log(ex);
    11391232                }
    11401233            }
     
    11431236        }
    11441237    };
    1145 
    1146     private static String normalizeChunk(String base, boolean debug) throws UnsupportedEncodingException {
    1147         if (base == null) {
    1148             return base;
    1149         }
    1150         if ("".equals(base)) {
    1151             return base;
    1152         }
    1153         String result = base;
    1154         String ssE = URLDecoder.decode(base, UTF8);
    1155         //            System.out.println("*" + base + "*");
    1156         //            System.out.println("-" + ssE + "-");
    1157         if (base.equals(ssE)) {
    1158             result = URLEncoder.encode(base, UTF8);
    1159             if (debug) {
    1160                 System.out.println(base + " chunk needs to be encoded => " + result);
    1161             }
    1162         } else {
    1163             if (debug) {
    1164                 System.out.println(base + " chunk already encoded");
    1165             }
    1166         }
    1167         return result;
    1168     }
    1169 
    1170     public static URL normalizeUrl(URL u, boolean debug) throws MalformedURLException, UnsupportedEncodingException {
    1171         if (u == null) {
    1172             return null;
    1173         }
    1174         String protocol = u.getProtocol();
    1175         if (protocol == null || "file".equals(protocol)) {
    1176             return u;
    1177         }
    1178         String file = u.getPath();
    1179         if (file == null) {
    1180             return u;
    1181         }
    1182         String host = u.getHost();
    1183         String ref = u.getRef();
    1184         int port = u.getPort();
    1185         String query = u.getQuery();
    1186         String[] qq = {};
    1187         if (query != null) {
    1188             qq = query.split(QUERY_DELIMITER);
    1189         }
    1190         String[] ss = file.split(PATH_DELIMITER);
    1191         int normalized = 0;
    1192         if (debug) {
    1193             System.out.println("normalizing path " + file + " in " + u.toString());
    1194         }
    1195         for (int i = 0; i < ss.length; i++) {
    1196             String base = ss[i];
    1197             String r = normalizeChunk(base, debug);
    1198             if (!r.equals(ss[i])) {
    1199                 normalized++;
    1200             }
    1201             ss[i] = r;
    1202         }
    1203         if (debug) {
    1204             System.out.println("normalizing query " + query + " in " + u.toString());
    1205         }
    1206         for (int i = 0; i < qq.length; i++) {
    1207             String base = qq[i];
    1208             String r = normalizeChunk(base, debug);
    1209             if (!r.equals(qq[i])) {
    1210                 normalized++;
    1211             }
    1212             qq[i] = r;
    1213         }
    1214         if (normalized == 0) {
    1215             if (debug) {
    1216                 System.out.println("Nothing was normalized in this url");
    1217             }
    1218             return u;
    1219         } else {
    1220             if (debug) {
    1221                 System.out.println(normalized + " chunks normalized, rejoining url");
    1222             }
    1223         }
    1224         StringBuilder composed = new StringBuilder("");
    1225         for (int i = 0; i < ss.length; i++) {
    1226             String string = ss[i];
    1227             if (ss.length <= 1 || (string != null && !"".equals(string))) {
    1228                 composed.append(PATH_DELIMITER_MARK).append(string);
    1229             }
    1230         }
    1231         String composed1 = composed.toString();
    1232         if (query != null && !query.trim().equals("")) {
    1233             composed.append(QUERY_MARK);
    1234             for (int i = 0; i < qq.length; i++) {
    1235                 String string = qq[i];
    1236                 if ((string != null && !"".equals(string))) {
    1237                     composed.append(string);
    1238                     if (i != qq.length - 1) {
    1239                         composed.append(QUERY_DELIMITER_MARK);
    1240                     }
    1241                 }
    1242             }
    1243         }
    1244         String composed2 = composed.substring(composed1.length() - 1);
    1245         if (ref != null && !ref.trim().equals("")) {
    1246             composed.append(HREF_MARK).append(ref);
    1247         }
    1248 
    1249         URL result = new URL(protocol, host, port, composed.toString());
    1250 
    1251         if (debug) {
    1252             System.out.println("normalized `" + composed1 + "` and `" + composed2 + "` in " + result.toString());
    1253         }
    1254         return result;
    1255 
    1256     }
    12571238}
  • trunk/icedtea-web/netx/net/sourceforge/jnlp/cache/ResourceUrlCreator.java

    r348 r429  
    3939
    4040import java.net.MalformedURLException;
     41import java.net.URI;
     42import java.net.URISyntaxException;
    4143import java.net.URL;
     44import java.net.URLDecoder;
     45import java.net.URLEncoder;
    4246import java.util.LinkedList;
    4347import java.util.List;
     48import java.io.UnsupportedEncodingException;
    4449
    4550import net.sourceforge.jnlp.DownloadOptions;
     
    5964     * The Resources may not be downloadable from any of them. The returned order is the order
    6065     * the urls should be attempted in.
    61      * @return
     66     * @return a list of URLs that the resources might be downloadable from
    6267     */
    6368    public List<URL> getUrls() {
     
    9095        }
    9196
    92         url = getVersionedUrlUsingQuery(resource);
     97        url = getVersionedUrl();
    9398        urls.add(url);
    9499
     
    103108     * @param usePack whether the URL should point to the pack200 file
    104109     * @param useVersion whether the URL should be modified to include the version
    105      * @return a URL for the resource or null if an appropraite URL can not be found
     110     * @return a URL for the resource or null if an appropriate URL can not be found
    106111     */
    107     protected URL getUrl(Resource resource, boolean usePack, boolean useVersion) {
     112    static URL getUrl(Resource resource, boolean usePack, boolean useVersion) {
    108113        if (!(usePack || useVersion)) {
    109114            throw new IllegalArgumentException("either pack200 or version required");
     
    117122        String filename = location.substring(lastSlash + 1);
    118123        if (useVersion && resource.requestVersion != null) {
    119             String parts[] = filename.split("\\.", 2);
    120             String name = parts[0];
    121             String extension = parts[1];
    122             filename = name + "__V" + resource.requestVersion + "." + extension;
     124            // With 'useVersion', j2-commons-cli.jar becomes, for example, j2-commons-cli__V1.0.jar
     125            String parts[] = filename.split("\\.", -1 /* Keep blank strings*/);
     126
     127            StringBuilder sb = new StringBuilder();
     128            for (int i = 0; i < parts.length; i++) {
     129                sb.append(parts[i]);
     130                // Append __V<number> before last '.'
     131                if (i == parts.length -2) {
     132                    sb.append("__V" + resource.requestVersion);
     133                }
     134                sb.append('.');
     135            }
     136            sb.setLength(sb.length() - 1); // remove last '.'
     137
     138            filename = sb.toString();
    123139        }
    124140        if (usePack) {
     
    136152
    137153    /**
    138      * Returns the URL for a resource, relying on HTTP query for getting the
    139      * right version
    140      *
    141      * @param resource the resource to get the url for
     154     * Returns the URL for this resource, including the resource's version number in the query string
    142155     */
    143     protected URL getVersionedUrlUsingQuery(Resource resource) {
    144         String actualLocation = resource.getLocation().getProtocol() + "://"
    145                 + resource.getLocation().getHost();
    146         if (resource.getLocation().getPort() != -1) {
    147             actualLocation += ":" + resource.getLocation().getPort();
     156    protected URL getVersionedUrl() {
     157        URL resourceUrl = resource.getLocation();
     158        String protocol = uriPartToString(resourceUrl.getProtocol()) + "://";
     159        String userInfo = uriPartToString(resourceUrl.getUserInfo());
     160        if (!userInfo.isEmpty()) {
     161            userInfo += "@";
    148162        }
    149         actualLocation += resource.getLocation().getPath();
    150         if (resource.requestVersion != null
    151                 && resource.requestVersion.isVersionId()) {
    152             actualLocation += "?version-id=" + resource.requestVersion;
     163        String host = uriPartToString(resourceUrl.getHost());
     164        String port;
     165        if (resourceUrl.getPort() == -1) {
     166            port = "";
     167        } else {
     168            port = ":" + String.valueOf(resourceUrl.getPort());
    153169        }
    154         URL versionedURL;
     170        String path = uriPartToString(resourceUrl.getPath());
     171        String query = uriPartToString(resourceUrl.getQuery());
     172        if (!query.isEmpty()) {
     173            query = "?" + query;
     174        }
     175        if (resource.requestVersion != null && resource.requestVersion.isVersionId()) {
     176            if (!query.isEmpty()) {
     177                query += "&";
     178            } else {
     179                query = "?" + query;
     180            }
     181            query += "version-id=" + resource.requestVersion;
     182        }
    155183        try {
    156             versionedURL = new URL(actualLocation);
     184            URL url = new URL(protocol + userInfo + host + port + path + query);
     185            return url;
    157186        } catch (MalformedURLException e) {
    158             return resource.getLocation();
     187            return resourceUrl;
    159188        }
    160         return versionedURL;
     189    }
     190
     191    private static String uriPartToString(String part) {
     192        if (part == null)
     193            return "";
     194        return part;
    161195    }
    162196
  • trunk/icedtea-web/netx/net/sourceforge/jnlp/cache/UpdatePolicy.java

    r348 r429  
    1919/**
    2020 * A policy that determines when a resource should be checked for
    21  * an updated version.<p>
     21 * an updated version.
    2222 *
    2323 * @author <a href="mailto:jmaxwell@users.sourceforge.net">Jon A. Maxwell (JAM)</a> - initial author
  • trunk/icedtea-web/netx/net/sourceforge/jnlp/config/BasicValueValidators.java

    r372 r429  
    3838package net.sourceforge.jnlp.config;
    3939
     40import java.io.File;
    4041import static net.sourceforge.jnlp.runtime.Translator.R;
    4142
     
    8889     * file may or may not exist
    8990     */
    90     private static class FilePathValidator implements ValueValidator {
    91 
     91    //package private for testing purposes
     92    static class FilePathValidator implements ValueValidator {
     93       
    9294        @Override
    9395        public void validate(Object value) throws IllegalArgumentException {
     
    99101
    100102            if (!(possibleValue instanceof String)) {
    101                 throw new IllegalArgumentException();
     103                throw new IllegalArgumentException("Value should be string!");
    102104            }
    103105
    104106            String possibleFile = (String) possibleValue;
    105             if (Defaults.OS_DOS_LIKE) {
    106                 if (!(Character.isLetter(possibleFile.charAt(0)) &&
    107                       possibleFile.charAt(1) == ':' &&
    108                       (possibleFile.charAt(2) == File.separatorChar ||
    109                        possibleFile.charAt(2) == '/'))) {
    110                     throw new IllegalArgumentException();
    111                 }
    112             }
    113             else
    114             if (!(possibleFile.startsWith("/"))) {
    115                 throw new IllegalArgumentException();
    116             }
    117 
    118         }
    119 
    120         @Override
    121         public String getPossibleValues() {
    122             return Defaults.OS_DOS_LIKE ? R("VVPossibleFileValuesDOS") : R("VVPossibleFileValues");
     107           
     108                boolean absolute = new File(possibleFile).isAbsolute();
     109                if (!absolute) {
     110                    throw new IllegalArgumentException("File must be absolute");
     111                }
     112
     113        }
     114
     115        @Override
     116        public String getPossibleValues() {
     117            return R("VVPossibleFileValues");
    123118        }
    124119
  • trunk/icedtea-web/netx/net/sourceforge/jnlp/config/Defaults.java

    r397 r429  
    4343import java.util.HashMap;
    4444import java.util.Map;
     45import net.sourceforge.jnlp.security.appletextendedsecurity.AppletSecurityLevel;
    4546
    4647import net.sourceforge.jnlp.ShortcutDesc;
     
    5152 */
    5253public class Defaults {
     54   
     55    final static String SYSTEM_HOME = System.getProperty("java.home");
     56    final static String SYSTEM_SECURITY = SYSTEM_HOME + File.separator + "lib" + File.separator + "security";
     57    final static String USER_CONFIG_HOME;
     58    public final static String USER_CACHE_HOME;
     59    final static String USER_SECURITY;
     60    final static String LOCKS_DIR = System.getProperty("java.io.tmpdir") + File.separator
     61            + System.getProperty("user.name") + File.separator + "netx" + File.separator
     62            + "locks";
     63    final static File userFile;
     64
     65    static {
     66        String configHome = System.getProperty("user.home") + File.separator + DeploymentConfiguration.DEPLOYMENT_CONFIG_DIR;
     67        String cacheHome = System.getProperty("user.home") + File.separator + DeploymentConfiguration.DEPLOYMENT_CACHE_DIR;
     68        String XDG_CONFIG_HOME = System.getenv("XDG_CONFIG_HOME");
     69        String XDG_CACHE_HOME = System.getenv("XDG_CACHE_HOME");
     70        if (XDG_CONFIG_HOME != null) {
     71            configHome = XDG_CONFIG_HOME + File.separator + DeploymentConfiguration.DEPLOYMENT_SUBDIR_DIR;
     72        }
     73        if (XDG_CACHE_HOME != null) {
     74            cacheHome = XDG_CACHE_HOME + File.separator + DeploymentConfiguration.DEPLOYMENT_SUBDIR_DIR;
     75        }
     76        USER_CONFIG_HOME = configHome;
     77        USER_CACHE_HOME = cacheHome;
     78        USER_SECURITY = USER_CONFIG_HOME + File.separator + "security";
     79        userFile = new File(USER_CONFIG_HOME + File.separator + DeploymentConfiguration.DEPLOYMENT_PROPERTIES);
     80    }
    5381
    5482    /**
     
    6391     */
    6492    public static Map<String, Setting<String>> getDefaults() {
    65         File userFile = new File(System.getProperty("user.home") + File.separator + DeploymentConfiguration.DEPLOYMENT_DIR
    66                 + File.separator + DeploymentConfiguration.DEPLOYMENT_PROPERTIES);
    67 
    6893        SecurityManager sm = System.getSecurityManager();
    6994        if (sm != null) {
     
    7196        }
    7297
    73         final String SYSTEM_HOME = System.getProperty("java.home");
    74         final String SYSTEM_SECURITY = SYSTEM_HOME + File.separator + "lib" + File.separator + "security";
    75 
    76         final String USER_HOME = System.getProperty("user.home") + File.separator + DeploymentConfiguration.DEPLOYMENT_DIR;
    77         final String USER_SECURITY = USER_HOME + File.separator + "security";
    78 
    79         final String LOCKS_DIR = System.getProperty("java.io.tmpdir") + File.separator
    80                 + System.getProperty("user.name") + File.separator + "netx" + File.separator
    81                 + "locks";
    8298
    8399        /*
     
    97113                        DeploymentConfiguration.KEY_USER_CACHE_DIR,
    98114                        BasicValueValidators.getFilePathValidator(),
    99                         USER_HOME + File.separator + "cache"
     115                        USER_CACHE_HOME + File.separator + "cache"
    100116                },
    101117                {
    102118                        DeploymentConfiguration.KEY_USER_PERSISTENCE_CACHE_DIR,
    103119                        BasicValueValidators.getFilePathValidator(),
    104                         USER_HOME + File.separator + "pcache"
     120                        USER_CACHE_HOME + File.separator + "pcache"
    105121                },
    106122                {
     
    112128                        DeploymentConfiguration.KEY_USER_LOG_DIR,
    113129                        BasicValueValidators.getFilePathValidator(),
    114                         USER_HOME + File.separator + "log"
     130                        USER_CONFIG_HOME + File.separator + "log"
    115131                },
    116132                {
    117133                        DeploymentConfiguration.KEY_USER_TMP_DIR,
    118134                        BasicValueValidators.getFilePathValidator(),
    119                         USER_HOME + File.separator + "tmp"
     135                        USER_CACHE_HOME + File.separator + "tmp"
    120136                },
    121137                {
     
    329345                                DeploymentConfiguration.CONSOLE_DISABLE,
    330346                                DeploymentConfiguration.CONSOLE_HIDE,
    331                                 DeploymentConfiguration.CONSOLE_SHOW
     347                                DeploymentConfiguration.CONSOLE_SHOW,
     348                                DeploymentConfiguration.CONSOLE_SHOW_PLUGIN,
     349                                DeploymentConfiguration.CONSOLE_SHOW_JAVAWS
    332350                        }),
    333351                        DeploymentConfiguration.CONSOLE_HIDE
    334352                },
    335                 /* tracing and logging */
    336                 {
    337                         DeploymentConfiguration.KEY_ENABLE_TRACING,
    338                         BasicValueValidators.getBooleanValidator(),
    339                         String.valueOf(false)
    340                 },
    341353                {
    342354                        DeploymentConfiguration.KEY_ENABLE_LOGGING,
    343355                        BasicValueValidators.getBooleanValidator(),
    344356                        String.valueOf(false)
     357                },
     358                {
     359                        DeploymentConfiguration.KEY_ENABLE_LOGGING_HEADERS,
     360                        BasicValueValidators.getBooleanValidator(),
     361                        String.valueOf(false)
     362                },
     363                {
     364                        DeploymentConfiguration.KEY_ENABLE_LOGGING_TOFILE,
     365                        BasicValueValidators.getBooleanValidator(),
     366                        String.valueOf(false)
     367                },
     368                {
     369                        DeploymentConfiguration.KEY_ENABLE_LOGGING_TOSTREAMS,
     370                        BasicValueValidators.getBooleanValidator(),
     371                        String.valueOf(true)
     372                },               
     373                {
     374                        DeploymentConfiguration.KEY_ENABLE_LOGGING_TOSYSTEMLOG,
     375                        BasicValueValidators.getBooleanValidator(),
     376                        String.valueOf(true)
    345377                },
    346378                /* JNLP association */
     
    386418                        BasicValueValidators.getRangedIntegerValidator(0, 10000),
    387419                        String.valueOf(500)
     420                },
     421                //JVM arguments for plugin
     422                {
     423                        DeploymentConfiguration.KEY_PLUGIN_JVM_ARGUMENTS,
     424                        null,
     425                        null
     426                },
     427               //unsigned applet security level
     428                {
     429                DeploymentConfiguration.KEY_SECURITY_LEVEL,
     430                new SecurityValueValidator(),
     431                null
     432                },
     433                //JVM executable for itw
     434                {
     435                        DeploymentConfiguration.KEY_JRE_DIR,
     436                        null,
     437                        null
     438                },
     439                //enable manifest-attributes checks
     440                {
     441                        DeploymentConfiguration.KEY_ENABLE_MANIFEST_ATTRIBUTES_CHECK,
     442                        BasicValueValidators.getBooleanValidator(),
     443                        String.valueOf(true)
    388444                }
    389445        };
  • trunk/icedtea-web/netx/net/sourceforge/jnlp/config/DeploymentConfiguration.java

    r348 r429  
    3737
    3838import javax.naming.ConfigurationException;
    39 
     39import javax.swing.JOptionPane;
     40
     41import net.sourceforge.jnlp.cache.CacheLRUWrapper;
    4042import net.sourceforge.jnlp.runtime.JNLPRuntime;
    4143import net.sourceforge.jnlp.util.FileUtils;
     44import net.sourceforge.jnlp.util.logging.OutputController;
    4245
    4346/**
     
    4952public final class DeploymentConfiguration {
    5053
    51     public static final String DEPLOYMENT_DIR = ".icedtea";
    52     public static final String DEPLOYMENT_CONFIG = "deployment.config";
     54    public static final String DEPLOYMENT_SUBDIR_DIR = "icedtea-web";
     55    public static final String DEPLOYMENT_CACHE_DIR = ".cache" + File.separator + DEPLOYMENT_SUBDIR_DIR;
     56    public static final String DEPLOYMENT_CONFIG_DIR = ".config" + File.separator + DEPLOYMENT_SUBDIR_DIR;
     57    public static final String DEPLOYMENT_CONFIG_FILE = "deployment.config";
    5358    public static final String DEPLOYMENT_PROPERTIES = "deployment.properties";
     59    public static final String APPLET_TRUST_SETTINGS = ".appletTrustSettings";
    5460
    5561    public static final String DEPLOYMENT_COMMENT = "Netx deployment configuration";
     
    6066    public static final int JNLP_ASSOCIATION_REPLACE_ASK = 3;
    6167
    62     /*
    63      * FIXME these should be moved into JavaConsole, but there is a strange
    64      * dependency in the build system. First all of netx is built. Then the
    65      * plugin is built. So we cannot refer to plugin code in here :(
     68    /**
     69     * when set to as value of KEY_CONSOLE_STARTUP_MODE = "deployment.console.startup.mode",
     70     * then console is not visible by default, but may be shown
    6671     */
    6772    public static final String CONSOLE_HIDE = "HIDE";
     73    /**
     74     * when set to as value of KEY_CONSOLE_STARTUP_MODE = "deployment.console.startup.mode",
     75     * then console show for both javaws and plugin
     76     */
    6877    public static final String CONSOLE_SHOW = "SHOW";
     78    /**
     79     * when set to as value of KEY_CONSOLE_STARTUP_MODE = "deployment.console.startup.mode",
     80     * then console is not visible by default, nop data are passed to it (save memory and cpu) but can not be shown
     81     */
    6982    public static final String CONSOLE_DISABLE = "DISABLE";
     83    /**
     84     * when set to as value of KEY_CONSOLE_STARTUP_MODE = "deployment.console.startup.mode",
     85     * then console show for  plugin
     86     */
     87    public static final String CONSOLE_SHOW_PLUGIN = "SHOW_PLUGIN_ONLY";
     88    /**
     89     * when set to as value of KEY_CONSOLE_STARTUP_MODE = "deployment.console.startup.mode",
     90     * then console show for javaws
     91     */
     92    public static final String CONSOLE_SHOW_JAVAWS = "SHOW_JAVAWS_ONLY";
    7093
    7194    public static final String KEY_USER_CACHE_DIR = "deployment.user.cachedir";
     
    106129    public static final String KEY_SECURITY_PROMPT_USER = "deployment.security.askgrantdialog.show";
    107130
     131    //enum of AppletSecurityLevel in result
     132    public static final String KEY_SECURITY_LEVEL = "deployment.security.level";
     133
    108134    public static final String KEY_SECURITY_TRUSTED_POLICY = "deployment.security.trusted.policy";
    109135
     
    120146     * Networking
    121147     */
     148
     149    /** the proxy type. possible values are {@code JNLPProxySelector.PROXY_TYPE_*} */
    122150    public static final String KEY_PROXY_TYPE = "deployment.proxy.type";
     151
     152    /** Boolean. If true, the http host/port should be used for https and ftp as well */
    123153    public static final String KEY_PROXY_SAME = "deployment.proxy.same";
     154
    124155    public static final String KEY_PROXY_AUTO_CONFIG_URL = "deployment.proxy.auto.config.url";
    125156    public static final String KEY_PROXY_BYPASS_LIST = "deployment.proxy.bypass.list";
     
    136167
    137168    /*
    138      * Tracing and Logging
    139      */
    140     public static final String KEY_ENABLE_TRACING = "deployment.trace";
    141     public static final String KEY_ENABLE_LOGGING = "deployment.log";
    142 
     169     * Logging
     170     */
     171    public static final String KEY_ENABLE_LOGGING = "deployment.log"; //same as verbose or ICEDTEAPLUGIN_DEBUG=true
     172    public static final String KEY_ENABLE_LOGGING_HEADERS = "deployment.log.headers"; //will add header OutputContorll.getHeader To all messages
     173    public static final String KEY_ENABLE_LOGGING_TOFILE = "deployment.log.file";
     174    public static final String KEY_ENABLE_LOGGING_TOSTREAMS = "deployment.log.stdstreams";
     175    public static final String KEY_ENABLE_LOGGING_TOSYSTEMLOG = "deployment.log.system";
     176   
    143177    /*
    144      * Console
     178     * manifest check
     179     */
     180    public static final String KEY_ENABLE_MANIFEST_ATTRIBUTES_CHECK = "deployment.manifest.attributes.check";
     181
     182    /**
     183     * Console initial status.
     184     * One of CONSOLE_* values
     185     * See declaration above:
     186     * CONSOLE_HIDE = "HIDE";
     187     * CONSOLE_SHOW = "SHOW";
     188     * CONSOLE_DISABLE = "DISABLE";
     189     * CONSOLE_SHOW_PLUGIN = "SHOW_PLUGIN_ONLY";
     190     * CONSOLE_SHOW_JAVAWS = "SHOW_JAVAWS_ONLY";
    145191     */
    146192    public static final String KEY_CONSOLE_STARTUP_MODE = "deployment.console.startup.mode";
     193   
     194
    147195
    148196    /*
     
    159207    public static final String KEY_UPDATE_TIMEOUT = "deployment.javaws.update.timeout";
    160208
     209    /*
     210     * JVM arguments for plugin
     211     */
     212    public static final String KEY_PLUGIN_JVM_ARGUMENTS= "deployment.plugin.jvm.arguments";
     213    public static final String KEY_JRE_DIR= "deployment.jre.dir";
     214    private ConfigurationException loadingException = null;
     215
     216    public void setLoadingException(ConfigurationException ex) {
     217        loadingException = ex;
     218    }
     219
     220    public ConfigurationException getLoadingException() {
     221        return loadingException;
     222    }
     223
     224    public void resetToDefaults() {
     225        currentConfiguration = Defaults.getDefaults();
     226    }
     227   
     228
    161229    public enum ConfigType {
    162230        System, User
     
    166234    private boolean systemPropertiesMandatory = false;
    167235
    168     /** The system's deployment.config file */
     236    /** The system's subdirResult deployment.config file */
    169237    private File systemPropertiesFile = null;
    170     /** The user's deployment.config file */
     238    /** The user's subdirResult deployment.config file */
    171239    private File userPropertiesFile = null;
     240   
     241    /*default user file*/
     242    public static final File USER_DEPLOYMENT_PROPERTIES_FILE = new File(Defaults.USER_CONFIG_HOME + File.separator + DEPLOYMENT_PROPERTIES);
    172243
    173244    /** the current deployment properties */
     
    186257     * Generally, it will try to continue and ignore errors it finds (such as file not found).
    187258     *
    188      * @throws DeploymentException if it encounters a fatal error.
     259     * @throws ConfigurationException if it encounters a fatal error.
    189260     */
    190261    public void load() throws ConfigurationException {
     
    192263    }
    193264
     265    public static File getAppletTrustUserSettingsPath() {
     266        return new File(Defaults.USER_CONFIG_HOME + File.separator + APPLET_TRUST_SETTINGS);
     267    }
     268
     269     public static File getAppletTrustGlobalSettingsPath() {
     270       return new File(File.separator + "etc" + File.separator + ".java" + File.separator
     271                + "deployment" + File.separator + APPLET_TRUST_SETTINGS);
     272       
     273    }
     274
    194275    /**
    195276     * Initialize this deployment configuration by reading configuration files.
     
    198279     * @param fixIssues If true, fix issues that are discovered when reading configuration by
    199280     * resorting to the default values
    200      * @throws DeploymentException if it encounters a fatal error.
     281     * @throws ConfigurationException if it encounters a fatal error.
    201282     */
    202283    public void load(boolean fixIssues) throws ConfigurationException {
    203284        // make sure no state leaks if security check fails later on
    204         File userFile = new File(System.getProperty("user.home") + File.separator + DEPLOYMENT_DIR
    205                 + File.separator + DEPLOYMENT_PROPERTIES);
     285        File userFile = new File(USER_DEPLOYMENT_PROPERTIES_FILE.getAbsolutePath());
    206286
    207287        SecurityManager sm = System.getSecurityManager();
     
    210290        }
    211291
     292        File systemConfigFile = findSystemConfigFile();
     293
     294        load(systemConfigFile, userFile, fixIssues);
     295    }
     296
     297    void load(File systemConfigFile, File userFile, boolean fixIssues) throws ConfigurationException {
    212298        Map<String, Setting<String>> initialProperties = Defaults.getDefaults();
    213299
     
    215301
    216302        /*
    217          * First, try to read the system's deployment.config file to find if
     303         * First, try to read the system's subdirResult deployment.config file to find if
    218304         * there is a system-level deployment.poperties file
    219305         */
    220306
    221         File systemConfigFile = findSystemConfigFile();
    222307        if (systemConfigFile != null) {
    223308            if (loadSystemConfiguration(systemConfigFile)) {
    224                 if (JNLPRuntime.isDebug()) {
    225                     System.out.println("System level " + DEPLOYMENT_CONFIG + " is mandatory: " + systemPropertiesMandatory);
    226                 }
     309                OutputController.getLogger().log("System level " + DEPLOYMENT_CONFIG_FILE + " is mandatory: " + systemPropertiesMandatory);
    227310                /* Second, read the System level deployment.properties file */
    228311                systemProperties = loadProperties(ConfigType.System, systemPropertiesFile,
     
    242325
    243326        /*
    244          * Third, read the user's deployment.properties file
     327         * Third, read the user's subdirResult deployment.properties file
    245328         */
    246329        userPropertiesFile = userFile;
     
    258341
    259342    /**
     343     * Copies the current configuration into the target
     344     */
     345    public void copyTo(Properties target) {
     346        Set<String> names = getAllPropertyNames();
     347
     348        for (String name : names) {
     349            String value = getProperty(name);
     350            // for Properties, missing and null are identical
     351            if (value != null) {
     352                target.setProperty(name, value);
     353            }
     354        }
     355    }
     356
     357    /**
    260358     * Get the value for the given key
    261359     *
     
    347445            Setting<String> s = initial.get(key);
    348446            if (!(s.getName().equals(key))) {
    349                 System.out.println(R("DCInternal", "key " + key + " does not match setting name " + s.getName()));
     447                OutputController.getLogger().log(OutputController.Level.MESSAGE_ALL, R("DCInternal", "key " + key + " does not match setting name " + s.getName()));
    350448            } else if (!defaults.containsKey(key)) {
    351                 System.out.println(R("DCUnknownSettingWithName", key));
     449                OutputController.getLogger().log(OutputController.Level.MESSAGE_ALL, R("DCUnknownSettingWithName", key));
    352450            } else {
    353451                ValueValidator checker = defaults.get(key).getValidator();
     
    359457                    checker.validate(s.getValue());
    360458                } catch (IllegalArgumentException e) {
    361                     System.out.println(R("DCIncorrectValue", key, s.getValue(), checker.getPossibleValues()));
     459                    OutputController.getLogger().log(OutputController.Level.MESSAGE_ALL, R("DCIncorrectValue", key, s.getValue(), checker.getPossibleValues()));
    362460                    s.setValue(s.getDefaultValue());
     461                    OutputController.getLogger().log(e);
    363462                }
    364463            }
     
    371470    private File findSystemConfigFile() {
    372471        File etcFile = new File(File.separator + "etc" + File.separator + ".java" + File.separator
    373                 + "deployment" + File.separator + DEPLOYMENT_CONFIG);
     472                + "deployment" + File.separator + DEPLOYMENT_CONFIG_FILE);
    374473        if (etcFile.isFile()) {
    375474            return etcFile;
    376475        }
    377476
    378         File jreFile = new File(System.getProperty("java.home") + File.separator + "lib"
    379                 + File.separator + DEPLOYMENT_CONFIG);
     477        String jrePath = null;
     478        try {
     479            Map<String, Setting<String>> tmpProperties = parsePropertiesFile(USER_DEPLOYMENT_PROPERTIES_FILE);
     480            Setting<String> jreSetting = tmpProperties.get(KEY_JRE_DIR);
     481            if (jreSetting != null) {
     482                jrePath = jreSetting.getValue();
     483            }
     484        } catch (Exception ex) {
     485            OutputController.getLogger().log(ex);
     486        }
     487
     488        File jreFile;
     489        if (jrePath != null) {
     490            jreFile = new File(jrePath + File.separator + "lib"
     491                    + File.separator + DEPLOYMENT_CONFIG_FILE);
     492        } else {
     493            jreFile = new File(System.getProperty("java.home") + File.separator + "lib"
     494                    + File.separator + DEPLOYMENT_CONFIG_FILE);
     495        }
    380496        if (jreFile.isFile()) {
    381497            return jreFile;
     
    389505     * system-properties related variables
    390506     */
    391     private boolean loadSystemConfiguration(File configFile) {
    392 
    393         if (JNLPRuntime.isDebug()) {
    394             System.out.println("Loading system configuation from: " + configFile);
    395         }
     507    private boolean loadSystemConfiguration(File configFile) throws ConfigurationException {
     508
     509        OutputController.getLogger().log("Loading system configuation from: " + configFile);
    396510
    397511        Map<String, Setting<String>> systemConfiguration = new HashMap<String, Setting<String>>();
     
    399513            systemConfiguration = parsePropertiesFile(configFile);
    400514        } catch (IOException e) {
    401             if (JNLPRuntime.isDebug()) {
    402                 System.out.println("No System level " + DEPLOYMENT_PROPERTIES + " found.");
    403             }
     515            OutputController.getLogger().log("No System level " + DEPLOYMENT_CONFIG_FILE + " found.");
     516            OutputController.getLogger().log(e);
    404517            return false;
    405518        }
     
    409522         * completely
    410523         */
    411 
     524        String urlString = null;
    412525        try {
    413             String urlString = systemConfiguration.get("deployment.system.config").getValue();
    414             if (urlString == null) {
    415                 if (JNLPRuntime.isDebug()) {
    416                     System.out.println("No System level " + DEPLOYMENT_PROPERTIES + " found.");
    417                 }
     526            Setting<String> urlSettings = systemConfiguration.get("deployment.system.config");
     527            if (urlSettings == null || urlSettings.getValue() == null) {
     528                OutputController.getLogger().log("No System level " + DEPLOYMENT_PROPERTIES + " found in "+configFile.getAbsolutePath());
    418529                return false;
    419530            }
     531            urlString = urlSettings.getValue();
     532            Setting<String> mandatory = systemConfiguration.get("deployment.system.config.mandatory");
     533            systemPropertiesMandatory = Boolean.valueOf(mandatory == null ? null : mandatory.getValue()); //never null
     534            OutputController.getLogger().log("System level settings " + DEPLOYMENT_PROPERTIES + " are mandatory:" + systemPropertiesMandatory);
    420535            URL url = new URL(urlString);
    421536            if (url.getProtocol().equals("file")) {
    422537                systemPropertiesFile = new File(url.getFile());
    423                 if (JNLPRuntime.isDebug()) {
    424                     System.out.println("Using System level" + DEPLOYMENT_PROPERTIES + ": "
    425                             + systemPropertiesFile);
    426                 }
    427                 Setting<String> mandatory = systemConfiguration.get("deployment.system.config.mandatory");
    428                 systemPropertiesMandatory = Boolean.valueOf(mandatory == null ? null : (String) mandatory.getValue());
     538                OutputController.getLogger().log("Using System level" + DEPLOYMENT_PROPERTIES + ": " + systemPropertiesFile);
    429539                return true;
    430540            } else {
    431                 if (JNLPRuntime.isDebug()) {
    432                     System.out.println("Remote + " + DEPLOYMENT_PROPERTIES + " not supported");
    433                 }
     541                OutputController.getLogger().log("Remote + " + DEPLOYMENT_PROPERTIES + " not supported: " + urlString + "in " + configFile.getAbsolutePath());
    434542                return false;
    435543            }
    436544        } catch (MalformedURLException e) {
    437             if (JNLPRuntime.isDebug()) {
    438                 System.out.println("Invalid url for " + DEPLOYMENT_PROPERTIES);
    439             }
    440             return false;
     545            OutputController.getLogger().log("Invalid url for " + DEPLOYMENT_PROPERTIES+ ": " + urlString + "in " + configFile.getAbsolutePath());
     546            OutputController.getLogger().log(e);
     547            if (systemPropertiesMandatory){
     548                ConfigurationException ce = new ConfigurationException("Invalid url to system properties, which are mandatory");
     549                ce.initCause(e);
     550                throw ce;
     551            } else {
     552                return false;
     553            }
    441554        }
    442555    }
     
    454567            throws ConfigurationException {
    455568        if (file == null || !file.isFile()) {
    456             if (JNLPRuntime.isDebug()) {
    457                 System.out.println("No " + type.toString() + " level " + DEPLOYMENT_PROPERTIES + " found.");
    458             }
     569            OutputController.getLogger().log("No " + type.toString() + " level " + DEPLOYMENT_PROPERTIES + " found.");
    459570            if (!mandatory) {
    460571                return null;
     
    464575        }
    465576
    466         if (JNLPRuntime.isDebug()) {
    467             System.out.println("Loading " + type.toString() + " level properties from: " + file);
    468         }
     577        OutputController.getLogger().log("Loading " + type.toString() + " level properties from: " + file);
    469578        try {
    470579            return parsePropertiesFile(file);
    471580        } catch (IOException e) {
     581            if (mandatory){
     582                ConfigurationException ce = new ConfigurationException("Exception during loading of " + file + " which is mandatory to read");
     583                ce.initCause(e);
     584                throw ce;
     585            }
     586            OutputController.getLogger().log(e);
    472587            return null;
    473588        }
     
    490605        }
    491606
    492         if (JNLPRuntime.isDebug()) {
    493             System.out.println("Saving properties into " + userPropertiesFile.toString());
    494         }
     607        OutputController.getLogger().log("Saving properties into " + userPropertiesFile.toString());
    495608        Properties toSave = new Properties();
    496609
    497610        for (String key : currentConfiguration.keySet()) {
    498611            String oldValue = unchangeableConfiguration.get(key) == null ? null
    499                     : (String) unchangeableConfiguration.get(key).getValue();
    500             String newValue = currentConfiguration.get(key) == null ? null : (String) currentConfiguration
     612                    : unchangeableConfiguration.get(key).getValue();
     613            String newValue = currentConfiguration.get(key) == null ? null : currentConfiguration
    501614                    .get(key).getValue();
    502615            if (oldValue == null && newValue == null) {
     
    533646     *
    534647     * @param propertiesFile the file to read Properties from
    535      * @param destination the map to which all the properties should be added
    536648     * @throws IOException if an IO problem occurs
    537649     */
     
    608720    @SuppressWarnings("unused")
    609721    private static void dumpConfiguration(Map<String, Setting<String>> config, PrintStream out) {
    610         System.out.println("KEY: VALUE [Locked]");
     722        OutputController.getLogger().log(OutputController.Level.MESSAGE_ALL, "KEY: VALUE [Locked]");
    611723
    612724        for (String key : config.keySet()) {
     
    616728        }
    617729    }
     730
     731    public static void move14AndOlderFilesTo15StructureCatched() {
     732        try {
     733            move14AndOlderFilesTo15Structure();
     734        } catch (Throwable t) {
     735            OutputController.getLogger().log(OutputController.Level.ERROR_DEBUG, "Critical error during converting old files to new. Continuing");
     736            OutputController.getLogger().log(t);
     737        }
     738
     739    }
     740
     741    private static void move14AndOlderFilesTo15Structure() {
     742        int errors = 0;
     743        String PRE_15_DEPLOYMENT_DIR = ".icedtea";
     744        String LEGACY_USER_HOME = System.getProperty("user.home") + File.separator + PRE_15_DEPLOYMENT_DIR;
     745        File configDir = new File(Defaults.USER_CONFIG_HOME);
     746        File cacheDir = new File(Defaults.USER_CACHE_HOME);
     747        File legacyUserDir = new File(LEGACY_USER_HOME);
     748        if (legacyUserDir.exists()) {
     749            OutputController.getLogger().log(OutputController.Level.MESSAGE_ALL, "Legacy configuration and cache found. Those will be now transported to new locations");
     750            OutputController.getLogger().log(OutputController.Level.MESSAGE_ALL, Defaults.USER_CONFIG_HOME + " and " + Defaults.USER_CACHE_HOME);
     751            OutputController.getLogger().log(OutputController.Level.MESSAGE_ALL, "You should not see this message next time you run icedtea-web!");
     752            OutputController.getLogger().log(OutputController.Level.MESSAGE_ALL, "Your custom dirs will not be touched and will work");
     753            OutputController.getLogger().log(OutputController.Level.MESSAGE_ALL, "-----------------------------------------------");
     754
     755            OutputController.getLogger().log(OutputController.Level.MESSAGE_ALL, "Preparing new directories:");
     756            OutputController.getLogger().log(OutputController.Level.MESSAGE_ALL, " " + Defaults.USER_CONFIG_HOME);
     757            errors += resultToStd(configDir.mkdirs());
     758            OutputController.getLogger().log(OutputController.Level.MESSAGE_ALL, " " + Defaults.USER_CACHE_HOME);
     759            errors += resultToStd(cacheDir.mkdirs());
     760
     761            String legacySecurity = LEGACY_USER_HOME + File.separator + "security";
     762            String currentSecurity = Defaults.USER_SECURITY;
     763            errors += moveLegacyToCurrent(legacySecurity, currentSecurity);
     764
     765            String legacyCache = LEGACY_USER_HOME + File.separator + "cache";
     766            String currentCache = Defaults.getDefaults().get(DeploymentConfiguration.KEY_USER_CACHE_DIR).getDefaultValue();
     767            errors += moveLegacyToCurrent(legacyCache, currentCache);
     768            OutputController.getLogger().log(OutputController.Level.MESSAGE_ALL, "Adapting " + CacheLRUWrapper.CACHE_INDEX_FILE_NAME + " to new destination");
     769            //replace all legacyCache by currentCache in new recently_used
     770            try {
     771                File f = new File(currentCache, CacheLRUWrapper.CACHE_INDEX_FILE_NAME);
     772                String s = FileUtils.loadFileAsString(f);
     773                s = s.replace(legacyCache, currentCache);
     774                FileUtils.saveFile(s, f);
     775            } catch (IOException ex) {
     776                OutputController.getLogger().log(OutputController.Level.MESSAGE_ALL, ex);
     777                errors++;
     778            }
     779
     780            String legacyPcahceDir = LEGACY_USER_HOME + File.separator + "pcache";
     781            String currentPcacheDir = Defaults.getDefaults().get(DeploymentConfiguration.KEY_USER_PERSISTENCE_CACHE_DIR).getDefaultValue();
     782            errors += moveLegacyToCurrent(legacyPcahceDir, currentPcacheDir);
     783
     784            String legacyLogDir = LEGACY_USER_HOME + File.separator + "log";
     785            String currentLogDir = Defaults.getDefaults().get(DeploymentConfiguration.KEY_USER_LOG_DIR).getDefaultValue();
     786            errors += moveLegacyToCurrent(legacyLogDir, currentLogDir);
     787
     788            String legacyProperties = LEGACY_USER_HOME + File.separator + DEPLOYMENT_PROPERTIES;
     789            String currentProperties = Defaults.USER_CONFIG_HOME + File.separator + DEPLOYMENT_PROPERTIES;
     790            errors += moveLegacyToCurrent(legacyProperties, currentProperties);
     791
     792            String legacyPropertiesOld = LEGACY_USER_HOME + File.separator + DEPLOYMENT_PROPERTIES + ".old";
     793            String currentPropertiesOld = Defaults.USER_CONFIG_HOME + File.separator + DEPLOYMENT_PROPERTIES + ".old";
     794            errors += moveLegacyToCurrent(legacyPropertiesOld, currentPropertiesOld);
     795
     796
     797            String legacyAppletTrust = LEGACY_USER_HOME + File.separator + APPLET_TRUST_SETTINGS;
     798            String currentAppletTrust = getAppletTrustUserSettingsPath().getAbsolutePath();
     799            errors += moveLegacyToCurrent(legacyAppletTrust, currentAppletTrust);
     800
     801            String legacyTmp = LEGACY_USER_HOME + File.separator + "tmp";
     802            String currentTmp = Defaults.getDefaults().get(DeploymentConfiguration.KEY_USER_TMP_DIR).getDefaultValue();
     803            errors += moveLegacyToCurrent(legacyTmp, currentTmp);
     804
     805            OutputController.getLogger().log(OutputController.Level.MESSAGE_ALL, "Removing now empty " + LEGACY_USER_HOME);
     806            errors += resultToStd(legacyUserDir.delete());
     807
     808            if (errors != 0) {
     809                OutputController.getLogger().log(OutputController.Level.MESSAGE_ALL, "There occureed " + errors + " errors");
     810                OutputController.getLogger().log(OutputController.Level.MESSAGE_ALL, "Please double check content of old data in " + LEGACY_USER_HOME + " with ");
     811                OutputController.getLogger().log(OutputController.Level.MESSAGE_ALL, "new " + Defaults.USER_CONFIG_HOME + " and " + Defaults.USER_CACHE_HOME);
     812                OutputController.getLogger().log(OutputController.Level.MESSAGE_ALL, "To disable this check again, please remove " + LEGACY_USER_HOME);
     813            }
     814
     815        } else {
     816            OutputController.getLogger().log("System is already following XDG .cache and .config specifications");
     817            try {
     818                OutputController.getLogger().log("config: " + Defaults.USER_CONFIG_HOME + " file exists: " + configDir.exists());
     819            } catch (Exception ex) {
     820                OutputController.getLogger().log(ex);
     821            }
     822            try {
     823                OutputController.getLogger().log("cache: " + Defaults.USER_CACHE_HOME + " file exists:" + cacheDir.exists());
     824            } catch (Exception ex) {
     825                OutputController.getLogger().log(ex);
     826            }
     827        }
     828        //this call should endure even if (ever) will migration code be removed
     829        DirectoryValidator.DirectoryCheckResults r = new DirectoryValidator().ensureDirs();
     830        if (!JNLPRuntime.isHeadless()) {
     831            if (r.getFailures() > 0) {
     832                JOptionPane.showMessageDialog(null, r.getMessage());
     833            }
     834        }
     835
     836    }
     837
     838    private static int moveLegacyToCurrent(String legacy, String current) {
     839        OutputController.getLogger().log(OutputController.Level.MESSAGE_ALL, "Moving " + legacy + " to " + current);
     840        File cf = new File(current);
     841        File old = new File(legacy);
     842        if (cf.exists()) {
     843            OutputController.getLogger().log(OutputController.Level.MESSAGE_ALL, "Warning! Destination " + current + " exists!");
     844        }
     845        if (old.exists()) {
     846            boolean moved = old.renameTo(cf);
     847            return resultToStd(moved);
     848        } else {
     849            OutputController.getLogger().log(OutputController.Level.MESSAGE_ALL, "Source " + legacy + " do not exists, nothing to do");
     850            return 0;
     851        }
     852
     853    }
     854
     855    private static int resultToStd(boolean securityMove) {
     856        if (securityMove) {
     857            OutputController.getLogger().log(OutputController.Level.MESSAGE_ALL, "OK");
     858            return 0;
     859        } else {
     860            OutputController.getLogger().log(OutputController.Level.MESSAGE_ALL, "ERROR");
     861            return 1;
     862        }
     863    }
    618864}
  • trunk/icedtea-web/netx/net/sourceforge/jnlp/config/Setting.java

    r348 r429  
    6868     * recognized setting, use null.
    6969     * @param value the initial value of this setting
    70      * @param source the origin of the value (a file, or perhaps "<internal>")
     70     * @param source the origin of the value (a file, or perhaps "{@code <internal>}")
    7171     */
    7272    public Setting(String name, String description, boolean locked,
  • trunk/icedtea-web/netx/net/sourceforge/jnlp/controlpanel/AboutPanel.java

    r348 r429  
    2323import java.awt.GridBagConstraints;
    2424import java.awt.GridBagLayout;
     25import java.awt.event.ActionEvent;
     26import java.awt.event.ActionListener;
    2527
    2628import javax.swing.Box;
     29import javax.swing.JButton;
    2730import javax.swing.JLabel;
    2831
     32import net.sourceforge.jnlp.about.AboutDialog;
    2933import net.sourceforge.jnlp.runtime.Translator;
    3034
     
    4448        JLabel logo = new JLabel();
    4549        JLabel aboutLabel = new JLabel("<html>" + Translator.R("CPAboutInfo") + "</html>");
    46 
     50        JButton aboutButton = new JButton(Translator.R("AboutDialogueTabAbout"));
     51        aboutButton.addActionListener(new ActionListener() {
     52            @Override
     53            public void actionPerformed(ActionEvent e) {
     54                AboutDialog.display();
     55            }
     56        });
    4757        c.fill = GridBagConstraints.BOTH;
    4858        c.gridy = 0;
     
    5464        c.weightx = 1;
    5565        add(aboutLabel, c);
    56 
     66        c.fill = GridBagConstraints.NONE;
     67        c.weighty = 0;
     68        c.weightx = 0;
     69        c.gridy++;
     70        c.gridx=1;
     71        add(aboutButton, c);
    5772        /* Keep all the elements at the top of the panel (Extra padding) */
     73        c.fill = GridBagConstraints.BOTH;
    5874        Component filler = Box.createRigidArea(new Dimension(1, 1));
    5975        c.weighty = 1;
    6076        c.gridy++;
    6177        add(filler, c);
     78       
     79       
     80       
    6281    }
    6382}
  • trunk/icedtea-web/netx/net/sourceforge/jnlp/controlpanel/AdvancedProxySettingsDialog.java

    r418 r429  
    3333import net.sourceforge.jnlp.runtime.Translator;
    3434import net.sourceforge.jnlp.util.ImageResources;
     35import net.sourceforge.jnlp.util.ScreenFinder;
    3536
    3637/**
    3738 * This dialog provides a means for user to edit more of the proxy settings.
    3839 *
    39  * @author Andrew Su <asu@redhat.com, andrew.su@utoronto.ca>
     40 * @author Andrew Su &lt;asu@redhat.com, andrew.su@utoronto.ca&gt;
    4041 *
    4142 */
     
    107108     */
    108109    private void centerDialog() {
    109         Dimension screen = Toolkit.getDefaultToolkit().getScreenSize();
    110         Dimension dialogSize = getSize();
    111 
    112         setLocation((screen.width - dialogSize.width) / 2, (screen.height - dialogSize.height) / 2);
     110        ScreenFinder.centerWindowsToCurrentScreen(this);
    113111    }
    114112
  • trunk/icedtea-web/netx/net/sourceforge/jnlp/controlpanel/AdvancedProxySettingsPane.java

    r348 r429  
    241241     * Make the button panel.
    242242     *
    243      * @return
     243     * @return the button panel created
     244     * @see JPanel
    244245     */
    245246    private JPanel createButtonPanel() {
  • trunk/icedtea-web/netx/net/sourceforge/jnlp/controlpanel/CachePane.java

    r348 r429  
    11/* CachePane.java -- Displays the specified folder and allows modification to its content.
    2 Copyright (C) 2010 Red Hat
     2Copyright (C) 2013 Red Hat
    33
    44This program is free software; you can redistribute it and/or modify
     
    2020import java.awt.BorderLayout;
    2121import java.awt.Component;
     22import java.awt.Cursor;
    2223import java.awt.Dimension;
     24import java.awt.EventQueue;
    2325import java.awt.FlowLayout;
    2426import java.awt.GridBagConstraints;
    2527import java.awt.GridBagLayout;
    2628import java.awt.GridLayout;
     29import java.awt.SystemColor;
     30import java.awt.Toolkit;
    2731import java.awt.event.ActionEvent;
    2832import java.awt.event.ActionListener;
     33import java.awt.event.WindowEvent;
    2934import java.io.File;
    3035import java.io.FileNotFoundException;
     
    3237import java.nio.channels.FileLock;
    3338import java.text.DateFormat;
    34 import java.text.ParseException;
    35 import java.text.SimpleDateFormat;
     39import java.text.NumberFormat;
    3640import java.util.ArrayList;
    3741import java.util.Comparator;
     42import java.util.Date;
    3843import java.util.Enumeration;
    3944import java.util.List;
     
    4247import javax.swing.JComponent;
    4348import javax.swing.JDialog;
     49import javax.swing.JOptionPane;
    4450import javax.swing.JPanel;
    4551import javax.swing.JScrollPane;
    4652import javax.swing.JTable;
    4753import javax.swing.ListSelectionModel;
    48 import javax.swing.table.DefaultTableModel;
     54import javax.swing.event.ListSelectionEvent;
     55import javax.swing.event.ListSelectionListener;
     56import javax.swing.table.DefaultTableCellRenderer;
     57import javax.swing.table.TableModel;
    4958import javax.swing.table.TableRowSorter;
    5059
    5160import net.sourceforge.jnlp.cache.CacheDirectory;
     61import net.sourceforge.jnlp.cache.CacheLRUWrapper;
     62import net.sourceforge.jnlp.cache.CacheUtil;
    5263import net.sourceforge.jnlp.cache.DirectoryNode;
    5364import net.sourceforge.jnlp.config.DeploymentConfiguration;
     
    5566import net.sourceforge.jnlp.util.FileUtils;
    5667import net.sourceforge.jnlp.util.PropertiesFile;
     68import net.sourceforge.jnlp.util.logging.OutputController;
     69import net.sourceforge.jnlp.util.ui.NonEditableTableModel;
    5770
    5871public class CachePane extends JPanel {
    59 
    6072    JDialog parent;
    6173    DeploymentConfiguration config;
     
    6375    private JComponent defaultFocusComponent;
    6476    DirectoryNode root;
    65     String[] columns = { Translator.R("CVCPColName"),
     77    String[] columns = {
     78            Translator.R("CVCPColName"),
    6679            Translator.R("CVCPColPath"),
    6780            Translator.R("CVCPColType"),
     
    7083            Translator.R("CVCPColLastModified") };
    7184    JTable cacheTable;
     85    private JButton deleteButton, refreshButton, doneButton, cleanAll;
    7286
    7387    /**
     
    94108        c.fill = GridBagConstraints.BOTH;
    95109
    96         DefaultTableModel model = new DefaultTableModel(columns, 0) {
    97             public boolean isCellEditable(int row, int column) {
    98                 return false;
    99             }
    100         };
     110        TableModel model = new NonEditableTableModel(columns, 0);
    101111
    102112        cacheTable = new JTable(model);
    103113        cacheTable.getSelectionModel().setSelectionMode(ListSelectionModel.SINGLE_SELECTION);
     114        cacheTable.getSelectionModel().addListSelectionListener(new ListSelectionListener() {
     115            @Override
     116            final public void valueChanged(ListSelectionEvent listSelectionEvent) {
     117                // If no row has been selected, disable the delete button, else enable it
     118                if (cacheTable.getSelectionModel().isSelectionEmpty()) {
     119                    deleteButton.setEnabled(false);
     120                }
     121                else {
     122                    deleteButton.setEnabled(true);
     123                }
     124            }
     125        });
    104126        cacheTable.setAutoResizeMode(JTable.AUTO_RESIZE_NEXT_COLUMN);
    105127        cacheTable.setPreferredScrollableViewportSize(new Dimension(600, 200));
     
    107129        JScrollPane scrollPane = new JScrollPane(cacheTable);
    108130
    109         populateTable();
    110 
    111         TableRowSorter<DefaultTableModel> tableSorter = new TableRowSorter<DefaultTableModel>(model);
    112         tableSorter.setComparator(4, new Comparator<Long>() { // Comparator for size column.
    113             @Override
    114             public int compare(Long o1, Long o2) {
    115                 return o1.compareTo(o2);
    116             }
    117         });
    118         tableSorter.setComparator(5, new Comparator<String>() { // Comparator for date column.
    119             @Override
    120             public int compare(String o1, String o2) {
    121                 DateFormat format = new SimpleDateFormat("MM/dd/yyyy");
    122                 try {
    123                     Long time1 = format.parse(o1).getTime();
    124                     Long time2 = format.parse(o2).getTime();
    125                     return time1.compareTo(time2);
    126                 } catch (ParseException e) {
    127                     return 0;
    128                 }
    129             }
    130         });
     131        TableRowSorter<TableModel> tableSorter = new TableRowSorter<TableModel>(model);
     132        final Comparator<Comparable<?>> comparator = new Comparator<Comparable<?>>() { // General purpose Comparator
     133            @Override
     134            @SuppressWarnings("unchecked")
     135            public final int compare(final Comparable a, final Comparable b) {
     136                return a.compareTo(b);
     137            }
     138        };
     139        tableSorter.setComparator(1, comparator); // Comparator for path column.
     140        tableSorter.setComparator(4, comparator); // Comparator for size column.
     141        tableSorter.setComparator(5, comparator); // Comparator for modified column.
    131142        cacheTable.setRowSorter(tableSorter);
     143        final DefaultTableCellRenderer tableCellRenderer = new DefaultTableCellRenderer() {
     144            @Override
     145            public final Component getTableCellRendererComponent(final JTable table, final Object value, final boolean isSelected, final boolean hasFocus, final int row, final int column) {
     146                super.getTableCellRendererComponent(table, value, isSelected, hasFocus, row, column);
     147
     148                switch (column) {
     149                    case 1: // Path column
     150                    // Render absolute path
     151                    super.setText(((File)value).getAbsolutePath());
     152                    break;
     153                    case 4: // Size column
     154                    // Render size formatted to default locale's number format
     155                    super.setText(NumberFormat.getInstance().format(value));
     156                    break;
     157                    case 5: // last modified column
     158                    // Render modify date formatted to default locale's date format
     159                    super.setText(DateFormat.getDateInstance().format(value));
     160                }
     161
     162                return this;
     163            }
     164        };
     165        // TableCellRenderer for path column
     166        cacheTable.getColumn(this.columns[1]).setCellRenderer(tableCellRenderer);
     167        // TableCellRenderer for size column
     168        cacheTable.getColumn(this.columns[4]).setCellRenderer(tableCellRenderer);
     169        // TableCellRenderer for last modified column
     170        cacheTable.getColumn(this.columns[5]).setCellRenderer(tableCellRenderer);
    132171
    133172        c.weightx = 1;
     
    138177        this.add(topPanel, BorderLayout.CENTER);
    139178        this.add(createButtonPanel(), BorderLayout.SOUTH);
    140 
    141179    }
    142180
     
    153191        List<JButton> buttons = new ArrayList<JButton>();
    154192
    155         JButton deleteButton = new JButton(Translator.R("CVCPButDelete"));
     193        this.deleteButton = new JButton(Translator.R("CVCPButDelete"));
    156194        deleteButton.addActionListener(new ActionListener() {
    157195            @Override
    158196            public void actionPerformed(ActionEvent e) {
    159                 FileLock fl = null;
    160                 File netxRunningFile = new File(config.getProperty(DeploymentConfiguration.KEY_USER_NETX_RUNNING_FILE));
    161                 if (!netxRunningFile.exists()) {
     197                disableButtons();
     198                // Delete on AWT thread after this action has been performed
     199                // in order to allow the cache viewer to update itself
     200                invokeLaterDelete();
     201            }
     202        });
     203        deleteButton.setEnabled(false);
     204        buttons.add(deleteButton);
     205
     206        this.cleanAll = new JButton(Translator.R("CVCPCleanCache"));
     207        cleanAll.addActionListener(new ActionListener() {
     208
     209            @Override
     210            public void actionPerformed(ActionEvent e) {
     211                disableButtons();
     212                // Delete on AWT thread after this action has been performed
     213                // in order to allow the cache viewer to update itself
     214                invokeLaterDeleteAll();
     215            }
     216        });
     217        buttons.add(cleanAll);
     218
     219        this.refreshButton = new JButton(Translator.R("CVCPButRefresh"));
     220        refreshButton.addActionListener(new ActionListener() {
     221            @Override
     222            public void actionPerformed(ActionEvent e) {
     223                disableButtons();
     224                // Populate cacheTable on AWT thread after this action event has been performed
     225                invokeLaterPopulateTable();
     226            }
     227        });
     228        refreshButton.setEnabled(false);
     229        buttons.add(refreshButton);
     230
     231        this.doneButton = new JButton(Translator.R("ButDone"));
     232        doneButton.addActionListener(new ActionListener() {
     233            @Override
     234            public void actionPerformed(ActionEvent e) {
     235                Toolkit.getDefaultToolkit().getSystemEventQueue().postEvent(
     236                        new WindowEvent(parent, WindowEvent.WINDOW_CLOSING));
     237            }
     238        });
     239
     240        int maxWidth = 0;
     241        int maxHeight = 0;
     242        for (JButton button : buttons) {
     243            maxWidth = Math.max(button.getMinimumSize().width, maxWidth);
     244            maxHeight = Math.max(button.getMinimumSize().height, maxHeight);
     245        }
     246
     247        int wantedWidth = maxWidth + 10;
     248        int wantedHeight = maxHeight;
     249        for (JButton button : buttons) {
     250            button.setPreferredSize(new Dimension(wantedWidth, wantedHeight));
     251            leftPanel.add(button);
     252        }
     253
     254        doneButton.setPreferredSize(new Dimension(wantedWidth, wantedHeight));
     255        doneButton.setEnabled(false);
     256        rightPanel.add(doneButton);
     257        buttonPanel.add(leftPanel);
     258        buttonPanel.add(rightPanel);
     259
     260        return buttonPanel;
     261    }
     262
     263    /**
     264     * Posts an event to the event queue to delete the currently selected
     265     * resource in {@link CachePane#cacheTable} after the {@code CachePane} and
     266     * {@link CacheViewer} have been instantiated and painted.
     267     * @see CachePane#cacheTable
     268     */
     269    private  void invokeLaterDelete() {
     270        EventQueue.invokeLater(new Runnable() {
     271            @Override
     272            public void run() {
     273                try {
     274                    FileLock fl = null;
     275                    File netxRunningFile = new File(config.getProperty(DeploymentConfiguration.KEY_USER_NETX_RUNNING_FILE));
     276                    if (!netxRunningFile.exists()) {
     277                        try {
     278                            FileUtils.createParentDir(netxRunningFile);
     279                            FileUtils.createRestrictedFile(netxRunningFile, true);
     280                        } catch (IOException e1) {
     281                            OutputController.getLogger().log(OutputController.Level.ERROR_ALL, e1);
     282                        }
     283                    }
     284
    162285                    try {
    163                         FileUtils.createParentDir(netxRunningFile);
    164                         FileUtils.createRestrictedFile(netxRunningFile, true);
    165                     } catch (IOException e1) {
    166                         e1.printStackTrace();
    167                     }
    168                 }
    169 
    170                 try {
    171                     fl = FileUtils.getFileLock(netxRunningFile.getPath(), false, false);
    172                 } catch (FileNotFoundException e1) {
    173                 }
    174 
    175                 int row = cacheTable.getSelectedRow();
    176                 try {
    177                     if (fl == null) return;
    178                     if (row == -1 || row > cacheTable.getRowCount() - 1)
    179                         return;
    180                     int modelRow = cacheTable.convertRowIndexToModel(row);
    181                     DirectoryNode fileNode = ((DirectoryNode) cacheTable.getModel().getValueAt(modelRow, 0));
    182                     if (fileNode.getFile().delete()) {
    183                         updateRecentlyUsed(fileNode.getFile());
    184                         fileNode.getParent().removeChild(fileNode);
    185                         FileUtils.deleteWithErrMesg(fileNode.getInfoFile());
    186                         ((DefaultTableModel) cacheTable.getModel()).removeRow(modelRow);
    187                         cacheTable.getSelectionModel().setSelectionInterval(row, row);
    188                         CacheDirectory.cleanParent(fileNode);
     286                        fl = FileUtils.getFileLock(netxRunningFile.getPath(), false, false);
     287                    } catch (FileNotFoundException e1) {
     288                    }
     289
     290                    int row = cacheTable.getSelectedRow();
     291                    try {
     292                        if (fl == null) {
     293                            JOptionPane.showMessageDialog(parent, Translator.R("CCannotClearCache"));
     294                            return;
     295                        }
     296                        int modelRow = cacheTable.convertRowIndexToModel(row);
     297                        DirectoryNode fileNode = ((DirectoryNode) cacheTable.getModel().getValueAt(modelRow, 0));
     298                        if (fileNode.getFile().delete()) {
     299                            updateRecentlyUsed(fileNode.getFile());
     300                            fileNode.getParent().removeChild(fileNode);
     301                            FileUtils.deleteWithErrMesg(fileNode.getInfoFile());
     302                            ((NonEditableTableModel) cacheTable.getModel()).removeRow(modelRow);
     303                            cacheTable.getSelectionModel().clearSelection();
     304                            CacheDirectory.cleanParent(fileNode);
     305                        }
     306                    } catch (Exception exception) {
     307                        // ignore
     308                    }
     309
     310                    if (fl != null) {
     311                        try {
     312                            fl.release();
     313                            fl.channel().close();
     314                        } catch (IOException e1) {
     315                            OutputController.getLogger().log(OutputController.Level.ERROR_ALL, e1);
     316                        }
    189317                    }
    190318                } catch (Exception exception) {
    191                     //ignore
    192                 }
    193 
    194                 if (fl != null) {
    195                     try {
    196                         fl.release();
    197                         fl.channel().close();
    198                     } catch (IOException e1) {
    199                         e1.printStackTrace();
    200                     }
     319                        OutputController.getLogger().log(OutputController.Level.ERROR_DEBUG, exception);
     320                } finally {
     321                    restoreDisabled();
    201322                }
    202323            }
    203324
    204325            private void updateRecentlyUsed(File f) {
    205                 File recentlyUsedFile = new File(location + File.separator + "recently_used");
     326                File recentlyUsedFile = new File(location + File.separator + CacheLRUWrapper.CACHE_INDEX_FILE_NAME);
    206327                PropertiesFile pf = new PropertiesFile(recentlyUsedFile);
    207328                pf.load();
     
    216337            }
    217338        });
    218         buttons.add(deleteButton);
    219 
    220         JButton refreshButton = new JButton(Translator.R("CVCPButRefresh"));
    221         refreshButton.addActionListener(new ActionListener() {
    222             @Override
    223             public void actionPerformed(ActionEvent e) {
    224                 populateTable();
    225             }
    226         });
    227         buttons.add(refreshButton);
    228 
    229         JButton doneButton = new JButton(Translator.R("ButDone"));
    230         doneButton.addActionListener(new ActionListener() {
    231             @Override
    232             public void actionPerformed(ActionEvent e) {
    233                 parent.dispose();
    234             }
    235         });
    236 
    237         int maxWidth = 0;
    238         int maxHeight = 0;
    239         for (JButton button : buttons) {
    240             maxWidth = Math.max(button.getMinimumSize().width, maxWidth);
    241             maxHeight = Math.max(button.getMinimumSize().height, maxHeight);
    242         }
    243 
    244         int wantedWidth = maxWidth + 10;
    245         int wantedHeight = maxHeight;
    246         for (JButton button : buttons) {
    247             button.setPreferredSize(new Dimension(wantedWidth, wantedHeight));
    248             leftPanel.add(button);
    249         }
    250 
    251         doneButton.setPreferredSize(new Dimension(wantedWidth, wantedHeight));
    252         rightPanel.add(doneButton);
    253         buttonPanel.add(leftPanel);
    254         buttonPanel.add(rightPanel);
    255 
    256         return buttonPanel;
     339    }
     340
     341    private void invokeLaterDeleteAll() {
     342        EventQueue.invokeLater(new Runnable() {
     343
     344            @Override
     345            public void run() {
     346                try {
     347                    visualCleanCache(parent);
     348                    populateTable();
     349                } catch (Exception exception) {
     350                    OutputController.getLogger().log(OutputController.Level.ERROR_DEBUG, exception);
     351                } finally {
     352                    restoreDisabled();
     353                }
     354            }
     355        });
     356    }
     357
     358    /**
     359     * Posts an event to the event queue to populate the
     360     * {@link CachePane#cacheTable} after the {@code CachePane} and
     361     * {@link CacheViewer} have been instantiated and painted.
     362     * @see CachePane#populateTable
     363     */
     364    final void invokeLaterPopulateTable() {
     365        EventQueue.invokeLater(new Runnable() {
     366            @Override
     367            public void run() {
     368                try {
     369                    populateTable();
     370                    // Disable cacheTable when no data to display, so no events are generated
     371                    if (cacheTable.getModel().getRowCount() == 0) {
     372                        cacheTable.setEnabled(false);
     373                        cacheTable.setBackground(SystemColor.control);
     374                        // No data in cacheTable, so nothing to delete
     375                        deleteButton.setEnabled(false);
     376                    } else {
     377                        cacheTable.setEnabled(true);
     378                        cacheTable.setBackground(SystemColor.text);
     379                    }
     380                } catch (Exception exception) {
     381                        OutputController.getLogger().log(OutputController.Level.ERROR_DEBUG, exception);
     382                } finally {
     383                    refreshButton.setEnabled(true);
     384                    doneButton.setEnabled(true);
     385                    cleanAll.setEnabled(true);
     386                }
     387            }
     388        });
    257389    }
    258390
     
    262394     */
    263395    private void populateTable() {
    264         ((DefaultTableModel) cacheTable.getModel()).setRowCount(0); //Clears the table
    265         for (Object[] v : generateData(root))
    266             ((DefaultTableModel) cacheTable.getModel()).addRow(v);
     396        try {
     397            // Populating the cacheTable may take a while, so indicate busy by cursor
     398            parent.getContentPane().setCursor(Cursor.getPredefinedCursor(Cursor.WAIT_CURSOR));
     399
     400            NonEditableTableModel tableModel;
     401            (tableModel = (NonEditableTableModel)cacheTable.getModel()).setRowCount(0); //Clears the table
     402            for (Object[] v : generateData(root)) {
     403                tableModel.addRow(v);
     404            }
     405        } catch (Exception exception) {
     406            OutputController.getLogger().log(OutputController.Level.ERROR_DEBUG, exception);
     407        } finally {
     408            // Reset cursor
     409            parent.getContentPane().setCursor(Cursor.getDefaultCursor());
     410        }
    267411    }
    268412
     
    282426                for (DirectoryNode domain : type.getChildren()) {
    283427                    for (DirectoryNode leaf : CacheDirectory.getLeafData(domain)) {
    284                         Object[] o = { leaf,
    285                                 leaf.getFile().getAbsolutePath(),
    286                                 type,
    287                                 domain,
    288                                 leaf.getFile().length(),
    289                                 new SimpleDateFormat("MM/dd/yyyy").format(leaf.getFile().lastModified()) };
     428                        final File f = leaf.getFile();
     429                        Object[] o = {
     430                            leaf,
     431                            f.getParentFile(),
     432                            type,
     433                            domain,
     434                            f.length(),
     435                            new Date(f.lastModified())
     436                        };
    290437                        data.add(o);
    291438                    }
     
    305452        }
    306453    }
     454
     455    public void disableButtons() {
     456        // may take a while, so indicate busy by cursor
     457        parent.getContentPane().setCursor(Cursor.getPredefinedCursor(Cursor.WAIT_CURSOR));
     458        // Disable dialog and buttons while operating
     459        deleteButton.setEnabled(false);
     460        refreshButton.setEnabled(false);
     461        doneButton.setEnabled(false);
     462        cleanAll.setEnabled(false);
     463    }
     464
     465    public void restoreDisabled() {
     466        cleanAll.setEnabled(true);
     467        // If nothing selected then keep deleteButton disabled
     468        if (!cacheTable.getSelectionModel().isSelectionEmpty()) {
     469            deleteButton.setEnabled(true);
     470        }
     471        // Enable buttons
     472        refreshButton.setEnabled(true);
     473        doneButton.setEnabled(true);
     474        // If cacheTable is empty disable it and set background
     475        // color to indicate being disabled
     476        if (cacheTable.getModel().getRowCount() == 0) {
     477            cacheTable.setEnabled(false);
     478            cacheTable.setBackground(SystemColor.control);
     479        }
     480        // Reset cursor
     481        parent.getContentPane().setCursor(Cursor.getDefaultCursor());
     482    }
     483
     484    public static void visualCleanCache(Component parent) {
     485        try {
     486            boolean success = CacheUtil.clearCache();
     487            if (!success) {
     488                JOptionPane.showMessageDialog(parent, Translator.R("CCannotClearCache"));
     489            }
     490        } catch (Exception ex) {
     491            JOptionPane.showMessageDialog(parent, Translator.R("CCannotClearCache"));
     492        }
     493    }
    307494}
     495
     496
  • trunk/icedtea-web/netx/net/sourceforge/jnlp/controlpanel/CacheViewer.java

    r418 r429  
    11/* CacheViewer.java -- Display the GUI for viewing and deleting cache files.
    2 Copyright (C) 2010 Red Hat
     2Copyright (C) 2013 Red Hat
    33
    44This program is free software; you can redistribute it and/or modify
     
    2323import java.awt.GridBagConstraints;
    2424import java.awt.GridBagLayout;
     25import java.awt.KeyEventDispatcher;
     26import java.awt.KeyboardFocusManager;
    2527import java.awt.Toolkit;
     28import java.awt.event.KeyEvent;
    2629import java.awt.event.WindowAdapter;
    2730import java.awt.event.WindowEvent;
     
    3235import net.sourceforge.jnlp.runtime.Translator;
    3336import net.sourceforge.jnlp.util.ImageResources;
     37import net.sourceforge.jnlp.util.ScreenFinder;
    3438
    3539/**
     
    5357    public CacheViewer(DeploymentConfiguration config) {
    5458        super((Frame) null, dialogTitle, true); // Don't need a parent.
     59        this.config = config;
     60        if (config == null) {
     61            throw new IllegalArgumentException("config: " + config);
     62        }
    5563        setIconImages(ImageResources.INSTANCE.getApplicationImages());
    56         this.config = config;
    5764
    5865        /* Prepare for adding components to dialog box */
     
    7077
    7178        pack();
     79        this.topPanel.invokeLaterPopulateTable();
    7280
    7381        /* Set focus to default button when first activated */
     
    7583            private boolean gotFocus = false;
    7684
     85            @Override
    7786            public void windowGainedFocus(WindowEvent we) {
    7887                // Once window gets focus, set initial focus
     
    8493        };
    8594        addWindowFocusListener(adapter);
     95
     96        // Add a KeyEventDispatcher to dispatch events when this CacheViewer has focus
     97        final CacheViewer cacheViewer = this;
     98        KeyboardFocusManager.getCurrentKeyboardFocusManager().addKeyEventDispatcher(new KeyEventDispatcher() {
     99            /**
     100             * Dispatches mainly the {@code KeyEvent.VK_ESCAPE} key event to
     101             * close the {@code CacheViewer} dialog.
     102             * @return {@code true} after an {@link KeyEvent#VK_ESCAPE
     103             * VK_ESCAPE} has been processed, otherwise {@code false}
     104             * @see KeyEventDispatcher
     105             */
     106            public boolean dispatchKeyEvent(final KeyEvent keyEvent) {
     107                // Check if Esc key has been pressed
     108                if (keyEvent.getKeyCode() == KeyEvent.VK_ESCAPE &&
     109                    keyEvent.getID() == KeyEvent.KEY_PRESSED) {
     110                    // Exclude this key event from further processing
     111                    keyEvent.consume();
     112                    // Remove this low-level KeyEventDispatcher
     113                    KeyboardFocusManager.getCurrentKeyboardFocusManager().removeKeyEventDispatcher(this);
     114                    // Post close event to CacheViewer dialog
     115                    Toolkit.getDefaultToolkit().getSystemEventQueue().postEvent(
     116                            new WindowEvent(cacheViewer, WindowEvent.WINDOW_CLOSING));
     117                    return true;
     118                }
     119                return false;
     120            }
     121        });
    86122
    87123        initialized = true;
     
    114150     */
    115151    private void centerDialog() {
    116         Dimension screen = Toolkit.getDefaultToolkit().getScreenSize();
    117         Dimension dialogSize = getSize();
    118 
    119         setLocation((screen.width - dialogSize.width) / 2, (screen.height - dialogSize.height) / 2);
     152        ScreenFinder.centerWindowsToCurrentScreen(this);
    120153    }
    121154}
  • trunk/icedtea-web/netx/net/sourceforge/jnlp/controlpanel/CommandLine.java

    r348 r429  
    3232import net.sourceforge.jnlp.config.DeploymentConfiguration;
    3333import net.sourceforge.jnlp.config.Setting;
     34import net.sourceforge.jnlp.runtime.JNLPRuntime;
     35import net.sourceforge.jnlp.util.logging.OutputController;
    3436
    3537/**
     
    4345 * that specific command. For example, see {@link #handleListCommand(List)}
    4446 * and {@link #printListHelp()}.
    45  * <p>
     47 * </p>
    4648 * Sample usage:
    47  * <pre>
     49 * <pre><code>
    4850 * CommandLine cli = new CommandLine();
    4951 * // the string array represents input using the command line
     
    5456 *    // bad!
    5557 * }
    56  * </pre>
     58 * </code></pre>
    5759 *
    58  * @author Omair Majid (omajid@redhat.com)
     60 * @author <a href="mailto:Omair%20Majid%20&lt;omajid@redhat.com&gt;">Omair Majid</a>
    5961 */
    6062public class CommandLine {
     
    8183            config.load(false);
    8284        } catch (ConfigurationException e) {
    83             System.out.println(R("RConfigurationFatal"));
     85            OutputController.getLogger().log(OutputController.Level.MESSAGE_ALL, R("RConfigurationFatal"));
     86            OutputController.getLogger().log(e);
    8487        }
    8588    }
     
    9295     */
    9396    public int handleHelpCommand(List<String> args) {
    94         System.out.println(R("Usage"));
    95         System.out.println("  " + PROGRAM_NAME + " "
     97        OutputController.getLogger().printOutLn(R("Usage"));
     98        OutputController.getLogger().printOutLn("  " + PROGRAM_NAME + " "
    9699                + allCommands.toString().replace(',', '|').replaceAll(" ", "") + " [help]");
    97         System.out.println(R("CLHelpDescription", PROGRAM_NAME));
     100        OutputController.getLogger().printOutLn(R("CLHelpDescription", PROGRAM_NAME));
    98101        return SUCCESS;
    99102    }
     
    103106     */
    104107    public void printListHelp() {
    105         System.out.println(R("Usage"));
    106         System.out.println("  " + PROGRAM_NAME + " list [--details]");
    107         System.out.println(R("CLListDescription"));
     108        OutputController.getLogger().printOutLn(R("Usage"));
     109        OutputController.getLogger().printOutLn("  " + PROGRAM_NAME + " list [--details]");
     110        OutputController.getLogger().printOutLn(R("CLListDescription"));
    108111    }
    109112
     
    135138        for (String key : all.keySet()) {
    136139            Setting<String> value = all.get(key);
    137             System.out.println(key + ": " + value.getValue());
     140            OutputController.getLogger().printOutLn(key + ": " + value.getValue());
    138141            if (verbose) {
    139                 System.out.println("\t" + R("CLDescription", value.getDescription()));
     142                OutputController.getLogger().printOutLn("\t" + R("CLDescription", value.getDescription()));
    140143            }
    141144        }
     
    147150     */
    148151    public void printGetHelp() {
    149         System.out.println(R("Usage"));
    150         System.out.println("  " + PROGRAM_NAME + " get property-name");
    151         System.out.println(R("CLGetDescription"));
     152        OutputController.getLogger().printOutLn(R("Usage"));
     153        OutputController.getLogger().printOutLn("  " + PROGRAM_NAME + " get property-name");
     154        OutputController.getLogger().printOutLn(R("CLGetDescription"));
    152155    }
    153156
     
    176179        if (all.containsKey(key)) {
    177180            value = all.get(key).getValue();
    178             System.out.println(value);
    179             return SUCCESS;
    180         } else {
    181             System.out.println(R("CLUnknownProperty", key));
     181            OutputController.getLogger().printOutLn(value);
     182            return SUCCESS;
     183        } else {
     184            OutputController.getLogger().log(OutputController.Level.MESSAGE_ALL, R("CLUnknownProperty", key));
    182185            return ERROR;
    183186        }
     
    188191     */
    189192    public void printSetHelp() {
    190         System.out.println(R("Usage"));
    191         System.out.println("  " + PROGRAM_NAME + " set property-name value");
    192         System.out.println(R("CLSetDescription"));
     193        OutputController.getLogger().printOutLn(R("Usage"));
     194        OutputController.getLogger().printOutLn("  " + PROGRAM_NAME + " set property-name value");
     195        OutputController.getLogger().printOutLn(R("CLSetDescription"));
    193196    }
    194197
     
    220223                    old.getValidator().validate(value);
    221224                } catch (IllegalArgumentException e) {
    222                     System.out.println(R("CLIncorrectValue", old.getName(), value, old.getValidator().getPossibleValues()));
     225                    OutputController.getLogger().log(OutputController.Level.WARNING_ALL, R("CLIncorrectValue", old.getName(), value, old.getValidator().getPossibleValues()));
     226                    OutputController.getLogger().log(e);
    223227                    return ERROR;
    224228                }
     
    226230            config.setProperty(key, value);
    227231        } else {
    228             System.out.println(R("CLWarningUnknownProperty", key));
     232            OutputController.getLogger().printOutLn(R("CLWarningUnknownProperty", key));
    229233            config.setProperty(key, value);
    230234        }
     
    233237            config.save();
    234238        } catch (IOException e) {
    235             e.printStackTrace();
     239            OutputController.getLogger().log(OutputController.Level.ERROR_ALL, e);
    236240            return ERROR;
    237241        }
     
    244248     */
    245249    public void printResetHelp() {
    246         System.out.println(R("Usage"));
    247         System.out.println("  " + PROGRAM_NAME + " reset [all|property-name]");
    248         System.out.println(R("CLResetDescription"));
     250        OutputController.getLogger().printOutLn(R("Usage"));
     251        OutputController.getLogger().printOutLn("  " + PROGRAM_NAME + " reset [all|property-name]");
     252        OutputController.getLogger().printOutLn(R("CLResetDescription"));
    249253    }
    250254
     
    276280        Map<String, Setting<String>> all = config.getRaw();
    277281        if (!resetAll && !all.containsKey(key)) {
    278             System.out.println(R("CLUnknownProperty", key));
     282            OutputController.getLogger().log(OutputController.Level.MESSAGE_ALL, R("CLUnknownProperty", key));
    279283            return ERROR;
    280284        }
     
    293297            config.save();
    294298        } catch (IOException e) {
    295             e.printStackTrace();
     299            OutputController.getLogger().log(OutputController.Level.ERROR_ALL, e);
    296300            return ERROR;
    297301        }
     
    304308     */
    305309    public void printInfoHelp() {
    306         System.out.println(R("Usage"));
    307         System.out.println("  " + PROGRAM_NAME + " info property-name");
    308         System.out.println(R("CLInfoDescription"));
     310        OutputController.getLogger().printOutLn(R("Usage"));
     311        OutputController.getLogger().printOutLn("  " + PROGRAM_NAME + " info property-name");
     312        OutputController.getLogger().printOutLn(R("CLInfoDescription"));
    309313    }
    310314
     
    332336        Setting<String> value = all.get(key);
    333337        if (value == null) {
    334             System.out.println(R("CLNoInfo"));
    335             return ERROR;
    336         } else {
    337             System.out.println(R("CLDescription", value.getDescription()));
    338             System.out.println(R("CLValue", value.getValue()));
     338            OutputController.getLogger().log(OutputController.Level.MESSAGE_ALL, R("CLNoInfo"));
     339            return ERROR;
     340        } else {
     341            OutputController.getLogger().printOutLn(R("CLDescription", value.getDescription()));
     342            OutputController.getLogger().printOutLn(R("CLValue", value.getValue()));
    339343            if (value.getValidator() != null) {
    340                 System.out.println("\t" + R("VVPossibleValues", value.getValidator().getPossibleValues()));
     344                OutputController.getLogger().printOutLn("\t" + R("VVPossibleValues", value.getValidator().getPossibleValues()));
    341345            }
    342             System.out.println(R("CLValueSource", value.getSource()));
     346            OutputController.getLogger().printOutLn(R("CLValueSource", value.getSource()));
    343347            return SUCCESS;
    344348        }
     
    349353     */
    350354    public void printCheckHelp() {
    351         System.out.println(R("Usage"));
    352         System.out.println("  " + PROGRAM_NAME + " check");
    353         System.out.println(R("CLCheckDescription"));
     355        OutputController.getLogger().printOutLn(R("Usage"));
     356        OutputController.getLogger().printOutLn("  " + PROGRAM_NAME + " check");
     357        OutputController.getLogger().printOutLn(R("CLCheckDescription"));
    354358    }
    355359
     
    379383        boolean allValid = true;
    380384        for (Setting<String> setting : validator.getIncorrectSetting()) {
    381             System.out.println(R("CLIncorrectValue", setting.getName(), setting.getValue(), setting.getValidator().getPossibleValues()));
     385            OutputController.getLogger().log(OutputController.Level.MESSAGE_ALL, R("CLIncorrectValue", setting.getName(), setting.getValue(), setting.getValidator().getPossibleValues()));
    382386            allValid = false;
    383387        }
    384388
    385389        for (Setting<String> setting : validator.getUnrecognizedSetting()) {
    386             System.out.println(R("CLUnknownProperty", setting.getName()));
     390            OutputController.getLogger().log(OutputController.Level.MESSAGE_ALL, R("CLUnknownProperty", setting.getName()));
    387391            allValid = false;
    388392        }
    389393
    390394        if (allValid) {
    391             System.out.println(R("CLNoIssuesFound"));
     395            OutputController.getLogger().printOutLn(R("CLNoIssuesFound"));
    392396            return SUCCESS;
    393397        } else {
     
    438442            val = handleCheckCommand(arguments);
    439443        } else if (allCommands.contains(command)) {
    440             System.out.println("INTERNAL ERROR: " + command + " should have been implemented");
     444            OutputController.getLogger().log(OutputController.Level.MESSAGE_ALL, "INTERNAL ERROR: " + command + " should have been implemented");
    441445            val = ERROR;
    442446        } else {
    443             System.out.println(R("CLUnknownCommand", command));
     447            OutputController.getLogger().log(OutputController.Level.MESSAGE_ALL, R("CLUnknownCommand", command));
    444448            handleHelpCommand(new ArrayList<String>());
    445449            val = ERROR;
     
    454458     */
    455459    public static void main(String[] args) throws Exception {
     460        DeploymentConfiguration.move14AndOlderFilesTo15StructureCatched();
    456461        if (args.length == 0) {
    457462            ControlPanel.main(new String[] {});
     
    460465            int result = cli.handle(args);
    461466
    462             // instead of returning, use System.exit() so we can pass back
     467            // instead of returning, use JNLPRuntime.exit() so we can pass back
    463468            // error codes indicating success or failure. Otherwise using
    464469            // this program for scripting will become much more challenging
    465             System.exit(result);
     470            JNLPRuntime.exit(result);
    466471        }
    467472    }
  • trunk/icedtea-web/netx/net/sourceforge/jnlp/controlpanel/ControlPanel.java

    r418 r429  
    4242import javax.swing.JLabel;
    4343import javax.swing.JList;
     44import javax.swing.JOptionPane;
    4445import javax.swing.JPanel;
    4546import javax.swing.JScrollPane;
     
    5354
    5455import net.sourceforge.jnlp.config.DeploymentConfiguration;
     56import net.sourceforge.jnlp.controlpanel.JVMPanel.JvmValidationResult;
    5557import net.sourceforge.jnlp.runtime.Translator;
    5658import net.sourceforge.jnlp.security.KeyStores;
    5759import net.sourceforge.jnlp.security.viewer.CertificatePane;
    5860import net.sourceforge.jnlp.util.ImageResources;
     61import net.sourceforge.jnlp.util.logging.OutputController;
    5962
    6063/**
     
    6669 */
    6770public class ControlPanel extends JFrame {
     71    private JVMPanel jvmPanel;
    6872
    6973    /**
     
    117121        setDefaultCloseOperation(WindowConstants.DISPOSE_ON_CLOSE);
    118122        pack();
    119         setMinimumSize(getPreferredSize());
    120123    }
    121124
    122125    private JPanel createTopPanel() {
    123         Font currentFont = null;
     126        Font currentFont;
    124127        JLabel about = new JLabel(R("CPMainDescriptionShort"));
    125128        currentFont = about.getFont();
     
    147150            image.setIcon(new ImageIcon(ImageIO.read(imgUrl)));
    148151        } catch (IOException e) {
    149             e.printStackTrace();
     152            OutputController.getLogger().log(OutputController.Level.ERROR_ALL, e);
    150153        }
    151154
     
    157160        return topPanel;
    158161    }
     162   
     163    private int validateJdk() {
     164        String s = ControlPanel.this.config.getProperty(DeploymentConfiguration.KEY_JRE_DIR);
     165        JvmValidationResult validationResult = JVMPanel.validateJvm(s);
     166        if (validationResult.id == JvmValidationResult.STATE.NOT_DIR
     167                || validationResult.id == JvmValidationResult.STATE.NOT_VALID_DIR
     168                || validationResult.id == JvmValidationResult.STATE.NOT_VALID_JDK) {
     169            return JOptionPane.showConfirmDialog(ControlPanel.this,
     170                    "<html>"+Translator.R("CPJVMNotokMessage1", s)+"<br/>"
     171                    + validationResult.formattedText+"<br/>"
     172                    + Translator.R("CPJVMNotokMessage2", DeploymentConfiguration.KEY_JRE_DIR, DeploymentConfiguration.USER_DEPLOYMENT_PROPERTIES_FILE)+"</html>",
     173                    Translator.R("CPJVMconfirmInvalidJdkTitle"),JOptionPane.OK_CANCEL_OPTION);
     174        }
     175        return JOptionPane.OK_OPTION;
     176    }
    159177
    160178    /**
     
    173191            public void actionPerformed(ActionEvent e) {
    174192                ControlPanel.this.saveConfiguration();
     193                int validationResult = validateJdk();
     194                if (validationResult!= JOptionPane.OK_OPTION){
     195                    return;
     196                }
    175197                ControlPanel.this.dispose();
    176198            }
     
    183205            public void actionPerformed(ActionEvent e) {
    184206                ControlPanel.this.saveConfiguration();
     207                int validationResult = validateJdk();
     208                if (validationResult != JOptionPane.OK_OPTION) {
     209                    int i = JOptionPane.showConfirmDialog(ControlPanel.this,
     210                            Translator.R("CPJVMconfirmReset"),
     211                            Translator.R("CPJVMconfirmReset"), JOptionPane.OK_CANCEL_OPTION);
     212                    if (i == JOptionPane.OK_OPTION) {
     213                        jvmPanel.resetTestFieldArgumentsExec();
     214                    }
     215                }
    185216            }
    186217        });
     
    219250     */
    220251    private JPanel createMainSettingsPanel() {
    221 
     252        jvmPanel =  (JVMPanel) createJVMSettingsPanel();
    222253        SettingsPanel[] panels = new SettingsPanel[] { new SettingsPanel(Translator.R("CPTabAbout"), createAboutPanel()),
    223254                new SettingsPanel(Translator.R("CPTabCache"), createCacheSettingsPanel()),
     
    227258                new SettingsPanel(Translator.R("CPTabDebugging"), createDebugSettingsPanel()),
    228259                new SettingsPanel(Translator.R("CPTabDesktopIntegration"), createDesktopSettingsPanel()),
     260                new SettingsPanel(Translator.R("CPTabJVMSettings"),jvmPanel),
    229261                new SettingsPanel(Translator.R("CPTabNetwork"), createNetworkSettingsPanel()),
    230262                // TODO: This is commented out since this is not implemented yet
    231263                // new SettingsPanel(Translator.R("CPTabRuntimes"), createRuntimesSettingsPanel()),
    232                 new SettingsPanel(Translator.R("CPTabSecurity"), createSecuritySettingsPanel()), };
     264                new SettingsPanel(Translator.R("CPTabSecurity"), createSecuritySettingsPanel()),
     265                //todo refactor to work with tmp file and apply as asu designed it
     266                new SettingsPanel(Translator.R("CPTabPolicy"), createPolicySettingsPanel()),
     267                new SettingsPanel(Translator.R("APPEXTSECControlPanelExtendedAppletSecurityTitle"), new UnsignedAppletsTrustingListPanel(DeploymentConfiguration.getAppletTrustGlobalSettingsPath(), DeploymentConfiguration.getAppletTrustUserSettingsPath(), this.config))
     268        };
    233269
    234270        // Add panels.
     
    241277            JPanel p = panel.getPanel();
    242278            Dimension d = p.getMinimumSize();
    243             if (d.height > height)
     279            if (d.height > height) {
    244280                height = d.height;
    245             if (d.width > width)
     281            }
     282            if (d.width > width) {
    246283                width = d.width;
     284            }
    247285        }
    248286        Dimension dim = new Dimension(width, height);
     
    265303        });
    266304        JScrollPane settingsListScrollPane = new JScrollPane(settingsList);
    267         settingsListScrollPane.setHorizontalScrollBarPolicy(JScrollPane.HORIZONTAL_SCROLLBAR_NEVER);
     305        settingsListScrollPane.setHorizontalScrollBarPolicy(JScrollPane.HORIZONTAL_SCROLLBAR_AS_NEEDED);
    268306
    269307        final JPanel settingsDetailPanel = new JPanel();
     
    320358    }
    321359
     360    private JPanel createPolicySettingsPanel() {
     361        return new PolicyPanel(this, this.config);
     362    }
     363
     364    private JPanel createJVMSettingsPanel() {
     365        return new JVMPanel(this.config);
     366    }
     367
    322368    /**
    323369     * This is a placeholder panel.
    324370     *
    325      * @return
     371     * @return a placeholder panel
     372     * @see JPanel
    326373     */
    327374    private JPanel createNotImplementedPanel() {
     
    343390            notImplementedPanel.add(label);
    344391        } catch (IOException e) {
    345             e.printStackTrace();
     392            OutputController.getLogger().log(OutputController.Level.ERROR_ALL, e);
    346393        }
    347394        return notImplementedPanel;
     
    355402            config.save();
    356403        } catch (IOException e) {
    357             e.printStackTrace();
     404            OutputController.getLogger().log(OutputController.Level.ERROR_ALL, e);
     405            JOptionPane.showMessageDialog(this, e);
    358406        }
    359407    }
    360408
    361409    public static void main(String[] args) throws Exception {
     410        DeploymentConfiguration.move14AndOlderFilesTo15StructureCatched();
    362411        final DeploymentConfiguration config = new DeploymentConfiguration();
    363412        try {
     
    370419            // if configuration is not loaded, we will get NullPointerExceptions
    371420            // everywhere
    372             e.printStackTrace();
     421            OutputController.getLogger().log(OutputController.Level.ERROR_ALL, e);
    373422        }
    374423
  • trunk/icedtea-web/netx/net/sourceforge/jnlp/controlpanel/DebuggingPanel.java

    r348 r429  
    2424import java.awt.GridBagConstraints;
    2525import java.awt.GridBagLayout;
     26import java.awt.event.ActionEvent;
     27import java.awt.event.ActionListener;
    2628import java.awt.event.ItemEvent;
    2729import java.awt.event.ItemListener;
    28 
    2930import javax.swing.Box;
     31import javax.swing.JButton;
    3032import javax.swing.JCheckBox;
    3133import javax.swing.JComboBox;
    3234import javax.swing.JLabel;
    3335import javax.swing.JPanel;
    34 
     36import javax.swing.JTextField;
     37import javax.swing.event.DocumentEvent;
     38import javax.swing.event.DocumentListener;
     39import net.sourceforge.jnlp.config.Defaults;
    3540import net.sourceforge.jnlp.config.DeploymentConfiguration;
    3641import net.sourceforge.jnlp.runtime.Translator;
     42import net.sourceforge.jnlp.util.logging.LogConfig;
    3743
    3844/**
     
    4450public class DebuggingPanel extends NamedBorderPanel implements ItemListener {
    4551
    46     /** List of properties used by this panel */
    47     public static String[] properties = { "deployment.trace", // Debugging
    48             "deployment.log", // Debugging
    49             "deployment.console.startup.mode", // Java Console
     52    /** List of properties used by checkboxes in this panel */
     53    public static String[] properties = {
     54            DeploymentConfiguration.KEY_ENABLE_LOGGING,
     55            DeploymentConfiguration.KEY_ENABLE_LOGGING_HEADERS,
     56            DeploymentConfiguration.KEY_ENABLE_LOGGING_TOFILE,
     57            DeploymentConfiguration.KEY_ENABLE_LOGGING_TOSTREAMS,
     58            DeploymentConfiguration.KEY_ENABLE_LOGGING_TOSYSTEMLOG
     59           
    5060    };
    51     private DeploymentConfiguration config;
     61   
     62     private DeploymentConfiguration config;
    5263
    5364    /**
     
    7182        GridBagConstraints c = new GridBagConstraints();
    7283
    73         JLabel debuggingDescription = new JLabel("<html>" + Translator.R("CPDebuggingDescription") + "<hr /><br /></html>");
    74 
    75         JCheckBox[] debuggingOptions = { new JCheckBox(Translator.R("DPEnableTracing")),
    76                 new JCheckBox(Translator.R("DPEnableLogging")), };
    77 
    78         ComboItem[] javaConsoleItems = { new ComboItem(Translator.R("DPDisable"), "DISABLE"),
    79                 new ComboItem(Translator.R("DPHide"), "HIDE"),
    80                 new ComboItem(Translator.R("DPShow"), "SHOW"), };
     84
     85        final JLabel debuggingDescription = new JLabel("<html>" + Translator.R("CPDebuggingDescription") + "<hr /><br /></html>");
     86        final JLabel logsDestinationTitle = new JLabel(Translator.R("CPFilesLogsDestDir")+": ");
     87        final JTextField logsDestination = new JTextField(config.getProperty(DeploymentConfiguration.KEY_USER_LOG_DIR));
     88        logsDestination.getDocument().addDocumentListener(new DocumentListener() {
     89
     90
     91            @Override
     92            public void insertUpdate(DocumentEvent e) {
     93                 save();
     94            }
     95
     96            @Override
     97            public void removeUpdate(DocumentEvent e) {
     98                 save();
     99            }
     100
     101            @Override
     102            public void changedUpdate(DocumentEvent e) {
     103                save();
     104
     105            }
     106
     107            private void save() {
     108                config.setProperty(DeploymentConfiguration.KEY_USER_LOG_DIR, logsDestination.getText());
     109            }
     110        });
     111        final JButton logsDestinationReset = new JButton(Translator.R("CPFilesLogsDestDirResert"));
     112        logsDestinationReset.addActionListener(new ActionListener() {
     113
     114            @Override
     115            public void actionPerformed(ActionEvent e) {
     116                logsDestination.setText(Defaults.getDefaults().get(DeploymentConfiguration.KEY_USER_LOG_DIR).getDefaultValue());
     117            }
     118        });
     119
     120        JCheckBox[] debuggingOptions = {
     121                new JCheckBox(Translator.R("DPEnableLogging")),
     122                new JCheckBox(Translator.R("DPEnableHeaders")),
     123                new JCheckBox(Translator.R("DPEnableFile")),
     124                new JCheckBox(Translator.R("DPEnableStds")),
     125                new JCheckBox(Translator.R("DPEnableSyslog"))
     126        };
     127        String[] hints = {
     128                (Translator.R("DPEnableLoggingHint")),
     129                (Translator.R("DPEnableHeadersHint")),
     130                (Translator.R("DPEnableFileHint", LogConfig.getLogConfig().getIcedteaLogDir())),
     131                (Translator.R("DPEnableStdsHint")),
     132                (Translator.R("DPEnableSyslogHint"))
     133        };
     134
     135        ComboItem[] javaConsoleItems = { new ComboItem(Translator.R("DPDisable"), DeploymentConfiguration.CONSOLE_DISABLE),
     136                new ComboItem(Translator.R("DPHide"), DeploymentConfiguration.CONSOLE_HIDE),
     137                new ComboItem(Translator.R("DPShow"), DeploymentConfiguration.CONSOLE_SHOW),
     138                new ComboItem(Translator.R("DPShowPluginOnly"), DeploymentConfiguration.CONSOLE_SHOW_PLUGIN),
     139                new ComboItem(Translator.R("DPShowJavawsOnly"), DeploymentConfiguration.CONSOLE_SHOW_JAVAWS) };
    81140
    82141        JLabel consoleLabel = new JLabel(Translator.R("DPJavaConsole"));
    83142        JComboBox consoleComboBox = new JComboBox();
    84         consoleComboBox.setActionCommand("deployment.console.startup.mode"); // The property this comboBox affects.
     143        consoleComboBox.setActionCommand(DeploymentConfiguration.KEY_CONSOLE_STARTUP_MODE); // The property this comboBox affects.
    85144
    86145        JPanel consolePanel = new JPanel();
     
    99158         */
    100159        for (int i = 0; i < properties.length; i++) {
    101             try {
    102                 String s = config.getProperty(properties[i]);
    103                 c.gridy = i + 1;
    104 
    105                 switch (i) {
    106                     case 0:
    107                     case 1:
    108                         debuggingOptions[i].setSelected(Boolean.parseBoolean(s));
    109                         debuggingOptions[i].setActionCommand(properties[i]);
    110                         debuggingOptions[i].addItemListener(this);
    111                         add(debuggingOptions[i], c);
    112                         break;
    113                     case 2:
    114                         for (int j = 0; j < javaConsoleItems.length; j++) {
    115                             consoleComboBox.addItem(javaConsoleItems[j]);
    116                             if (config.getProperty("deployment.console.startup.mode").equals(javaConsoleItems[j].getValue()))
    117                                 consoleComboBox.setSelectedIndex(j);
    118                         }
    119                         consoleComboBox.addItemListener(this);
    120                         add(consolePanel, c);
    121                 }
    122 
    123             } catch (Exception e) {
    124                 debuggingOptions[i] = null;
     160            String s = config.getProperty(properties[i]);
     161            c.gridy++;
     162            if (i == 2) {
     163                JLabel space = new JLabel("<html>" + Translator.R("CPDebuggingPossibilites") + ":</html>");
     164                add(space, c);
     165                c.gridy++;
     166            }
     167
     168            debuggingOptions[i].setSelected(Boolean.parseBoolean(s));
     169            debuggingOptions[i].setActionCommand(properties[i]);
     170            debuggingOptions[i].setToolTipText(hints[i]);
     171            debuggingOptions[i].addItemListener(this);
     172            add(debuggingOptions[i], c);
     173
     174              if (i == 2) {
     175                 c.gridx++;
     176                add(logsDestinationTitle, c);
     177                c.gridx++;
     178                add(logsDestination, c);
     179                c.gridx++;
     180                add(logsDestinationReset, c);
     181                c.gridx-=3;
    125182            }
    126183        }
    127184
     185
     186        for (int j = 0; j < javaConsoleItems.length; j++) {
     187            consoleComboBox.addItem(javaConsoleItems[j]);
     188            if (config.getProperty(DeploymentConfiguration.KEY_CONSOLE_STARTUP_MODE).equals(javaConsoleItems[j].getValue())) {
     189                consoleComboBox.setSelectedIndex(j);
     190            }
     191        }
     192        c.gridy++;
     193        consoleComboBox.addItemListener(this);
     194        add(consolePanel, c);
     195       
    128196        // pack the bottom so that it doesn't change size if resized.
    129197        Component filler = Box.createRigidArea(new Dimension(1, 1));
     
    134202
    135203    @Override
     204    @SuppressWarnings("unchecked")
    136205    public void itemStateChanged(ItemEvent e) {
    137206
  • trunk/icedtea-web/netx/net/sourceforge/jnlp/controlpanel/DesktopShortcutPanel.java

    r348 r429  
    7373        for (int j = 0; j < items.length; j++) {
    7474            shortcutComboOptions.addItem(items[j]);
    75             if (config.getProperty("deployment.javaws.shortcut").equals(items[j].getValue()))
     75            if (config.getProperty("deployment.javaws.shortcut").equals(items[j].getValue())) {
    7676                shortcutComboOptions.setSelectedIndex(j);
     77            }
    7778        }
    7879
  • trunk/icedtea-web/netx/net/sourceforge/jnlp/controlpanel/DocumentAdapter.java

    r348 r429  
    2424
    2525import net.sourceforge.jnlp.config.DeploymentConfiguration;
     26import net.sourceforge.jnlp.util.logging.OutputController;
    2627
    2728/**
     
    9596            }
    9697        } catch (BadLocationException e1) {
    97             // TODO Auto-generated catch block
    98             e1.printStackTrace();
     98            OutputController.getLogger().log(OutputController.Level.ERROR_ALL, e1);
    9999        }
    100100    }
  • trunk/icedtea-web/netx/net/sourceforge/jnlp/controlpanel/TemporaryInternetFilesPanel.java

    r418 r429  
    110110            @Override
    111111            public void actionPerformed(ActionEvent e) {
    112                 JFileChooser fileChooser = new JFileChooser();
     112                JFileChooser fileChooser = new JFileChooser(location.getText());
    113113                fileChooser.setFileSelectionMode(JFileChooser.DIRECTORIES_ONLY);
    114114                fileChooser.setFileHidingEnabled(false);
    115                 if (fileChooser.showOpenDialog(null) == JFileChooser.APPROVE_OPTION) {
     115                fileChooser.setAcceptAllFileFilterUsed(false);
     116                fileChooser.setDialogTitle(Translator.R("TIFPLocationLabel"));
     117                if (fileChooser.showDialog(null, Translator.R("TIFPFileChooserChooseButton")) == JFileChooser.APPROVE_OPTION) {
    116118                    // Check if we have permission to write to that location.
    117119                    String result = fileChooser.getSelectedFile().getAbsolutePath();
  • trunk/icedtea-web/netx/net/sourceforge/jnlp/resources/Messages.properties

    r418 r429  
    1313ButProceed=Proceed
    1414ButRun=Run
     15ButSandbox=Sandbox
    1516ButApply=Apply
    1617ButDone=Done
    1718ButShowDetails=Show Details
    1819ButHideDetails=Hide Details
     20ButYes=Yes
     21ButNo=No
     22
     23CertWarnRunTip=Trust this applet and run with full permissions
     24CertWarnSandboxTip=Do not trust this applet and run with restricted permissions
     25CertWarnCancelTip=Do not run this applet
     26CertWarnPolicyTip=Advanced sandbox settings
     27CertWarnPolicyEditorItem=Launch PolicyEditor
    1928
    2029AFileOnTheMachine=a file on the machine
     
    2231Usage=Usage:
    2332Error=Error
     33Warning=Warning
    2434
    2535Continue=Do you want to continue?
     
    3343Value=Value
    3444Version=Version
     45
     46# about dialogue
     47AboutDialogueTabAbout=About
     48AboutDialogueTabAuthors=Authors
     49AboutDialogueTabChangelog=Changelog
     50AboutDialogueTabNews=News
     51AboutDialogueTabGPLv2=GPLv2
     52
     53# missing permissions dialogue
     54MissingPermissionsMainTitle=Application <span color='red'> {0} </span> \
     55from <span color='red'> {1} </span> is missing the permissions attribute. \
     56Applications without this attribute should not be trusted. Do you wish to allow this application to run?
     57MissingPermissionsInfo=For more information you can visit:<br/>\
     58<a href="http://docs.oracle.com/javase/7/docs/technotes/guides/jweb/security/manifest.html#permissions"> \
     59JAR File Manifest Attributes</a> <br/> \
     60and<br/> <a href="http://docs.oracle.com/javase/7/docs/technotes/guides/jweb/security/no_redeploy.html"> \
     61Preventing the repurposing of Applications</a>
     62
     63# missing Application-Library-Allowable-Codebase dialogue
     64ALACAMissingMainTitle=The application <span color='red'> {0} </span> \
     65from <span color='red'> {1} </span> uses resources from the following remote locations: \
     66{2} \
     67Are you sure you want to run this application?
     68ALACAMissingInfo=For more information see:<br/>\
     69<a href="http://docs.oracle.com/javase/7/docs/technotes/guides/jweb/security/manifest.html#app_library"> \
     70JAR File Manifest Attributes</a> <br/> \
     71and<br/> <a href="http://docs.oracle.com/javase/7/docs/technotes/guides/jweb/security/no_redeploy.html"> \
     72Preventing the Repurposing of an Application</a>
     73
     74# matching Application-Library-Allowable-Codebase dialogue
     75ALACAMatchingMainTitle=The application <span color='red'> {0} </span> \
     76from <span color='red'> {1} </span> uses resources from the following remote locations:<br/>{2} <br/> \
     77Are you sure you want to run this application?
     78ALACAMatchingInfo=For more information you can visit:<br/>\
     79<a href="http://docs.oracle.com/javase/7/docs/technotes/guides/jweb/security/manifest.html#app_library"> \
     80JAR File Manifest Attributes</a> <br/> \
     81and<br/> <a href="http://docs.oracle.com/javase/7/docs/technotes/guides/jweb/security/no_redeploy.html"> \
     82Preventing the Repurposing of an Application</a>
    3583
    3684# LS - Severity
     
    52100 
    53101LThreadInterrupted=Thread interrupted while waiting for file to launch.
    54 LThreadInterruptedInfo=
     102LThreadInterruptedInfo=This can lead to deadlock or yield other damage during execution. Please restart your application/browser.
    55103LCouldNotLaunch=Could not launch JNLP file.
    56 LCouldNotLaunchInfo=
     104LCouldNotLaunchInfo=The application has not been initialized, for more information execute javaws/browser from the command line and send a bug report.
    57105LCantRead=Could not read or parse the JNLP file.
    58 LCantReadInfo=
     106LCantReadInfo=You can try to download this file manually and send it as bug report to IcedTea-Web team.
    59107LNullLocation=Could not determine .jnlp file location.
    60108LNullLocationInfo=An attempt was made to launch a JNLP file in another JVM, but the file could not be located.  In order to launch in an external JVM, the runtime must be able to locate the .jnlp file either in the local filesystem or on a server.
     
    70118LNoInstallersInfo=JNLP installer files are not yet supported.
    71119LInitApplet=Could not initialize applet.
    72 LInitAppletInfo=
     120LInitAppletInfo=For more information click "more information button".
    73121LInitApplication=Could not initialize application.
    74 LInitApplicationInfo=
     122LInitApplicationInfo=The application has not been initialized, for more information execute javaws from the command line.
    75123LNotLaunchable=Not a launchable JNLP file.
    76124LNotLaunchableInfo=File must be a JNLP application, applet, or installer type.
     
    79127LUnsignedJarWithSecurity=Cannot grant permissions to unsigned jars.
    80128LUnsignedJarWithSecurityInfo=Application requested security permissions, but jars are not signed.
     129LSignedJNLPAppDifferentCerts=The JNLP application is not fully signed by a single cert.
     130LSignedJNLPAppDifferentCertsInfo=The JNLP application has its components individually signed, however there must be a common signer to all entries.
     131LUnsignedApplet=The applet was unsigned.
     132LUnsignedAppletPolicyDenied=The applet was unsigned, and the security policy prevented it from running.
     133LUnsignedAppletUserDenied=The applet was unsigned, and was not trusted.
     134LPartiallySignedApplet=The applet was partially signed.
     135LPartiallySignedAppletUserDenied=The applet was partially signed, and the user did not trust it.
    81136LSignedAppJarUsingUnsignedJar=Signed application using unsigned jars.
    82137LSignedAppJarUsingUnsignedJarInfo=The main application jar is signed, but some of the jars it is using aren't.
     138LRunInSandboxError=Run in Sandbox call performed too late.
     139LRunInSandboxErrorInfo=The classloader was notified to run the applet sandboxed, but security settings were already initialized.
    83140LSignedJNLPFileDidNotMatch=The signed JNLP file did not match the launching JNLP file.
    84141LNoSecInstance=Error: No security instance for {0}. The application may have trouble continuing
    85142LCertFoundIn={0} found in cacerts ({1})
     143LSingleInstanceExists=Another instance of this applet already exists and only one may be run at the same time.
    86144 
    87145JNotApplet=File is not an applet.
     
    94152LCancelOnUserRequest=Canceled on user request.
    95153LFatalVerification=A fatal error occurred while trying to verify jars.
    96 LFatalVerificationInfo=
     154LFatalVerificationInfo=An exception has been thrown in class JarCertVerifier. Being unable to read the cacerts or trusted.certs files could be a possible cause for this exception.
    97155
    98156LNotVerifiedDialog=Not all jars could be verified.
     
    100158
    101159# Parser
    102 PInvalidRoot=Root node is not a jnlp node
    103 PNoResources=No resources section defined
     160PInvalidRoot=Root element is not a jnlp element.
     161PNoResources=No resources element specified.
    104162PUntrustedNative=nativelib element cannot be specified unless a trusted environment is requested.
    105163PExtensionHasJ2SE=j2se element cannot be specified in a component extension file.
    106164PInnerJ2SE=j2se element cannot be specified within a j2se element.
    107 PTwoMains=Duplicate main JAR defined in a resources element (there can be only one)
    108 PNativeHasMain=Cannot specify main attribute on native JARs.
    109 PNoInfoElement=No information section defined.
     165PTwoMains=Duplicate main attribute specified on a resources element (there can be only one)
     166PNativeHasMain=main attribute cannot be specified on a nativelib element.
     167PNoInfoElement=No information element specified.
    110168PMissingTitle=title
    111169PMissingVendor=vendor
    112 PMissingElement=The {0} section has not been defined for your locale nor does a default value exist in the JNLP file.
    113 PTwoDescriptions=Duplicate description of kind {0}
    114 PSharing=Element "sharing-allowed" is illegal in a standard JNLP file
    115 PTwoSecurity=Only one security element allowed per JNLPFile.
    116 PEmptySecurity=Security element specified but does not contain a permissions element.
    117 PTwoDescriptors=Only one application descriptor element allowed per JNLPFile.
     170PMissingElement=The {0} section has not been specified for your locale nor does a default value exist in the JNLP file.
     171PTwoDescriptions=Duplicate description elements of kind {0} are illegal.
     172PSharing=sharing-allowed element is illegal in a standard JNLP file
     173PTwoSecurity=Only one security element allowed per JNLP file.
     174PEmptySecurity=security element specified but does not contain a permissions element.
     175PTwoDescriptors=Only one application-desc element allowed per JNLP file.
    118176PTwoDesktops=Only one desktop element allowed
    119177PTwoMenus=Only one menu element allowed
     
    133191# Runtime
    134192BLaunchAbout=Launching about window...
     193BLaunchAboutFailure=Was not able to launch About window
    135194BNeedsFile=Must specify a .jnlp file
    136195RNoAboutJnlp=Unable to find about.jnlp
     
    139198BBadParam=Incorrect parameter format {0} (should be name=value)
    140199BNoDir=Directory {0} does not exist.
     200BNoCodeOrObjectApplet=Applet tag must specify a 'code' or 'object' attribute.
    141201RNoResource=Missing Resource: {0}
    142202RShutdown=This exception to prevent shutdown of JVM, but the process has been terminated.
     
    145205RCantCreateFile=Cant create file {0}
    146206RCantDeleteFile=Cant delete file {0}
     207RCantOpenFile=Could not open file {0}
     208RCantWriteFile=Could not write to file {0}
     209RFileReadOnly=Opening file in read-only mode
     210RExpectedFile=Expected {0} to be a file but it was not
    147211RRemoveRPermFailed=Removing read permission on file {0} failed
    148212RRemoveWPermFailed=Removing write permissions on file {0} failed
     
    158222RNestedJarExtration=Unable to extract nested jar.
    159223RUnexpected=Unexpected {0} at {1}
    160 RConfigurationError=Fatal error while reading the configuration
     224RConfigurationError=Fatal error while reading the configuration, continuing with empty. Please fix
    161225RConfigurationFatal=ERROR: a fatal error has occurred while loading configuration. Perhaps a global configuration was required but could not be found
     226RFailingToDefault=Failing to default configuration
    162227RPRoxyPacNotSupported=Using Proxy Auto Config (PAC) files is not supported.
    163228RProxyFirefoxNotFound=Unable to use Firefox's proxy settings. Using "DIRECT" as proxy type.
     
    166231RBrowserLocationPromptMessage=Specify Browser Location
    167232RBrowserLocationPromptMessageWithReason=Specify Browser Location (the browser command "{0}" is invalid).
     233BAboutITW=The IcedTea-Web project provides a Free Software web browser plugin running applets written in the Java programming language and an implementation of Java Web Start, originally based on the NetX project. Visit the IcedTea-Web homepage: http://icedtea.classpath.org/wiki/IcedTea-Web . Use "man javaws" or "javaws -help" for more information.
     234BFileInfoAuthors=Names and email addresses of contributors to this project can be found in the file AUTHORS in the IcedTea-Web root directory.
     235BFileInfoCopying=The full GPLv2 license of this project can be found in the file COPYING in the IcedTea-Web root directory.
     236BFileInfoNews=News about releases of this project can be found in the file NEWS in the IcedTea-Web root directory.
    168237
    169238# Boot options, message should be shorter than this ---------------->
     
    174243BOParam     = Adds an applet parameter before launching.
    175244BOProperty  = Sets a system property before launching.
    176 BOUpdate    = Update check if seconds since last checked.
     245BOUpdate    = Check for updates.
    177246BOLicense   = Display the GPL license and exit.
    178247BOVerbose   = Enable verbose output.
    179248BOAbout     = Shows a sample application.
     249BOVersion   = Print the IcedTea-Web version and exit.
    180250BONosecurity= Disables the secure runtime environment.
    181251BONoupdate  = Disables checking for updates.
     
    183253BOStrict    = Enables strict checking of JNLP file format.
    184254BOViewer    = Shows the trusted certificate viewer.
     255BOXml       = Uses a strict XML parser to parse the JNLP file.
     256BOredirect  = Follows HTTP redirects.
    185257BXnofork    = Do not create another JVM.
    186258BXclearcache= Clean the JNLP application cache.
     259BXignoreheaders= Skip jar header verification.
    187260BOHelp      = Print this message and exit.
    188261
     
    193266CComplete=Complete
    194267CChooseCache=Choose a cache directory...
    195 CChooseCacheInfo=Netx needs a location for storing cache files.
     268CChooseCacheInfo=NetX needs a location for storing cache files.
    196269CChooseCacheDir=Cache directory
    197 CCannotClearCache=Can not clear cache at this time
     270CCannotClearCache=Can not clear the cache at this time. Try later. If the problem persists, try closing your browser(s) & JNLP applications. At the end you can try to kill all java applications. \\\n You can clear cache by javaws -Xclearcache or via itw-settings Cache -> View files -> Purge
    198271CFakeCache=Cache is corrupt. Fixing.
    199 CFakedCache=Cache is corrupt and has been fixed. It is strongly recommended that you run 'javaws -Xclearcache' and rerun your application as soon as possible.
     272CFakedCache=Cache was corrupt and has been fixed. It is strongly recommended that you run 'javaws -Xclearcache' and rerun your application as soon as possible. You can also use via itw-settings Cache -> View files -> Purge
    200273
    201274# Security
     
    203276SFileWriteAccess=The application has requested write access to {0}. Do you want to allow this action?
    204277SDesktopShortcut=The application has requested permission to create a desktop launcher. Do you want to allow this action?
    205 SSigUnverified=The application's digital signature cannot be verified. Do you want to run the application?
    206 SSigVerified=The application's digital signature has been verified. Do you want to run the application?
    207 SSignatureError=The application's digital signature has an error. Do you want to run the application?
     278SSigUnverified=The application's digital signature cannot be verified. Do you want to run the application? It will be granted unrestricted access to your computer.
     279SSigVerified=The application's digital signature has been verified. Do you want to run the application? It will be granted unrestricted access to your computer.
     280SSignatureError=The application's digital signature has an error. Do you want to run the application? It will be granted unrestricted access to your computer.
    208281SUntrustedSource=The digital signature could not be verified by a trusted source. Only run if you trust the origin of the application.
    209 SWarnFullPermissionsIgnorePolicy=The code executed will be given full permissions, ignoring any java policies you may have.
     282SWarnFullPermissionsIgnorePolicy=The code executed will be given full permissions, ignoring any Java policies you may have.
    210283STrustedSource=The digital signature has been validated by a trusted source.
    211284SClipboardReadAccess=The application has requested read-only access to the system clipboard. Do you want to allow this action?
     
    217290SAlwaysTrustPublisher=Always trust content from this publisher
    218291SHttpsUnverified=The website's HTTPS certificate cannot be verified.
    219 SNotAllSignedSummary=Only parts of this application code are signed.
    220 SNotAllSignedDetail=This application contains both signed and unsigned code. While signed code is safe if you trust the provider, unsigned code may imply code outside of the trusted provider's control.
    221 SNotAllSignedQuestion=Do you wish to proceed and run this application anyway?
     292SRememberOption=<b>Remember this option?</b>
     293SRememberAppletOnly=For applet
     294SRememberCodebase=For site <u>{0}</u>
     295SUnsignedSummary=An unsigned Java application wants to run
     296SUnsignedDetail=An unsigned application from the following location wants to run:<br/>&nbsp;&nbsp;<u>{0}</u><br/>The page which made the request was:<br/>&nbsp;&nbsp;<u>{1}</u><br/><br/><b>It is recommended you only run applications from sites you trust.</b>
     297SUnsignedAllowedBefore=<font color="green">You have accepted this applet previously.</font>
     298SUnsignedRejectedBefore=<font color="red">You have rejected this applet previously.</font>
     299SUnsignedQuestion=Allow the applet to run?
     300SPartiallySignedSummary=Only parts of this application code are signed.
     301SPartiallySignedDetail=This application contains both signed and unsigned code. While signed code is safe if you trust the provider, unsigned code may imply code outside of the trusted provider's control.
     302SPartiallySignedQuestion=Do you wish to proceed and run this application anyway?
    222303SAuthenticationPrompt=The {0} server at {1} is requesting authentication. It says "{2}"
    223304SJNLPFileIsNotSigned=This application contains a digital signature in which the launching JNLP file is not signed.
     305SAppletTitle=Applet title: {0}
     306STrustedOnlyAttributeFailure=This application specifies Trusted-only as True in its Manifest. {0} and requests permission level: {1}. This is not allowed.
     307STOAsignedMsgFully = The applet is fully signed
     308STOAsignedMsgAndSandbox = The applet is fully signed and sandboxed
     309STOAsignedMsgPartiall = The applet is not fully signed
     310STempPermNoFile=No file access
     311STempPermNoNetwork=No network access
     312STempPermNoExec=No command execution
     313STempNoFileOrNetwork=No file or network access
     314STempNoExecOrNetwork=No command execution or network access
     315STempNoFileOrExec=No file access or command execution
     316STempNoFileOrNetworkOrExec=No file access, network access, or command execution
     317STempAllMedia=All media
     318STempSoundOnly=Play audio
     319STempClipboardOnly=Access clipboard
     320STempPrintOnly=Print documents
     321STempAllFileAndPropertyAccess=All file and properties access
     322STempReadLocalFilesAndProperties=Read-only local files and properties
     323STempReflectionOnly=Java Reflection only
    224324
    225325# Security - used for the More Information dialog
     
    227327SBadExtendedKeyUsage=Resources contain entries whose signer certificate's ExtendedKeyUsage extension doesn't allow code signing.
    228328SBadNetscapeCertType=Resources contain entries whose signer certificate's NetscapeCertType extension doesn't allow code signing.
    229 SHasUnsignedEntry=Resources contain unsigned entries which have not been integrity-checked.
    230329SHasExpiredCert=The digital signature has expired.
    231330SHasExpiringCert=Resources contain entries whose signer certificate will expire within six months.
     
    233332SUntrustedCertificate=The digital signature was generated with an untrusted certificate.
    234333STrustedCertificate=The digital signature was generated with a trusted certificate.
    235 SCNMisMatch=The expected hostname for this certificate is: "{0}"<BR>The address being connected to is: "{1}"
    236 SRunWithoutRestrictions=This application will be run without the security restrictions normally provided by java.
     334SCNMisMatch=The expected hostname for this certificate is: "{0}"<br/>The address being connected to is: "{1}"
     335SRunWithoutRestrictions=This application will be run without the security restrictions normally provided by Java.
    237336SCertificateDetails=Certificate Details
    238337
     
    264363CVSystem=System
    265364
    266 #KeyStores: see KeyStores.java
     365# KeyStores: see KeyStores.java
    267366KS=KeyStore
    268367KSCerts=Trusted Certificates
    269368KSJsseCerts=Trusted JSSE Certificates
    270369KSCaCerts=Trusted Root CA Certificates
    271 KSJsseCaCerts=Trusted JSSE Root CA Certificates,
     370KSJsseCaCerts=Trusted JSSE Root CA Certificates
    272371KSClientCerts=Client Authentication Certificates
    273372
     
    277376DCSourceInternal=<internal>
    278377DCUnknownSettingWithName=Property "{0}" is unknown.
     378DCmaindircheckNotexists=After all attempts, your configuration directory {0} do not exists.
     379DCmaindircheckNotdir=Your configuration directory {0} is not directory.
     380DCmaindircheckRwproblem=Your configuration directory {0} can not be read/written properly.
    279381
    280382# Value Validator messages. Messages should follow "Possible values ..."
    281383VVPossibleValues=Possible values {0}
    282384VVPossibleBooleanValues=are {0} or {1}
    283 VVPossibleFileValues=include the absolute location of a file - it must begin with a /
    284 VVPossibleFileValuesDOS=include the absolute location of a file - it must begin with a drive letter
     385VVPossibleFileValues=include an absolute path to a file or directory
    285386VVPossibleRangedIntegerValues=are in range {0} to {1} (inclusive)
    286387VVPossibleUrlValues=include any valid url (eg http://icedtea.classpath.org/hg/)
     
    291392
    292393# Control Panel - Tab Descriptions
    293 CPAboutDescription=View version information about Icedtea Control Panel.
     394CPAboutDescription=View version information about IcedTea Control Panel.
    294395CPNetworkSettingsDescription=Configure network settings, including how IcedTea-Web connects to the internet and whether to use any proxies.
    295396CPTempInternetFilesDescription=Java stores application data for faster execution the next time you run it.
     
    299400CPDebuggingDescription=Enable options here to help with debugging
    300401CPDesktopIntegrationDescription=Set whether or not to allow creation of desktop shortcut.
     402CPJVMPluginArguments=Set JVM arguments for plugin.
     403CPJVMitwExec=Set JVM for IcedTea-Web \u2014 working best with OpenJDK
     404CPJVMitwExecValidation=Validate JVM for IcedTea-Web
     405CPJVMPluginSelectExec=Browse for JVM for IcedTea-Web
     406CPJVMnone=No validation result for
     407CPJVMvalidated=Validation result for
     408CPJVMvalueNotSet=Value is not set. Hardcoded JVM will be used.
     409CPJVMnotLaunched=Error, process was not launched, see console output for more info.
     410CPJVMnoSuccess=Error, process have not ended successfully, see output for details, but your java is not set correctly.
     411CPJVMopenJdkFound=Excellent, OpenJDK detected
     412CPJVMoracleFound=Great, Oracle java detected
     413CPJVMibmFound=Good, IBM java detected
     414CPJVMgijFound=Warning, gij detected
     415CPJVMstrangeProcess=Your path had an executable process, but it was not recognized. Verify the Java version in the console output.
     416CPJVMnotDir=Error, The path you chose is not a directory.
     417CPJVMisDir=Ok, the path you chose is a directory.
     418CPJVMnoJava=Error, the directory you chose does not contain bin/java.
     419CPJVMjava=Ok, the directory you chose contains bin/java.
     420CPJVMnoRtJar=Error, the directory you chose does not contain lib/rt.jar
     421CPJVMrtJar=Ok, the directory you chose contains lib/rt.jar.
     422CPJVMPluginAllowTTValidation=Validate JRE immediately
     423CPJVMNotokMessage1=You have entered invalid JDK value <u>({0})</u> with following error message:
     424CPJVMNotokMessage2=You might be seeing this message because: <blockquote> * Some validity tests have not been passed<br/> * Non-OpenJDK is detected</blockquote>With invalid JDK IcedTea-Web will probably not be able to start.<br/>You will have to modify or remove <u>{0}</u> property in your configuration file <u>{1}</u>. <br/>You should try to search for OpenJDK in your system or be sure you know what you are doing.
     425CPJVMconfirmInvalidJdkTitle=Confirm invalid JDK
     426CPJVMconfirmReset=Reset to default?
     427CPPolicyDetail=View or edit your user-level Java Policy File. This allows you to grant or deny runtime permissions to applets regardless of the standard security sandboxing rules.
     428CPPolicyTooltip=Open {0} in policy editor
     429CPPolicyEditorNotFound=Could not find a system policy file editor. Check that policytool is on your PATH.
    301430
    302431# Control Panel - Buttons
     
    306435CPButView=View...
    307436CPButCertificates=Certificates...
     437CPButSimpleEditor=Simple editor
     438CPButAdvancedEditor=Advanced editor
    308439
    309440# Control Panel - Headers
    310 CPHead=IcedTea Web Control Panel
    311 CPHeadAbout=About
    312 CPHeadNetworkSettings=Network Proxy Settings
    313 CPHeadTempInternetFiles=Temporary Internet Files
    314 CPHeadJRESettings=Java Runtime Environment Settings
    315 CPHeadCertificates=Certificates
    316 CPHeadDebugging=Debugging Settings
    317 CPHeadDesktopIntegration=Desktop Integrations
    318 CPHeadSecurity=Security Settings
     441CPHead=IcedTea-Web Control Panel
     442CPHeadAbout=\u00a0About\u00a0IcedTea-Web\u00a0
     443CPHeadNetworkSettings=\u00a0Network\u00a0Proxy\u00a0Settings\u00a0
     444CPHeadTempInternetFiles=\u00a0Temporary\u00a0Internet\u00a0Files\u00a0
     445CPHeadJRESettings=\u00a0Java\u00a0Runtime\u00a0Environment\u00a0Settings\u00a0
     446CPHeadCertificates=\u00a0Certificates\u00a0
     447CPHeadDebugging=\u00a0Debugging\u00a0Settings\u00a0
     448CPHeadDesktopIntegration=\u00a0Desktop\u00a0Integrations\u00a0
     449CPHeadSecurity=\u00a0Security\u00a0Settings\u00a0
     450CPHeadJVMSettings=\u00a0JVM\u00a0Settings\u00a0
     451CPHeadPolicy=\u00a0Custom\u00a0Policy\u00a0Settings\u00a0
    319452
    320453# Control Panel - Tabs
     
    328461CPTabRuntimes=Runtimes
    329462CPTabSecurity=Security
     463CPTabJVMSettings=JVM Settings
     464CPTabPolicy=Policy Settings
    330465
    331466# Control Panel - AboutPanel
    332 CPAboutInfo=This is the control panel for setting deployments.properties.<br/>Not all options will take effect until implemented.<br/>The use of multiple JREs is currently unsupported.<br/>
     467CPAboutInfo=This is the control panel for setting deployments.properties.<br/>Not all options will take effect until implemented.<br/>The use of multiple JREs is currently limited to OpenJDK.<br/>
    333468
    334469# Control Panel - AdvancedProxySettings
     
    348483
    349484# Control Panel - DebugginPanel
    350 DPEnableTracing=Enable tracing
    351 DPEnableLogging=Enable logging
     485CPDebuggingPossibilites=Logging outputs
     486DPEnableLogging=Enable debugging
     487DPEnableLoggingHint=When this switch is on,  then also debug messages are logged. Same as -verbose or ICEDTEAPLUGIN_DEBUG=true
     488DPEnableHeaders=Enable headers
     489DPEnableHeadersHint=When this switch is on, each logged message have header with additional information like user, place in code  and time
     490DPEnableFile=Enable logging to file
     491CPFilesLogsDestDir=File logs directory
     492CPFilesLogsDestDirResert=Reset to default
     493DPEnableFileHint=output messages will be saved to file in your {0}  directory
     494DPEnableStds=Enable logging to standard outputs
     495DPEnableStdsHint=messages will be printed to standard outputs
     496DPEnableSyslog=Enable logging to system logs
     497DPEnableSyslogHint=output messages will be saved to system logs
    352498DPDisable=Disable
    353499DPHide=Hide on startup
    354500DPShow=Show on startup
     501DPShowPluginOnly=Show on plugin startup
     502DPShowJavawsOnly=Show on javaws startup
    355503DPJavaConsole=Java Console
     504DPJavaConsoleDisabledHint=Java console is disabled. Use itweb-settings to configure it out of disabled to any show or hide value.
     505
     506# PolicyEditor
     507PEUsage=policyeditor [-file policyfile]
     508PEHelpFlag=Print this message and exit
     509PEFileFlag=Specify a policyfile path to open
     510PECodebaseFlag=Specify (a) codebase URL(s) to add and/or focus in the editor
     511PETitle=Policy Editor
     512PEReadProps=Read system properties
     513PEReadPropsDetail=Allow applets to read system properties such as your username and home directory location
     514PEWriteProps=Write system properties
     515PEWritePropsDetail=Allow applets to (over)write system properties
     516PEReadFiles=Read from local files
     517PEReadFilesDetail=Allow applets to read from files in your home directory
     518PEWriteFiles=Write to local files
     519PEWriteFilesDetail=Allow applets to write to files in your home directory
     520PEDeleteFiles=Delete local files
     521PEDeleteFilesDetail=Allow applets to delete files in your home directory
     522PEReadSystemFiles=Read all system files
     523PEReadSystemFilesDetail=Allow applets read-only access to all locations on your computer
     524PEWriteSystemFiles=Write all system files
     525PEWriteSystemFilesDetail=Allow applets write-only access to all locations on your computer
     526PEReadTempFiles=Read from temp files
     527PEReadTempFilesDetail=Allow applets to read from your temporary files directory
     528PEWriteTempFiles=Write to temp files
     529PEWriteTempFilesDetail=Allow applets to write to your temporary files directory
     530PEDeleteTempFiles=Delete temp files
     531PEDeleteTempFilesDetail=Allow applets to delete files in your temporary files directory
     532PEAWTPermission=Window System Access
     533PEAWTPermissionDetail=Allow applets all AWT windowing system access
     534PEClipboard=Access clipboard
     535PEClipboardDetail=Allow applets to read from and write to your clipboard
     536PENetwork=Access the network
     537PENetworkDetail=Allow applets to establish any network connections
     538PEPrint=Print documents
     539PEPrintDetail=Allow applets to queue print jobs
     540PEPlayAudio=Play sounds
     541PEPlayAudioDetail=Allow applets to play sounds, but not record
     542PERecordAudio=Record audio
     543PERecordAudioDetail=Allow applets to record audio, but not play back
     544PEReflection=Java reflection
     545PEReflectionDetail=Allow applets to access the Java Reflection API
     546PEClassLoader=Get ClassLoader
     547PEClassLoaderDetail=Allow applets to access the system classloader (often used with Reflection)
     548PEClassInPackage=Access other packages
     549PEClassInPackageDetail=Allow applets to access classes from other applet packages (often used with Reflection)
     550PEDeclaredMembers=Access private class data
     551PEDeclaredMembersDetail=Allow applets to access normally hidden data from other Java classes (often used with Reflection)
     552PEAccessThreads=Modify threads
     553PEAccessThreadsDetail=Allow applets to start, stop, and otherwise manage threads
     554PEAccessThreadGroups=Modify threadgroups
     555PEAccessThreadGroupsDetail=Allow applets to start, stop, and otherwise manage thread groups
     556PEExec=Execute commands
     557PEExecDetail=Allow applets to execute system commands
     558PEGetEnv=Get environment variables
     559PEGetEnvDetail=Allow applets to read system environment variables
     560PECouldNotOpen=Unable to open policy file
     561PECouldNotSave=Unable to save policy file
     562PEAddCodebase=Add new Codebase
     563PERemoveCodebase=Remove
     564PECodebasePrompt=Enter a new codebase
     565PEGlobalSettings=All Applets
     566PESaveChanges=Save changes before exiting?
     567PEChangesSaved=Changes saved
     568PECheckboxLabel=Permissions
     569PECodebaseLabel=Codebases
     570PEFileMenu=File
     571PEOpenMenuItem=Open...
     572PESaveMenuItem=Save
     573PESaveAsMenuItem=Save As...
     574PEExitMenuItem=Exit
     575PEViewMenu=View
     576PECustomPermissionsItem=Custom Permissions...
     577PEFileModified=File Modification Warning
     578PEFileModifiedDetail=The policy file at {0} has been modified since it was opened. Reload and re-edit before saving?
     579PEGAccesUnowenedCode = Execute unowned code
     580PEGMediaAccess = Media access
     581PEGrightClick = right click to fold/unfold
     582PEGReadFileSystem = Read to system
     583PEGWriteFileSystem = Write to system
     584
     585
     586# Policy Editor CustomPolicyViewer
     587PECPTitle=Custom Policy Viewer
     588PECPListLabel=Other policies for {0}
     589PECPAddButton=Add
     590PECPRemoveButton=Remove
     591PECPCloseButton=Close
     592PECPType=type
     593PECPTarget=target
     594PECPActions=actions
     595PECPPrompt=Enter a custom permission. Do not include \"permission\" or punctuation marks.
     596
     597# PolicyEditor key mnemonics. See KeyEvent.VK_*
     598# N
     599PEAddCodebaseMnemonic=78
     600# R
     601PERemoveCodebaseMnemonic=82
     602# A
     603PEOkButtonMnemonic=65
     604# C
     605PECancelButtonMnemonic=67
     606# F
     607PEFileMenuMnemonic=70
     608# I
     609PEViewMenuMnemonic=73
     610# O
     611PEOpenMenuItemMnemonic=79
     612# S
     613PESaveMenuItemMnemonic=83
     614# A
     615PESaveAsMenuItemMnemonic=65
     616# X
     617PEExitMenuItemMnemonic=88
     618# U
     619PECustomPermissionsItemMnemonic=85
     620
     621#conole itself labels
     622CONSOLErungc = Run GC
     623CONSOLErunFinalizers = Run Finalizers
     624CONSOLErunningFinalizers = Running finalization....
     625CONSOLEmemoryInfo = Memory Info
     626CONSOLEsystemProperties = System Properties
     627CONSOLEclassLoaders = Available Classloaders
     628CONSOLEthreadList = Thread List
     629CONSOLEthread = Thread
     630CONSOLEnoClassLoaders = No Classloader info exists in system
     631CONSOLEmemoryMax = Max Memory
     632CONSOLEmemoryTotal = Total Memory
     633CONSOLEmemoryFree = Free Memory
     634CONSOLEClean=Clear
     635
     636# console output pane labels
     637COPsortCopyAllDate=sort copy all by date
     638COPshowHeaders=Show headers:
     639COPuser=user
     640COPorigin=origin
     641COPlevel=level
     642COPdate=date
     643COPthread1=thread 1
     644COPthread2=thread 2
     645COPShowMessages=Show messages
     646COPstdOut=std. Out
     647COPstdErr=std. Err
     648COPjava=java
     649COPplugin=plugin
     650COPpreInit=pre-init
     651COPpluginOnly=plugin only
     652COPSortBy=Sort by
     653COPregex=Regular expression filter
     654COPAsArrived=As arrived (no sort)
     655COPcode=code
     656COPmessage=message
     657COPSearch=Search
     658COPautoRefresh=auto refresh
     659COPrefresh=refresh
     660COPApply=Apply
     661COPmark=mark
     662COPCopyAllPlain=Copy all (plain)
     663COPCopyAllRich=Copy all (rich)
     664COPnext=next>>>
     665COPprevious=<<<previous
     666COPcaseSensitive=case sensitive
     667COPincomplete=incomplete
     668COPhighlight=highlight
     669COPwordWrap=word wrap
     670COPdebug=debug
     671COPinfo=info
     672COPpostInit=post-init
     673COPcomplete=complete
     674COPmatch=match
     675COPnot=not
     676COPrevert=revert
     677COPitw=IcedTea-Web
     678COPclientApp=Client app.
    356679
    357680# Control Panel - DesktopShortcutPanel
     
    379702
    380703# Control Panel - SecurityGeneralPanel
    381 SGPAllowUserGrantSigned=Allow users to grant permissions to signed content 
    382 SGPAllowUserGrantUntrust=Allow users to grant permissions to content from an untrusted authority 
     704SGPAllowUserGrantSigned=Allow users to grant permissions to signed content
     705SGPAllowUserGrantUntrust=Allow users to grant permissions to content from an untrusted authority
    383706SGPUseBrowserKeystore=Use certificates and keys in browser keystore (Unsupported)
    384707SGPUsePersonalCertOneMatch=Use personal certificate automatically if only one matches server request (Unsupported)
    385 SGPWarnCertHostMismatch=Warn if site certificate does not match hostname 
     708SGPWarnCertHostMismatch=Warn if site certificate does not match hostname
    386709SGPShowValid=Show site certificate even if it is valid (Unsupported)
    387 SGPShowSandboxWarning=Show sandbox warning banner 
    388 SGPAllowUserAcceptJNLPSecurityRequests=Allow user to accept JNLP security requests 
     710SGPShowSandboxWarning=Show sandbox warning banner
     711SGPAllowUserAcceptJNLPSecurityRequests=Allow user to accept JNLP security requests
    389712SGPCheckCertRevocationList=Check certificates for revocation using Certificate Revocation Lists (CRLs) (Unsupported)
    390713SGPEnableOnlineCertValidate=Enable online certificate validation (Unsupported)
     
    398721# Control Panel - TemporaryInternetFilesPanel
    399722TIFPEnableCache=Keep temporary files on my computer
    400 TIFPLocation=Location
     723TIFPLocation=\u00a0Location\u00a0
    401724TIFPLocationLabel=Select the location where temporary files are kept
    402725TIFPChange=Change
    403 TIFPDiskSpace=Disk space
     726TIFPDiskSpace=\u00a0Disk\u00a0space\u00a0
    404727TIFPCompressionLevel=Select the compression level for JAR files
    405728TIFPNone=None
    406729TIFPMax=Max
    407 TIFPCacheSize=Set the amount of disk space for storing temporary files
     730TIFPCacheSize=Set the amount of disk space for storing temporary files (MB)
    408731TIFPDeleteFiles=Delete files
    409732TIFPViewFiles=View files...
     733TIFPFileChooserChooseButton=Choose
    410734
    411735# Control Panel - Cache Viewer
     
    413737CVCPButRefresh=Refresh
    414738CVCPButDelete=Delete
     739CVCPCleanCache=Purge
     740CVCPCleanCacheTip=Some errors may be caused by old files in your cache. Before submitting the bug, you may clear cache and try to run application again. \\\n You can clear cache by javaws -Xclearcache or via itw-settings Cache -> View files -> Purge
    415741CVCPColLastModified=Last Modified
    416742CVCPColSize=Size (Bytes)
     
    438764CLGetDescription=Shows the value for property-name
    439765CLSetDescription=Sets the property-name to value if possible. The value is checked for being valid. If the administrator has locked the property, this will have no effect
    440 CLResetDescription=Resets the value for property-name to it\'s default value
     766CLResetDescription=Resets the value for property-name to it\'s default value.\nall resets all properties recognized by IcedTea-Web to their default value.
    441767CLInfoDescription=Shows more information about the given property
    442 CLCheckDescription=Shows any properties that have been defined but are not recognized by IcedTea Web
    443 CLHelpDescription=The itweb-settings tool allows a user to modify, view and check configuration. \nTo use the GUI, do not pass any arguments. To use the CLI mode, pass in the approrpiate command and parameters. For help with a particular command, try: {0} command help
     768CLCheckDescription=Shows any properties that have been defined but are not recognized by IcedTea-Web
     769CLHelpDescription=The itweb-settings tool allows a user to modify, view and check configuration.\nTo use the GUI, do not pass any arguments. To use the CLI mode, pass in the approrpiate command and parameters. For help with a particular command, try: {0} command help
     770
     771#  splash screen related
     772SPLASHerror = Click here for details. An exception has occurred.
     773SPLASH_ERROR = ERROR
     774SPLASHtitle = Title
     775SPLASHvendor = Vendor
     776SPLASHhomepage = Homepage
     777SPLASHdescription = Description
     778SPLASHClose= Close
     779SPLASHclosewAndCopyException = Close and copy the stack trace to clipboard
     780SPLASHexOccured = An exception has occurred...
     781SPLASHHome = Home
     782SPLASHcantCopyEx = Can not copy exception
     783SPLASHnoExRecorded = No exception recorded
     784SPLASHmainL1 = For even more information you can visit {0} and follow the steps described there on how to obtain necessary information to file bug
     785SPLASHurl = http://icedtea.classpath.org/wiki/IcedTea-Web#Filing_bugs
     786SPLASHurlLooks = http://icedtea.classpath.org/wiki/IcedTea-Web
     787SPLASHmainL3 = No further information available, try to launch the browser from the command line and examine the output.
     788SPLASHcloseAndCopyShorter = Close and copy to clipboard
     789SPLASHmainL4 = The folloing exception has occured. For more information, try to launch the browser from the command line and examine the output.
     790SPLASHmainL2 = Additional information may be available in the console or logs. Even more information is available if debugging is enabled.
     791SPLASHexWas = Exception was:
     792SPLASHcfl = Can't follow link to
     793SPLASHvendorsInfo = Information from vendor of your application
     794SPLASHanotherInfo = Another available info
     795SPLASHdefaultHomepage = Unspecified homepage, verify source rather
     796SPLASHerrorInInformation = Error during loading of information element, verify source rather
     797SPLASHmissingInformation = Information element is missing, verify source rather
     798SPLASHchainWas = This is the list of exceptions that occurred launching your applet. Please note, those exceptions can originate from multiple applets. For a helpful bug report, be sure to run only one applet.
     799
     800CBCheckFile = The application is a local file. Codebase validation is disabled. See: http://docs.oracle.com/javase/7/docs/technotes/guides/jweb/security/no_redeploy.html for details.
     801CBCheckNoEntry = This application does not specify a Codebase in its manifest. Please verify with the applet's vendor. Continuing. See: http://docs.oracle.com/javase/7/docs/technotes/guides/jweb/security/no_redeploy.html for details.
     802CBCheckUnsignedPass = Codebase matches codebase manifest attribute, but application is unsigned. Continuing. See: http://docs.oracle.com/javase/7/docs/technotes/guides/jweb/security/no_redeploy.html for details.
     803CBCheckUnsignedFail= The application's codebase does NOT match the codebase specified in its manifest, but the application is unsigned. Continuing. See: http://docs.oracle.com/javase/7/docs/technotes/guides/jweb/security/no_redeploy.html for details.
     804CBCheckOkSignedOk = Codebase matches codebase manifest attribute, and  application is signed. Continuing. See: http://docs.oracle.com/javase/7/docs/technotes/guides/jweb/security/no_redeploy.html for details.
     805CBCheckSignedAppletDontMatchException = Signed applets are not allowed to run when their actual Codebase does not match the Codebase specified in their manifest. Expected: {0}. Actual: {1}. See: http://docs.oracle.com/javase/7/docs/technotes/guides/jweb/security/no_redeploy.html for details.
     806CBCheckSignedFail = Application Codebase does NOT match the Codebase specified in the application's manifest, and this application is signed. You are strongly discouraged from running this application. See: http://docs.oracle.com/javase/7/docs/technotes/guides/jweb/security/no_redeploy.html for details.
     807
     808APPEXTSECappletSecurityLevelExtraHighId=Disable running of all Java applets
     809APPEXTSECappletSecurityLevelVeryHighId=Very High Security
     810APPEXTSECappletSecurityLevelHighId=High Security
     811APPEXTSECappletSecurityLevelLowId=Low Security
     812APPEXTSECappletSecurityLevelExtraHighExplanation=No applet will be run
     813APPEXTSECappletSecurityLevelVeryHighExplanation=No unsigned applets will be run
     814APPEXTSECappletSecurityLevelHighExplanation=User will be prompted for each unsigned applet
     815APPEXTSECappletSecurityLevelLowExplanation=All, even unsigned, applets will be run
     816APPEXTSECunsignedAppletActionAlways=Always trust this (matching) applet(s)
     817APPEXTSECunsignedAppletActionNever=Never trust this (matching) applet(s)
     818APPEXTSECunsignedAppletActionYes=This applet was visited and allowed
     819APPEXTSecunsignedAppletActionSandbox=This applet was visited and allowed to run with restricted privileges
     820APPEXTSECunsignedAppletActionNo=This applet was visited and denied
     821APPEXTSECControlPanelExtendedAppletSecurityTitle=Extended applet security
     822APPEXTSECguiTableModelTableColumnAction=Action
     823APPEXTSECguiTableModelTableColumnDateOfAction=Date of action
     824APPEXTSECguiTableModelTableColumnDocumentBase=Document-base
     825APPEXTSECguiTableModelTableColumnCodeBase=Code-base
     826APPEXTSECguiTableModelTableColumnArchives=Archives
     827APPEXTSECguiPanelAppletInfoHederPart1={0} {1}
     828APPEXTSECguiPanelAppletInfoHederPart2={0} from  {1}
     829APPEXTSECguiPanelConfirmDeletionOf=Are you sure you want to delete following {0} items
     830APPEXTSECguiPanelHelpButton=Help
     831APPEXTSECguiPanelSecurityLevel=Security Level
     832APPEXTSECguiPanelGlobalBehaviourCaption=Settings of global behavior for applets
     833APPEXTSECguiPanelDeleteMenuSelected=selected
     834APPEXTSECguiPanelDeleteMenuAllA=all allowed (A)
     835APPEXTSECguiPanelDeleteMenuAllN=all forbidden (N)
     836APPEXTSECguiPanelDeleteMenuAlly=all approved (y)
     837APPEXTSECguiPanelDeleteMenuAlln=all rejected (n)
     838APPEXTSECguiPanelDeleteMenuAllAll=absolute all
     839APPEXTSECguiPanelDeleteButton=Delete
     840APPEXTSECguiPanelDeleteButtonToolTip=You can press delete key during browsing the table. It will act as delete selected
     841APPEXTSECguiPanelTestUrlButton=Test url
     842APPEXTSECguiPanelAddRowButton=Add new row
     843APPEXTSECguiPanelValidateTableButton=Validate table
     844APPEXTSECguiPanelAskeforeActionBox=Ask me before action
     845APPEXTSECguiPanelShowRegExesBox=Show full regular expressions
     846APPEXTSECguiPanelInverSelection=Invert selection
     847APPEXTSECguiPanelMoveRowUp=Move row up
     848APPEXTSECguiPanelMoveRowDown=Move row down
     849APPEXTSECguiPanelCustomDefs=User definitions
     850APPEXTSECguiPanelGlobalDefs=System definitions
     851APPEXTSECguiPanelDocTest=Type document base URL
     852APPEXTSECguiPanelCodeTest=Type code base URL
     853APPEXTSECguiPanelNoMatch=Nothing matched
     854APPEXTSECguiPanelMatchingNote=Please note, that only first matched result will be considered as result.
     855APPEXTSECguiPanelMatched=Matched
     856APPEXTSECguiPanelMatchingError=Error during matching: {0}
     857APPEXTSECguiPanelCanNotValidate=Can not validate, can not create tmp file - {0}
     858APPEXTSECguiPanelEmptyDoc=All document-bases must be full
     859APPEXTSECguiPanelEmptyCode=All code-bases must be full
     860APPEXTSECguiPanelTableValid=Table looks valid
     861APPEXTSECguiPanelTableInvalid=Invalid with following error: {0}
     862APPEXTSECguiPanelShowOnlyPermanent=Show only permanent records
     863APPEXTSECguiPanelShowOnlyTemporal=Show only previously temporarily decided records
     864APPEXTSECguiPanelShowAll=Show all records
     865APPEXTSECguiPanelShowOnlyPermanentA=Show only allowed permanent records
     866APPEXTSECguiPanelShowOnlyPermanentN=Show only forbidden permanent records
     867APPEXTSECguiPanelShowOnlyTemporalY=Show previously allowed applets records
     868APPEXTSECguiPanelShowOnlyTemporalN=Show previously denied applets records
     869APPEXTSEChelpHomeDialogue=Dialogue
     870APPEXTSEChelp=<body> \
     871<h1>Help for Extended applet security - itw-settings, files and structures, dialogue</h1> \
     872<p> \
     873Extended Applet Security refers to security features for unsigned applets. Traditionally, only signed applets required user confirmation and unsigned applets ran automatically. This is represented by the 'low security' setting. Unsigned applets must be allowed or disallowed individually on 'high security' (the default), and additionally do not run at all on 'very high security'. In theory, unsigned applets can safely run automatically. In practice, however, any vulnerability in the Java security sandbox will prevent this from being true. \
     874</p> \
     875<p> \
     876To do so it uses  the <b>Security Level</b> main settings switch rules in the tables of <b>Custom definitions</b> and <b>Global definitions</b><br/> \
     877You can read much more about development of (and help us to improve!) this feature at <a href="http://icedtea.classpath.org/wiki/Extended_Applets_Security">dedicated IcedTea-Web page</a> \
     878</p> \
     879<A name="level"><h2>Security Level</h2></A> \
     880<p> \
     881Its a main switch for "extended applet security". Its value is commonly stored in usrs_home/.icedtea/deployment.properties, but can be enforced via global settings in /etc/.java/deployment/deployment.properties or JAVA_HOME/lib/deployment.properties under the key <b>deployment.security.level</b><br/> \
     882<li/><b>Disable running of all Java applets</b> - stored as <i>DENY_ALL</i> - No applet will be run<br/> \
     883<blockquote cite="" > \
     884No applet will be allowed to run. However the Java virtual machine will always be executed (and an error screen with reason appear instead of applets). To disable Java completely you can uninstall IcedTea-Web or disable it in your browser (if supported). The tables with records are of course ignored. \
     885</blockquote> \
     886<li/><b>Very High Security</b> - stored as <i>DENY_UNSIGNED</i> - No unsigned applets will be run<br/> \
     887<blockquote cite="" > \
     888No applet <b>unsigned</b> will be allowed to run (and an error screen with reason will appear instead of such applets). The tables with records are of course again ignored. \
     889</blockquote> \
     890<li/><b>High Security</b> - stored as <i>ASK_UNSIGNED</i> - User will be prompted for each unsigned applet<br/> \
     891<blockquote cite="" > \
     892All <b>unsigned</b> applets will be tested against the tables below if they should be allowed or forbidden to run. If they are not matched in the table then the user is prompted and the decision is stored in <a href="#table">tables</a> below. If the user denies the applet, an error screen with reason appears and the applet does not run. If the user allows applets to run, the user can choose to save this decision and whether to allow just one applet or a whole group of applets (see <a href="#dialogue"><b>Dialogue</b> paragraph </a>below). \
     893<br/>This is default behavior. \
     894</blockquote> \
     895<li/><b>Low Security</b> - stored as <i>ALLOW_UNSIGNED</i> - All, even unsigned, applets will be run<br/> \
     896<blockquote cite="" > \
     897All applets <b>even unsigned</b> will be allowed to run. User will not be warned and the tables with records are of course again ignored. \
     898</blockquote> \
     899You need to press <b>ok</b> or <b>apply</b> button to make the changes take effect. \
     900</p> \
     901 \
     902 \
     903<h2><A name="table">Table with recorded actions</A></h2> \
     904<p> \
     905<h4>Custom x Global table</h4> \
     906After each action in <b>High Security</b> dialogue the record is added to, or updated in, the table or configuration file. Commonly in users file - home/.icedtea/.appletTrustSettings - "Custom definition" panel.<br/> \
     907But superuser can specify default behavior in /etc/.java/deployment/ .appletTrustSettings - "Global definition" panel.<br/> \
     908<h4>"Syntax"</h4> \
     909<li/><b>Action</b> - Desired behavior when applet is matched<br/> \
     910<blockquote cite="" > \
     911<li/><b>Always trust this applet</b> - This unsigned applet will always be run in High Security Security Level. It is stored as <i>A</i> in .appletTrustSettings<br/> \
     912<li/><b>Never trust this applet</b> - This unsigned applet will never be run in High Security Security Level. It is stored as <i>N</i> in .appletTrustSettings<br/> \
     913<li/><b>Visited and allowed</b> - When the user is asked about this applet again, a note that this applet was already trusted in past will be displayed. It is stored as <i>y</i> in .appletTrustSettings<br/> \
     914<li/><b>Visited and denied</b> - When user will be asked about this applet again, he will see information that this applet was already denied in past. It is stored as <i>n</i> in .appletTrustSettings<br/> \
     915</blockquote> \
     916<li/><b>Date</b> - date of last action on this item (read only item)<br/> \
     917<li/><b>Document base</b> - is the page from which the applet was requested. It is actually a regular expression to match a specific URL. See about regular expressions and their usage <a href="#regexes">lower</a><br/> \
     918<li/><b>Code base</b> - is the URL where an applets code came from. It is actually a regular expression to match a specific URL. See about regular expressions and their usage <a href="#regexes">lower</a><br/> \
     919<li/><b>Archives</b> - coma separated list of archives with applet's code. Can be empty if source code are just classes or group of applets is allowed<br/> \
     920<br/> \
     921When you change a value in the table, its effect is immediate. \
     922<h4>Controls of tables</h4> \
     923<p> \
     924<li/><b>Delete</b> - deletes items as specified in combo box on side<br/> \
     925<blockquote cite="" > \
     926<li/><b>selected</b> - removes all selected items. Key <b>Del</b> does the same. Default behavior. <b>Multiple selections</b> allowed. Selection can be inverted by button even more on side<br/> \
     927<li/><b>all allowed (A)</b> - removes all permanently trusted records<br/> \
     928<li/><b>all forbidden (N)</b> - removes all permanently forbidden records<br/> \
     929<li/><b>all approved (y)</b> - removes all previously (temporarily) trusted records<br/> \
     930<li/><b>all rejected (n)</b> - removes all previously (temporarily) denied records<br/> \
     931<li/><b>all</b> - will clear the table<br/> \
     932<br/> \
     933<b>Ask me before action</b> - switch to ask before each deletion (in bulk) or not to ask. Asking dialogue can be pretty long, so if you do not see the buttons, just press <b>Esc</b> \
     934</blockquote> \
     935<li/><b>Show full regular expressions</b> - Disable or Enable filtering of quotation marks \Q\E in code/document base columns. About regular expressions see more <a href="#regexes">lower</a><br/> \
     936<br/> \
     937<li/>Filtering in table(s)<br/> \
     938<blockquote cite="" > \
     939<li/><b>Show only permanent records</b> - Shows only permanently allowed <b>(A)</b> or denied <b>(N)</b> records. Default behavior<br/> \
     940<li/><b>Show only temporarily decided records</b> - Shows only once allowed <b>(y)</b> or denied <b>(n)</b> informative records.<br/> \
     941<li/><b>Show only permanently allowed records</b> - Shows only permanently allowed <b>(A)</b> records<br/> \
     942<li/><b>Show only permanently denied records</b> - Shows only permanently denied <b>(N)</b> records<br/> \
     943<li/><b>Show only temporarily allowed records</b> - Shows only once allowed <b>(y)</b> informative records.<br/> \
     944<li/><b>Show only temporarily denied records</b> - Shows only once denied <b>(n)</b> informative records.<br/> \
     945</blockquote> \
     946</p> \
     947<li/><b>Add new row</b> - will add new, exemplary filled, row with current date and empty archives  <br/> \
     948<li/><b>Validate table</b> - will test if table can save, load, and if each value is valid:<br/> \
     949<blockquote cite="" > \
     950<li/><b>Action</b> - is one of A,N,y,n<br/> \
     951<li/><b>Date</b> - is valid date<br/> \
     952<li/><b>Code base and document base</b> - are valid <a href="#regexes">regular expressions</a> or empty<br/> \
     953<li/><b>Archives</b> - coma separated list of archives or empty<br/> \
     954</blockquote> \
     955<li/><b>Test url</b> - In two dialogues (in two steps) will let you enter document base and codebase, and then try to match them against all records. All matching items are returned! Last values are remembered> \
     956<li/><b>Move row down/up</b><br/> \
     957<blockquote cite="" > \
     958Order of rows is important. First matched result is returned (permanent have priority). So you can prioritize your matches using these buttons. <br/> \
     959For example, if you \Qhttp://blogs.com/\E.* regular expression to allow all applets on http://blogs.com, then it must be AFTER your \Qhttp://blogs.com/evilJohn\E.* regular expression forbidding all applets from blog of hacker evilJohn. \
     960</blockquote> \
     961</p> \
     962<p> \
     963<h2><A name="dialogue">Dialogue</A></h2> \
     964If <a href="#level"><b>High Security</b></a> is set, and a new unsigned applet is hit then the dialogue is shown asking you to allow it or deny it. You can also <b>choose</b> if you want to allow or deny this applet <b>every-time</b> (A or N) you encounter it or for <b>just one run</b> (y,n).<br/> \
     965You can also select to trust or deny (again temporarily or permanently)  <b>all</b> the applets from <b>same, exact, codebase</b>. If you are visiting one page, which has various applets on various documents then this is a choice for you.<br/> \
     966If you decide not to allow remembering your decision, then just a temporary record is made. If you revisit a page, a small green or red label will inform you about your last decision.<br/> \
     967Once you select <b>remember</b> your decision, the dialog will <b>never appear again</b>.  But you can <b>edit</b> your decision in <b>itw-settings application <a href="#table">table</a></b> (packed with IcedTea-Web). If you change your decision to temporary one (n,y)  or delete its row, the dialogue will appear again. Of course you can switch also from Always to Never or vice versa. \
     968<br/> \
     969The dialogue always mentions the page on which an applet is displayed, and the URL from which it comes.  There is also a hint, if you have ever visited this applet saying if you have allowed or rejected it in the past <br/> \
     970<blockquote cite="" > \
     971<h3>Controls</h3> \
     972<blockquote cite="" > \
     973<li/><b>Remember this option</b> - If set, then dialogue will never be shown for this applet or page again. \
     974<blockquote cite="" > \
     975<li/><b>For applet</b> - Exact applet will be allowed or denied \
     976<li/><b>For site</b> - All applets from this place will be allowed or denied  \
     977</blockquote> \
     978<li/><b>Proceed</b> - Applets, as selected above will be allowed \
     979<li/><b>Cancel</b> - Applets, as selected above will be forbidden \
     980</blockquote> \
     981Be aware to "proceed" + "Remember this option" + "For site" on pages you do not know! It can make you vulnerable! \
     982</blockquote> \
     983</p> \
     984<p> \
     985<h2><A name="regexes">Regular expressions</A></h2> \
     986IcedTea-Web extended applet security - uses a powerful matching engine to match exact (sets of) applets. Base stone is <b>Quotation</b> of URL \Q\E and <b>wildchars</b> llike .* or .? or more.<br/> \
     987This was designed to suits the need to block or allow exact pages. The best is to show some examples:<br/> \
     988N 12.12.2012 .* \Qhttp://blogs.com/evilJohn\E.* <br/> \
     989N 12.12.2012 \Qhttp://blogs.com/goodJohn/evilApplet.html\E.* \Qhttp://blogs.com/goodJohn/\E goodJohnsArchive.jar <br/> \
     990A 12.12.2012 \Qhttp://blogs.com/\E.* \Qhttp://blogs.com/\E.* <br/> \
     991N 12.12.2012 .* \Qhttp://adds.com\E.* <br/> \
     992Y 12.12.2012 .* \Qhttp://www.walter-fendt.de/ph14_jar/\E <br/> \
     993<br/> \
     994<i>So this table, created 12.12.2012:<br/></i> \
     995<li/>Forbid all stuff which have some code on http://blogs.com/evilJohn pages<br/> \
     996<li/>Forbidding also one exact applet from http://blogs.com/goodJohn/ with archive goodJohnsArchive.jar<br/> \
     997<li/>Allowing all (other) applets from http://blogs.com/ but only when displayed also on http://blogs.com/<br/> \
     998<li/>Forbidding all applets with code saved on  http://adds.com (except on http://blogs.com/ - to have forbidden http://adds.com also on http://blogs.com/, this (http://adds.com) record must be above blogs record)<br/> \
     999<li/>And finally allowing all nice physical applets on  walter-fendt's pages <br/> \
     1000<br/> \
     1001Note - the date saved in .appletTrustSettings has a not so nice format, but I left this for now...<br/> \
     1002<br/> \
     1003All information about full regular expression syntax can be found on <a href="http://docs.oracle.com/javase/6/docs/api/java/util/regex/Pattern.html">http://docs.oracle.com/javase/6/docs/api/java/util/regex/Pattern.html</a> \
     1004</p> \
     1005<h2>Conclusion</h2> \
     1006<p> \
     1007Stay tuned to our homepage at <a href="http://icedtea.classpath.org/wiki/IcedTea-Web">http://icedtea.classpath.org/wiki/IcedTea-Web</a>!<br/> \
     1008If you encounter any bug, feel free to file it in our <a href="http://icedtea.classpath.org/bugzilla/">bugzilla</a> ... According to <a href="http://icedtea.classpath.org/wiki/IcedTea-Web#Filing_bugs">http://icedtea.classpath.org/wiki/IcedTea-Web#Filing_bugs</a><br/> \
     1009<br/> \
     1010Safe browsing from your IcedTea-Web team... \
     1011</p> \
     1012</body> \
  • trunk/icedtea-web/netx/net/sourceforge/jnlp/runtime/AppletAudioClip.java

    r348 r429  
    2020import java.applet.*;
    2121import javax.sound.sampled.*;
     22import net.sourceforge.jnlp.util.logging.OutputController;
    2223
    2324// based on Deane Richan's AppletAudioClip
     
    4849            clip.open(stream);
    4950        } catch (Exception ex) {
    50             System.err.println("Error loading sound:" + location.toString());
     51            OutputController.getLogger().log(OutputController.Level.ERROR_ALL, "Error loading sound:" + location.toString());
     52            OutputController.getLogger().log(ex);
    5153            clip = null;
    5254        }
  • trunk/icedtea-web/netx/net/sourceforge/jnlp/runtime/AppletEnvironment.java

    r418 r429  
    1717package net.sourceforge.jnlp.runtime;
    1818
     19import net.sourceforge.jnlp.util.logging.OutputController;
    1920import java.applet.*;
    2021import java.awt.*;
     
    2829
    2930import net.sourceforge.jnlp.*;
     31import net.sourceforge.jnlp.splashscreen.SplashController;
    3032import net.sourceforge.jnlp.util.*;
    3133
     
    8890        // that do not have app code on the stack
    8991        WindowListener closer = new WindowAdapter() {
     92            @Override
    9093            public void windowClosing(WindowEvent event) {
    9194                appletInstance.destroy();
    92                 System.exit(0);
     95                JNLPRuntime.exit(0);
    9396            }
    9497        };
     
    104107     */
    105108    private void checkDestroyed() {
    106         if (destroyed)
     109        if (destroyed) {
    107110            throw new IllegalStateException("Illegal applet stub/context access: applet destroyed.");
     111        }
    108112    }
    109113
     
    131135    }
    132136
     137     /**
     138     * container must be SplashContoler
     139     *
     140     */
     141    public SplashController getSplashControler() {
     142       
     143        return (SplashController)cont;
     144    }
     145
    133146    /**
    134147     * Initialize, start, and show the applet.
     
    137150        checkDestroyed();
    138151
    139         if (appletStarted)
     152        if (appletStarted) {
    140153            return;
     154        }
    141155
    142156        appletStarted = true;
     
    145159            AppletDesc appletDesc = file.getApplet();
    146160
    147             if (cont instanceof AppletStub)
     161            if (cont instanceof AppletStub) {
    148162                applet.setStub((AppletStub) cont);
    149             else
     163            }
     164            else {
    150165                applet.setStub(this);
     166            }
    151167
    152168            cont.setLayout(new BorderLayout());
     
    166182            try {
    167183                SwingUtilities.invokeAndWait(new Runnable() {
     184                    @Override
    168185                    public void run() {
    169186                        // do first because some applets need to be displayed before
     
    185202            }
    186203        } catch (Exception ex) {
    187             if (JNLPRuntime.isDebug())
    188                 ex.printStackTrace();
     204            OutputController.getLogger().log(ex);
    189205
    190206            // should also kill the applet?
     
    198214     * otherwise return null.
    199215     */
     216    @Override
    200217    public Applet getApplet(String name) {
    201218        checkDestroyed();
    202219
    203         if (name != null && name.equals(file.getApplet().getName()))
     220        if (name != null && name.equals(file.getApplet().getName())) {
    204221            return applet;
    205         else
     222        } else {
    206223            return null;
     224        }
    207225    }
    208226
     
    212230    public void setApplet(Applet applet) {
    213231        if (this.applet != null) {
    214             if (JNLPRuntime.isDebug()) {
    215                 Exception ex = new IllegalStateException("Applet can only be set once.");
    216                 ex.printStackTrace();
    217             }
     232            OutputController.getLogger().log(new IllegalStateException("Applet can only be set once."));
    218233            return;
    219234        }
     
    225240     * from the JNLP file.
    226241     */
     242    @Override
    227243    public Enumeration<Applet> getApplets() {
    228244        checkDestroyed();
     
    234250     * Returns an audio clip.
    235251     */
     252    @Override
    236253    public AudioClip getAudioClip(URL location) {
    237254        checkDestroyed();
     
    248265     * Return an image loaded from the specified location.
    249266     */
     267    @Override
    250268    public Image getImage(URL location) {
    251269        checkDestroyed();
     
    260278     * Not implemented yet.
    261279     */
     280    @Override
    262281    public void showDocument(java.net.URL uRL) {
    263282        checkDestroyed();
     
    268287     * Not implemented yet.
    269288     */
     289    @Override
    270290    public void showDocument(java.net.URL uRL, java.lang.String str) {
    271291        checkDestroyed();
     
    276296     * Not implemented yet.
    277297     */
     298    @Override
    278299    public void showStatus(java.lang.String str) {
    279300        checkDestroyed();
     
    284305     * Required for JRE1.4, but not implemented yet.
    285306     */
     307    @Override
    286308    public void setStream(String key, InputStream stream) {
    287309        checkDestroyed();
     
    292314     * Required for JRE1.4, but not implemented yet.
    293315     */
     316    @Override
    294317    public InputStream getStream(String key) {
    295318        checkDestroyed();
     
    301324     * Required for JRE1.4, but not implemented yet.
    302325     */
     326    @Override
    303327    public Iterator<String> getStreamKeys() {
    304328        checkDestroyed();
     
    309333    // stub methods
    310334
     335    @Override
    311336    public void appletResize(int width, int height) {
    312337        checkDestroyed();
     
    321346    }
    322347
     348    @Override
    323349    public AppletContext getAppletContext() {
    324350        checkDestroyed();
     
    327353    }
    328354
     355    @Override
    329356    public URL getCodeBase() {
    330357        checkDestroyed();
     
    333360    }
    334361
     362    @Override
    335363    public URL getDocumentBase() {
    336364        checkDestroyed();
     
    341369    // FIXME: Sun's applet code forces all parameters to lower case.
    342370    // Does Netx's JNLP code do the same, so we can remove the first lookup?
     371    @Override
    343372    public String getParameter(String name) {
    344373        checkDestroyed();
    345374
    346         String s = (String) parameters.get(name);
    347         if (s != null)
     375        String s = parameters.get(name);
     376        if (s != null) {
    348377            return s;
    349 
    350         return (String) parameters.get(name.toLowerCase());
    351     }
    352 
     378        }
     379
     380        return  parameters.get(name.toLowerCase());
     381    }
     382
     383    @Override
    353384    public boolean isActive() {
    354385        checkDestroyed();
  • trunk/icedtea-web/netx/net/sourceforge/jnlp/runtime/AppletInstance.java

    r418 r429  
    2121
    2222import net.sourceforge.jnlp.*;
     23import net.sourceforge.jnlp.util.logging.OutputController;
    2324
    2425/**
     
    5758    public void setApplet(Applet applet) {
    5859        if (this.applet != null) {
    59             if (JNLPRuntime.isDebug()) {
    60                 Exception ex = new IllegalStateException("Applet can only be set once.");
    61                 ex.printStackTrace();
    62             }
     60                OutputController.getLogger().log(new IllegalStateException("Applet can only be set once."));
    6361            return;
    6462        }
     
    130128            applet.destroy();
    131129        } catch (Exception ex) {
    132             if (JNLPRuntime.isDebug())
    133                 ex.printStackTrace();
     130            OutputController.getLogger().log(ex);
    134131        }
    135132
  • trunk/icedtea-web/netx/net/sourceforge/jnlp/runtime/ApplicationInstance.java

    r418 r429  
    1818
    1919import java.awt.Window;
     20import java.io.File;
    2021import java.net.URL;
    2122import java.security.AccessControlContext;
     
    3839import net.sourceforge.jnlp.security.SecurityDialogs;
    3940import net.sourceforge.jnlp.security.SecurityDialogs.AccessType;
     41import net.sourceforge.jnlp.util.logging.OutputController;
    4042import net.sourceforge.jnlp.util.WeakList;
    4143import net.sourceforge.jnlp.util.XDesktopEntry;
     
    4345/**
    4446 * Represents a running instance of an application described in a
    45  * JNLPFile.  This class provides a way to track the application's
    46  * resources and destroy the application.<p>
     47 * JNLPFile. This class provides a way to track the application's
     48 * resources and destroy the application.
    4749 *
    4850 * @author <a href="mailto:jmaxwell@users.sourceforge.net">Jon A. Maxwell (JAM)</a> - initial author
     
    6466
    6567    /**
     68     * <p>
    6669     * Every application/applet gets its own AppContext. This allows us to do
    6770     * things like have two different look and feels for two different applets
    6871     * (running in the same VM), allows untrusted programs to manipulate the
    69      * event queue (safely) and (possibly) more.<p>
    70      *
     72     * event queue (safely) and (possibly) more.
     73     * </p>
     74     * <p>
    7175     * It is set to the AppContext which created this ApplicationInstance
     76     * </p>
    7277     */
    7378    private AppContext appContext;
     
    147152        XDesktopEntry entry = new XDesktopEntry(file);
    148153        ShortcutDesc sd = file.getInformation().getShortcut();
    149 
     154        File possibleDesktopFile = entry.getLinuxDesktopIconFile();
     155        if (possibleDesktopFile.exists()) {
     156            OutputController.getLogger().log("ApplicationInstance.addMenuAndDesktopEntries(): file - "
     157                    + possibleDesktopFile.getAbsolutePath() + " already exists. Not proceeding with desktop additions");
     158            return;
     159        }
    150160        if (shouldCreateShortcut(sd)) {
    151161            entry.createDesktopShortcut();
     
    156166             * Sun's WebStart implementation doesnt seem to do anything under GNOME
    157167             */
    158             if (JNLPRuntime.isDebug()) {
    159                 System.err.println("ApplicationInstance.addMenuAndDesktopEntries():"
    160                         + " Adding menu entries NOT IMPLEMENTED");
    161             }
     168            OutputController.getLogger().log(OutputController.Level.ERROR_DEBUG, "ApplicationInstance.addMenuAndDesktopEntries():"
     169                    + " Adding menu entries NOT IMPLEMENTED");
    162170        }
    163171
     
    172180     */
    173181    private boolean shouldCreateShortcut(ShortcutDesc sd) {
     182        if (JNLPRuntime.isTrustAll()) {
     183            return (sd != null && sd.onDesktop());
     184        }
    174185        String currentSetting = JNLPRuntime.getConfiguration()
    175186                .getProperty(DeploymentConfiguration.KEY_CREATE_DESKTOP_SHORTCUT);
     
    208219     * also collectable so basically is almost never called (an
    209220     * application would have to close its windows and exit its
    210      * threads but not call System.exit).
     221     * threads but not call JNLPRuntime.exit).
    211222     */
    212223    public void finalize() {
     
    284295            int nthreads = group.enumerate(threads);
    285296            for (int i = 0; i < nthreads; i++) {
    286                 if (JNLPRuntime.isDebug())
    287                     System.out.println("Interrupt thread: " + threads[i]);
    288 
     297                OutputController.getLogger().log("Interrupt thread: " + threads[i]);
    289298                threads[i].interrupt();
    290299            }
    291300
    292301            // then stop
    293             Thread.currentThread().yield();
     302            Thread.yield();
    294303            nthreads = group.enumerate(threads);
    295304            for (int i = 0; i < nthreads; i++) {
    296                 if (JNLPRuntime.isDebug())
    297                     System.out.println("Stop thread: " + threads[i]);
    298 
     305                OutputController.getLogger().log("Stop thread: " + threads[i]);
    299306                threads[i].stop();
    300307            }
  • trunk/icedtea-web/netx/net/sourceforge/jnlp/runtime/Boot.java

    r418 r429  
    2929import java.util.Map;
    3030
     31import javax.swing.UIManager;
     32
    3133import net.sourceforge.jnlp.LaunchException;
    3234import net.sourceforge.jnlp.Launcher;
    3335import net.sourceforge.jnlp.ParserSettings;
     36import net.sourceforge.jnlp.about.AboutDialog;
    3437import net.sourceforge.jnlp.cache.CacheUtil;
    3538import net.sourceforge.jnlp.cache.UpdatePolicy;
     39import net.sourceforge.jnlp.config.DeploymentConfiguration;
    3640import net.sourceforge.jnlp.security.viewer.CertificateViewer;
    3741import net.sourceforge.jnlp.services.ServiceUtil;
     42import net.sourceforge.jnlp.util.logging.OutputController;
     43import sun.awt.AppContext;
     44import sun.awt.SunToolkit;
    3845
    3946/**
    40  * This is the main entry point for the JNLP client.  The main
     47 * This is the main entry point for the JNLP client. The main
    4148 * method parses the command line parameters and loads a JNLP
    42  * file into the secure runtime environment.  This class is meant
     49 * file into the secure runtime environment. This class is meant
    4350 * to be called from the command line or file association; to
    4451 * initialize the netx engine from other code invoke the
    45  * <code>JNLPRuntime.initialize</code> method after configuring
     52 * {@link JNLPRuntime#initialize} method after configuring
    4653 * the runtime.
    4754 *
     
    5461    // should inherit the same options as this instance (store argv?)
    5562
    56     private static final String name = Boot.class.getPackage().getImplementationTitle();
    57     private static final String version = Boot.class.getPackage().getImplementationVersion();
    58 
    59     /** the text to display before launching the about link */
    60     private static final String aboutMessage = ""
    61             + name + " " + version
    62             + "\n"
    63             + R("BLaunchAbout");
     63    public static final String name = Boot.class.getPackage().getImplementationTitle();
     64    public static final String version = Boot.class.getPackage().getImplementationVersion();
     65
     66    private static final String nameAndVersion = name + " " + version;
    6467
    6568    private static final String miniLicense = "\n"
     
    8285            + "\n";
    8386
     87    private static final String itwInfoMessage = ""
     88            + nameAndVersion
     89            + "\n\n*  "
     90            + R("BAboutITW")
     91            + "\n*  "
     92            + R("BFileInfoAuthors")
     93            + "\n*  "
     94            + R("BFileInfoNews")
     95            + "\n*  "
     96            + R("BFileInfoCopying");
     97
    8498    private static final String helpMessage = "\n"
    8599            + "Usage:   " + R("BOUsage") + "\n"
     
    91105            + "\n"
    92106            + "run-options:" + "\n"
     107            + "  -version              " + R("BOVersion") + "\n"
    93108            + "  -arg arg              " + R("BOArg") + "\n"
    94109            + "  -param name=value     " + R("BOParam") + "\n"
     
    101116            + "  -headless             " + R("BOHeadless") + "\n"
    102117            + "  -strict               " + R("BOStrict") + "\n"
     118            + "  -xml                  " + R("BOXml") + "\n"
     119            + "  -allowredirect        " + R("BOredirect") + "\n"
    103120            + "  -Xnofork              " + R("BXnofork") + "\n"
    104121            + "  -Xclearcache          " + R("BXclearcache") + "\n"
     122            + "  -Xignoreheaders       " + R("BXignoreheaders") + "\n"
    105123            + "  -help                 " + R("BOHelp") + "\n";
    106124
     
    115133        args = argsIn;
    116134
     135        if (AppContext.getAppContext() == null) {
     136            SunToolkit.createNewAppContext();
     137        }
     138        if (null != getOption("-headless")) {
     139            JNLPRuntime.setHeadless(true);
     140        }
     141
     142        DeploymentConfiguration.move14AndOlderFilesTo15StructureCatched();
     143
    117144        if (null != getOption("-viewer")) {
    118 
    119145            try {
    120146                CertificateViewer.main(null);
    121                 System.exit(0);
     147                JNLPRuntime.exit(0);
    122148            } catch (Exception e) {
    123                 // TODO Auto-generated catch block
    124                 e.printStackTrace();
     149                OutputController.getLogger().log(OutputController.Level.ERROR_ALL, e);
    125150            }
    126 
     151        }
     152
     153        if (null != getOption("-version")) {
     154            OutputController.getLogger().printOutLn(nameAndVersion);
     155            JNLPRuntime.exit(0);
    127156        }
    128157
    129158        if (null != getOption("-license")) {
    130             System.out.println(miniLicense);
    131             System.exit(0);
     159            OutputController.getLogger().printOutLn(miniLicense);
     160            JNLPRuntime.exit(0);
    132161        }
    133162
    134163        if (null != getOption("-help")) {
    135             System.out.println(helpMessage);
    136             System.exit(0);
    137         }
    138 
    139         if (null != getOption("-about"))
    140             System.out.println(aboutMessage);
     164            OutputController.getLogger().printOutLn(helpMessage);
     165            JNLPRuntime.exit(0);
     166        }
     167
     168        if (null != getOption("-about")) {
     169                OutputController.getLogger().printOutLn(itwInfoMessage);
     170            if (null != getOption("-headless")) {
     171                JNLPRuntime.exit(0);
     172            } else {
     173                try {
     174                    UIManager.setLookAndFeel(UIManager.getSystemLookAndFeelClassName());
     175                } catch (Exception e) {
     176                    OutputController.getLogger().log("Unable to set system look and feel");
     177                }
     178                OutputController.getLogger().printOutLn(R("BLaunchAbout"));
     179                AboutDialog.display();
     180                return;
     181            }
     182        }
    141183
    142184        if (null != getOption("-verbose"))
     
    148190        }
    149191
    150         if (null != getOption("-headless"))
    151             JNLPRuntime.setHeadless(true);
    152 
    153192        if (null != getOption("-noupdate"))
    154193            JNLPRuntime.setDefaultUpdatePolicy(UpdatePolicy.NEVER);
     
    160199            JNLPRuntime.setTrustAll(true);
    161200        }
     201        if (null != getOption("-Xtrustnone")) {
     202            JNLPRuntime.setTrustNone(true);
     203        }
     204        if (null != getOption("-Xignoreheaders")) {
     205            JNLPRuntime.setIgnoreHeaders(true);
     206        }
     207        if (null != getOption("-allowredirect")) {
     208            JNLPRuntime.setAllowRedirect(true);
     209        }
    162210
    163211        JNLPRuntime.setInitialArgments(Arrays.asList(argsIn));
    164212
    165         // do in a privileged action to clear the security context of
    166         // the Boot13 class, which doesn't have any privileges in
    167         // JRE1.3; JRE1.4 works without Boot13 or this PrivilegedAction.
    168213        AccessController.doPrivileged(new Boot());
    169214
     
    193238        extra.put("properties", getOptions("-property"));
    194239
    195         boolean strict = (null != getOption("-strict"));
    196         ParserSettings settings = new ParserSettings(strict);
     240        ParserSettings settings = ParserSettings.setGlobalParserSettingsFromArgs(args);
    197241
    198242        try {
     
    200244            launcher.setParserSettings(settings);
    201245            launcher.setInformationToMerge(extra);
    202             launcher.launch(getFileLocation(), true);
     246            launcher.launch(getFileLocation());
    203247        } catch (LaunchException ex) {
    204248            // default handler prints this
    205249        } catch (Exception ex) {
    206             if (JNLPRuntime.isDebug())
    207                 ex.printStackTrace();
    208 
     250            OutputController.getLogger().log(ex);
    209251            fatalError(R("RUnexpected", ex.toString(), ex.getStackTrace()[0]));
    210252        }
     
    214256
    215257    private static void fatalError(String message) {
    216         System.err.println("netx: " + message);
    217         System.exit(1);
    218     }
    219 
    220     /**
    221      * Returns the location of the about.jnlp file or null if this file
    222      * does not exist.
    223      */
    224     private static String getAboutFile() {
    225         ClassLoader cl = Boot.class.getClassLoader();
    226         if (cl == null) {
    227             cl = ClassLoader.getSystemClassLoader();
    228         }
    229         try {
    230                     //extracts full path to about.jnlp
    231             String s = cl.getResource("net/sourceforge/jnlp/runtime/Boot.class").toString();
    232             s=s.substring(0,s.indexOf("!"));
    233             s=s.substring(s.indexOf(":")+1);
    234             s=s.substring(s.indexOf(":")+1);
    235             s="file://"+s.replace("netx.jar","about.jnlp");
    236             if (JNLPRuntime.isDebug()){
    237                 System.out.println("Using " + s + " as about.jnlp URL");
    238             }
    239 
    240             return s;
    241          } catch (Exception e) {
    242             e.printStackTrace();
    243             return null;
    244         }
     258        OutputController.getLogger().log(OutputController.Level.ERROR_ALL, "netx: " + message);
     259        JNLPRuntime.exit(1);
    245260    }
    246261
     
    253268        String location = getJNLPFile();
    254269
    255         // override -jnlp with aboutFile
    256         if (getOption("-about") != null) {
    257             location = getAboutFile();
    258             if (location == null)
    259                 fatalError(R("RNoAboutJnlp"));
    260         } else {
    261             location = getJNLPFile();
    262         }
    263 
    264270        if (location == null) {
    265             System.out.println(helpMessage);
    266             System.exit(1);
    267         }
    268 
    269         if (JNLPRuntime.isDebug())
    270             System.out.println(R("BFileLoc") + ": " + location);
     271            OutputController.getLogger().printOutLn(helpMessage);
     272            JNLPRuntime.exit(1);
     273        }
     274
     275        OutputController.getLogger().log(R("BFileLoc") + ": " + location);
    271276
    272277        URL url = null;
     
    279284                url = new URL(ServiceUtil.getBasicService().getCodeBase(), location);
    280285        } catch (Exception e) {
     286            OutputController.getLogger().log(e);
    281287            fatalError("Invalid jnlp file " + location);
    282             if (JNLPRuntime.isDebug())
    283                 e.printStackTrace();
    284288        }
    285289
     
    293297
    294298        if (args.length == 0) {
    295             System.out.println(helpMessage);
    296             System.exit(0);
     299            OutputController.getLogger().printOutLn(helpMessage);
     300            JNLPRuntime.exit(0);
    297301        } else if (args.length == 1) {
    298302            return args[args.length - 1];
     
    304308                return lastArg;
    305309            } else {
    306                 System.out.println(helpMessage);
    307                 System.exit(0);
     310                OutputController.getLogger().printOutLn(helpMessage);
     311                JNLPRuntime.exit(0);
    308312            }
    309313        }
  • trunk/icedtea-web/netx/net/sourceforge/jnlp/runtime/CachedJarFileCallback.java

    r418 r429  
    5050import java.util.Map;
    5151import java.util.concurrent.ConcurrentHashMap;
    52 import java.util.jar.JarFile;
     52import net.sourceforge.jnlp.util.logging.OutputController;
     53import net.sourceforge.jnlp.util.JarFile;
    5354
    5455import net.sourceforge.jnlp.util.UrlUtils;
     
    8283
    8384    @Override
    84     public JarFile retrieve(URL url) throws IOException {
     85    public java.util.jar.JarFile retrieve(URL url) throws IOException {
    8586        URL localUrl = mapping.get(url);
    8687
     
    104105                returnFile.getManifest().getMainAttributes().putValue("Class-Path", "");
    105106
    106                 if (JNLPRuntime.isDebug()) {
    107                     System.err.println("Class-Path attribute cleared for " + returnFile.getName());
    108                 }
     107                OutputController.getLogger().log(OutputController.Level.ERROR_DEBUG, "Class-Path attribute cleared for " + returnFile.getName());
     108               
    109109
    110110            } catch (NullPointerException npe) {
     
    123123     * This method is a copy of URLJarFile.retrieve() without the callback check.
    124124     */
    125     private JarFile cacheJarFile(URL url) throws IOException {
    126         JarFile result = null;
     125    private  java.util.jar.JarFile cacheJarFile(URL url) throws IOException {
     126        java.util.jar.JarFile result = null;
    127127
    128128        final int BUF_SIZE = 2048;
     
    133133        try {
    134134            result =
    135                     AccessController.doPrivileged(new PrivilegedExceptionAction<JarFile>() {
     135                    AccessController.doPrivileged(new PrivilegedExceptionAction<java.util.jar.JarFile>() {
    136136                        @Override
    137                         public JarFile run() throws IOException {
     137                        public java.util.jar.JarFile run() throws IOException {
    138138                            OutputStream out = null;
    139139                            File tmpFile = null;
  • trunk/icedtea-web/netx/net/sourceforge/jnlp/runtime/FakePacEvaluator.java

    r348 r429  
    4040import static net.sourceforge.jnlp.runtime.Translator.R;
    4141import java.net.URL;
     42import net.sourceforge.jnlp.util.logging.OutputController;
    4243
    4344/**
     
    4748    @Override
    4849    public String getProxies(URL url) {
    49         if (JNLPRuntime.isDebug()) {
    50             System.err.println(R("RPRoxyPacNotSupported"));
    51         }
     50        OutputController.getLogger().log(OutputController.Level.ERROR_ALL, R("RPRoxyPacNotSupported"));
    5251        return "DIRECT";
    5352    }
  • trunk/icedtea-web/netx/net/sourceforge/jnlp/runtime/JNLPClassLoader.java

    r418 r429  
    1818import static net.sourceforge.jnlp.runtime.Translator.R;
    1919
    20 import java.io.Closeable;
    2120import java.io.File;
    2221import java.io.FileOutputStream;
     
    5655import java.util.Vector;
    5756import java.util.concurrent.ConcurrentHashMap;
     57import java.util.concurrent.locks.ReentrantLock;
     58import java.util.jar.Attributes;
    5859import java.util.jar.JarEntry;
    59 import java.util.jar.JarFile;
    6060import java.util.jar.Manifest;
    6161
    6262import net.sourceforge.jnlp.AppletDesc;
    6363import net.sourceforge.jnlp.ApplicationDesc;
    64 import net.sourceforge.jnlp.DownloadOptions;
    6564import net.sourceforge.jnlp.ExtensionDesc;
    6665import net.sourceforge.jnlp.JARDesc;
     
    7069import net.sourceforge.jnlp.LaunchDesc;
    7170import net.sourceforge.jnlp.LaunchException;
     71import net.sourceforge.jnlp.NullJnlpFileException;
    7272import net.sourceforge.jnlp.ParseException;
     73import net.sourceforge.jnlp.ParserSettings;
    7374import net.sourceforge.jnlp.PluginBridge;
    7475import net.sourceforge.jnlp.ResourcesDesc;
     
    7778import net.sourceforge.jnlp.cache.CacheUtil;
    7879import net.sourceforge.jnlp.cache.IllegalResourceDescriptorException;
     80import net.sourceforge.jnlp.cache.NativeLibraryStorage;
    7981import net.sourceforge.jnlp.cache.ResourceTracker;
    8082import net.sourceforge.jnlp.cache.UpdatePolicy;
    81 import net.sourceforge.jnlp.security.SecurityDialogs;
    82 import net.sourceforge.jnlp.security.SecurityDialogs.AccessType;
     83import net.sourceforge.jnlp.security.AppVerifier;
     84import net.sourceforge.jnlp.security.JNLPAppVerifier;
     85import net.sourceforge.jnlp.security.PluginAppVerifier;
     86import net.sourceforge.jnlp.security.appletextendedsecurity.UnsignedAppletTrustConfirmation;
    8387import net.sourceforge.jnlp.tools.JarCertVerifier;
    84 import net.sourceforge.jnlp.util.FileUtils;
     88import net.sourceforge.jnlp.util.JarFile;
     89import net.sourceforge.jnlp.util.StreamUtils;
     90import net.sourceforge.jnlp.util.UrlUtils;
     91import net.sourceforge.jnlp.util.logging.OutputController;
    8592import sun.misc.JarIndex;
    8693
    8794/**
    88  * Classloader that takes it's resources from a JNLP file.  If the
     95 * Classloader that takes it's resources from a JNLP file. If the
    8996 * JNLP file defines extensions, separate classloaders for these
    90  * will be created automatically.  Classes are loaded with the
     97 * will be created automatically. Classes are loaded with the
    9198 * security context when the classloader was created.
    9299 *
     
    103110    final public static String TEMPLATE = "JNLP-INF/APPLICATION_TEMPLATE.JNLP";
    104111    final public static String APPLICATION = "JNLP-INF/APPLICATION.JNLP";
    105    
     112
     113    /** Actions to specify how cache is to be managed **/
     114    public static enum DownloadAction {
     115        DOWNLOAD_TO_CACHE, REMOVE_FROM_CACHE, CHECK_CACHE
     116    }
     117
     118    public static enum SigningState {
     119        FULL, PARTIAL, NONE
     120    }
     121
    106122    /** True if the application has a signed JNLP File */
    107123    private boolean isSignedJNLP = false;
    108124   
    109     /** map from JNLPFile url to shared classloader */
    110     private static Map<String, JNLPClassLoader> urlToLoader =
    111             new HashMap<String, JNLPClassLoader>(); // never garbage collected!
    112 
    113     /** the directory for native code */
    114     private File nativeDir = null; // if set, some native code exists
    115 
    116     /** a list of directories that contain native libraries */
    117     private List<File> nativeDirectories = Collections.synchronizedList(new LinkedList<File>());
     125    /** map from JNLPFile unique key to shared classloader */
     126    private static Map<String, JNLPClassLoader> uniqueKeyToLoader = new ConcurrentHashMap<String, JNLPClassLoader>();
     127
     128    /** map from JNLPFile unique key to lock, the lock is needed to enforce correct
     129     * initialization of applets that share a unique key*/
     130    private static Map<String, ReentrantLock> uniqueKeyToLock = new HashMap<String, ReentrantLock>();
     131
     132    /** Provides a search path & temporary storage for native code */
     133    private NativeLibraryStorage nativeLibraryStorage;
    118134
    119135    /** security context */
     
    150166    private ArrayList<Permission> runtimePermissions = new ArrayList<Permission>();
    151167
    152     /** all jars not yet part of classloader or active */
    153     private List<JARDesc> available = new ArrayList<JARDesc>();
    154 
    155     /** all of the jar files that were verified */
    156     private ArrayList<String> verifiedJars = null;
    157 
    158     /** all of the jar files that were not verified */
    159     private ArrayList<String> unverifiedJars = null;
     168    /** all jars not yet part of classloader or active
     169     * Synchronized since this field may become shared data between multiple classloading threads.
     170     * See loadClass(String) and CodebaseClassLoader.findClassNonRecursive(String).
     171     */
     172    private List<JARDesc> available = Collections.synchronizedList(new ArrayList<JARDesc>());
    160173
    161174    /** the jar cert verifier tool to verify our jars */
    162     private JarCertVerifier jcv = null;
    163 
    164     private boolean signing = false;
    165 
    166     /** ArrayList containing jar indexes for various jars available to this classloader */
    167     private ArrayList<JarIndex> jarIndexes = new ArrayList<JarIndex>();
    168 
    169     /** Set of classpath strings declared in the manifest.mf files */
    170     private Set<String> classpaths = new HashSet<String>();
    171 
    172     /** File entries in the jar files available to this classloader */
    173     private TreeSet<String> jarEntries = new TreeSet<String>();
    174 
    175     /** Map of specific original (remote) CodeSource Urls  to securitydesc */
    176     private HashMap<URL, SecurityDesc> jarLocationSecurityMap =
    177             new HashMap<URL, SecurityDesc>();
     175    private final JarCertVerifier jcv;
     176
     177    private SigningState signing = SigningState.NONE;
     178
     179    /** ArrayList containing jar indexes for various jars available to this classloader
     180     * Synchronized since this field may become shared data between multiple classloading threads/
     181     * See loadClass(String) and CodebaseClassLoader.findClassNonRecursive(String).
     182     */
     183    private List<JarIndex> jarIndexes = Collections.synchronizedList(new ArrayList<JarIndex>());
     184
     185    /** Set of classpath strings declared in the manifest.mf files
     186     * Synchronized since this field may become shared data between multiple classloading threads.
     187     * See loadClass(String) and CodebaseClassLoader.findClassNonRecursive(String).
     188     */
     189    private Set<String> classpaths = Collections.synchronizedSet(new HashSet<String>());
     190
     191    /** File entries in the jar files available to this classloader
     192     * Synchronized sinc this field may become shared data between multiple classloading threads.
     193     * See loadClass(String) and CodebaseClassLoader.findClassNonRecursive(String).
     194     */
     195    private Set<String> jarEntries = Collections.synchronizedSet(new TreeSet<String>());
     196
     197    /** Map of specific original (remote) CodeSource Urls  to securitydesc
     198     *  Synchronized since this field may become shared data between multiple classloading threads.
     199     *  See loadClass(String) and CodebaseClassLoader.findClassNonRecursive(String).
     200     */
     201    private Map<URL, SecurityDesc> jarLocationSecurityMap =
     202            Collections.synchronizedMap(new HashMap<URL, SecurityDesc>());
    178203
    179204    /*Set to prevent once tried-to-get resources to be tried again*/
     
    189214    /** Name of the application's main class */
    190215    private String mainClass = null;
    191 
     216   
    192217    /**
    193218     * Variable to track how many times this loader is in use
    194219     */
    195220    private int useCount = 0;
     221
     222    private boolean enableCodeBase = false;
     223
     224    private final SecurityDelegate securityDelegate;
    196225
    197226    /**
     
    201230     */
    202231    protected JNLPClassLoader(JNLPFile file, UpdatePolicy policy) throws LaunchException {
    203         this(file,policy,null);
     232        this(file, policy, null, false);
    204233    }
    205234
     
    208237     *
    209238     * @param file the JNLP file
    210      * @param name of the application's main class
    211      */
    212     protected JNLPClassLoader(JNLPFile file, UpdatePolicy policy, String mainName) throws LaunchException {
     239     * @param policy the UpdatePolicy for this class loader
     240     * @param mainName name of the application's main class
     241     */
     242    protected JNLPClassLoader(JNLPFile file, UpdatePolicy policy, String mainName, boolean enableCodeBase) throws LaunchException {
    213243        super(new URL[0], JNLPClassLoader.class.getClassLoader());
    214244
    215         if (JNLPRuntime.isDebug())
    216             System.out.println("New classloader: " + file.getFileLocation());
     245        OutputController.getLogger().log("New classloader: " + file.getFileLocation());
    217246
    218247        this.file = file;
     
    220249        this.resources = file.getResources();
    221250
     251        this.nativeLibraryStorage = new NativeLibraryStorage(tracker);
     252
    222253        this.mainClass = mainName;
     254
     255        this.enableCodeBase = enableCodeBase;
     256
     257       
     258        AppVerifier verifier;
     259
     260        if (file instanceof PluginBridge && !((PluginBridge)file).useJNLPHref()) {
     261            verifier = new PluginAppVerifier();
     262        } else {
     263            verifier = new JNLPAppVerifier();
     264        }
     265
     266        jcv = new JarCertVerifier(verifier);
     267
     268        if (this.enableCodeBase) {
     269            addToCodeBaseLoader(this.file.getCodeBase());
     270        }
     271
     272        this.securityDelegate = new SecurityDelegateImpl(this);
    223273
    224274        // initialize extensions
     
    226276
    227277        initializeResources();
     278       
     279        //loading mainfests before resources are initialised may cause waiting for resources
     280        file.getManifestsAttributes().setLoader(this);
    228281
    229282        // initialize permissions
     
    232285        setSecurity();
    233286
     287        ManifestAttributesChecker mac = new ManifestAttributesChecker(security, file, signing, securityDelegate);
     288        mac.checkAll();
     289       
    234290        installShutdownHooks();
     291       
    235292
    236293    }
     
    249306                 * cleanup things they created
    250307                 */
    251                 if (nativeDir != null) {
    252                     if (JNLPRuntime.isDebug()) {
    253                         System.out.println("Cleaning up native directory" + nativeDir.getAbsolutePath());
    254                     }
    255                     try {
    256                         FileUtils.recursiveDelete(nativeDir,
    257                                 new File(System.getProperty("java.io.tmpdir")));
    258                     } catch (IOException e) {
    259                         /*
    260                          * failed to delete a file in tmpdir, no big deal (not
    261                          * to mention that the VM is shutting down at this
    262                          * point so no much we can do)
    263                          */
    264                     }
    265                 }
     308                nativeLibraryStorage.cleanupTemporaryFolder();
    266309            }
    267310        });
     
    269312
    270313    private void setSecurity() throws LaunchException {
    271 
    272         URL codebase = null;
    273 
    274         if (file.getCodeBase() != null) {
    275             codebase = file.getCodeBase();
    276         } else {
    277             //Fixme: codebase should be the codebase of the Main Jar not
    278             //the location. Although, it still works in the current state.
    279             codebase = file.getResources().getMainJAR().getLocation();
    280         }
    281 
    282         /**
    283          * When we're trying to load an applet, file.getSecurity() will return
    284          * null since there is no jnlp file to specify permissions. We
    285          * determine security settings here, after trying to verify jars.
    286          */
    287         if (file instanceof PluginBridge) {
    288             if (signing == true) {
    289                 this.security = new SecurityDesc(file,
    290                         SecurityDesc.ALL_PERMISSIONS,
    291                         codebase.getHost());
    292             } else {
    293                 this.security = new SecurityDesc(file,
    294                         SecurityDesc.SANDBOX_PERMISSIONS,
    295                         codebase.getHost());
    296             }
    297         } else { //regular jnlp file
    298 
    299             /*
    300              * Various combinations of the jars being signed and <security> tags being
    301              * present are possible. They are treated as follows
    302              *
    303              * Jars          JNLP File         Result
    304              *
    305              * Signed        <security>        Appropriate Permissions
    306              * Signed        no <security>     Sandbox
    307              * Unsigned      <security>        Error
    308              * Unsigned      no <security>     Sandbox
    309              *
    310              */
    311             if (!file.getSecurity().getSecurityType().equals(SecurityDesc.SANDBOX_PERMISSIONS) && !signing) {
    312                 throw new LaunchException(file, null, R("LSFatal"), R("LCClient"), R("LUnsignedJarWithSecurity"), R("LUnsignedJarWithSecurityInfo"));
    313             } else if (signing == true) {
    314                 this.security = file.getSecurity();
    315             } else {
    316                 this.security = new SecurityDesc(file,
    317                         SecurityDesc.SANDBOX_PERMISSIONS,
    318                         codebase.getHost());
    319             }
    320         }
    321     }
    322 
    323     /**
    324      * Returns a JNLP classloader for the specified JNLP file.
     314        URL codebase = UrlUtils.guessCodeBase(file);
     315        this.security = securityDelegate.getClassLoaderSecurity(codebase.getHost());
     316    }
     317
     318    /**
     319     * Gets the lock for a given unique key, creating one if it does not yet exist.
     320     * This operation is atomic & thread-safe.
     321     *
     322     * @param uniqueKey the file whose unique key should be used
     323     * @return the lock
     324     */
     325    private static ReentrantLock getUniqueKeyLock(String uniqueKey) {
     326        synchronized (uniqueKeyToLock) {
     327            ReentrantLock storedLock = uniqueKeyToLock.get(uniqueKey);
     328
     329            if (storedLock == null) {
     330                storedLock = new ReentrantLock();
     331                uniqueKeyToLock.put(uniqueKey, storedLock);
     332            }
     333
     334            return storedLock;
     335        }
     336    }
     337
     338    /**
     339     * Creates a fully initialized JNLP classloader for the specified JNLPFile,
     340     * to be used as an applet/application's classloader.
     341     * In contrast, JNLP classloaders can also be constructed simply to merge
     342     * its resources into another classloader.
    325343     *
    326344     * @param file the file to load classes for
    327345     * @param policy the update policy to use when downloading resources
    328      */
    329     public static JNLPClassLoader getInstance(JNLPFile file, UpdatePolicy policy) throws LaunchException {
    330         return getInstance(file, policy, null);
     346     * @param mainName Overrides the main class name of the application
     347     */
     348    private static JNLPClassLoader createInstance(JNLPFile file, UpdatePolicy policy, String mainName, boolean enableCodeBase) throws LaunchException {
     349        String uniqueKey = file.getUniqueKey();
     350        JNLPClassLoader baseLoader = uniqueKeyToLoader.get(uniqueKey);
     351        JNLPClassLoader loader = new JNLPClassLoader(file, policy, mainName, enableCodeBase);
     352
     353        // If security level is 'high' or greater, we must check if the user allows unsigned applets
     354        // when the JNLPClassLoader is created. We do so here, because doing so in the constructor
     355        // causes unwanted side-effects for some applets. However, if the loader has been tagged
     356        // with "runInSandbox", then we do not show this dialog - since this tag indicates that
     357        // the user was already shown a CertWarning dialog and has chosen to run the applet sandboxed.
     358        // This means they've already agreed to running the applet and have specified with which
     359        // permission level to do it!
     360        if (loader.getSigningState() == SigningState.PARTIAL) {
     361            loader.securityDelegate.promptUserOnPartialSigning();
     362        } else if (!loader.getSigning() && !loader.securityDelegate.userPromptedForSandbox() && file instanceof PluginBridge) {
     363            UnsignedAppletTrustConfirmation.checkUnsignedWithUserIfRequired((PluginBridge)file);
     364        }
     365
     366        // New loader init may have caused extentions to create a
     367        // loader for this unique key. Check.
     368        JNLPClassLoader extLoader = uniqueKeyToLoader.get(uniqueKey);
     369
     370        if (extLoader != null && extLoader != loader) {
     371            if (loader.getSigning() != extLoader.getSigning()) {
     372                loader.securityDelegate.promptUserOnPartialSigning();
     373            }
     374            loader.merge(extLoader);
     375            extLoader.decrementLoaderUseCount(); // loader urls have been merged, ext loader is no longer used
     376        }
     377
     378        // loader is now current + ext. But we also need to think of
     379        // the baseLoader
     380        if (baseLoader != null && baseLoader != loader) {
     381           loader.merge(baseLoader);
     382        }
     383
     384        return loader;
     385    }
     386
     387    /**
     388     * Returns a JNLP classloader for the specified JNLP file.
     389     *
     390     * @param file the file to load classes for
     391     * @param policy the update policy to use when downloading resources
     392     */
     393    public static JNLPClassLoader getInstance(JNLPFile file, UpdatePolicy policy, boolean enableCodeBase) throws LaunchException {
     394        return getInstance(file, policy, null, enableCodeBase);
    331395    }
    332396
     
    338402     * @param mainName Overrides the main class name of the application
    339403     */
    340     public static JNLPClassLoader getInstance(JNLPFile file, UpdatePolicy policy, String mainName) throws LaunchException {
     404    public static JNLPClassLoader getInstance(JNLPFile file, UpdatePolicy policy, String mainName, boolean enableCodeBase) throws LaunchException {
    341405        JNLPClassLoader baseLoader = null;
    342406        JNLPClassLoader loader = null;
    343407        String uniqueKey = file.getUniqueKey();
    344408
    345         if (uniqueKey != null)
    346             baseLoader = urlToLoader.get(uniqueKey);
    347 
    348         try {
    349 
     409        synchronized ( getUniqueKeyLock(uniqueKey) ) {
     410            baseLoader = uniqueKeyToLoader.get(uniqueKey);
    350411
    351412            // A null baseloader implies that no loader has been created
     
    355416                     !baseLoader.getJNLPFile().getFileLocation().equals(file.getFileLocation()))) {
    356417
    357                 loader = new JNLPClassLoader(file, policy, mainName);
    358 
    359                 // New loader init may have caused extentions to create a
    360                 // loader for this unique key. Check.
    361                 JNLPClassLoader extLoader = urlToLoader.get(uniqueKey);
    362 
    363                 if (extLoader != null && extLoader != loader) {
    364                     if (loader.signing && !extLoader.signing)
    365                         if (!SecurityDialogs.showNotAllSignedWarningDialog(file))
    366                             throw new LaunchException(file, null, R("LSFatal"), R("LCClient"), R("LSignedAppJarUsingUnsignedJar"), R("LSignedAppJarUsingUnsignedJarInfo"));
    367 
    368                     loader.merge(extLoader);
    369                     extLoader.decrementLoaderUseCount(); // loader urls have been merged, ext loader is no longer used
    370                 }
    371 
    372                 // loader is now current + ext. But we also need to think of
    373                 // the baseLoader
    374                 if (baseLoader != null && baseLoader != loader) {
    375                    loader.merge(baseLoader);
    376                 }
    377 
     418                loader = createInstance(file, policy, mainName, enableCodeBase);
    378419            } else {
    379420                // if key is same and locations match, this is the loader we want
    380421                if (!file.isApplication()) {
    381422                    // If this is an applet, we do need to consider its loader
    382                    loader = new JNLPClassLoader(file, policy, mainName);
     423                    loader = new JNLPClassLoader(file, policy, mainName, enableCodeBase);
    383424
    384425                    if (baseLoader != null)
     
    388429            }
    389430
    390         } catch (LaunchException e) {
    391             throw e;
    392         }
    393 
    394         // loaders are mapped to a unique key. Only extensions and parent
    395         // share a key, so it is safe to always share based on it
    396        
    397         loader.incrementLoaderUseCount();
    398         synchronized(urlToLoader) {
    399             urlToLoader.put(uniqueKey, loader);
     431            // loaders are mapped to a unique key. Only extensions and parent
     432            // share a key, so it is safe to always share based on it
     433
     434            loader.incrementLoaderUseCount();
     435
     436            uniqueKeyToLoader.put(uniqueKey, loader);
    400437        }
    401438
     
    412449     * @param mainName Overrides the main class name of the application
    413450     */
    414     public static JNLPClassLoader getInstance(URL location, String uniqueKey, Version version, UpdatePolicy policy, String mainName)
     451    public static JNLPClassLoader getInstance(URL location, String uniqueKey, Version version, ParserSettings settings, UpdatePolicy policy, String mainName, boolean enableCodeBase)
    415452            throws IOException, ParseException, LaunchException {
    416         JNLPClassLoader loader = urlToLoader.get(uniqueKey);
    417 
    418         if (loader == null || !location.equals(loader.getJNLPFile().getFileLocation())) {
    419             JNLPFile jnlpFile = new JNLPFile(location, uniqueKey, version, false, policy);
    420 
    421             loader = getInstance(jnlpFile, policy, mainName);
     453
     454        JNLPClassLoader loader;
     455
     456        synchronized ( getUniqueKeyLock(uniqueKey) ) {
     457            loader = uniqueKeyToLoader.get(uniqueKey);
     458
     459            if (loader == null || !location.equals(loader.getJNLPFile().getFileLocation())) {
     460                JNLPFile jnlpFile = new JNLPFile(location, uniqueKey, version, settings, policy);
     461
     462                loader = getInstance(jnlpFile, policy, mainName, enableCodeBase);
     463            }
    422464        }
    423465
     
    429471     */
    430472    void initializeExtensions() {
    431         ExtensionDesc[] ext = resources.getExtensions();
     473        ExtensionDesc[] extDescs = resources.getExtensions();
    432474
    433475        List<JNLPClassLoader> loaderList = new ArrayList<JNLPClassLoader>();
     
    448490
    449491        //if (ext != null) {
    450         for (int i = 0; i < ext.length; i++) {
     492        for (ExtensionDesc ext : extDescs) {
    451493            try {
    452494                String uniqueKey = this.getJNLPFile().getUniqueKey();
    453                 JNLPClassLoader loader = getInstance(ext[i].getLocation(), uniqueKey, ext[i].getVersion(), updatePolicy, mainClass);
     495                JNLPClassLoader loader = getInstance(ext.getLocation(), uniqueKey, ext.getVersion(), file.getParserSettings(), updatePolicy, mainClass, this.enableCodeBase);
    454496                loaderList.add(loader);
    455497            } catch (Exception ex) {
    456                 ex.printStackTrace();
     498                OutputController.getLogger().log(OutputController.Level.ERROR_ALL, ex);
    457499            }
    458500        }
     
    469511
    470512        JARDesc jars[] = resources.getJARs();
    471         for (int i = 0; i < jars.length; i++) {
    472             Permission p = CacheUtil.getReadPermission(jars[i].getLocation(),
    473                                                        jars[i].getVersion());
    474 
    475             if (JNLPRuntime.isDebug()) {
    476                 if (p == null)
    477                     System.out.println("Unable to add permission for " + jars[i].getLocation());
    478                 else
    479                     System.out.println("Permission added: " + p.toString());
     513        for (JARDesc jar : jars) {
     514            Permission p = CacheUtil.getReadPermission(jar.getLocation(), jar.getVersion());
     515
     516            if (p == null) {
     517                OutputController.getLogger().log("Unable to add permission for " + jar.getLocation());
     518            } else {
     519                OutputController.getLogger().log("Permission added: " + p.toString());
    480520            }
    481521            if (p != null)
     
    489529     * @return true if file exists AND is an invalid jar, false otherwise
    490530     */
    491     private boolean isInvalidJar(JARDesc jar){
     531    boolean isInvalidJar(JARDesc jar){
    492532        File cacheFile = tracker.getCacheFile(jar.getLocation());
    493533        if (cacheFile == null)
     
    529569                    addToCodeBaseLoader(new URL(file.getCodeBase(), codeBaseFolder));
    530570                } catch (MalformedURLException mfe) {
    531                     System.err.println("Problem trying to add folder to code base:");
    532                     System.err.println(mfe.getMessage());
     571                    OutputController.getLogger().log(OutputController.Level.WARNING_ALL, "Problem trying to add folder to code base:");
     572                    OutputController.getLogger().log(OutputController.Level.ERROR_ALL, mfe);
    533573                }
    534574            }
     
    537577        JARDesc jars[] = resources.getJARs();
    538578
    539         if (jars == null || jars.length == 0) {
    540 
    541             boolean allSigned = true;
     579        if (jars.length == 0) {
     580
     581            boolean allSigned = (loaders.length > 1) /* has extensions */;
    542582            for (int i = 1; i < loaders.length; i++) {
    543583                if (!loaders[i].getSigning()) {
     
    547587            }
    548588
    549             if(allSigned)
    550                 signing = true;
     589            if (allSigned)
     590                signing = SigningState.FULL;
    551591
    552592            //Check if main jar is found within extensions
     
    563603        List<JARDesc> initialJars = new ArrayList<JARDesc>();
    564604
    565         for (int i = 0; i < jars.length; i++) {
    566 
    567             available.add(jars[i]);
    568 
    569             if (jars[i].isEager())
    570                 initialJars.add(jars[i]); // regardless of part
    571 
    572             tracker.addResource(jars[i].getLocation(),
    573                                 jars[i].getVersion(),
    574                                 getDownloadOptionsForJar(jars[i]),
    575                                 jars[i].isCacheable() ? JNLPRuntime.getDefaultUpdatePolicy() : UpdatePolicy.FORCE
    576                                );
    577         }
    578        
     605        for (JARDesc jar : jars) {
     606
     607            available.add(jar);
     608
     609            if (jar.isEager())
     610                initialJars.add(jar); // regardless of part
     611
     612            tracker.addResource(jar.getLocation(),
     613                    jar.getVersion(), file.getDownloadOptions(),
     614                    jar.isCacheable() ? JNLPRuntime.getDefaultUpdatePolicy() : UpdatePolicy.FORCE);
     615        }
     616
    579617        //If there are no eager jars, initialize the first jar
    580618        if(initialJars.size() == 0)
     
    603641        if (JNLPRuntime.isVerifying()) {
    604642
    605             JarCertVerifier jcv;
    606 
    607643            try {
    608                 jcv = verifyJars(initialJars);
     644                jcv.add(initialJars, tracker);
    609645            } catch (Exception e) {
    610646                //we caught an Exception from the JarCertVerifier class.
    611647                //Note: one of these exceptions could be from not being able
    612648                //to read the cacerts or trusted.certs files.
    613                 e.printStackTrace();
     649                OutputController.getLogger().log(OutputController.Level.ERROR_ALL, e);
    614650                throw new LaunchException(null, null, R("LSFatal"),
    615                                         R("LCInit"), R("LFatalVerification"), R("LFatalVerificationInfo"));
     651                                        R("LCInit"), R("LFatalVerification"), R("LFatalVerificationInfo") + ": " +e.getMessage());
    616652            }
    617653
    618654            //Case when at least one jar has some signing
    619             if (jcv.anyJarsSigned() && jcv.isFullySignedByASingleCert()) {
    620                 signing = true;
    621 
    622                 if (!jcv.allJarsSigned() &&
    623                                     !SecurityDialogs.showNotAllSignedWarningDialog(file))
    624                     throw new LaunchException(file, null, R("LSFatal"), R("LCClient"), R("LSignedAppJarUsingUnsignedJar"), R("LSignedAppJarUsingUnsignedJarInfo"));
    625 
     655            if (jcv.isFullySigned()) {
     656                signing = SigningState.FULL;
    626657
    627658                // Check for main class in the downloaded jars, and check/verify signed JNLP fill
     
    629660
    630661                // If jar with main class was not found, check available resources
    631                 while (!foundMainJar && available != null && available.size() != 0) 
     662                while (!foundMainJar && available != null && available.size() != 0)
    632663                    addNextResource();
    633664
     
    636667                foundMainJar = foundMainJar || hasMainInExtensions();
    637668
    638                 // If jar with main class was not found and there are no more
    639                 // available jars, throw a LaunchException
    640                 if (file.getLaunchInfo() != null) {
    641                     if (!foundMainJar
    642                             && (available == null || available.size() == 0))
    643                         throw new LaunchException(file, null, R("LSFatal"),
    644                                 R("LCClient"), R("LCantDetermineMainClass"),
    645                                 R("LCantDetermineMainClassInfo"));
     669                boolean externalAppletMainClass = (file.getLaunchInfo() != null && !foundMainJar
     670                        && (available == null || available.size() == 0));
     671
     672                // We do this check here simply to ensure that if there are no JARs at all,
     673                // and also no main-class in the codebase (ie the applet doesn't really exist), we
     674                // fail ASAP rather than continuing (and showing the NotAllSigned dialog for no applet)
     675                if (externalAppletMainClass) {
     676                    if (codeBaseLoader != null) {
     677                        try {
     678                            codeBaseLoader.findClass(mainClass);
     679                        } catch (ClassNotFoundException extCnfe) {
     680                            OutputController.getLogger().log(OutputController.Level.ERROR_ALL, extCnfe);
     681                            throw new LaunchException(file, extCnfe, R("LSFatal"), R("LCInit"), R("LCantDetermineMainClass"), R("LCantDetermineMainClassInfo"));
     682                        }
     683                    } else {
     684                        throw new LaunchException(file, null, R("LSFatal"), R("LCInit"), R("LCantDetermineMainClass"), R("LCantDetermineMainClassInfo"));
     685                    }
     686                }
     687
     688                // If externalAppletMainClass is true and a LaunchException was not thrown above,
     689                // then the main-class can be loaded from the applet codebase, but is obviously not signed
     690                if (!jcv.allJarsSigned()) {
     691                    checkPartialSigningWithUser();
    646692                }
    647693
    648694                // If main jar was found, but a signed JNLP file was not located
    649                 if (!isSignedJNLP && foundMainJar) 
     695                if (!isSignedJNLP && foundMainJar)
    650696                    file.setSignedJNLPAsMissing();
    651                
     697
    652698                //user does not trust this publisher
    653                 if (!jcv.getAlreadyTrustPublisher()) {
    654                     checkTrustWithUser(jcv);
     699                if (!jcv.isTriviallySigned()) {
     700                    checkTrustWithUser();
    655701                } else {
    656702                    /**
     
    661707            } else {
    662708
    663                 signing = false;
    664                 //otherwise this jar is simply unsigned -- make sure to ask
    665                 //for permission on certain actions
    666             }
    667         }
    668 
     709                // Otherwise this jar is simply unsigned -- make sure to ask
     710                // for permission on certain actions
     711                signing = SigningState.NONE;
     712            }
     713        }
     714
     715        boolean containsSignedJar = false, containsUnsignedJar = false;
    669716        for (JARDesc jarDesc : file.getResources().getJARs()) {
     717            File cachedFile;
     718
    670719            try {
    671 
    672                 File cachedFile;
    673 
    674                 try {
    675                     cachedFile = tracker.getCacheFile(jarDesc.getLocation());
    676                 } catch (IllegalResourceDescriptorException irde){
    677                     //Caused by ignored resource being removed due to not being valid
    678                     System.err.println("JAR " + jarDesc.getLocation() + " is not a valid jar file. Continuing.");
    679                     continue;
    680                 }
    681 
    682                 if (cachedFile == null) {
    683                     System.err.println("JAR " + jarDesc.getLocation() + " not found. Continuing.");
    684                     continue; // JAR not found. Keep going.
    685                 }
    686 
    687                 // TODO: Should be toURI().toURL()
    688                 URL location = cachedFile.toURL();
    689                 SecurityDesc jarSecurity = file.getSecurity();
    690 
    691                 if (file instanceof PluginBridge) {
    692 
    693                     URL codebase = null;
    694 
    695                     if (file.getCodeBase() != null) {
    696                         codebase = file.getCodeBase();
    697                     } else {
    698                         //Fixme: codebase should be the codebase of the Main Jar not
    699                         //the location. Although, it still works in the current state.
    700                         codebase = file.getResources().getMainJAR().getLocation();
    701                     }
    702 
    703                     if (signing) {
    704                         jarSecurity = new SecurityDesc(file,
    705                                                         SecurityDesc.ALL_PERMISSIONS,
    706                                                         codebase.getHost());
    707                     } else {
    708                         jarSecurity = new SecurityDesc(file,
    709                                                         SecurityDesc.SANDBOX_PERMISSIONS,
    710                                                         codebase.getHost());
    711                     }
    712                 }
    713 
    714                 jarLocationSecurityMap.put(jarDesc.getLocation(), jarSecurity);
    715             } catch (MalformedURLException mfe) {
    716                 System.err.println(mfe.getMessage());
    717             }
    718         }
     720                cachedFile = tracker.getCacheFile(jarDesc.getLocation());
     721            } catch (IllegalResourceDescriptorException irde) {
     722                //Caused by ignored resource being removed due to not being valid
     723                OutputController.getLogger().log(OutputController.Level.ERROR_ALL, "JAR " + jarDesc.getLocation() + " is not a valid jar file. Continuing.");
     724                continue;
     725            }
     726
     727            if (cachedFile == null) {
     728                OutputController.getLogger().log(OutputController.Level.ERROR_ALL, "JAR " + jarDesc.getLocation() + " not found. Continuing.");
     729                continue; // JAR not found. Keep going.
     730            }
     731
     732            final URL codebase;
     733            if (file.getCodeBase() != null) {
     734                codebase = file.getCodeBase();
     735            } else {
     736                // FIXME: codebase should be the codebase of the Main Jar not
     737                // the location. Although, it still works in the current state.
     738                codebase = file.getResources().getMainJAR().getLocation();
     739            }
     740
     741            final SecurityDesc jarSecurity = securityDelegate.getCodebaseSecurityDesc(jarDesc, codebase.getHost());
     742            if (jarSecurity.getSecurityType().equals(SecurityDesc.SANDBOX_PERMISSIONS)) {
     743                containsUnsignedJar = true;
     744            } else {
     745                containsSignedJar = true;
     746            }
     747
     748            jarLocationSecurityMap.put(jarDesc.getLocation(), jarSecurity);
     749        }
     750
     751        if (containsSignedJar && containsUnsignedJar) {
     752            checkPartialSigningWithUser();
     753        }
     754
    719755        activateJars(initialJars);
    720756    }
    721757   
     758     /***
     759     * Checks for the jar that contains the attribute.
     760     *
     761     * @param jars Jars that are checked to see if they contain the main class
     762     * @param  name attribute to be found
     763     */
     764    public String checkForAttributeInJars(List<JARDesc> jars, Attributes.Name name) {
     765       
     766        if (jars.isEmpty()) {
     767            return null;
     768        }
     769
     770        String result = null;
     771       
     772        // Check main jar
     773        JARDesc mainJarDesc = ResourcesDesc.getMainJAR(jars);
     774        result = getManifestAttribute(mainJarDesc.getLocation(), name);
     775
     776        if (result != null) {
     777            return result;
     778        }
     779       
     780        // Check first jar
     781        JARDesc firstJarDesc = jars.get(0);
     782        result = getManifestAttribute(firstJarDesc.getLocation(),name);
     783       
     784        if (result != null) {
     785            return result;
     786        }
     787
     788        // Still not found? Iterate and set if only 1 was found
     789        for (JARDesc jarDesc: jars) {
     790            String attributeInThisJar = getManifestAttribute(jarDesc.getLocation(), name);
     791                if (attributeInThisJar != null) {
     792                    if (result == null) { // first main class
     793                        result = attributeInThisJar;
     794                    } else { // There is more than one main class. Set to null and break.
     795                        result = null;
     796                        break;
     797                }
     798            }
     799        }
     800        return result;
     801    }
    722802    /***
    723803     * Checks for the jar that contains the main class. If the main class was
     
    728808     * @throws LaunchException Thrown if the signed JNLP file, within the main jar, fails to be verified or does not match
    729809     */
    730     private void checkForMain(List<JARDesc> jars) throws LaunchException {
     810    void checkForMain(List<JARDesc> jars) throws LaunchException {
    731811
    732812        // Check launch info
    733813        if (mainClass == null) {
    734814            LaunchDesc launchDesc = file.getLaunchInfo();
    735             if (launchDesc == null) {
    736                 return;
    737             }
    738 
    739             mainClass = launchDesc.getMainClass();
     815            if (launchDesc != null) {
     816                mainClass = launchDesc.getMainClass();
     817            }
    740818        }
    741819
    742820        // The main class may be specified in the manifest
    743821
    744         // Check main jar
    745822        if (mainClass == null) {
    746             JARDesc mainJarDesc = file.getResources().getMainJAR();
    747             mainClass = getMainClassName(mainJarDesc.getLocation());
    748         }
    749 
    750         // Check first jar
    751         if (mainClass == null) {
    752             JARDesc firstJarDesc = jars.get(0);
    753             mainClass = getMainClassName(firstJarDesc.getLocation());
    754         }
    755 
    756         // Still not found? Iterate and set if only 1 was found
    757         if (mainClass == null) {
    758 
    759             for (JARDesc jarDesc: jars) {
    760                 String mainClassInThisJar = getMainClassName(jarDesc.getLocation());
    761 
    762                 if (mainClassInThisJar != null) {
    763 
    764                     if (mainClass == null) { // first main class
    765                         mainClass = mainClassInThisJar;
    766                     } else { // There is more than one main class. Set to null and break.
    767                         mainClass = null;
     823            mainClass = checkForAttributeInJars(jars, Attributes.Name.MAIN_CLASS);
     824        }
     825
     826        String desiredJarEntryName = mainClass + ".class";
     827
     828        for (JARDesc jar : jars) {
     829
     830            try {
     831                File localFile = tracker
     832                        .getCacheFile(jar.getLocation());
     833
     834                if (localFile == null) {
     835                    OutputController.getLogger().log(OutputController.Level.ERROR_ALL, "JAR " + jar.getLocation() + " not found. Continuing.");
     836                    continue; // JAR not found. Keep going.
     837                }
     838
     839                JarFile jarFile = new JarFile(localFile);
     840
     841                for (JarEntry entry : Collections.list(jarFile.entries())) {
     842                    String jeName = entry.getName().replaceAll("/", ".");
     843                    if (jeName.equals(desiredJarEntryName)) {
     844                        foundMainJar = true;
     845                        verifySignedJNLP(jar, jarFile);
    768846                        break;
    769847                    }
    770848                }
    771             }
    772         }
    773 
    774         String desiredJarEntryName = mainClass + ".class";
    775 
    776         for (int i = 0; i < jars.size(); i++) {
    777 
    778             try {
    779                 File localFile = tracker
    780                         .getCacheFile(jars.get(i).getLocation());
    781 
    782                 if (localFile == null) {
    783                     System.err.println("JAR " + jars.get(i).getLocation() + " not found. Continuing.");
    784                     continue; // JAR not found. Keep going.
    785                 }
    786 
    787                 JarFile jarFile = new JarFile(localFile);
    788                 Enumeration<JarEntry> entries = jarFile.entries();
    789                 JarEntry je;
    790 
    791                 while (entries.hasMoreElements()) {
    792                     je = entries.nextElement();
    793                     String jeName = je.getName().replaceAll("/", ".");
    794                     if (jeName.equals(desiredJarEntryName)) {
    795                         foundMainJar = true;
    796                         verifySignedJNLP(jars.get(i), jarFile);
    797                         break;
    798                     }
    799                 }
     849
     850                jarFile.close();
    800851            } catch (IOException e) {
    801852                /*
     
    814865     * @return the main class name, null if there isn't one of if there was an error
    815866     */
    816     private String getMainClassName(URL location) {
    817 
    818         String mainClass = null;
     867    String getMainClassName(URL location) {
     868        return getManifestAttribute(location, Attributes.Name.MAIN_CLASS);
     869    }
     870   
     871   
     872    /**
     873     * Gets the name of the main method if specified in the manifest
     874     *
     875     * @param location The JAR location
     876     * @return the attribute value, null if there isn't one of if there was an error
     877     */
     878    public String getManifestAttribute(URL location, Attributes.Name  attribute) {
     879
     880        String attributeValue = null;
    819881        File f = tracker.getCacheFile(location);
    820882
    821883        if( f != null) {
     884            JarFile mainJar = null;
    822885            try {
    823                 JarFile mainJar = new JarFile(f);
    824                 mainClass = mainJar.getManifest().
    825                         getMainAttributes().getValue("Main-Class");
     886                mainJar = new JarFile(f);
     887                Manifest manifest = mainJar.getManifest();
     888                if (manifest == null || manifest.getMainAttributes() == null){
     889                    //yes, jars without manifest exists
     890                    return null;
     891                }
     892                attributeValue = manifest.getMainAttributes().getValue(attribute);
    826893            } catch (IOException ioe) {
    827                 mainClass = null;
    828             }
    829         }
    830 
    831         return mainClass;
     894                attributeValue = null;
     895            } finally {
     896                StreamUtils.closeSilently(mainJar);
     897            }
     898        }
     899
     900        return attributeValue;
    832901    }
    833902
     
    863932            throws LaunchException {
    864933
    865         JarCertVerifier signer = new JarCertVerifier();
    866934        List<JARDesc> desc = new ArrayList<JARDesc>();
    867935        desc.add(jarDesc);
     
    874942
    875943        try {
    876             signer.verifyJars(desc, tracker);
    877 
    878             if (signer.allJarsSigned()) { // If the jar is signed
    879 
    880                 Enumeration<JarEntry> entries = jarFile.entries();
    881                 JarEntry je;
    882 
    883                 while (entries.hasMoreElements()) {
    884                     je = entries.nextElement();
     944            // NOTE: verification should have happened by now. In other words,
     945            // calling jcv.verifyJars(desc, tracker) here should have no affect.
     946            if (jcv.isFullySigned()) {
     947
     948                for (JarEntry je : Collections.list(jarFile.entries())) {
    885949                    String jeName = je.getName().toUpperCase();
    886950
    887951                    if (jeName.equals(TEMPLATE) || jeName.equals(APPLICATION)) {
    888952
    889                         if (JNLPRuntime.isDebug())
    890                             System.err.println("Creating Jar InputStream from JarEntry");
     953                        OutputController.getLogger().log(OutputController.Level.ERROR_DEBUG, "Creating Jar InputStream from JarEntry");
    891954
    892955                        inStream = jarFile.getInputStream(je);
    893956                        inputReader = new InputStreamReader(inStream);
    894957
    895                         if (JNLPRuntime.isDebug())
    896                             System.err.println("Creating File InputStream from lauching JNLP file");
     958                        OutputController.getLogger().log(OutputController.Level.ERROR_DEBUG, "Creating File InputStream from lauching JNLP file");
    897959
    898960                        JNLPFile jnlp = this.getJNLPFile();
     
    913975
    914976                        if (jeName.equals(APPLICATION)) { // If signed application was found
    915                             if (JNLPRuntime.isDebug())
    916                                 System.err.println("APPLICATION.JNLP has been located within signed JAR. Starting verfication...");
     977                            OutputController.getLogger().log(OutputController.Level.ERROR_DEBUG, "APPLICATION.JNLP has been located within signed JAR. Starting verfication...");
    917978                           
    918979                            matcher = new JNLPMatcher(inputReader, jnlpReader, false);
    919980                        } else { // Otherwise template was found
    920                             if (JNLPRuntime.isDebug())
    921                                 System.err.println("APPLICATION_TEMPLATE.JNLP has been located within signed JAR. Starting verfication...");
     981                            OutputController.getLogger().log(OutputController.Level.ERROR_DEBUG, "APPLICATION_TEMPLATE.JNLP has been located within signed JAR. Starting verfication...");
    922982                           
    923983                            matcher = new JNLPMatcher(inputReader, jnlpReader,
     
    930990
    931991                        this.isSignedJNLP = true;
    932                         if (JNLPRuntime.isDebug())
    933                             System.err.println("Signed Application Verification Successful");
     992                        OutputController.getLogger().log(OutputController.Level.ERROR_DEBUG, "Signed Application Verification Successful");
    934993
    935994                        break;
     
    9541013        } catch (Exception e) {
    9551014           
    956             if (JNLPRuntime.isDebug())
    957                 e.printStackTrace(System.err);
     1015            OutputController.getLogger().log(e);
    9581016
    9591017            /*
    9601018             * After this exception is caught, it is escaped. If an exception is
    9611019             * thrown while handling the jar file, (mainly for
    962              * JarCertVerifier.verifyJars) it assumes the jar file is unsigned and
     1020             * JarCertVerifier.add) it assumes the jar file is unsigned and
    9631021             * skip the check for a signed JNLP file
    9641022             */
     
    9671025
    9681026            //Close all streams
    969             closeStream(inStream);
    970             closeStream(inputReader);
    971             closeStream(fr);
    972             closeStream(jnlpReader);
    973         }
    974 
    975         if (JNLPRuntime.isDebug())
    976             System.err.println("Ending check for signed JNLP file...");
    977     }
    978 
    979     /***
    980      * Closes a stream
    981      *
    982      * @param stream the stream that will be closed
    983      */
    984     private void closeStream (Closeable stream) {
    985         if (stream != null)
    986             try {
    987                 stream.close();
    988             } catch (Exception e) {
    989                 e.printStackTrace(System.err);
    990             }
    991     }
    992    
    993     private void checkTrustWithUser(JarCertVerifier jcv) throws LaunchException {
    994         if (JNLPRuntime.isTrustAll()){
     1027            StreamUtils.closeSilently(inStream);
     1028            StreamUtils.closeSilently(inputReader);
     1029            StreamUtils.closeSilently(fr);
     1030            StreamUtils.closeSilently(jnlpReader);
     1031        }
     1032
     1033        OutputController.getLogger().log(OutputController.Level.ERROR_DEBUG, "Ending check for signed JNLP file...");
     1034    }
     1035
     1036    /**
     1037     * Prompt the user for trust on all the signers that require approval.
     1038     * @throws LaunchException if the user does not approve every dialog prompt.
     1039     */
     1040    private void checkTrustWithUser() throws LaunchException {
     1041        if (JNLPRuntime.isTrustNone()) {
     1042            if (!securityDelegate.getRunInSandbox()) {
     1043                setRunInSandbox();
     1044            }
    9951045            return;
    9961046        }
    997         if (!jcv.getRootInCacerts()) { //root cert is not in cacerts
    998             boolean b = SecurityDialogs.showCertWarningDialog(
    999                     AccessType.UNVERIFIED, file, jcv);
    1000             if (!b)
    1001                 throw new LaunchException(null, null, R("LSFatal"),
    1002                         R("LCLaunching"), R("LNotVerified"), "");
    1003         } else if (jcv.getRootInCacerts()) { //root cert is in cacerts
    1004             boolean b = false;
    1005             if (jcv.noSigningIssues())
    1006                 b = SecurityDialogs.showCertWarningDialog(
    1007                         AccessType.VERIFIED, file, jcv);
    1008             else if (!jcv.noSigningIssues())
    1009                 b = SecurityDialogs.showCertWarningDialog(
    1010                         AccessType.SIGNING_ERROR, file, jcv);
    1011             if (!b)
    1012                 throw new LaunchException(null, null, R("LSFatal"),
    1013                         R("LCLaunching"), R("LCancelOnUserRequest"), "");
    1014         }
     1047        if (JNLPRuntime.isTrustAll() || securityDelegate.getRunInSandbox()) {
     1048            return;
     1049        }
     1050
     1051        if (getSigningState() == SigningState.FULL && jcv.isFullySigned() && !jcv.getAlreadyTrustPublisher()) {
     1052            jcv.checkTrustWithUser(securityDelegate, file);
     1053        }
     1054    }
     1055
     1056    /*
     1057     * Sets whether applets are to be run sandboxed, regardless of JAR
     1058     * signing. This MUST be called before any call to initializeResources,
     1059     * setSecurity, activateJars, or any other method that sets the value
     1060     * of this.security or adds entries into this.jarLocationSecurityMap.
     1061     * @throws LaunchException if security settings have been initialized before
     1062     * this method is called
     1063     */
     1064    public void setRunInSandbox() throws LaunchException {
     1065        securityDelegate.setRunInSandbox();
     1066    }
     1067
     1068    public boolean userPromptedForSandbox() {
     1069        return securityDelegate.getRunInSandbox();
    10151070    }
    10161071
     
    10301085    public void setApplication(ApplicationInstance app) {
    10311086        if (this.app != null) {
    1032             if (JNLPRuntime.isDebug()) {
    1033                 Exception ex = new IllegalStateException("Application can only be set once");
    1034                 ex.printStackTrace();
    1035             }
     1087                OutputController.getLogger().log(new IllegalStateException("Application can only be set once"));
    10361088            return;
    10371089        }
     
    10871139                    }
    10881140                    if (getCodeSourceSecurity(cs.getLocation()).getSecurityType() == null) {
    1089                         if (JNLPRuntime.isDebug()){
    1090                         new NullPointerException("Warning! Code source security type was null").printStackTrace();
    1091                         }
     1141                        OutputController.getLogger().log(new NullPointerException("Warning! Code source security type was null"));
    10921142                    }
    10931143                    Object securityType = getCodeSourceSecurity(cs.getLocation()).getSecurityType();
     
    10991149                }
    11001150
    1101                 Enumeration<Permission> e = permissions.elements();
    1102                 while (e.hasMoreElements()) {
    1103                     result.add(e.nextElement());
     1151                for (Permission perm : Collections.list(permissions.elements())) {
     1152                    result.add(perm);
    11041153                }
    11051154            }
    11061155
    11071156            // add in permission to read the cached JAR files
    1108             for (int i = 0; i < resourcePermissions.size(); i++) {
    1109                 result.add(resourcePermissions.get(i));
     1157            for (Permission perm : resourcePermissions) {
     1158                result.add(perm);
    11101159            }
    11111160
    11121161            // add in the permissions that the user granted.
    1113             for (int i = 0; i < runtimePermissions.size(); i++) {
    1114                 result.add(runtimePermissions.get(i));
     1162            for (Permission perm : runtimePermissions) {
     1163                result.add(perm);
    11151164            }
    11161165
    11171166            // Class from host X should be allowed to connect to host X
    1118             if (cs.getLocation().getHost().length() > 0)
     1167            if (cs.getLocation() != null && cs.getLocation().getHost().length() > 0)
    11191168                result.add(new SocketPermission(cs.getLocation().getHost(),
    11201169                        "connect, accept"));
     
    11221171            return result;
    11231172        } catch (RuntimeException ex) {
    1124             if (JNLPRuntime.isDebug()) {
    1125                 ex.printStackTrace();
    1126             }
     1173            OutputController.getLogger().log(ex);
    11271174            throw ex;
    11281175        }
     
    11391186     */
    11401187    protected void fillInPartJars(List<JARDesc> jars) {
    1141         for (int i = 0; i < jars.size(); i++) {
    1142             String part = jars.get(i).getPart();
    1143 
    1144             for (int a = 0; a < available.size(); a++) {
    1145                 JARDesc jar = available.get(a);
    1146 
    1147                 if (part != null && part.equals(jar.getPart()))
    1148                     if (!jars.contains(jar))
    1149                         jars.add(jar);
     1188        for (JARDesc desc : jars) {
     1189            String part = desc.getPart();
     1190
     1191            // "available" field can be affected by two different threads
     1192            // working in loadClass(String)
     1193            synchronized (available) {
     1194                for (JARDesc jar : available) {
     1195                    if (part != null && part.equals(jar.getPart()))
     1196                        if (!jars.contains(jar))
     1197                            jars.add(jar);
     1198                }
    11501199            }
    11511200        }
     
    11681217                waitForJars(jars);
    11691218
    1170                 for (int i = 0; i < jars.size(); i++) {
    1171                     JARDesc jar = jars.get(i);
    1172 
     1219                for (JARDesc jar : jars) {
    11731220                    available.remove(jar);
    11741221
     
    11901237
    11911238                            JarFile jarFile = new JarFile(localFile);
    1192                             Enumeration<JarEntry> e = jarFile.entries();
    1193                             while (e.hasMoreElements()) {
    1194                                 JarEntry je = e.nextElement();
     1239                            for (JarEntry je : Collections.list(jarFile.entries())) {
    11951240
    11961241                                // another jar in my jar? it is more likely than you think
     
    12251270                                    }
    12261271
    1227                                     JarCertVerifier signer = new JarCertVerifier();
    1228                                     List<JARDesc> jars = new ArrayList<JARDesc>();
    1229                                     JARDesc jarDesc = new JARDesc(new File(extractedJarLocation).toURL(), null, null, false, false, false, false);
    1230                                     jars.add(jarDesc);
    12311272                                    tracker.addResource(new File(extractedJarLocation).toURL(), null, null, null);
    1232                                     signer.verifyJars(jars, tracker);
    1233 
    1234                                     if (signer.anyJarsSigned() && !signer.getAlreadyTrustPublisher()) {
    1235                                         checkTrustWithUser(signer);
     1273
     1274                                    URL codebase = file.getCodeBase();
     1275                                    if (codebase == null) {
     1276                                        //FIXME: codebase should be the codebase of the Main Jar not
     1277                                        //the location. Although, it still works in the current state.
     1278                                        codebase = file.getResources().getMainJAR().getLocation();
    12361279                                    }
     1280
     1281                                    final SecurityDesc jarSecurity = securityDelegate.getJarPermissions(codebase.getHost());
    12371282
    12381283                                    try {
     
    12431288                                        addURL(fakeRemote);
    12441289
    1245                                         SecurityDesc jarSecurity = file.getSecurity();
    1246 
    1247                                         if (file instanceof PluginBridge) {
    1248 
    1249                                             URL codebase = null;
    1250 
    1251                                             if (file.getCodeBase() != null) {
    1252                                                 codebase = file.getCodeBase();
    1253                                             } else {
    1254                                                 //Fixme: codebase should be the codebase of the Main Jar not
    1255                                                 //the location. Although, it still works in the current state.
    1256                                                 codebase = file.getResources().getMainJAR().getLocation();
    1257                                             }
    1258 
    1259                                             jarSecurity = new SecurityDesc(file,
    1260                                                     SecurityDesc.ALL_PERMISSIONS,
    1261                                                     codebase.getHost());
    1262                                         }
    1263 
    12641290                                        jarLocationSecurityMap.put(fakeRemote, jarSecurity);
    12651291
    12661292                                    } catch (MalformedURLException mfue) {
    1267                                         if (JNLPRuntime.isDebug())
    1268                                             System.err.println("Unable to add extracted nested jar to classpath");
    1269 
    1270                                         mfue.printStackTrace();
     1293                                        OutputController.getLogger().log(OutputController.Level.WARNING_DEBUG, "Unable to add extracted nested jar to classpath");
     1294                                        OutputController.getLogger().log(OutputController.Level.ERROR_ALL, mfue);
    12711295                                    }
    12721296                                }
     
    12751299                            }
    12761300
     1301                            jarFile.close();
    12771302                        }
    12781303
     
    12981323                            if (index != null)
    12991324                                jarIndexes.add(index);
     1325
     1326                            jarFile.close();
    13001327                        } else {
    13011328                            CachedJarFileCallback.getInstance().addMapping(jar.getLocation(), jar.getLocation());
    13021329                        }
    13031330
    1304                         if (JNLPRuntime.isDebug())
    1305                             System.err.println("Activate jar: " + location);
     1331                        OutputController.getLogger().log(OutputController.Level.ERROR_DEBUG, "Activate jar: " + location);
    13061332                    }
    13071333                    catch (Exception ex) {
    1308                         if (JNLPRuntime.isDebug())
    1309                             ex.printStackTrace();
     1334                       OutputController.getLogger().log(ex);
    13101335                    }
    13111336
    13121337                    // some programs place a native library in any jar
    1313                     activateNative(jar);
     1338                    nativeLibraryStorage.addSearchJar(jar.getLocation());
    13141339                }
    13151340
     
    13191344
    13201345        AccessController.doPrivileged(activate, acc);
    1321     }
    1322 
    1323     /**
    1324      * Search for and enable any native code contained in a JAR by copying the
    1325      * native files into the filesystem. Called in the security context of the
    1326      * classloader.
    1327      */
    1328     protected void activateNative(JARDesc jar) {
    1329         if (JNLPRuntime.isDebug())
    1330             System.out.println("Activate native: " + jar.getLocation());
    1331 
    1332         File localFile = tracker.getCacheFile(jar.getLocation());
    1333         if (localFile == null)
    1334             return;
    1335 
    1336         String[] librarySuffixes = { ".so", ".dylib", ".jnilib", ".framework", ".dll" };
    1337 
    1338         try {
    1339             JarFile jarFile = new JarFile(localFile, false);
    1340             Enumeration<JarEntry> entries = jarFile.entries();
    1341 
    1342             while (entries.hasMoreElements()) {
    1343                 JarEntry e = entries.nextElement();
    1344 
    1345                 if (e.isDirectory()) {
    1346                     continue;
    1347                 }
    1348 
    1349                 String name = new File(e.getName()).getName();
    1350                 boolean isLibrary = false;
    1351 
    1352                 for (String suffix : librarySuffixes) {
    1353                     if (name.endsWith(suffix)) {
    1354                         isLibrary = true;
    1355                         break;
    1356                     }
    1357                 }
    1358                 if (!isLibrary) {
    1359                     continue;
    1360                 }
    1361 
    1362                 if (nativeDir == null)
    1363                     nativeDir = getNativeDir();
    1364 
    1365                 File outFile = new File(nativeDir, name);
    1366                 if (!outFile.isFile()) {
    1367                     FileUtils.createRestrictedFile(outFile, true);
    1368                 }
    1369                 CacheUtil.streamCopy(jarFile.getInputStream(e),
    1370                                      new FileOutputStream(outFile));
    1371 
    1372             }
    1373         } catch (IOException ex) {
    1374             if (JNLPRuntime.isDebug())
    1375                 ex.printStackTrace();
    1376         }
    1377     }
    1378 
    1379     /**
    1380      * Return the base directory to store native code files in.
    1381      * This method does not need to return the same directory across
    1382      * calls.
    1383      */
    1384     protected File getNativeDir() {
    1385         final int rand = (int)((Math.random()*2 - 1) * Integer.MAX_VALUE);
    1386         nativeDir = new File(System.getProperty("java.io.tmpdir")
    1387                              + File.separator + "netx-native-"
    1388                              + (rand & 0xFFFF));
    1389         File parent = nativeDir.getParentFile();
    1390         if (!parent.isDirectory() && !parent.mkdirs()) {
    1391             return null;
    1392         }
    1393 
    1394         try {
    1395             FileUtils.createRestrictedDirectory(nativeDir);
    1396             // add this new native directory to the search path
    1397             addNativeDirectory(nativeDir);
    1398             return nativeDir;
    1399         } catch (IOException e) {
    1400             return null;
    1401         }
    1402     }
    1403 
    1404     /**
    1405      * Adds the {@link File} to the search path of this {@link JNLPClassLoader}
    1406      * when trying to find a native library
    1407      */
    1408     protected void addNativeDirectory(File nativeDirectory) {
    1409         nativeDirectories.add(nativeDirectory);
    1410     }
    1411 
    1412     /**
    1413      * Returns a list of all directories in the search path of the current classloader
    1414      * when it tires to find a native library.
    1415      * @return a list of directories in the search path for native libraries
    1416      */
    1417     protected List<File> getNativeDirectories() {
    1418         return nativeDirectories;
    14191346    }
    14201347
     
    14241351    protected String findLibrary(String lib) {
    14251352        String syslib = System.mapLibraryName(lib);
    1426 
    1427         for (File dir : getNativeDirectories()) {
    1428             File target = new File(dir, syslib);
    1429             if (target.exists())
    1430                 return target.toString();
     1353        File libFile = nativeLibraryStorage.findLibrary(syslib);
     1354
     1355        if (libFile != null) {
     1356            return libFile.toString();
    14311357        }
    14321358
     
    14421368     */
    14431369    protected String findLibraryExt(String lib) {
    1444         for (int i = 0; i < loaders.length; i++) {
     1370        for (JNLPClassLoader loader : loaders) {
    14451371            String result = null;
    14461372
    1447             if (loaders[i] != this)
    1448                 result = loaders[i].findLibrary(lib);
     1373            if (loader != this)
     1374                result = loader.findLibrary(lib);
    14491375
    14501376            if (result != null)
     
    14611387     * @param jars the jars
    14621388     */
    1463     private void waitForJars(List jars) {
     1389    private void waitForJars(List<JARDesc> jars) {
    14641390        URL urls[] = new URL[jars.size()];
    14651391
    14661392        for (int i = 0; i < jars.size(); i++) {
    1467             JARDesc jar = (JARDesc) jars.get(i);
     1393            JARDesc jar = jars.get(i);
    14681394
    14691395            urls[i] = jar.getLocation();
     
    14741400
    14751401    /**
    1476          * Verifies code signing of jars to be used.
    1477          *
    1478          * @param jars the jars to be verified.
    1479          */
    1480     private JarCertVerifier verifyJars(List<JARDesc> jars) throws Exception {
    1481 
    1482         jcv = new JarCertVerifier();
    1483         jcv.verifyJars(jars, tracker);
    1484         return jcv;
    1485     }
    1486 
    1487     /**
    14881402     * Find the loaded class in this loader or any of its extension loaders.
    14891403     */
    1490     protected Class findLoadedClassAll(String name) {
    1491         for (int i = 0; i < loaders.length; i++) {
    1492             Class result = null;
    1493 
    1494             if (loaders[i] == this) {
    1495                 final String fName = name;
    1496                 try {
    1497                     result = AccessController.doPrivileged(
    1498                             new PrivilegedExceptionAction<Class<?>>() {
    1499                                 public Class<?> run() {
    1500                                     return JNLPClassLoader.super.findLoadedClass(fName);
    1501                                 }
    1502                             }, getAccessControlContextForClassLoading());
    1503                 } catch (PrivilegedActionException pae) {
    1504                     result = null;
    1505                 }
     1404    protected Class<?> findLoadedClassAll(String name) {
     1405        for (JNLPClassLoader loader : loaders) {
     1406            Class<?> result = null;
     1407
     1408            if (loader == this) {
     1409                result = JNLPClassLoader.super.findLoadedClass(name);
    15061410            } else {
    1507                 result = loaders[i].findLoadedClassAll(name);
     1411                result = loader.findLoadedClassAll(name);
    15081412            }
    15091413
     
    15241428     * classloader, or one of the classloaders for the JNLP file's
    15251429     * extensions.
    1526      */
    1527     public synchronized Class<?> loadClass(String name) throws ClassNotFoundException {
    1528 
     1430     * This method used to be qualified "synchronized." This was done solely for the
     1431     * purpose of ensuring only one thread entered the method at a time. This was not
     1432     * strictly necessary - ensuring that all affected fields are thread-safe is
     1433     * sufficient. Locking on the JNLPClassLoader instance when this method is called
     1434     * can result in deadlock if another thread is dealing with the CodebaseClassLoader
     1435     * at the same time. This solution is very heavy-handed as the instance lock is not
     1436     * truly required, and taking the lock on the classloader instance when not needed is
     1437     * not in general a good idea because it can and will lead to deadlock when multithreaded
     1438     * classloading is in effect. The solution is to keep the fields thread safe on their own.
     1439     * This is accomplished by wrapping them in Collections.synchronized* to provide
     1440     * atomic add/remove operations, and synchronizing on them when iterating or performing
     1441     * multiple mutations.
     1442     * See bug report RH976833. On some systems this bug will manifest itself as deadlock on
     1443     * every webpage with more than one Java applet, potentially also causing the browser
     1444     * process to hang.
     1445     * More information in the mailing list archives:
     1446     * http://mail.openjdk.java.net/pipermail/distro-pkg-dev/2013-September/024536.html
     1447     *
     1448     * Affected fields: available, classpaths, jarIndexes, jarEntries, jarLocationSecurityMap
     1449     */
     1450    public Class<?> loadClass(String name) throws ClassNotFoundException {
    15291451        Class<?> result = findLoadedClassAll(name);
    15301452
     
    15531475                // Look in 'Class-Path' as specified in the manifest file
    15541476                try {
    1555                     for (String classpath: classpaths) {
    1556                         JARDesc desc;
    1557                         try {
    1558                             URL jarUrl = new URL(file.getCodeBase(), classpath);
    1559                             desc = new JARDesc(jarUrl, null, null, false, true, false, true);
    1560                         } catch (MalformedURLException mfe) {
    1561                             throw new ClassNotFoundException(name, mfe);
     1477                    // This field synchronized before iterating over it since it may
     1478                    // be shared data between threads
     1479                    synchronized (classpaths) {
     1480                        for (String classpath : classpaths) {
     1481                            JARDesc desc;
     1482                            try {
     1483                                URL jarUrl = new URL(file.getCodeBase(), classpath);
     1484                                desc = new JARDesc(jarUrl, null, null, false, true, false, true);
     1485                            } catch (MalformedURLException mfe) {
     1486                                throw new ClassNotFoundException(name, mfe);
     1487                            }
     1488                            addNewJar(desc);
    15621489                        }
    1563                         addNewJar(desc);
    15641490                    }
    15651491
     
    15671493                    return result;
    15681494                } catch (ClassNotFoundException cnfe1) {
    1569                     if (JNLPRuntime.isDebug()) {
    1570                         cnfe1.printStackTrace();
    1571                     }
     1495                    OutputController.getLogger().log(cnfe1);
    15721496                }
    15731497
     
    15761500                // Currently this loads jars directly from the site. We cannot cache it because this
    15771501                // call is initiated from within the applet, which does not have disk read/write permissions
    1578                 for (JarIndex index : jarIndexes) {
    1579                     // Non-generic code in sun.misc.JarIndex
    1580                     @SuppressWarnings("unchecked")
    1581                     LinkedList<String> jarList = index.get(name.replace('.', '/'));
    1582 
    1583                     if (jarList != null) {
    1584                         for (String jarName : jarList) {
    1585                             JARDesc desc;
    1586                             try {
    1587                                 desc = new JARDesc(new URL(file.getCodeBase(), jarName),
    1588                                         null, null, false, true, false, true);
    1589                             } catch (MalformedURLException mfe) {
    1590                                 throw new ClassNotFoundException(name);
    1591                             }
    1592                             try {
    1593                                 addNewJar(desc);
    1594                             } catch (Exception e) {
    1595                                 if (JNLPRuntime.isDebug()) {
    1596                                     e.printStackTrace();
     1502                // This field synchronized before iterating over it since it may
     1503                // be shared data between threads
     1504                synchronized (jarIndexes) {
     1505                    for (JarIndex index : jarIndexes) {
     1506                        // Non-generic code in sun.misc.JarIndex
     1507                        @SuppressWarnings("unchecked")
     1508                        LinkedList<String> jarList = index.get(name.replace('.', '/'));
     1509
     1510                        if (jarList != null) {
     1511                            for (String jarName : jarList) {
     1512                                JARDesc desc;
     1513                                try {
     1514                                    desc = new JARDesc(new URL(file.getCodeBase(), jarName),
     1515                                            null, null, false, true, false, true);
     1516                                } catch (MalformedURLException mfe) {
     1517                                    throw new ClassNotFoundException(name);
     1518                                }
     1519                                try {
     1520                                    addNewJar(desc);
     1521                                } catch (Exception e) {
     1522                                    OutputController.getLogger().log(e);
    15971523                                }
    15981524                            }
     1525
     1526                            // If it still fails, let it error out
     1527                            result = loadClassExt(name);
    15991528                        }
    1600 
    1601                         // If it still fails, let it error out
    1602                         result = loadClassExt(name);
    16031529                    }
    16041530                }
     
    16181544     * This will add the JARDesc into the resourceTracker and block until it
    16191545     * is downloaded.
     1546     * </p>
    16201547     * @param desc the JARDesc for the new jar
    16211548     */
    16221549    private void addNewJar(final JARDesc desc) {
     1550        this.addNewJar(desc, JNLPRuntime.getDefaultUpdatePolicy());
     1551    }
     1552
     1553    /**
     1554     * Adds a new JARDesc into this classloader.
     1555     * @param desc the JARDesc for the new jar
     1556     * @param updatePolicy the UpdatePolicy for the resource
     1557     */
     1558    private void addNewJar(final JARDesc desc, UpdatePolicy updatePolicy) {
    16231559
    16241560        available.add(desc);
     
    16271563                desc.getVersion(),
    16281564                null,
    1629                 JNLPRuntime.getDefaultUpdatePolicy()
     1565                updatePolicy
    16301566                );
    16311567
     
    16511587            // Verify if needed
    16521588
    1653             final JarCertVerifier signer = new JarCertVerifier();
    16541589            final List<JARDesc> jars = new ArrayList<JARDesc>();
    16551590            jars.add(desc);
     
    16631598            AccessController.doPrivileged(new PrivilegedExceptionAction<Void>() {
    16641599                public Void run() throws Exception {
    1665                     signer.verifyJars(jars, tracker);
    1666 
    1667                     if (signer.anyJarsSigned() && !signer.getAlreadyTrustPublisher()) {
    1668                         checkTrustWithUser(signer);
    1669                     }
    1670 
    1671                     final SecurityDesc security;
    1672                     if (signer.anyJarsSigned()) {
    1673                         security = new SecurityDesc(file,
    1674                                 SecurityDesc.ALL_PERMISSIONS,
    1675                                 file.getCodeBase().getHost());
    1676                     } else {
    1677                         security = new SecurityDesc(file,
    1678                                 SecurityDesc.SANDBOX_PERMISSIONS,
    1679                                 file.getCodeBase().getHost());
    1680                     }
     1600                    jcv.add(jars, tracker);
     1601
     1602                    checkTrustWithUser();
     1603
     1604                    final SecurityDesc security = securityDelegate.getJarPermissions(file.getCodeBase().getHost());
    16811605
    16821606                    jarLocationSecurityMap.put(remoteURL, security);
     
    16941618            // Exception => jar will not get added to classpath, which will
    16951619            // result in CNFE from loadClass.
    1696             e.printStackTrace();
     1620            OutputController.getLogger().log(OutputController.Level.ERROR_ALL, e);
    16971621        }
    16981622    }
     
    17011625     * Find the class in this loader or any of its extension loaders.
    17021626     */
    1703     protected Class findClass(String name) throws ClassNotFoundException {
    1704         for (int i = 0; i < loaders.length; i++) {
     1627    @Override
     1628    protected Class<?> findClass(String name) throws ClassNotFoundException {
     1629        for (JNLPClassLoader loader : loaders) {
    17051630            try {
    1706                 if (loaders[i] == this) {
     1631                if (loader == this) {
    17071632                    final String fName = name;
    17081633                    return AccessController.doPrivileged(
     
    17131638                            }, getAccessControlContextForClassLoading());
    17141639                } else {
    1715                     return loaders[i].findClass(name);
     1640                    return loader.findClass(name);
    17161641                }
    17171642            } catch (ClassNotFoundException ex) {
    17181643            } catch (ClassFormatError cfe) {
     1644                OutputController.getLogger().log(OutputController.Level.ERROR_ALL, cfe);
    17191645            } catch (PrivilegedActionException pae) {
     1646            } catch (NullJnlpFileException ex) {
     1647                throw new ClassNotFoundException(this.mainClass + " in main classloader ", ex);
    17201648            }
    17211649        }
     
    17231651        // Try codebase loader
    17241652        if (codeBaseLoader != null)
    1725             return codeBaseLoader.findClass(name, true);
     1653            return codeBaseLoader.findClassNonRecursive(name);
    17261654
    17271655        // All else failed. Throw CNFE
     
    17341662     * is found.
    17351663     */
    1736     private Class loadClassExt(String name) throws ClassNotFoundException {
     1664    private Class<?> loadClassExt(String name) throws ClassNotFoundException {
    17371665        // make recursive
    17381666        addAvailable();
     
    17751703     * class loaders.
    17761704     *
    1777      * @return a <code>URL</code> for the resource, or <code>null</code>
     1705     * @return a {@link URL} for the resource, or {@code null}
    17781706     * if the resource could not be found.
    17791707     */
     
    17881716            }
    17891717        } catch (IOException e) {
    1790             if (JNLPRuntime.isDebug()) {
    1791                 e.printStackTrace();
    1792             }
     1718            OutputController.getLogger().log(e);
    17931719        }
    17941720       
     
    18141740            }
    18151741        } catch (LaunchException le) {
    1816             le.printStackTrace();
     1742            OutputController.getLogger().log(OutputController.Level.ERROR_ALL, le);
    18171743        }
    18181744
     
    18281754        Enumeration<URL> e = null;
    18291755
    1830         for (int i = 0; i < loaders.length; i++) {
     1756        for (JNLPClassLoader loader : loaders) {
    18311757            // TODO check if this will blow up or not
    18321758            // if loaders[1].getResource() is called, wont it call getResource() on
    18331759            // the original caller? infinite recursion?
    18341760
    1835             if (loaders[i] == this) {
     1761            if (loader == this) {
    18361762                final String fName = name;
    18371763                try {
     
    18451771                }
    18461772            } else {
    1847                 e = loaders[i].findResources(name);
     1773                e = loader.findResources(name);
    18481774            }
    18491775
     
    19561882
    19571883    public boolean getSigning() {
     1884        return signing == SigningState.FULL;
     1885    }
     1886
     1887    /**
     1888     * Call this when it's suspected that an applet's permission level may have
     1889     * just changed from Full Signing to Partial Signing.
     1890     * This will display a one-time prompt asking the user to confirm running
     1891     * the partially signed applet.
     1892     * Partially Signed applets always start off as appearing to be Fully
     1893     * Signed, and then during the initialization or loading process, we find
     1894     * that we actually need to demote the applet to Partial, either due to
     1895     * finding that not all of its JARs are actually signed, or because it
     1896     * needs to load something unsigned out of the codebase.
     1897     */
     1898    private void checkPartialSigningWithUser() {
     1899        if (signing == SigningState.FULL && JNLPRuntime.isVerifying()) {
     1900            signing = SigningState.PARTIAL;
     1901            try {
     1902                securityDelegate.promptUserOnPartialSigning();
     1903            } catch (LaunchException e) {
     1904                throw new RuntimeException("The signed applet required loading of unsigned code from the codebase, "
     1905                        + "which the user refused", e);
     1906            }
     1907        }
     1908    }
     1909
     1910    public SigningState getSigningState() {
    19581911        return signing;
    19591912    }
     
    19721925    protected SecurityDesc getCodeSourceSecurity(URL source) {
    19731926        SecurityDesc sec=jarLocationSecurityMap.get(source);
    1974         if (sec == null && !alreadyTried.contains(source)) {
    1975             alreadyTried.add(source);
    1976             //try to load the jar which is requesting the permissions, but was NOT downloaded by standard way
    1977             if (JNLPRuntime.isDebug()) {
    1978                 System.out.println("Application is trying to get permissions for " + source.toString() + ", which was not added by standard way. Trying to download and verify!");
    1979             }
    1980             try {
    1981                 JARDesc des = new JARDesc(source, null, null, false, false, false, false);
    1982                 addNewJar(des);
    1983                 sec = jarLocationSecurityMap.get(source);
    1984             } catch (Throwable t) {
    1985                 if (JNLPRuntime.isDebug()) {
    1986                     t.printStackTrace();
    1987                 }
    1988                 sec = null;
     1927        synchronized (alreadyTried) {
     1928            if (sec == null && !alreadyTried.contains(source)) {
     1929                alreadyTried.add(source);
     1930                //try to load the jar which is requesting the permissions, but was NOT downloaded by standard way
     1931                OutputController.getLogger().log("Application is trying to get permissions for " + source.toString() + ", which was not added by standard way. Trying to download and verify!");
     1932                try {
     1933                    JARDesc des = new JARDesc(source, null, null, false, false, false, false);
     1934                    addNewJar(des);
     1935                    sec = jarLocationSecurityMap.get(source);
     1936                } catch (Throwable t) {
     1937                    OutputController.getLogger().log(t);
     1938                    sec = null;
     1939                }
    19891940            }
    19901941        }
    19911942        if (sec == null){
    1992             System.out.println(Translator.R("LNoSecInstance",source.toString()));
     1943            OutputController.getLogger().log(OutputController.Level.MESSAGE_ALL, Translator.R("LNoSecInstance",source.toString()));
    19931944        }
    19941945        return sec;
     
    20171968
    20181969        // native search paths
    2019         for (File nativeDirectory : extLoader.getNativeDirectories())
    2020             addNativeDirectory(nativeDirectory);
     1970        for (File nativeDirectory : extLoader.nativeLibraryStorage.getSearchDirectories()) {
     1971            nativeLibraryStorage.addSearchDirectory(nativeDirectory);
     1972        }
    20211973
    20221974        // security descriptors
    2023         for (URL key : extLoader.jarLocationSecurityMap.keySet()) {
    2024             jarLocationSecurityMap.put(key, extLoader.jarLocationSecurityMap.get(key));
     1975        synchronized (jarLocationSecurityMap) {
     1976            for (URL key : extLoader.jarLocationSecurityMap.keySet()) {
     1977                jarLocationSecurityMap.put(key, extLoader.jarLocationSecurityMap.get(key));
     1978            }
    20251979        }
    20261980    }
     
    20291983     * Adds the given path to the path loader
    20301984     *
    2031      * @param URL the path to add
     1985     * @param u the path to add
    20321986     * @throws IllegalArgumentException If the given url is not a path
    20331987     */
     
    20492003            codeBaseLoader.addURL(u);
    20502004        }
    2051     }
    2052 
    2053     private DownloadOptions getDownloadOptionsForJar(JARDesc jar) {
    2054         return file.getDownloadOptionsForJar(jar);
    20552005    }
    20562006
     
    20982048     * @throws SecurityException if caller is not trusted
    20992049     */
    2100     private synchronized void incrementLoaderUseCount() {
    2101        
     2050    private void incrementLoaderUseCount() {
     2051
    21022052        // For use by trusted code only
    21032053        if (System.getSecurityManager() != null)
    21042054            System.getSecurityManager().checkPermission(new AllPermission());
    2105        
    2106         useCount++;
     2055
     2056        // NB: There will only ever be one class-loader per unique-key
     2057        synchronized ( getUniqueKeyLock(file.getUniqueKey()) ){
     2058            useCount++;
     2059        }
     2060    }
     2061
     2062    /**
     2063     * Returns all loaders that this loader uses, including itself
     2064     */
     2065    JNLPClassLoader[] getLoaders() {
     2066        return loaders;
     2067    }
     2068
     2069    /**
     2070     * Remove jars from the file system.
     2071     *
     2072     * @param jars Jars marked for removal.
     2073     */
     2074    void removeJars(JARDesc[] jars) {
     2075
     2076        for (JARDesc eachJar : jars) {
     2077            try {
     2078                tracker.removeResource(eachJar.getLocation());
     2079            } catch (Exception e) {
     2080                    OutputController.getLogger().log(e);
     2081                    OutputController.getLogger().log(OutputController.Level.ERROR_DEBUG, "Failed to remove resource from tracker, continuing..");
     2082            }
     2083
     2084            File cachedFile = CacheUtil.getCacheFile(eachJar.getLocation(), null);
     2085            String directoryUrl = CacheUtil.getCacheParentDirectory(cachedFile.getAbsolutePath());
     2086
     2087            File directory = new File(directoryUrl);
     2088
     2089            OutputController.getLogger().log("Deleting cached file: " + cachedFile.getAbsolutePath());
     2090
     2091            cachedFile.delete();
     2092
     2093            OutputController.getLogger().log("Deleting cached directory: " + directory.getAbsolutePath());
     2094
     2095            directory.delete();
     2096        }
     2097    }
     2098
     2099    /**
     2100     * Downloads and initializes jars into this loader.
     2101     *
     2102     * @param ref Path of the launch or extension JNLP File containing the
     2103     * resource. If null, main JNLP's file location will be used instead.
     2104     * @param part The name of the path.
     2105     * @throws LaunchException
     2106     */
     2107    void initializeNewJarDownload(URL ref, String part, Version version) {
     2108        JARDesc[] jars = ManageJnlpResources.findJars(this, ref, part, version);
     2109
     2110        for (JARDesc eachJar : jars) {
     2111            OutputController.getLogger().log("Downloading and initializing jar: " + eachJar.getLocation().toString());
     2112
     2113            this.addNewJar(eachJar, UpdatePolicy.FORCE);
     2114        }
     2115    }
     2116
     2117    /**
     2118     * Manages DownloadService jars which are not mentioned in the JNLP file
     2119     * @param ref Path to the resource.
     2120     * @param version The version of resource. If null, no version is specified.
     2121     * @param action The action to perform with the resource. Either DOWNLOADTOCACHE, REMOVEFROMCACHE, or CHECKCACHE.
     2122     * @return true if CHECKCACHE and the resource is cached.
     2123     */
     2124    boolean manageExternalJars(URL ref, String version, DownloadAction action) {
     2125        boolean approved = false;
     2126        JNLPClassLoader foundLoader = LocateJnlpClassLoader.getLoaderByResourceUrl(this, ref, version);
     2127        Version resourceVersion = (version == null) ? null : new Version(version);
     2128
     2129        if (foundLoader != null)
     2130            approved = true;
     2131
     2132        else if (ref.toString().startsWith(file.getCodeBase().toString()))
     2133            approved = true;
     2134        else if (SecurityDesc.ALL_PERMISSIONS.equals(security.getSecurityType()))
     2135            approved = true;
     2136
     2137        if (approved) {
     2138            if (foundLoader == null)
     2139                foundLoader = this;
     2140
     2141            if (action == DownloadAction.DOWNLOAD_TO_CACHE) {
     2142                JARDesc jarToCache = new JARDesc(ref, resourceVersion, null, false, true, false, true);
     2143                OutputController.getLogger().log("Downloading and initializing jar: " + ref.toString());
     2144
     2145                foundLoader.addNewJar(jarToCache, UpdatePolicy.FORCE);
     2146
     2147            } else if (action == DownloadAction.REMOVE_FROM_CACHE) {
     2148                JARDesc[] jarToRemove = { new JARDesc(ref, resourceVersion, null, false, true, false, true) };
     2149                foundLoader.removeJars(jarToRemove);
     2150
     2151            } else if (action == DownloadAction.CHECK_CACHE) {
     2152                return CacheUtil.isCached(ref, resourceVersion);
     2153            }
     2154        }
     2155        return false;
    21072156    }
    21082157
     
    21142163     * @throws SecurityException if caller is not trusted
    21152164     */
    2116     public synchronized void decrementLoaderUseCount() {
     2165    public void decrementLoaderUseCount() {
    21172166
    21182167        // For use by trusted code only
     
    21202169            System.getSecurityManager().checkPermission(new AllPermission());
    21212170
    2122         useCount--;
    2123 
    2124         if (useCount <= 0) {
    2125             synchronized(urlToLoader) {
    2126                 urlToLoader.remove(file.getUniqueKey());
     2171        String uniqueKey = file.getUniqueKey();
     2172
     2173        // NB: There will only ever be one class-loader per unique-key
     2174        synchronized ( getUniqueKeyLock(uniqueKey) ) {
     2175            useCount--;
     2176
     2177            if (useCount <= 0) {
     2178                uniqueKeyToLoader.remove(uniqueKey);
    21272179            }
    21282180        }
     
    21502202        } catch (AccessControlException ace) {
    21512203            // continue below
    2152         } catch (ClassCircularityError cce) {
    2153             // continue below
    21542204        }
    21552205
     
    21652215
    21662216        // Permissions for all remote hosting urls
    2167         for (URL u: jarLocationSecurityMap.keySet()) {
    2168             permissions.add(new SocketPermission(u.getHost(),
    2169                                                  "connect, accept"));
     2217        synchronized (jarLocationSecurityMap) {
     2218            for (URL u : jarLocationSecurityMap.keySet()) {
     2219                permissions.add(new SocketPermission(u.getHost(),
     2220                        "connect, accept"));
     2221            }
    21702222        }
    21712223
     
    21822234        return new AccessControlContext(new ProtectionDomain[] { pd });
    21832235    }
     2236   
     2237    public String getMainClass() {
     2238        return mainClass;
     2239    }
     2240   
     2241
     2242
     2243   /**
     2244     * SecurityDelegate, in real usage, relies on having a "parent" JNLPClassLoader instance.
     2245     * However, JNLPClassLoaders are very large, heavyweight, difficult-to-mock objects, which
     2246     * means that unit testing on anything that uses a SecurityDelegate can become very difficult.
     2247     * For example, JarCertVerifier is designed separated from the ClassLoader so it can be tested
     2248     * in isolation. However, JCV needs some sort of access back to JNLPClassLoader instances to
     2249     * be able to invoke setRunInSandbox(). The SecurityDelegate handles this, allowing JCV to be
     2250     * tested without instantiating JNLPClassLoaders, by creating a fake SecurityDelegate that does
     2251     * not require one.
     2252     */
     2253    public static interface SecurityDelegate {
     2254        public boolean isPluginApplet();
     2255
     2256        public boolean userPromptedForPartialSigning();
     2257
     2258        public boolean userPromptedForSandbox();
     2259
     2260        public SecurityDesc getCodebaseSecurityDesc(final JARDesc jarDesc, final String codebaseHost);
     2261
     2262        public SecurityDesc getClassLoaderSecurity(final String codebaseHost) throws LaunchException;
     2263
     2264        public SecurityDesc getJarPermissions(final String codebaseHost);
     2265
     2266        public void promptUserOnPartialSigning() throws LaunchException;
     2267
     2268        public void setRunInSandbox() throws LaunchException;
     2269
     2270        public boolean getRunInSandbox();
     2271
     2272        public void addPermission(final Permission perm);
     2273
     2274        public void addPermissions(final PermissionCollection perms);
     2275
     2276        public void addPermissions(final Collection<Permission> perms);
     2277    }
     2278
     2279    /**
     2280     * Handles security decision logic for the JNLPClassLoader, eg which permission level to assign
     2281     * to JARs.
     2282     */
     2283    public static class SecurityDelegateImpl implements SecurityDelegate {
     2284        private final JNLPClassLoader classLoader;
     2285        private boolean runInSandbox;
     2286        private boolean promptedForPartialSigning;
     2287        private boolean promptedForSandbox;
     2288
     2289        public SecurityDelegateImpl(final JNLPClassLoader classLoader) {
     2290            this.classLoader = classLoader;
     2291            runInSandbox = false;
     2292            promptedForSandbox = false;
     2293        }
     2294
     2295        public boolean isPluginApplet() {
     2296            return classLoader.file instanceof PluginBridge;
     2297        }
     2298
     2299        public SecurityDesc getCodebaseSecurityDesc(final JARDesc jarDesc, final String codebaseHost) {
     2300            if (runInSandbox) {
     2301                return new SecurityDesc(classLoader.file,
     2302                        SecurityDesc.SANDBOX_PERMISSIONS,
     2303                        codebaseHost);
     2304            } else {
     2305                if (isPluginApplet()) {
     2306                    try {
     2307                        if (JarCertVerifier.isJarSigned(jarDesc, new PluginAppVerifier(), classLoader.tracker)) {
     2308                            return new SecurityDesc(classLoader.file,
     2309                                    SecurityDesc.ALL_PERMISSIONS,
     2310                                    codebaseHost);
     2311                        } else {
     2312                            return new SecurityDesc(classLoader.file,
     2313                                    SecurityDesc.SANDBOX_PERMISSIONS,
     2314                                    codebaseHost);
     2315                        }
     2316                    } catch (final Exception e) {
     2317                        OutputController.getLogger().log(e);
     2318                        return new SecurityDesc(classLoader.file,
     2319                                SecurityDesc.SANDBOX_PERMISSIONS,
     2320                                codebaseHost);
     2321                    }
     2322                } else {
     2323                    return classLoader.file.getSecurity();
     2324                }
     2325            }
     2326        }
     2327
     2328        public SecurityDesc getClassLoaderSecurity(final String codebaseHost) throws LaunchException {
     2329            if (isPluginApplet()) {
     2330                if (!runInSandbox && classLoader.getSigning()) {
     2331                    return new SecurityDesc(classLoader.file,
     2332                            SecurityDesc.ALL_PERMISSIONS,
     2333                            codebaseHost);
     2334                } else {
     2335                    return new SecurityDesc(classLoader.file,
     2336                            SecurityDesc.SANDBOX_PERMISSIONS,
     2337                            codebaseHost);
     2338                }
     2339            } else {
     2340                /*
     2341                 * Various combinations of the jars being signed and <security> tags being
     2342                 * present are possible. They are treated as follows
     2343                 *
     2344                 * Jars          JNLP File         Result
     2345                 *
     2346                 * Signed        <security>        Appropriate Permissions
     2347                 * Signed        no <security>     Sandbox
     2348                 * Unsigned      <security>        Error
     2349                 * Unsigned      no <security>     Sandbox
     2350                 *
     2351                 */
     2352                if (!runInSandbox && !classLoader.getSigning()
     2353                        && !classLoader.file.getSecurity().getSecurityType().equals(SecurityDesc.SANDBOX_PERMISSIONS)) {
     2354                    if (classLoader.jcv.allJarsSigned()) {
     2355                        throw new LaunchException(classLoader.file, null, R("LSFatal"), R("LCClient"), R("LSignedJNLPAppDifferentCerts"), R("LSignedJNLPAppDifferentCertsInfo"));
     2356                    } else {
     2357                        throw new LaunchException(classLoader.file, null, R("LSFatal"), R("LCClient"), R("LUnsignedJarWithSecurity"), R("LUnsignedJarWithSecurityInfo"));
     2358                    }
     2359                } else if (!runInSandbox && classLoader.getSigning()) {
     2360                    return classLoader.file.getSecurity();
     2361                } else {
     2362                    return new SecurityDesc(classLoader.file,
     2363                            SecurityDesc.SANDBOX_PERMISSIONS,
     2364                            codebaseHost);
     2365                }
     2366            }
     2367        }
     2368
     2369        public SecurityDesc getJarPermissions(final String codebaseHost) {
     2370            if (!runInSandbox && classLoader.jcv.isFullySigned()) {
     2371                // Already trust application, nested jar should be given
     2372                return new SecurityDesc(classLoader.file,
     2373                        SecurityDesc.ALL_PERMISSIONS,
     2374                        codebaseHost);
     2375            } else {
     2376                return new SecurityDesc(classLoader.file,
     2377                        SecurityDesc.SANDBOX_PERMISSIONS,
     2378                        codebaseHost);
     2379            }
     2380        }
     2381
     2382        public void setRunInSandbox() throws LaunchException {
     2383            if (promptedForSandbox || classLoader.security != null
     2384                    || classLoader.jarLocationSecurityMap.size() != 0) {
     2385                throw new LaunchException(classLoader.file, null, R("LSFatal"), R("LCInit"), R("LRunInSandboxError"), R("LRunInSandboxErrorInfo"));
     2386            }
     2387
     2388            JNLPRuntime.reloadPolicy(); // ensure that we have the most up-to-date custom policy loaded
     2389            this.promptedForSandbox = true;
     2390            this.runInSandbox = true;
     2391        }
     2392
     2393        public void promptUserOnPartialSigning() throws LaunchException {
     2394            if (promptedForPartialSigning || JNLPRuntime.isTrustAll()) {
     2395                return;
     2396            }
     2397            promptedForPartialSigning = true;
     2398            UnsignedAppletTrustConfirmation.checkPartiallySignedWithUserIfRequired(this, classLoader.file, classLoader.jcv);
     2399        }
     2400
     2401        public boolean getRunInSandbox() {
     2402            return this.runInSandbox;
     2403        }
     2404
     2405        public boolean userPromptedForPartialSigning() {
     2406            return this.promptedForPartialSigning;
     2407        }
     2408
     2409        public boolean userPromptedForSandbox() {
     2410            return this.promptedForSandbox;
     2411        }
     2412
     2413        public void addPermission(final Permission perm) {
     2414            classLoader.addPermission(perm);
     2415        }
     2416
     2417        public void addPermissions(final PermissionCollection perms) {
     2418            Enumeration<Permission> e = perms.elements();
     2419            while (e.hasMoreElements()) {
     2420                addPermission(e.nextElement());
     2421            }
     2422        }
     2423
     2424        public void addPermissions(final Collection<Permission> perms) {
     2425            for (final Permission perm : perms) {
     2426                addPermission(perm);
     2427            }
     2428        }
     2429
     2430    }
     2431   
    21842432
    21852433    /*
    21862434     * Helper class to expose protected URLClassLoader methods.
    2187      */
    2188 
     2435     * Classes loaded from the codebase are absolutely NOT signed, by definition!
     2436     * If the CodeBaseClassLoader is used to load any classes in JNLPClassLoader,
     2437     * then you *MUST* check if the JNLPClassLoader is set to FULL signing. If so,
     2438     * then it must be set instead to PARTIAL, and the user prompted if it is okay
     2439     * to proceed. If the JNLPClassLoader is already PARTIAL or NONE signing, then
     2440     * nothing must be done. This is required so that we can support partial signing
     2441     * of applets but also ensure that using codebase loading in conjunction with
     2442     * signed JARs still results in the user having to confirm that this is
     2443     * acceptable.
     2444     */
    21892445    public static class CodeBaseClassLoader extends URLClassLoader {
    21902446
     
    21972453
    21982454        public CodeBaseClassLoader(URL[] urls, JNLPClassLoader cl) {
    2199             super(urls);
     2455            super(urls, cl);
    22002456            parentJNLPClassLoader = cl;
    22012457        }
     
    22062462        }
    22072463
    2208         @Override
    2209         public Class<?> findClass(String name) throws ClassNotFoundException {
    2210             return findClass(name, false);
    2211         }
    2212 
    2213         public Class<?> findClass(String name, boolean recursivelyInvoked) throws ClassNotFoundException {
    2214 
    2215             if (!recursivelyInvoked) {
    2216                 try {
    2217                     return parentJNLPClassLoader.findClass(name);
    2218                 } catch (ClassNotFoundException cnfe) {
    2219                     // continue
    2220                 }
    2221             }
    2222 
     2464        /*
     2465         * Use with care! Check the class-level Javadoc before calling this.
     2466         */
     2467        Class<?> findClassNonRecursive(final String name) throws ClassNotFoundException {
    22232468            // If we have searched this path before, don't try again
    22242469            if (Arrays.equals(super.getURLs(), notFoundResources.get(name)))
     
    22262471
    22272472            try {
    2228                 final String fName = name;
    22292473                return AccessController.doPrivileged(
    22302474                        new PrivilegedExceptionAction<Class<?>>() {
    22312475                            public Class<?> run() throws ClassNotFoundException {
    2232                                 return CodeBaseClassLoader.super.findClass(fName);
     2476                                Class<?> c = CodeBaseClassLoader.super.findClass(name);
     2477                                parentJNLPClassLoader.checkPartialSigningWithUser();
     2478                                return c;
    22332479                            }
    22342480                        }, parentJNLPClassLoader.getAccessControlContextForClassLoading());
    22352481            } catch (PrivilegedActionException pae) {
    22362482                notFoundResources.put(name, super.getURLs());
    2237                 throw new ClassNotFoundException("Could not find class " + name);
    2238             }
     2483                throw new ClassNotFoundException("Could not find class " + name, pae);
     2484            } catch (NullJnlpFileException njf) {
     2485                notFoundResources.put(name, super.getURLs());
     2486                throw new ClassNotFoundException("Could not find class " + name, njf);
     2487            }
     2488        }
     2489
     2490        /*
     2491         * Use with care! Check the class-level Javadoc before calling this.
     2492         */
     2493        @Override
     2494        public Class<?> findClass(String name) throws ClassNotFoundException {
     2495            // Calls JNLPClassLoader#findClass which may call into this.findClassNonRecursive
     2496            Class<?> c = getParentJNLPClassLoader().findClass(name);
     2497            parentJNLPClassLoader.checkPartialSigningWithUser();
     2498            return c;
    22392499        }
    22402500
     
    22992559                            }, parentJNLPClassLoader.getAccessControlContextForClassLoading());
    23002560                } catch (PrivilegedActionException pae) {
    2301                 }
     2561                } 
    23022562
    23032563                if (url == null) {
     
    23112571        }
    23122572    }
     2573   
     2574   
    23132575}
  • trunk/icedtea-web/netx/net/sourceforge/jnlp/runtime/JNLPPolicy.java

    r348 r429  
    2424
    2525import net.sourceforge.jnlp.config.DeploymentConfiguration;
     26import net.sourceforge.jnlp.util.logging.OutputController;
    2627
    2728/**
     
    9192                // systempolicy permissions need to be accounted for as well
    9293                e = systemPolicy.getPermissions(appletCS).elements();
    93                 while (e.hasMoreElements())
     94                while (e.hasMoreElements()) {
    9495                    clPermissions.add(e.nextElement());
     96                }
    9597
    9698                // and so do permissions from the jnlp-specific system policy
    9799                if (systemJnlpPolicy != null) {
    98100                    e = systemJnlpPolicy.getPermissions(appletCS).elements();
    99                     while (e.hasMoreElements())
     101                    while (e.hasMoreElements()) {
    100102                        clPermissions.add(e.nextElement());
     103                    }
    101104                }
    102105
     
    104107                if (userJnlpPolicy != null) {
    105108                    e = userJnlpPolicy.getPermissions(appletCS).elements();
    106                     while (e.hasMoreElements())
     109                    while (e.hasMoreElements()) {
    107110                        clPermissions.add(e.nextElement());
     111                    }
     112
     113                    CodeSource appletCodebaseSource = new CodeSource(JNLPRuntime.getApplication().getJNLPFile().getCodeBase(), (java.security.cert.Certificate[]) null);
     114                    e = userJnlpPolicy.getPermissions(appletCodebaseSource).elements();
     115                    while (e.hasMoreElements()) {
     116                        clPermissions.add(e.nextElement());
     117                    }
    108118                }
    109119
     
    120130     */
    121131    public void refresh() {
    122         // no op
     132        if (userJnlpPolicy != null) {
     133            userJnlpPolicy.refresh();
     134        }
    123135    }
    124136
     
    168180                policy = getInstance("JavaPolicy", new URIParameter(policyUri));
    169181            } catch (IllegalArgumentException e) {
    170                 e.printStackTrace();
     182                OutputController.getLogger().log(OutputController.Level.ERROR_ALL, e);
    171183            } catch (NoSuchAlgorithmException e) {
    172                 e.printStackTrace();
     184                OutputController.getLogger().log(OutputController.Level.ERROR_ALL, e);
    173185            } catch (URISyntaxException e) {
    174                 e.printStackTrace();
     186                OutputController.getLogger().log(OutputController.Level.ERROR_ALL, e);
    175187            }
    176188        }
  • trunk/icedtea-web/netx/net/sourceforge/jnlp/runtime/JNLPProxySelector.java

    r348 r429  
    3434
    3535import net.sourceforge.jnlp.config.DeploymentConfiguration;
     36import net.sourceforge.jnlp.util.logging.OutputController;
    3637
    3738/**
     
    8384    private String overrideHosts = null;
    8485
    85     /**
    86      * Creates a new JNLPProxySelector.
    87      */
    88     public JNLPProxySelector() {
    89         parseConfiguration();
     86    public JNLPProxySelector(DeploymentConfiguration config) {
     87        parseConfiguration(config);
    9088    }
    9189
     
    9391     * Initialize this ProxySelector by reading the configuration
    9492     */
    95     private void parseConfiguration() {
    96         DeploymentConfiguration config = JNLPRuntime.getConfiguration();
    97 
     93    private void parseConfiguration(DeploymentConfiguration config) {
    9894        proxyType = Integer.valueOf(config.getProperty(DeploymentConfiguration.KEY_PROXY_TYPE));
    9995
     
    10399                autoConfigUrl = new URL(autoConfigString);
    104100            } catch (MalformedURLException e) {
    105                 e.printStackTrace();
     101                OutputController.getLogger().log(OutputController.Level.ERROR_ALL, e);
    106102            }
    107103        }
     
    165161                proxyPort = Integer.valueOf(port);
    166162            } catch (NumberFormatException e) {
    167                 e.printStackTrace();
     163                OutputController.getLogger().log(OutputController.Level.ERROR_ALL, e);
    168164            }
    169165        }
     
    176172    @Override
    177173    public void connectFailed(URI uri, SocketAddress sa, IOException ioe) {
    178         ioe.printStackTrace();
     174        OutputController.getLogger().log(OutputController.Level.ERROR_ALL, ioe);
    179175    }
    180176
     
    184180    @Override
    185181    public List<Proxy> select(URI uri) {
    186         if (JNLPRuntime.isDebug()) {
    187             System.out.println("Selecting proxy for: " + uri);
    188         }
    189 
     182        OutputController.getLogger().log("Selecting proxy for: " + uri);
     183       
    190184        if (inBypassList(uri)) {
    191185            List<Proxy> proxies = Arrays.asList(new Proxy[] { Proxy.NO_PROXY });
    192             if (JNLPRuntime.isDebug()) {
    193                 System.out.println("Selected proxies: " + Arrays.toString(proxies.toArray()));
    194             }
     186            OutputController.getLogger().log("Selected proxies: " + Arrays.toString(proxies.toArray()));
    195187            return proxies;
    196188        }
     
    217209        }
    218210
    219         if (JNLPRuntime.isDebug()) {
    220             System.out.println("Selected proxies: " + Arrays.toString(proxies.toArray()));
    221         }
     211        OutputController.getLogger().log("Selected proxies: " + Arrays.toString(proxies.toArray()));
    222212        return proxies;
    223213    }
     
    241231                }
    242232            } else if (scheme.equals("socket")) {
    243                 String host = uri.getSchemeSpecificPart().split(":")[0];
     233                String host = uri.getHost();
    244234
    245235                if (bypassLocal && isLocalHost(host)) {
     
    299289     */
    300290    private List<Proxy> getFromConfiguration(URI uri) {
     291        return getFromArguments(uri, sameProxy, false,
     292                proxyHttpsHost, proxyHttpsPort,
     293                proxyHttpHost, proxyHttpPort,
     294                proxyFtpHost, proxyFtpPort,
     295                proxySocks4Host, proxySocks4Port);
     296    }
     297
     298    /**
     299     * Returns a list of proxies by using the arguments
     300     *
     301     * @return a List of Proxy objects
     302     */
     303    protected static List<Proxy> getFromArguments(URI uri,
     304            boolean sameProxy, boolean sameProxyIncludesSocket,
     305            String proxyHttpsHost, int proxyHttpsPort,
     306            String proxyHttpHost, int proxyHttpPort,
     307            String proxyFtpHost, int proxyFtpPort,
     308            String proxySocks4Host, int proxySocks4Port) {
     309
    301310        List<Proxy> proxies = new ArrayList<Proxy>();
    302311
    303312        String scheme = uri.getScheme();
    304313
     314        boolean socksProxyAdded = false;
     315
    305316        if (sameProxy) {
    306             SocketAddress sa = new InetSocketAddress(proxyHttpHost, proxyHttpPort);
    307             Proxy proxy;
    308             if (scheme.equals("socket")) {
    309                 proxy = new Proxy(Type.SOCKS, sa);
    310             } else {
    311                 proxy = new Proxy(Type.HTTP, sa);
    312             }
    313             proxies.add(proxy);
    314         } else if (scheme.equals("http")) {
     317            if (proxyHttpHost != null) {
     318                SocketAddress sa = new InetSocketAddress(proxyHttpHost, proxyHttpPort);
     319                if ((scheme.equals("https") || scheme.equals("http") || scheme.equals("ftp"))) {
     320                    Proxy proxy = new Proxy(Type.HTTP, sa);
     321                    proxies.add(proxy);
     322                } else if (scheme.equals("socket") && sameProxyIncludesSocket) {
     323                    Proxy proxy = new Proxy(Type.SOCKS, sa);
     324                    proxies.add(proxy);
     325                    socksProxyAdded = true;
     326                }
     327            }
     328        } else if (scheme.equals("http") && proxyHttpHost != null) {
    315329            SocketAddress sa = new InetSocketAddress(proxyHttpHost, proxyHttpPort);
    316330            proxies.add(new Proxy(Type.HTTP, sa));
    317         } else if (scheme.equals("https")) {
     331        } else if (scheme.equals("https") && proxyHttpsHost != null) {
    318332            SocketAddress sa = new InetSocketAddress(proxyHttpsHost, proxyHttpsPort);
    319333            proxies.add(new Proxy(Type.HTTP, sa));
    320         } else if (scheme.equals("ftp")) {
     334        } else if (scheme.equals("ftp") && proxyFtpHost != null) {
    321335            SocketAddress sa = new InetSocketAddress(proxyFtpHost, proxyFtpPort);
    322336            proxies.add(new Proxy(Type.HTTP, sa));
    323         } else if (scheme.equals("socket")) {
     337        }
     338
     339        if (!socksProxyAdded && (proxySocks4Host != null)) {
    324340            SocketAddress sa = new InetSocketAddress(proxySocks4Host, proxySocks4Port);
    325341            proxies.add(new Proxy(Type.SOCKS, sa));
    326         } else {
     342            socksProxyAdded = true;
     343        }
     344
     345        if (proxies.size() == 0) {
    327346            proxies.add(Proxy.NO_PROXY);
    328347        }
     
    349368            proxies.addAll(getProxiesFromPacResult(proxiesString));
    350369        } catch (MalformedURLException e) {
    351             e.printStackTrace();
     370            OutputController.getLogger().log(OutputController.Level.ERROR_ALL, e);
    352371            proxies.add(Proxy.NO_PROXY);
    353372        }
     
    369388     * @param pacString a string indicating proxies. For example
    370389     * "PROXY foo.bar:3128; DIRECT"
    371      * @return a list of Proxy objects represeting the parsed string.
     390     * @return a list of Proxy objects representing the parsed string. In
     391     * case of malformed input, an empty list may be returned
    372392     */
    373393    public static List<Proxy> getProxiesFromPacResult(String pacString) {
     
    407427                proxies.add(Proxy.NO_PROXY);
    408428            } else {
    409                 if (JNLPRuntime.isDebug()) {
    410                     System.out.println("Unrecognized proxy token: " + token);
    411                 }
     429                 OutputController.getLogger().log("Unrecognized proxy token: " + token);
    412430            }
    413431        }
  • trunk/icedtea-web/netx/net/sourceforge/jnlp/runtime/JNLPRuntime.java

    r418 r429  
    1717package net.sourceforge.jnlp.runtime;
    1818
    19 import java.io.*;
     19import java.awt.EventQueue;
     20import java.io.File;
     21import java.io.FileInputStream;
     22import java.io.FileOutputStream;
     23import java.io.IOException;
     24import java.lang.reflect.Constructor;
     25import java.lang.reflect.InvocationTargetException;
    2026import java.net.Authenticator;
     27import java.net.InetAddress;
    2128import java.net.ProxySelector;
     29import java.net.URL;
     30import java.net.UnknownHostException;
    2231import java.nio.channels.FileChannel;
    2332import java.nio.channels.FileLock;
    24 import java.awt.*;
    25 import java.text.*;
    26 import java.util.*;
     33import java.security.AllPermission;
     34import java.security.KeyStore;
     35import java.security.Policy;
     36import java.security.Security;
     37import java.text.MessageFormat;
    2738import java.util.List;
    28 import java.security.*;
    29 import javax.jnlp.*;
     39import java.util.ResourceBundle;
     40
     41import javax.jnlp.ServiceManager;
    3042import javax.naming.ConfigurationException;
    3143import javax.net.ssl.HttpsURLConnection;
     
    3446import javax.net.ssl.SSLSocketFactory;
    3547import javax.net.ssl.TrustManager;
     48import javax.swing.JOptionPane;
    3649import javax.swing.UIManager;
    3750import javax.swing.text.html.parser.ParserDelegator;
    3851
    39 import sun.net.www.protocol.jar.URLJarFile;
    40 
    41 import net.sourceforge.jnlp.*;
     52import net.sourceforge.jnlp.DefaultLaunchHandler;
     53import net.sourceforge.jnlp.GuiLaunchHandler;
     54import net.sourceforge.jnlp.LaunchHandler;
     55import net.sourceforge.jnlp.Launcher;
    4256import net.sourceforge.jnlp.browser.BrowserAwareProxySelector;
    43 import net.sourceforge.jnlp.cache.*;
     57import net.sourceforge.jnlp.cache.CacheUtil;
     58import net.sourceforge.jnlp.cache.DefaultDownloadIndicator;
     59import net.sourceforge.jnlp.cache.DownloadIndicator;
     60import net.sourceforge.jnlp.cache.UpdatePolicy;
    4461import net.sourceforge.jnlp.config.DeploymentConfiguration;
    4562import net.sourceforge.jnlp.security.JNLPAuthenticator;
    4663import net.sourceforge.jnlp.security.KeyStores;
    4764import net.sourceforge.jnlp.security.SecurityDialogMessageHandler;
    48 import net.sourceforge.jnlp.security.VariableX509TrustManager;
    49 import net.sourceforge.jnlp.services.*;
    50 import net.sourceforge.jnlp.util.*;
     65import net.sourceforge.jnlp.services.XServiceManagerStub;
     66import net.sourceforge.jnlp.util.FileUtils;
     67import net.sourceforge.jnlp.util.logging.JavaConsole;
     68import net.sourceforge.jnlp.util.logging.OutputController;
     69import net.sourceforge.jnlp.util.logging.LogConfig;
     70import sun.net.www.protocol.jar.URLJarFile;
    5171
    5272/**
     73 * <p>
    5374 * Configure and access the runtime environment.  This class
    5475 * stores global jnlp properties such as default download
    5576 * indicators, the install/base directory, the default resource
    5677 * update policy, etc.  Some settings, such as the base directory,
    57  * cannot be changed once the runtime has been initialized.<p>
    58  *
     78 * cannot be changed once the runtime has been initialized.
     79 * </p>
     80 * <p>
    5981 * The JNLP runtime can be locked to prevent further changes to
    6082 * the runtime environment except by a specified class.  If set,
    6183 * only instances of the <i>exit class</i> can exit the JVM or
    6284 * change the JNLP runtime settings once the runtime has been
    63  * initialized.<p>
     85 * initialized.
     86 * </p>
    6487 *
    6588 * @author <a href="mailto:jmaxwell@users.sourceforge.net">Jon A. Maxwell (JAM)</a> - initial author
     
    7295    }
    7396
     97    /**
     98     * java-abrt-connector can print out specific application String method, it is good to save visited urls for reproduce purposes.
     99     * For javaws we can read the destination jnlp from commandline
     100     * However for plugin (url arrive via pipes). Also for plugin we can not be sure which opened tab/window
     101     * have caused the crash. Thats why the individual urls are added, not replaced.
     102     */
     103    private static String history = "";
     104
    74105    /** the localized resource strings */
    75106    private static ResourceBundle resources;
    76107
    77     private static final DeploymentConfiguration config = new DeploymentConfiguration();
    78 
    79108    /** the security manager */
    80109    private static JNLPSecurityManager security;
     
    110139    private static boolean debug = false;
    111140
    112     /** whether streams should be redirected */
    113     private static boolean redirectStreams = false;
     141    /**
     142     * whether plugin debug mode is on
     143     */
     144    private static Boolean pluginDebug = null;
    114145
    115146    /** mutex to wait on, for initialization */
     
    122153    private static boolean forksAllowed = true;
    123154
    124     /** all security dialogs will be consumed and pretented as beeing verified by user and allowed.*/
     155    /** all security dialogs will be consumed and pretented as being verified by user and allowed.*/
    125156    private static boolean trustAll=false;
     157
     158    /** all security dialogs will be consumed and we will pretend the Sandbox option was chosen */
     159    private static boolean trustNone = false;
     160   
     161    /** allows 301.302.303.307.308 redirects to be followed when downloading resources*/
     162    private static boolean allowRedirect = false;;
     163   
     164    /** when this is true, ITW will not attempt any inet connections and will work only with what is in cache*/
     165    private static boolean offlineForced = false;
     166
     167    private static Boolean onlineDetected = null;
     168
     169
     170    /**
     171     * Header is not checked and so eg
     172     * <a href="https://en.wikipedia.org/wiki/Gifar">gifar</a> exploit is
     173     * possible.<br/>
     174     * However if jar file is a bit corrupted, then it sometimes can work so
     175     * this switch can disable the header check.
     176     * @see <a href="https://en.wikipedia.org/wiki/Gifar">Gifar attack</a>
     177     */
     178    private static boolean ignoreHeaders=false;
    126179
    127180    /** contains the arguments passed to the jnlp runtime */
     
    131184    private static FileLock fileLock;
    132185
    133     public static final String STDERR_FILE = "java.stderr";
    134     public static final String STDOUT_FILE = "java.stdout";
    135 
    136 
    137186    /**
    138187     * Returns whether the JNLP runtime environment has been
    139      * initialized.  Once initialized, some properties such as the
    140      * base directory cannot be changed.  Before
     188     * initialized. Once initialized, some properties such as the
     189     * base directory cannot be changed. Before
    141190     */
    142191    public static boolean isInitialized() {
     
    147196     * Initialize the JNLP runtime environment by installing the
    148197     * security manager and security policy, initializing the JNLP
    149      * standard services, etc.<p>
    150      *
    151      * This method should be called from the main AppContext/Thread. <p>
    152      *
    153      * This method cannot be called more than once.  Once
     198     * standard services, etc.
     199     * <p>
     200     * This method should be called from the main AppContext/Thread.
     201     * </p>
     202     * <p>
     203     * This method cannot be called more than once. Once
    154204     * initialized, methods that alter the runtime can only be
    155      * called by the exit class.<p>
    156      *
    157      * @param isApplication is true if a webstart application is being initialized
    158      *
     205     * called by the exit class.
     206     * </p>
     207     *
     208     * @param isApplication is {@code true} if a webstart application is being
     209     * initialized
    159210     * @throws IllegalStateException if the runtime was previously initialized
    160211     */
     
    163214
    164215        try {
    165             config.load();
    166         } catch (ConfigurationException e) {
    167             /* exit if there is a fatal exception loading the configuration */
    168             if (isApplication) {
    169                 System.out.println(getMessage("RConfigurationError"));
    170                 System.exit(1);
    171             }
    172         }
    173 
    174         KeyStores.setConfiguration(config);
    175 
    176         initializeStreams();
     216            UIManager.setLookAndFeel(UIManager.getSystemLookAndFeelClassName());
     217        } catch (Exception e) {
     218            OutputController.getLogger().log("Unable to set system look and feel");
     219        }
     220
     221        if (JavaConsole.canShowOnStartup(isApplication)) {
     222            JavaConsole.getConsole().showConsoleLater();
     223        }
     224        /* exit if there is a fatal exception loading the configuration */
     225        if (getConfiguration().getLoadingException() != null) {
     226            if (getConfiguration().getLoadingException() instanceof ConfigurationException){
     227                // ConfigurationException is thrown only if deployment.config's field
     228                // deployment.system.config.mandatory is true, and the destination
     229                //where deployment.system.config points is not readable
     230                throw new RuntimeException(getConfiguration().getLoadingException());
     231            }
     232            OutputController.getLogger().log(OutputController.Level.WARNING_ALL, getMessage("RConfigurationError")+": "+getConfiguration().getLoadingException().getMessage());
     233        }
     234        KeyStores.setConfiguration(getConfiguration());
    177235
    178236        isWebstartApplication = isApplication;
     
    191249        if (handler == null) {
    192250            if (headless) {
    193                 handler = new DefaultLaunchHandler(System.err);
     251                handler = new DefaultLaunchHandler(OutputController.getLogger());
    194252            } else {
    195                 handler = new GuiLaunchHandler(System.err);
     253                handler = new GuiLaunchHandler(OutputController.getLogger());
    196254            }
    197255        }
     
    201259        policy = new JNLPPolicy();
    202260        security = new JNLPSecurityManager(); // side effect: create JWindow
    203 
    204         try {
    205             UIManager.setLookAndFeel(UIManager.getSystemLookAndFeelClassName());
    206         } catch (Exception e) {
    207             // ignore it
    208         }
    209261
    210262        doMainAppContextHacks();
     
    224276            KeyManagerFactory kmf = KeyManagerFactory.getInstance("SunX509");
    225277            kmf.init(ks, KeyStores.getPassword());
    226             TrustManager[] trust = new TrustManager[] { VariableX509TrustManager.getInstance() };
     278            TrustManager[] trust = new TrustManager[] { getSSLSocketTrustManager() };
    227279            context.init(kmf.getKeyManagers(), trust, null);
    228280            sslSocketFactory = context.getSocketFactory();
     
    230282            HttpsURLConnection.setDefaultSSLSocketFactory(sslSocketFactory);
    231283        } catch (Exception e) {
    232             System.err.println("Unable to set SSLSocketfactory (may _prevent_ access to sites that should be trusted)! Continuing anyway...");
    233             e.printStackTrace();
     284            OutputController.getLogger().log(OutputController.Level.ERROR_ALL, "Unable to set SSLSocketfactory (may _prevent_ access to sites that should be trusted)! Continuing anyway...");
     285            OutputController.getLogger().log(OutputController.Level.ERROR_ALL, e);
    234286        }
    235287
    236288        // plug in a custom authenticator and proxy selector
    237289        Authenticator.setDefault(new JNLPAuthenticator());
    238         ProxySelector.setDefault(new BrowserAwareProxySelector());
     290        BrowserAwareProxySelector proxySelector = new BrowserAwareProxySelector(getConfiguration());
     291        proxySelector.initialize();
     292        ProxySelector.setDefault(proxySelector);
    239293
    240294        // Restrict access to netx classes
     
    246300        initialized = true;
    247301
     302    }
     303
     304    public static void reloadPolicy() {
     305        policy.refresh();
     306    }
     307
     308    /**
     309     * Returns a TrustManager ideal for the running VM.
     310     *
     311     * @return TrustManager the trust manager to use for verifying https certificates
     312     */
     313    private static TrustManager getSSLSocketTrustManager() throws
     314                                ClassNotFoundException, IllegalAccessException, InstantiationException, InvocationTargetException {
     315
     316        try {
     317
     318            Class<?> trustManagerClass;
     319            Constructor<?> tmCtor = null;
     320
     321            if (System.getProperty("java.version").startsWith("1.6")) { // Java 6
     322                try {
     323                    trustManagerClass = Class.forName("net.sourceforge.jnlp.security.VariableX509TrustManagerJDK6");
     324                 } catch (ClassNotFoundException cnfe) {
     325                     OutputController.getLogger().log(OutputController.Level.ERROR_ALL, "Unable to find class net.sourceforge.jnlp.security.VariableX509TrustManagerJDK6");
     326                     return null;
     327                 }
     328            } else { // Java 7 or more (technically could be <= 1.5 but <= 1.5 is unsupported)
     329                try {
     330                    trustManagerClass = Class.forName("net.sourceforge.jnlp.security.VariableX509TrustManagerJDK7");
     331                 } catch (ClassNotFoundException cnfe) {
     332                     OutputController.getLogger().log(OutputController.Level.ERROR_ALL, "Unable to find class net.sourceforge.jnlp.security.VariableX509TrustManagerJDK7");
     333                     return null;
     334                 }
     335            }
     336
     337            Constructor<?>[] tmCtors = trustManagerClass.getDeclaredConstructors();
     338            tmCtor = tmCtors[0];
     339
     340            for (Constructor<?> ctor : tmCtors) {
     341                if (tmCtor.getGenericParameterTypes().length == 0) {
     342                    tmCtor = ctor;
     343                    break;
     344                }
     345            }
     346
     347            return (TrustManager) tmCtor.newInstance();
     348        } catch (RuntimeException e) {
     349            OutputController.getLogger().log(OutputController.Level.ERROR_ALL, "Unable to load JDK-specific TrustManager. Was this version of IcedTea-Web compiled with JDK 6 or 7?");
     350            OutputController.getLogger().log(e);
     351            throw e;
     352        }
    248353    }
    249354
     
    282387    }
    283388
    284     /**
    285      * Initializes the standard output and error streams, redirecting them or
    286      * duplicating them as required.
    287      */
    288     private static void initializeStreams() {
    289         Boolean enableLogging = Boolean.valueOf(config
    290                 .getProperty(DeploymentConfiguration.KEY_ENABLE_LOGGING));
    291         if (redirectStreams || enableLogging) {
    292             String logDir = config.getProperty(DeploymentConfiguration.KEY_USER_LOG_DIR);
    293 
     389
     390   
     391     
     392   
     393   
     394
     395    public static boolean isOfflineForced() {
     396        return offlineForced;
     397    }
     398
     399    public static void setOnlineDetected(boolean online) {
     400        onlineDetected = online;
     401        OutputController.getLogger().log(OutputController.Level.MESSAGE_DEBUG, "Detected online set to: " + onlineDetected);
     402    }
     403
     404    public static boolean isOnlineDetected() {
     405        if (onlineDetected == null) {
     406            //"file" protocol do not do online check
     407            //sugest online for this case
     408            return true;
     409        }
     410        return onlineDetected;
     411    }
     412
     413    public static boolean isOnline() {
     414        if (isOfflineForced()) {
     415            return false;
     416        }
     417        return isOnlineDetected();
     418    }
     419
     420    public static void detectOnline(URL location) {
     421        if (onlineDetected != null) {
     422            return;
     423        }
     424        try {
     425            if (location.getProtocol().equals("file")) {
     426                return;
     427            }
     428            //Checks the offline/online status of the system.
     429            InetAddress.getByName(location.getHost());
     430        } catch (UnknownHostException ue) {
     431            OutputController.getLogger().log(OutputController.Level.ERROR_ALL, "The host of " + location.toExternalForm() + " file should be located seems down, or you are simply offline.");
     432            JNLPRuntime.setOnlineDetected(false);
     433            return;
     434        }
     435        setOnlineDetected(true);
     436    }
     437   
     438    /**
     439     * see <a href="https://en.wikipedia.org/wiki/Double-checked_locking#Usage_in_Java">Double-checked locking in Java</a>
     440     * for cases how not to do lazy initialization
     441     * and <a href="https://en.wikipedia.org/wiki/Initialization_on_demand_holder_idiom">Initialization on demand holder idiom</a>
     442     * for ITW approach
     443     */
     444    private static class DeploymentConfigurationHolder {
     445
     446        private static final DeploymentConfiguration INSTANCE = initConfiguration();
     447
     448        private static DeploymentConfiguration initConfiguration() {
     449            DeploymentConfiguration config = new DeploymentConfiguration();
    294450            try {
    295                 File errFile = new File(logDir, JNLPRuntime.STDERR_FILE);
    296                 FileUtils.createParentDir(errFile);
    297                 FileUtils.createRestrictedFile(errFile, true);
    298                 File outFile = new File(logDir, JNLPRuntime.STDOUT_FILE);
    299                 FileUtils.createParentDir(outFile);
    300                 FileUtils.createRestrictedFile(outFile, true);
    301 
    302                 if (redirectStreams) {
    303                     System.setErr(new PrintStream(new FileOutputStream(errFile)));
    304                     System.setOut(new PrintStream(new FileOutputStream(outFile)));
    305                 } else {
    306                     System.setErr(new TeeOutputStream(new FileOutputStream(errFile), System.err));
    307                     System.setOut(new TeeOutputStream(new FileOutputStream(outFile), System.out));
     451                config.load();
     452                config.copyTo(System.getProperties());
     453            } catch (ConfigurationException ex) {
     454                OutputController.getLogger().log(OutputController.Level.MESSAGE_ALL, Translator.R("RConfigurationError"));
     455                //mark this exceptionas we can die on it later
     456                config.setLoadingException(ex);
     457                //to be sure - we MUST die - http://docs.oracle.com/javase/6/docs/technotes/guides/deployment/deployment-guide/properties.html
     458            }catch(Exception t){
     459                //all exceptions are causing InstantiatizationError so this do it much more readble
     460                OutputController.getLogger().log(OutputController.Level.ERROR_ALL, t);
     461                OutputController.getLogger().log(OutputController.Level.WARNING_ALL, Translator.R("RFailingToDefault"));
     462                if (!JNLPRuntime.isHeadless()){
     463                    JOptionPane.showMessageDialog(null, getMessage("RFailingToDefault")+"\n"+t.toString());
    308464                }
    309             } catch (Exception e) {
    310                 e.printStackTrace();
    311             }
     465                //try to survive this unlikely exception
     466                config.resetToDefaults();
     467            } finally {
     468                OutputController.getLogger().startConsumer();
     469            }
     470            return config;
    312471        }
    313472    }
     
    315474    /**
    316475     * Gets the Configuration associated with this runtime
     476     *
    317477     * @return a {@link DeploymentConfiguration} object that can be queried to
    318478     * find relevant configuration settings
    319479     */
    320480    public static DeploymentConfiguration getConfiguration() {
    321         return config;
     481        return DeploymentConfigurationHolder.INSTANCE;
    322482    }
    323483
     
    349509     * components.  In headless mode, client features that use the
    350510     * AWT are disabled such that the client can be used in
    351      * headless mode (<code>java.awt.headless=true</code>).
     511     * headless mode ({@code java.awt.headless=true}).
    352512     *
    353513     * @throws IllegalStateException if the runtime was previously initialized
     
    357517        headless = enabled;
    358518    }
     519   
     520    public static void setAllowRedirect(boolean enabled) {
     521        checkInitialized();
     522        allowRedirect = enabled;
     523    }
     524
     525    public static boolean isAllowRedirect() {
     526        return allowRedirect;
     527    }
     528   
    359529
    360530    /**
     
    379549     * applications, and can be used to use netx with other code
    380550     * that uses its own security manager or policy.
    381      *
     551     * <p>
    382552     * Disabling security is not recommended and should only be
    383      * used if the JNLP files opened are trusted.  This method can
    384      * only be called before initalizing the runtime.<p>
     553     * used if the JNLP files opened are trusted. This method can
     554     * only be called before initalizing the runtime.
     555     * </p>
    385556     *
    386557     * @param enabled whether security should be enabled
     
    411582     * @throws IllegalStateException if caller is not the exit class
    412583     */
    413     public static void setExitClass(Class exitClass) {
     584    public static void setExitClass(Class<?> exitClass) {
    414585        checkExitClass();
    415586        security.setExitClass(exitClass);
     
    438609     */
    439610    public static boolean isDebug() {
     611        return isSetDebug() ||  isPluginDebug() || LogConfig.getLogConfig().isEnableLogging();
     612    }
     613
     614     public static boolean isSetDebug() {
    440615        return debug;
    441616    }
     
    452627    }
    453628
    454     /**
    455      * Sets whether the standard output/error streams should be redirected to
    456      * the loggging files.
    457      *
    458      * @throws IllegalStateException if the runtime has already been initialized
    459      */
    460     public static void setRedirectStreams(boolean redirect) {
    461         checkInitialized();
    462         redirectStreams = redirect;
    463     }
    464 
     629 
    465630    /**
    466631     * Sets the default update policy.
     
    514679    /**
    515680     * Returns the localized resource string identified by the
    516      * specified key.  If the message is empty, a null is
     681     * specified key. If the message is empty, a null is
    517682     * returned.
    518683     */
     
    533698
    534699    /**
    535      * Returns the localized resource string using the specified
    536      * arguments.
     700     * Returns the localized resource string using the specified arguments.
    537701     *
    538702     * @param args the formatting arguments to the resource string
     
    543707
    544708    /**
    545      * Returns true if the current runtime will fork
     709     * Returns {@code true} if the current runtime will fork
    546710     */
    547711    public static boolean getForksAllowed() {
     
    555719
    556720    /**
    557      * Throws an exception if called when the runtime is
    558      * already initialized.
     721     * Throws an exception if called when the runtime is already initialized.
    559722     */
    560723    private static void checkInitialized() {
     
    564727
    565728    /**
    566      * Throws an exception if called with security enabled but
    567      * a caller is not the exit class and the runtime has been
    568      * initialized.
     729     * Throws an exception if called with security enabled but a caller is not
     730     * the exit class and the runtime has been initialized.
    569731     */
    570732    private static void checkExitClass() {
     
    599761
    600762    /**
    601      * @return true if running on Windows
     763     * @return {@code true} if running on Windows
    602764     */
    603765    public static boolean isWindows() {
     
    607769
    608770    /**
    609      * @return true if running on a Unix or Unix-like system (including Linux
    610      * and *BSD)
     771     * @return {@code true} if running on a Unix or Unix-like system (including
     772     * Linux and *BSD)
    611773     */
    612774    public static boolean isUnix() {
     
    628790
    629791    /**
    630      * Indicate that netx is running by creating the {@link JNLPRuntime#INSTANCE_FILE} and
     792     * Indicate that netx is running by creating the
     793     * {@link DeploymentConfiguration#KEY_USER_NETX_RUNNING_FILE} and
    631794     * acquiring a shared lock on it
    632795     */
     
    662825           
    663826            if (fileLock != null && fileLock.isShared()) {
    664                 if (JNLPRuntime.isDebug()) {
    665                     System.out.println("Acquired shared lock on " +
     827                OutputController.getLogger().log("Acquired shared lock on " +
    666828                            netxRunningFile.toString() + " to indicate javaws is running");
    667                 }
    668829            }
    669830        } catch (IOException e) {
    670             e.printStackTrace();
    671         }
    672 
    673         Runtime.getRuntime().addShutdownHook(new Thread() {
     831            OutputController.getLogger().log(OutputController.Level.ERROR_ALL, e);
     832        }
     833
     834        Runtime.getRuntime().addShutdownHook(new Thread("JNLPRuntimeShutdownHookThread") {
    674835            public void run() {
    675836                markNetxStopped();
     
    681842    /**
    682843     * Indicate that netx is stopped by releasing the shared lock on
    683      * {@link JNLPRuntime#INSTANCE_FILE}.
     844     * {@link DeploymentConfiguration#KEY_USER_NETX_RUNNING_FILE}.
    684845     */
    685846    private static void markNetxStopped() {
     
    691852            fileLock.channel().close();
    692853            fileLock = null;
    693             if (JNLPRuntime.isDebug()) {
    694                 String file = JNLPRuntime.getConfiguration()
    695                         .getProperty(DeploymentConfiguration.KEY_USER_NETX_RUNNING_FILE);
    696                 System.out.println("Release shared lock on " + file);
    697             }
     854            OutputController.getLogger().log("Release shared lock on " + JNLPRuntime.getConfiguration()
     855                        .getProperty(DeploymentConfiguration.KEY_USER_NETX_RUNNING_FILE));
    698856        } catch (IOException e) {
    699             e.printStackTrace();
     857            OutputController.getLogger().log(e);
    700858        }
    701859    }
     
    709867    }
    710868
     869    static void setTrustNone(final boolean b) {
     870        trustNone = b;
     871    }
     872
     873    public static boolean isTrustNone() {
     874        return trustNone;
     875    }
     876
     877    public static boolean isIgnoreHeaders() {
     878        return ignoreHeaders;
     879    }
     880
     881    public static void setIgnoreHeaders(boolean ignoreHeaders) {
     882        JNLPRuntime.ignoreHeaders = ignoreHeaders;
     883    }
     884
     885    private static boolean isPluginDebug() {
     886        if (pluginDebug == null) {
     887            try {
     888                //there are cases when this itself is not allowed by security manager, and so
     889                //throws exception. Under some conditions it can couse deadlock
     890                pluginDebug = System.getenv().containsKey("ICEDTEAPLUGIN_DEBUG");
     891            } catch (Exception ex) {
     892                pluginDebug = false;
     893                OutputController.getLogger().log(ex);
     894            }
     895        }
     896        return pluginDebug;
     897    }
     898
     899    public static void exit(int i) {
     900        OutputController.getLogger().close();
     901        System.exit(i);
     902    }
     903
     904
     905    public static void saveHistory(String documentBase) {
     906        JNLPRuntime.history += " " + documentBase + " ";
     907    }
     908
     909    /**
     910     * Used by java-abrt-connector via reflection
     911     * @return history
     912     */
     913    private static String getHistory() {
     914        return history;
     915    }
     916   
     917   
     918
    711919}
  • trunk/icedtea-web/netx/net/sourceforge/jnlp/runtime/JNLPSecurityManager.java

    r418 r429  
    1919import static net.sourceforge.jnlp.runtime.Translator.R;
    2020
    21 import java.awt.Frame;
    2221import java.awt.Window;
    23 import java.lang.ref.WeakReference;
    2422import java.net.SocketPermission;
    25 import java.security.AllPermission;
    2623import java.security.AccessControlException;
    2724import java.security.Permission;
    28 import java.security.SecurityPermission;
    2925
    3026import javax.swing.JWindow;
    3127
    32 import net.sourceforge.jnlp.JNLPFile;
    3328import net.sourceforge.jnlp.security.SecurityDialogs.AccessType;
    3429import net.sourceforge.jnlp.services.ServiceUtil;
     30import net.sourceforge.jnlp.util.logging.OutputController;
    3531import net.sourceforge.jnlp.util.WeakList;
    3632import sun.awt.AWTSecurityManager;
    3733import sun.awt.AppContext;
    38 import sun.security.util.SecurityConstants;
    3934
    4035/**
    41  * Security manager for JNLP environment.  This security manager
     36 * Security manager for JNLP environment. This security manager
    4237 * cannot be replaced as it always denies attempts to replace the
    43  * security manager or policy.<p>
    44  *
     38 * security manager or policy.
     39 * <p>
    4540 * The JNLP security manager tracks windows created by an
    4641 * application, allowing those windows to be disposed when the
    47  * application exits but the JVM does not.  If security is not
     42 * application exits but the JVM does not. If security is not
    4843 * enabled then the first application to call System.exit will
    49  * halt the JVM.<p>
     44 * halt the JVM.
     45 * </p>
    5046 *
    5147 * @author <a href="mailto:jmaxwell@users.sourceforge.net">Jon A. Maxwell (JAM)</a> - initial author
     
    118114        // called for it (and not disposed).
    119115
    120         if (!JNLPRuntime.isHeadless())
     116        if (!JNLPRuntime.isHeadless()) {
    121117            new JWindow().getOwner();
     118        }
    122119
    123120        mainAppContext = AppContext.getAppContext();
     
    137134     */
    138135    private boolean isExitClass(Class stack[]) {
    139         if (exitClass == null)
     136        if (exitClass == null) {
    140137            return true;
    141 
    142         for (int i = 0; i < stack.length; i++)
    143             if (stack[i] == exitClass)
     138        }
     139
     140        for (int i = 0; i < stack.length; i++) {
     141            if (stack[i] == exitClass) {
    144142                return true;
     143            }
     144        }
    145145
    146146        return false;
     
    154154     * @throws IllegalStateException if the exit class is already set
    155155     */
    156     public void setExitClass(Class exitClass) throws IllegalStateException {
    157         if (this.exitClass != null)
     156    public void setExitClass(Class<?> exitClass) throws IllegalStateException {
     157        if (this.exitClass != null) {
    158158            throw new IllegalStateException(R("RExitTaken"));
     159        }
    159160
    160161        this.exitClass = exitClass;
     
    181182            }
    182183
    183             if (w == window)
     184            if (w == window) {
    184185                return weakApplications.get(i);
     186            }
    185187        }
    186188
     
    204206        }
    205207
    206         if (maxDepth <= 0)
     208        if (maxDepth <= 0) {
    207209            maxDepth = stack.length;
     210        }
    208211
    209212        // this needs to be tightened up
     
    230233        // Since we want to deal with JNLPClassLoader, extract it if this
    231234        // is a codebase loader
    232         if (cl instanceof JNLPClassLoader.CodeBaseClassLoader)
     235        if (cl instanceof JNLPClassLoader.CodeBaseClassLoader) {
    233236            cl = ((JNLPClassLoader.CodeBaseClassLoader) cl).getParentJNLPClassLoader();
     237        }
    234238
    235239        if (cl instanceof JNLPClassLoader) {
     
    245249     * be determined; otherwise returns super.getThreadGroup()
    246250     */
     251    @Override
    247252    public ThreadGroup getThreadGroup() {
    248253        ApplicationInstance app = getApplication();
    249         if (app == null)
     254        if (app == null) {
    250255            return super.getThreadGroup();
     256        }
    251257
    252258        return app.getThreadGroup();
     
    258264     * permission to change the security manager or policy.
    259265     */
     266    @Override
    260267    public void checkPermission(Permission perm) {
    261268        String name = perm.getName();
     
    264271        // otherwise.
    265272        //      if (true)
    266         //        System.out.println("Checking permission: " + perm.toString());
     273        //        OutputController.getLogger().log("Checking permission: " + perm.toString());
    267274
    268275        if (!JNLPRuntime.isWebstartApplication() &&
    269                 ("setPolicy".equals(name) || "setSecurityManager".equals(name)))
     276                ("setPolicy".equals(name) || "setSecurityManager".equals(name))) {
    270277            throw new SecurityException(R("RCantReplaceSM"));
     278        }
    271279
    272280        try {
     
    284292            super.checkPermission(perm);
    285293        } catch (SecurityException ex) {
    286             if (JNLPRuntime.isDebug()) {
    287                 System.out.println("Denying permission: " + perm);
    288             }
     294            OutputController.getLogger().log("Denying permission: " + perm);
    289295            throw ex;
    290296        }
     
    319325            cl.addPermission(perm);
    320326            if (JNLPRuntime.isDebug()) {
    321                 if (cl.getPermissions(null).implies(perm))
    322                     System.err.println("Added permission: " + perm.toString());
    323                 else
    324                     System.err.println("Unable to add permission: " + perm.toString());
     327                if (cl.getSecurity() == null) {
     328                    if (cl.getPermissions(null).implies(perm)){
     329                        OutputController.getLogger().log(OutputController.Level.ERROR_ALL, "Added permission: " + perm.toString());
     330                    } else {
     331                        OutputController.getLogger().log(OutputController.Level.ERROR_ALL, "Unable to add permission: " + perm.toString());
     332                    }
     333                } else {
     334                    OutputController.getLogger().log(OutputController.Level.ERROR_ALL, "Cannot get permissions for null codesource when classloader security is not null");
     335                }
    325336            }
    326337        } else {
    327             if (JNLPRuntime.isDebug())
    328                 System.err.println("Unable to add permission: " + perm + ", classloader not JNLP.");
     338            OutputController.getLogger().log(OutputController.Level.ERROR_DEBUG, "Unable to add permission: " + perm + ", classloader not JNLP.");
    329339        }
    330340    }
     
    335345     * be disposed when the calling application exits.
    336346     */
     347    @Override
    337348    public boolean checkTopLevelWindow(Object window) {
    338349        ApplicationInstance app = getApplication();
     
    342353            Window w = (Window) window;
    343354
    344             if (JNLPRuntime.isDebug())
    345                 System.err.println("SM: app: " + app.getTitle() + " is adding a window: " + window + " with appContext " + AppContext.getAppContext());
     355            OutputController.getLogger().log(OutputController.Level.ERROR_DEBUG, "SM: app: " + app.getTitle() + " is adding a window: " + window + " with appContext " + AppContext.getAppContext());
    346356
    347357            weakWindows.add(w); // for mapping window -> app
     
    358368
    359369    /**
    360      * Checks whether the caller can exit the system.  This method
     370     * Checks whether the caller can exit the system. This method
    361371     * identifies whether the caller is a real call to Runtime.exec
    362372     * and has special behavior when returning from this method
     
    365375     * stopped and its resources destroyed (when possible), and an
    366376     * exception will be thrown to prevent the JVM from shutting
    367      * down.<p>
    368      *
     377     * down.
     378     * <p>
    369379     * Calls not from Runtime.exit or with no exit class set will
    370380     * behave normally, and the exit class can always exit the JVM.
    371      */
     381     * </p>
     382     */
     383    @Override
    372384    public void checkExit(int status) {
    373385
     
    375387        Class stack[] = getClassContext();
    376388        if (!exitAllowed) {
    377             for (int i = 0; i < stack.length; i++)
    378                 if (stack[i].getClassLoader() != null)
     389            for (int i = 0; i < stack.length; i++) {
     390                if (stack[i].getClassLoader() != null) {
    379391                    throw new AccessControlException("Applets may not call System.exit()");
     392                }
     393            }
    380394        }
    381395
     
    384398        boolean realCall = (stack[1] == Runtime.class);
    385399
    386         if (isExitClass(stack)) // either exitClass called or no exitClass set
    387             return; // to Runtime.exit or fake call to see if app has permission
     400        if (isExitClass(stack)) {
     401            return;
     402        } // to Runtime.exit or fake call to see if app has permission
    388403
    389404        // not called from Runtime.exit()
     
    414429     * AWTSecurityManager and if so, call this method to give it a chance to
    415430     * return the appropriate appContext based on the application that is
    416      * running.<p>
    417      *
     431     * running.
     432     * <p>
    418433     * This can be called from any thread (possibly a swing thread) to find out
    419434     * the AppContext for the thread (which may correspond to a particular
    420435     * applet).
     436     * </p>
    421437     */
    422438    @Override
     
    445461     *             permission to accesss the AWT event queue.
    446462     */
     463    @Override
    447464    public void checkAwtEventQueueAccess() {
    448465        /*
  • trunk/icedtea-web/netx/net/sourceforge/jnlp/runtime/PacEvaluatorFactory.java

    r348 r429  
    4444import java.net.URL;
    4545import java.util.Properties;
     46import net.sourceforge.jnlp.util.logging.OutputController;
    4647
    4748
     
    6162            properties.load(in);
    6263        } catch (IOException e) {
    63             if (JNLPRuntime.isDebug()) {
    64                 e.printStackTrace();
    65             }
     64            OutputController.getLogger().log(e);
    6665        } finally {
    6766            try {
    6867                in.close();
    6968            } catch (IOException e) {
    70                 if (JNLPRuntime.isDebug()) {
    71                     e.printStackTrace();
    72                 }
     69                OutputController.getLogger().log(e);
    7370            }
    7471        }
     
    8986                // ignore
    9087            } catch (InstantiationException e) {
    91                 e.printStackTrace();
     88                OutputController.getLogger().log(OutputController.Level.ERROR_ALL, e);
    9289            } catch (IllegalAccessException e) {
    93                 e.printStackTrace();
     90                OutputController.getLogger().log(OutputController.Level.ERROR_ALL, e);
    9491            } catch (NoSuchMethodException e) {
    95                 e.printStackTrace();
     92                OutputController.getLogger().log(OutputController.Level.ERROR_ALL, e);
    9693            } catch (IllegalArgumentException e) {
    97                 e.printStackTrace();
     94                OutputController.getLogger().log(OutputController.Level.ERROR_ALL, e);
    9895            } catch (InvocationTargetException e) {
    9996                if (e.getCause() != null) {
    100                     e.getCause().printStackTrace();
     97                    OutputController.getLogger().log(OutputController.Level.ERROR_ALL, e.getCause());
    10198                }
    10299            }
  • trunk/icedtea-web/netx/net/sourceforge/jnlp/runtime/RhinoBasedPacEvaluator.java

    r348 r429  
    4949import java.security.PrivilegedAction;
    5050import java.security.ProtectionDomain;
     51import java.util.PropertyPermission;
     52import net.sourceforge.jnlp.util.logging.OutputController;
    5153
    5254import net.sourceforge.jnlp.util.TimedHashMap;
     
    6062 * proxy file to find the proxy for a given url.
    6163 *
    62  * @see http://en.wikipedia.org/wiki/Proxy_auto-config#The_PAC_file
     64 * @see <a href="http://en.wikipedia.org/wiki/Proxy_auto-config#The_PAC_file">The PAC File</a>
    6365 */
    6466public class RhinoBasedPacEvaluator implements PacEvaluator {
     
    7577     */
    7678    public RhinoBasedPacEvaluator(URL pacUrl) {
    77         if (JNLPRuntime.isDebug()) {
    78             System.err.println("Using the Rhino based PAC evaluator for url " + pacUrl);
    79         }
     79        OutputController.getLogger().log(OutputController.Level.ERROR_DEBUG, "Using the Rhino based PAC evaluator for url " + pacUrl);
    8080        pacHelperFunctionContents = getHelperFunctionContents();
    8181        this.pacUrl = pacUrl;
     
    119119    private String getProxiesWithoutCaching(URL url) {
    120120        if (pacHelperFunctionContents == null) {
    121             System.err.println("Error loading pac functions");
     121            OutputController.getLogger().log(OutputController.Level.ERROR_ALL, "Error loading pac functions");
    122122            return "DIRECT";
    123123        }
     
    125125        EvaluatePacAction evaluatePacAction = new EvaluatePacAction(pacContents, pacUrl.toString(),
    126126                pacHelperFunctionContents, url);
     127
     128        // Purposefully giving only these permissions rather than using java.policy. The "evaluatePacAction"
     129        // isn't supposed to do very much and so doesn't require all the default permissions given by
     130        // java.policy
    127131        Permissions p = new Permissions();
    128132        p.add(new RuntimePermission("accessClassInPackage.org.mozilla.javascript"));
    129133        p.add(new SocketPermission("*", "resolve"));
     134        p.add(new PropertyPermission("java.vm.name", "read"));
     135
    130136        ProtectionDomain pd = new ProtectionDomain(null, p);
    131137        AccessControlContext context = new AccessControlContext(new ProtectionDomain[] { pd });
     
    145151            try {
    146152                while ((line = pacReader.readLine()) != null) {
    147                     // System.out.println(line);
     153                    // OutputController.getLogger().log(OutputController.Level.MESSAGE_ALL, line);
    148154                    contents = contents.append(line).append("\n");
    149155                }
     
    175181                contents = new StringBuilder();
    176182                while ((line = pacFuncsReader.readLine()) != null) {
    177                     // System.out.println(line);
     183                    // OutputController.getLogger().log(OutputController.Level.MESSAGE_ALL,line);
    178184                    contents = contents.append(line).append("\n");
    179185                }
     
    182188            }
    183189        } catch (IOException e) {
    184             e.printStackTrace();
     190            OutputController.getLogger().log(OutputController.Level.ERROR_ALL, e);
    185191            contents = null;
    186192        }
     
    243249                Object functionObj = scope.get("FindProxyForURL", scope);
    244250                if (!(functionObj instanceof Function)) {
    245                     System.err.println("FindProxyForURL not found");
     251                    OutputController.getLogger().log(OutputController.Level.ERROR_ALL, "FindProxyForURL not found");
    246252                    return null;
    247253                } else {
     
    253259                }
    254260            } catch (Exception e) {
    255                 e.printStackTrace();
     261                OutputController.getLogger().log(OutputController.Level.ERROR_ALL, e);
    256262                return "DIRECT";
    257263            } finally {
  • trunk/icedtea-web/netx/net/sourceforge/jnlp/security/CertVerifier.java

    r348 r429  
    11/* CertVerifier.java
    2    Copyright (C) 2009 Red Hat, Inc.
     2   Copyright (C) 2012 Red Hat, Inc.
    33
    44This file is part of IcedTea.
     
    4040import java.security.cert.CertPath;
    4141import java.security.cert.Certificate;
    42 import java.util.ArrayList;
     42import java.util.List;
    4343
    4444/**
    45  * An interface that provides various details about a certificate
     45 * An interface that provides various details about certificates of an app.
    4646 */
    4747
     
    5959
    6060    /**
    61      * Return if there are signing issues with the certificate(s) being veried
     61     * Return if there are signing issues with the certificate being verified
    6262     */
    63     public boolean hasSigningIssues();
     63    public boolean hasSigningIssues(CertPath certPath);
    6464
    6565    /**
    66      * Return if there are no signing issues with this cert (!hasSigningIssues())
     66     * Get the details regarding issue with this certificate
    6767     */
    68     public boolean noSigningIssues();
     68    public List<String> getDetails(CertPath certPath);
    6969
    7070    /**
    71      * Get the details regarding issue(s) with this certificate
    72      */
    73     public ArrayList<String> getDetails();
    74 
    75     /**
    76      * Return a valid certificate path to this certificate(s) being verified
     71     * Return a valid certificate path to this certificate being verified
    7772     * @return The CertPath
    7873     */
    79     public CertPath getCertPath();
     74    public CertPath getCertPath(CertPath certPath);
    8075
    8176    /**
    8277     * Returns the application's publisher's certificate.
    8378     */
    84     public abstract Certificate getPublisher();
     79    public abstract Certificate getPublisher(CertPath certPath);
    8580
    8681    /**
    8782     * Returns the application's root's certificate. This
    88      * may return the same certificate as getPublisher() in
     83     * may return the same certificate as getPublisher(CertPath certPath) in
    8984     * the event that the application is self signed.
    9085     */
    91     public abstract Certificate getRoot();
    92 
     86    public abstract Certificate getRoot(CertPath certPath);
    9387}
  • trunk/icedtea-web/netx/net/sourceforge/jnlp/security/CertificateUtils.java

    r418 r429  
    4646import java.io.PrintStream;
    4747import java.math.BigInteger;
    48 import java.security.InvalidKeyException;
    4948import java.security.Key;
    5049import java.security.KeyStore;
    5150import java.security.KeyStoreException;
    52 import java.security.NoSuchAlgorithmException;
    53 import java.security.NoSuchProviderException;
    54 import java.security.SignatureException;
    5551import java.security.cert.Certificate;
    5652import java.security.cert.CertificateException;
     
    6056import java.util.Random;
    6157
    62 import net.sourceforge.jnlp.runtime.JNLPRuntime;
    6358import net.sourceforge.jnlp.runtime.Translator;
     59import net.sourceforge.jnlp.util.logging.OutputController;
    6460import net.sourceforge.jnlp.util.replacements.BASE64Encoder;
    6561import sun.security.provider.X509Factory;
     
    7874    public static final void addToKeyStore(File file, KeyStore ks) throws CertificateException,
    7975            IOException, KeyStoreException {
    80         if (JNLPRuntime.isDebug()) {
    81             System.out.println("Importing certificate from " + file + " into " + ks);
    82         }
     76
     77        OutputController.getLogger().log("Importing certificate from " + file + " into " + ks);
    8378
    8479        BufferedInputStream bis = new BufferedInputStream(new FileInputStream(file));
     
    10196    public static final void addToKeyStore(X509Certificate cert, KeyStore ks)
    10297            throws KeyStoreException {
    103         if (JNLPRuntime.isDebug()) {
    104             System.out.println("Importing " + cert.getSubjectX500Principal().getName());
    105         }
     98
     99        OutputController.getLogger().log("Importing " + cert.getSubjectX500Principal().getName());
    106100
    107101        String alias = null;
     
    174168
    175169                    if (c.equals(keyStores[i].getCertificate(alias))) {
    176                         if (JNLPRuntime.isDebug()) {
    177                             System.out.println(Translator.R("LCertFoundIn", c.getSubjectX500Principal().getName(), KeyStores.getPathToKeystore(keyStores[i].hashCode())));
    178                         }
    179 
     170                    OutputController.getLogger().log(Translator.R("LCertFoundIn", c.getSubjectX500Principal().getName(), KeyStores.getPathToKeystore(keyStores[i].hashCode())));
    180171                        return true;
    181172                    } // else continue
     
    183174
    184175            } catch (KeyStoreException e) {
    185                 e.printStackTrace();
     176                OutputController.getLogger().log(OutputController.Level.ERROR_ALL, e);
    186177                // continue
    187178            }
  • trunk/icedtea-web/netx/net/sourceforge/jnlp/security/HttpsCertVerifier.java

    r348 r429  
    5353import java.util.Collection;
    5454import java.util.List;
     55import net.sourceforge.jnlp.util.logging.OutputController;
    5556
    5657import sun.security.util.DerValue;
     
    6061public class HttpsCertVerifier implements CertVerifier {
    6162
    62     private VariableX509TrustManager tm;
    6363    private X509Certificate[] chain;
    6464    private String authType;
     
    6868    private ArrayList<String> details = new ArrayList<String>();
    6969
    70     public HttpsCertVerifier(VariableX509TrustManager tm,
    71                              X509Certificate[] chain, String authType,
     70    public HttpsCertVerifier(X509Certificate[] chain, String authType,
    7271                             boolean isTrusted, boolean hostMatched,
    7372                             String hostName) {
    74         this.tm = tm;
    7573        this.chain = chain;
    7674        this.authType = authType;
     
    8078    }
    8179
     80    @Override
    8281    public boolean getAlreadyTrustPublisher() {
    8382        return isTrusted;
    8483    }
    8584
    86     public CertPath getCertPath() {
     85
     86    /* XXX: Most of these methods have a CertPath param that should be passed
     87     * from the UI dialogs. However, this is not implemented yet so most of
     88     * the params are ignored.
     89     */
     90
     91    @Override
     92    public CertPath getCertPath(CertPath certPath) { // Parameter ignored.
    8793
    8894        ArrayList<X509Certificate> list = new ArrayList<X509Certificate>();
     
    95101            certPaths.add(CertificateFactory.getInstance("X.509").generateCertPath(list));
    96102        } catch (CertificateException ce) {
    97             ce.printStackTrace();
     103            OutputController.getLogger().log(OutputController.Level.ERROR_ALL, ce);
    98104
    99105            // carry on
     
    103109    }
    104110
    105     public ArrayList<String> getDetails() {
     111    @Override
     112    public List<String> getDetails(CertPath certPath) { // Parameter ignored.
    106113
    107114        boolean hasExpiredCert = false;
     
    183190
    184191        } catch (CertificateParsingException cpe) {
    185             cpe.printStackTrace();
     192            OutputController.getLogger().log(OutputController.Level.ERROR_ALL, cpe);
    186193        } catch (IOException ioe) {
    187             ioe.printStackTrace();
     194            OutputController.getLogger().log(OutputController.Level.ERROR_ALL, ioe);
    188195        }
    189196
     
    196203    }
    197204
    198     public Certificate getPublisher() {
     205    @Override
     206    public Certificate getPublisher(CertPath certPath) { // Paramater ignored.
    199207        if (chain.length > 0)
    200208            return (Certificate) chain[0];
     
    202210    }
    203211
    204     public Certificate getRoot() {
     212    @Override
     213    public Certificate getRoot(CertPath certPath) { // Parameter ignored.
    205214        if (chain.length > 0)
    206215            return (Certificate) chain[chain.length - 1];
     
    211220        try {
    212221            KeyStore[] caCertsKeyStores = KeyStores.getCAKeyStores();
    213             return CertificateUtils.inKeyStores((X509Certificate) getRoot(), caCertsKeyStores);
     222            return CertificateUtils.inKeyStores((X509Certificate) getRoot(null), caCertsKeyStores);
    214223        } catch (Exception e) {
    215224        }
     
    217226    }
    218227
    219     public boolean hasSigningIssues() {
     228    @Override
     229    public boolean hasSigningIssues(CertPath certPath) {
    220230        return false;
    221231    }
    222 
    223     public boolean noSigningIssues() {
    224         return false;
    225     }
    226 
    227232}
  • trunk/icedtea-web/netx/net/sourceforge/jnlp/security/KeyStores.java

    r418 r429  
    5656import net.sourceforge.jnlp.runtime.Translator;
    5757import net.sourceforge.jnlp.util.FileUtils;
     58import net.sourceforge.jnlp.util.logging.OutputController;
    5859
    5960/**
    60  * The <code>KeyStores</code> class allows easily accessing the various KeyStores
     61 * The {@code KeyStores} class allows easily accessing the various KeyStores
    6162 * used.
    6263 */
     
    8687    private static final String DEFAULT_PASSWORD = "changeit";
    8788
    88     public static final char[] getPassword() {
     89    public static char[] getPassword() {
    8990        return DEFAULT_PASSWORD.toCharArray();
    9091    }
     
    142143            keystoresPaths.put(ks.hashCode(),location);
    143144        } catch (Exception e) {
    144             e.printStackTrace();
     145            OutputController.getLogger().log(OutputController.Level.ERROR_ALL, e);
    145146        }
    146147        return ks;
  • trunk/icedtea-web/netx/net/sourceforge/jnlp/security/SecurityDialog.java

    r418 r429  
    3838package net.sourceforge.jnlp.security;
    3939
     40import java.awt.BorderLayout;
     41import java.awt.event.ActionListener;
     42import java.awt.event.WindowAdapter;
     43import java.awt.event.WindowEvent;
     44import java.security.cert.X509Certificate;
     45import java.util.List;
     46import java.util.concurrent.CopyOnWriteArrayList;
     47
     48import javax.swing.JDialog;
     49
    4050import net.sourceforge.jnlp.JNLPFile;
    41 import net.sourceforge.jnlp.runtime.JNLPRuntime;
     51import net.sourceforge.jnlp.runtime.JNLPClassLoader.SecurityDelegate;
    4252import net.sourceforge.jnlp.security.SecurityDialogs.AccessType;
    4353import net.sourceforge.jnlp.security.SecurityDialogs.DialogType;
     54import net.sourceforge.jnlp.security.dialogs.AccessWarningPane;
     55import net.sourceforge.jnlp.security.dialogs.AppletWarningPane;
     56import net.sourceforge.jnlp.security.dialogs.CertWarningPane;
     57import net.sourceforge.jnlp.security.dialogs.CertsInfoPane;
     58import net.sourceforge.jnlp.security.dialogs.MatchingALACAttributePanel;
     59import net.sourceforge.jnlp.security.dialogs.MissingALACAttributePanel;
     60import net.sourceforge.jnlp.security.dialogs.MissingPermissionsAttributePanel;
     61import net.sourceforge.jnlp.security.dialogs.MoreInfoPane;
     62import net.sourceforge.jnlp.security.dialogs.PasswordAuthenticationPane;
     63import net.sourceforge.jnlp.security.dialogs.SecurityDialogPanel;
     64import net.sourceforge.jnlp.security.dialogs.SingleCertInfoPane;
     65import net.sourceforge.jnlp.security.dialogs.apptrustwarningpanel.AppTrustWarningDialog;
    4466import net.sourceforge.jnlp.util.ImageResources;
    45 
    46 import java.awt.*;
    47 
    48 import javax.swing.*;
    49 
    50 import java.awt.event.*;
    51 import java.security.cert.X509Certificate;
    52 import java.util.concurrent.CopyOnWriteArrayList;
    53 
    54 import java.util.List;
     67import net.sourceforge.jnlp.util.ScreenFinder;
     68import net.sourceforge.jnlp.util.logging.OutputController;
    5569
    5670/**
     
    214228
    215229    private void initDialog() {
    216         setSystemLookAndFeel();
    217 
    218230        String dialogTitle = "";
    219231        if (dialogType == DialogType.CERT_WARNING) {
     
    230242        else if (dialogType == DialogType.APPLET_WARNING)
    231243            dialogTitle = "Applet Warning";
    232         else if (dialogType == DialogType.NOTALLSIGNED_WARNING)
     244        else if (dialogType == DialogType.PARTIALLYSIGNED_WARNING)
    233245            dialogTitle = "Security Warning";
    234246        else if (dialogType == DialogType.AUTHENTICATION)
     
    243255
    244256        pack();
     257        centerDialog(this);
    245258
    246259        WindowAdapter adapter = new WindowAdapter() {
     
    261274                    SecurityDialog dialog = (SecurityDialog) e.getSource();
    262275                    dialog.setResizable(true);
    263                     centerDialog(dialog);
    264276                    dialog.setValue(null);
    265277                }
     
    268280        addWindowListener(adapter);
    269281        addWindowFocusListener(adapter);
    270 
    271282    }
    272283
     
    293304
    294305        if (dialogType == DialogType.CERT_WARNING)
    295             panel = new CertWarningPane(this, this.certVerifier);
     306            panel = new CertWarningPane(this, this.certVerifier, (SecurityDelegate) extras[0]);
    296307        else if (dialogType == DialogType.MORE_INFO)
    297308            panel = new MoreInfoPane(this, this.certVerifier);
     
    304315        else if (dialogType == DialogType.APPLET_WARNING)
    305316            panel = new AppletWarningPane(this, this.certVerifier);
    306         else if (dialogType == DialogType.NOTALLSIGNED_WARNING)
    307             panel = new NotAllSignedWarningPane(this);
     317        else if (dialogType == DialogType.PARTIALLYSIGNED_WARNING)
     318            panel = AppTrustWarningDialog.partiallySigned(this, file, (SecurityDelegate) extras[0]);
     319        else if (dialogType == DialogType.UNSIGNED_WARNING) // Only necessary for applets on 'high security' or above
     320            panel = AppTrustWarningDialog.unsigned(this, file);
    308321        else if (dialogType == DialogType.AUTHENTICATION)
    309322            panel = new PasswordAuthenticationPane(this, extras);
     323        else if (dialogType == DialogType.UNSIGNED_EAS_NO_PERMISSIONS_WARNING)
     324            panel = new MissingPermissionsAttributePanel(this, (String) extras[0], (String) extras[1]);
     325        else if (dialogType == DialogType.MISSING_ALACA)
     326            panel = new MissingALACAttributePanel(this, (String) extras[0], (String) extras[1], (String) extras[2]);
     327        else if (dialogType == DialogType.MATCHING_ALACA)
     328            panel = new MatchingALACAttributePanel(this, (String) extras[0], (String) extras[1], (String) extras[2]);
    310329
    311330        add(panel, BorderLayout.CENTER);
     
    313332
    314333    private static void centerDialog(JDialog dialog) {
    315         Dimension screen = Toolkit.getDefaultToolkit().getScreenSize();
    316         Dimension dialogSize = dialog.getSize();
    317 
    318         dialog.setLocation((screen.width - dialogSize.width) / 2,
    319                         (screen.height - dialogSize.height) / 2);
     334        ScreenFinder.centerWindowsToCurrentScreen(dialog);
    320335    }
    321336
    322337    private void selectDefaultButton() {
    323338        if (panel == null) {
    324             System.out.println("initial value panel is null");
     339            OutputController.getLogger().log(OutputController.Level.MESSAGE_ALL, "initial value panel is null");
    325340        }
    326341        panel.requestFocusOnDefaultButton();
    327342    }
    328343
    329     protected void setValue(Object value) {
    330         if (JNLPRuntime.isDebug()) {
    331             System.out.println("Setting value:" + value);
    332         }
     344    public void setValue(Object value) {
     345        OutputController.getLogger().log("Setting value:" + value);
    333346        this.value = value;
    334347    }
    335348
    336349    public Object getValue() {
    337         if (JNLPRuntime.isDebug()) {
    338             System.out.println("Returning value:" + value);
    339         }
     350        OutputController.getLogger().log("Returning value:" + value);
    340351        return value;
    341352    }
     
    351362    }
    352363
    353     /**
    354      * Updates the look and feel of the window to be the system look and feel
    355      */
    356     protected void setSystemLookAndFeel() {
    357         try {
    358             UIManager.setLookAndFeel(UIManager.getSystemLookAndFeelClassName());
    359         } catch (Exception e) {
    360             //don't worry if we can't.
    361         }
    362     }
    363 
    364364    private final List<ActionListener> listeners = new CopyOnWriteArrayList<ActionListener>();
    365365
  • trunk/icedtea-web/netx/net/sourceforge/jnlp/security/SecurityDialogMessage.java

    r348 r429  
     1/* SecurityDialogMessage.java
     2   Copyright (C) 2011 Red Hat, Inc.
     3
     4This file is part of IcedTea.
     5
     6IcedTea is free software; you can redistribute it and/or
     7modify it under the terms of the GNU General Public License as published by
     8the Free Software Foundation, version 2.
     9
     10IcedTea is distributed in the hope that it will be useful,
     11but WITHOUT ANY WARRANTY; without even the implied warranty of
     12MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
     13General Public License for more details.
     14
     15You should have received a copy of the GNU General Public License
     16along with IcedTea; see the file COPYING.  If not, write to
     17the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
     1802110-1301 USA.
     19
     20Linking this library statically or dynamically with other modules is
     21making a combined work based on this library.  Thus, the terms and
     22conditions of the GNU General Public License cover the whole
     23combination.
     24
     25As a special exception, the copyright holders of this library give you
     26permission to link this library with independent modules to produce an
     27executable, regardless of the license terms of these independent
     28modules, and to copy and distribute the resulting executable under
     29terms of your choice, provided that you also meet, for each linked
     30independent module, the terms and conditions of the license of that
     31module.  An independent module is a module which is not derived from
     32or based on this library.  If you modify this library, you may extend
     33this exception to your version of the library, but you are not
     34obligated to do so.  If you do not wish to do so, delete this
     35exception statement from your version.
     36 */
     37
    138package net.sourceforge.jnlp.security;
    239
  • trunk/icedtea-web/netx/net/sourceforge/jnlp/security/SecurityDialogMessageHandler.java

    r348 r429  
    4545import sun.awt.AppContext;
    4646
    47 import net.sourceforge.jnlp.runtime.JNLPRuntime;
     47import net.sourceforge.jnlp.util.logging.OutputController;
    4848
    4949/**
     
    5656 * their Look and Feel is not affected by the Look and Feel of the
    5757 * applet/application.
     58 * </p>
    5859 * <p>
    5960 * This class contains allows a client application to post a
     
    6162 * the queue, it shows a security warning to the user, and sets
    6263 * {@link SecurityDialogMessage#userResponse} to the appropriate value.
     64 * </p>
    6365 */
    6466public final class SecurityDialogMessageHandler implements Runnable {
     
    7375    @Override
    7476    public void run() {
    75         if (JNLPRuntime.isDebug()) {
    76             System.out.println("Starting security dialog thread");
    77         }
     77        OutputController.getLogger().log("Starting security dialog thread");
    7878        while (true) {
    7979            try {
     
    9292     * {@link SecurityDialogMessage#toDispose} (if not null) is disposed and
    9393     * {@link SecurityDialogMessage#lock} (in not null) is released.
     94     * </p>
    9495     *
    9596     * @param message the message indicating what type of security dialog to
     
    128129     * {@link SecurityDialogMessage#toDispose} (if not null) is disposed and
    129130     * {@link SecurityDialogMessage#lock} (in not null) is released.
     131     * </p>
    130132     *
    131133     * @param message indicates the type of security dialog to show
     
    135137            queue.put(message);
    136138        } catch (InterruptedException e) {
    137             e.printStackTrace();
     139            OutputController.getLogger().log(OutputController.Level.ERROR_ALL, e);
    138140        }
    139141    }
  • trunk/icedtea-web/netx/net/sourceforge/jnlp/security/SecurityDialogs.java

    r418 r429  
    4242import java.awt.event.WindowEvent;
    4343import java.net.NetPermission;
     44import java.net.URL;
    4445import java.security.AccessController;
    4546import java.security.PrivilegedAction;
     47import java.util.Set;
    4648import java.util.concurrent.Semaphore;
    4749
     
    5153import net.sourceforge.jnlp.JNLPFile;
    5254import net.sourceforge.jnlp.config.DeploymentConfiguration;
     55import net.sourceforge.jnlp.runtime.JNLPClassLoader.SecurityDelegate;
    5356import net.sourceforge.jnlp.runtime.JNLPRuntime;
     57import net.sourceforge.jnlp.security.appletextendedsecurity.ExecuteAppletAction;
     58import net.sourceforge.jnlp.security.dialogs.apptrustwarningpanel.AppTrustWarningPanel.AppSigningWarningAction;
     59import net.sourceforge.jnlp.util.UrlUtils;
    5460
    5561/**
    56  * A factory for showing many possible types of security warning to the user.<p>
    57  *
     62 * <p>
     63 * A factory for showing many possible types of security warning to the user.
     64 * </p>
     65 * <p>
    5866 * This contains all the public methods that classes outside this package should
    5967 * use instead of using {@link SecurityDialog} directly.
    60  *
     68 * </p>
     69 * <p>
    6170 * All of these methods post a message to the
    6271 * {@link SecurityDialogMessageHandler} and block waiting for a response.
     72 * </p>
    6373 */
    6474public class SecurityDialogs {
     
    7080        SINGLE_CERT_INFO,
    7181        ACCESS_WARNING,
    72         NOTALLSIGNED_WARNING,
     82        PARTIALLYSIGNED_WARNING,
     83        UNSIGNED_WARNING,   /* requires confirmation with 'high-security' setting */
    7384        APPLET_WARNING,
    7485        AUTHENTICATION,
     86        UNSIGNED_EAS_NO_PERMISSIONS_WARNING,   /* when Extended applet security is at High Security and no permission attribute is find, */
     87        MISSING_ALACA, /*alaca - Application-Library-Allowable-Codebase Attribute*/
     88        MATCHING_ALACA
    7589    }
    7690
     
    86100        VERIFIED,
    87101        UNVERIFIED,
    88         NOTALLSIGNED,
     102        PARTIALLYSIGNED,
     103        UNSIGNED,           /* requires confirmation with 'high-security' setting */
    89104        SIGNING_ERROR
     105    }
     106
     107    public static enum AppletAction {
     108        RUN,
     109        SANDBOX,
     110        CANCEL;
     111        public static AppletAction fromInteger(int i) {
     112            switch (i) {
     113                case 0:
     114                    return RUN;
     115                case 1:
     116                    return SANDBOX;
     117                case 2:
     118                    return CANCEL;
     119                default:
     120                    return CANCEL;
     121            }
     122        }
    90123    }
    91124
     
    128161        Object selectedValue = getUserResponse(message);
    129162
    130         if (selectedValue == null) {
    131             return false;
    132         } else if (selectedValue instanceof Integer) {
    133             if (((Integer) selectedValue).intValue() == 0)
    134                 return true;
    135             else
    136                 return false;
    137         } else {
    138             return false;
    139         }
    140     }
    141 
    142     /**
    143      * Shows a warning dialog for when the main application jars are signed,
    144      * but extensions aren't
     163        return getIntegerResponseAsBoolean(selectedValue);
     164    }
     165
     166    /**
     167     * Shows a warning dialog for when a plugin applet is unsigned.
     168     * This is used with 'high-security' setting.
    145169     *
    146170     * @return true if permission was granted by the user, false otherwise.
    147171     */
    148     public static boolean showNotAllSignedWarningDialog(JNLPFile file) {
    149 
    150         if (!shouldPromptUser()) {
    151             return false;
     172    public static AppSigningWarningAction showUnsignedWarningDialog(JNLPFile file) {
     173
     174        if (!shouldPromptUser()) {
     175            return new AppSigningWarningAction(ExecuteAppletAction.NO, false);
    152176        }
    153177
    154178        final SecurityDialogMessage message = new SecurityDialogMessage();
    155         message.dialogType = DialogType.NOTALLSIGNED_WARNING;
    156         message.accessType = AccessType.NOTALLSIGNED;
     179        message.dialogType = DialogType.UNSIGNED_WARNING;
     180        message.accessType = AccessType.UNSIGNED;
    157181        message.file = file;
    158         message.extras = new Object[0];
    159 
    160         Object selectedValue = getUserResponse(message);
    161 
    162         if (selectedValue == null) {
    163             return false;
    164         } else if (selectedValue instanceof Integer) {
    165             if (((Integer) selectedValue).intValue() == 0) {
    166                 return true;
    167             } else {
    168                 return false;
    169             }
    170         } else {
    171             return false;
    172         }
     182
     183        return (AppSigningWarningAction) getUserResponse(message);
    173184    }
    174185
    175186    /**
    176187     * Shows a security warning dialog according to the specified type of
    177      * access. If <code>type</code> is one of AccessType.VERIFIED or
    178      * AccessType.UNVERIFIED, extra details will be available with regards
    179      * to code signing and signing certificates.
     188     * access. If {@code accessType} is one of {@link AccessType#VERIFIED} or
     189     * {@link AccessType#UNVERIFIED}, extra details will be available with
     190     * regards to code signing and signing certificates.
    180191     *
    181192     * @param accessType the type of warning dialog to show
     
    183194     * @param certVerifier the JarCertVerifier used to verify this application
    184195     *
    185      * @return true if the user accepted the certificate
    186      */
    187     public static boolean showCertWarningDialog(AccessType accessType,
    188             JNLPFile file, CertVerifier certVerifier) {
    189 
    190         if (!shouldPromptUser()) {
    191             return false;
     196     * @return RUN if the user accepted the certificate, SANDBOX if the user
     197     * wants the applet to run with only sandbox permissions, or CANCEL if the
     198     * user did not accept running the applet
     199     */
     200    public static AppletAction showCertWarningDialog(AccessType accessType,
     201            JNLPFile file, CertVerifier certVerifier, SecurityDelegate securityDelegate) {
     202
     203        if (!shouldPromptUser()) {
     204            return AppletAction.CANCEL;
    192205        }
    193206
     
    197210        message.file = file;
    198211        message.certVerifier = certVerifier;
     212        message.extras = new Object[] { securityDelegate };
    199213
    200214        Object selectedValue = getUserResponse(message);
    201215
    202         if (selectedValue == null) {
    203             return false;
    204         } else if (selectedValue instanceof Integer) {
    205             if (((Integer) selectedValue).intValue() == 0)
    206                 return true;
    207             else
    208                 return false;
    209         } else {
    210             return false;
    211         }
     216        return getIntegerResponseAsAppletAction(selectedValue);
     217    }
     218
     219    /**
     220     * Shows a warning dialog for when an applet or application is partially signed.
     221     *
     222     * @return true if permission was granted by the user, false otherwise.
     223     */
     224    public static AppSigningWarningAction showPartiallySignedWarningDialog(JNLPFile file, CertVerifier certVerifier,
     225            SecurityDelegate securityDelegate) {
     226
     227        if (!shouldPromptUser()) {
     228            return new AppSigningWarningAction(ExecuteAppletAction.NO, false);
     229        }
     230
     231        final SecurityDialogMessage message = new SecurityDialogMessage();
     232        message.dialogType = DialogType.PARTIALLYSIGNED_WARNING;
     233        message.accessType = AccessType.PARTIALLYSIGNED;
     234        message.file = file;
     235        message.certVerifier = certVerifier;
     236        message.extras = new Object[] { securityDelegate };
     237
     238        return (AppSigningWarningAction) getUserResponse(message);
    212239    }
    213240
     
    239266
    240267        Object response = getUserResponse(message);
    241         if (response == null) {
    242             return null;
    243         } else {
    244             return (Object[]) response;
    245         }
    246     }
    247 
     268        return (Object[]) response;
     269    }
     270
     271     public static boolean  showMissingALACAttributePanel(String title, URL codeBase, Set<URL> remoteUrls) {
     272
     273        if (!shouldPromptUser()) {
     274            return false;
     275        }
     276
     277        SecurityDialogMessage message = new SecurityDialogMessage();
     278        message.dialogType = DialogType.MISSING_ALACA;
     279        message.extras = new Object[]{title, codeBase.toString(), UrlUtils.setOfUrlsToHtmlList(remoteUrls)};
     280        Object selectedValue = getUserResponse(message);
     281        return getIntegerResponseAsBoolean(selectedValue);
     282    }
     283     
     284     public static boolean showMatchingALACAttributePanel(String title, URL codeBase, Set<URL> remoteUrls) {
     285
     286        if (!shouldPromptUser()) {
     287            return false;
     288        }
     289
     290        SecurityDialogMessage message = new SecurityDialogMessage();
     291        message.dialogType = DialogType.MATCHING_ALACA;
     292        message.extras = new Object[]{title, codeBase.toString(), UrlUtils.setOfUrlsToHtmlList(remoteUrls)};
     293        Object selectedValue = getUserResponse(message);
     294        return getIntegerResponseAsBoolean(selectedValue);
     295    }
     296     
    248297    /**
    249298     * FIXME This is unused. Remove it?
    250      * @return (0, 1, 2) => (Yes, No, Cancel)
     299     * @return (0, 1, 2) =&gt; (Yes, No, Cancel)
    251300     */
    252301    public static int showAppletWarning() {
     
    262311
    263312        // result 0 = Yes, 1 = No, 2 = Cancel
    264         if (selectedValue == null) {
    265             return 2;
    266         } else if (selectedValue instanceof Integer) {
     313        if (selectedValue instanceof Integer) {
     314            // If the selected value can be cast to Integer, use that value
    267315            return ((Integer) selectedValue).intValue();
    268316        } else {
     317            // Otherwise default to "cancel"
    269318            return 2;
    270319        }
    271320    }
    272321
     322     public static boolean showMissingPermissionsAttributeDialogue(String title, URL codeBase) {
     323
     324         if (!shouldPromptUser()) {
     325             return false;
     326         }
     327
     328         SecurityDialogMessage message = new SecurityDialogMessage();
     329         message.dialogType = DialogType.UNSIGNED_EAS_NO_PERMISSIONS_WARNING;
     330         message.extras = new Object[]{title, codeBase.toExternalForm()};
     331         Object selectedValue = getUserResponse(message);
     332         return SecurityDialogs.getIntegerResponseAsBoolean(selectedValue);
     333    }
    273334    /**
    274335     * Posts the message to the SecurityThread and gets the response. Blocks
     
    352413
    353414    /**
     415     * Returns true iff the given Object reference can be cast to Integer and that Integer's
     416     * intValue is 0.
     417     * @param ref the Integer (hopefully) reference
     418     * @return whether the given reference is both an Integer type and has intValue of 0
     419     */
     420    public static boolean getIntegerResponseAsBoolean(Object ref) {
     421        boolean isInteger = ref instanceof Integer;
     422        if (isInteger) {
     423            Integer i = (Integer) ref;
     424            return i.intValue() == 0;
     425        }
     426        return false;
     427    }
     428
     429    public static AppletAction getIntegerResponseAsAppletAction(Object ref) {
     430        if (ref instanceof Integer) {
     431            return AppletAction.fromInteger((Integer) ref);
     432        }
     433        return AppletAction.CANCEL;
     434    }
     435
     436    /**
    354437     * Returns whether the current runtime configuration allows prompting user
    355438     * for security warnings.
     
    366449        });
    367450    }
    368 
     451   
    369452}
  • trunk/icedtea-web/netx/net/sourceforge/jnlp/security/SecurityUtil.java

    r348 r429  
    4545import net.sourceforge.jnlp.security.KeyStores.Level;
    4646import net.sourceforge.jnlp.security.KeyStores.Type;
     47import net.sourceforge.jnlp.util.logging.OutputController;
    4748
    4849public class SecurityUtil {
     
    211212                }
    212213            } catch (Exception e) {
    213                 e.printStackTrace();
     214                OutputController.getLogger().log(OutputController.Level.ERROR_ALL, e);
    214215                throw e;
    215216            } finally {
  • trunk/icedtea-web/netx/net/sourceforge/jnlp/security/VariableX509TrustManager.java

    r418 r429  
    3838package net.sourceforge.jnlp.security;
    3939
     40import java.lang.reflect.InvocationTargetException;
     41import java.lang.reflect.Method;
     42import java.net.Socket;
    4043import java.security.AccessController;
    4144import java.security.KeyStore;
     
    4851import java.util.List;
    4952
     53import javax.net.ssl.SSLEngine;
     54import javax.net.ssl.SSLSocket;
    5055import javax.net.ssl.TrustManager;
    5156import javax.net.ssl.TrustManagerFactory;
    5257import javax.net.ssl.X509TrustManager;
    5358
     59import net.sourceforge.jnlp.runtime.JNLPRuntime;
     60import net.sourceforge.jnlp.security.SecurityDialogs.AccessType;
     61import net.sourceforge.jnlp.security.SecurityDialogs.AppletAction;
     62import net.sourceforge.jnlp.util.logging.OutputController;
    5463import sun.security.util.HostnameChecker;
    5564import sun.security.validator.ValidatorException;
    56 
    57 import com.sun.net.ssl.internal.ssl.X509ExtendedTrustManager;
    58 import net.sourceforge.jnlp.runtime.JNLPRuntime;
    59 
    60 import net.sourceforge.jnlp.security.SecurityDialogs.AccessType;
    6165
    6266/**
     
    6670 */
    6771
    68 final public class VariableX509TrustManager extends X509ExtendedTrustManager {
     72final public class VariableX509TrustManager {
    6973
    7074    /** TrustManagers containing trusted CAs */
     
    109113            }
    110114        } catch (Exception e) {
    111             e.printStackTrace();
     115            OutputController.getLogger().log(OutputController.Level.ERROR_ALL, e);
    112116        }
    113117
     
    134138            }
    135139        } catch (Exception e) {
    136             e.printStackTrace();
     140            OutputController.getLogger().log(OutputController.Level.ERROR_ALL, e);
    137141        }
    138142
     
    158162            }
    159163        } catch (Exception e) {
    160             e.printStackTrace();
     164            OutputController.getLogger().log(OutputController.Level.ERROR_ALL, e);
    161165        }
    162166    }
     
    165169     * Check if client is trusted (no support for custom here, only system/user)
    166170     */
    167     public void checkClientTrusted(X509Certificate[] chain, String authType,
    168                                    String hostName, String algorithm)
     171    public void checkTrustClient(X509Certificate[] chain, String authType,
     172                                   String hostName)
    169173            throws CertificateException {
    170174
     
    187191    }
    188192
    189     public void checkClientTrusted(X509Certificate[] chain, String authType)
    190             throws CertificateException {
    191         checkClientTrusted(chain, authType, null, null);
    192     }
    193 
    194     public void checkServerTrusted(X509Certificate[] chain, String authType,
    195                                    String hostName, String algorithm)
    196             throws CertificateException {
    197         checkServerTrusted(chain, authType, hostName, false);
    198     }
    199 
    200     public void checkServerTrusted(X509Certificate[] chain, String authType)
    201             throws CertificateException {
    202         checkServerTrusted(chain, authType, null, null);
    203     }
    204 
    205     /**
    206      * Check if the server is trusted
     193    /**
     194     * Check if the server is trusted.
     195     *
     196     * First, existing stores are checked to see if the certificate is trusted.
     197     * Next, if the certificate is not explicitly trusted by the user, a host
     198     * name check is performed. The user is them prompted as needed.
    207199     *
    208200     * @param chain The cert chain
    209201     * @param authType The auth type algorithm
    210      * @param checkOnly Whether to "check only" i.e. no user prompt, or to prompt for permission
    211      */
    212     public synchronized void checkServerTrusted(X509Certificate[] chain,
     202     * @param hostName The expected hostName that the server should have
     203     * @param socket The SSLSocket in use (may be null)
     204     * @param engine The SSLEngine in use (may be null)
     205     */
     206    public synchronized void checkTrustServer(X509Certificate[] chain,
    213207                             String authType, String hostName,
    214                              boolean checkOnly) throws CertificateException {
     208                             SSLSocket socket, SSLEngine engine) throws CertificateException {
    215209        CertificateException ce = null;
    216210        boolean trusted = true;
    217         boolean CNMatched = true;
    218 
     211        boolean CNMatched = false;
     212
     213        // Check trust stores
    219214        try {
    220             checkAllManagers(chain, authType);
     215            checkAllManagers(chain, authType, socket, engine);
    221216        } catch (CertificateException e) {
    222217            trusted = false;
     
    225220
    226221        // If the certificate is not explicitly trusted, we
    227         // need to prompt the user
     222        // check host match
    228223        if (!isExplicitlyTrusted(chain, authType)) {
    229 
    230             if (hostName == null) {
    231                 CNMatched = false;
    232             } else {
     224            if (hostName != null) {
    233225                try {
    234226                    HostnameChecker checker = HostnameChecker
    235227                            .getInstance(HostnameChecker.TYPE_TLS);
    236228
    237                     checker.match(hostName, chain[0]); // only need to match @ 0 for
    238                                                        // CN
    239 
     229                    checker.match(hostName, chain[0]); // only need to match @ 0 for CN
     230
     231                    CNMatched = true;
    240232                } catch (CertificateException e) {
    241                     CNMatched = false;
    242233                    ce = e;
    243234                }
    244235            }
    245         }
    246 
     236        } else {
     237            // If it is explicitly trusted, just return right away.
     238            return;
     239        }
     240
     241        // If it is (not explicitly trusted) AND
     242        // ((it is not in store) OR (there is a host mismatch))
    247243        if (!trusted || !CNMatched) {
    248             if (checkOnly) {
    249                 throw ce;
    250             } else {
    251                 if (!isTemporarilyUntrusted(chain[0])) {
    252                     boolean b = askUser(chain, authType, trusted, CNMatched, hostName);
    253 
    254                     if (b) {
    255                         temporarilyTrust(chain[0]);
    256                     } else {
    257                         temporarilyUntrust(chain[0]);
    258                     }
    259                 }
    260 
    261                 checkAllManagers(chain, authType);
    262             }
    263         }
    264     }
    265 
    266     /**
    267      * Check system, user and custom trust manager
    268      */
    269     private void checkAllManagers(X509Certificate[] chain, String authType) throws CertificateException {
     244            if (!isTemporarilyUntrusted(chain[0])) {
     245                boolean b = askUser(chain, authType, trusted, CNMatched, hostName);
     246
     247                if (b) {
     248                    temporarilyTrust(chain[0]);
     249                    return;
     250                } else {
     251                    temporarilyUntrust(chain[0]);
     252                }
     253            }
     254
     255            throw ce;
     256        }
     257    }
     258
     259    /**
     260     * Check system, user and custom trust manager.
     261     *
     262     * This method is intended to work with both, JRE6 and JRE7. If socket
     263     * and engine are null, it assumes that the call is for JRE6 (i.e. not
     264     * javax.net.ssl.X509ExtendedTrustManager which is Java 7 specific). If
     265     * either of those are not null, it will assume that the caTrustManagers
     266     * are javax.net.ssl.X509ExtendedTrustManager instances and will
     267     * invoke their check methods.
     268     *
     269     * @param chain The certificate chain
     270     * @param authType The authentication type
     271     * @param socket the SSLSocket being used for the connection
     272     * @param engine the SSLEngine being used for the connection
     273     */
     274    private void checkAllManagers(X509Certificate[] chain, String authType, Socket socket, SSLEngine engine) throws CertificateException {
     275
    270276        // first try CA TrustManagers
    271277        boolean trusted = false;
     
    273279        for (int i = 0; i < caTrustManagers.length; i++) {
    274280            try {
    275                 caTrustManagers[i].checkServerTrusted(chain, authType);
     281                if (socket == null && engine == null) {
     282                    caTrustManagers[i].checkServerTrusted(chain, authType);
     283                } else {
     284
     285                    try {
     286                        Class<?> x509ETMClass = Class.forName("javax.net.ssl.X509ExtendedTrustManager");
     287                        if (engine == null) {
     288                            Method mcheckServerTrusted = x509ETMClass.getDeclaredMethod("checkServerTrusted", X509Certificate[].class, String.class, Socket.class);
     289                            mcheckServerTrusted.invoke(caTrustManagers[i], chain, authType, socket);
     290                        } else {
     291                            Method mcheckServerTrusted = x509ETMClass.getDeclaredMethod("checkServerTrusted", X509Certificate[].class, String.class, SSLEngine.class);
     292                            mcheckServerTrusted.invoke(caTrustManagers[i], chain, authType, engine);
     293                        }
     294                    } catch (NoSuchMethodException nsme) {
     295                        throw new ValidatorException(nsme.getMessage());
     296                    } catch (InvocationTargetException ite) {
     297                        throw new ValidatorException(ite.getMessage());
     298                    } catch (IllegalAccessException iae) {
     299                        throw new ValidatorException(iae.getMessage());
     300                    } catch (ClassNotFoundException cnfe) {
     301                        throw new ValidatorException(cnfe.getMessage());
     302                    }
     303                }
     304
    276305                trusted = true;
    277306                break;
     
    280309            }
    281310        }
     311
    282312        if (trusted) {
    283313            return;
     
    301331        if (!temporarilyTrusted.contains(chain[0])) {
    302332            if (savedException == null) {
    303                 // System.out.println("IMPOSSIBLE!");
     333                // OutputController.getLogger().log(OutputController.Level.MESSAGE_ALL, "IMPOSSIBLE!");
    304334                throw new ValidatorException(ValidatorException.T_SIGNATURE_ERROR, chain[0]);
    305335            }
     
    333363    }
    334364
    335     public X509Certificate[] getAcceptedIssuers() {
     365    protected X509Certificate[] getAcceptedIssuers() {
    336366        List<X509Certificate> issuers = new ArrayList<X509Certificate>();
    337367
     
    389419            return true;
    390420        }
    391         final VariableX509TrustManager trustManager = this;
    392421        return AccessController.doPrivileged(new PrivilegedAction<Boolean>() {
    393422            @Override
     
    395424                return SecurityDialogs.showCertWarningDialog(
    396425                        AccessType.UNVERIFIED, null,
    397                         new HttpsCertVerifier(trustManager, chain, authType,
     426                        new HttpsCertVerifier(chain, authType,
    398427                                              isTrusted, hostMatched,
    399                                               hostName));
     428                                hostName), null) == AppletAction.RUN;
    400429            }
    401430        });
  • trunk/icedtea-web/netx/net/sourceforge/jnlp/security/viewer/CertificatePane.java

    r418 r429  
    8181import net.sourceforge.jnlp.security.KeyStores.Level;
    8282import net.sourceforge.jnlp.util.FileUtils;
     83import net.sourceforge.jnlp.util.logging.OutputController;
    8384
    8485public class CertificatePane extends JPanel {
     
    151152            keyStore = KeyStores.getKeyStore(currentKeyStoreLevel, currentKeyStoreType);
    152153        } catch (Exception e) {
    153             e.printStackTrace();
     154            OutputController.getLogger().log(OutputController.Level.ERROR_ALL, e);
    154155        }
    155156    }
    156157
    157158    //create the GUI here.
    158     protected void addComponents() {
     159    private void addComponents() {
    159160
    160161        JPanel main = new JPanel(new BorderLayout());
     
    264265            while (aliases.hasMoreElements()) {
    265266                Certificate c = keyStore.getCertificate(aliases.nextElement());
    266                 if (c instanceof X509Certificate)
     267                if (c instanceof X509Certificate) {
    267268                    certs.add((X509Certificate) c);
     269                }
    268270            }
    269271
     
    279281        } catch (Exception e) {
    280282            //TODO
    281             e.printStackTrace();
     283           OutputController.getLogger().log(OutputController.Level.ERROR_ALL, e);
    282284        }
    283285    }
     
    310312                                JOptionPane.OK_CANCEL_OPTION,
    311313                                JOptionPane.INFORMATION_MESSAGE);
    312         if (result == JOptionPane.OK_OPTION)
     314        if (result == JOptionPane.OK_OPTION) {
    313315            return jpf.getPassword();
    314         else
     316        }
     317        else {
    315318            return null;
     319        }
    316320    }
    317321
     
    328332        }
    329333
     334        @Override
    330335        public String toString() {
    331336            return KeyStores.toDisplayableString(null, type);
     
    336341    private class CertificateTypeListener implements ActionListener {
    337342        @Override
     343        @SuppressWarnings("unchecked")//this is just certificateTypeCombo, nothing else
    338344        public void actionPerformed(ActionEvent e) {
    339345            JComboBox source = (JComboBox) e.getSource();
     
    372378
    373379    private class ImportButtonListener implements ActionListener {
     380        @Override
    374381        public void actionPerformed(ActionEvent e) {
    375382
     
    405412                } catch (Exception ex) {
    406413                    // TODO: handle exception
    407                     ex.printStackTrace();
     414                    OutputController.getLogger().log(OutputController.Level.ERROR_ALL, ex);
    408415                }
    409416            }
     
    412419
    413420    private class ExportButtonListener implements ActionListener {
     421        @Override
    414422        public void actionPerformed(ActionEvent e) {
    415423
    416             JTable table = null;
     424            final JTable table ;
    417425            if (currentKeyStoreLevel == Level.USER) {
    418426                table = userTable;
     
    435443                            if (currentKeyStoreType == KeyStores.Type.CLIENT_CERTS) {
    436444                                char[] password = getPassword(R("CVExportPasswordMessage"));
    437                                 if (password != null)
     445                                if (password != null) {
    438446                                    CertificateUtils.dumpPKCS12(alias, chooser.getSelectedFile(), keyStore, password);
     447                                }
    439448                            } else {
    440449                                Certificate c = keyStore.getCertificate(alias);
     
    447456                }
    448457            } catch (Exception ex) {
    449                 // TODO
    450                 ex.printStackTrace();
     458                OutputController.getLogger().log(OutputController.Level.ERROR_ALL, ex);
    451459            }
    452460        }
     
    458466         * Removes a certificate from the keyStore and writes changes to disk.
    459467         */
     468        @Override
    460469        public void actionPerformed(ActionEvent e) {
    461470
    462             JTable table = null;
     471            final JTable table;
    463472            if (currentKeyStoreLevel == Level.USER) {
    464473                table = userTable;
     
    492501                }
    493502            } catch (Exception ex) {
    494                 // TODO
    495                 ex.printStackTrace();
     503                OutputController.getLogger().log(OutputController.Level.ERROR_ALL, ex);
    496504            }
    497505
     
    504512         * Shows the details of a trusted certificate.
    505513         */
     514        @Override
    506515        public void actionPerformed(ActionEvent e) {
    507516
    508             JTable table = null;
     517            final JTable table;
    509518            if (currentKeyStoreLevel == Level.USER) {
    510519                table = userTable;
  • trunk/icedtea-web/netx/net/sourceforge/jnlp/security/viewer/CertificateViewer.java

    r418 r429  
    5353import net.sourceforge.jnlp.runtime.JNLPRuntime;
    5454import net.sourceforge.jnlp.util.ImageResources;
     55import net.sourceforge.jnlp.util.ScreenFinder;
    5556
    5657public class CertificateViewer extends JDialog {
     
    9596
    9697    private void centerDialog() {
    97         Dimension screen = Toolkit.getDefaultToolkit().getScreenSize();
    98         Dimension dialogSize = getSize();
    99 
    100         setLocation((screen.width - dialogSize.width) / 2,
    101                         (screen.height - dialogSize.height) / 2);
     98        ScreenFinder.centerWindowsToCurrentScreen(this);
    10299    }
    103100
    104101    public static void showCertificateViewer() throws Exception {
    105102        JNLPRuntime.initialize(true);
    106         setSystemLookAndFeel();
    107103
    108104        CertificateViewer cv = new CertificateViewer();
     
    113109    }
    114110
    115     private static void setSystemLookAndFeel() {
    116         try {
    117             UIManager.setLookAndFeel(UIManager.getSystemLookAndFeelClassName());
    118         } catch (Exception e) {
    119             // don't worry if we can't.
    120         }
    121     }
    122 
    123111    public static void main(String[] args) throws Exception {
    124112        CertificateViewer.showCertificateViewer();
  • trunk/icedtea-web/netx/net/sourceforge/jnlp/services/ServiceUtil.java

    r418 r429  
    4343import net.sourceforge.jnlp.security.SecurityDialogs;
    4444import net.sourceforge.jnlp.security.SecurityDialogs.AccessType;
     45import net.sourceforge.jnlp.util.logging.OutputController;
    4546
    4647/**
    4748 * Provides static methods to interact useful for using the JNLP
    48  * services.<p>
     49 * services.
    4950 *
    5051 * @author <a href="mailto:jmaxwell@users.sourceforge.net">Jon A. Maxwell (JAM)</a> - initial author
     
    155156     * perform.
    156157     */
    157     static Object createPrivilegedProxy(Class iface, final Object receiver) {
     158    static Object createPrivilegedProxy(Class<?> iface, final Object receiver) {
    158159        return java.lang.reflect.Proxy.newProxyInstance(XServiceManagerStub.class.getClassLoader(),
    159                 new Class[] { iface },
     160                new Class<?>[] { iface },
    160161                new PrivilegedHandler(receiver));
    161162    }
     
    171172        }
    172173
     174        @Override
    173175        public Object invoke(Object proxy, final Method method, final Object[] args) throws Throwable {
    174176            if (JNLPRuntime.isDebug()) {
    175                 System.err.println("call privileged method: " + method.getName());
    176                 if (args != null)
    177                     for (int i = 0; i < args.length; i++)
    178                         System.err.println("           arg: " + args[i]);
     177                OutputController.getLogger().log(OutputController.Level.ERROR_DEBUG, "call privileged method: " + method.getName());
     178                if (args != null) {
     179                    for (int i = 0; i < args.length; i++) {
     180                        OutputController.getLogger().log(OutputController.Level.ERROR_DEBUG, "           arg: " + args[i]);
     181                    }
     182                }
    179183            }
    180184
    181185            PrivilegedExceptionAction<Object> invoker = new PrivilegedExceptionAction<Object>() {
     186                @Override
    182187                public Object run() throws Exception {
    183188                    return method.invoke(receiver, args);
     
    188193                Object result = AccessController.doPrivileged(invoker);
    189194
    190                 if (JNLPRuntime.isDebug())
    191                     System.err.println("        result: " + result);
     195                OutputController.getLogger().log(OutputController.Level.ERROR_DEBUG, "        result: " + result);
    192196
    193197                return result;
     
    243247                return false;
    244248            }
    245             if (app == null)
     249            if (app == null) {
    246250                app = JNLPRuntime.getApplication();
     251            }
    247252
    248253            final AccessType tmpType = type;
     
    254259            //from resources.jar.
    255260            Boolean b = AccessController.doPrivileged(new PrivilegedAction<Boolean>() {
     261                @Override
    256262                public Boolean run() {
    257263                    boolean b = SecurityDialogs.showAccessWarningDialog(tmpType,
     
    295301    public static boolean isSigned(ApplicationInstance app) {
    296302
    297         if (app == null)
     303        if (app == null) {
    298304            app = JNLPRuntime.getApplication();
     305        }
    299306
    300307        StackTraceElement[] stack = Thread.currentThread().getStackTrace();
     
    302309        for (int i = 0; i < stack.length; i++) {
    303310
    304             Class c = null;
     311            Class<?> c = null;
    305312
    306313            try {
    307314                c = Class.forName(stack[i].getClassName());
    308315            } catch (Exception e1) {
     316                OutputController.getLogger().log(e1);
    309317                try {
    310318                    c = Class.forName(stack[i].getClassName(), false,
    311319                            app.getClassLoader());
    312320                } catch (Exception e2) {
    313                     System.err.println(e2.getMessage());
     321                    OutputController.getLogger().log(e2);
    314322                }
    315323            }
  • trunk/icedtea-web/netx/net/sourceforge/jnlp/services/XBasicService.java

    r348 r429  
    3434import net.sourceforge.jnlp.runtime.ApplicationInstance;
    3535import net.sourceforge.jnlp.runtime.JNLPRuntime;
     36import net.sourceforge.jnlp.util.logging.OutputController;
    3637
    3738/**
     
    181182                return true;
    182183            } catch (IOException ex) {
    183                 if (JNLPRuntime.isDebug())
    184                     ex.printStackTrace();
     184                OutputController.getLogger().log(ex);
    185185            }
    186186        }
     
    194194        initialized = true;
    195195        initializeBrowserCommand();
    196         if (JNLPRuntime.isDebug()) {
    197             System.out.println("browser is " + command);
    198         }
     196        OutputController.getLogger().log("browser is " + command);
    199197    }
    200198
     
    229227                        config.save();
    230228                    } catch (IOException e) {
    231                         e.printStackTrace();
     229                        OutputController.getLogger().log(OutputController.Level.ERROR_ALL, e);
    232230                    }
    233231                    break;
     
    246244                        config.save();
    247245                    } catch (IOException e) {
    248                         e.printStackTrace();
     246                        OutputController.getLogger().log(OutputController.Level.ERROR_ALL, e);
    249247                    }
    250248                }
     
    273271            return (p.exitValue() == 0);
    274272        } catch (IOException e) {
    275             e.printStackTrace();
     273            OutputController.getLogger().log(OutputController.Level.ERROR_ALL, e);
    276274            return false;
    277275        } catch (InterruptedException e) {
    278             e.printStackTrace();
     276            OutputController.getLogger().log(OutputController.Level.ERROR_ALL, e);
    279277            return false;
    280278        }
  • trunk/icedtea-web/netx/net/sourceforge/jnlp/services/XDownloadService.java

    r348 r429  
    2121import javax.jnlp.*;
    2222
     23import net.sourceforge.jnlp.JARDesc;
     24import net.sourceforge.jnlp.Version;
     25import net.sourceforge.jnlp.cache.CacheUtil;
     26import net.sourceforge.jnlp.runtime.JNLPClassLoader;
     27import net.sourceforge.jnlp.runtime.ManageJnlpResources;
     28import net.sourceforge.jnlp.runtime.JNLPRuntime;
     29
    2330/**
    2431 * The DownloadService JNLP service.
     
    2936class XDownloadService implements DownloadService {
    3037
    31     protected XDownloadService() {
    32     }
    33 
    34     // comments copied from DownloadService interface
     38    /**
     39     * Returns the {@link JNLPClassLoader} of the application
     40     * @return the {@link JNLPClassLoader} of the application
     41     */
     42    JNLPClassLoader getClassLoader() {
     43        return (JNLPClassLoader) JNLPRuntime.getApplication().getClassLoader();
     44    }
    3545
    3646    /**
    3747     * Returns a listener that will automatically display download
    3848     * progress to the user.
     49     * @return always {@code null}
    3950     */
    4051    public DownloadServiceListener getDefaultProgressWindow() {
     
    4758     */
    4859    public boolean isExtensionPartCached(URL ref, String version, String part) {
    49         return true;
     60        boolean allCached = true;
     61        Version resourceVersion = (version == null) ? null : new Version(version);
     62
     63        JARDesc[] jars = ManageJnlpResources.findJars(this.getClassLoader(), ref, part, resourceVersion);
     64
     65        if (jars.length <= 0)
     66            return false;
     67
     68        for (int i = 0; i < jars.length && allCached; i++) {
     69            allCached = CacheUtil.isCached(jars[i].getLocation(), resourceVersion);
     70        }
     71
     72        return allCached;
    5073    }
    5174
     
    5578     */
    5679    public boolean isExtensionPartCached(URL ref, String version, String[] parts) {
    57         return true;
     80        boolean allCached = true;
     81        if (parts.length <= 0)
     82            return false;
     83
     84        for (String eachPart : parts)
     85            allCached = this.isExtensionPartCached(ref, version, eachPart);
     86
     87        return allCached;
    5888    }
    5989
     
    6595     */
    6696    public boolean isPartCached(String part) {
    67         return true;
     97        boolean allCached = true;
     98        JARDesc[] jars = ManageJnlpResources.findJars(this.getClassLoader(), null, part, null);
     99
     100        if (jars.length <= 0)
     101            return false;
     102
     103        for (int i = 0; i < jars.length && allCached; i++) {
     104            allCached = CacheUtil.isCached(jars[i].getLocation(), null);
     105        }
     106
     107        return allCached;
    68108    }
    69109
     
    75115     */
    76116    public boolean isPartCached(String[] parts) {
    77         return true;
     117        boolean allCached = true;
     118        if (parts.length <= 0)
     119            return false;
     120
     121        for (String eachPart : parts)
     122            allCached = this.isPartCached(eachPart);
     123
     124        return allCached;
    78125    }
    79126
     
    84131     */
    85132    public boolean isResourceCached(URL ref, String version) {
    86         return true;
     133        return ManageJnlpResources.isExternalResourceCached(this.getClassLoader(), ref, version);
    87134    }
    88135
     
    93140     */
    94141    public void loadExtensionPart(URL ref, String version, String[] parts, DownloadServiceListener progress) throws IOException {
     142        for (String eachPart : parts)
     143            this.loadExtensionPart(ref, version, eachPart, progress);
    95144    }
    96145
     
    101150     */
    102151    public void loadExtensionPart(URL ref, String version, String part, DownloadServiceListener progress) throws IOException {
     152        Version resourceVersion = (version == null) ? null : new Version(version);
     153        ManageJnlpResources.downloadJars(this.getClassLoader(), ref, part, resourceVersion);
    103154    }
    104155
     
    109160     */
    110161    public void loadPart(String[] parts, DownloadServiceListener progress) throws IOException {
     162        for (String eachPart : parts)
     163            this.loadPart(eachPart, progress);
    111164    }
    112165
     
    117170     */
    118171    public void loadPart(String part, DownloadServiceListener progress) throws IOException {
     172        ManageJnlpResources.downloadJars(this.getClassLoader(), null, part, null);
    119173    }
    120174
     
    125179     */
    126180    public void loadResource(URL ref, String version, DownloadServiceListener progress) throws IOException {
     181        ManageJnlpResources.loadExternalResouceToCache(this.getClassLoader(), ref, version);
    127182    }
    128183
     
    134189     */
    135190    public void removeExtensionPart(URL ref, String version, String part) throws IOException {
     191        Version resourceVersion = (version == null) ? null : new Version(version);
     192        JARDesc[] jars = ManageJnlpResources.findJars(this.getClassLoader(), ref, part, resourceVersion);
     193        ManageJnlpResources.removeCachedJars(this.getClassLoader(), ref, jars);
    136194    }
    137195
     
    143201     */
    144202    public void removeExtensionPart(URL ref, String version, String[] parts) throws IOException {
     203        for (String eachPart : parts)
     204            this.removeExtensionPart(ref, version, eachPart);
    145205    }
    146206
     
    152212     */
    153213    public void removePart(String part) throws IOException {
     214        JARDesc[] jars = ManageJnlpResources.findJars(this.getClassLoader(), null, part, null);
     215        ManageJnlpResources.removeCachedJars(this.getClassLoader(), null, jars);
    154216    }
    155217
     
    161223     */
    162224    public void removePart(String[] parts) throws IOException {
     225        for (String eachPart : parts)
     226            this.removePart(eachPart);
    163227    }
    164228
     
    170234     */
    171235    public void removeResource(URL ref, String version) throws IOException {
     236        ManageJnlpResources.removeExternalCachedResource(this.getClassLoader(), ref, version);
    172237    }
    173238
  • trunk/icedtea-web/netx/net/sourceforge/jnlp/services/XFileOpenService.java

    r348 r429  
    9292                File[] files = chooser.getSelectedFiles();
    9393                int length = files.length;
    94                 XFileContents[] xfiles = new XFileContents[length];
    95                 for (int i = 0; i < length; i++)
    96                     xfiles[i] = new XFileContents(files[i]);
    97                 return (FileContents[]) ServiceUtil.createPrivilegedProxy(
    98                            FileContents.class, xfiles);
     94                FileContents[] result = new FileContents[length];
     95                for (int i = 0; i < length; i++) {
     96                    XFileContents xfile = new XFileContents(files[i]);
     97                    result[i] = (FileContents) ServiceUtil.createPrivilegedProxy(FileContents.class, xfile);
     98                }
     99                return result;
    99100            } else {
    100101                return null;
  • trunk/icedtea-web/netx/net/sourceforge/jnlp/services/XPersistenceService.java

    r418 r429  
    2626import net.sourceforge.jnlp.runtime.*;
    2727import net.sourceforge.jnlp.util.FileUtils;
     28import net.sourceforge.jnlp.util.logging.OutputController;
    2829
    2930/**
     
    6869            requestPath = "";
    6970
    70         if (JNLPRuntime.isDebug()) {
    71             System.out.println("codebase path: " + source.getFile());
    72             System.out.println("request path: " + requestPath);
    73         }
     71          OutputController.getLogger().log("codebase path: " + source.getFile());
     72          OutputController.getLogger().log("request path: " + requestPath);
    7473
    7574        if (!source.getFile().startsWith(requestPath)
  • trunk/icedtea-web/netx/net/sourceforge/jnlp/services/XPrintService.java

    r348 r429  
    4848
    4949import net.sourceforge.jnlp.runtime.JNLPRuntime;
     50import net.sourceforge.jnlp.util.logging.OutputController;
    5051
    5152public class XPrintService implements PrintService {
     
    8586                    return true;
    8687                } catch (PrinterException pe) {
    87                     System.err.println("Could not print: " + pe);
     88                    OutputController.getLogger().log(OutputController.Level.ERROR_ALL, "Could not print: " + pe);
     89                    OutputController.getLogger().log(OutputController.Level.ERROR_DEBUG, pe);
    8890                    return false;
    8991                }
     
    103105                    return true;
    104106                } catch (PrinterException pe) {
    105                     System.err.println("Could not print: " + pe);
     107                    OutputController.getLogger().log(OutputController.Level.ERROR_ALL, "Could not print: " + pe);
     108                    OutputController.getLogger().log(OutputController.Level.ERROR_DEBUG, pe);
    106109                    return false;
    107110                }
     
    119122                                "Warning",
    120123                                JOptionPane.WARNING_MESSAGE);
    121         System.err.println("Unable to print: Unable to find default printer.");
     124        OutputController.getLogger().log(OutputController.Level.ERROR_ALL, "Unable to print: Unable to find default printer.");
    122125    }
    123126}
  • trunk/icedtea-web/netx/net/sourceforge/jnlp/services/XSingleInstanceService.java

    r348 r429  
    2525import java.util.LinkedList;
    2626import java.util.List;
     27import java.util.Map.Entry;
     28import java.util.Set;
    2729
    2830import javax.jnlp.SingleInstanceListener;
     
    3032
    3133import net.sourceforge.jnlp.JNLPFile;
     34import net.sourceforge.jnlp.PluginBridge;
    3235import net.sourceforge.jnlp.runtime.JNLPRuntime;
     36import net.sourceforge.jnlp.util.logging.OutputController;
    3337
    3438/**
     
    6165                lockFile.createWithPort(listeningSocket.getLocalPort());
    6266
    63                 if (JNLPRuntime.isDebug()) {
    64                     System.out.println("Starting SingleInstanceServer on port" + listeningSocket);
    65                 }
     67                OutputController.getLogger().log("Starting SingleInstanceServer on port" + listeningSocket);
    6668
    6769                while (true) {
     
    7476                    } catch (Exception exception) {
    7577                        // not much to do here...
    76                         exception.printStackTrace();
     78                        OutputController.getLogger().log(OutputController.Level.ERROR_ALL, exception);
    7779                    }
    7880
    7981                }
    8082            } catch (IOException e) {
    81                 e.printStackTrace();
     83                OutputController.getLogger().log(OutputController.Level.ERROR_ALL, e);
    8284            } finally {
    8385                if (listeningSocket != null) {
     
    8688                    } catch (IOException e) {
    8789                        // Give up.
    88                         e.printStackTrace();
     90                        OutputController.getLogger().log(OutputController.Level.ERROR_ALL, e);
    8991                    }
    9092                }
     
    102104     * Initialize the new SingleInstanceService
    103105     *
    104      * @throws InstanceAlreadyExistsException if the instance already exists
     106     * @throws InstanceExistsException if the instance already exists
    105107     */
    106108    public void initializeSingleInstance() {
    107         if (!initialized) {
    108             // this is called after the application has started. so safe to use
    109             // JNLPRuntime.getApplication()
    110             checkSingleInstanceRunning(JNLPRuntime.getApplication().getJNLPFile());
     109        // this is called after the application has started. so safe to use
     110        // JNLPRuntime.getApplication()
     111        JNLPFile jnlpFile = JNLPRuntime.getApplication().getJNLPFile();
     112        if (!initialized || jnlpFile instanceof PluginBridge) {
     113            // Either a new process or a new applet being handled by the plugin.
     114            checkSingleInstanceRunning(jnlpFile);
    111115            initialized = true;
    112116            SingleInstanceLock lockFile;
    113             JNLPFile jnlpFile = JNLPRuntime.getApplication().getJNLPFile();
    114117            lockFile = new SingleInstanceLock(jnlpFile);
    115118            if (!lockFile.isValid()) {
     
    128131     *         already exists
    129132     */
     133    @Override
    130134    public void checkSingleInstanceRunning(JNLPFile jnlpFile) {
    131135        SingleInstanceLock lockFile = new SingleInstanceLock(jnlpFile);
    132136        if (lockFile.isValid()) {
    133137            int port = lockFile.getPort();
    134             if (JNLPRuntime.isDebug()) {
    135                 System.out.println("Lock file is valid (port=" + port + "). Exiting.");
    136             }
     138            OutputController.getLogger().log("Lock file is valid (port=" + port + "). Exiting.");
     139
     140            String[] args = null;
     141            if (jnlpFile.isApplet()) {
     142                // FIXME Proprietary plug-in is unclear about how to handle
     143                // applets and their parameters.
     144                //Right now better to forward at least something
     145                Set<Entry<String, String>> currentParams = jnlpFile.getApplet().getParameters().entrySet();
     146                args = new String[currentParams.size() * 2];
     147                int i = 0;
     148                for (Entry<String, String> entry : currentParams) {
     149                    args[i] = entry.getKey();
     150                    args[i+1] = entry.getValue();
     151                    i += 2;
     152                }
     153            } else if (jnlpFile.isInstaller()) {
     154                // TODO Implement this once installer service is available.
     155            } else {
     156                args = jnlpFile.getApplication().getArguments();
     157            }
     158
    137159            try {
    138                 sendProgramArgumentsToExistingApplication(port, jnlpFile.getApplication()
    139                         .getArguments());
     160                sendProgramArgumentsToExistingApplication(port, args);
    140161                throw new InstanceExistsException(String.valueOf(port));
    141162            } catch (IOException e) {
     
    181202
    182203        } catch (UnknownHostException unknownHost) {
    183             if (JNLPRuntime.isDebug()) {
    184                 System.out.println("Unable to find localhost");
    185             }
     204            OutputController.getLogger().log("Unable to find localhost");
    186205            throw new RuntimeException(unknownHost);
    187206        }
     
    204223     * Add the specified SingleInstanceListener
    205224     *
    206      * @throws InstanceExistsException, which is likely to terminate the
     225     * @throws InstanceExistsException which is likely to terminate the
    207226     *         application but not guaranteed to
    208227     */
  • trunk/icedtea-web/netx/net/sourceforge/jnlp/tools/JarCertVerifier.java

    r418 r429  
    2626package net.sourceforge.jnlp.tools;
    2727
    28 import static net.sourceforge.jnlp.runtime.Translator.R;
    29 
    30 import java.io.*;
    31 import java.util.*;
    32 import java.util.jar.*;
     28import java.io.File;
     29import java.io.IOException;
     30import java.io.InputStream;
     31import java.security.CodeSigner;
     32import java.security.KeyStore;
     33import java.security.cert.CertPath;
    3334import java.security.cert.Certificate;
    3435import java.security.cert.X509Certificate;
    35 import java.security.cert.CertPath;
    36 import java.security.*;
    37 import sun.security.x509.*;
    38 import sun.security.util.*;
    39 
    40 import net.sourceforge.jnlp.*;
    41 import net.sourceforge.jnlp.cache.*;
    42 import net.sourceforge.jnlp.security.*;
     36import java.util.ArrayList;
     37import java.util.Collections;
     38import java.util.Enumeration;
     39import java.util.HashMap;
     40import java.util.List;
     41import java.util.Map;
     42import java.util.Vector;
     43import java.util.jar.JarEntry;
     44
     45import net.sourceforge.jnlp.JARDesc;
     46import net.sourceforge.jnlp.JNLPFile;
     47import net.sourceforge.jnlp.LaunchException;
     48import net.sourceforge.jnlp.cache.ResourceTracker;
     49import net.sourceforge.jnlp.runtime.JNLPClassLoader.SecurityDelegate;
     50import net.sourceforge.jnlp.security.AppVerifier;
     51import net.sourceforge.jnlp.security.CertVerifier;
     52import net.sourceforge.jnlp.security.CertificateUtils;
     53import net.sourceforge.jnlp.security.KeyStores;
     54import net.sourceforge.jnlp.util.JarFile;
     55import net.sourceforge.jnlp.util.logging.OutputController;
     56import sun.security.util.DerInputStream;
     57import sun.security.util.DerValue;
     58import sun.security.x509.NetscapeCertTypeExtension;
    4359
    4460/**
    45  * <p>The jar certificate verifier utility.
    46  *
     61 * The jar certificate verifier utility.
     62 * 
    4763 * @author Roland Schemers
    4864 * @author Jan Luehe
     
    5672    private static final String SIG_PREFIX = META_INF + "SIG-";
    5773
    58     private static final long SIX_MONTHS = 180 * 24 * 60 * 60 * 1000L; //milliseconds
    59 
    60     static enum verifyResult {
     74    private static final long SIX_MONTHS = 180 * 24 * 60 * 60 * 1000L; // milliseconds
     75
     76    static enum VerifyResult {
    6177        UNSIGNED, SIGNED_OK, SIGNED_NOT_OK
    6278    }
    6379
    64     // signer's certificate chain (when composing)
    65     X509Certificate[] certChain;
    66 
    67     boolean verbose = false; // verbose output when signing/verifying
    68     boolean showcerts = false; // show certs when verifying
    69 
    70     private boolean hasExpiredCert = false;
    71     private boolean hasExpiringCert = false;
    72     private boolean notYetValidCert = false;
    73 
    74     private boolean badKeyUsage = false;
    75     private boolean badExtendedKeyUsage = false;
    76     private boolean badNetscapeCertType = false;
    77 
    78     private boolean alreadyTrustPublisher = false;
    79     private boolean rootInCacerts = false;
    80 
    81     /**
    82      * The single certPath used in this JarSiging. We're only keeping
    83      * track of one here, since in practice there's only one signer
    84      * for a JNLP Application.
    85      */
    86     private CertPath certPath = null;
    87 
    88     private boolean noSigningIssues = true;
    89 
    90     private boolean anyJarsSigned = false;
    91 
    92     /** all of the jar files that were verified */
    93     private ArrayList<String> verifiedJars = null;
    94 
    95     /** all of the jar files that were not verified */
    96     private ArrayList<String> unverifiedJars = null;
    97 
    98     /** the certificates used for jar verification */
    99     private HashMap<CertPath, Integer> certs = new HashMap<CertPath, Integer>();
    100 
    101     /** details of this signing */
    102     private ArrayList<String> details = new ArrayList<String>();
    103 
    104     private int totalSignableEntries = 0;
    105 
    106     /* (non-Javadoc)
    107      * @see net.sourceforge.jnlp.tools.CertVerifier2#getAlreadyTrustPublisher()
    108      */
     80    /** All of the jar files that were verified for signing */
     81    private List<String> verifiedJars = new ArrayList<String>();
     82
     83    /** All of the jar files that were not verified */
     84    private List<String> unverifiedJars = new ArrayList<String>();
     85
     86    /** The certificates used for jar verification linked to their respective information */
     87    private Map<CertPath, CertInformation> certs = new HashMap<CertPath, CertInformation>();
     88
     89    /** Temporary cert path hack to be used to keep track of which one a UI dialog is using */
     90    private CertPath currentlyUsed;
     91
     92    /** Absolute location to jars and the number of entries which are possibly signable */
     93    private Map<String, Integer> jarSignableEntries = new HashMap<String, Integer>();
     94
     95    /** The application verifier to use by this instance */
     96    private AppVerifier appVerifier;
     97
     98    /**
     99     * Create a new jar certificate verifier utility that uses the provided verifier for its strategy pattern.
     100     *
     101     * @param verifier
     102     *            The application verifier to be used by the new instance.
     103     */
     104    public JarCertVerifier(AppVerifier verifier) {
     105        appVerifier = verifier;
     106    }
     107
     108    /**
     109     * Return true if there are no signable entries in the jar.
     110     * This will return false if any of verified jars have content more than just META-INF/.
     111     */
     112    public boolean isTriviallySigned() {
     113        return getTotalJarEntries(jarSignableEntries) <= 0
     114                && certs.size() <= 0;
     115    }
     116
    109117    public boolean getAlreadyTrustPublisher() {
    110         return alreadyTrustPublisher;
    111     }
    112 
    113     /* (non-Javadoc)
    114      * @see net.sourceforge.jnlp.tools.CertVerifier2#getRootInCacerts()
    115      */
     118        boolean allPublishersTrusted = appVerifier.hasAlreadyTrustedPublisher(
     119                certs, jarSignableEntries);
     120        OutputController.getLogger().log("App already has trusted publisher: "
     121                    + allPublishersTrusted);
     122        return allPublishersTrusted;
     123    }
     124
    116125    public boolean getRootInCacerts() {
    117         return rootInCacerts;
    118     }
    119 
    120     public CertPath getCertPath() {
    121         return certPath;
    122     }
    123 
    124     /* (non-Javadoc)
    125      * @see net.sourceforge.jnlp.tools.CertVerifier2#hasSigningIssues()
    126      */
    127     public boolean hasSigningIssues() {
    128         return hasExpiredCert || notYetValidCert || badKeyUsage
    129                 || badExtendedKeyUsage || badNetscapeCertType;
    130     }
    131 
    132     /* (non-Javadoc)
    133      * @see net.sourceforge.jnlp.tools.CertVerifier2#noSigningIssues()
    134      */
    135     public boolean noSigningIssues() {
    136         return noSigningIssues;
    137     }
    138 
    139     public boolean anyJarsSigned() {
    140         return anyJarsSigned;
    141     }
    142 
    143     /* (non-Javadoc)
    144      * @see net.sourceforge.jnlp.tools.CertVerifier2#getDetails()
    145      */
    146     public ArrayList<String> getDetails() {
    147         return details;
    148     }
    149 
    150     /* (non-Javadoc)
    151      * @see net.sourceforge.jnlp.tools.CertVerifier2#getCerts()
    152      */
    153     public ArrayList<CertPath> getCerts() {
     126        boolean allRootCAsTrusted = appVerifier.hasRootInCacerts(certs,
     127                jarSignableEntries);
     128        OutputController.getLogger().log("App has trusted root CA: " + allRootCAsTrusted);
     129        return allRootCAsTrusted;
     130    }
     131
     132    public CertPath getCertPath(CertPath cPath) { // Parameter ignored.
     133        return currentlyUsed;
     134    }
     135
     136    public boolean hasSigningIssues(CertPath certPath) {
     137        return certs.get(certPath).hasSigningIssues();
     138    }
     139
     140    public List<String> getDetails(CertPath certPath) {
     141        if (certPath != null) {
     142            currentlyUsed = certPath;
     143        }
     144        return certs.get(currentlyUsed).getDetailsAsStrings();
     145    }
     146
     147    /**
     148     * Get a list of the cert paths of all signers across the app.
     149     *
     150     * @return List of CertPath vars representing each of the signers present on any jar.
     151     */
     152    public List<CertPath> getCertsList() {
    154153        return new ArrayList<CertPath>(certs.keySet());
    155154    }
    156155
    157156    /**
    158      * Returns whether or not all entries have a common signer.
    159      * 
    160      * It is possible to create jars where only some entries are signed. In
    161      * such cases, we should not prompt the user to accept anything, as the whole
    162      * application must be treated as unsigned. This method should be called by a
    163      * caller before it is about to ask the user to accept a cert and determine
    164      * whether the application is trusted or not.
    165      * 
    166      * @return Whether or not all entries have a common signer
    167      */
    168     public boolean isFullySignedByASingleCert() {
    169 
    170         for (CertPath cPath : certs.keySet()) {
    171             // If this cert has signed everything, return true
    172             if (certs.get(cPath) == totalSignableEntries)
    173                 return true;
    174         }
    175 
    176         // No cert found that signed all entries. Return false.
    177         return false;
    178     }
    179 
    180     public void verifyJars(List<JARDesc> jars, ResourceTracker tracker)
     157     * Find the information the specified cert path has with respect to this application.
     158     *
     159     * @return All the information the path has with this app.
     160     */
     161    public CertInformation getCertInformation(CertPath cPath) {
     162        return certs.get(cPath);
     163    }
     164
     165    /**
     166     * Returns whether or not the app is considered completely signed.
     167     *
     168     * An app using a JNLP is considered signed if all of the entries of its jars are signed by at least one common signer.
     169     *
     170     * An applet on the other hand only needs to have each individual jar be fully signed by a signer. The signers can differ between jars.
     171     *
     172     * @return Whether or not the app is considered signed.
     173     */
     174    // FIXME: Change javadoc once applets do not need entire jars signed.
     175    public boolean isFullySigned() {
     176        if (isTriviallySigned())
     177            return true;
     178        boolean fullySigned = appVerifier.isFullySigned(certs,
     179                jarSignableEntries);
     180        OutputController.getLogger().log("App already has trusted publisher: "
     181                    + fullySigned);
     182        return fullySigned;
     183    }
     184
     185    public static boolean isJarSigned(JARDesc jar, AppVerifier verifier, ResourceTracker tracker) throws Exception {
     186        JarCertVerifier certVerifier = new JarCertVerifier(verifier);
     187        List<JARDesc> singleJarList = new ArrayList<JARDesc>();
     188        singleJarList.add(jar);
     189        certVerifier.add(singleJarList, tracker);
     190        return certVerifier.allJarsSigned();
     191    }
     192
     193    /**
     194     * Update the verifier to consider new jars when verifying.
     195     *
     196     * @param jars
     197     *            List of new jars to be verified.
     198     * @param tracker
     199     *            Resource tracker used to obtain the the jars from cache
     200     * @throws Exception
     201     *             Caused by issues with obtaining the jars' entries or interacting with the tracker.
     202     */
     203    public void add(List<JARDesc> jars, ResourceTracker tracker)
    181204            throws Exception {
    182 
    183         verifiedJars = new ArrayList<String>();
    184         unverifiedJars = new ArrayList<String>();
     205        verifyJars(jars, tracker);
     206    }
     207
     208    /**
     209     * Verify the jars provided and update the state of this instance to match the new information.
     210     *
     211     * @param jars
     212     *            List of new jars to be verified.
     213     * @param tracker
     214     *            Resource tracker used to obtain the the jars from cache
     215     * @throws Exception
     216     *             Caused by issues with obtaining the jars' entries or interacting with the tracker.
     217     */
     218    private void verifyJars(List<JARDesc> jars, ResourceTracker tracker)
     219            throws Exception {
    185220
    186221        for (JARDesc jar : jars) {
     
    197232
    198233                String localFile = jarFile.getAbsolutePath();
    199                 verifyResult result = verifyJar(localFile);
    200 
    201                 if (result == verifyResult.UNSIGNED) {
     234                if (verifiedJars.contains(localFile)
     235                        || unverifiedJars.contains(localFile)) {
     236                    continue;
     237                }
     238
     239                VerifyResult result = verifyJar(localFile);
     240
     241                if (result == VerifyResult.UNSIGNED) {
    202242                    unverifiedJars.add(localFile);
    203                 } else if (result == verifyResult.SIGNED_NOT_OK) {
    204                     noSigningIssues = false;
     243                } else if (result == VerifyResult.SIGNED_NOT_OK) {
    205244                    verifiedJars.add(localFile);
    206                 } else if (result == verifyResult.SIGNED_OK) {
     245                } else if (result == VerifyResult.SIGNED_OK) {
    207246                    verifiedJars.add(localFile);
    208247                }
     
    214253        }
    215254
    216         //we really only want the first certPath
    217         for (CertPath cPath : certs.keySet()) {
    218 
    219             if (certs.get(cPath) != totalSignableEntries)
    220                 continue;
    221             else
    222                 certPath = cPath;
    223 
    224             // check if the certs added above are in the trusted path
    225             checkTrustedCerts();
    226 
    227             if (alreadyTrustPublisher || rootInCacerts)
    228                 break;
    229         }
    230 
    231     }
    232 
    233     private verifyResult verifyJar(String jarName) throws Exception {
    234         boolean anySigned = false;
    235         boolean hasUnsignedEntry = false;
     255        for (CertPath certPath : certs.keySet())
     256            checkTrustedCerts(certPath);
     257    }
     258
     259    /**
     260     * Checks through all the jar entries of jarName for signers, storing all the common ones in the certs hash map.
     261     *
     262     * @param jarName
     263     *            The absolute path to the jar file.
     264     * @return The return of {@link JarCertVerifier#verifyJarEntryCerts} using the entries found in the jar located at jarName.
     265     * @throws Exception
     266     *             Will be thrown if there are any problems with the jar.
     267     */
     268    private VerifyResult verifyJar(String jarName) throws Exception {
    236269        JarFile jarFile = null;
    237270
     
    248281                InputStream is = jarFile.getInputStream(je);
    249282                try {
    250                     int n;
    251                     while ((n = is.read(buffer, 0, buffer.length)) != -1) {
     283                    while (is.read(buffer, 0, buffer.length) != -1) {
    252284                        // we just read. this will throw a SecurityException
    253                         // if  a signature/digest check fails.
     285                        // if a signature/digest check fails.
    254286                    }
    255287                } finally {
     
    259291                }
    260292            }
    261 
    262             if (jarFile.getManifest() != null) {
    263                 if (verbose)
    264                     System.out.println();
    265 
    266                 long now = System.currentTimeMillis();
    267 
    268                 for (JarEntry je : entriesVec) {
    269                     String name = je.getName();
    270                     CodeSigner[] signers = je.getCodeSigners();
    271                     boolean isSigned = (signers != null);
    272                     anySigned |= isSigned;
    273 
    274                     boolean shouldHaveSignature = !je.isDirectory()
    275                                                 && !isMetaInfFile(name);
    276 
    277                     hasUnsignedEntry |= shouldHaveSignature &&  !isSigned;
    278 
    279                     if (shouldHaveSignature)
    280                         totalSignableEntries++;
    281 
    282                     if (shouldHaveSignature && isSigned) {
    283                         for (int i = 0; i < signers.length; i++) {
    284                             CertPath certPath = signers[i].getSignerCertPath();
    285                             if (!certs.containsKey(certPath))
    286                                 certs.put(certPath, 1);
    287                             else
    288                                 certs.put(certPath, certs.get(certPath) + 1);
    289 
    290                             Certificate cert = signers[i].getSignerCertPath()
    291                                     .getCertificates().get(0);
    292                             if (cert instanceof X509Certificate) {
    293                                 checkCertUsage((X509Certificate) cert, null);
    294                                 if (!showcerts) {
    295                                     long notBefore = ((X509Certificate) cert)
    296                                                      .getNotBefore().getTime();
    297                                     long notAfter = ((X509Certificate) cert)
    298                                                     .getNotAfter().getTime();
    299 
    300                                     if (now < notBefore) {
    301                                         notYetValidCert = true;
    302                                     }
    303 
    304                                     if (notAfter < now) {
    305                                         hasExpiredCert = true;
    306                                     } else if (notAfter < now + SIX_MONTHS) {
    307                                         hasExpiringCert = true;
    308                                     }
    309                                 }
    310                             }
    311                         }
    312                     }
    313                 } //while e has more elements
    314             } else { //if man not null
    315 
    316                 // Else increment totalEntries by 1 so that unsigned jars with
    317                 // no manifests can't sneak in
    318                 totalSignableEntries++;
    319             }
    320 
    321             //Alert the user if any of the following are true.
    322             if (!anySigned) {
    323                 return verifyResult.UNSIGNED;
    324             } else {
    325                 anyJarsSigned = true;
    326 
    327                 //warnings
    328                 if (hasUnsignedEntry || hasExpiredCert || hasExpiringCert ||
    329                         badKeyUsage || badExtendedKeyUsage || badNetscapeCertType ||
    330                         notYetValidCert) {
    331 
    332                     addToDetails(R("SRunWithoutRestrictions"));
    333 
    334                     if (badKeyUsage)
    335                         addToDetails(R("SBadKeyUsage"));
    336                     if (badExtendedKeyUsage)
    337                         addToDetails(R("SBadExtendedKeyUsage"));
    338                     if (badNetscapeCertType)
    339                         addToDetails(R("SBadNetscapeCertType"));
    340                     if (hasUnsignedEntry)
    341                         addToDetails(R("SHasUnsignedEntry"));
    342                     if (hasExpiredCert)
    343                         addToDetails(R("SHasExpiredCert"));
    344                     if (hasExpiringCert)
    345                         addToDetails(R("SHasExpiringCert"));
    346                     if (notYetValidCert)
    347                         addToDetails(R("SNotYetValidCert"));
    348                 }
    349             }
     293            return verifyJarEntryCerts(jarName, jarFile.getManifest() != null,
     294                    entriesVec);
     295
    350296        } catch (Exception e) {
    351             e.printStackTrace();
     297            OutputController.getLogger().log(OutputController.Level.ERROR_ALL, e);
    352298            throw e;
    353299        } finally { // close the resource
     
    356302            }
    357303        }
    358 
    359         //anySigned does not guarantee that all files were signed.
    360         return (anySigned && !(hasUnsignedEntry || hasExpiredCert
    361                               || badKeyUsage || badExtendedKeyUsage || badNetscapeCertType || notYetValidCert)) ? verifyResult.SIGNED_OK : verifyResult.SIGNED_NOT_OK;
    362     }
    363 
    364     /**
    365      * Checks the user's trusted.certs file and the cacerts file to see
    366      * if a publisher's and/or CA's certificate exists there.
    367      */
    368     private void checkTrustedCerts() throws Exception {
    369         if (certPath != null) {
    370             try {
    371                 X509Certificate publisher = (X509Certificate) getPublisher();
    372                 KeyStore[] certKeyStores = KeyStores.getCertKeyStores();
    373                 alreadyTrustPublisher = CertificateUtils.inKeyStores(publisher, certKeyStores);
    374                 X509Certificate root = (X509Certificate) getRoot();
    375                 KeyStore[] caKeyStores = KeyStores.getCAKeyStores();
    376                 // Check entire cert path for a trusted CA
    377                 for (Certificate c : certPath.getCertificates()) {
    378                         if ((rootInCacerts = CertificateUtils.inKeyStores(
    379                             (X509Certificate) c, caKeyStores))) {
    380                         break;
     304    }
     305
     306    /**
     307     * Checks through all the jar entries for signers, storing all the common ones in the certs hash map.
     308     *
     309     * @param jarName
     310     *            The absolute path to the jar file.
     311     * @param jarHasManifest
     312     *            Whether or not the associated jar has a manifest.
     313     * @param entries
     314     *            The list of entries in the associated jar.
     315     * @return If there is at least one signable entry that is not signed by a common signer, return UNSIGNED. Otherwise every signable entry is signed by at least one common signer. If the signer has no issues, return SIGNED_OK. If there are any signing issues, return SIGNED_NOT_OK.
     316     * @throws Exception
     317     *             Will be thrown if there are issues with entries.
     318     */
     319    VerifyResult verifyJarEntryCerts(String jarName, boolean jarHasManifest,
     320            Vector<JarEntry> entries) throws Exception {
     321        // Contains number of entries the cert with this CertPath has signed.
     322        Map<CertPath, Integer> jarSignCount = new HashMap<CertPath, Integer>();
     323        int numSignableEntriesInJar = 0;
     324
     325        // Record current time just before checking the jar begins.
     326        long now = System.currentTimeMillis();
     327        if (jarHasManifest) {
     328
     329            for (JarEntry je : entries) {
     330                String name = je.getName();
     331                CodeSigner[] signers = je.getCodeSigners();
     332                boolean isSigned = (signers != null);
     333
     334                boolean shouldHaveSignature = !je.isDirectory()
     335                        && !isMetaInfFile(name);
     336
     337                if (shouldHaveSignature) {
     338                    numSignableEntriesInJar++;
     339                }
     340
     341                if (shouldHaveSignature && isSigned) {
     342                    for (int i = 0; i < signers.length; i++) {
     343                        CertPath certPath = signers[i].getSignerCertPath();
     344
     345                        if (!jarSignCount.containsKey(certPath))
     346                            jarSignCount.put(certPath, 1);
     347                        else
     348                            jarSignCount.put(certPath,
     349                                    jarSignCount.get(certPath) + 1);
    381350                    }
    382351                }
    383             } catch (Exception e) {
    384                 // TODO: Warn user about not being able to
    385                 // look through their cacerts/trusted.certs
    386                 // file depending on exception.
    387                 throw e;
    388             }
    389 
    390             if (!rootInCacerts)
    391                 addToDetails(R("SUntrustedCertificate"));
    392             else
    393                 addToDetails(R("STrustedCertificate"));
    394         }
    395     }
    396 
    397     /* (non-Javadoc)
    398      * @see net.sourceforge.jnlp.tools.CertVerifier2#getPublisher()
    399      */
    400     public Certificate getPublisher() {
    401         if (certPath != null) {
    402             List<? extends Certificate> certList = certPath.getCertificates();
     352            } // while e has more elements
     353        } else { // if manifest is null
     354
     355            // Else increment total entries by 1 so that unsigned jars with
     356            // no manifests can't sneak in
     357            numSignableEntriesInJar++;
     358        }
     359
     360        jarSignableEntries.put(jarName, numSignableEntriesInJar);
     361
     362        // Find all signers that have signed every signable entry in this jar.
     363        boolean allEntriesSignedBySingleCert = false;
     364        for (CertPath certPath : jarSignCount.keySet()) {
     365            if (jarSignCount.get(certPath) == numSignableEntriesInJar) {
     366                allEntriesSignedBySingleCert = true;
     367
     368                boolean wasPreviouslyVerified = certs.containsKey(certPath);
     369                if (!wasPreviouslyVerified)
     370                    certs.put(certPath, new CertInformation());
     371
     372                CertInformation certInfo = certs.get(certPath);
     373                if (wasPreviouslyVerified)
     374                    certInfo.resetForReverification();
     375
     376                certInfo.setNumJarEntriesSigned(jarName,
     377                        numSignableEntriesInJar);
     378
     379                Certificate cert = certPath.getCertificates().get(0);
     380                if (cert instanceof X509Certificate) {
     381                    checkCertUsage(certPath, (X509Certificate) cert, null);
     382                    long notBefore = ((X509Certificate) cert).getNotBefore().getTime();
     383                    long notAfter = ((X509Certificate) cert).getNotAfter().getTime();
     384                    if (now < notBefore) {
     385                        certInfo.setNotYetValidCert();
     386                    }
     387
     388                    if (notAfter < now) {
     389                        certInfo.setHasExpiredCert();
     390                    } else if (notAfter < now + SIX_MONTHS) {
     391                        certInfo.setHasExpiringCert();
     392                    }
     393                }
     394            }
     395        }
     396
     397        // Every signable entry of this jar needs to be signed by at least
     398        // one signer for the jar to be considered successfully signed.
     399        VerifyResult result = null;
     400
     401        if (numSignableEntriesInJar == 0) {
     402            // Allow jars with no signable entries to simply be considered signed.
     403            // There should be no security risk in doing so.
     404            result = VerifyResult.SIGNED_OK;
     405        } else if (allEntriesSignedBySingleCert) {
     406
     407            // We need to find at least one signer without any issues.
     408            for (CertPath entryCertPath : jarSignCount.keySet()) {
     409                if (certs.containsKey(entryCertPath)
     410                        && !hasSigningIssues(entryCertPath)) {
     411                    result = VerifyResult.SIGNED_OK;
     412                    break;
     413                }
     414            }
     415            if (result == null) {
     416                // All signers had issues
     417                result = VerifyResult.SIGNED_NOT_OK;
     418            }
     419        } else {
     420            result = VerifyResult.UNSIGNED;
     421        }
     422
     423        OutputController.getLogger().log("Jar found at " + jarName
     424                    + "has been verified as " + result);
     425        return result;
     426    }
     427
     428    /**
     429     * Checks the user's trusted.certs file and the cacerts file to see if a
     430     * publisher's and/or CA's certificate exists there.
     431     *
     432     * @param certPath
     433     *            The cert path of the signer being checked for trust.
     434     */
     435    private void checkTrustedCerts(CertPath certPath) throws Exception {
     436        CertInformation info = certs.get(certPath);
     437        try {
     438            X509Certificate publisher = (X509Certificate) getPublisher(certPath);
     439            KeyStore[] certKeyStores = KeyStores.getCertKeyStores();
     440            if (CertificateUtils.inKeyStores(publisher, certKeyStores))
     441                info.setAlreadyTrustPublisher();
     442            KeyStore[] caKeyStores = KeyStores.getCAKeyStores();
     443            // Check entire cert path for a trusted CA
     444            for (Certificate c : certPath.getCertificates()) {
     445                if (CertificateUtils.inKeyStores((X509Certificate) c,
     446                        caKeyStores)) {
     447                    info.setRootInCacerts();
     448                    return;
     449                }
     450            }
     451        } catch (Exception e) {
     452            // TODO: Warn user about not being able to
     453            // look through their cacerts/trusted.certs
     454            // file depending on exception.
     455            OutputController.getLogger().log("WARNING: Unable to read through cert store files.");
     456            throw e;
     457        }
     458
     459        // Otherwise a parent cert was not found to be trusted.
     460        info.setUntrusted();
     461    }
     462
     463    public void setCurrentlyUsedCertPath(CertPath cPath) {
     464        currentlyUsed = cPath;
     465    }
     466
     467    public Certificate getPublisher(CertPath cPath) {
     468        if (cPath != null) {
     469            currentlyUsed = cPath;
     470        }
     471        if (currentlyUsed != null) {
     472            List<? extends Certificate> certList = currentlyUsed
     473                    .getCertificates();
    403474            if (certList.size() > 0) {
    404475                return certList.get(0);
     
    411482    }
    412483
    413     /* (non-Javadoc)
    414      * @see net.sourceforge.jnlp.tools.CertVerifier2#getRoot()
    415      */
    416     public Certificate getRoot() {
    417         if (certPath != null) {
    418             List<? extends Certificate> certList = certPath.getCertificates();
     484    public Certificate getRoot(CertPath cPath) {
     485        if (cPath != null) {
     486            currentlyUsed = cPath;
     487        }
     488        if (currentlyUsed != null) {
     489            List<? extends Certificate> certList = currentlyUsed
     490                    .getCertificates();
    419491            if (certList.size() > 0) {
    420492                return certList.get(certList.size() - 1);
     
    427499    }
    428500
    429     private void addToDetails(String detail) {
    430         if (!details.contains(detail))
    431             details.add(detail);
    432     }
    433 
    434501    /**
    435502     * Returns whether a file is in META-INF, and thus does not require signing.
    436      *
    437      * Signature-related files under META-INF include:
    438      * . META-INF/MANIFEST.MF
    439      * . META-INF/SIG-*
    440      * . META-INF/*.SF
    441      * . META-INF/*.DSA
    442      * . META-INF/*.RSA
     503     *
     504     * Signature-related files under META-INF include: . META-INF/MANIFEST.MF . META-INF/SIG-* . META-INF/*.SF . META-INF/*.DSA . META-INF/*.RSA
    443505     */
    444506    static boolean isMetaInfFile(String name) {
     
    449511    /**
    450512     * Check if userCert is designed to be a code signer
    451      * @param userCert the certificate to be examined
    452      * @param bad 3 booleans to show if the KeyUsage, ExtendedKeyUsage,
    453      *            NetscapeCertType has codeSigning flag turned on.
    454      *            If null, the class field badKeyUsage, badExtendedKeyUsage,
     513     *
     514     * @param userCert
     515     *            the certificate to be examined
     516     * @param bad
     517     *            3 booleans to show if the KeyUsage, ExtendedKeyUsage,
     518     *            NetscapeCertType has codeSigning flag turned on. If null,
     519     *            the class field badKeyUsage, badExtendedKeyUsage,
    455520     *            badNetscapeCertType will be set.
    456      *
    457      * Required for verifyJar()
    458      */
    459     void checkCertUsage(X509Certificate userCert, boolean[] bad) {
     521     *
     522     *            Required for verifyJar()
     523     */
     524    void checkCertUsage(CertPath certPath, X509Certificate userCert,
     525            boolean[] bad) {
    460526
    461527        // Can act as a signer?
     
    475541                    bad[0] = true;
    476542                } else {
    477                     badKeyUsage = true;
     543                    certs.get(certPath).setBadKeyUsage();
    478544                }
    479545            }
     
    488554                        bad[1] = true;
    489555                    } else {
    490                         badExtendedKeyUsage = true;
     556                        certs.get(certPath).setBadExtendedKeyUsage();
    491557                    }
    492558                }
     
    498564        try {
    499565            // OID_NETSCAPE_CERT_TYPE
    500             byte[] netscapeEx = userCert.getExtensionValue
    501                                 ("2.16.840.1.113730.1.1");
     566            byte[] netscapeEx = userCert
     567                    .getExtensionValue("2.16.840.1.113730.1.1");
    502568            if (netscapeEx != null) {
    503569                DerInputStream in = new DerInputStream(netscapeEx);
     
    506572                        .toByteArray();
    507573
    508                 NetscapeCertTypeExtension extn =
    509                         new NetscapeCertTypeExtension(encoded);
    510 
    511                 Boolean val = (Boolean) extn.get(
    512                                   NetscapeCertTypeExtension.OBJECT_SIGNING);
     574                NetscapeCertTypeExtension extn = new NetscapeCertTypeExtension(
     575                        encoded);
     576
     577                Boolean val = (Boolean) extn
     578                        .get(NetscapeCertTypeExtension.OBJECT_SIGNING);
    513579                if (!val) {
    514580                    if (bad != null) {
    515581                        bad[2] = true;
    516582                    } else {
    517                         badNetscapeCertType = true;
     583                        certs.get(certPath).setBadNetscapeCertType();
    518584                    }
    519585                }
     
    526592    /**
    527593     * Returns if all jars are signed.
    528      *
     594     * 
    529595     * @return True if all jars are signed, false if there are one or more unsigned jars
    530596     */
     
    533599    }
    534600
     601    public void checkTrustWithUser(SecurityDelegate securityDelegate, JNLPFile file) throws LaunchException {
     602        appVerifier.checkTrustWithUser(securityDelegate, this, file);
     603    }
     604
     605    public Map<String, Integer> getJarSignableEntries() {
     606        return Collections.unmodifiableMap(jarSignableEntries);
     607    }
     608
     609    /**
     610     * Get the total number of entries in the provided map.
     611     *
     612     * @return The number of entries.
     613     */
     614    public static int getTotalJarEntries(Map<String, Integer> map) {
     615        int sum = 0;
     616        for (int value : map.values()) {
     617            sum += value;
     618        }
     619        return sum;
     620    }
    535621}
  • trunk/icedtea-web/netx/net/sourceforge/jnlp/tools/KeyStoreUtil.java

    r418 r429  
    2727
    2828/**
    29  * <p> This class provides several utilities to <code>KeyStore</code>.
     29 * This class provides several utilities to {@link java.security.KeyStore}.
    3030 *
    3131 * @since 1.6.0
  • trunk/icedtea-web/netx/net/sourceforge/jnlp/util/BasicExceptionDialog.java

    r418 r429  
    3838package net.sourceforge.jnlp.util;
    3939
     40import net.sourceforge.jnlp.util.logging.OutputController;
    4041import static net.sourceforge.jnlp.runtime.Translator.R;
    4142
    4243import java.awt.BorderLayout;
     44import java.awt.Component;
    4345import java.awt.Dimension;
    4446import java.awt.event.ActionEvent;
    4547import java.awt.event.ActionListener;
    46 import java.io.PrintWriter;
    47 import java.io.StringWriter;
    4848
    4949import javax.swing.BorderFactory;
     
    5757import javax.swing.JScrollPane;
    5858import javax.swing.JTextArea;
     59import javax.swing.SwingUtilities;
     60import net.sourceforge.jnlp.controlpanel.CachePane;
     61import net.sourceforge.jnlp.util.logging.JavaConsole;
    5962
    6063/**
     
    6366public class BasicExceptionDialog {
    6467
    65     private static String exceptionToString(Exception exception) {
    66         StringWriter stringWriter = new StringWriter();
    67         PrintWriter printWriter = new PrintWriter(stringWriter);
    68         exception.printStackTrace(printWriter);
    69         return stringWriter.toString();
    70     }
    7168
    7269    /**
     
    7673     */
    7774    public static void show(Exception exception) {
    78         String detailsText = exceptionToString(exception);
     75        String detailsText = OutputController.exceptionToString(exception);
    7976
    8077        final JPanel mainPanel = new JPanel(new BorderLayout());
     
    8582        errorDialog.setIconImages(ImageResources.INSTANCE.getApplicationImages());
    8683
    87         final JPanel quickInfoPanel = new JPanel();
    88         BoxLayout layout = new BoxLayout(quickInfoPanel, BoxLayout.Y_AXIS);
    89         quickInfoPanel.setLayout(layout);
    90         mainPanel.add(quickInfoPanel, BorderLayout.PAGE_START);
     84        final JPanel quickInfoPanelAll = new JPanel();
     85        final JPanel quickInfoPanelMessage = new JPanel();
     86        final JPanel quickInfoPanelButtons = new JPanel();
     87        BoxLayout layoutAll = new BoxLayout(quickInfoPanelAll, BoxLayout.Y_AXIS);
     88        BoxLayout layoutMessage = new BoxLayout(quickInfoPanelMessage, BoxLayout.X_AXIS);
     89        BoxLayout layoutButtons = new BoxLayout(quickInfoPanelButtons, BoxLayout.X_AXIS);
     90        quickInfoPanelAll.setLayout(layoutAll);
     91        quickInfoPanelMessage.setLayout(layoutMessage);
     92        quickInfoPanelButtons.setLayout(layoutButtons);
     93        mainPanel.add(quickInfoPanelAll, BorderLayout.PAGE_START);
     94        quickInfoPanelAll.add(quickInfoPanelMessage);
     95        quickInfoPanelAll.add(quickInfoPanelButtons);
    9196
    9297        JLabel errorLabel = new JLabel(exception.getMessage());
    9398        errorLabel.setAlignmentY(JComponent.LEFT_ALIGNMENT);
    94         quickInfoPanel.add(errorLabel);
     99        quickInfoPanelMessage.add(errorLabel);
    95100
    96101        final JButton viewDetails = new JButton(R("ButShowDetails"));
    97102        viewDetails.setAlignmentY(JComponent.LEFT_ALIGNMENT);
    98103        viewDetails.setActionCommand("show");
    99         quickInfoPanel.add(viewDetails);
     104        quickInfoPanelButtons.add(viewDetails);
     105
     106        final JButton cacheButton = getClearCacheButton(errorDialog);
     107        cacheButton.setAlignmentY(JComponent.LEFT_ALIGNMENT);
     108        quickInfoPanelButtons.add(cacheButton);
     109
     110        final JButton consoleButton = getShowButton(errorDialog);
     111        consoleButton.setAlignmentY(JComponent.LEFT_ALIGNMENT);
     112        quickInfoPanelButtons.add(consoleButton);
     113
     114        final JPanel fillRest = new JPanel();
     115        fillRest.setAlignmentY(JComponent.LEFT_ALIGNMENT);
     116        quickInfoPanelButtons.add(fillRest);
    100117
    101118        JTextArea textArea = new JTextArea();
     
    125142        errorDialog.pack();
    126143        errorDialog.setResizable(true);
     144        ScreenFinder.centerWindowsToCurrentScreen(errorDialog);
    127145        errorDialog.setVisible(true);
    128146        errorDialog.dispose();
    129147    }
     148
     149     public static JButton getShowButton(final Component parent) {
     150        JButton consoleButton = new JButton();
     151        consoleButton.setText(R("DPJavaConsole"));
     152        consoleButton.addActionListener(new java.awt.event.ActionListener() {
     153
     154            @Override
     155            public void actionPerformed(java.awt.event.ActionEvent evt) {
     156                try {
     157                    JavaConsole.getConsole().showConsoleLater(true);
     158                } catch (Exception ex) {
     159                    OutputController.getLogger().log(OutputController.Level.ERROR_ALL, ex);
     160                    JOptionPane.showConfirmDialog(parent, ex);
     161                }
     162            }
     163        });
     164        if (!JavaConsole.isEnabled()) {
     165            consoleButton.setEnabled(false);
     166            consoleButton.setToolTipText(R("DPJavaConsoleDisabledHint"));
     167        }
     168        return consoleButton;
     169    }
     170
     171    public static JButton getClearCacheButton(final Component parent) {
     172        JButton clearAllButton = new JButton();
     173        clearAllButton.setText(R("CVCPCleanCache"));
     174        clearAllButton.setToolTipText(R("CVCPCleanCacheTip"));
     175        clearAllButton.addActionListener(new java.awt.event.ActionListener() {
     176
     177            @Override
     178            public void actionPerformed(java.awt.event.ActionEvent evt) {
     179                SwingUtilities.invokeLater(new Runnable() {
     180
     181                    @Override
     182                    public void run() {
     183                        try {
     184                            CachePane.visualCleanCache(parent);
     185                        } catch (Exception ex) {
     186                            OutputController.getLogger().log(OutputController.Level.ERROR_DEBUG, ex);
     187                        }
     188                    }
     189                });
     190            }
     191        });
     192        return clearAllButton;
     193    }
    130194}
  • trunk/icedtea-web/netx/net/sourceforge/jnlp/util/FileUtils.java

    r396 r429  
    1717package net.sourceforge.jnlp.util;
    1818
     19import java.awt.Component;
    1920import static net.sourceforge.jnlp.runtime.Translator.R;
    2021
     22import java.awt.Window;
     23import java.io.BufferedReader;
     24import java.io.BufferedWriter;
    2125import java.io.File;
     26import java.io.FileInputStream;
    2227import java.io.FileNotFoundException;
     28import java.io.FileOutputStream;
    2329import java.io.IOException;
     30import java.io.InputStream;
     31import java.io.InputStreamReader;
     32import java.io.OutputStreamWriter;
    2433import java.io.RandomAccessFile;
     34import java.io.Writer;
    2535import java.nio.channels.FileChannel;
    2636import java.nio.channels.FileLock;
     37import java.security.DigestInputStream;
     38import java.security.MessageDigest;
     39import java.security.NoSuchAlgorithmException;
     40import java.util.ArrayList;
     41import java.util.List;
    2742
    2843import net.sourceforge.jnlp.config.Defaults;
     44import javax.swing.JFrame;
     45import javax.swing.JOptionPane;
     46import javax.swing.SwingUtilities;
     47
     48import net.sourceforge.jnlp.config.DirectoryValidator;
     49import net.sourceforge.jnlp.config.DirectoryValidator.DirectoryCheckResults;
    2950import net.sourceforge.jnlp.runtime.JNLPRuntime;
     51import net.sourceforge.jnlp.util.logging.OutputController;
    3052
    3153/**
     
    3658
    3759public final class FileUtils {
     60
     61    /**
     62     * Indicates whether a file was successfully opened. If not, provides specific reasons
     63     * along with a general failure case
     64     */
     65    public enum OpenFileResult {
     66        /** The file was successfully opened */
     67        SUCCESS,
     68        /** The file could not be opened, for non-specified reasons */
     69        FAILURE,
     70        /** The file could not be opened because it did not exist and could not be created */
     71        CANT_CREATE,
     72        /** The file can be opened but in read-only */
     73        CANT_WRITE,
     74        /** The specified path pointed to a non-file filesystem object, ie a directory */
     75        NOT_FILE;
     76    }
    3877
    3978    /**
     
    140179        if (f.exists()) {
    141180            if (!f.delete()) {
    142                 System.err.println(R("RCantDeleteFile", eMsg == null ? f : eMsg));
     181                OutputController.getLogger().log(OutputController.Level.ERROR_ALL, R("RCantDeleteFile", eMsg == null ? f : eMsg));
    143182            }
    144183        }
     
    178217        }
    179218
     219        if (JNLPRuntime.isWindows()) {
     220            // remove all permissions
     221            if (!tempFile.setExecutable(false, false)) {
     222                OutputController.getLogger().log(OutputController.Level.ERROR_ALL, R("RRemoveXPermFailed", tempFile));
     223            }
     224            if (!tempFile.setReadable(false, false)) {
     225                OutputController.getLogger().log(OutputController.Level.ERROR_ALL, R("RRemoveRPermFailed", tempFile));
     226            }
     227            if (!tempFile.setWritable(false, false)) {
     228                OutputController.getLogger().log(OutputController.Level.ERROR_ALL, R("RRemoveWPermFailed", tempFile));
     229            }
     230
     231            // allow owner to read
     232            if (!tempFile.setReadable(true, true)) {
     233                OutputController.getLogger().log(OutputController.Level.ERROR_ALL, R("RGetRPermFailed", tempFile));
     234            }
     235
     236            // allow owner to write
     237            if (writableByOwner && !tempFile.setWritable(true, true)) {
     238                OutputController.getLogger().log(OutputController.Level.ERROR_ALL, R("RGetWPermFailed", tempFile));
     239            }
     240
     241            // allow owner to enter directories
     242            if (isDir && !tempFile.setExecutable(true, true)) {
     243                OutputController.getLogger().log(OutputController.Level.ERROR_ALL, R("RGetXPermFailed", tempFile));
     244            }
     245            // rename this file. Unless the file is moved/renamed, any program that
     246            // opened the file right after it was created might still be able to
     247            // read the data.
     248            if (!tempFile.renameTo(file)) {
     249                OutputController.getLogger().log(OutputController.Level.ERROR_ALL, R("RCantRename", tempFile, file));
     250            }
     251        } else {
    180252        // remove all permissions
    181253        if (!Defaults.OS_DOS_LIKE) {
     
    205277            throw new IOException(R("RGetXPermFailed", tempFile));
    206278        }
    207 
     279       
    208280        // rename this file. Unless the file is moved/renamed, any program that
    209281        // opened the file right after it was created might still be able to
     
    217289            throw new IOException(R("RCantRename", tempFile, file));
    218290        }
    219 
     291        }
     292
     293    }
     294
     295    /**
     296     * Ensure that the parent directory of the file exists and that we are
     297     * able to create and access files within this directory
     298     * @param file the {@link File} representing a Java Policy file to test
     299     * @return a {@link DirectoryCheckResults} object representing the results of the test
     300     */
     301    public static DirectoryCheckResults testDirectoryPermissions(File file) {
     302        try {
     303            file = file.getCanonicalFile();
     304        } catch (final IOException e) {
     305            OutputController.getLogger().log(e);
     306            return null;
     307        }
     308        if (file == null || file.getParentFile() == null || !file.getParentFile().exists()) {
     309            return null;
     310        }
     311        final List<File> policyDirectory = new ArrayList<File>();
     312        policyDirectory.add(file.getParentFile());
     313        final DirectoryValidator validator = new DirectoryValidator(policyDirectory);
     314        final DirectoryCheckResults result = validator.ensureDirs();
     315
     316        return result;
     317    }
     318
     319    /**
     320     * Verify that a given file object points to a real, accessible plain file.
     321     * @param file the {@link File} to verify
     322     * @return an {@link OpenFileResult} representing the accessibility level of the file
     323     */
     324    public static OpenFileResult testFilePermissions(File file) {
     325        if (file == null || !file.exists()) {
     326            return OpenFileResult.FAILURE;
     327        }
     328        try {
     329            file = file.getCanonicalFile();
     330        } catch (final IOException e) {
     331            return OpenFileResult.FAILURE;
     332        }
     333        final DirectoryCheckResults dcr = FileUtils.testDirectoryPermissions(file);
     334        if (dcr != null && dcr.getFailures() == 0) {
     335            if (file.isDirectory())
     336                return OpenFileResult.NOT_FILE;
     337            try {
     338                if (!file.exists() && !file.createNewFile()) {
     339                    return OpenFileResult.CANT_CREATE;
     340                }
     341            } catch (IOException e) {
     342                return OpenFileResult.CANT_CREATE;
     343            }
     344            final boolean read = file.canRead(), write = file.canWrite();
     345            if (read && write)
     346                return OpenFileResult.SUCCESS;
     347            else if (read)
     348                return OpenFileResult.CANT_WRITE;
     349            else
     350                return OpenFileResult.FAILURE;
     351        }
     352        return OpenFileResult.FAILURE;
     353    }
     354
     355    /**
     356     * Show a dialog informing the user that the file is currently read-only
     357     * @param frame a {@link JFrame} to act as parent to this dialog
     358     */
     359    public static void showReadOnlyDialog(final Component frame) {
     360        SwingUtilities.invokeLater(new Runnable() {
     361            @Override
     362            public void run() {
     363                JOptionPane.showMessageDialog(frame, R("RFileReadOnly"), R("Warning"), JOptionPane.WARNING_MESSAGE);
     364            }
     365        });
     366    }
     367
     368    /**
     369     * Show a generic error dialog indicating the  file could not be opened
     370     * @param frame a {@link JFrame} to act as parent to this dialog
     371     * @param filePath a {@link String} representing the path to the file we failed to open
     372     */
     373    public static void showCouldNotOpenFilepathDialog(final Component frame, final String filePath) {
     374        showCouldNotOpenDialog(frame, R("RCantOpenFile", filePath));
     375    }
     376
     377    /**
     378     * Show an error dialog indicating the file could not be opened, with a particular reason
     379     * @param frame a {@link JFrame} to act as parent to this dialog
     380     * @param filePath a {@link String} representing the path to the file we failed to open
     381     * @param reason a {@link OpenFileResult} specifying more precisely why we failed to open the file
     382     */
     383    public static void showCouldNotOpenFileDialog(final Component frame, final String filePath, final OpenFileResult reason) {
     384        final String message;
     385        switch (reason) {
     386            case CANT_CREATE:
     387                message = R("RCantCreateFile", filePath);
     388                break;
     389            case CANT_WRITE:
     390                message = R("RCantWriteFile", filePath);
     391                break;
     392            case NOT_FILE:
     393                message = R("RExpectedFile", filePath);
     394                break;
     395            default:
     396                message = R("RCantOpenFile", filePath);
     397                break;
     398        }
     399        showCouldNotOpenDialog(frame, message);
     400    }
     401
     402    /**
     403     * Show a dialog informing the user that the file could not be opened
     404     * @param frame a {@link JFrame} to act as parent to this dialog
     405     * @param filePath a {@link String} representing the path to the file we failed to open
     406     * @param message a {@link String} giving the specific reason the file could not be opened
     407     */
     408    public static void showCouldNotOpenDialog(final Component frame, final String message) {
     409        SwingUtilities.invokeLater(new Runnable() {
     410            @Override
     411            public void run() {
     412                JOptionPane.showMessageDialog(frame, message, R("Error"), JOptionPane.ERROR_MESSAGE);
     413            }
     414        });
    220415    }
    221416
     
    284479     */
    285480    public static void recursiveDelete(File file, File base) throws IOException {
    286         if (JNLPRuntime.isDebug()) {
    287             System.err.println("Deleting: " + file);
    288         }
     481        OutputController.getLogger().log(OutputController.Level.ERROR_DEBUG, "Deleting: " + file);
    289482
    290483        if (!(file.getCanonicalPath().startsWith(base.getCanonicalPath()))) {
     
    342535            }
    343536        } catch (IOException e) {
    344             e.printStackTrace();
     537            OutputController.getLogger().log(OutputController.Level.ERROR_ALL, e);
    345538        }
    346539        return lock;
    347540    }
     541
     542    /**
     543     * helping dummy  method to save String as file
     544     *
     545     * @param content
     546     * @param f
     547     * @throws IOException
     548     */
     549    public static void saveFile(String content, File f) throws IOException {
     550        saveFile(content, f, "utf-8");
     551    }
     552
     553    public static void saveFile(String content, File f, String encoding) throws IOException {
     554        Writer output = new BufferedWriter(new OutputStreamWriter(new FileOutputStream(f), encoding));
     555        output.write(content);
     556        output.flush();
     557        output.close();
     558    }
     559
     560    /**
     561     * utility method which can read from any stream as one long String
     562     *
     563     * @param is stream
     564     * @param encoding the encoding to use to convert the bytes from the stream
     565     * @return stream as string
     566     * @throws IOException if connection can't be established or resource does not exist
     567     */
     568    public static String getContentOfStream(InputStream is, String encoding) throws IOException {
     569        try {
     570            BufferedReader br = new BufferedReader(new InputStreamReader(is, encoding));
     571            StringBuilder sb = new StringBuilder();
     572            while (true) {
     573                String s = br.readLine();
     574                if (s == null) {
     575                    break;
     576                }
     577                sb.append(s).append("\n");
     578
     579            }
     580            return sb.toString();
     581        } finally {
     582            is.close();
     583        }
     584
     585    }
     586
     587    /**
     588     * utility method which can read from any stream as one long String
     589     *
     590     * @param is stream
     591     * @return stream as string
     592     * @throws IOException if connection can't be established or resource does not exist
     593     */
     594    public static String getContentOfStream(InputStream is) throws IOException {
     595        return getContentOfStream(is, "UTF-8");
     596
     597    }
     598
     599    public static String loadFileAsString(File f) throws IOException {
     600        return getContentOfStream(new FileInputStream(f));
     601    }
     602
     603    public static String loadFileAsString(File f, String encoding) throws IOException {
     604        return getContentOfStream(new FileInputStream(f), encoding);
     605    }
     606
     607    public static byte[] getFileMD5Sum(final File file, final String algorithm) throws NoSuchAlgorithmException,
     608            FileNotFoundException, IOException {
     609        final MessageDigest md5;
     610        InputStream is = null;
     611        DigestInputStream dis = null;
     612        try {
     613            md5 = MessageDigest.getInstance(algorithm);
     614            is = new FileInputStream(file);
     615            dis = new DigestInputStream(is, md5);
     616
     617            md5.update(getContentOfStream(dis).getBytes());
     618        } finally {
     619            if (is != null) {
     620                is.close();
     621            }
     622            if (dis != null) {
     623                dis.close();
     624            }
     625        }
     626
     627        return md5.digest();
     628    }
    348629}
  • trunk/icedtea-web/netx/net/sourceforge/jnlp/util/ImageResources.java

    r418 r429  
    3838package net.sourceforge.jnlp.util;
    3939
     40import net.sourceforge.jnlp.util.logging.OutputController;
    4041import java.awt.Image;
    4142import java.io.IOException;
     
    8283            return image;
    8384        } catch (IOException ioe) {
    84             ioe.printStackTrace();
     85            OutputController.getLogger().log(OutputController.Level.ERROR_ALL, ioe);
    8586            return null;
    8687        }
  • trunk/icedtea-web/netx/net/sourceforge/jnlp/util/PropertiesFile.java

    r418 r429  
    1717package net.sourceforge.jnlp.util;
    1818
     19import net.sourceforge.jnlp.util.logging.OutputController;
    1920import java.io.*;
    2021import java.util.*;
     
    2425 * exceptions.  The properties are automatically loaded from the
    2526 * file when the first property is requested, but the save method
    26  * must be called before changes are saved to the file.<p>
     27 * must be called before changes are saved to the file.
    2728 *
    2829 * @author <a href="mailto:jmaxwell@users.sourceforge.net">Jon A. Maxwell (JAM)</a> - initial author
     
    139140                }
    140141            } catch (IOException ex) {
    141                 ex.printStackTrace();
     142                OutputController.getLogger().log(OutputController.Level.ERROR_ALL, ex);
    142143            }
    143144        }
     
    165166            }
    166167        } catch (IOException ex) {
    167             ex.printStackTrace();
     168            OutputController.getLogger().log(OutputController.Level.ERROR_ALL, ex);
    168169        }
    169170    }
  • trunk/icedtea-web/netx/net/sourceforge/jnlp/util/Reflect.java

    r348 r429  
    1717package net.sourceforge.jnlp.util;
    1818
    19 import java.lang.reflect.*;
     19import java.lang.reflect.Method;
     20import net.sourceforge.jnlp.util.logging.OutputController;
     21
    2022
    2123/**
    2224 * Provides simply, convenient methods to invoke methods by
    23  * name.  This class is used to consolidate reflection needed to
     25 * name. This class is used to consolidate reflection needed to
    2426 * access methods specific to Sun's JVM or to remain backward
    25  * compatible while supporting method in newer JVMs.<p>
    26  *
     27 * compatible while supporting method in newer JVMs.
     28 * <p>
    2729 * Most methods of this class invoke the first method on the
    2830 * specified object that matches the name and number of
    29  * parameters.  The type of the parameters are not considered, so
     31 * parameters. The type of the parameters are not considered, so
    3032 * do not attempt to use this class to invoke overloaded
    31  * methods.<p>
    32  *
    33  * Instances of this class are not synchronized.<p>
     33 * methods.
     34 * </p>
     35 * <p>
     36 * Instances of this class are not synchronized.
     37 * </p>
    3438 *
    3539 * @author <a href="mailto:jon.maxwell@acm.org">Jon A. Maxwell (JAM)</a> - initial author
     
    7579    public Object invokeStatic(String className, String method, Object args[]) {
    7680        try {
    77             Class c = Class.forName(className, true, Reflect.class.getClassLoader());
     81            Class<?> c = Class.forName(className, true, Reflect.class.getClassLoader());
    7882
    7983            Method m = getMethod(c, method, args);
    80             if (m.isAccessible() != accessible)
     84            if (m.isAccessible() != accessible) {
    8185                m.setAccessible(accessible);
     86            }
    8287
    8388            return m.invoke(null, args);
     
    103108        try {
    104109            Method m = getMethod(object.getClass(), method, args);
    105             if (m.isAccessible() != accessible)
     110            if (m.isAccessible() != accessible) {
    106111                m.setAccessible(accessible);
     112            }
    107113
    108114            return m.invoke(object, args);
    109115        } catch (Exception ex) { // eat
    110             ex.printStackTrace();
     116            OutputController.getLogger().log(OutputController.Level.ERROR_ALL, ex);
    111117            return null;
    112118        }
     
    117123     * arguments.
    118124     */
    119     public Method getMethod(Class type, String method, Object args[]) {
     125    public Method getMethod(Class<?> type, String method, Object args[]) {
    120126        try {
    121             for (Class c = type; c != null; c = c.getSuperclass()) {
     127            for (Class<?> c = type; c != null; c = c.getSuperclass()) {
    122128                Method methods[] = c.getMethods();
    123129
     
    126132                        Class parameters[] = methods[i].getParameterTypes();
    127133
    128                         if (parameters.length == args.length)
     134                        if (parameters.length == args.length) {
    129135                            return methods[i];
     136                        }
    130137                    }
    131138                }
    132139            }
    133140        } catch (Exception ex) { // eat
    134             ex.printStackTrace();
     141            OutputController.getLogger().log(OutputController.Level.ERROR_ALL, ex);
    135142        }
    136143
  • trunk/icedtea-web/netx/net/sourceforge/jnlp/util/TimedHashMap.java

    r348 r429  
    3838package net.sourceforge.jnlp.util;
    3939
     40import net.sourceforge.jnlp.util.logging.OutputController;
    4041import java.util.HashMap;
    4142
     
    8384            // Item exists. If it has not expired, renew its access time and return it
    8485            if (age <= expiry) {
    85                 if (JNLPRuntime.isDebug()) {
    86                     System.err.println("Returning proxy " + actualMap.get(key) + " from cache for " + key);
    87                 }
     86                OutputController.getLogger().log(OutputController.Level.ERROR_DEBUG, "Returning proxy " + actualMap.get(key) + " from cache for " + key);
    8887                timeStamps.put(key, System.nanoTime());
    8988                return actualMap.get(key);
    9089            } else {
    91                 if (JNLPRuntime.isDebug()) {
    92                     System.err.println("Proxy cache for " + key + " has expired (age=" + (age * 1e-9) + " seconds)");
    93                 }
     90                OutputController.getLogger().log(OutputController.Level.ERROR_DEBUG, "Proxy cache for " + key + " has expired (age=" + (age * 1e-9) + " seconds)");
    9491            }
    9592        }
  • trunk/icedtea-web/netx/net/sourceforge/jnlp/util/UrlUtils.java

    r348 r429  
    3838package net.sourceforge.jnlp.util;
    3939
     40import net.sourceforge.jnlp.util.logging.OutputController;
     41import java.io.File;
     42import java.io.IOException;
     43import java.io.UnsupportedEncodingException;
     44import java.net.MalformedURLException;
     45import java.net.URI;
     46import java.net.URISyntaxException;
    4047import java.net.URL;
     48import java.net.URLDecoder;
     49import net.sourceforge.jnlp.JNLPFile;
    4150
    4251public class UrlUtils {
     52    private static final String UTF8 = "utf-8";
     53
     54    public static URL normalizeUrlAndStripParams(URL url, boolean encodeFileUrls) {
     55        try {
     56            String[] urlParts = url.toString().split("\\?");
     57            URL strippedUrl = new URL(urlParts[0]);
     58            return normalizeUrl(strippedUrl, encodeFileUrls);
     59        } catch (IOException e) {
     60            OutputController.getLogger().log(OutputController.Level.ERROR_ALL, e);
     61        } catch (URISyntaxException e) {
     62            OutputController.getLogger().log(OutputController.Level.ERROR_ALL, e);
     63        }
     64        return url;
     65    }
     66
     67    public static URL normalizeUrlAndStripParams(URL url) {
     68        return normalizeUrlAndStripParams(url, false);
     69    }
    4370
    4471    public static boolean isLocalFile(URL url) {
     
    5178        return false;
    5279    }
     80
     81    /* Decode a percent-encoded URL. Catch checked exceptions and log. */
     82    public static URL decodeUrlQuietly(URL url) {
     83        try {
     84            return new URL(URLDecoder.decode(url.toString(), UTF8));
     85        } catch (IOException e) {
     86            OutputController.getLogger().log(OutputController.Level.ERROR_ALL, e);
     87            return url;
     88        }
     89    }
     90
     91    /* Use the URI syntax check of 'toURI' to see if it matches RFC2396.
     92     * See http://www.ietf.org/rfc/rfc2396.txt */
     93    public static boolean isValidRFC2396Url(URL url) {
     94        try {
     95            url.toURI();
     96            return true;
     97        } catch (URISyntaxException e) {
     98            return false;
     99        }
     100    }
     101
     102    /* Ensure a URL is properly percent-encoded.
     103     * Certain usages require local-file URLs to be encoded, eg for code-base & document-base. */
     104    public static URL normalizeUrl(URL url, boolean encodeFileUrls) throws MalformedURLException, UnsupportedEncodingException, URISyntaxException {
     105        if (url == null) {
     106            return null;
     107        }
     108
     109        String protocol = url.getProtocol();
     110        boolean shouldEncode = (encodeFileUrls || !"file".equals(protocol));
     111
     112        // PR1465: We should not call 'URLDecoder.decode' on RFC2396-compliant URLs
     113        if (protocol == null || !shouldEncode || url.getPath() == null || isValidRFC2396Url(url)) {
     114            return url;
     115        }
     116
     117        //Decode the URL before encoding
     118        URL decodedURL = new URL(URLDecoder.decode(url.toString(), UTF8));
     119
     120        //Create URI with the decoded URL
     121        URI uri = new URI(decodedURL.getProtocol(), null, decodedURL.getHost(), decodedURL.getPort(), decodedURL.getPath(), decodedURL.getQuery(), null);
     122
     123        //Returns the encoded URL
     124        URL encodedURL = new URL(uri.toASCIIString());
     125
     126        return encodedURL;
     127    }
     128
     129    /* Ensure a URL is properly percent-encoded. Does not encode local-file URLs. */
     130    public static URL normalizeUrl(URL url) throws MalformedURLException, UnsupportedEncodingException, URISyntaxException {
     131        return normalizeUrl(url, false);
     132    }
     133
     134    /* Ensure a URL is properly percent-encoded. Catch checked exceptions and log. */
     135    public static URL normalizeUrlQuietly(URL url, boolean encodeFileUrls) {
     136        try {
     137            return normalizeUrl(url, encodeFileUrls);
     138        } catch (MalformedURLException e) {
     139            OutputController.getLogger().log(OutputController.Level.ERROR_ALL, e);
     140        } catch (UnsupportedEncodingException e) {
     141            OutputController.getLogger().log(OutputController.Level.ERROR_ALL, e);
     142        } catch (URISyntaxException e) {
     143            OutputController.getLogger().log(OutputController.Level.ERROR_ALL, e);
     144        }
     145        return url;
     146    }
     147
     148    /* Ensure a URL is properly percent-encoded. Catch checked exceptions and log. */
     149    public static URL normalizeUrlQuietly(URL url) {
     150        return normalizeUrlQuietly(url, false);
     151    }
     152
     153    /* Decode a URL as a file, being tolerant of URLs with mixed encoded & decoded portions. */
     154    public static File decodeUrlAsFile(URL url) {
     155        return new File(decodeUrlQuietly(url).getFile());
     156    }
     157 
     158    /**
     159     * This function i striping part behind last path delimiter.
     160     *
     161     * Expected is input like protcol://som.url/some/path/file.suff
     162     * Then output will bee protcol://som.url/some/path
     163     *
     164     * Be aware of input like  protcol://som.url/some/path/
     165     * then input will be just  protcol://som.url/some/path
     166     *
     167     * You can use sanitizeLastSlash and see also unittests
     168     * Both unix and windows salshes are supported
     169     *
     170     * @param src
     171     * @return
     172     */
     173    public static URL removeFileName(final URL src) {
     174        URL nsrc = normalizeUrlAndStripParams(src);
     175        String s = nsrc.getPath();
     176        int i1 = s.lastIndexOf("/");
     177        int i2 = s.lastIndexOf("\\");
     178        int i = Math.max(i1, i2);
     179        if (i < 0) {
     180            return src;
     181        }
     182        s = s.substring(0, i);
     183        try {
     184            return sanitizeLastSlash(new URL(src.getProtocol(), src.getHost(), src.getPort(), s));
     185        } catch (MalformedURLException ex) {
     186            OutputController.getLogger().log(ex);
     187            return nsrc;
     188        }
     189    }
     190
     191    /**
     192     * Small utility function creating li list from collection of urls
     193     * @param remoteUrls
     194     * @return
     195     */
     196    public static String setOfUrlsToHtmlList(Iterable<URL> remoteUrls) {
     197        StringBuilder sb = new StringBuilder();
     198        sb.append("<ul>");
     199        for (URL url : remoteUrls) {
     200            sb.append("<li>").append(url.toExternalForm()).append("</li>");
     201        }
     202        sb.append("</ul>");
     203        return sb.toString();
     204    }
     205
     206    /**
     207     * This function is removing all tailing slashes of url and
     208     * both unix and windows salshes are supported.
     209     * See tests for valid and invalid inputs/outputs
     210     * Shortly   protcol://som.url/some/path/ or  protcol://som.url/some/path////
     211     * (and same for windows  protcol://som.url/some\path\\) will become  protcol://som.url/some/path
     212     * Even  protcol://som.url/ is reduced to  protcol://som.url
     213     *
     214     *
     215     * When input is like
     216     * @param in
     217     * @return
     218     * @throws MalformedURLException
     219     */
     220    public static URL sanitizeLastSlash(URL in) throws MalformedURLException {
     221        if (in == null) {
     222            return null;
     223        }
     224        String s = sanitizeLastSlash(in.toExternalForm());
     225        return new URL(s);
     226    }
     227
     228    public static String sanitizeLastSlash(final String in) {
     229        if (in == null) {
     230            return null;
     231        }
     232        String s = in;
     233        while (s.endsWith("/") || s.endsWith("\\")) {
     234            s = s.substring(0, s.length() - 1);
     235        }
     236        return s;
     237    }
     238
     239    /**
     240     * both urls are processed by sanitizeLastSlash before actual equals.
     241     * So protcol://som.url/some/path/ is same as protcol://som.url/some/path.
     242     * Even protcol://som.url/some/path\ is same as protcol://som.url/some/path/
     243     *
     244     * @param u1
     245     * @param u2
     246     * @return
     247     */
     248    public static boolean equalsIgnoreLastSlash(URL u1, URL u2) {
     249        try {
     250            if (u1 == null && u2 == null) {
     251                return true;
     252            }
     253            if (u1 == null && u2 != null) {
     254                return false;
     255            }
     256            if (u1 != null && u2 == null) {
     257                return false;
     258            }
     259            return sanitizeLastSlash(u1).equals(sanitizeLastSlash(u2));
     260        } catch (MalformedURLException ex) {
     261            throw new RuntimeException(ex);
     262        }
     263    }
     264
     265     public static URL guessCodeBase(JNLPFile file) {
     266        if (file.getCodeBase() != null) {
     267            return file.getCodeBase();
     268        } else {
     269            //Fixme: codebase should be the codebase of the Main Jar not
     270            //the location. Although, it still works in the current state.
     271            return file.getResources().getMainJAR().getLocation();
     272        }
     273    }
    53274}
  • trunk/icedtea-web/netx/net/sourceforge/jnlp/util/WeakList.java

    r348 r429  
    2626 * may return null).  The weak references are only removed when
    2727 * the trimToSize method is called so that the indices remain
    28  * constant otherwise.<p>
     28 * constant otherwise.
    2929 *
    3030 * @author <a href="mailto:jmaxwell@users.sourceforge.net">Jon A. Maxwell (JAM)</a> - initial author
  • trunk/icedtea-web/netx/net/sourceforge/jnlp/util/XDesktopEntry.java

    r348 r429  
    1717package net.sourceforge.jnlp.util;
    1818
     19import net.sourceforge.jnlp.util.logging.OutputController;
     20import java.io.BufferedReader;
    1921import java.io.File;
    2022import java.io.FileNotFoundException;
    2123import java.io.FileOutputStream;
     24import java.io.FileReader;
    2225import java.io.IOException;
    2326import java.io.OutputStreamWriter;
     
    2629import java.net.URL;
    2730import java.nio.charset.Charset;
     31import java.util.ArrayList;
    2832import java.util.Arrays;
     33import java.util.Collections;
     34import java.util.Comparator;
     35import java.util.List;
     36import java.util.Map;
     37import java.util.Map.Entry;
     38import java.util.Set;
    2939
    3040import net.sourceforge.jnlp.IconDesc;
     
    7989        String fileContents = "[Desktop Entry]\n";
    8090        fileContents += "Version=1.0\n";
    81         fileContents += "Name=" + sanitize(file.getTitle()) + "\n";
     91        fileContents += "Name=" + getDesktopIconName() + "\n";
    8292        fileContents += "GenericName=Java Web Start Application\n";
    8393        fileContents += "Comment=" + sanitize(file.getInformation().getDescription()) + "\n";
     
    93103        }
    94104
    95         //Shortcut executes the jnlp from cache and system preferred java..
    96         fileContents += "Exec=" + "javaws" + " \"" + cacheFile.getAbsolutePath() + "\"\n";
     105        //Shortcut executes the jnlp as it was with system preferred java. It should work fine offline
     106        fileContents += "Exec=" + "javaws" + " \"" + file.getSourceLocation() + "\"\n";
    97107
    98108        return new StringReader(fileContents);
     
    123133    }
    124134
     135    public File getShortcutTmpFile() {
     136        String userTmp = JNLPRuntime.getConfiguration().getProperty(DeploymentConfiguration.KEY_USER_TMP_DIR);
     137        File shortcutFile = new File(userTmp + File.separator + FileUtils.sanitizeFileName(file.getTitle()) + ".desktop");
     138        return shortcutFile;
     139    }
     140
    125141    /**
    126142     * Set the icon size to use for the desktop shortcut
     
    141157            installDesktopLauncher();
    142158        } catch (Exception e) {
    143             e.printStackTrace();
     159            OutputController.getLogger().log(OutputController.Level.ERROR_ALL, e);
    144160        }
    145161    }
     
    149165     */
    150166    private void installDesktopLauncher() {
    151         File shortcutFile = new File(JNLPRuntime.getConfiguration()
    152                 .getProperty(DeploymentConfiguration.KEY_USER_TMP_DIR)
    153                 + File.separator + FileUtils.sanitizeFileName(file.getTitle()) + ".desktop");
     167        File shortcutFile = getShortcutTmpFile();
    154168        try {
    155169
     
    183197            String[] execString = new String[] { "xdg-desktop-icon", "install", "--novendor",
    184198                    shortcutFile.getCanonicalPath() };
    185             if (JNLPRuntime.isDebug()) {
    186                 System.err.println("Execing: " + Arrays.toString(execString));
    187             }
     199            OutputController.getLogger().log(OutputController.Level.ERROR_DEBUG, "Execing: " + Arrays.toString(execString));
    188200            Process installer = Runtime.getRuntime().exec(execString);
    189201            new StreamEater(installer.getInputStream()).start();
     
    193205                installer.waitFor();
    194206            } catch (InterruptedException e) {
    195                 e.printStackTrace();
     207                OutputController.getLogger().log(OutputController.Level.ERROR_ALL, e);
    196208            }
    197209
     
    201213
    202214        } catch (FileNotFoundException e) {
    203             e.printStackTrace();
     215            OutputController.getLogger().log(OutputController.Level.ERROR_ALL, e);
    204216        } catch (IOException e) {
    205             e.printStackTrace();
     217            OutputController.getLogger().log(OutputController.Level.ERROR_ALL, e);
    206218        }
    207219    }
     
    229241            this.iconLocation = location.substring("file:".length());
    230242
    231             if (JNLPRuntime.isDebug()) {
    232                 System.err.println("Cached desktop shortcut icon: " + this.iconLocation);
    233             }
    234         }
    235     }
    236 
     243            OutputController.getLogger().log(OutputController.Level.ERROR_DEBUG, "Cached desktop shortcut icon: " + this.iconLocation);
     244        }
     245    }
     246
     247    public String getDesktopIconName() {
     248        return sanitize(file.getTitle());
     249    }
     250
     251    public File getLinuxDesktopIconFile() {
     252        return new File(findFreedesktopOrgDesktopPathCatch() + "/" + getDesktopIconName() + ".desktop");
     253    }
     254
     255    private static String findFreedesktopOrgDesktopPathCatch() {
     256        try {
     257            return findFreedesktopOrgDesktopPath();
     258        } catch (Exception ex) {
     259            OutputController.getLogger().log(OutputController.Level.ERROR_ALL, ex);
     260            return System.getProperty("user.home") + "/Desktop/";
     261        }
     262    }
     263
     264    /**
     265     * Instead of having all this parsing of user-dirs.dirs and replacing
     266     * variables we can execute `echo $(xdg-user-dir DESKTOP)` and it will do
     267     * all the job in case approaches below become failing
     268     *
     269     * @return variables (if declared) and quotation marks (unless escaped) free
     270     * path
     271     * @throws IOException if no file do not exists or key with desktop do not
     272     * exists
     273     */
     274    private static String findFreedesktopOrgDesktopPath() throws IOException {
     275        File userDirs = new File(System.getProperty("user.home") + "/.config/user-dirs.dirs");
     276        if (!userDirs.exists()) {
     277            return System.getProperty("user.home") + "/Desktop/";
     278        }
     279        return getFreedesktopOrgDesktopPathFrom(userDirs);
     280    }
     281
     282    private static String getFreedesktopOrgDesktopPathFrom(File userDirs) throws IOException {
     283        BufferedReader r = new BufferedReader(new FileReader(userDirs));
     284        try {
     285            return getFreedesktopOrgDesktopPathFrom(r);
     286        } finally {
     287            r.close();
     288        }
     289
     290    }
     291    static final String XDG_DESKTOP_DIR = "XDG_DESKTOP_DIR";
     292
     293    static String getFreedesktopOrgDesktopPathFrom(BufferedReader r) throws IOException {
     294        while (true) {
     295            String s = r.readLine();
     296            if (s == null) {
     297                throw new IOException("End of user-dirs found, but no " + XDG_DESKTOP_DIR + " key found");
     298            }
     299            s = s.trim();
     300            if (s.startsWith(XDG_DESKTOP_DIR)) {
     301                if (!s.contains("=")) {
     302                    throw new IOException(XDG_DESKTOP_DIR + " has no value");
     303                }
     304                String[] keyAndValue = s.split("=");
     305                keyAndValue[1] = keyAndValue[1].trim();
     306                String filteredQuotes = filterQuotes(keyAndValue[1]);
     307                return evaluateLinuxVariables(filteredQuotes);
     308            }
     309        }
     310    }
     311    private static final String MIC = "MAGIC_QUOTIN_ITW_CONSTANT_FOR_DUMMIES";
     312
     313    private static String filterQuotes(String string) {
     314        //get rid of " but not of
     315        String s = string.replaceAll("\\\\\"", MIC);
     316        s = s.replaceAll("\"", "");
     317        s = s.replaceAll(MIC, "\\\"");
     318        return s;
     319    }
     320
     321    private static String evaluateLinuxVariables(String orig) {
     322        return evaluateLinuxVariables(orig, System.getenv());
     323    }
     324
     325    private static String evaluateLinuxVariables(String orig, Map<String, String> variables) {
     326        Set<Entry<String, String>> env = variables.entrySet();
     327        List<Entry<String, String>> envVariables = new ArrayList<Entry<String, String>>(env);
     328        Collections.sort(envVariables, new Comparator<Entry<String, String>>() {
     329            @Override
     330            public int compare(Entry<String, String> o1, Entry<String, String> o2) {
     331                return o2.getKey().length() - o1.getKey().length();
     332            }
     333        });
     334        while (true) {
     335            String before = orig;
     336            for (Entry<String, String> entry : envVariables) {
     337                orig = orig.replaceAll("\\$" + entry.getKey(), entry.getValue());
     338            }
     339            if (before.equals(orig)) {
     340                return orig;
     341            }
     342        }
     343
     344    }
    237345}
  • trunk/icedtea-web/netx/net/sourceforge/jnlp/util/replacements/CharacterEncoder.java

    r418 r429  
    4040 * data into text (generally 7 bit ASCII or 8 bit ISO-Latin-1 text)
    4141 * for transmition over text channels such as e-mail and network news.
    42  *
     42 * <p>
    4343 * The character encoders have been structured around a central theme
    4444 * that, in general, the encoded text has the form:
    45  *
    46  * <pre>
     45 * <pre><code>
    4746 *      [Buffer Prefix]
    4847 *      [Line Prefix][encoded data atoms][Line Suffix]
    4948 *      [Buffer Suffix]
    50  * </pre>
    51  *
    52  * In the CharacterEncoder and CharacterDecoder classes, one complete
    53  * chunk of data is referred to as a <i>buffer</i>. Encoded buffers
    54  * are all text, and decoded buffers (sometimes just referred to as
    55  * buffers) are binary octets.
    56  *
    57  * To create a custom encoder, you must, at a minimum,  overide three
     49 * </code></pre>
     50 * </p>
     51 * <p>
     52 * In the {@code CharacterEncoder} and {@link CharacterDecoder}
     53 * classes, one complete chunk of data is referred to as a
     54 * <i>buffer</i>. Encoded buffers are all text, and decoded buffers
     55 * (sometimes just referred to as buffers) are binary octets.
     56 * </p>
     57 * <p>
     58 * To create a custom encoder, you must, at a minimum, overide three
    5859 * abstract methods in this class.
    59  * <DL>
    60  * <DD>bytesPerAtom which tells the encoder how many bytes to
     60 * <dl>
     61 * <dd/>bytesPerAtom which tells the encoder how many bytes to
    6162 * send to encodeAtom
    62  * <DD>encodeAtom which encodes the bytes sent to it as text.
    63  * <DD>bytesPerLine which tells the encoder the maximum number of
     63 * <dd/>encodeAtom which encodes the bytes sent to it as text.
     64 * <dd/>bytesPerLine which tells the encoder the maximum number of
    6465 * bytes per line.
    65  * </DL>
    66  *
     66 * </dl>
     67 * </p>
     68 * <p>
    6769 * Several useful encoders have already been written and are
    6870 * referenced in the See Also list below.
    69  *
     71 * </p>
    7072 * @author      Chuck McManis
    71  * @see         CharacterDecoder;
    72  * @see         UCEncoder
    73  * @see         UUEncoder
     73 * @see         CharacterDecoder
    7474 * @see         BASE64Encoder
    7575 */
     
    201201    /**
    202202     * Return a byte array from the remaining bytes in this ByteBuffer.
    203      * <P>
    204      * The ByteBuffer's position will be advanced to ByteBuffer's limit.
    205      * <P>
     203     * <p>
     204     * The ByteBuffer's position will be advanced to ByteBuffer's limit.
     205     * </p>
     206     * <p>
    206207     * To avoid an extra copy, the implementation will attempt to return the
    207208     * byte array backing the ByteBuffer.  If this is not possible, a
    208209     * new byte array will be created.
     210     * </p>
    209211     */
    210212    private byte [] getBytes(ByteBuffer bb) {
     
    248250     * Encode the <i>aBuffer</i> ByteBuffer and write the encoded
    249251     * result to the OutputStream <i>aStream</i>.
    250      * <P>
    251      * The ByteBuffer's position will be advanced to ByteBuffer's limit.
     252     * <p>
     253     * The ByteBuffer's position will be advanced to ByteBuffer's limit.
     254     * </p>
    252255     */
    253256    public void encode(ByteBuffer aBuffer, OutputStream aStream)
     
    260263     * A 'streamless' version of encode that simply takes a ByteBuffer
    261264     * and returns a string containing the encoded buffer.
    262      * <P>
    263      * The ByteBuffer's position will be advanced to ByteBuffer's limit.
     265     * <p>
     266     * The ByteBuffer's position will be advanced to ByteBuffer's limit.
     267     * </p>
    264268     */
    265269    public String encode(ByteBuffer aBuffer) {
     
    332336     * Encode the <i>aBuffer</i> ByteBuffer and write the encoded
    333337     * result to the OutputStream <i>aStream</i>.
    334      * <P>
    335      * The ByteBuffer's position will be advanced to ByteBuffer's limit.
     338     * <p>
     339     * The ByteBuffer's position will be advanced to ByteBuffer's limit.
     340     * </p>
    336341     */
    337342    public void encodeBuffer(ByteBuffer aBuffer, OutputStream aStream)
     
    344349     * A 'streamless' version of encode that simply takes a ByteBuffer
    345350     * and returns a string containing the encoded buffer.
    346      * <P>
    347      * The ByteBuffer's position will be advanced to ByteBuffer's limit.
     351     * <p>
     352     * The ByteBuffer's position will be advanced to ByteBuffer's limit.
     353     * </p>
    348354     */
    349355    public String encodeBuffer(ByteBuffer aBuffer) {
  • trunk/icedtea-web/netx/net/sourceforge/nanoxml/XMLElement.java

    r418 r429  
    3535
    3636import net.sourceforge.jnlp.runtime.JNLPRuntime;
     37import net.sourceforge.jnlp.util.logging.OutputController;
    3738
    3839/**
    3940 * XMLElement is a representation of an XML object. The object is able to parse
    4041 * XML code.
    41  * <P><DL>
    42  * <DT><B>Parsing XML Data</B></DT>
    43  * <DD>
     42 * <p><dl>
     43 * <dt><b>Parsing XML Data</b></dt>
     44 * <dd>
    4445 * You can parse XML data using the following code:
    45  * <UL><CODE>
    46  * XMLElement xml = new XMLElement();<BR>
    47  * FileReader reader = new FileReader("filename.xml");<BR>
    48  * xml.parseFromReader(reader);
    49  * </CODE></UL></DD></DL>
    50  * <DL><DT><B>Retrieving Attributes</B></DT>
    51  * <DD>
     46 * <pre>{@code
     47 *XMLElement xml = new XMLElement();
     48 *FileReader reader = new FileReader("filename.xml");
     49 *xml.parseFromReader(reader);
     50 *}</pre></dd></dl>
     51 * <dl><dt><b>Retrieving Attributes</b></dt>
     52 * <dd>
    5253 * You can enumerate the attributes of an element using the method
    5354 * {@link #enumerateAttributeNames() enumerateAttributeNames}.
     
    5556 * {@link #getAttribute(java.lang.String) getAttribute}.
    5657 * The following example shows how to list the attributes of an element:
    57  * <UL><CODE>
    58  * XMLElement element = ...;<BR>
    59  * Enumeration enum = element.enumerateAttributeNames();<BR>
    60  * while (enum.hasMoreElements()) {<BR>
    61  * &nbsp;&nbsp;&nbsp;&nbsp;String key = (String) enum.nextElement();<BR>
    62  * &nbsp;&nbsp;&nbsp;&nbsp;String value = (String) element.getAttribute(key);<BR>
    63  * &nbsp;&nbsp;&nbsp;&nbsp;System.out.println(key + " = " + value);<BR>
    64  * }
    65  * </CODE></UL></DD></DL>
    66  * <DL><DT><B>Retrieving Child Elements</B></DT>
    67  * <DD>
     58 * <pre>{@code
     59 *XMLElement element = ...;
     60 *Enumeration enum = element.enumerateAttributeNames();
     61 *while (enum.hasMoreElements()) {
     62 *    String key = (String) enum.nextElement();
     63 *    String value = (String) element.getAttribute(key);
     64 *    System.out.println(key + " = " + value);
     65 *}}</pre></dd></dl>
     66 * <dl><dt><b>Retrieving Child Elements</b></dt>
     67 * <dd>
    6868 * You can enumerate the children of an element using
    6969 * {@link #enumerateChildren() enumerateChildren}.
    7070 * The number of child elements can be retrieved using
    7171 * {@link #countChildren() countChildren}.
    72  * </DD></DL>
    73  * <DL><DT><B>Elements Containing Character Data</B></DT>
    74  * <DD>
     72 * </dd></dl>
     73 * <dl><dt><b>Elements Containing Character Data</b></dt>
     74 * <dd>
    7575 * If an elements contains character data, like in the following example:
    76  * <UL><CODE>
    77  * &lt;title&gt;The Title&lt;/title&gt;
    78  * </CODE></UL>
     76 * <pre>{@code <title>The Title</title>}</pre>
    7977 * you can retrieve that data using the method
    8078 * {@link #getContent() getContent}.
    81  * </DD></DL>
    82  * <DL><DT><B>Subclassing XMLElement</B></DT>
    83  * <DD>
     79 * </dd></dl>
     80 * <dl><dt><b>Subclassing XMLElement</b></dt>
     81 * <dd>
    8482 * When subclassing XMLElement, you need to override the method
    8583 * {@link #createAnotherElement() createAnotherElement}
    8684 * which has to return a new copy of the receiver.
    87  * </DD></DL>
    88  * <P>
     85 * </dd></dl>
     86 * </p>
    8987 *
    9088 * @see net.sourceforge.nanoxml.XMLParseException
     
    10098     *
    10199     * <dl><dt><b>Invariants:</b></dt><dd>
    102      * <ul><li>The field can be empty.
    103      *     <li>The field is never <code>null</code>.
    104      *     <li>The keys and the values are strings.
     100     * <ul><li>The field can be empty.</li>
     101     *     <li>The field is never {@code null}.</li>
     102     *     <li>The keys and the values are strings.</li>
    105103     * </ul></dd></dl>
    106104     */
     
    111109     *
    112110     * <dl><dt><b>Invariants:</b></dt><dd>
    113      * <ul><li>The field can be empty.
    114      *     <li>The field is never <code>null</code>.
    115      *     <li>The elements are instances of <code>XMLElement</code>
    116      *         or a subclass of <code>XMLElement</code>.
     111     * <ul><li>The field can be empty.</li>
     112     *     <li>The field is never {@code null}.</li>
     113     *     <li>The elements are instances of {@code XMLElement}
     114     *         or a subclass of {@code XMLElement}.</li>
    117115     * </ul></dd></dl>
    118116     */
     
    123121     *
    124122     * <dl><dt><b>Invariants:</b></dt><dd>
    125      * <ul><li>The field is <code>null</code> iff the element is not
    126      *         initialized by either parse or setName.
    127      *     <li>If the field is not <code>null</code>, it's not empty.
    128      *     <li>If the field is not <code>null</code>, it contains a valid
    129      *         XML identifier.
     123     * <ul><li>The field is {@code null} iff the element is not
     124     *         initialized by either parse or {@link #setName setName()}.</li>
     125     *     <li>If the field is not {@code null}, it's not empty.</li>
     126     *     <li>If the field is not {@code null}, it contains a valid
     127     *         XML identifier.</li>
    130128     * </ul></dd></dl>
    131129     */
     
    133131
    134132    /**
    135      * The #PCDATA content of the object.
     133     * The {@code #PCDATA} content of the object.
    136134     *
    137135     * <dl><dt><b>Invariants:</b></dt><dd>
    138      * <ul><li>The field is <code>null</code> iff the element is not a
    139      *         #PCDATA element.
    140      *     <li>The field can be any string, including the empty string.
     136     * <ul><li>The field is {@code null} iff the element is not a
     137     *         {@code #PCDATA} element.</li>
     138     *     <li>The field can be any string, including the empty string.</li>
    141139     * </ul></dd></dl>
    142140     */
     
    148146     *
    149147     * <dl><dt><b>Invariants:</b></dt><dd>
    150      * <ul><li>The field is never <code>null</code>.
     148     * <ul><li>The field is never {@code null}.</li>
    151149     *     <li>The field always contains the following associations:
    152150     *         "lt"&nbsp;=&gt;&nbsp;"&lt;", "gt"&nbsp;=&gt;&nbsp;"&gt;",
    153151     *         "quot"&nbsp;=&gt;&nbsp;"\"", "apos"&nbsp;=&gt;&nbsp;"'",
    154      *         "amp"&nbsp;=&gt;&nbsp;"&amp;"
    155      *     <li>The keys are strings
    156      *     <li>The values are char arrays
     152     *         "amp"&nbsp;=&gt;&nbsp;"&amp;"</li>
     153     *     <li>The keys are strings</li>
     154     *     <li>The values are char arrays</li>
    157155     * </ul></dd></dl>
    158156     */
     
    163161     *
    164162     * <dl><dt><b>Invariants:</b></dt><dd>
    165      * <ul><li><code>lineNr &gt= 0</code>
     163     * <ul><li>{@code lineNr >= 0}</li>
    166164     * </ul></dd></dl>
    167165     */
     
    169167
    170168    /**
    171      * <code>true</code> if the case of the element and attribute names
    172      * are case insensitive.
     169     * {@code true} if the case of the element and attribute names are case
     170     * insensitive.
    173171     */
    174172    private boolean ignoreCase;
    175173
    176174    /**
    177      * <code>true</code> if the leading and trailing whitespace of #PCDATA
     175     * {@code true} if the leading and trailing whitespace of {@code #PCDATA}
    178176     * sections have to be ignored.
    179177     */
     
    181179
    182180    /**
    183      * Character read too much.
     181     * Character read too much.<br/>
    184182     * This character provides push-back functionality to the input reader
    185183     * without having to use a PushbackReader.
    186      * If there is no such character, this field is '\0'.
     184     * If there is no such character, this field is {@code '\0'}.
    187185     */
    188186    private char charReadTooMuch;
     
    197195     *
    198196     * <dl><dt><b>Invariants:</b></dt><dd>
    199      * <ul><li>The field is not <code>null</code> while the parse method
    200      *         is running.
     197     * <ul><li>The field is not {@code null} while the parse method is
     198     *         running.</li>
    201199     * </ul></dd></dl>
    202200     */
     
    207205     *
    208206     * <dl><dt><b>Invariants:</b></dt><dd>
    209      * <ul><li>parserLineNr &gt; 0 while the parse method is running.
     207     * <ul><li>parserLineNr &gt; 0 while the parse method is running.</li>
    210208     * </ul></dd></dl>
    211209     */
     
    213211
    214212    /**
    215      * Creates and initializes a new XML element.
     213     * Creates and initializes a new XML element.<br/>
    216214     * Calling the construction is equivalent to:
    217      * <ul><code>new XMLElement(new Hashtable(), false, true)
    218      * </code></ul>
     215     * <ul><li>{@code new XMLElement(new Hashtable(), false, true)}</li></ul>
    219216     *
    220217     * <dl><dt><b>Postconditions:</b></dt><dd>
    221      * <ul><li>countChildren() => 0
    222      *     <li>enumerateChildren() => empty enumeration
    223      *     <li>enumeratePropertyNames() => empty enumeration
    224      *     <li>getChildren() => empty vector
    225      *     <li>getContent() => ""
    226      *     <li>getLineNr() => 0
    227      *     <li>getName() => null
    228      * </ul></dd></dl>
    229      *
     218     * <ul><li>{@linkplain #countChildren} =&gt; 0</li>
     219     *     <li>{@linkplain #enumerateChildren} =&gt; empty enumeration</li>
     220     *     <li>enumeratePropertyNames() =&gt; empty enumeration</li>
     221     *     <li>getChildren() =&gt; empty vector</li>
     222     *     <li>{@linkplain #getContent} =&gt; ""</li>
     223     *     <li>{@linkplain #getLineNr} =&gt; 0</li>
     224     *     <li>{@linkplain #getName} =&gt; null</li>
     225     * </ul></dd></dl>
    230226     */
    231227    public XMLElement() {
     
    235231    /**
    236232     * Creates and initializes a new XML element.
    237      * <P>
    238      * This constructor should <I>only</I> be called from
    239      * {@link #createAnotherElement() createAnotherElement}
    240      * to create child elements.
     233     * <p>
     234     * This constructor should <i>only</i> be called from
     235     * {@link #createAnotherElement} to create child elements.
    241236     *
    242237     * @param entities
    243238     *     The entity conversion table.
    244239     * @param skipLeadingWhitespace
    245      *     <code>true</code> if leading and trailing whitespace in PCDATA
     240     *     {@code true} if leading and trailing whitespace in PCDATA
    246241     *     content has to be removed.
    247242     * @param fillBasicConversionTable
    248      *     <code>true</code> if the basic entities need to be added to
     243     *     {@code true} if the basic entities need to be added to
    249244     *     the entity list (client code calling this constructor).
    250245     * @param ignoreCase
    251      *     <code>true</code> if the case of element and attribute names have
     246     *     {@code true} if the case of element and attribute names have
    252247     *     to be ignored.
    253248     *
    254      * </dl><dl><dt><b>Preconditions:</b></dt><dd>
    255      * <ul><li><code>entities != null</code>
    256      *     <li>if <code>fillBasicConversionTable == false</code>
    257      *         then <code>entities</code> contains at least the following
    258      *         entries: <code>amp</code>, <code>lt</code>, <code>gt</code>,
    259      *         <code>apos</code> and <code>quot</code>
     249     * <dl><dt><b>Preconditions:</b></dt><dd>
     250     * <ul><li>{@code entities != null}</li>
     251     *     <li>if {@code fillBasicConversionTable == false}
     252     *         then {@code entities} contains at least the following
     253     *         entries: {@code amp}, {@code lt}, {@code gt}, {@code apos} and
     254     *         {@code quot}</li>
    260255     * </ul></dd></dl>
    261256     *
    262257     * <dl><dt><b>Postconditions:</b></dt><dd>
    263      * <ul><li>countChildren() => 0
    264      *     <li>enumerateChildren() => empty enumeration
    265      *     <li>enumeratePropertyNames() => empty enumeration
    266      *     <li>getChildren() => empty vector
    267      *     <li>getContent() => ""
    268      *     <li>getLineNr() => 0
    269      *     <li>getName() => null
    270      * </ul></dd></dl><dl>
    271      *
     258     * <ul><li>{@linkplain #countChildren} =&gt; 0</li>
     259     *     <li>{@linkplain #enumerateChildren} =&gt; empty enumeration</li>
     260     *     <li>enumeratePropertyNames() =&gt; empty enumeration</li>
     261     *     <li>getChildren() =&gt; empty vector</li>
     262     *     <li>{@linkplain #getContent} =&gt; ""</li>
     263     *     <li>{@linkplain #getLineNr} =&gt; 0</li>
     264     *     <li>{@linkplain #getName} =&gt; null</li>
     265     * </ul></dd></dl>
    272266     */
    273267    protected XMLElement(Hashtable<String, char[]> entities,
     
    306300     *     The child element to add.
    307301     *
    308      * </dl><dl><dt><b>Preconditions:</b></dt><dd>
    309      * <ul><li><code>child != null</code>
    310      *     <li><code>child.getName() != null</code>
    311      *     <li><code>child</code> does not have a parent element
     302     * <dl><dt><b>Preconditions:</b></dt><dd>
     303     * <ul><li>{@code child != null}</li>
     304     *     <li>{@code child.getName() != null}</li>
     305     *     <li>{@code child} does not have a parent element</li>
    312306     * </ul></dd></dl>
    313307     *
    314308     * <dl><dt><b>Postconditions:</b></dt><dd>
    315      * <ul><li>countChildren() => old.countChildren() + 1
    316      *     <li>enumerateChildren() => old.enumerateChildren() + child
    317      *     <li>getChildren() => old.enumerateChildren() + child
    318      * </ul></dd></dl><dl>
     309     * <ul><li>{@linkplain #countChildren} =&gt; old.countChildren() + 1</li>
     310     *     <li>{@linkplain #enumerateChildren} =&gt; old.enumerateChildren()
     311               + child</li>
     312     *     <li>getChildren() =&gt; old.enumerateChildren() + child</li>
     313     * </ul></dd></dl>
    319314     *
    320315     */
     
    331326     *     The value of the attribute.
    332327     *
    333      * </dl><dl><dt><b>Preconditions:</b></dt><dd>
    334      * <ul><li><code>name != null</code>
    335      *     <li><code>name</code> is a valid XML identifier
    336      *     <li><code>value != null</code>
     328     * <dl><dt><b>Preconditions:</b></dt><dd>
     329     * <ul><li>{@code name != null}</li>
     330     *     <li>{@code name} is a valid XML identifier</li>
     331     *     <li>{@code value != null}</li>
    337332     * </ul></dd></dl>
    338333     *
    339334     * <dl><dt><b>Postconditions:</b></dt><dd>
    340      * <ul><li>enumerateAttributeNames()
    341      *         => old.enumerateAttributeNames() + name
    342      *     <li>getAttribute(name) => value
    343      * </ul></dd></dl><dl>
    344      *
     335     * <ul><li>{@linkplain #enumerateAttributeNames}
     336     *         =&gt; old.enumerateAttributeNames() + name</li>
     337     *     <li>{@linkplain #getAttribute(java.lang.String) getAttribute(name)}
     338     *         =&gt; value</li>
     339     * </ul></dd></dl>
    345340     */
    346341    public void setAttribute(String name,
     
    356351     *
    357352     * <dl><dt><b>Postconditions:</b></dt><dd>
    358      * <ul><li><code>result >= 0</code>
    359      * </ul></dd></dl>
    360      *
     353     * <ul><li>{@code result >= 0}</li>
     354     * </ul></dd></dl>
    361355     */
    362356    public int countChildren() {
     
    368362     *
    369363     * <dl><dt><b>Postconditions:</b></dt><dd>
    370      * <ul><li><code>result != null</code>
    371      * </ul></dd></dl>
    372      *
    373      */
    374     public Enumeration enumerateAttributeNames() {
     364     * <ul><li>{@code result != null}</li>
     365     * </ul></dd></dl>
     366     */
     367    public Enumeration<String> enumerateAttributeNames() {
    375368        return this.attributes.keys();
    376369    }
     
    380373     *
    381374     * <dl><dt><b>Postconditions:</b></dt><dd>
    382      * <ul><li><code>result != null</code>
    383      * </ul></dd></dl>
    384      *
    385      */
    386     public Enumeration enumerateChildren() {
     375     * <ul><li>{@code result != null}</li>
     376     * </ul></dd></dl>
     377     */
     378    public Enumeration<XMLElement> enumerateChildren() {
    387379        return this.children.elements();
    388380    }
     
    390382    /**
    391383     * Returns the PCDATA content of the object. If there is no such content,
    392      * <CODE>null</CODE> is returned.
    393      *
     384     * {@code null} is returned.
    394385     */
    395386    public String getContent() {
     
    399390    /**
    400391     * Returns the line nr in the source data on which the element is found.
    401      * This method returns <code>0</code> there is no associated source data.
     392     * This method returns {@code 0} there is no associated source data.
    402393     *
    403394     * <dl><dt><b>Postconditions:</b></dt><dd>
    404      * <ul><li><code>result >= 0</code>
     395     * <ul><li>{@code result >= 0}</li>
    405396     * </ul></dd></dl>
    406397     */
     
    410401
    411402    /**
    412      * Returns an attribute of the element.
    413      * If the attribute doesn't exist, <code>null</code> is returned.
     403     * Returns an attribute of the element.<br/>
     404     * If the attribute doesn't exist, {@code null} is returned.
    414405     *
    415406     * @param name The name of the attribute.
    416407     *
    417      * </dl><dl><dt><b>Preconditions:</b></dt><dd>
    418      * <ul><li><code>name != null</code>
    419      *     <li><code>name</code> is a valid XML identifier
    420      * </ul></dd></dl><dl>
    421      *
     408     * <dl><dt><b>Preconditions:</b></dt><dd>
     409     * <ul><li>{@code name != null}</li>
     410     *     <li>{@code name} is a valid XML identifier</li>
     411     * </ul></dd></dl>
    422412     */
    423413    public Object getAttribute(String name) {
     
    431421    /**
    432422     * Returns the name of the element.
    433      *
     423     * @return this {@code XMLElement} object's name
    434424     */
    435425    public String getName() {
     
    438428
    439429    /**
    440      * Reads one XML element from a java.io.Reader and parses it.
     430     * Reads one XML element from a {@link java.io.Reader} and parses it.
    441431     *
    442432     * @param reader
    443433     *     The reader from which to retrieve the XML data.
    444434     *
    445      * </dl><dl><dt><b>Preconditions:</b></dt><dd>
    446      * <ul><li><code>reader != null</code>
    447      *     <li><code>reader</code> is not closed
     435     * <dl><dt><b>Preconditions:</b></dt><dd>
     436     * <ul><li>{@code reader != null}</li>
     437     *     <li>{@code reader} is not closed</li>
    448438     * </ul></dd></dl>
    449439     *
    450440     * <dl><dt><b>Postconditions:</b></dt><dd>
    451441     * <ul><li>the state of the receiver is updated to reflect the XML element
    452      *         parsed from the reader
     442     *         parsed from the reader</li>
    453443     *     <li>the reader points to the first character following the last
    454      *         '&gt;' character of the XML element
    455      * </ul></dd></dl><dl>
     444     *         {@code '&gt;'} character of the XML element</li>
     445     * </ul></dd></dl>
    456446     *
    457447     * @throws java.io.IOException
     
    473463     *     The line number of the first line in the data.
    474464     *
    475      * </dl><dl><dt><b>Preconditions:</b></dt><dd>
    476      * <ul><li><code>reader != null</code>
    477      *     <li><code>reader</code> is not closed
     465     * <dl><dt><b>Preconditions:</b></dt><dd>
     466     * <ul><li>{@code reader != null}</li>
     467     *     <li>{@code reader} is not closed</li>
    478468     * </ul></dd></dl>
    479469     *
    480470     * <dl><dt><b>Postconditions:</b></dt><dd>
    481471     * <ul><li>the state of the receiver is updated to reflect the XML element
    482      *         parsed from the reader
     472     *         parsed from the reader</li>
    483473     *     <li>the reader points to the first character following the last
    484      *         '&gt;' character of the XML element
    485      * </ul></dd></dl><dl>
     474     *         {@code '&gt;'} character of the XML element</li>
     475     * </ul></dd></dl>
    486476     *
    487477     * @throws java.io.IOException
     
    518508    /**
    519509     * Creates a new similar XML element.
    520      * <P>
     510     * <p>
    521511     * You should override this method when subclassing XMLElement.
     512     * </p>
    522513     */
    523514    protected XMLElement createAnotherElement() {
     
    544535     *     The new name.
    545536     *
    546      * </dl><dl><dt><b>Preconditions:</b></dt><dd>
    547      * <ul><li><code>name != null</code>
    548      *     <li><code>name</code> is a valid XML identifier
    549      * </ul></dd></dl>
    550      *
     537     * <dl><dt><b>Preconditions:</b></dt><dd>
     538     * <ul><li{@code name != null}</li>
     539     *     <li>{@code name} is a valid XML identifier</li>
     540     * </ul></dd></dl>
    551541     */
    552542    public void setName(String name) {
     
    561551     *     The buffer in which the scanned identifier will be put.
    562552     *
    563      * </dl><dl><dt><b>Preconditions:</b></dt><dd>
    564      * <ul><li><code>result != null</code>
     553     * <dl><dt><b>Preconditions:</b></dt><dd>
     554     * <ul><li>{@code result != null}</li>
    565555     *     <li>The next character read from the reader is a valid first
    566      *         character of an XML identifier.
     556     *         character of an XML identifier.</li>
    567557     * </ul></dd></dl>
    568558     *
    569559     * <dl><dt><b>Postconditions:</b></dt><dd>
    570560     * <ul><li>The next character read from the reader won't be an identifier
    571      *         character.
    572      * </ul></dd></dl><dl>
     561     *         character.</li>
     562     * </ul></dd></dl>
    573563     */
    574564    protected void scanIdentifier(StringBuffer result)
     
    608598
    609599    /**
    610      * This method scans an identifier from the current reader.
    611      * The scanned whitespace is appended to <code>result</code>.
     600     * This method scans an identifier from the current reader.<br/>
     601     * The scanned whitespace is appended to {@code result}.
    612602     *
    613603     * @return the next character following the whitespace.
    614604     *
    615      * </dl><dl><dt><b>Preconditions:</b></dt><dd>
    616      * <ul><li><code>result != null</code>
     605     * <dl><dt><b>Preconditions:</b></dt><dd>
     606     * <ul><li>{@code result != null}</li>
    617607     * </ul></dd></dl>
    618608     */
     
    636626
    637627    /**
    638      * This method scans a delimited string from the current reader.
    639      * The scanned string without delimiters is appended to
    640      * <code>string</code>.
    641      *
    642      * </dl><dl><dt><b>Preconditions:</b></dt><dd>
    643      * <ul><li><code>string != null</code>
    644      *     <li>the next char read is the string delimiter
     628     * This method scans a delimited string from the current reader.<br/>
     629     * The scanned string without delimiters is appended to {@code string}.
     630     *
     631     * <dl><dt><b>Preconditions:</b></dt><dd>
     632     * <ul><li>{@code string != null}</li>
     633     *     <li>the next char read is the string delimiter</li>
    645634     * </ul></dd></dl>
    646635     */
     
    664653
    665654    /**
    666      * Scans a #PCDATA element. CDATA sections and entities are resolved.
    667      * The next &lt; char is skipped.
    668      * The scanned data is appended to <code>data</code>.
    669      *
    670      * </dl><dl><dt><b>Preconditions:</b></dt><dd>
    671      * <ul><li><code>data != null</code>
     655     * Scans a {@code #PCDATA} element. CDATA sections and entities are
     656     * resolved.<br/>
     657     * The next &lt; char is skipped.<br/>
     658     * The scanned data is appended to {@code data}.
     659     *
     660     * <dl><dt><b>Preconditions:</b></dt><dd>
     661     * <ul><li>{@code data != null}</li>
    672662     * </ul></dd></dl>
    673663     */
     
    694684    /**
    695685     * Scans a special tag and if the tag is a CDATA section, append its
    696      * content to <code>buf</code>.
    697      *
    698      * </dl><dl><dt><b>Preconditions:</b></dt><dd>
    699      * <ul><li><code>buf != null</code>
    700      *     <li>The first &lt; has already been read.
     686     * content to {@code buf}.
     687     *
     688     * <dl><dt><b>Preconditions:</b></dt><dd>
     689     * <ul><li>{@code buf != null}</li>
     690     *     <li>The first &lt; has already been read.</li>
    701691     * </ul></dd></dl>
    702692     */
     
    751741     * Skips a comment.
    752742     *
    753      * </dl><dl><dt><b>Preconditions:</b></dt><dd>
    754      * <ul><li>The first &lt;!-- has already been read.
     743     * <dl><dt><b>Preconditions:</b></dt><dd>
     744     * <ul><li>The first &lt;!-- has already been read.</li>
    755745     * </ul></dd></dl>
    756746     */
     
    791781     *                     already been read.
    792782     *
    793      * </dl><dl><dt><b>Preconditions:</b></dt><dd>
    794      * <ul><li>The first &lt;! has already been read.
    795      *     <li><code>bracketLevel >= 0</code>
     783     * <dl><dt><b>Preconditions:</b></dt><dd>
     784     * <ul><li>The first &lt;! has already been read.</li>
     785     *     <li>{@code bracketLevel &gt;= 0}</li>
    796786     * </ul></dd></dl>
    797787     */
     
    842832
    843833    /**
    844      * Scans the data for literal text.
     834     * Scans the data for literal text.<br/>
    845835     * Scanning stops when a character does not match or after the complete
    846836     * text has been checked, whichever comes first.
     
    848838     * @param literal the literal to check.
    849839     *
    850      * </dl><dl><dt><b>Preconditions:</b></dt><dd>
    851      * <ul><li><code>literal != null</code>
     840     * <dl><dt><b>Preconditions:</b></dt><dd>
     841     * <ul><li>{@code literal != null}</li>
    852842     * </ul></dd></dl>
    853843     */
     
    890880     * @param elt The element that will contain the result.
    891881     *
    892      * </dl><dl><dt><b>Preconditions:</b></dt><dd>
    893      * <ul><li>The first &lt; has already been read.
    894      *     <li><code>elt != null</code>
     882     * <dl><dt><b>Preconditions:</b></dt><dd>
     883     * <ul><li>The first &lt; has already been read.</li>
     884     *     <li>{@code elt != null}</li>
    895885     * </ul></dd></dl>
    896886     */
     
    996986
    997987    /**
    998      * Resolves an entity. The name of the entity is read from the reader.
    999      * The value of the entity is appended to <code>buf</code>.
     988     * Resolves an entity. The name of the entity is read from the reader.<br/>
     989     * The value of the entity is appended to {@code buf}.
    1000990     *
    1001991     * @param buf Where to put the entity value.
    1002992     *
    1003      * </dl><dl><dt><b>Preconditions:</b></dt><dd>
    1004      * <ul><li>The first &amp; has already been read.
    1005      *     <li><code>buf != null</code>
     993     * <dl><dt><b>Preconditions:</b></dt><dd>
     994     * <ul><li>The first &amp; has already been read.</li>
     995     *     <li>{@code buf != null}</li>
    1006996     * </ul></dd></dl>
    1007997     */
     
    10431033     * @param ch The character to push back.
    10441034     *
    1045      * </dl><dl><dt><b>Preconditions:</b></dt><dd>
    1046      * <ul><li>The read-back buffer is empty.
    1047      *     <li><code>ch != '\0'</code>
     1035     * <dl><dt><b>Preconditions:</b></dt><dd>
     1036     * <ul><li>The read-back buffer is empty.</li>
     1037     *     <li>{@code ch != '\0'}</li>
    10481038     * </ul></dd></dl>
    10491039     */
     
    10581048     * @param name The name of the entity.
    10591049     *
    1060      * </dl><dl><dt><b>Preconditions:</b></dt><dd>
    1061      * <ul><li><code>name != null</code>
     1050     * <dl><dt><b>Preconditions:</b></dt><dd>
     1051     * <ul><li>{@code name != null}</li>
    10621052     * </ul></dd></dl>
    10631053     */
     
    10741064     * @param value The value of the entity.
    10751065     *
    1076      * </dl><dl><dt><b>Preconditions:</b></dt><dd>
    1077      * <ul><li><code>name != null</code>
    1078      *     <li><code>value != null</code>
     1066     * <dl><dt><b>Preconditions:</b></dt><dd>
     1067     * <ul><li>{@code name != null}</li>
     1068     *     <li>{@code value != null}</li>
    10791069     * </ul></dd></dl>
    10801070     */
     
    11001090     * @param context The context in which the error occured.
    11011091     *
    1102      * </dl><dl><dt><b>Preconditions:</b></dt><dd>
    1103      * <ul><li><code>context != null</code>
    1104      *     <li><code>context.length() &gt; 0</code>
     1092     * <dl><dt><b>Preconditions:</b></dt><dd>
     1093     * <ul><li>{@code context != null}</li>
     1094     *     <li>{@code context.length() &gt; 0}</li>
    11051095     * </ul></dd></dl>
    11061096     */
     
    11171107     *                expected.
    11181108     *
    1119      * </dl><dl><dt><b>Preconditions:</b></dt><dd>
    1120      * <ul><li><code>charSet != null</code>
    1121      *     <li><code>charSet.length() &gt; 0</code>
     1109     * <dl><dt><b>Preconditions:</b></dt><dd>
     1110     * <ul><li>{@code charSet != null}</li>
     1111     *     <li>{@code charSet.length() &gt; 0}</li>
    11221112     * </ul></dd></dl>
    11231113     */
     
    11341124     *                expected.
    11351125     * @param ch The character that was received instead.
    1136      * </dl><dl><dt><b>Preconditions:</b></dt><dd>
    1137      * <ul><li><code>charSet != null</code>
    1138      *     <li><code>charSet.length() &gt; 0</code>
     1126     * <dl><dt><b>Preconditions:</b></dt><dd>
     1127     * <ul><li>{@code charSet != null}</li>
     1128     *     <li>{@code charSet.length() &gt; 0}</li>
    11391129     * </ul></dd></dl>
    11401130     */
     
    11491139     * @param name The name of the entity.
    11501140     *
    1151      * </dl><dl><dt><b>Preconditions:</b></dt><dd>
    1152      * <ul><li><code>name != null</code>
    1153      *     <li><code>name.length() &gt; 0</code>
     1141     * <dl><dt><b>Preconditions:</b></dt><dd>
     1142     * <ul><li>{@code name != null}</li>
     1143     *     <li>{@code name.length() &gt; 0}</li>
    11541144     * </ul></dd></dl>
    11551145     */
     
    11631153     * xml code.
    11641154     *
    1165      * @param isr The reader of the InputStream containing the xml.
    1166      * @param pout The PipedOutputStream that will be receiving the filtered
    1167      *             xml file.
     1155     * @param isr The reader of the {@link InputStream} containing the xml.
     1156     * @param pout The {@link PipedOutputStream} that will be receiving the
     1157     *             filtered xml file.
    11681158     */
    11691159    public void sanitizeInput(Reader isr, OutputStream pout) {
     
    12051195                    if (JNLPRuntime.isDebug()) {
    12061196                        if (ch == 10) {
    1207                             System.out.println();
    1208                             System.out.print("line: " + newline + " ");
     1197                            OutputController.getLogger().printOutLn("");
     1198                            OutputController.getLogger().printOut("line: " + newline + " ");
    12091199                            newline++;
    12101200                        } else {
    1211                             System.out.print(ch);
     1201                            OutputController.getLogger().printOut(ch+"");
    12121202                        }
    12131203                    }
     
    12361226                            this.sanitizeCharReadTooMuch = ch;
    12371227                            if (JNLPRuntime.isDebug()) {
    1238                                 System.out.print('<');
    1239                                 System.out.print('!');
    1240                                 System.out.print('-');
     1228                                OutputController.getLogger().printOut("<");
     1229                                OutputController.getLogger().printOut("!");
     1230                                OutputController.getLogger().printOut("-");
    12411231                            }
    12421232                        }
     
    12461236                        this.sanitizeCharReadTooMuch = ch;
    12471237                        if (JNLPRuntime.isDebug()) {
    1248                             System.out.print('<');
    1249                             System.out.print('!');
     1238                              OutputController.getLogger().printOut("<");
     1239                              OutputController.getLogger().printOut("!");
    12501240                        }
    12511241                    }
     
    12561246                    if (JNLPRuntime.isDebug()) {
    12571247                        if (ch == 10) {
    1258                             System.out.println();
    1259                             System.out.print("line: " + newline + " ");
     1248                            OutputController.getLogger().printOutLn("");
     1249                            OutputController.getLogger().printOut("line: " + newline + " ");
    12601250                            newline++;
    12611251                        } else {
    1262                             System.out.print(ch);
     1252                            OutputController.getLogger().printOut(ch+"");
    12631253                        }
    12641254                    }
     
    12721262            // Print the stack trace here -- xml.parseFromReader() will
    12731263            // throw the ParseException if something goes wrong.
    1274             e.printStackTrace();
     1264            OutputController.getLogger().log(OutputController.Level.ERROR_ALL, e);
    12751265        }
    12761266    }
  • trunk/icedtea-web/netx/net/sourceforge/nanoxml/XMLParseException.java

    r348 r429  
    3232 * An XMLParseException is thrown when an error occures while parsing an XML
    3333 * string.
    34  * <P>
    35  * $Revision: 1.1 $<BR>
    36  * $Date: 2002/08/03 04:05:32 $<P>
     34 * <p>
     35 * $Revision: 1.1 $<br/>
     36 * $Date: 2002/08/03 04:05:32 $</p>
    3737 *
    3838 * @see net.sourceforge.nanoxml.XMLElement
     
    5454     *
    5555     * <dl><dt><b>Invariants:</b></dt><dd>
    56      * <ul><li><code>lineNr &gt 0 || lineNr == NO_LINE</code>
     56     * <ul><li>{@code lineNr > 0 || lineNr == NO_LINE}
    5757     * </ul></dd></dl>
    5858     */
     
    6565     * @param message A message describing what went wrong.
    6666     *
    67      * </dl><dl><dt><b>Preconditions:</b></dt><dd>
    68      * <ul><li><code>message != null</code>
     67     * <dl><dt><b>Preconditions:</b></dt><dd>
     68     * <ul><li>{@code message != null}</li>
    6969     * </ul></dd></dl>
    7070     *
    7171     * <dl><dt><b>Postconditions:</b></dt><dd>
    72      * <ul><li>getLineNr() => NO_LINE
    73      * </ul></dd></dl><dl>
     72     * <ul><li>{@code getLineNr() => NO_LINE}</li>
     73     * </ul></dd></dl>
    7474     */
    7575    public XMLParseException(String name,
     
    8989     * @param message A message describing what went wrong.
    9090     *
    91      * </dl><dl><dt><b>Preconditions:</b></dt><dd>
    92      * <ul><li><code>message != null</code>
    93      *     <li><code>lineNr &gt; 0</code>
     91     * <dl><dt><b>Preconditions:</b></dt><dd>
     92     * <ul><li>{@code message != null}</li>
     93     *     <li>{@code lineNr &gt; 0}</li>
    9494     * </ul></dd></dl>
    9595     *
    9696     * <dl><dt><b>Postconditions:</b></dt><dd>
    97      * <ul><li>getLineNr() => lineNr
    98      * </ul></dd></dl><dl>
     97     * <ul><li>{@code getLineNr() => lineNr}</li>
     98     * </ul></dd></dl>
    9999     */
    100100    public XMLParseException(String name,
     
    109109
    110110    /**
    111      * Where the error occurred, or <code>NO_LINE</code> if the line number is
     111     * Where the error occurred, or {@code NO_LINE} if the line number is
    112112     * unknown.
    113113     *
     
    117117        return this.lineNr;
    118118    }
    119 
    120119}
Note: See TracChangeset for help on using the changeset viewer.