Provider.java revision 12245:2f69eb7d4b90
1/* 2 * Copyright (c) 1996, 2015, Oracle and/or its affiliates. All rights reserved 3 * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. 4 * 5 * This code is free software; you can redistribute it and/or modify it 6 * under the terms of the GNU General Public License version 2 only, as 7 * published by the Free Software Foundation. Oracle designates this 8 * particular file as subject to the "Classpath" exception as provided 9 * by Oracle in the LICENSE file that accompanied this code. 10 * 11 * This code is distributed in the hope that it will be useful, but WITHOUT 12 * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or 13 * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License 14 * version 2 for more details (a copy is included in the LICENSE file that 15 * accompanied this code). 16 * 17 * You should have received a copy of the GNU General Public License version 18 * 2 along with this work; if not, write to the Free Software Foundation, 19 * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. 20 * 21 * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA 22 * or visit www.oracle.com if you need additional information or have any 23 * questions. 24 */ 25 26package java.security; 27 28import java.io.*; 29import java.util.*; 30import static java.util.Locale.ENGLISH; 31import java.lang.ref.*; 32import java.lang.reflect.*; 33import java.util.function.BiConsumer; 34import java.util.function.BiFunction; 35import java.util.function.Function; 36 37/** 38 * This class represents a "provider" for the 39 * Java Security API, where a provider implements some or all parts of 40 * Java Security. Services that a provider may implement include: 41 * 42 * <ul> 43 * 44 * <li>Algorithms (such as DSA, RSA, or SHA-256). 45 * 46 * <li>Key generation, conversion, and management facilities (such as for 47 * algorithm-specific keys). 48 * 49 * </ul> 50 * 51 * <p>Some provider implementations may encounter unrecoverable internal 52 * errors during their operation, for example a failure to communicate with a 53 * security token. A {@link ProviderException} should be used to indicate 54 * such errors. 55 * 56 * <p>Please note that a provider can be used to implement any security 57 * service in Java that uses a pluggable architecture with a choice 58 * of implementations that fit underneath. 59 * 60 * <p>The service type {@code Provider} is reserved for use by the 61 * security framework. Services of this type cannot be added, removed, 62 * or modified by applications. 63 * The following attributes are automatically placed in each Provider object: 64 * <table cellspacing=4> 65 * <caption><b>Attributes Automatically Placed in a Provider Object</b></caption> 66 * <tr><th>Name</th><th>Value</th> 67 * <tr><td>{@code Provider.id name}</td> 68 * <td>{@code String.valueOf(provider.getName())}</td> 69 * <tr><td>{@code Provider.id version}</td> 70 * <td>{@code String.valueOf(provider.getVersion())}</td> 71 * <tr><td>{@code Provider.id info}</td> 72 <td>{@code String.valueOf(provider.getInfo())}</td> 73 * <tr><td>{@code Provider.id className}</td> 74 * <td>{@code provider.getClass().getName()}</td> 75 * </table> 76 * 77 * <p>Each provider has a name and a version number. A provider normally 78 * identifies itself with a file named {@code java.security.Provider} 79 * in the resource directory {@code META-INF/services}. 80 * Security providers are looked up via the {@link ServiceLoader} mechanism 81 * using the {@link ClassLoader#getSystemClassLoader application class loader}. 82 * 83 * <p>Providers may be configured such that they are automatically 84 * installed and made available at runtime via the 85 * {@link Security#getProviders() Security.getProviders()} method. 86 * The mechanism for configuring and installing security providers is 87 * implementation-specific. 88 * 89 * @implNote 90 * The JDK implementation supports static registration of the security 91 * providers via the {@code conf/security/java.security} file in the Java 92 * installation directory. These providers are automatically installed by 93 * the JDK runtime, see <a href = 94 * "../../../technotes/guides/security/crypto/CryptoSpec.html#Provider">The Provider Class</a> 95 * in the "Java Cryptography Architecture API Specification & Reference" 96 * for information about how a particular type of provider, the cryptographic 97 * service provider, works and is installed. 98 * 99 * @author Benjamin Renaud 100 * @author Andreas Sterbenz 101 */ 102public abstract class Provider extends Properties { 103 104 // Declare serialVersionUID to be compatible with JDK1.1 105 static final long serialVersionUID = -4298000515446427739L; 106 107 private static final sun.security.util.Debug debug = 108 sun.security.util.Debug.getInstance 109 ("provider", "Provider"); 110 111 /** 112 * The provider name. 113 * 114 * @serial 115 */ 116 private String name; 117 118 /** 119 * A description of the provider and its services. 120 * 121 * @serial 122 */ 123 private String info; 124 125 /** 126 * The provider version number. 127 * 128 * @serial 129 */ 130 private double version; 131 132 133 private transient Set<Map.Entry<Object,Object>> entrySet = null; 134 private transient int entrySetCallCount = 0; 135 136 private transient boolean initialized; 137 138 private static Object newInstanceUtil(final Class<?> clazz, 139 final Class<?> ctrParamClz, final Object ctorParamObj) 140 throws Exception { 141 if (ctrParamClz == null) { 142 Constructor<?> con = clazz.getConstructor(); 143 return con.newInstance(); 144 } else { 145 Constructor<?> con = clazz.getConstructor(ctrParamClz); 146 return con.newInstance(ctorParamObj); 147 } 148 } 149 150 /** 151 * Constructs a provider with the specified name, version number, 152 * and information. 153 * 154 * @param name the provider name. 155 * 156 * @param version the provider version number. 157 * 158 * @param info a description of the provider and its services. 159 */ 160 protected Provider(String name, double version, String info) { 161 this.name = name; 162 this.version = version; 163 this.info = info; 164 putId(); 165 initialized = true; 166 } 167 168 /** 169 * Apply the supplied configuration argument to this provider instance 170 * and return the configured provider. Note that if this provider cannot 171 * be configured in-place, a new provider will be created and returned. 172 * Therefore, callers should always use the returned provider. 173 * 174 * @implSpec 175 * The default implementation throws {@code UnsupportedOperationException}. 176 * Subclasses should override this method only if a configuration argument 177 * is supported. 178 * 179 * @param configArg the configuration information for configuring this 180 * provider. 181 * 182 * @throws UnsupportedOperationException if a configuration argument is 183 * not supported. 184 * @throws NullPointerException if the supplied configuration argument is 185 null. 186 * @throws InvalidParameterException if the supplied configuration argument 187 * is invalid. 188 * @return a provider configured with the supplied configuration argument. 189 * 190 * @since 1.9 191 */ 192 public Provider configure(String configArg) { 193 throw new UnsupportedOperationException("configure is not supported"); 194 } 195 196 /** 197 * Returns the name of this provider. 198 * 199 * @return the name of this provider. 200 */ 201 public String getName() { 202 return name; 203 } 204 205 /** 206 * Returns the version number for this provider. 207 * 208 * @return the version number for this provider. 209 */ 210 public double getVersion() { 211 return version; 212 } 213 214 /** 215 * Returns a human-readable description of the provider and its 216 * services. This may return an HTML page, with relevant links. 217 * 218 * @return a description of the provider and its services. 219 */ 220 public String getInfo() { 221 return info; 222 } 223 224 /** 225 * Returns a string with the name and the version number 226 * of this provider. 227 * 228 * @return the string with the name and the version number 229 * for this provider. 230 */ 231 public String toString() { 232 return name + " version " + version; 233 } 234 235 /* 236 * override the following methods to ensure that provider 237 * information can only be changed if the caller has the appropriate 238 * permissions. 239 */ 240 241 /** 242 * Clears this provider so that it no longer contains the properties 243 * used to look up facilities implemented by the provider. 244 * 245 * <p>If a security manager is enabled, its {@code checkSecurityAccess} 246 * method is called with the string {@code "clearProviderProperties."+name} 247 * (where {@code name} is the provider name) to see if it's ok to clear 248 * this provider. 249 * 250 * @throws SecurityException 251 * if a security manager exists and its {@link 252 * java.lang.SecurityManager#checkSecurityAccess} method 253 * denies access to clear this provider 254 * 255 * @since 1.2 256 */ 257 @Override 258 public synchronized void clear() { 259 check("clearProviderProperties."+name); 260 if (debug != null) { 261 debug.println("Remove " + name + " provider properties"); 262 } 263 implClear(); 264 } 265 266 /** 267 * Reads a property list (key and element pairs) from the input stream. 268 * 269 * @param inStream the input stream. 270 * @exception IOException if an error occurred when reading from the 271 * input stream. 272 * @see java.util.Properties#load 273 */ 274 @Override 275 public synchronized void load(InputStream inStream) throws IOException { 276 check("putProviderProperty."+name); 277 if (debug != null) { 278 debug.println("Load " + name + " provider properties"); 279 } 280 Properties tempProperties = new Properties(); 281 tempProperties.load(inStream); 282 implPutAll(tempProperties); 283 } 284 285 /** 286 * Copies all of the mappings from the specified Map to this provider. 287 * These mappings will replace any properties that this provider had 288 * for any of the keys currently in the specified Map. 289 * 290 * @since 1.2 291 */ 292 @Override 293 public synchronized void putAll(Map<?,?> t) { 294 check("putProviderProperty."+name); 295 if (debug != null) { 296 debug.println("Put all " + name + " provider properties"); 297 } 298 implPutAll(t); 299 } 300 301 /** 302 * Returns an unmodifiable Set view of the property entries contained 303 * in this Provider. 304 * 305 * @see java.util.Map.Entry 306 * @since 1.2 307 */ 308 @Override 309 public synchronized Set<Map.Entry<Object,Object>> entrySet() { 310 checkInitialized(); 311 if (entrySet == null) { 312 if (entrySetCallCount++ == 0) // Initial call 313 entrySet = Collections.unmodifiableMap(this).entrySet(); 314 else 315 return super.entrySet(); // Recursive call 316 } 317 318 // This exception will be thrown if the implementation of 319 // Collections.unmodifiableMap.entrySet() is changed such that it 320 // no longer calls entrySet() on the backing Map. (Provider's 321 // entrySet implementation depends on this "implementation detail", 322 // which is unlikely to change. 323 if (entrySetCallCount != 2) 324 throw new RuntimeException("Internal error."); 325 326 return entrySet; 327 } 328 329 /** 330 * Returns an unmodifiable Set view of the property keys contained in 331 * this provider. 332 * 333 * @since 1.2 334 */ 335 @Override 336 public Set<Object> keySet() { 337 checkInitialized(); 338 return Collections.unmodifiableSet(super.keySet()); 339 } 340 341 /** 342 * Returns an unmodifiable Collection view of the property values 343 * contained in this provider. 344 * 345 * @since 1.2 346 */ 347 @Override 348 public Collection<Object> values() { 349 checkInitialized(); 350 return Collections.unmodifiableCollection(super.values()); 351 } 352 353 /** 354 * Sets the {@code key} property to have the specified 355 * {@code value}. 356 * 357 * <p>If a security manager is enabled, its {@code checkSecurityAccess} 358 * method is called with the string {@code "putProviderProperty."+name}, 359 * where {@code name} is the provider name, to see if it's ok to set this 360 * provider's property values. 361 * 362 * @throws SecurityException 363 * if a security manager exists and its {@link 364 * java.lang.SecurityManager#checkSecurityAccess} method 365 * denies access to set property values. 366 * 367 * @since 1.2 368 */ 369 @Override 370 public synchronized Object put(Object key, Object value) { 371 check("putProviderProperty."+name); 372 if (debug != null) { 373 debug.println("Set " + name + " provider property [" + 374 key + "/" + value +"]"); 375 } 376 return implPut(key, value); 377 } 378 379 /** 380 * If the specified key is not already associated with a value (or is mapped 381 * to {@code null}) associates it with the given value and returns 382 * {@code null}, else returns the current value. 383 * 384 * <p>If a security manager is enabled, its {@code checkSecurityAccess} 385 * method is called with the string {@code "putProviderProperty."+name}, 386 * where {@code name} is the provider name, to see if it's ok to set this 387 * provider's property values. 388 * 389 * @throws SecurityException 390 * if a security manager exists and its {@link 391 * java.lang.SecurityManager#checkSecurityAccess} method 392 * denies access to set property values. 393 * 394 * @since 1.8 395 */ 396 @Override 397 public synchronized Object putIfAbsent(Object key, Object value) { 398 check("putProviderProperty."+name); 399 if (debug != null) { 400 debug.println("Set " + name + " provider property [" + 401 key + "/" + value +"]"); 402 } 403 return implPutIfAbsent(key, value); 404 } 405 406 /** 407 * Removes the {@code key} property (and its corresponding 408 * {@code value}). 409 * 410 * <p>If a security manager is enabled, its {@code checkSecurityAccess} 411 * method is called with the string {@code "removeProviderProperty."+name}, 412 * where {@code name} is the provider name, to see if it's ok to remove this 413 * provider's properties. 414 * 415 * @throws SecurityException 416 * if a security manager exists and its {@link 417 * java.lang.SecurityManager#checkSecurityAccess} method 418 * denies access to remove this provider's properties. 419 * 420 * @since 1.2 421 */ 422 @Override 423 public synchronized Object remove(Object key) { 424 check("removeProviderProperty."+name); 425 if (debug != null) { 426 debug.println("Remove " + name + " provider property " + key); 427 } 428 return implRemove(key); 429 } 430 431 /** 432 * Removes the entry for the specified key only if it is currently 433 * mapped to the specified value. 434 * 435 * <p>If a security manager is enabled, its {@code checkSecurityAccess} 436 * method is called with the string {@code "removeProviderProperty."+name}, 437 * where {@code name} is the provider name, to see if it's ok to remove this 438 * provider's properties. 439 * 440 * @throws SecurityException 441 * if a security manager exists and its {@link 442 * java.lang.SecurityManager#checkSecurityAccess} method 443 * denies access to remove this provider's properties. 444 * 445 * @since 1.8 446 */ 447 @Override 448 public synchronized boolean remove(Object key, Object value) { 449 check("removeProviderProperty."+name); 450 if (debug != null) { 451 debug.println("Remove " + name + " provider property " + key); 452 } 453 return implRemove(key, value); 454 } 455 456 /** 457 * Replaces the entry for the specified key only if currently 458 * mapped to the specified value. 459 * 460 * <p>If a security manager is enabled, its {@code checkSecurityAccess} 461 * method is called with the string {@code "putProviderProperty."+name}, 462 * where {@code name} is the provider name, to see if it's ok to set this 463 * provider's property values. 464 * 465 * @throws SecurityException 466 * if a security manager exists and its {@link 467 * java.lang.SecurityManager#checkSecurityAccess} method 468 * denies access to set property values. 469 * 470 * @since 1.8 471 */ 472 @Override 473 public synchronized boolean replace(Object key, Object oldValue, 474 Object newValue) { 475 check("putProviderProperty." + name); 476 477 if (debug != null) { 478 debug.println("Replace " + name + " provider property " + key); 479 } 480 return implReplace(key, oldValue, newValue); 481 } 482 483 /** 484 * Replaces the entry for the specified key only if it is 485 * currently mapped to some value. 486 * 487 * <p>If a security manager is enabled, its {@code checkSecurityAccess} 488 * method is called with the string {@code "putProviderProperty."+name}, 489 * where {@code name} is the provider name, to see if it's ok to set this 490 * provider's property values. 491 * 492 * @throws SecurityException 493 * if a security manager exists and its {@link 494 * java.lang.SecurityManager#checkSecurityAccess} method 495 * denies access to set property values. 496 * 497 * @since 1.8 498 */ 499 @Override 500 public synchronized Object replace(Object key, Object value) { 501 check("putProviderProperty." + name); 502 503 if (debug != null) { 504 debug.println("Replace " + name + " provider property " + key); 505 } 506 return implReplace(key, value); 507 } 508 509 /** 510 * Replaces each entry's value with the result of invoking the given 511 * function on that entry, in the order entries are returned by an entry 512 * set iterator, until all entries have been processed or the function 513 * throws an exception. 514 * 515 * <p>If a security manager is enabled, its {@code checkSecurityAccess} 516 * method is called with the string {@code "putProviderProperty."+name}, 517 * where {@code name} is the provider name, to see if it's ok to set this 518 * provider's property values. 519 * 520 * @throws SecurityException 521 * if a security manager exists and its {@link 522 * java.lang.SecurityManager#checkSecurityAccess} method 523 * denies access to set property values. 524 * 525 * @since 1.8 526 */ 527 @Override 528 public synchronized void replaceAll(BiFunction<? super Object, ? super Object, ? extends Object> function) { 529 check("putProviderProperty." + name); 530 531 if (debug != null) { 532 debug.println("ReplaceAll " + name + " provider property "); 533 } 534 implReplaceAll(function); 535 } 536 537 /** 538 * Attempts to compute a mapping for the specified key and its 539 * current mapped value (or {@code null} if there is no current 540 * mapping). 541 * 542 * <p>If a security manager is enabled, its {@code checkSecurityAccess} 543 * method is called with the strings {@code "putProviderProperty."+name} 544 * and {@code "removeProviderProperty."+name}, where {@code name} is the 545 * provider name, to see if it's ok to set this provider's property values 546 * and remove this provider's properties. 547 * 548 * @throws SecurityException 549 * if a security manager exists and its {@link 550 * java.lang.SecurityManager#checkSecurityAccess} method 551 * denies access to set property values or remove properties. 552 * 553 * @since 1.8 554 */ 555 @Override 556 public synchronized Object compute(Object key, 557 BiFunction<? super Object, ? super Object, ? extends Object> remappingFunction) { 558 check("putProviderProperty." + name); 559 check("removeProviderProperty" + name); 560 561 if (debug != null) { 562 debug.println("Compute " + name + " provider property " + key); 563 } 564 return implCompute(key, remappingFunction); 565 } 566 567 /** 568 * If the specified key is not already associated with a value (or 569 * is mapped to {@code null}), attempts to compute its value using 570 * the given mapping function and enters it into this map unless 571 * {@code null}. 572 * 573 * <p>If a security manager is enabled, its {@code checkSecurityAccess} 574 * method is called with the strings {@code "putProviderProperty."+name} 575 * and {@code "removeProviderProperty."+name}, where {@code name} is the 576 * provider name, to see if it's ok to set this provider's property values 577 * and remove this provider's properties. 578 * 579 * @throws SecurityException 580 * if a security manager exists and its {@link 581 * java.lang.SecurityManager#checkSecurityAccess} method 582 * denies access to set property values and remove properties. 583 * 584 * @since 1.8 585 */ 586 @Override 587 public synchronized Object computeIfAbsent(Object key, Function<? super Object, ? extends Object> mappingFunction) { 588 check("putProviderProperty." + name); 589 check("removeProviderProperty" + name); 590 591 if (debug != null) { 592 debug.println("ComputeIfAbsent " + name + " provider property " + 593 key); 594 } 595 return implComputeIfAbsent(key, mappingFunction); 596 } 597 598 /** 599 * If the value for the specified key is present and non-null, attempts to 600 * compute a new mapping given the key and its current mapped value. 601 * 602 * <p>If a security manager is enabled, its {@code checkSecurityAccess} 603 * method is called with the strings {@code "putProviderProperty."+name} 604 * and {@code "removeProviderProperty."+name}, where {@code name} is the 605 * provider name, to see if it's ok to set this provider's property values 606 * and remove this provider's properties. 607 * 608 * @throws SecurityException 609 * if a security manager exists and its {@link 610 * java.lang.SecurityManager#checkSecurityAccess} method 611 * denies access to set property values or remove properties. 612 * 613 * @since 1.8 614 */ 615 @Override 616 public synchronized Object computeIfPresent(Object key, BiFunction<? super Object, ? super Object, ? extends Object> remappingFunction) { 617 check("putProviderProperty." + name); 618 check("removeProviderProperty" + name); 619 620 if (debug != null) { 621 debug.println("ComputeIfPresent " + name + " provider property " + 622 key); 623 } 624 return implComputeIfPresent(key, remappingFunction); 625 } 626 627 /** 628 * If the specified key is not already associated with a value or is 629 * associated with null, associates it with the given value. Otherwise, 630 * replaces the value with the results of the given remapping function, 631 * or removes if the result is null. This method may be of use when 632 * combining multiple mapped values for a key. 633 * 634 * <p>If a security manager is enabled, its {@code checkSecurityAccess} 635 * method is called with the strings {@code "putProviderProperty."+name} 636 * and {@code "removeProviderProperty."+name}, where {@code name} is the 637 * provider name, to see if it's ok to set this provider's property values 638 * and remove this provider's properties. 639 * 640 * @throws SecurityException 641 * if a security manager exists and its {@link 642 * java.lang.SecurityManager#checkSecurityAccess} method 643 * denies access to set property values or remove properties. 644 * 645 * @since 1.8 646 */ 647 @Override 648 public synchronized Object merge(Object key, Object value, BiFunction<? super Object, ? super Object, ? extends Object> remappingFunction) { 649 check("putProviderProperty." + name); 650 check("removeProviderProperty" + name); 651 652 if (debug != null) { 653 debug.println("Merge " + name + " provider property " + key); 654 } 655 return implMerge(key, value, remappingFunction); 656 } 657 658 // let javadoc show doc from superclass 659 @Override 660 public Object get(Object key) { 661 checkInitialized(); 662 return super.get(key); 663 } 664 /** 665 * @since 1.8 666 */ 667 @Override 668 public synchronized Object getOrDefault(Object key, Object defaultValue) { 669 checkInitialized(); 670 return super.getOrDefault(key, defaultValue); 671 } 672 673 /** 674 * @since 1.8 675 */ 676 @Override 677 public synchronized void forEach(BiConsumer<? super Object, ? super Object> action) { 678 checkInitialized(); 679 super.forEach(action); 680 } 681 682 // let javadoc show doc from superclass 683 @Override 684 public Enumeration<Object> keys() { 685 checkInitialized(); 686 return super.keys(); 687 } 688 689 // let javadoc show doc from superclass 690 @Override 691 public Enumeration<Object> elements() { 692 checkInitialized(); 693 return super.elements(); 694 } 695 696 // let javadoc show doc from superclass 697 public String getProperty(String key) { 698 checkInitialized(); 699 return super.getProperty(key); 700 } 701 702 private void checkInitialized() { 703 if (!initialized) { 704 throw new IllegalStateException(); 705 } 706 } 707 708 private void check(String directive) { 709 checkInitialized(); 710 SecurityManager security = System.getSecurityManager(); 711 if (security != null) { 712 security.checkSecurityAccess(directive); 713 } 714 } 715 716 // legacy properties changed since last call to any services method? 717 private transient boolean legacyChanged; 718 // serviceMap changed since last call to getServices() 719 private transient boolean servicesChanged; 720 721 // Map<String,String> 722 private transient Map<String,String> legacyStrings; 723 724 // Map<ServiceKey,Service> 725 // used for services added via putService(), initialized on demand 726 private transient Map<ServiceKey,Service> serviceMap; 727 728 // Map<ServiceKey,Service> 729 // used for services added via legacy methods, init on demand 730 private transient Map<ServiceKey,Service> legacyMap; 731 732 // Set<Service> 733 // Unmodifiable set of all services. Initialized on demand. 734 private transient Set<Service> serviceSet; 735 736 // register the id attributes for this provider 737 // this is to ensure that equals() and hashCode() do not incorrectly 738 // report to different provider objects as the same 739 private void putId() { 740 // note: name and info may be null 741 super.put("Provider.id name", String.valueOf(name)); 742 super.put("Provider.id version", String.valueOf(version)); 743 super.put("Provider.id info", String.valueOf(info)); 744 super.put("Provider.id className", this.getClass().getName()); 745 } 746 747 private void readObject(ObjectInputStream in) 748 throws IOException, ClassNotFoundException { 749 Map<Object,Object> copy = new HashMap<>(); 750 for (Map.Entry<Object,Object> entry : super.entrySet()) { 751 copy.put(entry.getKey(), entry.getValue()); 752 } 753 defaults = null; 754 in.defaultReadObject(); 755 implClear(); 756 initialized = true; 757 putAll(copy); 758 } 759 760 private boolean checkLegacy(Object key) { 761 String keyString = (String)key; 762 if (keyString.startsWith("Provider.")) { 763 return false; 764 } 765 766 legacyChanged = true; 767 if (legacyStrings == null) { 768 legacyStrings = new LinkedHashMap<>(); 769 } 770 return true; 771 } 772 773 /** 774 * Copies all of the mappings from the specified Map to this provider. 775 * Internal method to be called AFTER the security check has been 776 * performed. 777 */ 778 private void implPutAll(Map<?,?> t) { 779 for (Map.Entry<?,?> e : t.entrySet()) { 780 implPut(e.getKey(), e.getValue()); 781 } 782 } 783 784 private Object implRemove(Object key) { 785 if (key instanceof String) { 786 if (!checkLegacy(key)) { 787 return null; 788 } 789 legacyStrings.remove((String)key); 790 } 791 return super.remove(key); 792 } 793 794 private boolean implRemove(Object key, Object value) { 795 if (key instanceof String && value instanceof String) { 796 if (!checkLegacy(key)) { 797 return false; 798 } 799 legacyStrings.remove((String)key, value); 800 } 801 return super.remove(key, value); 802 } 803 804 private boolean implReplace(Object key, Object oldValue, Object newValue) { 805 if ((key instanceof String) && (oldValue instanceof String) && 806 (newValue instanceof String)) { 807 if (!checkLegacy(key)) { 808 return false; 809 } 810 legacyStrings.replace((String)key, (String)oldValue, 811 (String)newValue); 812 } 813 return super.replace(key, oldValue, newValue); 814 } 815 816 private Object implReplace(Object key, Object value) { 817 if ((key instanceof String) && (value instanceof String)) { 818 if (!checkLegacy(key)) { 819 return null; 820 } 821 legacyStrings.replace((String)key, (String)value); 822 } 823 return super.replace(key, value); 824 } 825 826 @SuppressWarnings("unchecked") // Function must actually operate over strings 827 private void implReplaceAll(BiFunction<? super Object, ? super Object, ? extends Object> function) { 828 legacyChanged = true; 829 if (legacyStrings == null) { 830 legacyStrings = new LinkedHashMap<>(); 831 } else { 832 legacyStrings.replaceAll((BiFunction<? super String, ? super String, ? extends String>) function); 833 } 834 super.replaceAll(function); 835 } 836 837 @SuppressWarnings("unchecked") // Function must actually operate over strings 838 private Object implMerge(Object key, Object value, BiFunction<? super Object, ? super Object, ? extends Object> remappingFunction) { 839 if ((key instanceof String) && (value instanceof String)) { 840 if (!checkLegacy(key)) { 841 return null; 842 } 843 legacyStrings.merge((String)key, (String)value, 844 (BiFunction<? super String, ? super String, ? extends String>) remappingFunction); 845 } 846 return super.merge(key, value, remappingFunction); 847 } 848 849 @SuppressWarnings("unchecked") // Function must actually operate over strings 850 private Object implCompute(Object key, BiFunction<? super Object, ? super Object, ? extends Object> remappingFunction) { 851 if (key instanceof String) { 852 if (!checkLegacy(key)) { 853 return null; 854 } 855 legacyStrings.computeIfAbsent((String) key, 856 (Function<? super String, ? extends String>) remappingFunction); 857 } 858 return super.compute(key, remappingFunction); 859 } 860 861 @SuppressWarnings("unchecked") // Function must actually operate over strings 862 private Object implComputeIfAbsent(Object key, Function<? super Object, ? extends Object> mappingFunction) { 863 if (key instanceof String) { 864 if (!checkLegacy(key)) { 865 return null; 866 } 867 legacyStrings.computeIfAbsent((String) key, 868 (Function<? super String, ? extends String>) mappingFunction); 869 } 870 return super.computeIfAbsent(key, mappingFunction); 871 } 872 873 @SuppressWarnings("unchecked") // Function must actually operate over strings 874 private Object implComputeIfPresent(Object key, BiFunction<? super Object, ? super Object, ? extends Object> remappingFunction) { 875 if (key instanceof String) { 876 if (!checkLegacy(key)) { 877 return null; 878 } 879 legacyStrings.computeIfPresent((String) key, 880 (BiFunction<? super String, ? super String, ? extends String>) remappingFunction); 881 } 882 return super.computeIfPresent(key, remappingFunction); 883 } 884 885 private Object implPut(Object key, Object value) { 886 if ((key instanceof String) && (value instanceof String)) { 887 if (!checkLegacy(key)) { 888 return null; 889 } 890 legacyStrings.put((String)key, (String)value); 891 } 892 return super.put(key, value); 893 } 894 895 private Object implPutIfAbsent(Object key, Object value) { 896 if ((key instanceof String) && (value instanceof String)) { 897 if (!checkLegacy(key)) { 898 return null; 899 } 900 legacyStrings.putIfAbsent((String)key, (String)value); 901 } 902 return super.putIfAbsent(key, value); 903 } 904 905 private void implClear() { 906 if (legacyStrings != null) { 907 legacyStrings.clear(); 908 } 909 if (legacyMap != null) { 910 legacyMap.clear(); 911 } 912 if (serviceMap != null) { 913 serviceMap.clear(); 914 } 915 legacyChanged = false; 916 servicesChanged = false; 917 serviceSet = null; 918 super.clear(); 919 putId(); 920 } 921 922 // used as key in the serviceMap and legacyMap HashMaps 923 private static class ServiceKey { 924 private final String type; 925 private final String algorithm; 926 private final String originalAlgorithm; 927 private ServiceKey(String type, String algorithm, boolean intern) { 928 this.type = type; 929 this.originalAlgorithm = algorithm; 930 algorithm = algorithm.toUpperCase(ENGLISH); 931 this.algorithm = intern ? algorithm.intern() : algorithm; 932 } 933 public int hashCode() { 934 return type.hashCode() + algorithm.hashCode(); 935 } 936 public boolean equals(Object obj) { 937 if (this == obj) { 938 return true; 939 } 940 if (obj instanceof ServiceKey == false) { 941 return false; 942 } 943 ServiceKey other = (ServiceKey)obj; 944 return this.type.equals(other.type) 945 && this.algorithm.equals(other.algorithm); 946 } 947 boolean matches(String type, String algorithm) { 948 return (this.type == type) && (this.originalAlgorithm == algorithm); 949 } 950 } 951 952 /** 953 * Ensure all the legacy String properties are fully parsed into 954 * service objects. 955 */ 956 private void ensureLegacyParsed() { 957 if ((legacyChanged == false) || (legacyStrings == null)) { 958 return; 959 } 960 serviceSet = null; 961 if (legacyMap == null) { 962 legacyMap = new LinkedHashMap<>(); 963 } else { 964 legacyMap.clear(); 965 } 966 for (Map.Entry<String,String> entry : legacyStrings.entrySet()) { 967 parseLegacyPut(entry.getKey(), entry.getValue()); 968 } 969 removeInvalidServices(legacyMap); 970 legacyChanged = false; 971 } 972 973 /** 974 * Remove all invalid services from the Map. Invalid services can only 975 * occur if the legacy properties are inconsistent or incomplete. 976 */ 977 private void removeInvalidServices(Map<ServiceKey,Service> map) { 978 for (Iterator<Map.Entry<ServiceKey, Service>> t = 979 map.entrySet().iterator(); t.hasNext(); ) { 980 Service s = t.next().getValue(); 981 if (s.isValid() == false) { 982 t.remove(); 983 } 984 } 985 } 986 987 private String[] getTypeAndAlgorithm(String key) { 988 int i = key.indexOf('.'); 989 if (i < 1) { 990 if (debug != null) { 991 debug.println("Ignoring invalid entry in provider " 992 + name + ":" + key); 993 } 994 return null; 995 } 996 String type = key.substring(0, i); 997 String alg = key.substring(i + 1); 998 return new String[] {type, alg}; 999 } 1000 1001 private final static String ALIAS_PREFIX = "Alg.Alias."; 1002 private final static String ALIAS_PREFIX_LOWER = "alg.alias."; 1003 private final static int ALIAS_LENGTH = ALIAS_PREFIX.length(); 1004 1005 private void parseLegacyPut(String name, String value) { 1006 if (name.toLowerCase(ENGLISH).startsWith(ALIAS_PREFIX_LOWER)) { 1007 // e.g. put("Alg.Alias.MessageDigest.SHA", "SHA-1"); 1008 // aliasKey ~ MessageDigest.SHA 1009 String stdAlg = value; 1010 String aliasKey = name.substring(ALIAS_LENGTH); 1011 String[] typeAndAlg = getTypeAndAlgorithm(aliasKey); 1012 if (typeAndAlg == null) { 1013 return; 1014 } 1015 String type = getEngineName(typeAndAlg[0]); 1016 String aliasAlg = typeAndAlg[1].intern(); 1017 ServiceKey key = new ServiceKey(type, stdAlg, true); 1018 Service s = legacyMap.get(key); 1019 if (s == null) { 1020 s = new Service(this); 1021 s.type = type; 1022 s.algorithm = stdAlg; 1023 legacyMap.put(key, s); 1024 } 1025 legacyMap.put(new ServiceKey(type, aliasAlg, true), s); 1026 s.addAlias(aliasAlg); 1027 } else { 1028 String[] typeAndAlg = getTypeAndAlgorithm(name); 1029 if (typeAndAlg == null) { 1030 return; 1031 } 1032 int i = typeAndAlg[1].indexOf(' '); 1033 if (i == -1) { 1034 // e.g. put("MessageDigest.SHA-1", "sun.security.provider.SHA"); 1035 String type = getEngineName(typeAndAlg[0]); 1036 String stdAlg = typeAndAlg[1].intern(); 1037 String className = value; 1038 ServiceKey key = new ServiceKey(type, stdAlg, true); 1039 Service s = legacyMap.get(key); 1040 if (s == null) { 1041 s = new Service(this); 1042 s.type = type; 1043 s.algorithm = stdAlg; 1044 legacyMap.put(key, s); 1045 } 1046 s.className = className; 1047 } else { // attribute 1048 // e.g. put("MessageDigest.SHA-1 ImplementedIn", "Software"); 1049 String attributeValue = value; 1050 String type = getEngineName(typeAndAlg[0]); 1051 String attributeString = typeAndAlg[1]; 1052 String stdAlg = attributeString.substring(0, i).intern(); 1053 String attributeName = attributeString.substring(i + 1); 1054 // kill additional spaces 1055 while (attributeName.startsWith(" ")) { 1056 attributeName = attributeName.substring(1); 1057 } 1058 attributeName = attributeName.intern(); 1059 ServiceKey key = new ServiceKey(type, stdAlg, true); 1060 Service s = legacyMap.get(key); 1061 if (s == null) { 1062 s = new Service(this); 1063 s.type = type; 1064 s.algorithm = stdAlg; 1065 legacyMap.put(key, s); 1066 } 1067 s.addAttribute(attributeName, attributeValue); 1068 } 1069 } 1070 } 1071 1072 /** 1073 * Get the service describing this Provider's implementation of the 1074 * specified type of this algorithm or alias. If no such 1075 * implementation exists, this method returns null. If there are two 1076 * matching services, one added to this provider using 1077 * {@link #putService putService()} and one added via {@link #put put()}, 1078 * the service added via {@link #putService putService()} is returned. 1079 * 1080 * @param type the type of {@link Service service} requested 1081 * (for example, {@code MessageDigest}) 1082 * @param algorithm the case insensitive algorithm name (or alternate 1083 * alias) of the service requested (for example, {@code SHA-1}) 1084 * 1085 * @return the service describing this Provider's matching service 1086 * or null if no such service exists 1087 * 1088 * @throws NullPointerException if type or algorithm is null 1089 * 1090 * @since 1.5 1091 */ 1092 public synchronized Service getService(String type, String algorithm) { 1093 checkInitialized(); 1094 // avoid allocating a new key object if possible 1095 ServiceKey key = previousKey; 1096 if (key.matches(type, algorithm) == false) { 1097 key = new ServiceKey(type, algorithm, false); 1098 previousKey = key; 1099 } 1100 if (serviceMap != null) { 1101 Service service = serviceMap.get(key); 1102 if (service != null) { 1103 return service; 1104 } 1105 } 1106 ensureLegacyParsed(); 1107 return (legacyMap != null) ? legacyMap.get(key) : null; 1108 } 1109 1110 // ServiceKey from previous getService() call 1111 // by re-using it if possible we avoid allocating a new object 1112 // and the toUpperCase() call. 1113 // re-use will occur e.g. as the framework traverses the provider 1114 // list and queries each provider with the same values until it finds 1115 // a matching service 1116 private static volatile ServiceKey previousKey = 1117 new ServiceKey("", "", false); 1118 1119 /** 1120 * Get an unmodifiable Set of all services supported by 1121 * this Provider. 1122 * 1123 * @return an unmodifiable Set of all services supported by 1124 * this Provider 1125 * 1126 * @since 1.5 1127 */ 1128 public synchronized Set<Service> getServices() { 1129 checkInitialized(); 1130 if (legacyChanged || servicesChanged) { 1131 serviceSet = null; 1132 } 1133 if (serviceSet == null) { 1134 ensureLegacyParsed(); 1135 Set<Service> set = new LinkedHashSet<>(); 1136 if (serviceMap != null) { 1137 set.addAll(serviceMap.values()); 1138 } 1139 if (legacyMap != null) { 1140 set.addAll(legacyMap.values()); 1141 } 1142 serviceSet = Collections.unmodifiableSet(set); 1143 servicesChanged = false; 1144 } 1145 return serviceSet; 1146 } 1147 1148 /** 1149 * Add a service. If a service of the same type with the same algorithm 1150 * name exists and it was added using {@link #putService putService()}, 1151 * it is replaced by the new service. 1152 * This method also places information about this service 1153 * in the provider's Hashtable values in the format described in the 1154 * <a href="../../../technotes/guides/security/crypto/CryptoSpec.html"> 1155 * Java Cryptography Architecture API Specification & Reference </a>. 1156 * 1157 * <p>Also, if there is a security manager, its 1158 * {@code checkSecurityAccess} method is called with the string 1159 * {@code "putProviderProperty."+name}, where {@code name} is 1160 * the provider name, to see if it's ok to set this provider's property 1161 * values. If the default implementation of {@code checkSecurityAccess} 1162 * is used (that is, that method is not overriden), then this results in 1163 * a call to the security manager's {@code checkPermission} method with 1164 * a {@code SecurityPermission("putProviderProperty."+name)} 1165 * permission. 1166 * 1167 * @param s the Service to add 1168 * 1169 * @throws SecurityException 1170 * if a security manager exists and its {@link 1171 * java.lang.SecurityManager#checkSecurityAccess} method denies 1172 * access to set property values. 1173 * @throws NullPointerException if s is null 1174 * 1175 * @since 1.5 1176 */ 1177 protected synchronized void putService(Service s) { 1178 check("putProviderProperty." + name); 1179 if (debug != null) { 1180 debug.println(name + ".putService(): " + s); 1181 } 1182 if (s == null) { 1183 throw new NullPointerException(); 1184 } 1185 if (s.getProvider() != this) { 1186 throw new IllegalArgumentException 1187 ("service.getProvider() must match this Provider object"); 1188 } 1189 if (serviceMap == null) { 1190 serviceMap = new LinkedHashMap<>(); 1191 } 1192 servicesChanged = true; 1193 String type = s.getType(); 1194 String algorithm = s.getAlgorithm(); 1195 ServiceKey key = new ServiceKey(type, algorithm, true); 1196 // remove existing service 1197 implRemoveService(serviceMap.get(key)); 1198 serviceMap.put(key, s); 1199 for (String alias : s.getAliases()) { 1200 serviceMap.put(new ServiceKey(type, alias, true), s); 1201 } 1202 putPropertyStrings(s); 1203 } 1204 1205 /** 1206 * Put the string properties for this Service in this Provider's 1207 * Hashtable. 1208 */ 1209 private void putPropertyStrings(Service s) { 1210 String type = s.getType(); 1211 String algorithm = s.getAlgorithm(); 1212 // use super() to avoid permission check and other processing 1213 super.put(type + "." + algorithm, s.getClassName()); 1214 for (String alias : s.getAliases()) { 1215 super.put(ALIAS_PREFIX + type + "." + alias, algorithm); 1216 } 1217 for (Map.Entry<UString,String> entry : s.attributes.entrySet()) { 1218 String key = type + "." + algorithm + " " + entry.getKey(); 1219 super.put(key, entry.getValue()); 1220 } 1221 } 1222 1223 /** 1224 * Remove the string properties for this Service from this Provider's 1225 * Hashtable. 1226 */ 1227 private void removePropertyStrings(Service s) { 1228 String type = s.getType(); 1229 String algorithm = s.getAlgorithm(); 1230 // use super() to avoid permission check and other processing 1231 super.remove(type + "." + algorithm); 1232 for (String alias : s.getAliases()) { 1233 super.remove(ALIAS_PREFIX + type + "." + alias); 1234 } 1235 for (Map.Entry<UString,String> entry : s.attributes.entrySet()) { 1236 String key = type + "." + algorithm + " " + entry.getKey(); 1237 super.remove(key); 1238 } 1239 } 1240 1241 /** 1242 * Remove a service previously added using 1243 * {@link #putService putService()}. The specified service is removed from 1244 * this provider. It will no longer be returned by 1245 * {@link #getService getService()} and its information will be removed 1246 * from this provider's Hashtable. 1247 * 1248 * <p>Also, if there is a security manager, its 1249 * {@code checkSecurityAccess} method is called with the string 1250 * {@code "removeProviderProperty."+name}, where {@code name} is 1251 * the provider name, to see if it's ok to remove this provider's 1252 * properties. If the default implementation of 1253 * {@code checkSecurityAccess} is used (that is, that method is not 1254 * overriden), then this results in a call to the security manager's 1255 * {@code checkPermission} method with a 1256 * {@code SecurityPermission("removeProviderProperty."+name)} 1257 * permission. 1258 * 1259 * @param s the Service to be removed 1260 * 1261 * @throws SecurityException 1262 * if a security manager exists and its {@link 1263 * java.lang.SecurityManager#checkSecurityAccess} method denies 1264 * access to remove this provider's properties. 1265 * @throws NullPointerException if s is null 1266 * 1267 * @since 1.5 1268 */ 1269 protected synchronized void removeService(Service s) { 1270 check("removeProviderProperty." + name); 1271 if (debug != null) { 1272 debug.println(name + ".removeService(): " + s); 1273 } 1274 if (s == null) { 1275 throw new NullPointerException(); 1276 } 1277 implRemoveService(s); 1278 } 1279 1280 private void implRemoveService(Service s) { 1281 if ((s == null) || (serviceMap == null)) { 1282 return; 1283 } 1284 String type = s.getType(); 1285 String algorithm = s.getAlgorithm(); 1286 ServiceKey key = new ServiceKey(type, algorithm, false); 1287 Service oldService = serviceMap.get(key); 1288 if (s != oldService) { 1289 return; 1290 } 1291 servicesChanged = true; 1292 serviceMap.remove(key); 1293 for (String alias : s.getAliases()) { 1294 serviceMap.remove(new ServiceKey(type, alias, false)); 1295 } 1296 removePropertyStrings(s); 1297 } 1298 1299 // Wrapped String that behaves in a case insensitive way for equals/hashCode 1300 private static class UString { 1301 final String string; 1302 final String lowerString; 1303 1304 UString(String s) { 1305 this.string = s; 1306 this.lowerString = s.toLowerCase(ENGLISH); 1307 } 1308 1309 public int hashCode() { 1310 return lowerString.hashCode(); 1311 } 1312 1313 public boolean equals(Object obj) { 1314 if (this == obj) { 1315 return true; 1316 } 1317 if (obj instanceof UString == false) { 1318 return false; 1319 } 1320 UString other = (UString)obj; 1321 return lowerString.equals(other.lowerString); 1322 } 1323 1324 public String toString() { 1325 return string; 1326 } 1327 } 1328 1329 // describe relevant properties of a type of engine 1330 private static class EngineDescription { 1331 final String name; 1332 final boolean supportsParameter; 1333 final String constructorParameterClassName; 1334 private volatile Class<?> constructorParameterClass; 1335 1336 EngineDescription(String name, boolean sp, String paramName) { 1337 this.name = name; 1338 this.supportsParameter = sp; 1339 this.constructorParameterClassName = paramName; 1340 } 1341 Class<?> getConstructorParameterClass() throws ClassNotFoundException { 1342 Class<?> clazz = constructorParameterClass; 1343 if (clazz == null) { 1344 clazz = Class.forName(constructorParameterClassName); 1345 constructorParameterClass = clazz; 1346 } 1347 return clazz; 1348 } 1349 } 1350 1351 // built in knowledge of the engine types shipped as part of the JDK 1352 private static final Map<String,EngineDescription> knownEngines; 1353 1354 private static void addEngine(String name, boolean sp, String paramName) { 1355 EngineDescription ed = new EngineDescription(name, sp, paramName); 1356 // also index by canonical name to avoid toLowerCase() for some lookups 1357 knownEngines.put(name.toLowerCase(ENGLISH), ed); 1358 knownEngines.put(name, ed); 1359 } 1360 1361 static { 1362 knownEngines = new HashMap<>(); 1363 // JCA 1364 addEngine("AlgorithmParameterGenerator", false, null); 1365 addEngine("AlgorithmParameters", false, null); 1366 addEngine("KeyFactory", false, null); 1367 addEngine("KeyPairGenerator", false, null); 1368 addEngine("KeyStore", false, null); 1369 addEngine("MessageDigest", false, null); 1370 addEngine("SecureRandom", false, null); 1371 addEngine("Signature", true, null); 1372 addEngine("CertificateFactory", false, null); 1373 addEngine("CertPathBuilder", false, null); 1374 addEngine("CertPathValidator", false, null); 1375 addEngine("CertStore", false, 1376 "java.security.cert.CertStoreParameters"); 1377 // JCE 1378 addEngine("Cipher", true, null); 1379 addEngine("ExemptionMechanism", false, null); 1380 addEngine("Mac", true, null); 1381 addEngine("KeyAgreement", true, null); 1382 addEngine("KeyGenerator", false, null); 1383 addEngine("SecretKeyFactory", false, null); 1384 // JSSE 1385 addEngine("KeyManagerFactory", false, null); 1386 addEngine("SSLContext", false, null); 1387 addEngine("TrustManagerFactory", false, null); 1388 // JGSS 1389 addEngine("GssApiMechanism", false, null); 1390 // SASL 1391 addEngine("SaslClientFactory", false, null); 1392 addEngine("SaslServerFactory", false, null); 1393 // POLICY 1394 addEngine("Policy", false, 1395 "java.security.Policy$Parameters"); 1396 // CONFIGURATION 1397 addEngine("Configuration", false, 1398 "javax.security.auth.login.Configuration$Parameters"); 1399 // XML DSig 1400 addEngine("XMLSignatureFactory", false, null); 1401 addEngine("KeyInfoFactory", false, null); 1402 addEngine("TransformService", false, null); 1403 // Smart Card I/O 1404 addEngine("TerminalFactory", false, 1405 "java.lang.Object"); 1406 } 1407 1408 // get the "standard" (mixed-case) engine name for arbitary case engine name 1409 // if there is no known engine by that name, return s 1410 private static String getEngineName(String s) { 1411 // try original case first, usually correct 1412 EngineDescription e = knownEngines.get(s); 1413 if (e == null) { 1414 e = knownEngines.get(s.toLowerCase(ENGLISH)); 1415 } 1416 return (e == null) ? s : e.name; 1417 } 1418 1419 /** 1420 * The description of a security service. It encapsulates the properties 1421 * of a service and contains a factory method to obtain new implementation 1422 * instances of this service. 1423 * 1424 * <p>Each service has a provider that offers the service, a type, 1425 * an algorithm name, and the name of the class that implements the 1426 * service. Optionally, it also includes a list of alternate algorithm 1427 * names for this service (aliases) and attributes, which are a map of 1428 * (name, value) String pairs. 1429 * 1430 * <p>This class defines the methods {@link #supportsParameter 1431 * supportsParameter()} and {@link #newInstance newInstance()} 1432 * which are used by the Java security framework when it searches for 1433 * suitable services and instantiates them. The valid arguments to those 1434 * methods depend on the type of service. For the service types defined 1435 * within Java SE, see the 1436 * <a href="../../../technotes/guides/security/crypto/CryptoSpec.html"> 1437 * Java Cryptography Architecture API Specification & Reference </a> 1438 * for the valid values. 1439 * Note that components outside of Java SE can define additional types of 1440 * services and their behavior. 1441 * 1442 * <p>Instances of this class are immutable. 1443 * 1444 * @since 1.5 1445 */ 1446 public static class Service { 1447 1448 private String type, algorithm, className; 1449 private final Provider provider; 1450 private List<String> aliases; 1451 private Map<UString,String> attributes; 1452 1453 // Reference to the cached implementation Class object 1454 private volatile Reference<Class<?>> classRef; 1455 1456 // flag indicating whether this service has its attributes for 1457 // supportedKeyFormats or supportedKeyClasses set 1458 // if null, the values have not been initialized 1459 // if TRUE, at least one of supportedFormats/Classes is non null 1460 private volatile Boolean hasKeyAttributes; 1461 1462 // supported encoding formats 1463 private String[] supportedFormats; 1464 1465 // names of the supported key (super) classes 1466 private Class<?>[] supportedClasses; 1467 1468 // whether this service has been registered with the Provider 1469 private boolean registered; 1470 1471 private static final Class<?>[] CLASS0 = new Class<?>[0]; 1472 1473 // this constructor and these methods are used for parsing 1474 // the legacy string properties. 1475 1476 private Service(Provider provider) { 1477 this.provider = provider; 1478 aliases = Collections.<String>emptyList(); 1479 attributes = Collections.<UString,String>emptyMap(); 1480 } 1481 1482 private boolean isValid() { 1483 return (type != null) && (algorithm != null) && (className != null); 1484 } 1485 1486 private void addAlias(String alias) { 1487 if (aliases.isEmpty()) { 1488 aliases = new ArrayList<>(2); 1489 } 1490 aliases.add(alias); 1491 } 1492 1493 void addAttribute(String type, String value) { 1494 if (attributes.isEmpty()) { 1495 attributes = new HashMap<>(8); 1496 } 1497 attributes.put(new UString(type), value); 1498 } 1499 1500 /** 1501 * Construct a new service. 1502 * 1503 * @param provider the provider that offers this service 1504 * @param type the type of this service 1505 * @param algorithm the algorithm name 1506 * @param className the name of the class implementing this service 1507 * @param aliases List of aliases or null if algorithm has no aliases 1508 * @param attributes Map of attributes or null if this implementation 1509 * has no attributes 1510 * 1511 * @throws NullPointerException if provider, type, algorithm, or 1512 * className is null 1513 */ 1514 public Service(Provider provider, String type, String algorithm, 1515 String className, List<String> aliases, 1516 Map<String,String> attributes) { 1517 if ((provider == null) || (type == null) || 1518 (algorithm == null) || (className == null)) { 1519 throw new NullPointerException(); 1520 } 1521 this.provider = provider; 1522 this.type = getEngineName(type); 1523 this.algorithm = algorithm; 1524 this.className = className; 1525 if (aliases == null) { 1526 this.aliases = Collections.<String>emptyList(); 1527 } else { 1528 this.aliases = new ArrayList<>(aliases); 1529 } 1530 if (attributes == null) { 1531 this.attributes = Collections.<UString,String>emptyMap(); 1532 } else { 1533 this.attributes = new HashMap<>(); 1534 for (Map.Entry<String,String> entry : attributes.entrySet()) { 1535 this.attributes.put(new UString(entry.getKey()), entry.getValue()); 1536 } 1537 } 1538 } 1539 1540 /** 1541 * Get the type of this service. For example, {@code MessageDigest}. 1542 * 1543 * @return the type of this service 1544 */ 1545 public final String getType() { 1546 return type; 1547 } 1548 1549 /** 1550 * Return the name of the algorithm of this service. For example, 1551 * {@code SHA-1}. 1552 * 1553 * @return the algorithm of this service 1554 */ 1555 public final String getAlgorithm() { 1556 return algorithm; 1557 } 1558 1559 /** 1560 * Return the Provider of this service. 1561 * 1562 * @return the Provider of this service 1563 */ 1564 public final Provider getProvider() { 1565 return provider; 1566 } 1567 1568 /** 1569 * Return the name of the class implementing this service. 1570 * 1571 * @return the name of the class implementing this service 1572 */ 1573 public final String getClassName() { 1574 return className; 1575 } 1576 1577 // internal only 1578 private final List<String> getAliases() { 1579 return aliases; 1580 } 1581 1582 /** 1583 * Return the value of the specified attribute or null if this 1584 * attribute is not set for this Service. 1585 * 1586 * @param name the name of the requested attribute 1587 * 1588 * @return the value of the specified attribute or null if the 1589 * attribute is not present 1590 * 1591 * @throws NullPointerException if name is null 1592 */ 1593 public final String getAttribute(String name) { 1594 if (name == null) { 1595 throw new NullPointerException(); 1596 } 1597 return attributes.get(new UString(name)); 1598 } 1599 1600 /** 1601 * Return a new instance of the implementation described by this 1602 * service. The security provider framework uses this method to 1603 * construct implementations. Applications will typically not need 1604 * to call it. 1605 * 1606 * <p>The default implementation uses reflection to invoke the 1607 * standard constructor for this type of service. 1608 * Security providers can override this method to implement 1609 * instantiation in a different way. 1610 * For details and the values of constructorParameter that are 1611 * valid for the various types of services see the 1612 * <a href="../../../technotes/guides/security/crypto/CryptoSpec.html"> 1613 * Java Cryptography Architecture API Specification & 1614 * Reference</a>. 1615 * 1616 * @param constructorParameter the value to pass to the constructor, 1617 * or null if this type of service does not use a constructorParameter. 1618 * 1619 * @return a new implementation of this service 1620 * 1621 * @throws InvalidParameterException if the value of 1622 * constructorParameter is invalid for this type of service. 1623 * @throws NoSuchAlgorithmException if instantiation failed for 1624 * any other reason. 1625 */ 1626 public Object newInstance(Object constructorParameter) 1627 throws NoSuchAlgorithmException { 1628 if (registered == false) { 1629 if (provider.getService(type, algorithm) != this) { 1630 throw new NoSuchAlgorithmException 1631 ("Service not registered with Provider " 1632 + provider.getName() + ": " + this); 1633 } 1634 registered = true; 1635 } 1636 Class<?> ctrParamClz; 1637 try { 1638 EngineDescription cap = knownEngines.get(type); 1639 if (cap == null) { 1640 // unknown engine type, use generic code 1641 // this is the code path future for non-core 1642 // optional packages 1643 ctrParamClz = constructorParameter == null? 1644 null : constructorParameter.getClass(); 1645 } else { 1646 ctrParamClz = cap.constructorParameterClassName == null? 1647 null : Class.forName(cap.constructorParameterClassName); 1648 if (constructorParameter != null) { 1649 if (ctrParamClz == null) { 1650 throw new InvalidParameterException 1651 ("constructorParameter not used with " + type 1652 + " engines"); 1653 } else { 1654 Class<?> argClass = constructorParameter.getClass(); 1655 if (ctrParamClz.isAssignableFrom(argClass) == false) { 1656 throw new InvalidParameterException 1657 ("constructorParameter must be instanceof " 1658 + cap.constructorParameterClassName.replace('$', '.') 1659 + " for engine type " + type); 1660 } 1661 } 1662 } 1663 } 1664 return newInstanceUtil(getImplClass(), ctrParamClz, constructorParameter); 1665 } catch (NoSuchAlgorithmException e) { 1666 throw e; 1667 } catch (InvocationTargetException e) { 1668 throw new NoSuchAlgorithmException 1669 ("Error constructing implementation (algorithm: " 1670 + algorithm + ", provider: " + provider.getName() 1671 + ", class: " + className + ")", e.getCause()); 1672 } catch (Exception e) { 1673 throw new NoSuchAlgorithmException 1674 ("Error constructing implementation (algorithm: " 1675 + algorithm + ", provider: " + provider.getName() 1676 + ", class: " + className + ")", e); 1677 } 1678 } 1679 1680 // return the implementation Class object for this service 1681 private Class<?> getImplClass() throws NoSuchAlgorithmException { 1682 try { 1683 Reference<Class<?>> ref = classRef; 1684 Class<?> clazz = (ref == null) ? null : ref.get(); 1685 if (clazz == null) { 1686 ClassLoader cl = provider.getClass().getClassLoader(); 1687 if (cl == null) { 1688 clazz = Class.forName(className); 1689 } else { 1690 clazz = cl.loadClass(className); 1691 } 1692 if (!Modifier.isPublic(clazz.getModifiers())) { 1693 throw new NoSuchAlgorithmException 1694 ("class configured for " + type + " (provider: " + 1695 provider.getName() + ") is not public."); 1696 } 1697 classRef = new WeakReference<>(clazz); 1698 } 1699 return clazz; 1700 } catch (ClassNotFoundException e) { 1701 throw new NoSuchAlgorithmException 1702 ("class configured for " + type + " (provider: " + 1703 provider.getName() + ") cannot be found.", e); 1704 } 1705 } 1706 1707 /** 1708 * Test whether this Service can use the specified parameter. 1709 * Returns false if this service cannot use the parameter. Returns 1710 * true if this service can use the parameter, if a fast test is 1711 * infeasible, or if the status is unknown. 1712 * 1713 * <p>The security provider framework uses this method with 1714 * some types of services to quickly exclude non-matching 1715 * implementations for consideration. 1716 * Applications will typically not need to call it. 1717 * 1718 * <p>For details and the values of parameter that are valid for the 1719 * various types of services see the top of this class and the 1720 * <a href="../../../technotes/guides/security/crypto/CryptoSpec.html"> 1721 * Java Cryptography Architecture API Specification & 1722 * Reference</a>. 1723 * Security providers can override it to implement their own test. 1724 * 1725 * @param parameter the parameter to test 1726 * 1727 * @return false if this service cannot use the specified 1728 * parameter; true if it can possibly use the parameter 1729 * 1730 * @throws InvalidParameterException if the value of parameter is 1731 * invalid for this type of service or if this method cannot be 1732 * used with this type of service 1733 */ 1734 public boolean supportsParameter(Object parameter) { 1735 EngineDescription cap = knownEngines.get(type); 1736 if (cap == null) { 1737 // unknown engine type, return true by default 1738 return true; 1739 } 1740 if (cap.supportsParameter == false) { 1741 throw new InvalidParameterException("supportsParameter() not " 1742 + "used with " + type + " engines"); 1743 } 1744 // allow null for keys without attributes for compatibility 1745 if ((parameter != null) && (parameter instanceof Key == false)) { 1746 throw new InvalidParameterException 1747 ("Parameter must be instanceof Key for engine " + type); 1748 } 1749 if (hasKeyAttributes() == false) { 1750 return true; 1751 } 1752 if (parameter == null) { 1753 return false; 1754 } 1755 Key key = (Key)parameter; 1756 if (supportsKeyFormat(key)) { 1757 return true; 1758 } 1759 if (supportsKeyClass(key)) { 1760 return true; 1761 } 1762 return false; 1763 } 1764 1765 /** 1766 * Return whether this service has its Supported* properties for 1767 * keys defined. Parses the attributes if not yet initialized. 1768 */ 1769 private boolean hasKeyAttributes() { 1770 Boolean b = hasKeyAttributes; 1771 if (b == null) { 1772 synchronized (this) { 1773 String s; 1774 s = getAttribute("SupportedKeyFormats"); 1775 if (s != null) { 1776 supportedFormats = s.split("\\|"); 1777 } 1778 s = getAttribute("SupportedKeyClasses"); 1779 if (s != null) { 1780 String[] classNames = s.split("\\|"); 1781 List<Class<?>> classList = 1782 new ArrayList<>(classNames.length); 1783 for (String className : classNames) { 1784 Class<?> clazz = getKeyClass(className); 1785 if (clazz != null) { 1786 classList.add(clazz); 1787 } 1788 } 1789 supportedClasses = classList.toArray(CLASS0); 1790 } 1791 boolean bool = (supportedFormats != null) 1792 || (supportedClasses != null); 1793 b = Boolean.valueOf(bool); 1794 hasKeyAttributes = b; 1795 } 1796 } 1797 return b.booleanValue(); 1798 } 1799 1800 // get the key class object of the specified name 1801 private Class<?> getKeyClass(String name) { 1802 try { 1803 return Class.forName(name); 1804 } catch (ClassNotFoundException e) { 1805 // ignore 1806 } 1807 try { 1808 ClassLoader cl = provider.getClass().getClassLoader(); 1809 if (cl != null) { 1810 return cl.loadClass(name); 1811 } 1812 } catch (ClassNotFoundException e) { 1813 // ignore 1814 } 1815 return null; 1816 } 1817 1818 private boolean supportsKeyFormat(Key key) { 1819 if (supportedFormats == null) { 1820 return false; 1821 } 1822 String format = key.getFormat(); 1823 if (format == null) { 1824 return false; 1825 } 1826 for (String supportedFormat : supportedFormats) { 1827 if (supportedFormat.equals(format)) { 1828 return true; 1829 } 1830 } 1831 return false; 1832 } 1833 1834 private boolean supportsKeyClass(Key key) { 1835 if (supportedClasses == null) { 1836 return false; 1837 } 1838 Class<?> keyClass = key.getClass(); 1839 for (Class<?> clazz : supportedClasses) { 1840 if (clazz.isAssignableFrom(keyClass)) { 1841 return true; 1842 } 1843 } 1844 return false; 1845 } 1846 1847 /** 1848 * Return a String representation of this service. 1849 * 1850 * @return a String representation of this service. 1851 */ 1852 public String toString() { 1853 String aString = aliases.isEmpty() 1854 ? "" : "\r\n aliases: " + aliases.toString(); 1855 String attrs = attributes.isEmpty() 1856 ? "" : "\r\n attributes: " + attributes.toString(); 1857 return provider.getName() + ": " + type + "." + algorithm 1858 + " -> " + className + aString + attrs + "\r\n"; 1859 } 1860 1861 } 1862 1863} 1864