| /* Security.java --- Java base security class implementation | |
| Copyright (C) 1999, 2001, 2002, 2003, 2004, 2005, 2006 | |
| Free Software Foundation, Inc. | |
| This file is part of GNU Classpath. | |
| GNU Classpath 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, or (at your option) | |
| any later version. | |
| GNU Classpath 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 GNU Classpath; 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 java.security; | |
| import gnu.classpath.SystemProperties; | |
| import gnu.classpath.Configuration; | |
| // GCJ LOCAL - We don't have VMStackWalker yet. | |
| // import gnu.classpath.VMStackWalker; | |
| import java.io.IOException; | |
| import java.io.InputStream; | |
| import java.net.URL; | |
| import java.util.Collections; | |
| import java.util.Enumeration; | |
| import java.util.HashMap; | |
| import java.util.HashSet; | |
| import java.util.Iterator; | |
| import java.util.LinkedHashSet; | |
| import java.util.Map; | |
| import java.util.Properties; | |
| import java.util.Set; | |
| import java.util.Vector; | |
| /** | |
| * This class centralizes all security properties and common security methods. | |
| * One of its primary uses is to manage security providers. | |
| * | |
| * @author Mark Benvenuto (ivymccough@worldnet.att.net) | |
| */ | |
| public final class Security | |
| { | |
| private static final String ALG_ALIAS = "Alg.Alias."; | |
| private static Vector providers = new Vector(); | |
| private static Properties secprops = new Properties(); | |
| static | |
| { | |
| String base = SystemProperties.getProperty("gnu.classpath.home.url"); | |
| String vendor = SystemProperties.getProperty("gnu.classpath.vm.shortname"); | |
| // Try VM specific security file | |
| boolean loaded = loadProviders (base, vendor); | |
| // Append classpath standard provider if possible | |
| if (!loadProviders (base, "classpath") | |
| && !loaded | |
| && providers.size() == 0) | |
| { | |
| if (Configuration.DEBUG) | |
| { | |
| /* No providers found and both security files failed to | |
| * load properly. Give a warning in case of DEBUG is | |
| * enabled. Could be done with java.util.logging later. | |
| */ | |
| System.err.println | |
| ("WARNING: could not properly read security provider files:"); | |
| System.err.println | |
| (" " + base + "/security/" + vendor | |
| + ".security"); | |
| System.err.println | |
| (" " + base + "/security/" + "classpath" | |
| + ".security"); | |
| System.err.println | |
| (" Falling back to standard GNU security provider"); | |
| } | |
| // Note that this matches our classpath.security file. | |
| providers.addElement (new gnu.java.security.provider.Gnu()); | |
| providers.addElement(new gnu.javax.crypto.jce.GnuCrypto()); | |
| providers.addElement(new gnu.javax.crypto.jce.GnuSasl()); | |
| providers.addElement(new gnu.javax.net.ssl.provider.Jessie()); | |
| providers.addElement(new gnu.javax.security.auth.callback.GnuCallbacks()); | |
| } | |
| } | |
| // This class can't be instantiated. | |
| private Security() | |
| { | |
| } | |
| /** | |
| * Tries to load the vender specific security providers from the given base | |
| * URL. Returns true if the resource could be read and completely parsed | |
| * successfully, false otherwise. | |
| */ | |
| private static boolean loadProviders(String baseUrl, String vendor) | |
| { | |
| if (baseUrl == null || vendor == null) | |
| return false; | |
| boolean result = true; | |
| String secfilestr = baseUrl + "/security/" + vendor + ".security"; | |
| try | |
| { | |
| InputStream fin = new URL(secfilestr).openStream(); | |
| secprops.load(fin); | |
| int i = 1; | |
| String name; | |
| while ((name = secprops.getProperty("security.provider." + i)) != null) | |
| { | |
| Exception exception = null; | |
| try | |
| { | |
| ClassLoader sys = ClassLoader.getSystemClassLoader(); | |
| providers.addElement(Class.forName(name, true, sys).newInstance()); | |
| } | |
| catch (ClassNotFoundException x) | |
| { | |
| exception = x; | |
| } | |
| catch (InstantiationException x) | |
| { | |
| exception = x; | |
| } | |
| catch (IllegalAccessException x) | |
| { | |
| exception = x; | |
| } | |
| if (exception != null) | |
| { | |
| System.err.println ("WARNING: Error loading security provider " | |
| + name + ": " + exception); | |
| result = false; | |
| } | |
| i++; | |
| } | |
| } | |
| catch (IOException ignored) | |
| { | |
| result = false; | |
| } | |
| return result; | |
| } | |
| /** | |
| * Returns the value associated to a designated property name for a given | |
| * algorithm. | |
| * | |
| * @param algName | |
| * the algorithm name. | |
| * @param propName | |
| * the name of the property to return. | |
| * @return the value of the specified property or <code>null</code> if none | |
| * found. | |
| * @deprecated Use the provider-based and algorithm-independent | |
| * {@link AlgorithmParameters} and {@link KeyFactory} engine | |
| * classes instead. | |
| */ | |
| public static String getAlgorithmProperty(String algName, String propName) | |
| { | |
| if (algName == null || propName == null) | |
| return null; | |
| String property = String.valueOf(propName) + "." + String.valueOf(algName); | |
| Provider p; | |
| for (Iterator i = providers.iterator(); i.hasNext(); ) | |
| { | |
| p = (Provider) i.next(); | |
| for (Iterator j = p.keySet().iterator(); j.hasNext(); ) | |
| { | |
| String key = (String) j.next(); | |
| if (key.equalsIgnoreCase(property)) | |
| return p.getProperty(key); | |
| } | |
| } | |
| return null; | |
| } | |
| /** | |
| * Inserts a new designated {@link Provider} at a designated (1-based) | |
| * position in the current list of installed {@link Provider}s, | |
| * | |
| * @param provider | |
| * the new {@link Provider} to add. | |
| * @param position | |
| * the position (starting from 1) of where to install | |
| * <code>provider</code>. | |
| * @return the actual position, in the list of installed Providers. Returns | |
| * <code>-1</code> if <code>provider</code> was laready in the | |
| * list. The actual position may be different than the desired | |
| * <code>position</code>. | |
| * @throws SecurityException | |
| * if a {@link SecurityManager} is installed and it disallows this | |
| * operation. | |
| * @see #getProvider(String) | |
| * @see #removeProvider(String) | |
| * @see SecurityPermission | |
| */ | |
| public static int insertProviderAt(Provider provider, int position) | |
| { | |
| SecurityManager sm = System.getSecurityManager(); | |
| if (sm != null) | |
| sm.checkSecurityAccess("insertProvider." + provider.getName()); | |
| position--; | |
| int max = providers.size (); | |
| for (int i = 0; i < max; i++) | |
| { | |
| if (((Provider) providers.elementAt(i)).getName().equals(provider.getName())) | |
| return -1; | |
| } | |
| if (position < 0) | |
| position = 0; | |
| if (position > max) | |
| position = max; | |
| providers.insertElementAt(provider, position); | |
| return position + 1; | |
| } | |
| /** | |
| * Appends the designated new {@link Provider} to the current list of | |
| * installed {@link Provider}s. | |
| * | |
| * @param provider | |
| * the new {@link Provider} to append. | |
| * @return the position (starting from 1) of <code>provider</code> in the | |
| * current list of {@link Provider}s, or <code>-1</code> if | |
| * <code>provider</code> was already there. | |
| * @throws SecurityException | |
| * if a {@link SecurityManager} is installed and it disallows this | |
| * operation. | |
| * @see #getProvider(String) | |
| * @see #removeProvider(String) | |
| * @see SecurityPermission | |
| */ | |
| public static int addProvider(Provider provider) | |
| { | |
| return insertProviderAt (provider, providers.size () + 1); | |
| } | |
| /** | |
| * Removes an already installed {@link Provider}, given its name, from the | |
| * current list of installed {@link Provider}s. | |
| * | |
| * @param name | |
| * the name of an already installed {@link Provider} to remove. | |
| * @throws SecurityException | |
| * if a {@link SecurityManager} is installed and it disallows this | |
| * operation. | |
| * @see #getProvider(String) | |
| * @see #addProvider(Provider) | |
| */ | |
| public static void removeProvider(String name) | |
| { | |
| SecurityManager sm = System.getSecurityManager(); | |
| if (sm != null) | |
| sm.checkSecurityAccess("removeProvider." + name); | |
| int max = providers.size (); | |
| for (int i = 0; i < max; i++) | |
| { | |
| if (((Provider) providers.elementAt(i)).getName().equals(name)) | |
| { | |
| providers.remove(i); | |
| break; | |
| } | |
| } | |
| } | |
| /** | |
| * Returns the current list of installed {@link Provider}s as an array | |
| * ordered according to their installation preference order. | |
| * | |
| * @return an array of all the installed providers. | |
| */ | |
| public static Provider[] getProviders() | |
| { | |
| Provider[] array = new Provider[providers.size ()]; | |
| providers.copyInto (array); | |
| return array; | |
| } | |
| /** | |
| * Returns an already installed {@link Provider} given its name. | |
| * | |
| * @param name | |
| * the name of an already installed {@link Provider}. | |
| * @return the {@link Provider} known by <code>name</code>. Returns | |
| * <code>null</code> if the current list of {@link Provider}s does | |
| * not include one named <code>name</code>. | |
| * @see #removeProvider(String) | |
| * @see #addProvider(Provider) | |
| */ | |
| public static Provider getProvider(String name) | |
| { | |
| if (name == null) | |
| return null; | |
| else | |
| { | |
| name = name.trim(); | |
| if (name.length() == 0) | |
| return null; | |
| } | |
| Provider p; | |
| int max = providers.size (); | |
| for (int i = 0; i < max; i++) | |
| { | |
| p = (Provider) providers.elementAt(i); | |
| if (p.getName().equals(name)) | |
| return p; | |
| } | |
| return null; | |
| } | |
| /** | |
| * Returns the value associated with a Security propery. | |
| * | |
| * @param key | |
| * the key of the property to fetch. | |
| * @return the value of the Security property associated with | |
| * <code>key</code>. Returns <code>null</code> if no such property | |
| * was found. | |
| * @throws SecurityException | |
| * if a {@link SecurityManager} is installed and it disallows this | |
| * operation. | |
| * @see #setProperty(String, String) | |
| * @see SecurityPermission | |
| */ | |
| public static String getProperty(String key) | |
| { | |
| // GCJ LOCAL - We don't have VMStackWalker yet. | |
| // XXX To prevent infinite recursion when the SecurityManager calls us, | |
| // don't do a security check if the caller is trusted (by virtue of having | |
| // been loaded by the bootstrap class loader). | |
| SecurityManager sm = System.getSecurityManager(); | |
| // if (sm != null && VMStackWalker.getCallingClassLoader() != null) | |
| if (sm != null) | |
| sm.checkSecurityAccess("getProperty." + key); | |
| return secprops.getProperty(key); | |
| } | |
| /** | |
| * Sets or changes a designated Security property to a designated value. | |
| * | |
| * @param key | |
| * the name of the property to set. | |
| * @param datum | |
| * the new value of the property. | |
| * @throws SecurityException | |
| * if a {@link SecurityManager} is installed and it disallows this | |
| * operation. | |
| * @see #getProperty(String) | |
| * @see SecurityPermission | |
| */ | |
| public static void setProperty(String key, String datum) | |
| { | |
| SecurityManager sm = System.getSecurityManager(); | |
| if (sm != null) | |
| sm.checkSecurityAccess("setProperty." + key); | |
| if (datum == null) | |
| secprops.remove(key); | |
| else | |
| secprops.put(key, datum); | |
| } | |
| /** | |
| * For a given <i>service</i> (e.g. Signature, MessageDigest, etc...) this | |
| * method returns the {@link Set} of all available algorithm names (instances | |
| * of {@link String}, from all currently installed {@link Provider}s. | |
| * | |
| * @param serviceName | |
| * the case-insensitive name of a service (e.g. Signature, | |
| * MessageDigest, etc). | |
| * @return a {@link Set} of {@link String}s containing the names of all | |
| * algorithm names provided by all of the currently installed | |
| * {@link Provider}s. | |
| * @since 1.4 | |
| */ | |
| public static Set getAlgorithms(String serviceName) | |
| { | |
| HashSet result = new HashSet(); | |
| if (serviceName == null || serviceName.length() == 0) | |
| return result; | |
| serviceName = serviceName.trim(); | |
| if (serviceName.length() == 0) | |
| return result; | |
| serviceName = serviceName.toUpperCase()+"."; | |
| Provider[] providers = getProviders(); | |
| int ndx; | |
| for (int i = 0; i < providers.length; i++) | |
| for (Enumeration e = providers[i].propertyNames(); e.hasMoreElements(); ) | |
| { | |
| String service = ((String) e.nextElement()).trim(); | |
| if (service.toUpperCase().startsWith(serviceName)) | |
| { | |
| service = service.substring(serviceName.length()).trim(); | |
| ndx = service.indexOf(' '); // get rid of attributes | |
| if (ndx != -1) | |
| service = service.substring(0, ndx); | |
| result.add(service); | |
| } | |
| } | |
| return Collections.unmodifiableSet(result); | |
| } | |
| /** | |
| * Returns an array of currently installed {@link Provider}s, ordered | |
| * according to their installation preference order, which satisfy a given | |
| * <i>selection</i> criterion. | |
| * | |
| * <p>This implementation recognizes a <i>selection</i> criterion written in | |
| * one of two following forms:</p> | |
| * | |
| * <ul> | |
| * <li><crypto_service>.<algorithm_or_type>: Where | |
| * <i>crypto_service</i> is a case-insensitive string, similar to what has | |
| * been described in the {@link #getAlgorithms(String)} method, and | |
| * <i>algorithm_or_type</i> is a known case-insensitive name of an | |
| * Algorithm, or one of its aliases. | |
| * | |
| * <p>For example, "CertificateFactory.X.509" would return all the installed | |
| * {@link Provider}s which provide a <i>CertificateFactory</i> | |
| * implementation of <i>X.509</i>.</p></li> | |
| * | |
| * <li><crypto_service>.<algorithm_or_type> <attribute_name>:<value>: | |
| * Where <i>crypto_service</i> is a case-insensitive string, similar to what | |
| * has been described in the {@link #getAlgorithms(String)} method, | |
| * <i>algorithm_or_type</i> is a case-insensitive known name of an Algorithm | |
| * or one of its aliases, <i>attribute_name</i> is a case-insensitive | |
| * property name with no whitespace characters, and no dots, in-between, and | |
| * <i>value</i> is a {@link String} with no whitespace characters in-between. | |
| * | |
| * <p>For example, "Signature.Sha1WithDSS KeySize:1024" would return all the | |
| * installed {@link Provider}s which declared their ability to provide | |
| * <i>Signature</i> services, using the <i>Sha1WithDSS</i> algorithm with | |
| * key sizes of <i>1024</i>.</p></li> | |
| * </ul> | |
| * | |
| * @param filter | |
| * the <i>selection</i> criterion for selecting among the installed | |
| * {@link Provider}s. | |
| * @return all the installed {@link Provider}s which satisfy the <i>selection</i> | |
| * criterion. Returns <code>null</code> if no installed | |
| * {@link Provider}s were found which satisfy the <i>selection</i> | |
| * criterion. Returns ALL installed {@link Provider}s if | |
| * <code>filter</code> is <code>null</code> or is an empty string. | |
| * @throws InvalidParameterException | |
| * if an exception occurs while parsing the <code>filter</code>. | |
| * @see #getProviders(Map) | |
| */ | |
| public static Provider[] getProviders(String filter) | |
| { | |
| if (providers == null || providers.isEmpty()) | |
| return null; | |
| if (filter == null || filter.length() == 0) | |
| return getProviders(); | |
| HashMap map = new HashMap(1); | |
| int i = filter.indexOf(':'); | |
| if (i == -1) // <service>.<algorithm> | |
| map.put(filter, ""); | |
| else // <service>.<algorithm> <attribute>:<value> | |
| map.put(filter.substring(0, i), filter.substring(i+1)); | |
| return getProviders(map); | |
| } | |
| /** | |
| * Returns an array of currently installed {@link Provider}s which satisfy a | |
| * set of <i>selection</i> criteria. | |
| * | |
| * <p>The <i>selection</i> criteria are defined in a {@link Map} where each | |
| * element specifies a <i>selection</i> querry. The <i>Keys</i> in this | |
| * {@link Map} must be in one of the two following forms:</p> | |
| * | |
| * <ul> | |
| * <li><crypto_service>.<algorithm_or_type>: Where | |
| * <i>crypto_service</i> is a case-insensitive string, similar to what has | |
| * been described in the {@link #getAlgorithms(String)} method, and | |
| * <i>algorithm_or_type</i> is a case-insensitive known name of an | |
| * Algorithm, or one of its aliases. The <i>value</i> of the entry in the | |
| * {@link Map} for such a <i>Key</i> MUST be the empty string. | |
| * {@link Provider}s which provide an implementation for the designated | |
| * <i>service algorithm</i> are included in the result.</li> | |
| * | |
| * <li><crypto_service>.<algorithm_or_type> <attribute_name>: | |
| * Where <i>crypto_service</i> is a case-insensitive string, similar to what | |
| * has been described in the {@link #getAlgorithms(String)} method, | |
| * <i>algorithm_or_type</i> is a case-insensitive known name of an Algorithm | |
| * or one of its aliases, and <i>attribute_name</i> is a case-insensitive | |
| * property name with no whitespace characters, and no dots, in-between. The | |
| * <i>value</i> of the entry in this {@link Map} for such a <i>Key</i> MUST | |
| * NOT be <code>null</code> or an empty string. {@link Provider}s which | |
| * declare the designated <i>attribute_name</i> and <i>value</i> for the | |
| * designated <i>service algorithm</i> are included in the result.</li> | |
| * </ul> | |
| * | |
| * @param filter | |
| * a {@link Map} of <i>selection querries</i>. | |
| * @return all currently installed {@link Provider}s which satisfy ALL the | |
| * <i>selection</i> criteria defined in <code>filter</code>. | |
| * Returns ALL installed {@link Provider}s if <code>filter</code> | |
| * is <code>null</code> or empty. | |
| * @throws InvalidParameterException | |
| * if an exception is encountered while parsing the syntax of the | |
| * {@link Map}'s <i>keys</i>. | |
| * @see #getProviders(String) | |
| */ | |
| public static Provider[] getProviders(Map filter) | |
| { | |
| if (providers == null || providers.isEmpty()) | |
| return null; | |
| if (filter == null) | |
| return getProviders(); | |
| Set querries = filter.keySet(); | |
| if (querries == null || querries.isEmpty()) | |
| return getProviders(); | |
| LinkedHashSet result = new LinkedHashSet(providers); // assume all | |
| int dot, ws; | |
| String querry, service, algorithm, attribute, value; | |
| LinkedHashSet serviceProviders = new LinkedHashSet(); // preserve insertion order | |
| for (Iterator i = querries.iterator(); i.hasNext(); ) | |
| { | |
| querry = (String) i.next(); | |
| if (querry == null) // all providers | |
| continue; | |
| querry = querry.trim(); | |
| if (querry.length() == 0) // all providers | |
| continue; | |
| dot = querry.indexOf('.'); | |
| if (dot == -1) // syntax error | |
| throw new InvalidParameterException( | |
| "missing dot in '" + String.valueOf(querry)+"'"); | |
| value = (String) filter.get(querry); | |
| // deconstruct querry into [service, algorithm, attribute] | |
| if (value == null || value.trim().length() == 0) // <service>.<algorithm> | |
| { | |
| value = null; | |
| attribute = null; | |
| service = querry.substring(0, dot).trim(); | |
| algorithm = querry.substring(dot+1).trim(); | |
| } | |
| else // <service>.<algorithm> <attribute> | |
| { | |
| ws = querry.indexOf(' '); | |
| if (ws == -1) | |
| throw new InvalidParameterException( | |
| "value (" + String.valueOf(value) + | |
| ") is not empty, but querry (" + String.valueOf(querry) + | |
| ") is missing at least one space character"); | |
| value = value.trim(); | |
| attribute = querry.substring(ws+1).trim(); | |
| // was the dot in the attribute? | |
| if (attribute.indexOf('.') != -1) | |
| throw new InvalidParameterException( | |
| "attribute_name (" + String.valueOf(attribute) + | |
| ") in querry (" + String.valueOf(querry) + ") contains a dot"); | |
| querry = querry.substring(0, ws).trim(); | |
| service = querry.substring(0, dot).trim(); | |
| algorithm = querry.substring(dot+1).trim(); | |
| } | |
| // service and algorithm must not be empty | |
| if (service.length() == 0) | |
| throw new InvalidParameterException( | |
| "<crypto_service> in querry (" + String.valueOf(querry) + | |
| ") is empty"); | |
| if (algorithm.length() == 0) | |
| throw new InvalidParameterException( | |
| "<algorithm_or_type> in querry (" + String.valueOf(querry) + | |
| ") is empty"); | |
| selectProviders(service, algorithm, attribute, value, result, serviceProviders); | |
| result.retainAll(serviceProviders); // eval next retaining found providers | |
| if (result.isEmpty()) // no point continuing | |
| break; | |
| } | |
| if (result.isEmpty()) | |
| return null; | |
| return (Provider[]) result.toArray(new Provider[result.size()]); | |
| } | |
| private static void selectProviders(String svc, String algo, String attr, | |
| String val, LinkedHashSet providerSet, | |
| LinkedHashSet result) | |
| { | |
| result.clear(); // ensure we start with an empty result set | |
| for (Iterator i = providerSet.iterator(); i.hasNext(); ) | |
| { | |
| Provider p = (Provider) i.next(); | |
| if (provides(p, svc, algo, attr, val)) | |
| result.add(p); | |
| } | |
| } | |
| private static boolean provides(Provider p, String svc, String algo, | |
| String attr, String val) | |
| { | |
| Iterator it; | |
| String serviceDotAlgorithm = null; | |
| String key = null; | |
| String realVal; | |
| boolean found = false; | |
| // if <svc>.<algo> <attr> is in the set then so is <svc>.<algo> | |
| // but it may be stored under an alias <algo>. resolve | |
| outer: for (int r = 0; r < 3; r++) // guard against circularity | |
| { | |
| serviceDotAlgorithm = (svc+"."+String.valueOf(algo)).trim(); | |
| for (it = p.keySet().iterator(); it.hasNext(); ) | |
| { | |
| key = (String) it.next(); | |
| if (key.equalsIgnoreCase(serviceDotAlgorithm)) // eureka | |
| { | |
| found = true; | |
| break outer; | |
| } | |
| // it may be there but as an alias | |
| if (key.equalsIgnoreCase(ALG_ALIAS + serviceDotAlgorithm)) | |
| { | |
| algo = p.getProperty(key); | |
| continue outer; | |
| } | |
| // else continue inner | |
| } | |
| } | |
| if (!found) | |
| return false; | |
| // found a candidate for the querry. do we have an attr to match? | |
| if (val == null) // <service>.<algorithm> querry | |
| return true; | |
| // <service>.<algorithm> <attribute>; find the key entry that match | |
| String realAttr; | |
| int limit = serviceDotAlgorithm.length() + 1; | |
| for (it = p.keySet().iterator(); it.hasNext(); ) | |
| { | |
| key = (String) it.next(); | |
| if (key.length() <= limit) | |
| continue; | |
| if (key.substring(0, limit).equalsIgnoreCase(serviceDotAlgorithm+" ")) | |
| { | |
| realAttr = key.substring(limit).trim(); | |
| if (! realAttr.equalsIgnoreCase(attr)) | |
| continue; | |
| // eveything matches so far. do the value | |
| realVal = p.getProperty(key); | |
| if (realVal == null) | |
| return false; | |
| realVal = realVal.trim(); | |
| // is it a string value? | |
| if (val.equalsIgnoreCase(realVal)) | |
| return true; | |
| // assume value is a number. cehck for greater-than-or-equal | |
| return (new Integer(val).intValue() >= new Integer(realVal).intValue()); | |
| } | |
| } | |
| return false; | |
| } | |
| } |