Frames | No Frames |
1: /* Security.java --- Java base security class implementation 2: Copyright (C) 1999, 2001, 2002, 2003, 2004, 2005 Free Software Foundation, Inc. 3: 4: This file is part of GNU Classpath. 5: 6: GNU Classpath is free software; you can redistribute it and/or modify 7: it under the terms of the GNU General Public License as published by 8: the Free Software Foundation; either version 2, or (at your option) 9: any later version. 10: 11: GNU Classpath is distributed in the hope that it will be useful, but 12: WITHOUT ANY WARRANTY; without even the implied warranty of 13: MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU 14: General Public License for more details. 15: 16: You should have received a copy of the GNU General Public License 17: along with GNU Classpath; see the file COPYING. If not, write to the 18: Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 19: 02110-1301 USA. 20: 21: Linking this library statically or dynamically with other modules is 22: making a combined work based on this library. Thus, the terms and 23: conditions of the GNU General Public License cover the whole 24: combination. 25: 26: As a special exception, the copyright holders of this library give you 27: permission to link this library with independent modules to produce an 28: executable, regardless of the license terms of these independent 29: modules, and to copy and distribute the resulting executable under 30: terms of your choice, provided that you also meet, for each linked 31: independent module, the terms and conditions of the license of that 32: module. An independent module is a module which is not derived from 33: or based on this library. If you modify this library, you may extend 34: this exception to your version of the library, but you are not 35: obligated to do so. If you do not wish to do so, delete this 36: exception statement from your version. */ 37: 38: 39: package java.security; 40: 41: import gnu.classpath.SystemProperties; 42: 43: import gnu.classpath.Configuration; 44: 45: import java.io.IOException; 46: import java.io.InputStream; 47: import java.net.URL; 48: import java.util.Collections; 49: import java.util.Enumeration; 50: import java.util.HashMap; 51: import java.util.HashSet; 52: import java.util.Iterator; 53: import java.util.LinkedHashSet; 54: import java.util.Map; 55: import java.util.Properties; 56: import java.util.Set; 57: import java.util.Vector; 58: 59: /** 60: * This class centralizes all security properties and common security methods. 61: * One of its primary uses is to manage providers. 62: * 63: * @author Mark Benvenuto (ivymccough@worldnet.att.net) 64: */ 65: public final class Security 66: { 67: private static final String ALG_ALIAS = "Alg.Alias."; 68: 69: private static Vector providers = new Vector(); 70: private static Properties secprops = new Properties(); 71: 72: static 73: { 74: String base = SystemProperties.getProperty("gnu.classpath.home.url"); 75: String vendor = SystemProperties.getProperty("gnu.classpath.vm.shortname"); 76: 77: // Try VM specific security file 78: boolean loaded = loadProviders (base, vendor); 79: 80: // Append classpath standard provider if possible 81: if (!loadProviders (base, "classpath") 82: && !loaded 83: && providers.size() == 0) 84: { 85: if (Configuration.DEBUG) 86: { 87: /* No providers found and both security files failed to 88: * load properly. Give a warning in case of DEBUG is 89: * enabled. Could be done with java.util.logging later. 90: */ 91: System.err.println 92: ("WARNING: could not properly read security provider files:"); 93: System.err.println 94: (" " + base + "/security/" + vendor 95: + ".security"); 96: System.err.println 97: (" " + base + "/security/" + "classpath" 98: + ".security"); 99: System.err.println 100: (" Falling back to standard GNU security provider"); 101: } 102: providers.addElement (new gnu.java.security.provider.Gnu()); 103: } 104: } 105: // This class can't be instantiated. 106: private Security() 107: { 108: } 109: 110: /** 111: * Tries to load the vender specific security providers from the given 112: * base URL. Returns true if the resource could be read and completely 113: * parsed successfully, false otherwise. 114: */ 115: private static boolean loadProviders(String baseUrl, String vendor) 116: { 117: if (baseUrl == null || vendor == null) 118: return false; 119: 120: boolean result = true; 121: String secfilestr = baseUrl + "/security/" + vendor + ".security"; 122: try 123: { 124: InputStream fin = new URL(secfilestr).openStream(); 125: secprops.load(fin); 126: 127: int i = 1; 128: String name; 129: while ((name = secprops.getProperty("security.provider." + i)) != null) 130: { 131: Exception exception = null; 132: try 133: { 134: ClassLoader sys = ClassLoader.getSystemClassLoader(); 135: providers.addElement(Class.forName(name, true, sys).newInstance()); 136: } 137: catch (ClassNotFoundException x) 138: { 139: exception = x; 140: } 141: catch (InstantiationException x) 142: { 143: exception = x; 144: } 145: catch (IllegalAccessException x) 146: { 147: exception = x; 148: } 149: 150: if (exception != null) 151: { 152: System.err.println ("WARNING: Error loading security provider " 153: + name + ": " + exception); 154: result = false; 155: } 156: i++; 157: } 158: } 159: catch (IOException ignored) 160: { 161: result = false; 162: } 163: 164: return result; 165: } 166: 167: /** 168: * Gets a specified property for an algorithm. The algorithm name should be a 169: * standard name. See Appendix A in the Java Cryptography Architecture API 170: * Specification & Reference for information about standard algorithm 171: * names. One possible use is by specialized algorithm parsers, which may map 172: * classes to algorithms which they understand (much like {@link Key} parsers 173: * do). 174: * 175: * @param algName the algorithm name. 176: * @param propName the name of the property to get. 177: * @return the value of the specified property. 178: * @deprecated This method used to return the value of a proprietary property 179: * in the master file of the "SUN" Cryptographic Service Provider in order to 180: * determine how to parse algorithm-specific parameters. Use the new 181: * provider-based and algorithm-independent {@link AlgorithmParameters} and 182: * {@link KeyFactory} engine classes (introduced in the Java 2 platform) 183: * instead. 184: */ 185: public static String getAlgorithmProperty(String algName, String propName) 186: { 187: if (algName == null || propName == null) 188: return null; 189: 190: String property = String.valueOf(propName) + "." + String.valueOf(algName); 191: Provider p; 192: for (Iterator i = providers.iterator(); i.hasNext(); ) 193: { 194: p = (Provider) i.next(); 195: for (Iterator j = p.keySet().iterator(); j.hasNext(); ) 196: { 197: String key = (String) j.next(); 198: if (key.equalsIgnoreCase(property)) 199: return p.getProperty(key); 200: } 201: } 202: return null; 203: } 204: 205: /** 206: * <p>Adds a new provider, at a specified position. The position is the 207: * preference order in which providers are searched for requested algorithms. 208: * Note that it is not guaranteed that this preference will be respected. The 209: * position is 1-based, that is, <code>1</code> is most preferred, followed by 210: * <code>2</code>, and so on.</p> 211: * 212: * <p>If the given provider is installed at the requested position, the 213: * provider that used to be at that position, and all providers with a 214: * position greater than position, are shifted up one position (towards the 215: * end of the list of installed providers).</p> 216: * 217: * <p>A provider cannot be added if it is already installed.</p> 218: * 219: * <p>First, if there is a security manager, its <code>checkSecurityAccess() 220: * </code> method is called with the string <code>"insertProvider."+provider. 221: * getName()</code> to see if it's ok to add a new provider. If the default 222: * implementation of <code>checkSecurityAccess()</code> is used (i.e., that 223: * method is not overriden), then this will result in a call to the security 224: * manager's <code>checkPermission()</code> method with a 225: * <code>SecurityPermission("insertProvider."+provider.getName())</code> 226: * permission.</p> 227: * 228: * @param provider the provider to be added. 229: * @param position the preference position that the caller would like for 230: * this provider. 231: * @return the actual preference position in which the provider was added, or 232: * <code>-1</code> if the provider was not added because it is already 233: * installed. 234: * @throws SecurityException if a security manager exists and its 235: * {@link SecurityManager#checkSecurityAccess(String)} method denies access 236: * to add a new provider. 237: * @see #getProvider(String) 238: * @see #removeProvider(String) 239: * @see SecurityPermission 240: */ 241: public static int insertProviderAt(Provider provider, int position) 242: { 243: SecurityManager sm = System.getSecurityManager(); 244: if (sm != null) 245: sm.checkSecurityAccess("insertProvider." + provider.getName()); 246: 247: position--; 248: int max = providers.size (); 249: for (int i = 0; i < max; i++) 250: { 251: if (((Provider) providers.elementAt(i)).getName().equals(provider.getName())) 252: return -1; 253: } 254: 255: if (position < 0) 256: position = 0; 257: if (position > max) 258: position = max; 259: 260: providers.insertElementAt(provider, position); 261: 262: return position + 1; 263: } 264: 265: /** 266: * <p>Adds a provider to the next position available.</p> 267: * 268: * <p>First, if there is a security manager, its <code>checkSecurityAccess() 269: * </code> method is called with the string <code>"insertProvider."+provider. 270: * getName()</code> to see if it's ok to add a new provider. If the default 271: * implementation of <code>checkSecurityAccess()</code> is used (i.e., that 272: * method is not overriden), then this will result in a call to the security 273: * manager's <code>checkPermission()</code> method with a 274: * <code>SecurityPermission("insertProvider."+provider.getName())</code> 275: * permission.</p> 276: * 277: * @param provider the provider to be added. 278: * @return the preference position in which the provider was added, or 279: * <code>-1</code> if the provider was not added because it is already 280: * installed. 281: * @throws SecurityException if a security manager exists and its 282: * {@link SecurityManager#checkSecurityAccess(String)} method denies access 283: * to add a new provider. 284: * @see #getProvider(String) 285: * @see #removeProvider(String) 286: * @see SecurityPermission 287: */ 288: public static int addProvider(Provider provider) 289: { 290: return insertProviderAt (provider, providers.size () + 1); 291: } 292: 293: /** 294: * <p>Removes the provider with the specified name.</p> 295: * 296: * <p>When the specified provider is removed, all providers located at a 297: * position greater than where the specified provider was are shifted down 298: * one position (towards the head of the list of installed providers).</p> 299: * 300: * <p>This method returns silently if the provider is not installed.</p> 301: * 302: * <p>First, if there is a security manager, its <code>checkSecurityAccess() 303: * </code> method is called with the string <code>"removeProvider."+name</code> 304: * to see if it's ok to remove the provider. If the default implementation of 305: * <code>checkSecurityAccess()</code> is used (i.e., that method is not 306: * overriden), then this will result in a call to the security manager's 307: * <code>checkPermission()</code> method with a <code>SecurityPermission( 308: * "removeProvider."+name)</code> permission.</p> 309: * 310: * @param name the name of the provider to remove. 311: * @throws SecurityException if a security manager exists and its 312: * {@link SecurityManager#checkSecurityAccess(String)} method denies access 313: * to remove the provider. 314: * @see #getProvider(String) 315: * @see #addProvider(Provider) 316: */ 317: public static void removeProvider(String name) 318: { 319: SecurityManager sm = System.getSecurityManager(); 320: if (sm != null) 321: sm.checkSecurityAccess("removeProvider." + name); 322: 323: int max = providers.size (); 324: for (int i = 0; i < max; i++) 325: { 326: if (((Provider) providers.elementAt(i)).getName().equals(name)) 327: { 328: providers.remove(i); 329: break; 330: } 331: } 332: } 333: 334: /** 335: * Returns an array containing all the installed providers. The order of the 336: * providers in the array is their preference order. 337: * 338: * @return an array of all the installed providers. 339: */ 340: public static Provider[] getProviders() 341: { 342: Provider[] array = new Provider[providers.size ()]; 343: providers.copyInto (array); 344: return array; 345: } 346: 347: /** 348: * Returns the provider installed with the specified name, if any. Returns 349: * <code>null</code> if no provider with the specified name is installed. 350: * 351: * @param name the name of the provider to get. 352: * @return the provider of the specified name. 353: * @see #removeProvider(String) 354: * @see #addProvider(Provider) 355: */ 356: public static Provider getProvider(String name) 357: { 358: Provider p; 359: int max = providers.size (); 360: for (int i = 0; i < max; i++) 361: { 362: p = (Provider) providers.elementAt(i); 363: if (p.getName().equals(name)) 364: return p; 365: } 366: return null; 367: } 368: 369: /** 370: * <p>Gets a security property value.</p> 371: * 372: * <p>First, if there is a security manager, its <code>checkPermission()</code> 373: * method is called with a <code>SecurityPermission("getProperty."+key)</code> 374: * permission to see if it's ok to retrieve the specified security property 375: * value.</p> 376: * 377: * @param key the key of the property being retrieved. 378: * @return the value of the security property corresponding to key. 379: * @throws SecurityException if a security manager exists and its 380: * {@link SecurityManager#checkPermission(Permission)} method denies access 381: * to retrieve the specified security property value. 382: * @see #setProperty(String, String) 383: * @see SecurityPermission 384: */ 385: public static String getProperty(String key) 386: { 387: SecurityManager sm = System.getSecurityManager(); 388: if (sm != null) 389: sm.checkSecurityAccess("getProperty." + key); 390: 391: return secprops.getProperty(key); 392: } 393: 394: /** 395: * <p>Sets a security property value.</p> 396: * 397: * <p>First, if there is a security manager, its <code>checkPermission()</code> 398: * method is called with a <code>SecurityPermission("setProperty."+key)</code> 399: * permission to see if it's ok to set the specified security property value. 400: * </p> 401: * 402: * @param key the name of the property to be set. 403: * @param datnum the value of the property to be set. 404: * @throws SecurityException if a security manager exists and its 405: * {@link SecurityManager#checkPermission(Permission)} method denies access 406: * to set the specified security property value. 407: * @see #getProperty(String) 408: * @see SecurityPermission 409: */ 410: public static void setProperty(String key, String datnum) 411: { 412: SecurityManager sm = System.getSecurityManager(); 413: if (sm != null) 414: sm.checkSecurityAccess("setProperty." + key); 415: 416: secprops.put(key, datnum); 417: } 418: 419: /** 420: * Returns a Set of Strings containing the names of all available algorithms 421: * or types for the specified Java cryptographic service (e.g., Signature, 422: * MessageDigest, Cipher, Mac, KeyStore). Returns an empty Set if there is no 423: * provider that supports the specified service. For a complete list of Java 424: * cryptographic services, please see the Java Cryptography Architecture API 425: * Specification & Reference. Note: the returned set is immutable. 426: * 427: * @param serviceName the name of the Java cryptographic service (e.g., 428: * Signature, MessageDigest, Cipher, Mac, KeyStore). Note: this parameter is 429: * case-insensitive. 430: * @return a Set of Strings containing the names of all available algorithms 431: * or types for the specified Java cryptographic service or an empty set if 432: * no provider supports the specified service. 433: * @since 1.4 434: */ 435: public static Set getAlgorithms(String serviceName) 436: { 437: HashSet result = new HashSet(); 438: if (serviceName == null || serviceName.length() == 0) 439: return result; 440: 441: serviceName = serviceName.trim(); 442: if (serviceName.length() == 0) 443: return result; 444: 445: serviceName = serviceName.toUpperCase()+"."; 446: Provider[] providers = getProviders(); 447: int ndx; 448: for (int i = 0; i < providers.length; i++) 449: for (Enumeration e = providers[i].propertyNames(); e.hasMoreElements(); ) 450: { 451: String service = ((String) e.nextElement()).trim(); 452: if (service.toUpperCase().startsWith(serviceName)) 453: { 454: service = service.substring(serviceName.length()).trim(); 455: ndx = service.indexOf(' '); // get rid of attributes 456: if (ndx != -1) 457: service = service.substring(0, ndx); 458: result.add(service); 459: } 460: } 461: return Collections.unmodifiableSet(result); 462: } 463: 464: /** 465: * <p>Returns an array containing all installed providers that satisfy the 466: * specified selection criterion, or <code>null</code> if no such providers 467: * have been installed. The returned providers are ordered according to their 468: * preference order.</p> 469: * 470: * <p>A cryptographic service is always associated with a particular 471: * algorithm or type. For example, a digital signature service is always 472: * associated with a particular algorithm (e.g., <i>DSA</i>), and a 473: * CertificateFactory service is always associated with a particular 474: * certificate type (e.g., <i>X.509</i>).</p> 475: * 476: * <p>The selection criterion must be specified in one of the following two 477: * formats:</p> 478: * 479: * <ul> 480: * <li><p><crypto_service>.<algorithm_or_type></p> 481: * <p>The cryptographic service name must not contain any dots.</p> 482: * <p>A provider satisfies the specified selection criterion iff the 483: * provider implements the specified algorithm or type for the specified 484: * cryptographic service.</p> 485: * <p>For example, "CertificateFactory.X.509" would be satisfied by any 486: * provider that supplied a CertificateFactory implementation for X.509 487: * certificates.</p></li> 488: * 489: * <li><p><crypto_service>.<algorithm_or_type> <attribute_name>:<attribute_value></p> 490: * <p>The cryptographic service name must not contain any dots. There must 491: * be one or more space charaters between the the <algorithm_or_type> 492: * and the <attribute_name>.</p> 493: * <p>A provider satisfies this selection criterion iff the provider 494: * implements the specified algorithm or type for the specified 495: * cryptographic service and its implementation meets the constraint 496: * expressed by the specified attribute name/value pair.</p> 497: * <p>For example, "Signature.SHA1withDSA KeySize:1024" would be satisfied 498: * by any provider that implemented the SHA1withDSA signature algorithm 499: * with a keysize of 1024 (or larger).</p></li> 500: * </ul> 501: * 502: * <p>See Appendix A in the Java Cryptogaphy Architecture API Specification 503: * & Reference for information about standard cryptographic service names, 504: * standard algorithm names and standard attribute names.</p> 505: * 506: * @param filter the criterion for selecting providers. The filter is case- 507: * insensitive. 508: * @return all the installed providers that satisfy the selection criterion, 509: * or null if no such providers have been installed. 510: * @throws InvalidParameterException if the filter is not in the required 511: * format. 512: * @see #getProviders(Map) 513: */ 514: public static Provider[] getProviders(String filter) 515: { 516: if (providers == null || providers.isEmpty()) 517: return null; 518: 519: if (filter == null || filter.length() == 0) 520: return getProviders(); 521: 522: HashMap map = new HashMap(1); 523: int i = filter.indexOf(':'); 524: if (i == -1) // <service>.<algorithm> 525: map.put(filter, ""); 526: else // <service>.<algorithm> <attribute>:<value> 527: map.put(filter.substring(0, i), filter.substring(i+1)); 528: 529: return getProviders(map); 530: } 531: 532: /** 533: * <p>Returns an array containing all installed providers that satisfy the 534: * specified selection criteria, or <code>null</code> if no such providers 535: * have been installed. The returned providers are ordered according to their 536: * preference order.</p> 537: * 538: * <p>The selection criteria are represented by a map. Each map entry 539: * represents a selection criterion. A provider is selected iff it satisfies 540: * all selection criteria. The key for any entry in such a map must be in one 541: * of the following two formats:</p> 542: * 543: * <ul> 544: * <li><p><crypto_service>.<algorithm_or_type></p> 545: * <p>The cryptographic service name must not contain any dots.</p> 546: * <p>The value associated with the key must be an empty string.</p> 547: * <p>A provider satisfies this selection criterion iff the provider 548: * implements the specified algorithm or type for the specified 549: * cryptographic service.</p></li> 550: * 551: * <li><p><crypto_service>.<algorithm_or_type> <attribute_name></p> 552: * <p>The cryptographic service name must not contain any dots. There must 553: * be one or more space charaters between the <algorithm_or_type> and 554: * the <attribute_name>.</p> 555: * <p>The value associated with the key must be a non-empty string. A 556: * provider satisfies this selection criterion iff the provider implements 557: * the specified algorithm or type for the specified cryptographic service 558: * and its implementation meets the constraint expressed by the specified 559: * attribute name/value pair.</p></li> 560: * </ul> 561: * 562: * <p>See Appendix A in the Java Cryptogaphy Architecture API Specification 563: * & Reference for information about standard cryptographic service names, 564: * standard algorithm names and standard attribute names.</p> 565: * 566: * @param filter the criteria for selecting providers. The filter is case- 567: * insensitive. 568: * @return all the installed providers that satisfy the selection criteria, 569: * or <code>null</code> if no such providers have been installed. 570: * @throws InvalidParameterException if the filter is not in the required 571: * format. 572: * @see #getProviders(String) 573: */ 574: public static Provider[] getProviders(Map filter) 575: { 576: if (providers == null || providers.isEmpty()) 577: return null; 578: 579: if (filter == null) 580: return getProviders(); 581: 582: Set querries = filter.keySet(); 583: if (querries == null || querries.isEmpty()) 584: return getProviders(); 585: 586: LinkedHashSet result = new LinkedHashSet(providers); // assume all 587: int dot, ws; 588: String querry, service, algorithm, attribute, value; 589: LinkedHashSet serviceProviders = new LinkedHashSet(); // preserve insertion order 590: for (Iterator i = querries.iterator(); i.hasNext(); ) 591: { 592: querry = (String) i.next(); 593: if (querry == null) // all providers 594: continue; 595: 596: querry = querry.trim(); 597: if (querry.length() == 0) // all providers 598: continue; 599: 600: dot = querry.indexOf('.'); 601: if (dot == -1) // syntax error 602: throw new InvalidParameterException( 603: "missing dot in '" + String.valueOf(querry)+"'"); 604: 605: value = (String) filter.get(querry); 606: // deconstruct querry into [service, algorithm, attribute] 607: if (value == null || value.trim().length() == 0) // <service>.<algorithm> 608: { 609: value = null; 610: attribute = null; 611: service = querry.substring(0, dot).trim(); 612: algorithm = querry.substring(dot+1).trim(); 613: } 614: else // <service>.<algorithm> <attribute> 615: { 616: ws = querry.indexOf(' '); 617: if (ws == -1) 618: throw new InvalidParameterException( 619: "value (" + String.valueOf(value) + 620: ") is not empty, but querry (" + String.valueOf(querry) + 621: ") is missing at least one space character"); 622: value = value.trim(); 623: attribute = querry.substring(ws+1).trim(); 624: // was the dot in the attribute? 625: if (attribute.indexOf('.') != -1) 626: throw new InvalidParameterException( 627: "attribute_name (" + String.valueOf(attribute) + 628: ") in querry (" + String.valueOf(querry) + ") contains a dot"); 629: 630: querry = querry.substring(0, ws).trim(); 631: service = querry.substring(0, dot).trim(); 632: algorithm = querry.substring(dot+1).trim(); 633: } 634: 635: // service and algorithm must not be empty 636: if (service.length() == 0) 637: throw new InvalidParameterException( 638: "<crypto_service> in querry (" + String.valueOf(querry) + 639: ") is empty"); 640: 641: if (algorithm.length() == 0) 642: throw new InvalidParameterException( 643: "<algorithm_or_type> in querry (" + String.valueOf(querry) + 644: ") is empty"); 645: 646: selectProviders(service, algorithm, attribute, value, result, serviceProviders); 647: result.retainAll(serviceProviders); // eval next retaining found providers 648: if (result.isEmpty()) // no point continuing 649: break; 650: } 651: 652: if (result.isEmpty()) 653: return null; 654: 655: return (Provider[]) result.toArray(new Provider[result.size()]); 656: } 657: 658: private static void selectProviders(String svc, String algo, String attr, 659: String val, LinkedHashSet providerSet, 660: LinkedHashSet result) 661: { 662: result.clear(); // ensure we start with an empty result set 663: for (Iterator i = providerSet.iterator(); i.hasNext(); ) 664: { 665: Provider p = (Provider) i.next(); 666: if (provides(p, svc, algo, attr, val)) 667: result.add(p); 668: } 669: } 670: 671: private static boolean provides(Provider p, String svc, String algo, 672: String attr, String val) 673: { 674: Iterator it; 675: String serviceDotAlgorithm = null; 676: String key = null; 677: String realVal; 678: boolean found = false; 679: // if <svc>.<algo> <attr> is in the set then so is <svc>.<algo> 680: // but it may be stored under an alias <algo>. resolve 681: outer: for (int r = 0; r < 3; r++) // guard against circularity 682: { 683: serviceDotAlgorithm = (svc+"."+String.valueOf(algo)).trim(); 684: for (it = p.keySet().iterator(); it.hasNext(); ) 685: { 686: key = (String) it.next(); 687: if (key.equalsIgnoreCase(serviceDotAlgorithm)) // eureka 688: { 689: found = true; 690: break outer; 691: } 692: // it may be there but as an alias 693: if (key.equalsIgnoreCase(ALG_ALIAS + serviceDotAlgorithm)) 694: { 695: algo = p.getProperty(key); 696: continue outer; 697: } 698: // else continue inner 699: } 700: } 701: 702: if (!found) 703: return false; 704: 705: // found a candidate for the querry. do we have an attr to match? 706: if (val == null) // <service>.<algorithm> querry 707: return true; 708: 709: // <service>.<algorithm> <attribute>; find the key entry that match 710: String realAttr; 711: int limit = serviceDotAlgorithm.length() + 1; 712: for (it = p.keySet().iterator(); it.hasNext(); ) 713: { 714: key = (String) it.next(); 715: if (key.length() <= limit) 716: continue; 717: 718: if (key.substring(0, limit).equalsIgnoreCase(serviceDotAlgorithm+" ")) 719: { 720: realAttr = key.substring(limit).trim(); 721: if (! realAttr.equalsIgnoreCase(attr)) 722: continue; 723: 724: // eveything matches so far. do the value 725: realVal = p.getProperty(key); 726: if (realVal == null) 727: return false; 728: 729: realVal = realVal.trim(); 730: // is it a string value? 731: if (val.equalsIgnoreCase(realVal)) 732: return true; 733: 734: // assume value is a number. cehck for greater-than-or-equal 735: return (new Integer(val).intValue() >= new Integer(realVal).intValue()); 736: } 737: } 738: 739: return false; 740: } 741: }