| /* | |
| * Copyright (c) 2003, 2024, Oracle and/or its affiliates. All rights reserved. | |
| * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. | |
| * | |
| * This code is free software; you can redistribute it and/or modify it | |
| * under the terms of the GNU General Public License version 2 only, as | |
| * published by the Free Software Foundation. Oracle designates this | |
| * particular file as subject to the "Classpath" exception as provided | |
| * by Oracle in the LICENSE file that accompanied this code. | |
| * | |
| * This code is distributed in the hope that it will be useful, but WITHOUT | |
| * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or | |
| * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License | |
| * version 2 for more details (a copy is included in the LICENSE file that | |
| * accompanied this code). | |
| * | |
| * You should have received a copy of the GNU General Public License version | |
| * 2 along with this work; if not, write to the Free Software Foundation, | |
| * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. | |
| * | |
| * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA | |
| * or visit www.oracle.com if you need additional information or have any | |
| * questions. | |
| */ | |
| package sun.security.jca; | |
| import java.util.*; | |
| import java.security.*; | |
| import java.security.Provider.Service; | |
| /** | |
| * Collection of utility methods to facilitate implementing getInstance() | |
| * methods in the JCA/JCE/JSSE/... framework. | |
| * | |
| * @author Andreas Sterbenz | |
| * @since 1.5 | |
| */ | |
| public class GetInstance { | |
| private GetInstance() { | |
| // empty | |
| } | |
| /** | |
| * Static inner class representing a newly created instance. | |
| */ | |
| public static final class Instance { | |
| // public final fields, access directly without accessors | |
| public final Provider provider; | |
| public final Object impl; | |
| private Instance(Provider provider, Object impl) { | |
| this.provider = provider; | |
| this.impl = impl; | |
| } | |
| // Return Provider and implementation as an array as used in the | |
| // old Security.getImpl() methods. | |
| public Object[] toArray() { | |
| return new Object[] {impl, provider}; | |
| } | |
| } | |
| public static Service getService(String type, String algorithm) | |
| throws NoSuchAlgorithmException { | |
| ProviderList list = Providers.getProviderList(); | |
| Service s = list.getService(type, algorithm); | |
| if (s == null) { | |
| throw new NoSuchAlgorithmException | |
| (algorithm + " " + type + " not available"); | |
| } | |
| return s; | |
| } | |
| public static Service getService(String type, String algorithm, | |
| String provider) throws NoSuchAlgorithmException, | |
| NoSuchProviderException { | |
| if (provider == null || provider.isEmpty()) { | |
| throw new IllegalArgumentException("missing provider"); | |
| } | |
| Provider p = Providers.getProviderList().getProvider(provider); | |
| if (p == null) { | |
| throw new NoSuchProviderException("no such provider: " + provider); | |
| } | |
| Service s = p.getService(type, algorithm); | |
| if (s == null) { | |
| throw new NoSuchAlgorithmException("no such algorithm: " | |
| + algorithm + " for provider " + provider); | |
| } | |
| return s; | |
| } | |
| public static Service getService(String type, String algorithm, | |
| Provider provider) throws NoSuchAlgorithmException { | |
| if (provider == null) { | |
| throw new IllegalArgumentException("missing provider"); | |
| } | |
| Service s = provider.getService(type, algorithm); | |
| if (s == null) { | |
| throw new NoSuchAlgorithmException("no such algorithm: " | |
| + algorithm + " for provider " + provider.getName()); | |
| } | |
| return s; | |
| } | |
| /** | |
| * Return an iterator over all the available Services that implement | |
| * (type, algorithm). Note that the iterator is initialized lazily | |
| * and Provider loading and lookup is only triggered when | |
| * necessary. | |
| */ | |
| public static Iterator<Service> getServices(String type, String algorithm) { | |
| ProviderList list = Providers.getProviderList(); | |
| return list.getServices(type, algorithm); | |
| } | |
| /** | |
| * Return an iterator over all the available Services that implement any of | |
| * the specified algorithms. See getServices(String, String) for details. | |
| */ | |
| public static Iterator<Service> getServices(List<ServiceId> ids) { | |
| ProviderList list = Providers.getProviderList(); | |
| return list.getServices(ids); | |
| } | |
| /* | |
| * For all the getInstance() methods below: | |
| * @param type the type of engine (e.g. MessageDigest) | |
| * @param clazz the Spi class that the implementation must subclass | |
| * (e.g. MessageDigestSpi.class) or null if no superclass check | |
| * is required | |
| * @param algorithm the name of the algorithm (or alias), e.g. MD5 | |
| * @param provider the provider (String or Provider object) | |
| * @param param the parameter to pass to the Spi constructor | |
| * (for CertStores) | |
| * | |
| * There are overloaded methods for all the permutations. | |
| */ | |
| public static Instance getInstance(String type, Class<?> clazz, | |
| String algorithm) throws NoSuchAlgorithmException { | |
| // in the almost all cases, the first service will work | |
| // avoid taking long path if so | |
| ProviderList list = Providers.getProviderList(); | |
| Service firstService = list.getService(type, algorithm); | |
| if (firstService == null) { | |
| throw new NoSuchAlgorithmException | |
| (algorithm + " " + type + " not available"); | |
| } | |
| NoSuchAlgorithmException failure; | |
| try { | |
| return getInstance(firstService, clazz); | |
| } catch (NoSuchAlgorithmException e) { | |
| failure = e; | |
| } | |
| // if we cannot get the service from the preferred provider, | |
| // fail over to the next | |
| Iterator<Service> services = list.getServices(type, algorithm); | |
| while (services.hasNext()) { | |
| Service s = services.next(); | |
| if (s == firstService) { | |
| // do not retry initial failed service | |
| continue; | |
| } | |
| try { | |
| return getInstance(s, clazz); | |
| } catch (NoSuchAlgorithmException e) { | |
| failure = e; | |
| } | |
| } | |
| throw failure; | |
| } | |
| public static Instance getInstance(String type, Class<?> clazz, | |
| String algorithm, Object param) throws NoSuchAlgorithmException { | |
| Iterator<Service> services = getServices(type, algorithm); | |
| NoSuchAlgorithmException failure = null; | |
| while (services.hasNext()) { | |
| Service s = services.next(); | |
| try { | |
| return getInstance(s, clazz, param); | |
| } catch (NoSuchAlgorithmException e) { | |
| failure = e; | |
| } | |
| } | |
| if (failure != null) { | |
| throw failure; | |
| } else { | |
| throw new NoSuchAlgorithmException | |
| (algorithm + " " + type + " not available"); | |
| } | |
| } | |
| public static Instance getInstance(String type, Class<?> clazz, | |
| String algorithm, String provider) throws NoSuchAlgorithmException, | |
| NoSuchProviderException { | |
| return getInstance(getService(type, algorithm, provider), clazz); | |
| } | |
| public static Instance getInstance(String type, Class<?> clazz, | |
| String algorithm, Object param, String provider) | |
| throws NoSuchAlgorithmException, NoSuchProviderException { | |
| return getInstance(getService(type, algorithm, provider), clazz, param); | |
| } | |
| public static Instance getInstance(String type, Class<?> clazz, | |
| String algorithm, Provider provider) | |
| throws NoSuchAlgorithmException { | |
| return getInstance(getService(type, algorithm, provider), clazz); | |
| } | |
| public static Instance getInstance(String type, Class<?> clazz, | |
| String algorithm, Object param, Provider provider) | |
| throws NoSuchAlgorithmException { | |
| return getInstance(getService(type, algorithm, provider), clazz, param); | |
| } | |
| /* | |
| * The two getInstance() methods below take a service. They are | |
| * intended for classes that cannot use the standard methods, e.g. | |
| * because they implement delayed provider selection like the | |
| * Signature class. | |
| */ | |
| public static Instance getInstance(Service s, Class<?> clazz) | |
| throws NoSuchAlgorithmException { | |
| Object instance = s.newInstance(null); | |
| checkSuperClass(s, instance.getClass(), clazz); | |
| return new Instance(s.getProvider(), instance); | |
| } | |
| public static Instance getInstance(Service s, Class<?> clazz, | |
| Object param) throws NoSuchAlgorithmException { | |
| Object instance = s.newInstance(param); | |
| checkSuperClass(s, instance.getClass(), clazz); | |
| return new Instance(s.getProvider(), instance); | |
| } | |
| /** | |
| * Check is subClass is a subclass of superClass. If not, | |
| * throw a NoSuchAlgorithmException. | |
| */ | |
| public static void checkSuperClass(Service s, Class<?> subClass, | |
| Class<?> superClass) throws NoSuchAlgorithmException { | |
| if (superClass == null) { | |
| return; | |
| } | |
| if (!superClass.isAssignableFrom(subClass)) { | |
| throw new NoSuchAlgorithmException | |
| ("class configured for " + s.getType() + ": " | |
| + s.getClassName() + " not a " + s.getType()); | |
| } | |
| } | |
| } |