• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 /*
2  *  Licensed to the Apache Software Foundation (ASF) under one or more
3  *  contributor license agreements.  See the NOTICE file distributed with
4  *  this work for additional information regarding copyright ownership.
5  *  The ASF licenses this file to You under the Apache License, Version 2.0
6  *  (the "License"); you may not use this file except in compliance with
7  *  the License.  You may obtain a copy of the License at
8  *
9  *     http://www.apache.org/licenses/LICENSE-2.0
10  *
11  *  Unless required by applicable law or agreed to in writing, software
12  *  distributed under the License is distributed on an "AS IS" BASIS,
13  *  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
14  *  See the License for the specific language governing permissions and
15  *  limitations under the License.
16  */
17 
18 /**
19 * @author Boris V. Kuznetsov
20 * @version $Revision$
21 */
22 
23 package org.apache.harmony.security.fortress;
24 
25 import java.security.NoSuchAlgorithmException;
26 import java.security.Provider;
27 import java.util.Locale;
28 
29 
30 /**
31  * This class implements common functionality for Provider supplied
32  * classes. The usage pattern is to allocate static Engine instance
33  * per service type and synchronize on that instance during calls to
34  * {@code getInstance} and retreival of the selected {@code Provider}
35  * and Service Provider Interface (SPI) results. Retreiving the
36  * results with {@code getProvider} and {@code getSpi} sets the
37  * internal {@code Engine} values to null to prevent memory leaks.
38  *
39  * <p>
40  *
41  * For example: <pre>   {@code
42  *   public class Foo {
43  *
44  *       private static final Engine ENGINE = new Engine("Foo");
45  *
46  *       private final FooSpi spi;
47  *       private final Provider provider;
48  *       private final String algorithm;
49  *
50  *       protected Foo(FooSpi spi,
51  *                     Provider provider,
52  *                     String algorithm) {
53  *           this.spi = spi;
54  *           this.provider = provider;
55  *           this.algorithm = algorithm;
56  *       }
57  *
58  *       public static Foo getInstance(String algorithm) {
59  *           Engine.SpiAndProvider sap = ENGINE.getInstance(algorithm, null);
60  *           return new Foo((FooSpi) sap.spi, sap.provider, algorithm);
61  *       }
62  *
63  *       public static Foo getInstance(String algorithm, Provider provider) {
64  *           Object spi = ENGINE.getInstance(algorithm, provider, null);
65  *           return new Foo((FooSpi) spi, provider, algorithm);
66  *       }
67  *
68  *       ...
69  *
70  * }</pre>
71  */
72 public class Engine {
73 
74     /**
75      * Access to package visible api in java.security
76      */
77     public static SecurityAccess door;
78 
79     /**
80      * Service name such as Cipher or SSLContext
81      */
82     private final String serviceName;
83 
84     /**
85      * Previous result for getInstance(String, Object) optimization.
86      * Only this non-Provider version of getInstance is optimized
87      * since the the Provider version does not require an expensive
88      * Services.getService call.
89      */
90     private volatile ServiceCacheEntry serviceCache;
91 
92     private static final class ServiceCacheEntry {
93         /** used to test for cache hit */
94         private final String algorithm;
95         /** used to test for cache validity */
96         private final int cacheVersion;
97         /** cached result */
98         private final Provider.Service service;
99 
ServiceCacheEntry(String algorithm, int cacheVersion, Provider.Service service)100         private ServiceCacheEntry(String algorithm,
101                                   int cacheVersion,
102                                   Provider.Service service) {
103             this.algorithm = algorithm;
104             this.cacheVersion = cacheVersion;
105             this.service = service;
106         }
107     }
108 
109     public static final class SpiAndProvider {
110         public final Object spi;
111         public final Provider provider;
SpiAndProvider(Object spi, Provider provider)112         private SpiAndProvider(Object spi, Provider provider) {
113             this.spi = spi;
114             this.provider = provider;
115         }
116     }
117 
118     /**
119      * Creates a Engine object
120      *
121      * @param service
122      */
Engine(String service)123     public Engine(String service) {
124         this.serviceName = service;
125     }
126 
127     /**
128      * Finds the appropriate service implementation and returns an
129      * {@code SpiAndProvider} instance containing a reference to SPI
130      * and its {@code Provider}
131      */
getInstance(String algorithm, Object param)132     public SpiAndProvider getInstance(String algorithm, Object param)
133             throws NoSuchAlgorithmException {
134         if (algorithm == null) {
135             throw new NoSuchAlgorithmException("Null algorithm name");
136         }
137         int newCacheVersion = Services.getCacheVersion();
138         Provider.Service service;
139         ServiceCacheEntry cacheEntry = this.serviceCache;
140         if (cacheEntry != null
141                 && cacheEntry.algorithm.equalsIgnoreCase(algorithm)
142                 && newCacheVersion == cacheEntry.cacheVersion) {
143             service = cacheEntry.service;
144         } else {
145             if (Services.isEmpty()) {
146                 throw notFound(serviceName, algorithm);
147             }
148             String name = this.serviceName + "." + algorithm.toUpperCase(Locale.US);
149             service = Services.getService(name);
150             if (service == null) {
151                 throw notFound(serviceName, algorithm);
152             }
153             this.serviceCache = new ServiceCacheEntry(algorithm, newCacheVersion, service);
154         }
155         return new SpiAndProvider(service.newInstance(param), service.getProvider());
156     }
157 
158     /**
159      * Finds the appropriate service implementation and returns and
160      * instance of the class that implements corresponding Service
161      * Provider Interface.
162      */
getInstance(String algorithm, Provider provider, Object param)163     public Object getInstance(String algorithm, Provider provider, Object param)
164             throws NoSuchAlgorithmException {
165         if (algorithm == null) {
166             throw new NoSuchAlgorithmException("algorithm == null");
167         }
168         Provider.Service service = provider.getService(serviceName, algorithm);
169         if (service == null) {
170             throw notFound(serviceName, algorithm);
171         }
172         return service.newInstance(param);
173     }
174 
notFound(String serviceName, String algorithm)175     private NoSuchAlgorithmException notFound(String serviceName, String algorithm)
176             throws NoSuchAlgorithmException {
177         throw new NoSuchAlgorithmException(serviceName + " " + algorithm
178                                            + " implementation not found");
179     }
180 }
181