[fyi][icedtea-web] backend and itw-settings for extended applets security

Adam Domurad adomurad at redhat.com
Tue Feb 5 07:08:24 PST 2013


On 02/03/2013 07:08 AM, Jiri Vanek wrote:
 > Whole troubles are described here 
http://icedtea.classpath.org/wiki/Extended_Applets_Security rather then 
in plain email.
 >
 > There is what me and adam have already achieved on this topic, what 
we have o achieve and where we are stil not so sure....
 >
 > This patch is containing itw-settings part and backend for 
manipulating stored entries.and basic matching.
 > I noted this just [fyi] because adam ave already walked through the 
patch, and so have I across his part. So the patch should be ready for 
push unless someone find something malicious on implementation or even 
on design.
 >
 > J.

Typos only / misspellings only.


 > diff -r e631770d76ba 
netx/net/sourceforge/appletextendedsecurity/AppletExtendedSecurity.java
 > --- /dev/null    Thu Jan 01 00:00:00 1970 +0000
 > +++ 
b/netx/net/sourceforge/appletextendedsecurity/AppletExtendedSecurity.java Fri 
Feb 01 20:55:48 2013 +0100
 > @@ -0,0 +1,84 @@
 > +/*
 > +Copyright (C) 2013 Red Hat
 > +
 > +This program is free software; you can redistribute it and/or modify
 > +it under the terms of the GNU General Public License as published by
 > +the Free Software Foundation; either version 2 of the License, or
 > +(at your option) any later version.
 > +
 > +This program is distributed in the hope that it will be useful, but
 > +WITHOUT ANY WARRANTY; without even the implied warranty of
 > +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
 > +General Public License for more details.
 > +
 > +You should have received a copy of the GNU General Public License
 > +along with this program; if not, write to the Free Software
 > +Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
 > +*/
 > +
 > +package net.sourceforge.appletextendedsecurity;
 > +
 > +import javax.naming.ConfigurationException;
 > +import 
net.sourceforge.appletextendedsecurity.impl.UnsignedAppletActionStorageImpl;
 > +import net.sourceforge.jnlp.config.DeploymentConfiguration;
 > +import net.sourceforge.jnlp.runtime.JNLPRuntime;
 > +
 > +
 > +public class AppletExtendedSecurity {
 > +
 > +    private static UnsignedAppletActionStorageImpl globalInstance;
 > +    private static UnsignedAppletActionStorageImpl customInstance;
 > +
 > +    /**
 > +     *
 > +     * @return storage with global items from /etc/
 > +     */
 > +
 > +    public static UnsignedAppletActionStorage 
getUnsignedAppletActionGlobalStorage(){
 > +        if (globalInstance == null){
 > +            globalInstance = new 
UnsignedAppletActionStorageImpl(DeploymentConfiguration.getAppletTrustGlobalSettingsPath());
 > +        }
 > +        return globalInstance;
 > +    }
 > +
 > +
 > +    /**
 > +     *
 > +     * @return storage with custom items from /home/
 > +     */
 > +    public static UnsignedAppletActionStorage 
getUnsignedAppletActionCustomStorage(){
 > +        if (customInstance == null){
 > +            customInstance = new 
UnsignedAppletActionStorageImpl(DeploymentConfiguration.getAppletTrustCustomSettingsPath());
 > +        }
 > +        return customInstance;
 > +    }
 > +
 > +    public static AppletSecurityLevel getDefaultSecurityLevel(){
 > +        return AppletSecurityLevel.getDefault();
 > +    }
 > +
 > +    /**
 > +     *
 > +     * @return user-set seurity level or default one if user-set do 
not exists

s/seurity/security/

 > +     */
 > +    public static AppletSecurityLevel getCustomSecurityLevel(){
 > +        DeploymentConfiguration conf = JNLPRuntime.getConfiguration();
 > +        if (conf==null){
 > +            conf = new DeploymentConfiguration();
 > +            try {
 > +            conf.load();
 > +            } catch (ConfigurationException ex){
 > +                ex.printStackTrace();
 > +                return getDefaultSecurityLevel();
 > +            }
 > +        }
 > +        String s = 
conf.getProperty(DeploymentConfiguration.KEY_SECURITY_LEVEL);
 > +        if (s==null) {
 > +            return getDefaultSecurityLevel();
 > +        }
 > +        return AppletSecurityLevel.fromString(s);
 > +    }
 > +
 > +
 > +
 > +}
 > diff -r e631770d76ba 
netx/net/sourceforge/appletextendedsecurity/AppletSecurityLevel.java
 > --- /dev/null    Thu Jan 01 00:00:00 1970 +0000
 > +++ 
b/netx/net/sourceforge/appletextendedsecurity/AppletSecurityLevel.java 
Fri Feb 01 20:55:48 2013 +0100
 > @@ -0,0 +1,83 @@
 > +/*
 > +Copyright (C) 2013 Red Hat
 > +
 > +This program is free software; you can redistribute it and/or modify
 > +it under the terms of the GNU General Public License as published by
 > +the Free Software Foundation; either version 2 of the License, or
 > +(at your option) any later version.
 > +
 > +This program is distributed in the hope that it will be useful, but
 > +WITHOUT ANY WARRANTY; without even the implied warranty of
 > +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
 > +General Public License for more details.
 > +
 > +You should have received a copy of the GNU General Public License
 > +along with this program; if not, write to the Free Software
 > +Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
 > +*/
 > +
 > +package net.sourceforge.appletextendedsecurity;
 > +
 > +import net.sourceforge.jnlp.runtime.Translator;
 > +
 > +public enum AppletSecurityLevel {
 > +
 > +    DENY_ALL, DENY_UNSIGNED, ASK_UNSIGNED, ALLOW_UNSIGNED;
 > +
 > +    public static String allToString() {
 > +        return DENY_ALL.toChars()+" "+DENY_UNSIGNED.toChars()+" 
"+ASK_UNSIGNED.toChars()+" "+ALLOW_UNSIGNED.toChars();
 > +    }
 > +
 > +
 > +
 > +    public String toChars() {
 > +        switch (this) {
 > +            case DENY_ALL:
 > +                return " DENY_ALL";
 > +            case DENY_UNSIGNED:
 > +                return "DENY_UNSIGNED";
 > +            case ASK_UNSIGNED:
 > +                return "ASK_UNSIGNED";
 > +            case ALLOW_UNSIGNED:
 > +                return "ALLOW_UNSIGNED";
 > +        }
 > +        throw new RuntimeException("Unknown AppletSecurityLevel");
 > +    }
 > +
 > +    public String toExplanation() {
 > +        switch (this) {
 > +            case DENY_ALL:
 > +                return 
Translator.R("APPEXTSECappletSecurityLevelExtraHighId")+" - 
"+Translator.R("APPEXTSECappletSecurityLevelExtraHighExplanation");
 > +            case DENY_UNSIGNED:
 > +                return 
Translator.R("APPEXTSECappletSecurityLevelVeryHighId")+" - 
"+Translator.R("APPEXTSECappletSecurityLevelVeryHighExplanation");
 > +            case ASK_UNSIGNED:
 > +                return 
Translator.R("APPEXTSECappletSecurityLevelHighId")+" - 
"+Translator.R("APPEXTSECappletSecurityLevelHighExplanation");
 > +            case ALLOW_UNSIGNED:
 > +                return 
Translator.R("APPEXTSECappletSecurityLevelLowId")+" - 
"+Translator.R("APPEXTSECappletSecurityLevelLowExplanation");
 > +        }
 > +        throw new RuntimeException("Unknown AppletSecurityLevel");
 > +    }
 > +
 > +    public static AppletSecurityLevel fromString(String s) {
 > +        if (s.trim().equalsIgnoreCase("DENY_ALL")) {
 > +            return AppletSecurityLevel.DENY_ALL;
 > +        } else if (s.trim().equalsIgnoreCase("DENY_UNSIGNED")) {
 > +            return AppletSecurityLevel.DENY_UNSIGNED;
 > +        } else if (s.trim().equalsIgnoreCase("ASK_UNSIGNED")) {
 > +            return AppletSecurityLevel.ASK_UNSIGNED;
 > +        } else if (s.trim().equalsIgnoreCase("ALLOW_UNSIGNED")) {
 > +            return AppletSecurityLevel.ALLOW_UNSIGNED;
 > +        } else {
 > +            throw new RuntimeException("Unknown AppletSecurityLevel 
for " + s);
 > +        }
 > +    }
 > +
 > +    @Override
 > +    public String toString() {
 > +        return toExplanation();
 > +    }
 > +
 > +    public static AppletSecurityLevel getDefault(){
 > +        return ASK_UNSIGNED;
 > +    }
 > +}
 > diff -r e631770d76ba 
netx/net/sourceforge/appletextendedsecurity/UnsignedAppletAction.java
 > --- /dev/null    Thu Jan 01 00:00:00 1970 +0000
 > +++ 
b/netx/net/sourceforge/appletextendedsecurity/UnsignedAppletAction.java 
Fri Feb 01 20:55:48 2013 +0100
 > @@ -0,0 +1,73 @@
 > +/*
 > +Copyright (C) 2013 Red Hat
 > +
 > +This program is free software; you can redistribute it and/or modify
 > +it under the terms of the GNU General Public License as published by
 > +the Free Software Foundation; either version 2 of the License, or
 > +(at your option) any later version.
 > +
 > +This program is distributed in the hope that it will be useful, but
 > +WITHOUT ANY WARRANTY; without even the implied warranty of
 > +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
 > +General Public License for more details.
 > +
 > +You should have received a copy of the GNU General Public License
 > +along with this program; if not, write to the Free Software
 > +Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
 > +*/
 > +
 > +package net.sourceforge.appletextendedsecurity;
 > +
 > +import net.sourceforge.jnlp.runtime.Translator;
 > +
 > +public enum UnsignedAppletAction {
 > +
 > +    ALWAYS, NEVER, YES, NO;
 > +
 > +    public String toChar() {
 > +        switch (this) {
 > +            case ALWAYS:
 > +                return "A";
 > +            case NEVER:
 > +                return "N";
 > +            case YES:
 > +                return "y";
 > +            case NO:
 > +                return "n";
 > +        }
 > +        throw new RuntimeException("Unknown UnsignedAppletAction");
 > +    }
 > +
 > +    public String toExplanation() {
 > +        switch (this) {
 > +            case ALWAYS:
 > +                return 
Translator.R("APPEXTSECunsignedAppletActionAlways");
 > +            case NEVER:
 > +                return 
Translator.R("APPEXTSECunsignedAppletActionNever");
 > +            case YES:
 > +                return Translator.R("APPEXTSECunsignedAppletActionYes");
 > +            case NO:
 > +                return Translator.R("APPEXTSECunsignedAppletActionNo");
 > +        }
 > +        throw new RuntimeException("Unknown UnsignedAppletAction");
 > +    }
 > +
 > +    public static UnsignedAppletAction fromString(String s) {
 > +        if (s.startsWith("A")) {
 > +            return UnsignedAppletAction.ALWAYS;
 > +        } else if (s.startsWith("N")) {
 > +            return UnsignedAppletAction.NEVER;
 > +        } else if (s.startsWith("y")) {
 > +            return UnsignedAppletAction.YES;
 > +        } else if (s.startsWith("n")) {
 > +            return UnsignedAppletAction.NO;
 > +        } else {
 > +            throw new RuntimeException("Unknown UnsignedAppletAction 
for " + s);
 > +        }
 > +    }
 > +
 > +    @Override
 > +    public String toString() {
 > +        return toChar() + " - " + toExplanation();
 > +    }
 > +}
 > diff -r e631770d76ba 
netx/net/sourceforge/appletextendedsecurity/UnsignedAppletActionEntry.java
 > --- /dev/null    Thu Jan 01 00:00:00 1970 +0000
 > +++ 
b/netx/net/sourceforge/appletextendedsecurity/UnsignedAppletActionEntry.java 
Fri Feb 01 20:55:48 2013 +0100
 > @@ -0,0 +1,169 @@
 > +/*
 > +Copyright (C) 2013 Red Hat
 > +
 > +This program is free software; you can redistribute it and/or modify
 > +it under the terms of the GNU General Public License as published by
 > +the Free Software Foundation; either version 2 of the License, or
 > +(at your option) any later version.
 > +
 > +This program is distributed in the hope that it will be useful, but
 > +WITHOUT ANY WARRANTY; without even the implied warranty of
 > +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
 > +General Public License for more details.
 > +
 > +You should have received a copy of the GNU General Public License
 > +along with this program; if not, write to the Free Software
 > +Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
 > +*/
 > +package net.sourceforge.appletextendedsecurity;
 > +
 > +import java.io.IOException;
 > +import java.io.Writer;
 > +import java.util.ArrayList;
 > +import java.util.Date;
 > +import java.util.List;
 > +
 > +public class UnsignedAppletActionEntry {
 > +
 > +
 > +
 > +    private UnsignedAppletAction unsignedAppletAction;
 > +    private Date timeStamp;
 > +    private UrlRegEx documentBase;
 > +    private UrlRegEx codeBase;
 > +    private String mainClass;
 > +    private List<String> archives;
 > +
 > +
 > +    public static UnsignedAppletActionEntry createFromString(String s) {
 > +        String[] split = s.split("\\s+");
 > +        UnsignedAppletActionEntry nw  = new UnsignedAppletActionEntry(
 > +                UnsignedAppletAction.fromString(split[0]),
 > +                new Date(new Long(split[1])),
 > +                new UrlRegEx(split[2]),
 > +                null,
 > +                null,
 > +                null
 > +                );
 > +        if (split.length>3){
 > +            nw.setCodeBase(new UrlRegEx(split[3]));
 > +        }
 > +        if (split.length>4){
 > +            nw.setMainClass(split[4]);
 > +        }
 > +        if (split.length>5){
 > + 
nw.setArchives(createArchivesList(s.substring(s.indexOf(split[4])+split[4].length()).trim()));
 > +        }
 > +        return nw;
 > +    }
 > +
 > +    public UnsignedAppletActionEntry(UnsignedAppletAction 
unsignedAppletAction, Date timeStamp, UrlRegEx documentBase, UrlRegEx 
codeBase, String mainClass, List<String> archives) {
 > +        this.unsignedAppletAction = unsignedAppletAction;
 > +        this.timeStamp = timeStamp;
 > +        this.documentBase = documentBase;
 > +        this.codeBase = codeBase;
 > +        this.mainClass = mainClass;
 > +        this.archives = archives;
 > +
 > +    }
 > +
 > +
 > +
 > +    @Override
 > +    public String toString() {
 > +        return unsignedAppletAction.toChar() +
 > +                " " + ((timeStamp == null)?"1":timeStamp.getTime()) +
 > +                " " + ((documentBase == 
null)?"":documentBase.getRegEx()) +
 > +                " " + ((codeBase == null)?"":codeBase.getRegEx()) +
 > +                " " + ((mainClass == null)?"":mainClass) +
 > +                " " + createArchivesString(archives);
 > +
 > +    }
 > +
 > +    public void write(Writer bw) throws IOException {
 > +        bw.write(this.toString());
 > +    }
 > +
 > +     public Date getTimeStamp() {
 > +        return timeStamp;
 > +    }
 > +
 > +    public UrlRegEx getDocumentBase() {
 > +        return documentBase;
 > +    }
 > +
 > +    public void setTimeStamp(Date timeStamp) {
 > +        this.timeStamp = timeStamp;
 > +    }
 > +
 > +    public void setDocumentBase(UrlRegEx documentBase) {
 > +        this.documentBase = documentBase;
 > +    }
 > +
 > +    public UnsignedAppletAction getUnsignedAppletAction() {
 > +        return unsignedAppletAction;
 > +    }
 > +
 > +    public void setUnsignedAppletAction(UnsignedAppletAction 
unsignedAppletAction) {
 > +        this.unsignedAppletAction = unsignedAppletAction;
 > +    }
 > +
 > +    public UrlRegEx getCodeBase() {
 > +        return codeBase;
 > +    }
 > +
 > +    public void setCodeBase(UrlRegEx codeBase) {
 > +        this.codeBase = codeBase;
 > +    }
 > +
 > +    public String getMainClass() {
 > +        return mainClass;
 > +    }
 > +
 > +    public void setMainClass(String mainClass) {
 > +        this.mainClass = mainClass;
 > +    }
 > +
 > +    public List<String> getArchives() {
 > +        return archives;
 > +    }
 > +
 > +    public void setArchives(List<String> archives) {
 > +        this.archives = archives;
 > +    }
 > +
 > +    public  static String createArchivesString(List<String> 
listOfArchives) {
 > +        if (listOfArchives == null){
 > +            return "";
 > +        }
 > +        StringBuilder sb = new StringBuilder();
 > +        for (int i = 0; i < listOfArchives.size(); i++) {
 > +            String string = listOfArchives.get(i);
 > +            if (string.trim().isEmpty()){
 > +                continue;
 > +            }
 > +            sb.append(string).append(";");
 > +        }
 > +        return sb.toString();
 > +    }
 > +    public  static List<String> createArchivesList(String 
semicolonedArchives) {
 > +        if (semicolonedArchives == null) return null;
 > +        if (semicolonedArchives.trim().isEmpty()) return null;
 > +        String[] items = semicolonedArchives.trim().split(";");
 > +        List<String> r = new ArrayList<String>(items.length);
 > +        for (int i = 0; i < items.length; i++) {
 > +            String string = items[i];
 > +            if (string.trim().isEmpty()){
 > +                continue;
 > +            }
 > +            r.add(string);
 > +
 > +        }
 > +        return r;
 > +
 > +    }
 > +
 > +
 > +
 > +
 > +}
 > diff -r e631770d76ba 
netx/net/sourceforge/appletextendedsecurity/UnsignedAppletActionStorage.java
 > --- /dev/null    Thu Jan 01 00:00:00 1970 +0000
 > +++ 
b/netx/net/sourceforge/appletextendedsecurity/UnsignedAppletActionStorage.java 
Fri Feb 01 20:55:48 2013 +0100
 > @@ -0,0 +1,106 @@
 > +/*
 > +Copyright (C) 2013 Red Hat
 > +
 > +This program is free software; you can redistribute it and/or modify
 > +it under the terms of the GNU General Public License as published by
 > +the Free Software Foundation; either version 2 of the License, or
 > +(at your option) any later version.
 > +
 > +This program is distributed in the hope that it will be useful, but
 > +WITHOUT ANY WARRANTY; without even the implied warranty of
 > +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
 > +General Public License for more details.
 > +
 > +You should have received a copy of the GNU General Public License
 > +along with this program; if not, write to the Free Software
 > +Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
 > +*//*
 > +Copyright (C) 2013 Red Hat
 > +
 > +This program is free software; you can redistribute it and/or modify
 > +it under the terms of the GNU General Public License as published by
 > +the Free Software Foundation; either version 2 of the License, or
 > +(at your option) any later version.
 > +
 > +This program is distributed in the hope that it will be useful, but
 > +WITHOUT ANY WARRANTY; without even the implied warranty of
 > +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
 > +General Public License for more details.
 > +
 > +You should have received a copy of the GNU General Public License
 > +along with this program; if not, write to the Free Software
 > +Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
 > +*/
 > +package net.sourceforge.appletextendedsecurity;
 > +
 > +import java.util.List;
 > +
 > +/**
 > + *
 > + * @author jvanek
 > + */
 > +public interface UnsignedAppletActionStorage {
 > +
 > +
 > +    /**
 > +     * This methods iterates through record in 
DeploymentConfiguration.getAppletTrustSettingsPath(),

s/record/records/

 > +     * and is mathing regexes saved here against params. so 
parameters here are NOR tegexes,

s/mathing/matching/
s/NOR/NOT/
s/tegexes/regexes/

 > +     * but are matched against saved regexes
 > +     *
 > +     * Null or empty values are dangerously ignored, user, be aware 
of it.
 > +     * eg:
 > +     * match only codeBase will be null someCodeBase null null
 > +     * match only documentBase will be someDocBase null null null
 > +     * match only applet not regarding code or document base will be 
null null mainClas archives

s/mainClas/mainClass/

 > +     * @param documentBase
 > +     * @param codeBase
 > +     * @param mainClass
 > +     * @param archives
 > +     * @return
 > +     */
 > +    public UnsignedAppletActionEntry getMatchingItem(String 
documentBase, String codeBase, String mainClass, List<String> archives);
 > +    /**
 > +     * Shortcut getMatchingItem(documentBase, null,null,null)
 > +     * @param documentBase
 > +     * @return
 > +     */
 > +    public UnsignedAppletActionEntry 
getMatchingItemByDocumentBase(String documentBase);
 > +    /**
 > +     * Shortcut getMatchingItem(null, codeBase,null,null)
 > +     * @param codeBase
 > +     * @return
 > +     */
 > +    public UnsignedAppletActionEntry 
getMatchingItemByCodeBase(String codeBase);
 > +    /**
 > +     * Shortcut getMatchingItem(documentBase, codeBase,null,null)
 > +     * @param documentBase
 > +     * @param  codeBase
 > +     * @return
 > +     */
 > +    public UnsignedAppletActionEntry getMatchingItemByBases(String 
documentBase, String codeBase);
 > +
 > +    /**
 > +     * Will add new record. Note that regexes are stored for bases 
matching.
 > +     *
 > +     * eg UnsignedAppletActionEntry which will dany some applet no 
metter of page will be

s/dany/deny/
s/metter/matter/

 > +     * new UnsignedAppletActionEntry(UnsignedAppletAction.NEVER, new 
Date(), null, null, someMain, someArchives)
 > +     *
 > +     * eg UnsignedAppletActionEntry which will allow all applets on 
page with same codebase will be
 > +     * new UnsignedAppletActionEntry(UnsignedAppletAction.NEVER, new 
Date(), ".*", ".*", null, null);
 > +     *
 > +     * @param item
 > +     */
 > +    public void add(final UnsignedAppletActionEntry item);
 > +
 > +    /**
 > +     * Will replace (current impl is matching  by  object's hashcode
 > +     * This is not reloading the list(but still saving after), so 
StorageIoEception
 > +     * can be thrown if it was not loaded before.
 > +     *
 > +     * Imho this should be used only to actualise timestamps or 
change UnsignedAppletAction
 > +     * @param item
 > +     */
 > +    public void update(final UnsignedAppletActionEntry item);
 > +
 > +
 > +}
 > diff -r e631770d76ba 
netx/net/sourceforge/appletextendedsecurity/UrlRegEx.java
 > --- /dev/null    Thu Jan 01 00:00:00 1970 +0000
 > +++ b/netx/net/sourceforge/appletextendedsecurity/UrlRegEx.java    
Fri Feb 01 20:55:48 2013 +0100
 > @@ -0,0 +1,47 @@
 > +/*
 > +Copyright (C) 2013 Red Hat
 > +
 > +This program is free software; you can redistribute it and/or modify
 > +it under the terms of the GNU General Public License as published by
 > +the Free Software Foundation; either version 2 of the License, or
 > +(at your option) any later version.
 > +
 > +This program is distributed in the hope that it will be useful, but
 > +WITHOUT ANY WARRANTY; without even the implied warranty of
 > +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
 > +General Public License for more details.
 > +
 > +You should have received a copy of the GNU General Public License
 > +along with this program; if not, write to the Free Software
 > +Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
 > +*/
 > +
 > +package net.sourceforge.appletextendedsecurity;
 > +
 > +public class UrlRegEx {
 > +
 > +    String regEx;
 > +    //cache pattern during each set and init?
 > +    //Pattern p
 > +
 > +    public UrlRegEx(String s) {
 > +        regEx = s;
 > +    }
 > +
 > +    @Override
 > +    public String toString() {
 > +        return getRegEx();
 > +    }
 > +
 > +    public String getRegEx() {
 > +        return regEx;
 > +    }
 > +
 > +    public String getFilteredRegEx() {
 > +        return regEx.replaceAll("\\\\Q", "").replaceAll("\\\\E", "");
 > +    }
 > +
 > +    public void setRegEx(String regEx) {
 > +        this.regEx = regEx;
 > +    }
 > +}
 > diff -r e631770d76ba 
netx/net/sourceforge/appletextendedsecurity/impl/UnsignedAppletActionStorageImpl.java
 > --- /dev/null    Thu Jan 01 00:00:00 1970 +0000
 > +++ 
b/netx/net/sourceforge/appletextendedsecurity/impl/UnsignedAppletActionStorageImpl.java 
Fri Feb 01 20:55:48 2013 +0100
 > @@ -0,0 +1,220 @@
 > +/*
 > +Copyright (C) 2013 Red Hat
 > +
 > +This program is free software; you can redistribute it and/or modify
 > +it under the terms of the GNU General Public License as published by
 > +the Free Software Foundation; either version 2 of the License, or
 > +(at your option) any later version.
 > +
 > +This program is distributed in the hope that it will be useful, but
 > +WITHOUT ANY WARRANTY; without even the implied warranty of
 > +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
 > +General Public License for more details.
 > +
 > +You should have received a copy of the GNU General Public License
 > +along with this program; if not, write to the Free Software
 > +Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
 > +*/
 > +
 > +package net.sourceforge.appletextendedsecurity.impl;
 > +
 > +import java.io.BufferedWriter;
 > +import java.io.File;
 > +import java.io.IOException;
 > +import java.util.ArrayList;
 > +import java.util.Collections;
 > +import java.util.List;
 > +import net.sourceforge.appletextendedsecurity.UnsignedAppletActionEntry;
 > +import 
net.sourceforge.appletextendedsecurity.UnsignedAppletActionStorage;
 > +import net.sourceforge.jnlp.util.lockingfile.LockingReaderWriter;
 > +import net.sourceforge.jnlp.util.lockingfile.StorageIoException;
 > +
 > +public class UnsignedAppletActionStorageImpl extends 
LockingReaderWriter implements UnsignedAppletActionStorage{
 > +
 > +    protected List<UnsignedAppletActionEntry> items;
 > +
 > +    public UnsignedAppletActionStorageImpl(String location) {
 > +        this(new File(location));
 > +    }
 > +
 > +    public UnsignedAppletActionStorageImpl(File location) {
 > +        super(location);
 > +    }
 > +
 > +    @Override
 > +    public void writeContents() throws IOException {
 > +        super.writeContents();
 > +    }
 > +
 > +    @Override
 > +    public synchronized void writeContentsLocked() throws IOException {
 > +        super.writeContentsLocked();
 > +    }
 > +
 > +
 > +
 > +
 > +
 > +    @Override
 > +    protected void readContents() throws IOException {
 > +        if (items == null) {
 > +            items = new ArrayList<UnsignedAppletActionEntry>();
 > +        } else {
 > +            items.clear();
 > +        }
 > +        super.readContents();
 > +    }
 > +
 > +    @Override
 > +    protected void readLine(String line) {
 > +        if (line.trim().length() != 0) {
 > + this.items.add(UnsignedAppletActionEntry.createFromString(line));
 > +        }
 > +    }
 > +
 > +    @Override
 > +    public void writeContent(BufferedWriter bw) throws IOException {
 > +        for (UnsignedAppletActionEntry item : items) {
 > +            item.write(bw);
 > +            bw.newLine();
 > +        }
 > +    }
 > +
 > +    @Override
 > +    public void add(final UnsignedAppletActionEntry item) {
 > +        doLocked(new Runnable() {
 > +
 > +            @Override
 > +            public void run() {
 > +                try {
 > +                    readContents();
 > +                    items.add(item);
 > +                    writeContents();
 > +                } catch (IOException ex) {
 > +                    throw new StorageIoException(ex);
 > +                }
 > +            }
 > +        });
 > +    }
 > +
 > +
 > +        @Override
 > +    public void update(final UnsignedAppletActionEntry item) {
 > +        doLocked(new Runnable() {
 > +
 > +            @Override
 > +            public void run() {
 > +                try {
 > +                    if (items == null){
 > +                        throw new StorageIoException("Storage is not 
initialised, can not update");
 > +                    }
 > +                    if (!items.contains(item)){
 > +                        throw new StorageIoException("Storage do not 
contains item you are updateing. can not update");

s/do not contains/does not contain/
s/updateing/updating/

 > +                    }
 > +                    writeContents();
 > +                } catch (IOException ex) {
 > +                    throw new StorageIoException(ex);
 > +                }
 > +            }
 > +        });
 > +    }
 > +
 > +
 > +
 > +    @Override
 > +    public UnsignedAppletActionEntry getMatchingItem(String 
documentBase, String codeBase, String mainClass, List<String> archives) {
 > +        List<UnsignedAppletActionEntry> result = 
getMatchingItems(documentBase, codeBase, mainClass, archives);
 > +        if (result == null || result.isEmpty()) {
 > +            return null;
 > +        }
 > +        //returns first item
 > +        return result.get(0);
 > +        //Or longest match??
 > +    }
 > +
 > +    public List<UnsignedAppletActionEntry> getMatchingItems(String 
documentBase, String codeBase, String mainClass, List<String> archives ) {
 > +        List<UnsignedAppletActionEntry> result = new ArrayList();
 > +        lock();
 > +        try {
 > +            readContents();
 > +            if (items == null) {
 > +                return result;
 > +            }
 > +            for (UnsignedAppletActionEntry unsignedAppletActionEntry 
: items) {
 > +                if 
(isMatching(unsignedAppletActionEntry,documentBase,codeBase,mainClass,archives)){
 > +                    result.add(unsignedAppletActionEntry);
 > +                }
 > +            }
 > +            return null;
 > +        } catch (IOException e) {
 > +            throw new StorageIoException(e);
 > +        } finally {
 > +            unlock();
 > +            return result;
 > +        }
 > +    }
 > +
 > +    private boolean isMatching(UnsignedAppletActionEntry 
unsignedAppletActionEntry, String documentBase, String codeBase, String 
mainClass, List<String> archives) {
 > +    boolean result = true;
 > +        if (documentBase != null && !documentBase.trim().isEmpty()) {
 > +            result = result && 
documentBase.matches(unsignedAppletActionEntry.getDocumentBase().getRegEx());
 > +        }
 > +        if (codeBase != null && !codeBase.trim().isEmpty()) {
 > +            result = result && 
codeBase.matches(unsignedAppletActionEntry.getCodeBase().getRegEx());
 > +        }
 > +        if (mainClass != null && !mainClass.trim().isEmpty()) {
 > +            result = result && 
mainClass.equals(unsignedAppletActionEntry.getMainClass());
 > +        }
 > +
 > +        if (archives != null) {
 > +            result = result && comapreArchives(archives, 
unsignedAppletActionEntry.getArchives());
 > +        }
 > +        return result;
 > +    }
 > +
 > +    @Override
 > +    public String toString() {
 > +        return getBackingFile()+" "+super.toString();
 > +    }
 > +
 > +    private boolean comapreArchives(List<String> archives, 
List<String> saved) {
 > +        if (archives.size()!=saved.size()) return false;
 > +        Collections.sort(archives);
 > +        Collections.sort(saved);
 > +        for (int i = 0; i < saved.size(); i++) {
 > +            String string1 = saved.get(i);
 > +            String string2 = archives.get(i);
 > +            //intentional reference compare
 > +            if (string1==string2) {
 > +                continue;
 > +            }
 > +            if (string1 == null || string2 == null){
 > +                return false;
 > +            }
 > +            if (string1.trim().equals(string2.trim())){
 > +                continue;
 > +            }
 > +            return false;
 > +        }
 > +        return true;
 > +    }
 > +
 > +    @Override
 > +    public UnsignedAppletActionEntry 
getMatchingItemByDocumentBase(String documentBase) {
 > +        return getMatchingItem(documentBase, null, null, null);
 > +    }
 > +
 > +    @Override
 > +    public UnsignedAppletActionEntry 
getMatchingItemByCodeBase(String codeBase) {
 > +        return getMatchingItem(null, codeBase, null, null);
 > +    }
 > +
 > +    @Override
 > +    public UnsignedAppletActionEntry getMatchingItemByBases(String 
documentBase, String codeBase) {
 > +        return getMatchingItem(documentBase, codeBase, null, null);
 > +    }
 > +
 > +
 > +
 > +
 > +}
 > diff -r e631770d76ba 
netx/net/sourceforge/appletextendedsecurity/impl/UnsignedAppletActionStorageOperator.java
 > --- /dev/null    Thu Jan 01 00:00:00 1970 +0000
 > +++ 
b/netx/net/sourceforge/appletextendedsecurity/impl/UnsignedAppletActionStorageOperator.java 
Fri Feb 01 20:55:48 2013 +0100
 > @@ -0,0 +1,180 @@
 > +/*
 > +Copyright (C) 2013 Red Hat
 > +
 > +This program is free software; you can redistribute it and/or modify
 > +it under the terms of the GNU General Public License as published by
 > +the Free Software Foundation; either version 2 of the License, or
 > +(at your option) any later version.
 > +
 > +This program is distributed in the hope that it will be useful, but
 > +WITHOUT ANY WARRANTY; without even the implied warranty of
 > +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
 > +General Public License for more details.
 > +
 > +You should have received a copy of the GNU General Public License
 > +along with this program; if not, write to the Free Software
 > +Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
 > +*/
 > +
 > +package net.sourceforge.appletextendedsecurity.impl;
 > +
 > +import java.io.File;
 > +import java.io.IOException;
 > +import java.util.Date;
 > +import net.sourceforge.appletextendedsecurity.UnsignedAppletAction;
 > +import net.sourceforge.appletextendedsecurity.UnsignedAppletActionEntry;
 > +import net.sourceforge.appletextendedsecurity.UrlRegEx;
 > +import net.sourceforge.jnlp.util.lockingfile.StorageIoException;
 > +
 > +public class UnsignedAppletActionStorageOperator extends 
UnsignedAppletActionStorageImpl {
 > +
 > +
 > +    public UnsignedAppletActionStorageOperator(String location) {
 > +        this(new File(location));
 > +    }
 > +
 > +    public UnsignedAppletActionStorageOperator(File location) {
 > +        super(location);
 > +    }
 > +
 > +    public UnsignedAppletActionEntry[] toArray() {
 > +        lock();
 > +        try {
 > +            readContents();
 > +            return items.toArray(new 
UnsignedAppletActionEntry[items.size()]);
 > +        } catch (IOException e) {
 > +            throw new StorageIoException(e);
 > +        } finally {
 > +            unlock();
 > +        }
 > +    }
 > +
 > +    public void clear() {
 > +        doLocked(new Runnable() {
 > +
 > +            public void run() {
 > +                try {
 > +                    items.clear();
 > +                    writeContents();
 > +                } catch (IOException e) {
 > +                    throw new StorageIoException(e);
 > +                }
 > +            }
 > +        });
 > +    }
 > +
 > +    public void removeByBehaviour(final UnsignedAppletAction 
unsignedAppletAction) {
 > +        doLocked(new Runnable() {
 > +
 > +            public void run() {
 > +                try {
 > +                    readContents();
 > +                    for (int i = 0; i < items.size(); i++) {
 > +                        UnsignedAppletActionEntry 
unsignedAppletActionEntry = items.get(i);
 > +                        if 
(unsignedAppletActionEntry.getUnsignedAppletAction() == 
unsignedAppletAction) {
 > +                            items.remove(i);
 > +                            i--;
 > +                        }
 > +
 > +                    }
 > +                    writeContents();
 > +                } catch (IOException e) {
 > +                    throw new StorageIoException(e);
 > +                }
 > +            }
 > +        });
 > +    }
 > +
 > +    private void swap(final int i, final int ii) {
 > +        doLocked(new Runnable() {
 > +
 > +            public void run() {
 > +                try {
 > +                    readContents();
 > +                    UnsignedAppletActionEntry backup = items.get(i);
 > +                    items.set(i, items.get(ii));
 > +                    items.set(ii, backup);
 > +                    writeContents();
 > +                } catch (IOException e) {
 > +                    throw new StorageIoException(e);
 > +                }
 > +            }
 > +        });
 > +
 > +    }
 > +
 > +    public void moveUp(int selectedRow) {
 > +        if (selectedRow <= 0) {
 > +            return;
 > +        }
 > +        swap(selectedRow, selectedRow - 1);
 > +    }
 > +
 > +    public void moveDown(int selectedRow) {
 > +        if (selectedRow >= items.size() - 1) {
 > +            return;
 > +        }
 > +        swap(selectedRow, selectedRow + 1);
 > +    }
 > +
 > +    public void remove(final int item) {
 > +        doLocked(new Runnable() {
 > +
 > +            public void run() {
 > +                try {
 > +                    readContents();
 > +                    items.remove(item);
 > +                    writeContents();
 > +                } catch (IOException ex) {
 > +                    throw new StorageIoException(ex);
 > +                }
 > +            }
 > +        });
 > +    }
 > +
 > +    public void modify(final UnsignedAppletActionEntry source, final 
int columnIndex, final Object aValue)  {
 > +         Runnable r = new Runnable() {
 > +
 > +            public void run() {
 > +
 > +                try {
 > +                    if (!items.contains(source)){
 > +                        throw new StorageIoException("Item to be 
modified not found in storage");
 > +                    }
 > +
 > +                    if (columnIndex == 0) {
 > + source.setUnsignedAppletAction((UnsignedAppletAction) aValue);
 > +                    }
 > +                    if (columnIndex == 1) {
 > +                        source.setTimeStamp((Date) aValue);
 > +                    }
 > +                    if (columnIndex == 2) {
 > +                        source.setDocumentBase(new UrlRegEx((String) 
aValue));
 > +                    }
 > +                    if (columnIndex == 3) {
 > +                        source.setCodeBase(new UrlRegEx((String) 
aValue));
 > +                    }
 > +                    if (columnIndex == 4) {
 > +                        source.setMainClass((String) aValue);
 > +                    }
 > +                    if (columnIndex == 5) {
 > + 
source.setArchives(UnsignedAppletActionEntry.createArchivesList((String) 
aValue));
 > +                    }
 > +
 > +                    writeContents();
 > +                } catch (IOException ex) {
 > +                    throw new StorageIoException(ex);
 > +                }
 > +            }
 > +        };
 > +        doLocked(r);
 > +
 > +    }
 > +
 > +    @Override
 > +    public synchronized void writeContentsLocked() throws IOException {
 > +        super.writeContentsLocked();
 > +    }
 > +
 > +
 > +}
 > diff -r e631770d76ba netx/net/sourceforge/jnlp/config/Defaults.java
 > --- a/netx/net/sourceforge/jnlp/config/Defaults.java    Thu Jan 31 
11:12:35 2013 +0100
 > +++ b/netx/net/sourceforge/jnlp/config/Defaults.java    Fri Feb 01 
20:55:48 2013 +0100
 > @@ -42,6 +42,7 @@
 >  import java.io.File;
 >  import java.util.HashMap;
 >  import java.util.Map;
 > +import net.sourceforge.appletextendedsecurity.AppletSecurityLevel;
 >
 >  import net.sourceforge.jnlp.ShortcutDesc;
 >  import net.sourceforge.jnlp.runtime.JNLPProxySelector;
 > @@ -384,6 +385,41 @@
 > DeploymentConfiguration.KEY_PLUGIN_JVM_ARGUMENTS,
 >                          null,
 >                          null
 > +                },
 > +               //unsigned applet security level
 > +                {
 > +                DeploymentConfiguration.KEY_SECURITY_LEVEL,
 > +                new ValueValidator() {
 > +
 > +                    @Override
 > +                    public void validate(Object value) throws 
IllegalArgumentException {
 > +                        if (value == null) {
 > +                            throw new 
IllegalArgumentException("Value can't be null");
 > +                        }
 > +                        if (value instanceof AppletSecurityLevel) {
 > +                            //??
 > +                            return;
 > +                        }
 > +                        if (!(value instanceof String)) {
 > +                            throw new 
IllegalArgumentException("Expected was String, was " + value.getClass());
 > +                        }
 > +                        try {
 > +                            AppletSecurityLevel validated = 
AppletSecurityLevel.fromString((String) value);
 > +                            if (validated == null) {
 > +                                throw new 
IllegalArgumentException("Result can't be null, was");
 > +                            }
 > +                            //thrown by fromString
 > +                        } catch (RuntimeException ex) {
 > +                            throw new IllegalArgumentException(ex);
 > +                        }
 > +                    }
 > +
 > +                    @Override
 > +                    public String getPossibleValues() {
 > +                        return AppletSecurityLevel.allToString();
 > +                    }
 > +                },
 > +                null
 >                  }
 >          };
 >
 > diff -r e631770d76ba 
netx/net/sourceforge/jnlp/config/DeploymentConfiguration.java
 > --- a/netx/net/sourceforge/jnlp/config/DeploymentConfiguration.java 
Thu Jan 31 11:12:35 2013 +0100
 > +++ b/netx/net/sourceforge/jnlp/config/DeploymentConfiguration.java 
Fri Feb 01 20:55:48 2013 +0100
 > @@ -51,6 +51,7 @@
 >      public static final String DEPLOYMENT_DIR = ".icedtea";
 >      public static final String DEPLOYMENT_CONFIG = "deployment.config";
 >      public static final String DEPLOYMENT_PROPERTIES = 
"deployment.properties";
 > +    public static final String APPLET_TRUST_SETTINGS = 
".appletTrustSettings";
 >
 >      public static final String DEPLOYMENT_COMMENT = "Netx deployment 
configuration";
 >
 > @@ -105,6 +106,9 @@
 >      /** Boolean. Only show security prompts to user if true */
 >      public static final String KEY_SECURITY_PROMPT_USER = 
"deployment.security.askgrantdialog.show";
 >
 > +    //enum of AppletSecurityLevel in result
 > +    public static final String KEY_SECURITY_LEVEL = 
"deployment.security.level";
 > +
 >      public static final String KEY_SECURITY_TRUSTED_POLICY = 
"deployment.security.trusted.policy";
 >
 >      /** Boolean. Only give 
AWTPermission("showWindowWithoutWarningBanner") if true */
 > @@ -196,6 +200,17 @@
 >          load(true);
 >      }
 >
 > +    public static File getAppletTrustCustomSettingsPath() {
 > +        return new File(System.getProperty("user.home") + 
File.separator + DEPLOYMENT_DIR
 > +                + File.separator + APPLET_TRUST_SETTINGS);
 > +    }
 > +
 > +     public static File getAppletTrustGlobalSettingsPath() {
 > +       return new File(File.separator + "etc" + File.separator + 
".java" + File.separator
 > +                + "deployment" + File.separator + 
APPLET_TRUST_SETTINGS);
 > +
 > +    }
 > +
 >      /**
 >       * Initialize this deployment configuration by reading 
configuration files.
 >       * Generally, it will try to continue and ignore errors it finds 
(such as file not found).
 > diff -r e631770d76ba 
netx/net/sourceforge/jnlp/controlpanel/ControlPanel.java
 > --- a/netx/net/sourceforge/jnlp/controlpanel/ControlPanel.java    Thu 
Jan 31 11:12:35 2013 +0100
 > +++ b/netx/net/sourceforge/jnlp/controlpanel/ControlPanel.java    Fri 
Feb 01 20:55:48 2013 +0100
 > @@ -41,6 +41,7 @@
 >  import javax.swing.JFrame;
 >  import javax.swing.JLabel;
 >  import javax.swing.JList;
 > +import javax.swing.JOptionPane;
 >  import javax.swing.JPanel;
 >  import javax.swing.JScrollPane;
 >  import javax.swing.SwingConstants;
 > @@ -230,7 +231,10 @@
 >                  new SettingsPanel(Translator.R("CPTabNetwork"), 
createNetworkSettingsPanel()),
 >                  // TODO: This is commented out since this is not 
implemented yet
 >                  // new SettingsPanel(Translator.R("CPTabRuntimes"), 
createRuntimesSettingsPanel()),
 > -                new SettingsPanel(Translator.R("CPTabSecurity"), 
createSecuritySettingsPanel()), };
 > +                new SettingsPanel(Translator.R("CPTabSecurity"), 
createSecuritySettingsPanel()),
 > +                //todo refactor to work with tmp file and apply as 
asu designed it
 > +                new 
SettingsPanel(Translator.R("APPEXTSECControlPanelExtendedAppletSecurityTitle"), 
new 
UnsignedAppletsTrustingListPanel(DeploymentConfiguration.getAppletTrustGlobalSettingsPath(),DeploymentConfiguration.getAppletTrustCustomSettingsPath(), 
this.config) )
 > +        };
 >
 >          // Add panels.
 >          final JPanel settingsPanel = new JPanel(new CardLayout());
 > @@ -360,6 +364,7 @@
 >              config.save();
 >          } catch (IOException e) {
 >              e.printStackTrace();
 > +            JOptionPane.showMessageDialog(this, e);
 >          }
 >      }
 >
 > diff -r e631770d76ba 
netx/net/sourceforge/jnlp/controlpanel/UnsignedAppletActionTableModel.java
 > --- /dev/null    Thu Jan 01 00:00:00 1970 +0000
 > +++ 
b/netx/net/sourceforge/jnlp/controlpanel/UnsignedAppletActionTableModel.java 
Fri Feb 01 20:55:48 2013 +0100
 > @@ -0,0 +1,168 @@
 > +/*
 > +Copyright (C) 2013 Red Hat
 > +
 > +This program is free software; you can redistribute it and/or modify
 > +it under the terms of the GNU General Public License as published by
 > +the Free Software Foundation; either version 2 of the License, or
 > +(at your option) any later version.
 > +
 > +This program is distributed in the hope that it will be useful, but
 > +WITHOUT ANY WARRANTY; without even the implied warranty of
 > +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
 > +General Public License for more details.
 > +
 > +You should have received a copy of the GNU General Public License
 > +along with this program; if not, write to the Free Software
 > +Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
 > +*/
 > +
 > +package net.sourceforge.jnlp.controlpanel;
 > +
 > +import java.util.Date;
 > +import javax.swing.table.AbstractTableModel;
 > +import net.sourceforge.appletextendedsecurity.UnsignedAppletAction;
 > +import net.sourceforge.appletextendedsecurity.UnsignedAppletActionEntry;
 > +import net.sourceforge.appletextendedsecurity.UrlRegEx;
 > +import 
net.sourceforge.appletextendedsecurity.impl.UnsignedAppletActionStorageOperator;
 > +import net.sourceforge.jnlp.runtime.Translator;
 > +
 > +public class UnsignedAppletActionTableModel extends AbstractTableModel {
 > +
 > +    final UnsignedAppletActionStorageOperator back;
 > +    private final String[] columns = new 
String[]{Translator.R("APPEXTSECguiTableModelTableColumnAction"),
 > + Translator.R("APPEXTSECguiTableModelTableColumnDateOfAction"),
 > + Translator.R("APPEXTSECguiTableModelTableColumnDocumentBase"),
 > + Translator.R("APPEXTSECguiTableModelTableColumnCodeBase"),
 > + Translator.R("APPEXTSECguiTableModelTableColumnMainClass"),
 > + Translator.R("APPEXTSECguiTableModelTableColumnArchives")};
 > +
 > +    public 
UnsignedAppletActionTableModel(UnsignedAppletActionStorageOperator back) {
 > +        this.back = back;
 > +    }
 > +
 > +    @Override
 > +    public int getRowCount() {
 > +        try {
 > +            return back.toArray().length;
 > +        } catch (Exception ex) {
 > +            throw new RuntimeException(ex);
 > +        }
 > +    }
 > +
 > +    @Override
 > +    public int getColumnCount() {
 > +        return columns.length;
 > +    }
 > +
 > +    @Override
 > +    public String getColumnName(int columnIndex) {
 > +        return columns[columnIndex];
 > +    }
 > +
 > +    @Override
 > +    public Class<?> getColumnClass(int columnIndex) {
 > +        if (columnIndex == 0) {
 > +            return UnsignedAppletAction.class;
 > +        }
 > +        if (columnIndex == 1) {
 > +            return Date.class;
 > +        }
 > +        if (columnIndex == 2) {
 > +            return UrlRegEx.class;
 > +        }
 > +        if (columnIndex == 3) {
 > +            return UrlRegEx.class;
 > +        }
 > +        if (columnIndex == 3) {
 > +            return String.class;
 > +        }
 > +        if (columnIndex == 3) {
 > +            return String.class;
 > +        }
 > +        return Object.class;
 > +    }
 > +
 > +    @Override
 > +    public boolean isCellEditable(int rowIndex, int columnIndex) {
 > +        if (back.isReadOnly()){
 > +            return false;
 > +        }
 > +        if (columnIndex==1) return false;
 > +        if (columnIndex==0) return true;
 > +        if (getValueAt(rowIndex, columnIndex-1)==null || 
getValueAt(rowIndex, columnIndex-1).toString().trim().isEmpty()) return 
false;
 > +        return true;
 > +    }
 > +
 > +    @Override
 > +    public Object getValueAt(int rowIndex, int columnIndex) {
 > +
 > +        UnsignedAppletActionEntry source = back.toArray()[rowIndex];
 > +        if (columnIndex == 0) {
 > +            return source.getUnsignedAppletAction();
 > +        }
 > +        if (columnIndex == 1) {
 > +            return source.getTimeStamp();
 > +        }
 > +        if (columnIndex == 2) {
 > +            return source.getDocumentBase();
 > +        }
 > +        if (columnIndex == 3) {
 > +            return source.getCodeBase();
 > +        }
 > +        if (columnIndex == 4) {
 > +            return source.getMainClass();
 > +        }
 > +        if (columnIndex == 5) {
 > +            return 
UnsignedAppletActionEntry.createArchivesString(source.getArchives());
 > +        }
 > +        return null;
 > +    }
 > +
 > +    @Override
 > +    public void setValueAt(final Object aValue, final int rowIndex, 
final int columnIndex) {
 > +        final UnsignedAppletActionEntry source = 
back.toArray()[rowIndex];
 > +       back.modify(source, columnIndex, aValue);
 > +
 > +    }
 > +
 > +    public void addRow() {
 > +        int i = back.toArray().length;
 > +        String s = "\\Qhttp://localhost:80/\\E.*";
 > +        back.add(new UnsignedAppletActionEntry(
 > +                UnsignedAppletAction.NEVER,
 > +                new Date(),
 > +                new UrlRegEx(s),
 > +                new UrlRegEx(s),
 > +                null,
 > +                null));
 > +        fireTableRowsInserted(i, i + 1);
 > +    }
 > +
 > +    public void removeRow(int i) {
 > +        back.remove(i);
 > +        fireTableRowsDeleted(i, i);
 > +    }
 > +
 > +    public void clear() {
 > +        int i = getRowCount();
 > +        back.clear();
 > +        fireTableRowsDeleted(0, i);
 > +    }
 > +
 > +    void removeByBehaviour(UnsignedAppletAction unsignedAppletAction) {
 > +        int i = getRowCount();
 > +        back.removeByBehaviour(unsignedAppletAction);
 > +        fireTableRowsDeleted(0, i);
 > +    }
 > +
 > +    void moveUp(int selectedRow) {
 > +        int i = getRowCount();
 > +        back.moveUp(selectedRow);
 > +        fireTableRowsUpdated(i-1, i);
 > +    }
 > +    void moveDown(int selectedRow) {
 > +        int i = getRowCount();
 > +        back.moveDown(selectedRow);
 > +        fireTableRowsUpdated(i, i+1);
 > +    }
 > +}
 > diff -r e631770d76ba 
netx/net/sourceforge/jnlp/controlpanel/UnsignedAppletsTrustingListPanel.java
 > --- /dev/null    Thu Jan 01 00:00:00 1970 +0000
 > +++ 
b/netx/net/sourceforge/jnlp/controlpanel/UnsignedAppletsTrustingListPanel.java 
Fri Feb 01 20:55:48 2013 +0100
 > @@ -0,0 +1,665 @@
 > +/*
 > + Copyright (C) 2013 Red Hat
 > +
 > + This program is free software; you can redistribute it and/or modify
 > + it under the terms of the GNU General Public License as published by
 > + the Free Software Foundation; either version 2 of the License, or
 > + (at your option) any later version.
 > +
 > + This program is distributed in the hope that it will be useful, but
 > + WITHOUT ANY WARRANTY; without even the implied warranty of
 > + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
 > + General Public License for more details.
 > +
 > + You should have received a copy of the GNU General Public License
 > + along with this program; if not, write to the Free Software
 > + Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
 > + */
 > +package net.sourceforge.jnlp.controlpanel;
 > +
 > +import java.awt.BorderLayout;
 > +import java.io.BufferedWriter;
 > +import java.io.File;
 > +import java.io.FileOutputStream;
 > +import java.io.OutputStreamWriter;
 > +import java.text.DateFormat;
 > +import java.util.ArrayList;
 > +import java.util.Collections;
 > +import java.util.Date;
 > +import java.util.List;
 > +import java.util.regex.Pattern;
 > +import javax.swing.event.ChangeEvent;
 > +import javax.swing.event.ListSelectionEvent;
 > +import net.sourceforge.appletextendedsecurity.UnsignedAppletAction;
 > +import net.sourceforge.appletextendedsecurity.UrlRegEx;
 > +import javax.swing.DefaultCellEditor;
 > +import javax.swing.JComboBox;
 > +import javax.swing.JFrame;
 > +import javax.swing.JOptionPane;
 > +import javax.swing.JPanel;
 > +import javax.swing.JTable;
 > +import javax.swing.JTextField;
 > +import javax.swing.event.ChangeListener;
 > +import javax.swing.event.ListSelectionListener;
 > +import javax.swing.table.DefaultTableCellRenderer;
 > +import javax.swing.table.DefaultTableModel;
 > +import javax.swing.table.TableCellEditor;
 > +import javax.swing.table.TableCellRenderer;
 > +import javax.swing.table.TableModel;
 > +import net.sourceforge.appletextendedsecurity.UnsignedAppletActionEntry;
 > +import 
net.sourceforge.appletextendedsecurity.impl.UnsignedAppletActionStorageOperator;
 > +import net.sourceforge.appletextendedsecurity.AppletSecurityLevel;
 > +import net.sourceforge.jnlp.config.DeploymentConfiguration;
 > +import net.sourceforge.jnlp.runtime.Translator;
 > +
 > +public class UnsignedAppletsTrustingListPanel extends 
javax.swing.JPanel {
 > +
 > +    private javax.swing.JButton jButton1;
 > +    private javax.swing.JButton jButton2;
 > +    private javax.swing.JButton jButton3;
 > +    private javax.swing.JButton jButton4;
 > +    private javax.swing.JButton jButton5;
 > +    private javax.swing.JButton jButton6;
 > +    private javax.swing.JButton jButton7;
 > +    private javax.swing.JButton jButton8;
 > +    private javax.swing.JCheckBox jCheckBox1;
 > +    private javax.swing.JCheckBox jCheckBox2;
 > +    private javax.swing.JComboBox jComboBox1;
 > +    private javax.swing.JComboBox jComboBox2;
 > +    private javax.swing.JLabel jLabel1;
 > +    private javax.swing.JLabel jLabel2;
 > +    private javax.swing.JScrollPane jScrollPane1;
 > +    private javax.swing.JTabbedPane jTabPane1;
 > +    private javax.swing.JTable jTable1;
 > +    private javax.swing.JScrollPane jScrollPane2;
 > +    private javax.swing.JTable jTable2;
 > +    private final UnsignedAppletActionStorageOperator customBackEnd;
 > +    private final UnsignedAppletActionStorageOperator globalBackEnd;
 > +    private final UnsignedAppletActionTableModel customModel;
 > +    private final UnsignedAppletActionTableModel globalModel;
 > +    private final DeploymentConfiguration conf;
 > +    private javax.swing.JTable currentTable;
 > +    private UnsignedAppletActionTableModel currentModel;
 > +    private String lastDoc;
 > +    private String lastCode;
 > +
 > +
 > +    /*
 > +     * for testing and playing
 > +     */
 > +    public static void main(String args[]) {
 > +        final String defaultDir = System.getProperty("user.home") + 
"/Desktop/";
 > +        final String defaultFileName1 = "terrorList1";
 > +        final String defaultFileName2 = "terrorList2";
 > +        final String defaultFile1 = defaultDir + defaultFileName1;
 > +        final String defaultFile2 = defaultDir + defaultFileName2;
 > +        java.awt.EventQueue.invokeLater(new Runnable() {
 > +            @Override
 > +            public void run() {
 > +                try {
 > +                    JFrame f = new JFrame();
 > +                    f.setSize(700, 300);
 > +                    f.setLayout(new BorderLayout());
 > + f.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
 > +                    DeploymentConfiguration cc = new 
DeploymentConfiguration();
 > +                    cc.load();
 > +                    File ff1 = new File(defaultFile1);
 > +                    File ff2 = new File(defaultFile2);
 > +                    f.add(new UnsignedAppletsTrustingListPanel(ff2, 
ff1, cc));
 > +                    f.setVisible(true);
 > +                } catch (Exception ex) {
 > +                    ex.printStackTrace();
 > +                }
 > +            }
 > +        });
 > +    }
 > +
 > +    public UnsignedAppletsTrustingListPanel(File globalSettings, 
File customSettings, DeploymentConfiguration conf) {
 > +        customBackEnd = new 
UnsignedAppletActionStorageOperator(customSettings);
 > +        globalBackEnd = new 
UnsignedAppletActionStorageOperator(globalSettings);
 > +        customModel = new UnsignedAppletActionTableModel(customBackEnd);
 > +        globalModel = new UnsignedAppletActionTableModel(globalBackEnd);
 > +        initComponents();
 > +        this.conf = conf;
 > +        AppletSecurityLevel gs = AppletSecurityLevel.getDefault();
 > +        String s = 
conf.getProperty(DeploymentConfiguration.KEY_SECURITY_LEVEL);
 > +        if (s != null) {
 > +            gs = AppletSecurityLevel.fromString(s);
 > +        }
 > +        jComboBox1.setSelectedItem(gs);
 > + jTable1.getSelectionModel().addListSelectionListener(new 
SingleSelectionListenerImpl(jTable1));
 > + jTable2.getSelectionModel().addListSelectionListener(new 
SingleSelectionListenerImpl(jTable2));
 > +        currentTable = jTable1;
 > +        currentModel = customModel;
 > +        setButtons((!currentModel.back.isReadOnly()));
 > +    }
 > +
 > +    public String 
appletItemsToCaption(List<UnsignedAppletActionEntry> ii, String caption) {
 > +        StringBuilder sb = new StringBuilder();
 > +        for (UnsignedAppletActionEntry i : ii) {
 > +            sb.append(appletItemToCaption(i, caption)).append("\n");
 > +        }
 > +        return sb.toString();
 > +    }
 > +
 > +    public String appletItemToCaption(UnsignedAppletActionEntry i, 
String caption) {
 > +        return Translator.R("APPEXTSECguiPanelAppletInfoHederPart1", 
caption, i.getDocumentBase().getFilteredRegEx())
 > +                + "\n  (" + 
Translator.R("APPEXTSECguiPanelAppletInfoHederPart2", 
i.getUnsignedAppletAction(), 
DateFormat.getInstance().format(i.getTimeStamp()))
 > +                + "\n    " + 
Translator.R("APPEXTSECguiTableModelTableColumnDocumentBase") + ": " + 
i.getDocumentBase().getFilteredRegEx()
 > +                + "\n    " + 
Translator.R("APPEXTSECguiTableModelTableColumnCodeBase") + ": " + 
i.getCodeBase().getFilteredRegEx()
 > +                + "\n    " + 
Translator.R("APPEXTSECguiTableModelTableColumnMainClass") + ": " + 
((i.getMainClass() == null) ? "" : i.getMainClass())
 > +                + "\n    " + 
Translator.R("APPEXTSECguiTableModelTableColumnArchives") + ": " + 
UnsignedAppletActionEntry.createArchivesString(i.getArchives());
 > +    }
 > +
 > +    public void removeSelectedFromTable(JTable table) {
 > +        int[] originalIndexes = table.getSelectedRows();
 > +        List<Integer> newIndexes = new 
ArrayList<Integer>(originalIndexes.length);
 > +        for (int i = 0; i < originalIndexes.length; i++) {
 > +            //we need to remap values first
 > +            int modelRow = 
table.convertRowIndexToModel(originalIndexes[i]);
 > +            newIndexes.add(modelRow);
 > +        }
 > +        //now to sort so we can incrementaly dec safely
 > +        Collections.sort(newIndexes);
 > +        if (jCheckBox1.isSelected()) {
 > +            String s = 
Translator.R("APPEXTSECguiPanelConfirmDeletionOf", newIndexes.size()) + 
": \n";
 > +            UnsignedAppletActionEntry[] items = 
currentModel.back.toArray();
 > +            for (int i = 0; i < newIndexes.size(); i++) {
 > +                Integer integer = newIndexes.get(i);
 > +                s += appletItemToCaption(items[integer], "  ") + "\n";
 > +            }
 > +            int a = JOptionPane.showConfirmDialog(this, s);
 > +            if (a != JOptionPane.OK_OPTION) {
 > +                return;
 > +            }
 > +        }
 > +        int sub = 0;
 > +        for (int i = 0; i < newIndexes.size(); i++) {
 > +            Integer integer = newIndexes.get(i);
 > +            currentModel.removeRow(integer.intValue() + sub);
 > +            sub--;
 > +        }
 > +    }
 > +
 > +    public void removeAllItemsFromTable(JTable table, 
UnsignedAppletActionTableModel model) {
 > +        table.clearSelection();
 > +
 > +        if (jCheckBox1.isSelected()) {
 > +            UnsignedAppletActionEntry[] items = model.back.toArray();
 > +            String s = 
Translator.R("APPEXTSECguiPanelConfirmDeletionOf", items.length) + ": \n";
 > +            for (int i = 0; i < items.length; i++) {
 > +                s += appletItemToCaption(items[i], "  ") + "\n";
 > +            }
 > +            int a = JOptionPane.showConfirmDialog(this, s);
 > +            if (a != JOptionPane.OK_OPTION) {
 > +                return;
 > +            }
 > +        }
 > +        model.clear();
 > +    }
 > +
 > +    private void initComponents() {
 > +
 > +        jScrollPane1 = new javax.swing.JScrollPane();
 > +        jScrollPane2 = new javax.swing.JScrollPane();
 > +        jTable1 = createTbale(customModel);
 > +        jTable2 = createTbale(globalModel);
 > +        jButton1 = new javax.swing.JButton();
 > +        jComboBox1 = new JComboBox(new AppletSecurityLevel[]{
 > +                    AppletSecurityLevel.DENY_ALL,
 > +                    AppletSecurityLevel.DENY_UNSIGNED,
 > +                    AppletSecurityLevel.ASK_UNSIGNED,
 > +                    AppletSecurityLevel.ALLOW_UNSIGNED
 > +                });
 > + jComboBox1.setSelectedItem(AppletSecurityLevel.getDefault());
 > +        jLabel2 = new javax.swing.JLabel();
 > +        jLabel1 = new javax.swing.JLabel();
 > +        jComboBox2 = new javax.swing.JComboBox();
 > +        jButton2 = new javax.swing.JButton();
 > +        jButton5 = new javax.swing.JButton();
 > +        jButton3 = new javax.swing.JButton();
 > +        jButton4 = new javax.swing.JButton();
 > +        jCheckBox1 = new javax.swing.JCheckBox();
 > +        jCheckBox2 = new javax.swing.JCheckBox();
 > +        jButton6 = new javax.swing.JButton();
 > +        jButton7 = new javax.swing.JButton();
 > +        jButton8 = new javax.swing.JButton();
 > +        jTabPane1 = new javax.swing.JTabbedPane();
 > +
 > +        jScrollPane1.setViewportView(jTable1);
 > +
 > +        jScrollPane2.setViewportView(jTable2);
 > +
 > + jButton1.setText(Translator.R("APPEXTSECguiPanelHelpButton"));
 > +        jButton1.addActionListener(new java.awt.event.ActionListener() {
 > +            @Override
 > +            public void actionPerformed(java.awt.event.ActionEvent 
evt) {
 > +                jButton1ActionPerformed(evt);
 > +            }
 > +        });
 > +
 > +        jComboBox1.addActionListener(new 
java.awt.event.ActionListener() {
 > +            @Override
 > +            public void actionPerformed(java.awt.event.ActionEvent 
evt) {
 > +                jComboBox1ActionPerformed(evt);
 > +            }
 > +        });
 > +
 > + jLabel2.setText(Translator.R("APPEXTSECguiPanelSecurityLevel"));
 > +
 > + 
jLabel1.setText(Translator.R("APPEXTSECguiPanelGlobalBehaviourCaption"));
 > +
 > +        jComboBox2.setModel(new javax.swing.DefaultComboBoxModel(new 
String[]{
 > + Translator.R("APPEXTSECguiPanelDeleteMenuSelected"),
 > + Translator.R("APPEXTSECguiPanelDeleteMenuAllA"),
 > + Translator.R("APPEXTSECguiPanelDeleteMenuAllN"),
 > + Translator.R("APPEXTSECguiPanelDeleteMenuAlly"),
 > + Translator.R("APPEXTSECguiPanelDeleteMenuAlln"),
 > + Translator.R("APPEXTSECguiPanelDeleteMenuAllAll")}));
 > +
 > + jButton2.setText(Translator.R("APPEXTSECguiPanelDeleteButton"));
 > +        jButton2.addActionListener(new java.awt.event.ActionListener() {
 > +            @Override
 > +            public void actionPerformed(java.awt.event.ActionEvent 
evt) {
 > +                jButton2ActionPerformed(evt);
 > +            }
 > +        });
 > +
 > + jButton5.setText(Translator.R("APPEXTSECguiPanelTestUrlButton"));
 > +        jButton5.addActionListener(new java.awt.event.ActionListener() {
 > +            @Override
 > +            public void actionPerformed(java.awt.event.ActionEvent 
evt) {
 > +                jButton5ActionPerformed(evt);
 > +            }
 > +        });
 > +
 > + jButton3.setText(Translator.R("APPEXTSECguiPanelAddRowButton"));
 > +        jButton3.addActionListener(new java.awt.event.ActionListener() {
 > +            @Override
 > +            public void actionPerformed(java.awt.event.ActionEvent 
evt) {
 > +                jButton3ActionPerformed(evt);
 > +            }
 > +        });
 > +
 > + jButton4.setText(Translator.R("APPEXTSECguiPanelValidateTableButton"));
 > +        jButton4.addActionListener(new java.awt.event.ActionListener() {
 > +            @Override
 > +            public void actionPerformed(java.awt.event.ActionEvent 
evt) {
 > +                jButton4ActionPerformed(evt);
 > +            }
 > +        });
 > +
 > +        jCheckBox1.setSelected(true);
 > + jCheckBox1.setText(Translator.R("APPEXTSECguiPanelAskeforeActionBox"));
 > +
 > + jCheckBox2.setText(Translator.R("APPEXTSECguiPanelShowRegExesBox"));
 > +        jCheckBox2.addActionListener(new 
java.awt.event.ActionListener() {
 > +            @Override
 > +            public void actionPerformed(java.awt.event.ActionEvent 
evt) {
 > +                jCheckBox2ActionPerformed(evt);
 > +            }
 > +        });
 > +
 > + jButton6.setText(Translator.R("APPEXTSECguiPanelInverSelection"));
 > +        jButton6.addActionListener(new java.awt.event.ActionListener() {
 > +            @Override
 > +            public void actionPerformed(java.awt.event.ActionEvent 
evt) {
 > +                jButton6ActionPerformed(evt);
 > +            }
 > +        });
 > +
 > + jButton7.setText(Translator.R("APPEXTSECguiPanelMoveRowUp"));
 > +        jButton7.setEnabled(false);
 > +        jButton7.addActionListener(new java.awt.event.ActionListener() {
 > +            @Override
 > +            public void actionPerformed(java.awt.event.ActionEvent 
evt) {
 > +                jButton7ActionPerformed(evt);
 > +            }
 > +        });
 > +
 > + jButton8.setText(Translator.R("APPEXTSECguiPanelMoveRowDown"));
 > +        jButton8.setEnabled(false);
 > +        jButton8.addActionListener(new java.awt.event.ActionListener() {
 > +            @Override
 > +            public void actionPerformed(java.awt.event.ActionEvent 
evt) {
 > +                jButton8ActionPerformed(evt);
 > +            }
 > +        });
 > +
 > +        javax.swing.GroupLayout layout = new 
javax.swing.GroupLayout(this);
 > +        this.setLayout(layout);
 > +        layout.setHorizontalGroup(
 > + 
layout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING).addGroup(javax.swing.GroupLayout.Alignment.TRAILING, 
layout.createSequentialGroup().addContainerGap().addGroup(layout.createParallelGroup(javax.swing.GroupLayout.Alignment.TRAILING).addComponent(jTabPane1, 
javax.swing.GroupLayout.Alignment.LEADING, 
javax.swing.GroupLayout.DEFAULT_SIZE, 583, 
Short.MAX_VALUE).addComponent(jLabel1, 
javax.swing.GroupLayout.Alignment.LEADING).addGroup(javax.swing.GroupLayout.Alignment.LEADING, 
layout.createSequentialGroup().addComponent(jLabel2).addPreferredGap(javax.swing.LayoutStyle.ComponentPlacement.RELATED).addComponent(jComboBox1, 
0, 474, 
Short.MAX_VALUE)).addGroup(javax.swing.GroupLayout.Alignment.LEADING, 
layout.createSequentialGroup().addComponent(jButton3).addPreferredGap(javax.swing.LayoutStyle.ComponentPlacement.UNRELATED).addComponent(jButton4).addPreferredGap(javax.swing.LayoutStyle.ComponentPlacement.UNRELATED).addComponent(jButton5).addPreferredGap(javax.swing.LayoutStyle.ComponentPlacement.RELATED, 
94, 
Short.MAX_VALUE).addComponent(jButton8).addPreferredGap(javax.swing.LayoutStyle.ComponentPlacement.RELATED).addComponent(jButton7)).addGroup(layout.createSequentialGroup().addGroup(layout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING).addGroup(layout.createSequentialGroup().addComponent(jButton2).addPreferredGap(javax.swing.LayoutStyle.ComponentPlacement.RELATED).addComponent(jComboBox2, 
javax.swing.GroupLayout.PREFERRED_SIZE, 
javax.swing.GroupLayout.DEFAULT_SIZE, 
javax.swing.GroupLayout.PREFERRED_SIZE).addPreferredGap(javax.swing.LayoutStyle.ComponentPlacement.RELATED).addComponent(jButton6)).addGroup(layout.createSequentialGroup().addComponent(jCheckBox1).addPreferredGap(javax.swing.LayoutStyle.ComponentPlacement.RELATED).addComponent(jCheckBox2))).addPreferredGap(javax.swing.LayoutStyle.ComponentPlacement.RELATED, 
93, Short.MAX_VALUE).addComponent(jButton1, 
javax.swing.GroupLayout.PREFERRED_SIZE, 108, 
javax.swing.GroupLayout.PREFERRED_SIZE))).addContainerGap()));
 > +        layout.setVerticalGroup(
 > + 
layout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING).addGroup(layout.createSequentialGroup().addContainerGap().addComponent(jLabel1).addPreferredGap(javax.swing.LayoutStyle.ComponentPlacement.RELATED).addGroup(layout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING).addComponent(jLabel2).addComponent(jComboBox1, 
javax.swing.GroupLayout.PREFERRED_SIZE, 
javax.swing.GroupLayout.DEFAULT_SIZE, 
javax.swing.GroupLayout.PREFERRED_SIZE)).addPreferredGap(javax.swing.LayoutStyle.ComponentPlacement.RELATED).addGroup(layout.createParallelGroup(javax.swing.GroupLayout.Alignment.TRAILING).addGroup(layout.createSequentialGroup().addGroup(layout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING, 
false).addComponent(jButton2).addComponent(jComboBox2).addComponent(jButton6, 
javax.swing.GroupLayout.DEFAULT_SIZE, 
javax.swing.GroupLayout.DEFAULT_SIZE, 
Short.MAX_VALUE)).addPreferredGap(javax.swing.LayoutStyle.ComponentPlacement.RELATED).addGroup(layout.createParallelGroup(javax.swing.GroupLayout.Alignment.BASELINE).addComponent(jCheckBox1).addComponent(jCheckBox2))).addComponent(jButton1, 
javax.swing.GroupLayout.PREFERRED_SIZE, 53, 
javax.swing.GroupLayout.PREFERRED_SIZE)).addPreferredGap(javax.swing.LayoutStyle.ComponentPlacement.UNRELATED).addComponent(jTabPane1, 
javax.swing.GroupLayout.DEFAULT_SIZE, 161, 
Short.MAX_VALUE).addPreferredGap(javax.swing.LayoutStyle.ComponentPlacement.RELATED).addGroup(layout.createParallelGroup(javax.swing.GroupLayout.Alignment.BASELINE).addComponent(jButton3).addComponent(jButton4).addComponent(jButton5).addComponent(jButton7).addComponent(jButton8)).addContainerGap()));
 > +
 > +        JPanel pane1 = new JPanel(new BorderLayout());
 > +        JPanel pane2 = new JPanel(new BorderLayout());
 > +        pane1.add(jScrollPane1);
 > +        pane2.add(jScrollPane2);
 > +        jTabPane1.add(pane1);
 > +        jTabPane1.add(pane2);
 > +        jTabPane1.setTitleAt(0, 
Translator.R("APPEXTSECguiPanelCustomDefs"));
 > +        jTabPane1.setTitleAt(1, 
Translator.R("APPEXTSECguiPanelGlobalDefs"));
 > +        jTabPane1.setToolTipTextAt(0, 
DeploymentConfiguration.getAppletTrustCustomSettingsPath().getAbsolutePath());
 > +        jTabPane1.setToolTipTextAt(1, 
DeploymentConfiguration.getAppletTrustGlobalSettingsPath().getAbsolutePath());
 > +        jTabPane1.addChangeListener(new ChangeListener() {
 > +            @Override
 > +            public void stateChanged(ChangeEvent e) {
 > +                switch (jTabPane1.getSelectedIndex()) {
 > +                    case 0:
 > +                        currentModel = customModel;
 > +                        currentTable = jTable1;
 > +                        break;
 > +                    case 1:
 > +                        currentModel = globalModel;
 > +                        currentTable = jTable2;
 > +                        break;
 > +                }
 > +                setButtons((!currentModel.back.isReadOnly()));
 > +            }
 > +        });
 > +    }
 > +
 > +    private void 
jComboBox1ActionPerformed(java.awt.event.ActionEvent evt) {
 > +        try {
 > + conf.setProperty(DeploymentConfiguration.KEY_SECURITY_LEVEL, 
((AppletSecurityLevel) jComboBox1.getSelectedItem()).toChars());
 > +            conf.save();
 > +        } catch (Exception ex) {
 > +            ex.printStackTrace();
 > +            JOptionPane.showMessageDialog(this, ex);
 > +        }
 > +    }
 > +
 > +    private void jButton2ActionPerformed(java.awt.event.ActionEvent 
evt) {
 > +
 > +        if (jComboBox2.getSelectedIndex() == 0) {
 > +            removeSelectedFromTable(currentTable);
 > +        }
 > +        if (jComboBox2.getSelectedIndex() == 1) {
 > +            removeByBehaviour(UnsignedAppletAction.ALWAYS);
 > +        }
 > +        if (jComboBox2.getSelectedIndex() == 2) {
 > +            removeByBehaviour(UnsignedAppletAction.NEVER);
 > +        }
 > +        if (jComboBox2.getSelectedIndex() == 3) {
 > +            removeByBehaviour(UnsignedAppletAction.YES);
 > +        }
 > +        if (jComboBox2.getSelectedIndex() == 4) {
 > +            removeByBehaviour(UnsignedAppletAction.NO);
 > +        }
 > +        if (jComboBox2.getSelectedIndex() == 5) {
 > +            removeAllItemsFromTable(currentTable, customModel);
 > +        }
 > +    }
 > +
 > +    private void jButton5ActionPerformed(java.awt.event.ActionEvent 
evt) {
 > +
 > +        String s1 = 
JOptionPane.showInputDialog(Translator.R("APPEXTSECguiPanelDocTest"), 
lastDoc);
 > +        String s2 = 
JOptionPane.showInputDialog(Translator.R("APPEXTSECguiPanelCodeTest"), 
lastCode);
 > +        lastDoc = s1;
 > +        lastCode = s2;
 > +        try {
 > +            List<UnsignedAppletActionEntry> i = 
currentModel.back.getMatchingItems(s1, s2, null, null);
 > +            if (i == null || i.isEmpty()) {
 > +                JOptionPane.showMessageDialog(this, 
Translator.R("APPEXTSECguiPanelNoMatch"));
 > +            } else {
 > +                JOptionPane.showMessageDialog(this, 
Translator.R("APPEXTSECguiPanelMatchingNote") + "\n" + 
appletItemsToCaption(i, Translator.R("APPEXTSECguiPanelMatched") + ": "));
 > +            }
 > +        } catch (Exception ex) {
 > +            ex.printStackTrace();
 > +            JOptionPane.showMessageDialog(this, 
Translator.R("APPEXTSECguiPanelMatchingError", ex));
 > +        }
 > +
 > +    }
 > +
 > +    private void jButton3ActionPerformed(java.awt.event.ActionEvent 
evt) {
 > +
 > +        currentModel.addRow();
 > +    }
 > +
 > +    private void jButton4ActionPerformed(java.awt.event.ActionEvent 
evt) {
 > +
 > +        File f = null;
 > +        try {
 > +            f = File.createTempFile("appletTable", "validation");
 > +        } catch (Exception ex) {
 > +            ex.printStackTrace();
 > +            JOptionPane.showMessageDialog(this, 
Translator.R("APPEXTSECguiPanelCanNOtValidate", ex.toString()));
 > +            return;
 > +        }
 > +        try {
 > +            currentModel.back.writeContentsLocked();
 > +            BufferedWriter bw = new BufferedWriter(new 
OutputStreamWriter(new FileOutputStream(f), "UTF-8"));
 > +            currentModel.back.writeContent(bw);
 > +            bw.flush();
 > +            bw.close();
 > +            UnsignedAppletActionStorageOperator copy = new 
UnsignedAppletActionStorageOperator(f);
 > +            UnsignedAppletActionEntry[] items = copy.toArray();
 > +            for (int i = 0; i < items.length; i++) {
 > +                UnsignedAppletActionEntry unsignedAppletActionEntry 
= items[i];
 > +                if (unsignedAppletActionEntry.getDocumentBase() != 
null && 
!unsignedAppletActionEntry.getDocumentBase().getRegEx().trim().isEmpty()) {
 > +                    Pattern p = 
Pattern.compile(unsignedAppletActionEntry.getDocumentBase().getRegEx());
 > +                    p.matcher("someInput").find();
 > +                } else {
 > +                    throw new 
RuntimeException(Translator.R("APPEXTSECguiPanelEmptyDoc"));
 > +                }
 > +                if (unsignedAppletActionEntry.getCodeBase() != null 
&& !unsignedAppletActionEntry.getCodeBase().getRegEx().trim().isEmpty()) {
 > +                    Pattern p = 
Pattern.compile(unsignedAppletActionEntry.getCodeBase().getRegEx());
 > +                    p.matcher("someInput").find();
 > +                } else {
 > +                    throw new 
RuntimeException(Translator.R("APPEXTSECguiPanelEmptyCode"));
 > +                }
 > + 
UnsignedAppletActionEntry.createArchivesString(UnsignedAppletActionEntry.createArchivesList(UnsignedAppletActionEntry.createArchivesString(unsignedAppletActionEntry.getArchives())));
 > +
 > +            }
 > +            JOptionPane.showMessageDialog(this, 
Translator.R("APPEXTSECguiPanelTableValid"));
 > +        } catch (Exception ex) {
 > +            ex.printStackTrace();
 > +            JOptionPane.showMessageDialog(this, 
Translator.R("APPEXTSECguiPanelTableInvalid ", ex.toString()));
 > +        } finally {
 > +            f.delete();
 > +        }
 > +
 > +    }
 > +
 > +    private void 
jCheckBox2ActionPerformed(java.awt.event.ActionEvent evt) {
 > +
 > +        reloadTable();
 > +    }
 > +
 > +    private void jButton6ActionPerformed(java.awt.event.ActionEvent 
evt) {
 > +        int[] selectedIndexs = currentTable.getSelectedRows();
 > +        currentTable.selectAll();
 > +
 > +        for (int i = 0; i < currentTable.getRowCount(); i++) {
 > +            for (int selectedIndex : selectedIndexs) {
 > +                if (selectedIndex == i) {
 > +                    currentTable.removeRowSelectionInterval(i, i);
 > +                    break;
 > +                }
 > +            }
 > +        }
 > +    }
 > +
 > +    private void jButton7ActionPerformed(java.awt.event.ActionEvent 
evt) {
 > +        int orig = currentTable.getSelectedRow();
 > +        int i = currentTable.convertRowIndexToModel(orig);
 > +        currentModel.moveUp(i);
 > +        reloadTable();
 > +        if (orig >= 1) {
 > + currentTable.getSelectionModel().setSelectionInterval(orig - 1, 
orig - 1);
 > +        }
 > +    }
 > +
 > +    private void jButton8ActionPerformed(java.awt.event.ActionEvent 
evt) {
 > +        int orig = currentTable.getSelectedRow();
 > +        int i = currentTable.convertRowIndexToModel(orig);
 > +        currentModel.moveDown(i);
 > +        reloadTable();
 > +        if (orig < currentModel.getRowCount()) {
 > + currentTable.getSelectionModel().setSelectionInterval(orig + 1, 
orig + 1);
 > +        }
 > +    }
 > +
 > +    private void jButton1ActionPerformed(java.awt.event.ActionEvent 
evt) {
 > +    }
 > +
 > +    private void setButtons(boolean b) {
 > +        jButton2.setEnabled(b);
 > +        jButton3.setEnabled(b);
 > +        jButton6.setEnabled(b);
 > +        jButton7.setEnabled(b);
 > +        jButton8.setEnabled(b);
 > +    }
 > +
 > +    private JTable createTbale(final TableModel model) {
 > +        JTable jt = new JTable() {
 > +            @Override
 > +            public TableCellEditor getCellEditor(int row, int column) {
 > +                if (column == 0) {
 > +                    return new DefaultCellEditor(new JComboBox(new 
UnsignedAppletAction[]{UnsignedAppletAction.ALWAYS, 
UnsignedAppletAction.NEVER, UnsignedAppletAction.YES, 
UnsignedAppletAction.NO}));
 > +                }
 > +                if (column == 2) {
 > +                    return new DefaultCellEditor(new 
MyTextField((UrlRegEx) (model.getValueAt(row, column))));
 > +                }
 > +                if (column == 3) {
 > +                    return new DefaultCellEditor(new 
MyTextField((UrlRegEx) (model.getValueAt(row, column))));
 > +                }
 > +                return super.getCellEditor(row, column);
 > +            }
 > +
 > +            @Override
 > +            public TableCellRenderer getCellRenderer(int row, int 
column) {
 > +                if (column == 1) {
 > +                    return new 
UrlRegexCellRenderer.MyDateCellRenderer((Date) (model.getValueAt(row, 
column)));
 > +                }
 > +                if (column == 2) {
 > +                    if (!jCheckBox2.isSelected()) {
 > +                        return new UrlRegexCellRenderer((UrlRegEx) 
(model.getValueAt(row, column)));
 > +                    }
 > +                }
 > +                if (column == 3) {
 > +                    if (!jCheckBox2.isSelected()) {
 > +                        return new UrlRegexCellRenderer((UrlRegEx) 
(model.getValueAt(row, column)));
 > +                    }
 > +                }
 > +                return super.getCellRenderer(row, column);
 > +            }
 > +        };
 > +        jt.setRowHeight(jt.getRowHeight() + jt.getRowHeight() / 2);
 > +        jt.setModel(model);
 > +        return jt;
 > +
 > +    }
 > +
 > +    private void reloadTable() {
 > +        currentTable.setModel(new DefaultTableModel());
 > +        currentTable.setModel(currentModel);
 > +
 > +    }
 > +
 > +    private void removeByBehaviour(UnsignedAppletAction 
unsignedAppletAction) {
 > +        UnsignedAppletActionEntry[] items = currentModel.back.toArray();
 > +        if (jCheckBox1.isSelected()) {
 > +            List<UnsignedAppletActionEntry> toBeDeleted = new 
ArrayList();
 > +            for (int i = 0; i < items.length; i++) {
 > +                UnsignedAppletActionEntry unsignedAppletActionEntry 
= items[i];
 > +                if 
(unsignedAppletActionEntry.getUnsignedAppletAction() == 
unsignedAppletAction) {
 > + toBeDeleted.add(unsignedAppletActionEntry);
 > +                }
 > +
 > +            }
 > +            String s = 
Translator.R("APPEXTSECguiPanelConfirmDeletionOf", 
toBeDeleted.size())+": \n";
 > +            for (int i = 0; i < toBeDeleted.size(); i++) {
 > +                s += appletItemToCaption(toBeDeleted.get(i), "  ") + 
"\n";
 > +            }
 > +            int a = JOptionPane.showConfirmDialog(this, s);
 > +            if (a != JOptionPane.OK_OPTION) {
 > +                return;
 > +            }
 > +        }
 > +        currentModel.removeByBehaviour(unsignedAppletAction);
 > +    }
 > +
 > +    public static final class MyTextField extends JTextField {
 > +
 > +        private final UrlRegEx keeper;
 > +
 > +        private MyTextField(UrlRegEx urlRegEx) {
 > +            if (urlRegEx == null) {
 > +                keeper = new UrlRegEx("");
 > +            } else {
 > +                this.keeper = urlRegEx;
 > +            }
 > +            setText(keeper.getFilteredRegEx());
 > +        }
 > +
 > +        @Override
 > +        public void setText(String t) {
 > +            super.setText(keeper.getRegEx());
 > +        }
 > +    }
 > +
 > +    public static final class UrlRegexCellRenderer extends 
DefaultTableCellRenderer {
 > +
 > +        private final UrlRegEx keeper;
 > +
 > +        private UrlRegexCellRenderer(UrlRegEx urlRegEx) {
 > +            if (urlRegEx == null) {
 > +                keeper = new UrlRegEx("");
 > +            } else {
 > +                this.keeper = urlRegEx;
 > +            }
 > +            setText(keeper.getFilteredRegEx());
 > +        }
 > +
 > +        @Override
 > +        public void setText(String t) {
 > +            if (keeper == null) {
 > +                super.setText("");
 > +            } else {
 > +                super.setText(keeper.getFilteredRegEx());
 > +            }
 > +        }
 > +
 > +        public static final class MyDateCellRenderer extends 
DefaultTableCellRenderer {
 > +
 > +            private final Date keeper;
 > +
 > +            private MyDateCellRenderer(Date d) {
 > +                this.keeper = d;
 > +                setText(DateFormat.getInstance().format(d));
 > +            }
 > +
 > +            @Override
 > +            public void setText(String t) {
 > +                if (keeper == null) {
 > +                    super.setText("");
 > +                } else {
 > + super.setText(DateFormat.getInstance().format(keeper));
 > +                }
 > +            }
 > +        }
 > +    }
 > +
 > +    private class SingleSelectionListenerImpl implements 
ListSelectionListener {
 > +
 > +        private final JTable table;
 > +
 > +        public SingleSelectionListenerImpl(JTable table) {
 > +            this.table = table;
 > +        }
 > +
 > +        @Override
 > +        public void valueChanged(ListSelectionEvent e) {
 > +            if (table.getSelectedRows().length == 1) {
 > +                jButton7.setEnabled(true);
 > +                jButton8.setEnabled(true);
 > +            } else {
 > +                jButton7.setEnabled(false);
 > +                jButton8.setEnabled(false);
 > +            }
 > +        }
 > +    }
 > +}
 > diff -r e631770d76ba 
netx/net/sourceforge/jnlp/resources/Messages.properties
 > --- a/netx/net/sourceforge/jnlp/resources/Messages.properties    Thu 
Jan 31 11:12:35 2013 +0100
 > +++ b/netx/net/sourceforge/jnlp/resources/Messages.properties    Fri 
Feb 01 20:55:48 2013 +0100
 > @@ -474,3 +474,57 @@
 >  SPLASHerrorInInformation = Error during loading of information 
element, verify source rather
 >  SPLASHmissingInformation = Information element is missing, verify 
source rather
 >  SPLASHchainWas = This is the list of exceptions that occurred 
launching your applet. Please note, those exceptions can be from 
multiple applets. For a good bug report, be sure to run only one applet.
 > +
 > +APPEXTSECappletSecurityLevelExtraHighId=Extra High Security
 > +APPEXTSECappletSecurityLevelVeryHighId=Very High Security
 > +APPEXTSECappletSecurityLevelHighId=High Security
 > +APPEXTSECappletSecurityLevelLowId=Low Security
 > +APPEXTSECappletSecurityLevelExtraHighExplanation=No applet will be run
 > +APPEXTSECappletSecurityLevelVeryHighExplanation=No unsigned applets 
will be run
 > +APPEXTSECappletSecurityLevelHighExplanation=User will be prompted 
for each unsigned applet
 > +APPEXTSECappletSecurityLevelLowExplanation=All, even untrusted, 
applets will be run

OK not typo but IMO s/ applets/ unsigned applets/

 > +APPEXTSECunsignedAppletActionAlways=Always trust this applet(s)

OK again not typo but maybe s/this applet(s)/matching applets/

 > +APPEXTSECunsignedAppletActionNever=Never trust this applet(s)
 > +APPEXTSECunsignedAppletActionYes=This applet was visited and allowed
 > +APPEXTSECunsignedAppletActionNo=This applet was visited and denied
 > +APPEXTSECControlPanelExtendedAppletSecurityTitle=Extended applet 
security
 > +APPEXTSECguiTableModelTableColumnAction=Action
 > +APPEXTSECguiTableModelTableColumnDateOfAction=Date of action
 > +APPEXTSECguiTableModelTableColumnDocumentBase=Document-base
 > +APPEXTSECguiTableModelTableColumnCodeBase=Code-base
 > +APPEXTSECguiTableModelTableColumnMainClass=Main class
 > +APPEXTSECguiTableModelTableColumnArchives=Archives
 > +APPEXTSECguiPanelAppletInfoHederPart1={0} {1}
 > +APPEXTSECguiPanelAppletInfoHederPart2={0} from  {1}
 > +APPEXTSECguiPanelConfirmDeletionOf=Are you sure you want to delete 
following {0} items
 > +APPEXTSECguiPanelHelpButton=Help
 > +APPEXTSECguiPanelSecurityLevel=Security Level
 > +APPEXTSECguiPanelGlobalBehaviourCaption=Settings of global behaviour 
for applets
 > +APPEXTSECguiPanelDeleteMenuSelected=selected
 > +APPEXTSECguiPanelDeleteMenuAllA=all allowed (A)
 > +APPEXTSECguiPanelDeleteMenuAllN=all forbidden (N)
 > +APPEXTSECguiPanelDeleteMenuAlly=all approved (y)
 > +APPEXTSECguiPanelDeleteMenuAlln=all disaprooved (n)

s/disaprooved/rejected/ :^)

 > +APPEXTSECguiPanelDeleteMenuAllAll=absolute all

s/absolute all/all matches/ :^)

 > +APPEXTSECguiPanelDeleteButton=Delete
 > +APPEXTSECguiPanelTestUrlButton=Test url
 > +APPEXTSECguiPanelAddRowButton=Add new row
 > +APPEXTSECguiPanelValidateTableButton=Validate table
 > +APPEXTSECguiPanelAskeforeActionBox=Ask me before action
 > +APPEXTSECguiPanelShowRegExesBox=Show full regular expressions
 > +APPEXTSECguiPanelInverSelection=Invert selection
 > +APPEXTSECguiPanelMoveRowUp=Move row up
 > +APPEXTSECguiPanelMoveRowDown=Move row down
 > +APPEXTSECguiPanelCustomDefs=Custom definitions
 > +APPEXTSECguiPanelGlobalDefs=Global definitions
 > +APPEXTSECguiPanelDocTest=Type document base URL
 > +APPEXTSECguiPanelCodeTest=Type code base URL
 > +APPEXTSECguiPanelNoMatch=Nothing matched
 > +APPEXTSECguiPanelMatchingNote=Please note, that only first matched 
result will be considered as result.
 > +APPEXTSECguiPanelMatched=Matched
 > +APPEXTSECguiPanelMatchingError=Error during matching: {0}
 > +APPEXTSECguiPanelCanNotValidate=Can not validate, can not create tmp 
file - {0}
 > +APPEXTSECguiPanelEmptyDoc=All document-bases must be full
 > +APPEXTSECguiPanelEmptyCode=All code-bases must be full
 > +APPEXTSECguiPanelTableValid=Table looks valid
 > +APPEXTSECguiPanelTableInvalid=Invalid with following error: {0}
 > \ No newline at end of file
 > diff -r e631770d76ba 
netx/net/sourceforge/jnlp/util/lockingfile/LockingFile.java
 > --- /dev/null    Thu Jan 01 00:00:00 1970 +0000
 > +++ b/netx/net/sourceforge/jnlp/util/lockingfile/LockingFile.java    
Fri Feb 01 20:55:48 2013 +0100
 > @@ -0,0 +1,156 @@
 > +/*
 > +Copyright (C) 2013 Red Hat, Inc.
 > +
 > +This file is part of IcedTea.
 > +
 > +IcedTea is free software; you can redistribute it and/or
 > +modify it under the terms of the GNU General Public License as 
published by
 > +the Free Software Foundation, version 2.
 > +
 > +IcedTea is distributed in the hope that it will be useful,
 > +but WITHOUT ANY WARRANTY; without even the implied warranty of
 > +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
 > +General Public License for more details.
 > +
 > +You should have received a copy of the GNU General Public License
 > +along with IcedTea; see the file COPYING.  If not, write to
 > +the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, 
Boston, MA
 > +02110-1301 USA.
 > +
 > +Linking this library statically or dynamically with other modules is
 > +making a combined work based on this library.  Thus, the terms and
 > +conditions of the GNU General Public License cover the whole
 > +combination.
 > +
 > +As a special exception, the copyright holders of this library give you
 > +permission to link this library with independent modules to produce an
 > +executable, regardless of the license terms of these independent
 > +modules, and to copy and distribute the resulting executable under
 > +terms of your choice, provided that you also meet, for each linked
 > +independent module, the terms and conditions of the license of that
 > +module.  An independent module is a module which is not derived from
 > +or based on this library.  If you modify this library, you may extend
 > +this exception to your version of the library, but you are not
 > +obligated to do so.  If you do not wish to do so, delete this
 > +exception statement from your version.
 > + */
 > +
 > +package net.sourceforge.jnlp.util.lockingfile;
 > +
 > +import java.nio.channels.FileChannel;
 > +
 > +import java.io.RandomAccessFile;
 > +
 > +import java.io.File;
 > +import java.io.IOException;
 > +import java.nio.channels.FileLock;
 > +import java.util.Map;
 > +import java.util.WeakHashMap;
 > +import java.util.concurrent.locks.ReentrantLock;
 > +
 > +/*
 > + * Process & thread locked access to a file. Creates file if it does 
not already exist.
 > + */
 > +public class LockingFile {
 > +
 > +    // The file for access
 > +    private RandomAccessFile randomAccessFile;
 > +    private FileChannel fileChannel;
 > +    private File file;
 > +
 > +    // A file lock will protect against locks for multiple
 > +    // processes, while a thread lock is still needed within a 
single JVM.
 > +
 > +    private FileLock processLock = null;
 > +    private ReentrantLock threadLock = new ReentrantLock();
 > +    private boolean readOnly;
 > +
 > +    private LockingFile(File file) {
 > +        this.file = file;
 > +        try{
 > +            //just try to ctreate
 > +            this.file.createNewFile();
 > +        }catch(Exception ex){
 > +            //intentionaly silent
 > +        }
 > +        if (!this.file.isFile() && file.getParentFile()!=null && 
!file.getParentFile().canWrite() ){
 > +            readOnly=true;
 > +        } else{
 > +        this.readOnly = !file.canWrite();
 > +        if (!readOnly && file.getParentFile()!=null && 
!file.getParentFile().canWrite()){
 > +                readOnly=true;
 > +        }
 > +        }
 > +    }
 > +
 > +    public boolean isReadOnly() {
 > +        return readOnly;
 > +    }
 > +
 > +
 > +
 > +    // Provide shared access to LockedFile's via weak map
 > +    static private final Map<File, LockingFile> instanceCache = new 
WeakHashMap<File, LockingFile>();
 > +
 > +    /**
 > +     * Get a LockingFile for a given File.
 > +     * Ensures that we share the same instance for all threads
 > +     * @param file the file to lock
 > +     * @return a LockingFile instance
 > +     */
 > +    synchronized public static LockingFile getInstance(File file) {
 > +        if (!instanceCache.containsKey(file)) {
 > +            instanceCache.put(file, new LockingFile(file));
 > +        }
 > +
 > +        return instanceCache.get(file);
 > +    }
 > +
 > +    /**
 > +     * Get the file being locked.
 > +     *
 > +     * @return the file
 > +     */
 > +    public File getFile() {
 > +        return file;
 > +    }
 > +
 > +    /**
 > +     * Lock access to the file. Lock is reentrant.
 > +     */
 > +    public void lock() throws IOException {
 > +        // Create if does not already exist, cannot lock 
non-existing file
 > +        if (!readOnly){
 > +            this.file.createNewFile();
 > +        }
 > +
 > +        this.threadLock.lock();
 > +        String rw="rws";
 > +        if (isReadOnly()){
 > +            rw="r";
 > +        }
 > +        if (file.exists()){
 > +        this.randomAccessFile = new RandomAccessFile(this.file, rw);
 > +        this.fileChannel = randomAccessFile.getChannel();
 > +        }
 > +
 > +        if (!isReadOnly()) this.processLock = this.fileChannel.lock();
 > +    }
 > +
 > +    /**
 > +     * Unlock access to the file. Lock is reentrant.
 > +     */
 > +    public void unlock() throws IOException {
 > +        boolean releaseProcessLock = (this.threadLock.getHoldCount() 
== 1);
 > +        try {
 > +            if (releaseProcessLock && this.processLock != null) {
 > +                this.processLock.release();
 > +                this.randomAccessFile.close();
 > +                this.fileChannel.close();
 > +            }
 > +        } finally {
 > +            this.processLock = null;
 > +        }
 > +        this.threadLock.unlock();
 > +    }
 > +}
 > \ No newline at end of file
 > diff -r e631770d76ba 
netx/net/sourceforge/jnlp/util/lockingfile/LockingReaderWriter.java
 > --- /dev/null    Thu Jan 01 00:00:00 1970 +0000
 > +++ 
b/netx/net/sourceforge/jnlp/util/lockingfile/LockingReaderWriter.java 
Fri Feb 01 20:55:48 2013 +0100
 > @@ -0,0 +1,201 @@
 > +/*
 > +Copyright (C) 2013 Red Hat, Inc.
 > +
 > +This file is part of IcedTea.
 > +
 > +IcedTea is free software; you can redistribute it and/or
 > +modify it under the terms of the GNU General Public License as 
published by
 > +the Free Software Foundation, version 2.
 > +
 > +IcedTea is distributed in the hope that it will be useful,
 > +but WITHOUT ANY WARRANTY; without even the implied warranty of
 > +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
 > +General Public License for more details.
 > +
 > +You should have received a copy of the GNU General Public License
 > +along with IcedTea; see the file COPYING.  If not, write to
 > +the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, 
Boston, MA
 > +02110-1301 USA.
 > +
 > +Linking this library statically or dynamically with other modules is
 > +making a combined work based on this library.  Thus, the terms and
 > +conditions of the GNU General Public License cover the whole
 > +combination.
 > +
 > +As a special exception, the copyright holders of this library give you
 > +permission to link this library with independent modules to produce an
 > +executable, regardless of the license terms of these independent
 > +modules, and to copy and distribute the resulting executable under
 > +terms of your choice, provided that you also meet, for each linked
 > +independent module, the terms and conditions of the license of that
 > +module.  An independent module is a module which is not derived from
 > +or based on this library.  If you modify this library, you may extend
 > +this exception to your version of the library, but you are not
 > +obligated to do so.  If you do not wish to do so, delete this
 > +exception statement from your version.
 > + */
 > +package net.sourceforge.jnlp.util.lockingfile;
 > +
 > +import java.io.BufferedWriter;
 > +
 > +import java.io.BufferedReader;
 > +import java.io.File;
 > +import java.io.FileInputStream;
 > +import java.io.FileOutputStream;
 > +import java.io.IOException;
 > +import java.io.InputStreamReader;
 > +import java.io.OutputStreamWriter;
 > +
 > +/**
 > + * Process-locked string storage backed by a file.
 > + * Each string is stored on its own line.
 > + * Any new-lines must be encoded somehow if they are to be stored.
 > + */
 > +public abstract class LockingReaderWriter {
 > +
 > +    private LockingFile lockedFile;
 > +
 > +    /**
 > +     * Create locking file-backed storage.
 > +     * @param file the storage file
 > +     */
 > +    public LockingReaderWriter(File file) {
 > +        this.lockedFile = LockingFile.getInstance(file);
 > +    }
 > +
 > +    /**
 > +     * Get the underlying file.
 > +     * Any access to this file should use lock() & unlock().
 > +     *
 > +     * @return the file
 > +     */
 > +    public File getBackingFile() {
 > +        return this.lockedFile.getFile();
 > +    }
 > +
 > +    public boolean isReadOnly() {
 > +        return this.lockedFile.isReadOnly();
 > +    }
 > +
 > +    /**
 > +     * Lock the underlying storage. Lock is reentrant.
 > +     */
 > +    public void lock() {
 > +        try {
 > +            lockedFile.lock();
 > +        } catch (IOException e) {
 > +            throw new StorageIoException(e);
 > +        }
 > +    }
 > +
 > +    /**
 > +     * Unlock the underlying storage. Lock is reentrant.
 > +     */
 > +    public void unlock() {
 > +        try {
 > +            lockedFile.unlock();
 > +        } catch (IOException e) {
 > +            throw new StorageIoException(e);
 > +        }
 > +    }
 > +
 > +    /**
 > +     * Writes stored contents to file. Assumes lock is held.
 > +     * @throws IOException
 > +     */
 > +    protected void writeContents() throws IOException {
 > +        if (!getBackingFile().isFile()){
 > +            return;
 > +        }
 > +        if (isReadOnly()){
 > +            return;
 > +        }
 > +        BufferedWriter writer = null;
 > +        try {
 > +            writer = new BufferedWriter(new OutputStreamWriter(
 > +                    new FileOutputStream(getBackingFile()), "UTF-8"));
 > +            writeContent(writer);
 > +            writer.flush();
 > +        } finally {
 > +            if (writer != null) {
 > +                writer.close();
 > +            }
 > +        }
 > +    }
 > +
 > +    protected abstract void writeContent(BufferedWriter writer) 
throws IOException;
 > +
 > +    /**
 > +     * Reads contents from file. Assumes lock is held.
 > +     * @throws IOException
 > +     */
 > +    protected void readContents() throws IOException {
 > +        if (!getBackingFile().isFile()){
 > +            return;
 > +        }
 > +        BufferedReader reader = null;
 > +        try {
 > +            reader = new BufferedReader(new InputStreamReader(
 > +                    new FileInputStream(getBackingFile()), "UTF-8"));
 > +
 > +            while (true) {
 > +                String line = reader.readLine();
 > +                if (line == null) {
 > +                    break;
 > +                }
 > +                readLine(line);
 > +            }
 > +        } finally {
 > +            if (reader != null) {
 > +                reader.close();
 > +            }
 > +        }
 > +    }
 > +
 > +    /**
 > +     * Reads contents from file. creating is lock .

I have already proofread this !

'Reads contents from the file, first acquring a lock.'

 > +     * @throws IOException
 > +     */
 > +    protected synchronized void readContentsLocked() throws 
IOException {
 > +        doLocked(new Runnable() {
 > +
 > +            @Override
 > +            public void run() {
 > +                try {
 > +                    readContents();
 > +                } catch (IOException ex) {
 > +                    throw new StorageIoException(ex);
 > +                }
 > +            }
 > +        });
 > +    }
 > +
 > +    /**
 > +     * Reads contents from file. creating is lock .


'Write contents to the file, first acquring a lock.'


 > +     * @throws IOException
 > +     */
 > +    protected synchronized void writeContentsLocked() throws 
IOException {
 > +        doLocked(new Runnable() {
 > +
 > +            public void run() {
 > +                try {
 > +                    writeContents();
 > +                } catch (IOException ex) {
 > +                    throw new StorageIoException(ex);
 > +                }
 > +            }
 > +        });
 > +
 > +    }
 > +
 > +    protected void doLocked(Runnable r) {
 > +        lock();
 > +        try {
 > +            r.run();
 > +        } finally {
 > +            unlock();
 > +        }
 > +    }
 > +
 > +    protected abstract void readLine(String line);
 > +}
 > diff -r e631770d76ba 
netx/net/sourceforge/jnlp/util/lockingfile/StorageIoException.java
 > --- /dev/null    Thu Jan 01 00:00:00 1970 +0000
 > +++ 
b/netx/net/sourceforge/jnlp/util/lockingfile/StorageIoException.java Fri 
Feb 01 20:55:48 2013 +0100
 > @@ -0,0 +1,22 @@
 > +package net.sourceforge.jnlp.util.lockingfile;
 > +
 > +/**
 > + * Thrown when an exception occurs using the storage (namely 
IOException)
 > + */
 > +public class StorageIoException extends RuntimeException {
 > +
 > +    LockingReaderWriter outer;
 > +
 > +    public StorageIoException(Exception e) {
 > +        super(e);
 > +    }
 > +
 > +    public StorageIoException(String e) {
 > +        super(e);
 > +    }
 > +
 > +     public StorageIoException(Exception e, LockingReaderWriter outer) {
 > +        super(e);
 > +        this.outer = outer;
 > +    }
 > +}
 > diff -r e631770d76ba 
tests/netx/unit/net/sourceforge/appletextendedsecurity/impl/UnsignedAppletActionStorageImplTest.java
 > --- /dev/null    Thu Jan 01 00:00:00 1970 +0000
 > +++ 
b/tests/netx/unit/net/sourceforge/appletextendedsecurity/impl/UnsignedAppletActionStorageImplTest.java 
Fri Feb 01 20:55:48 2013 +0100
 > @@ -0,0 +1,97 @@
 > +/*
 > +Copyright (C) 2013 Red Hat
 > +
 > +This program is free software; you can redistribute it and/or modify
 > +it under the terms of the GNU General Public License as published by
 > +the Free Software Foundation; either version 2 of the License, or
 > +(at your option) any later version.
 > +
 > +This program is distributed in the hope that it will be useful, but
 > +WITHOUT ANY WARRANTY; without even the implied warranty of
 > +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
 > +General Public License for more details.
 > +
 > +You should have received a copy of the GNU General Public License
 > +along with this program; if not, write to the Free Software
 > +Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
 > +*/
 > +
 > +package net.sourceforge.appletextendedsecurity.impl;
 > +
 > +import net.sourceforge.appletextendedsecurity.UnsignedAppletActionEntry;
 > +import java.io.File;
 > +import java.io.IOException;
 > +import java.util.Arrays;
 > +import net.sourceforge.jnlp.ServerAccess;
 > +import org.junit.Assert;
 > +import org.junit.BeforeClass;
 > +import org.junit.Test;
 > +
 > +public class UnsignedAppletActionStorageImplTest {
 > +
 > +    private static File f1;
 > +    private static File f2;
 > +    private static File f3;
 > +    private static File f4;
 > +
 > +    @BeforeClass
 > +    public static void preapreTestFiles() throws IOException {
 > +        f1 = File.createTempFile("itwMatching", "testFile1");
 > +        f2 = File.createTempFile("itwMatching", "testFile2");
 > +        f3 = File.createTempFile("itwMatching", "testFile3");
 > +        f4 = File.createTempFile("itwMatching", "testFile4");
 > +        ServerAccess.saveFile("A 123456 .* .* main jar1;jar2", f1);
 > +        ServerAccess.saveFile("A 123456 .* \\Qbla\\E main 
jar1;jar2", f2);
 > +    }
 > +
 > +    @Test
 > +    public void allMatchingDocAndCode() {
 > +        UnsignedAppletActionStorageImpl i1 = new 
UnsignedAppletActionStorageImpl(f1);
 > +        UnsignedAppletActionEntry r1 = i1.getMatchingItem("bla", 
"blaBla", "main", Arrays.asList(new String[]{"jar1", "jar2"}));
 > +        Assert.assertNotNull("r1 should be found", r1);
 > +        UnsignedAppletActionEntry r3 = i1.getMatchingItem("blah", 
"blaBla", "main", Arrays.asList(new String[]{"jar2", "jar1"}));
 > +        Assert.assertNotNull("r3 should be found", r1);
 > +        UnsignedAppletActionEntry r2 = i1.getMatchingItem("bla", 
"blaBlam", "wrong_main", Arrays.asList(new String[]{"jar1", "jar2"}));
 > +        Assert.assertNull("r2 should NOT be found", r2);
 > +        UnsignedAppletActionEntry r4 = i1.getMatchingItem("blha", 
"blaBlam", "main", Arrays.asList(new String[]{"jar2", "wrong_jar"}));
 > +        Assert.assertNull("r4 should NOT be found", r4);
 > +        UnsignedAppletActionEntry r5 = i1.getMatchingItem("blaBla", 
"blaBlaBla", "main", Arrays.asList(new String[]{"jar2"}));
 > +        Assert.assertNull("r5 should NOT be found", r5);
 > +
 > +    }
 > +
 > +     @Test
 > +    public void allMatchingDocAndStrictCode() {
 > +        UnsignedAppletActionStorageImpl i1 = new 
UnsignedAppletActionStorageImpl(f2);
 > +        UnsignedAppletActionEntry r1 = 
i1.getMatchingItem("whatever", "bla", "main", Arrays.asList(new 
String[]{"jar1", "jar2"}));
 > +        Assert.assertNotNull("r1 should be found", r1);
 > +        UnsignedAppletActionEntry r3 = 
i1.getMatchingItem("whatever", null, "main", Arrays.asList(new 
String[]{"jar2", "jar1"}));
 > +        Assert.assertNotNull("r3 should be found", r1);
 > +        UnsignedAppletActionEntry r2 = i1.getMatchingItem("bla", 
"blaBlam", "main", Arrays.asList(new String[]{"jar1", "jar2"}));
 > +        Assert.assertNull("r2 should NOT be found", r2);
 > +        UnsignedAppletActionEntry r4 = i1.getMatchingItem(null, 
"blaBlam", null, null);
 > +        Assert.assertNull("r4 should NOT be found", r4);
 > +
 > +    }
 > +
 > +     @Test
 > +    public void allMatchingDocAndCodeWithNulls() {
 > +        UnsignedAppletActionStorageImpl i1 = new 
UnsignedAppletActionStorageImpl(f1);
 > +        UnsignedAppletActionEntry r1 = i1.getMatchingItem("bla", 
"blaBla", null, null);
 > +        Assert.assertNotNull("r1 should be found", r1);
 > +        UnsignedAppletActionEntry r3 = i1.getMatchingItem("bla", 
"whatever", "", null);
 > +        Assert.assertNotNull("r3 should be found", r1);
 > +        UnsignedAppletActionEntry r2 = i1.getMatchingItem("bla", 
"blaBla", null, Arrays.asList(new String[]{"jar2", "jar1"}));
 > +        Assert.assertNotNull("r2 should be found", r2);
 > +        UnsignedAppletActionEntry r4 = i1.getMatchingItem("bla", 
"blaBla", "main", null);
 > +        Assert.assertNotNull("r4 should be found", r4);
 > +        UnsignedAppletActionEntry r5 = i1.getMatchingItem("", 
"blaBla", "main", Arrays.asList(new String[]{"jar2", "jar1"}));
 > +        Assert.assertNotNull("r5 should be found", r5);
 > +        UnsignedAppletActionEntry r6 = i1.getMatchingItem(null, 
null, "main", Arrays.asList(new String[]{"jar2", "jar1"}));
 > +        Assert.assertNotNull("r6 should be found", r6);
 > +        UnsignedAppletActionEntry r7 = i1.getMatchingItem(null, 
null, "main", Arrays.asList(new String[]{"jar2", "jar11"}));
 > +        Assert.assertNull("r7 should NOT be found", r7);
 > +
 > +
 > +    }
 > +}
 > diff -r e631770d76ba 
tests/netx/unit/net/sourceforge/jnlp/util/lockingfile/LockingStringListStorageTest.java
 > --- /dev/null    Thu Jan 01 00:00:00 1970 +0000
 > +++ 
b/tests/netx/unit/net/sourceforge/jnlp/util/lockingfile/LockingStringListStorageTest.java 
Fri Feb 01 20:55:48 2013 +0100
 > @@ -0,0 +1,385 @@
 > +/*
 > +Copyright (C) 2013 Red Hat
 > +
 > +This program is free software; you can redistribute it and/or modify
 > +it under the terms of the GNU General Public License as published by
 > +the Free Software Foundation; either version 2 of the License, or
 > +(at your option) any later version.
 > +
 > +This program is distributed in the hope that it will be useful, but
 > +WITHOUT ANY WARRANTY; without even the implied warranty of
 > +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
 > +General Public License for more details.
 > +
 > +You should have received a copy of the GNU General Public License
 > +along with this program; if not, write to the Free Software
 > +Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
 > +*/
 > +
 > +package net.sourceforge.jnlp.util.lockingfile;
 > +
 > +import static org.junit.Assert.assertFalse;
 > +import static org.junit.Assert.assertTrue;
 > +import org.junit.Before;
 > +import java.io.BufferedWriter;
 > +import java.io.File;
 > +import java.io.IOException;
 > +import java.util.ArrayList;
 > +import java.util.List;
 > +import org.junit.Assert;
 > +import org.junit.Test;
 > +
 > +
 > +
 > +public  class LockingStringListStorageTest {
 > +
 > +/**
 > + * Process-locked string storage backed by a file.
 > + * Each string is stored on its own line.
 > + * Any new-lines must be encoded somehow if they are to be stored.
 > + */
 > +public static class LockingStringListStorage extends 
LockingReaderWriter {
 > +
 > +    private List<String> cachedContents = new ArrayList<String>();
 > +
 > +    //To sutisfy testengine, void constructor and dummy testmethod
 > +    public LockingStringListStorage() throws IOException {
 > +        this(createTmpBackend());
 > +    }
 > +
 > +    @Test
 > +    public void lockingStringListStorageCanBeInstantiated(){
 > +        Assert.assertNotNull(this);
 > +    }
 > +
 > +
 > +    private static File createTmpBackend() throws IOException{
 > +        File f = File.createTempFile("forTests","emptyConstructor");
 > +        f.deleteOnExit();
 > +        return f;
 > +    }
 > +
 > +
 > +    /**
 > +     * Create locking file-backed storage.
 > +     * @param file the storage file
 > +     */
 > +    public LockingStringListStorage(File file) {
 > +        super(file);
 > +    }
 > +
 > +    /**
 > +     *  Get the underlying string list cache. Should lock
 > +     *  before using.
 > +     *  @return the cache
 > +     */
 > +    final protected List<String> getCachedContents() {
 > +        return cachedContents;
 > +    }
 > +
 > +    @Override
 > +    public void writeContent(BufferedWriter writer) throws IOException {
 > +        for (String string : cachedContents) {
 > +            writer.write(string);
 > +            writer.newLine();
 > +        }
 > +    }
 > +
 > +    @Override
 > +    protected void readLine(String line) {
 > +        this.cachedContents.add(line);
 > +    }
 > +
 > +    @Override
 > +    protected void readContents() throws IOException {
 > +        cachedContents.clear();
 > +        super.readContents();
 > +    }
 > +
 > +    /*
 > +     * Atomic container abstraction methods. These all allow the 
file-backed
 > +     * string list to be treated as a convenient in-memory object.
 > +     */
 > +    /**
 > +     * Appends the specified line to the end of the storage.
 > +     *
 > +     * @param line the line to add
 > +     */
 > +    synchronized public void add(final String line) {
 > +        doLocked(new Runnable() {
 > +
 > +            public void run() {
 > +                try {
 > +                    readContents();
 > +                    cachedContents.add(line);
 > +                    writeContents();
 > +                } catch (IOException ex) {
 > +                    throw new StorageIoException(ex);
 > +                }
 > +            }
 > +        });
 > +    }
 > +
 > +    /**
 > +     * Returns an array containing all of the lines in the storage.
 > +     *
 > +     * @return an array of the stored strings
 > +     */
 > +    synchronized public String[] toArray() {
 > +        lock();
 > +        try {
 > +            readContents();
 > +            return cachedContents.toArray(new String[]{});
 > +        } catch (IOException e) {
 > +            throw new StorageIoException(e);
 > +        } finally {
 > +            unlock();
 > +        }
 > +    }
 > +
 > +    /**
 > +     * Returns amount of lines in the storage.
 > +     *
 > +     * @return amount of stored strings
 > +     */
 > +    synchronized public int size() {
 > +        lock();
 > +        try {
 > +            readContents();
 > +            return cachedContents.size();
 > +        } catch (IOException e) {
 > +            throw new StorageIoException(e);
 > +        } finally {
 > +            unlock();
 > +        }
 > +    }
 > +
 > +    /**
 > +     * Returns 'i'th line
 > +     *
 > +     * @return the line
 > +     */
 > +    synchronized public String get(int i) {
 > +        lock();
 > +        try {
 > +            readContents();
 > +            return cachedContents.get(i);
 > +        } catch (IOException e) {
 > +            throw new StorageIoException(e);
 > +        } finally {
 > +            unlock();
 > +        }
 > +    }
 > +
 > +    /**
 > +     * Set the 'i'th line
 > +     *
 > +     * @param line the new line
 > +     */
 > +    synchronized public String set(int i, String line) {
 > +        lock();
 > +        try {
 > +            readContents();
 > +            return cachedContents.set(i, line);
 > +        } catch (IOException e) {
 > +            throw new StorageIoException(e);
 > +        } finally {
 > +            unlock();
 > +        }
 > +    }
 > +
 > +    /**
 > +     * Returns a copied list containing all of the lines in the storage.
 > +     *
 > +     * @return a list of the stored strings
 > +     */
 > +    synchronized public List<String> toList() {
 > +        lock();
 > +        try {
 > +            readContents();
 > +            return new ArrayList<String>(cachedContents);
 > +        } catch (IOException e) {
 > +            throw new StorageIoException(e);
 > +        } finally {
 > +            unlock();
 > +        }
 > +    }
 > +
 > +    /**
 > +     * Returns <tt>true</tt> if the storage contains the specified 
element.
 > +     *
 > +     * @param line
 > +     * @return <tt>true</tt> if the storage contains the line
 > +     */
 > +    synchronized public boolean contains(String line) {
 > +        lock();
 > +        try {
 > +            readContents();
 > +            return cachedContents.contains(line);
 > +        } catch (IOException e) {
 > +            throw new StorageIoException(e);
 > +        } finally {
 > +            unlock();
 > +        }
 > +    }
 > +
 > +    /**
 > +     * Empty the storage.
 > +     */
 > +    synchronized public void clear() {
 > +        lock();
 > +        try {
 > +            cachedContents.clear();
 > +            writeContents();
 > +        } catch (IOException e) {
 > +            throw new StorageIoException(e);
 > +        } finally {
 > +            unlock();
 > +        }
 > +    }
 > +
 > +    /**
 > +     * Removes the first occurrence of the specified element from 
this list,
 > +     * if it is present (optional operation).  If this list does not 
contain
 > +     * the element, it is unchanged.
 > +     *
 > +     * @param line string to be removed from this list, if present
 > +     * @return <tt>true</tt> if the storage contained the line
 > +     */
 > +    synchronized public boolean remove(String line) {
 > +        boolean didRemove;
 > +
 > +        lock();
 > +        try {
 > +            readContents();
 > +            didRemove = cachedContents.remove(line);
 > +            writeContents();
 > +        } catch (IOException e) {
 > +            throw new StorageIoException(e);
 > +        } finally {
 > +            unlock();
 > +        }
 > +
 > +        return didRemove;
 > +    }
 > +}
 > +
 > +
 > +    private static File storagefile;
 > +
 > +    private static LockingStringListStorage newInstance() {
 > +        return new LockingStringListStorage(storagefile);
 > +    }
 > +
 > +    @Before
 > +    public void setUp() throws IOException {
 > +        storagefile = File.createTempFile("foo", "bar");
 > +    }
 > +
 > +    @Test
 > +    public void testSimpleActions() throws IOException {
 > +        LockingStringListStorage storage = newInstance();
 > +
 > +        storage.add("teststring");
 > +        assertTrue(storage.contains("teststring"));
 > +        storage.remove("teststring");
 > +        assertFalse(storage.contains("teststring"));
 > +    }
 > +
 > +    @Test
 > +    public void testInterleavedActions() throws IOException {
 > +        LockingStringListStorage storage1 = newInstance();
 > +        LockingStringListStorage storage2 = newInstance();
 > +
 > +        storage1.add("teststring");
 > +        assertTrue(storage2.contains("teststring"));
 > +        storage2.remove("teststring");
 > +        assertFalse(storage1.contains("teststring"));
 > +    }
 > +
 > +    static class TestThread extends Thread {
 > +        String testString;
 > +        int iterations;
 > +        Throwable error = null;
 > +
 > +        TestThread(String testString, int iterations) {
 > +            this.testString = testString;
 > +            this.iterations = iterations;
 > +        }
 > +
 > +        @Override
 > +        public void run() {
 > +            try {
 > +                LockingStringListStorage storage = newInstance();
 > +                for (int i = 0; i < iterations; i++) {
 > + assertTrue(storage.contains(this.testString));
 > +                    storage.add(this.testString);
 > +                    storage.remove(this.testString);
 > + assertTrue(storage.contains(this.testString));
 > +                }
 > +            } catch (Throwable error) {
 > +                error.printStackTrace();
 > +                this.error = error;
 > +            }
 > +        }
 > +    }
 > +
 > +    private void concurrentReadWrites(int threadAmount, int iterations,
 > +            String testString) throws InterruptedException {
 > +        LockingStringListStorage storage = newInstance();
 > +
 > +        storage.add(testString);
 > +
 > +        List<TestThread> testThreads = new ArrayList<TestThread>();
 > +
 > +        for (int i = 0; i < threadAmount; i++) {
 > +            TestThread thread = new TestThread(testString, iterations);
 > +            testThreads.add(thread);
 > +            thread.start();
 > +        }
 > +
 > +        for (int i = 0; i < threadAmount; i++) {
 > +            testThreads.get(i).join();
 > +        }
 > +
 > +        assertTrue(storage.contains(testString));
 > +        storage.remove(testString);
 > +
 > +        // So long as number adds == number writes, we should be 
left with
 > +        // nothing at end.
 > +        assertFalse(storage.contains(testString));
 > +    }
 > +
 > +    // Long testing string, the contents are not important
 > +    private String makeLongTestString() {
 > +        StringBuilder sb = new StringBuilder();
 > +        for (int i = 0; i < 1000; i++) {
 > +            sb.append(Integer.toString(i));
 > +        }
 > +        return sb.toString();
 > +    }
 > +
 > +    @Test
 > +    public void testManyReadWrite() throws Exception {
 > +        int oneThread = 1;
 > +        String shortString = "teststring";
 > +
 > +        // This was causing 'too many open files' because 
FileUtils#getFileLock
 > +        // leaks file descriptors. No longer used.
 > +        concurrentReadWrites(oneThread, 500 /* iterations */,
 > +                shortString);
 > +    }
 > +
 > +    @Test
 > +    public void testManyThreads() throws Exception {
 > +        int threadAmount = 25;
 > +        String shortString = "teststring";
 > +        String longString = makeLongTestString();
 > +
 > +        concurrentReadWrites(threadAmount, 10 /* per-thread 
iterations */,
 > +                shortString);
 > +        concurrentReadWrites(threadAmount, 2 /* per-thread 
iterations */,
 > +                longString);
 > +    }
 > +
 > +}

Happy hacking,
-Adam



More information about the distro-pkg-dev mailing list