1adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project/* 2adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project * Licensed to the Apache Software Foundation (ASF) under one or more 3adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project * contributor license agreements. See the NOTICE file distributed with 4adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project * this work for additional information regarding copyright ownership. 5adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project * The ASF licenses this file to You under the Apache License, Version 2.0 6adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project * (the "License"); you may not use this file except in compliance with 7adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project * the License. You may obtain a copy of the License at 8adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project * 9adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project * http://www.apache.org/licenses/LICENSE-2.0 10adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project * 11adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project * Unless required by applicable law or agreed to in writing, software 12adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project * distributed under the License is distributed on an "AS IS" BASIS, 13adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 14adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project * See the License for the specific language governing permissions and 15adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project * limitations under the License. 16adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project */ 17adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project 18adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project/** 19adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project* @author Boris V. Kuznetsov 20adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project* @version $Revision$ 21adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project*/ 22adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project 23adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Projectpackage org.apache.harmony.security.fortress; 24adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project 25adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Projectimport java.security.NoSuchAlgorithmException; 26adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Projectimport java.security.Provider; 27a695e8fafadd2591cd148e78f19bc6d7c15121bbJesse Wilsonimport java.util.Locale; 28adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project 29adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project 30adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project/** 310a480846a9798c763b088a122ab0dcd3dc3a17b6Brian Carlstrom * This class implements common functionality for Provider supplied 320a480846a9798c763b088a122ab0dcd3dc3a17b6Brian Carlstrom * classes. The usage pattern is to allocate static Engine instance 330a480846a9798c763b088a122ab0dcd3dc3a17b6Brian Carlstrom * per service type and synchronize on that instance during calls to 340a480846a9798c763b088a122ab0dcd3dc3a17b6Brian Carlstrom * {@code getInstance} and retreival of the selected {@code Provider} 350a480846a9798c763b088a122ab0dcd3dc3a17b6Brian Carlstrom * and Service Provider Interface (SPI) results. Retreiving the 360a480846a9798c763b088a122ab0dcd3dc3a17b6Brian Carlstrom * results with {@code getProvider} and {@code getSpi} sets the 370a480846a9798c763b088a122ab0dcd3dc3a17b6Brian Carlstrom * internal {@code Engine} values to null to prevent memory leaks. 38f33eae7e84eb6d3b0f4e86b59605bb3de73009f3Elliott Hughes * 390a480846a9798c763b088a122ab0dcd3dc3a17b6Brian Carlstrom * <p> 40f33eae7e84eb6d3b0f4e86b59605bb3de73009f3Elliott Hughes * 410a480846a9798c763b088a122ab0dcd3dc3a17b6Brian Carlstrom * For example: <pre> {@code 420a480846a9798c763b088a122ab0dcd3dc3a17b6Brian Carlstrom * public class Foo { 430a480846a9798c763b088a122ab0dcd3dc3a17b6Brian Carlstrom * 440a480846a9798c763b088a122ab0dcd3dc3a17b6Brian Carlstrom * private static final Engine ENGINE = new Engine("Foo"); 450a480846a9798c763b088a122ab0dcd3dc3a17b6Brian Carlstrom * 460a480846a9798c763b088a122ab0dcd3dc3a17b6Brian Carlstrom * private final FooSpi spi; 470a480846a9798c763b088a122ab0dcd3dc3a17b6Brian Carlstrom * private final Provider provider; 480a480846a9798c763b088a122ab0dcd3dc3a17b6Brian Carlstrom * private final String algorithm; 490a480846a9798c763b088a122ab0dcd3dc3a17b6Brian Carlstrom * 500a480846a9798c763b088a122ab0dcd3dc3a17b6Brian Carlstrom * protected Foo(FooSpi spi, 510a480846a9798c763b088a122ab0dcd3dc3a17b6Brian Carlstrom * Provider provider, 520a480846a9798c763b088a122ab0dcd3dc3a17b6Brian Carlstrom * String algorithm) { 530a480846a9798c763b088a122ab0dcd3dc3a17b6Brian Carlstrom * this.spi = spi; 540a480846a9798c763b088a122ab0dcd3dc3a17b6Brian Carlstrom * this.provider = provider; 550a480846a9798c763b088a122ab0dcd3dc3a17b6Brian Carlstrom * this.algorithm = algorithm; 560a480846a9798c763b088a122ab0dcd3dc3a17b6Brian Carlstrom * } 570a480846a9798c763b088a122ab0dcd3dc3a17b6Brian Carlstrom * 580a480846a9798c763b088a122ab0dcd3dc3a17b6Brian Carlstrom * public static Foo getInstance(String algorithm) { 596cdb6b7e6939270ccd21790ec95e42197cefc0c3Brian Carlstrom * Engine.SpiAndProvider sap = ENGINE.getInstance(algorithm, null); 606cdb6b7e6939270ccd21790ec95e42197cefc0c3Brian Carlstrom * return new Foo((FooSpi) sap.spi, sap.provider, algorithm); 610a480846a9798c763b088a122ab0dcd3dc3a17b6Brian Carlstrom * } 620a480846a9798c763b088a122ab0dcd3dc3a17b6Brian Carlstrom * 630a480846a9798c763b088a122ab0dcd3dc3a17b6Brian Carlstrom * public static Foo getInstance(String algorithm, Provider provider) { 646cdb6b7e6939270ccd21790ec95e42197cefc0c3Brian Carlstrom * Object spi = ENGINE.getInstance(algorithm, provider, null); 656cdb6b7e6939270ccd21790ec95e42197cefc0c3Brian Carlstrom * return new Foo((FooSpi) spi, provider, algorithm); 660a480846a9798c763b088a122ab0dcd3dc3a17b6Brian Carlstrom * } 670a480846a9798c763b088a122ab0dcd3dc3a17b6Brian Carlstrom * 680a480846a9798c763b088a122ab0dcd3dc3a17b6Brian Carlstrom * ... 690a480846a9798c763b088a122ab0dcd3dc3a17b6Brian Carlstrom * 700a480846a9798c763b088a122ab0dcd3dc3a17b6Brian Carlstrom * }</pre> 71adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project */ 72adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Projectpublic class Engine { 73adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project 740a480846a9798c763b088a122ab0dcd3dc3a17b6Brian Carlstrom /** 750a480846a9798c763b088a122ab0dcd3dc3a17b6Brian Carlstrom * Access to package visible api in java.security 760a480846a9798c763b088a122ab0dcd3dc3a17b6Brian Carlstrom */ 770a480846a9798c763b088a122ab0dcd3dc3a17b6Brian Carlstrom public static SecurityAccess door; 780a480846a9798c763b088a122ab0dcd3dc3a17b6Brian Carlstrom 79adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project /** 806cdb6b7e6939270ccd21790ec95e42197cefc0c3Brian Carlstrom * Service name such as Cipher or SSLContext 81adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project */ 826cdb6b7e6939270ccd21790ec95e42197cefc0c3Brian Carlstrom private final String serviceName; 83adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project 84adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project /** 856cdb6b7e6939270ccd21790ec95e42197cefc0c3Brian Carlstrom * Previous result for getInstance(String, Object) optimization. 866cdb6b7e6939270ccd21790ec95e42197cefc0c3Brian Carlstrom * Only this non-Provider version of getInstance is optimized 876cdb6b7e6939270ccd21790ec95e42197cefc0c3Brian Carlstrom * since the the Provider version does not require an expensive 886cdb6b7e6939270ccd21790ec95e42197cefc0c3Brian Carlstrom * Services.getService call. 89adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project */ 906cdb6b7e6939270ccd21790ec95e42197cefc0c3Brian Carlstrom private volatile ServiceCacheEntry serviceCache; 916cdb6b7e6939270ccd21790ec95e42197cefc0c3Brian Carlstrom 926cdb6b7e6939270ccd21790ec95e42197cefc0c3Brian Carlstrom private static final class ServiceCacheEntry { 936cdb6b7e6939270ccd21790ec95e42197cefc0c3Brian Carlstrom /** used to test for cache hit */ 946cdb6b7e6939270ccd21790ec95e42197cefc0c3Brian Carlstrom private final String algorithm; 956cdb6b7e6939270ccd21790ec95e42197cefc0c3Brian Carlstrom /** used to test for cache validity */ 96c7a56c94bdea0e20123ae6fba5eca5b8d984c670Brian Carlstrom private final int cacheVersion; 976cdb6b7e6939270ccd21790ec95e42197cefc0c3Brian Carlstrom /** cached result */ 986cdb6b7e6939270ccd21790ec95e42197cefc0c3Brian Carlstrom private final Provider.Service service; 996cdb6b7e6939270ccd21790ec95e42197cefc0c3Brian Carlstrom 1006cdb6b7e6939270ccd21790ec95e42197cefc0c3Brian Carlstrom private ServiceCacheEntry(String algorithm, 101c7a56c94bdea0e20123ae6fba5eca5b8d984c670Brian Carlstrom int cacheVersion, 1026cdb6b7e6939270ccd21790ec95e42197cefc0c3Brian Carlstrom Provider.Service service) { 1036cdb6b7e6939270ccd21790ec95e42197cefc0c3Brian Carlstrom this.algorithm = algorithm; 104c7a56c94bdea0e20123ae6fba5eca5b8d984c670Brian Carlstrom this.cacheVersion = cacheVersion; 1056cdb6b7e6939270ccd21790ec95e42197cefc0c3Brian Carlstrom this.service = service; 1066cdb6b7e6939270ccd21790ec95e42197cefc0c3Brian Carlstrom } 1076cdb6b7e6939270ccd21790ec95e42197cefc0c3Brian Carlstrom } 1086cdb6b7e6939270ccd21790ec95e42197cefc0c3Brian Carlstrom 1096cdb6b7e6939270ccd21790ec95e42197cefc0c3Brian Carlstrom public static final class SpiAndProvider { 1106cdb6b7e6939270ccd21790ec95e42197cefc0c3Brian Carlstrom public final Object spi; 1116cdb6b7e6939270ccd21790ec95e42197cefc0c3Brian Carlstrom public final Provider provider; 1126cdb6b7e6939270ccd21790ec95e42197cefc0c3Brian Carlstrom private SpiAndProvider(Object spi, Provider provider) { 1136cdb6b7e6939270ccd21790ec95e42197cefc0c3Brian Carlstrom this.spi = spi; 1146cdb6b7e6939270ccd21790ec95e42197cefc0c3Brian Carlstrom this.provider = provider; 1156cdb6b7e6939270ccd21790ec95e42197cefc0c3Brian Carlstrom } 1166cdb6b7e6939270ccd21790ec95e42197cefc0c3Brian Carlstrom } 117adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project 118adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project /** 119adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project * Creates a Engine object 120f33eae7e84eb6d3b0f4e86b59605bb3de73009f3Elliott Hughes * 121adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project * @param service 122adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project */ 123adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project public Engine(String service) { 124adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project this.serviceName = service; 125adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project } 126adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project 127adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project /** 1286cdb6b7e6939270ccd21790ec95e42197cefc0c3Brian Carlstrom * Finds the appropriate service implementation and returns an 1296cdb6b7e6939270ccd21790ec95e42197cefc0c3Brian Carlstrom * {@code SpiAndProvider} instance containing a reference to SPI 1306cdb6b7e6939270ccd21790ec95e42197cefc0c3Brian Carlstrom * and its {@code Provider} 131adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project */ 1326cdb6b7e6939270ccd21790ec95e42197cefc0c3Brian Carlstrom public SpiAndProvider getInstance(String algorithm, Object param) 133adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project throws NoSuchAlgorithmException { 134adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project if (algorithm == null) { 135897538a36c18f4db8f9f68ee566aec0bda842e9fElliott Hughes throw new NoSuchAlgorithmException("Null algorithm name"); 136adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project } 137c7a56c94bdea0e20123ae6fba5eca5b8d984c670Brian Carlstrom int newCacheVersion = Services.getCacheVersion(); 1386cdb6b7e6939270ccd21790ec95e42197cefc0c3Brian Carlstrom Provider.Service service; 1396cdb6b7e6939270ccd21790ec95e42197cefc0c3Brian Carlstrom ServiceCacheEntry cacheEntry = this.serviceCache; 1406cdb6b7e6939270ccd21790ec95e42197cefc0c3Brian Carlstrom if (cacheEntry != null 141a695e8fafadd2591cd148e78f19bc6d7c15121bbJesse Wilson && cacheEntry.algorithm.equalsIgnoreCase(algorithm) 142c7a56c94bdea0e20123ae6fba5eca5b8d984c670Brian Carlstrom && newCacheVersion == cacheEntry.cacheVersion) { 1436cdb6b7e6939270ccd21790ec95e42197cefc0c3Brian Carlstrom service = cacheEntry.service; 144adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project } else { 145adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project if (Services.isEmpty()) { 146897538a36c18f4db8f9f68ee566aec0bda842e9fElliott Hughes throw notFound(serviceName, algorithm); 147adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project } 148a695e8fafadd2591cd148e78f19bc6d7c15121bbJesse Wilson String name = this.serviceName + "." + algorithm.toUpperCase(Locale.US); 1496cdb6b7e6939270ccd21790ec95e42197cefc0c3Brian Carlstrom service = Services.getService(name); 1506cdb6b7e6939270ccd21790ec95e42197cefc0c3Brian Carlstrom if (service == null) { 151897538a36c18f4db8f9f68ee566aec0bda842e9fElliott Hughes throw notFound(serviceName, algorithm); 152adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project } 153c7a56c94bdea0e20123ae6fba5eca5b8d984c670Brian Carlstrom this.serviceCache = new ServiceCacheEntry(algorithm, newCacheVersion, service); 154adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project } 1556cdb6b7e6939270ccd21790ec95e42197cefc0c3Brian Carlstrom return new SpiAndProvider(service.newInstance(param), service.getProvider()); 156897538a36c18f4db8f9f68ee566aec0bda842e9fElliott Hughes } 157897538a36c18f4db8f9f68ee566aec0bda842e9fElliott Hughes 158adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project /** 1596cdb6b7e6939270ccd21790ec95e42197cefc0c3Brian Carlstrom * Finds the appropriate service implementation and returns and 1606cdb6b7e6939270ccd21790ec95e42197cefc0c3Brian Carlstrom * instance of the class that implements corresponding Service 1616cdb6b7e6939270ccd21790ec95e42197cefc0c3Brian Carlstrom * Provider Interface. 162adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project */ 1636cdb6b7e6939270ccd21790ec95e42197cefc0c3Brian Carlstrom public Object getInstance(String algorithm, Provider provider, Object param) 1646cdb6b7e6939270ccd21790ec95e42197cefc0c3Brian Carlstrom throws NoSuchAlgorithmException { 165adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project if (algorithm == null) { 166897538a36c18f4db8f9f68ee566aec0bda842e9fElliott Hughes throw new NoSuchAlgorithmException("algorithm == null"); 167adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project } 1686cdb6b7e6939270ccd21790ec95e42197cefc0c3Brian Carlstrom Provider.Service service = provider.getService(serviceName, algorithm); 1696cdb6b7e6939270ccd21790ec95e42197cefc0c3Brian Carlstrom if (service == null) { 170897538a36c18f4db8f9f68ee566aec0bda842e9fElliott Hughes throw notFound(serviceName, algorithm); 171adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project } 1726cdb6b7e6939270ccd21790ec95e42197cefc0c3Brian Carlstrom return service.newInstance(param); 1730a480846a9798c763b088a122ab0dcd3dc3a17b6Brian Carlstrom } 1740a480846a9798c763b088a122ab0dcd3dc3a17b6Brian Carlstrom 1756cdb6b7e6939270ccd21790ec95e42197cefc0c3Brian Carlstrom private NoSuchAlgorithmException notFound(String serviceName, String algorithm) 1766cdb6b7e6939270ccd21790ec95e42197cefc0c3Brian Carlstrom throws NoSuchAlgorithmException { 1776cdb6b7e6939270ccd21790ec95e42197cefc0c3Brian Carlstrom throw new NoSuchAlgorithmException(serviceName + " " + algorithm 1786cdb6b7e6939270ccd21790ec95e42197cefc0c3Brian Carlstrom + " implementation not found"); 1790a480846a9798c763b088a122ab0dcd3dc3a17b6Brian Carlstrom } 180897538a36c18f4db8f9f68ee566aec0bda842e9fElliott Hughes} 181