| /* Engine -- generic getInstance method. | |
| Copyright (C) 2003, 2006 Free Software Foundation, Inc. | |
| This file is part of GNU Classpath. | |
| GNU Classpath is free software; you can redistribute it and/or modify | |
| it under the terms of the GNU General Public License as published by | |
| the Free Software Foundation; either version 2, or (at your option) | |
| any later version. | |
| GNU Classpath 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 for more details. | |
| You should have received a copy of the GNU General Public License | |
| along with GNU Classpath; see the file COPYING. If not, write to the | |
| Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA | |
| 02110-1301 USA. | |
| Linking this library statically or dynamically with other modules is | |
| making a combined work based on this library. Thus, the terms and | |
| conditions of the GNU General Public License cover the whole | |
| combination. | |
| As a special exception, the copyright holders of this library give you | |
| permission to link this library with independent modules to produce an | |
| executable, regardless of the license terms of these independent | |
| modules, and to copy and distribute the resulting executable under | |
| terms of your choice, provided that you also meet, for each linked | |
| independent module, the terms and conditions of the license of that | |
| module. An independent module is a module which is not derived from | |
| or based on this library. If you modify this library, you may extend | |
| this exception to your version of the library, but you are not | |
| obligated to do so. If you do not wish to do so, delete this | |
| exception statement from your version. */ | |
| package gnu.java.security; | |
| import java.lang.reflect.Constructor; | |
| import java.lang.reflect.InvocationTargetException; | |
| import java.security.NoSuchAlgorithmException; | |
| import java.security.Provider; | |
| import java.util.Enumeration; | |
| /** | |
| * Generic implementation of the getInstance methods in the various | |
| * engine classes in java.security. | |
| * <p> | |
| * These classes ({@link java.security.Signature} for example) can be | |
| * thought of as the "chrome, upholstery, and steering wheel", and the SPI | |
| * (service provider interface, e.g. {@link java.security.SignatureSpi}) | |
| * classes can be thought of as the "engine" -- providing the actual | |
| * functionality of whatever cryptographic algorithm the instance | |
| * represents. | |
| * | |
| * @see Provider | |
| * @author Casey Marshall | |
| */ | |
| public final class Engine | |
| { | |
| // Constants. | |
| // ------------------------------------------------------------------------ | |
| /** Prefix for aliases. */ | |
| private static final String ALG_ALIAS = "Alg.Alias."; | |
| /** Maximum number of aliases to try. */ | |
| private static final int MAX_ALIASES = 5; | |
| /** Argument list for no-argument constructors. */ | |
| private static final Object[] NO_ARGS = new Object[0]; | |
| // Constructor. | |
| // ------------------------------------------------------------------------ | |
| /** This class cannot be instantiated. */ | |
| private Engine() { } | |
| // Class method. | |
| // ------------------------------------------------------------------------ | |
| /** | |
| * Get the implementation for <i>algorithm</i> for service | |
| * <i>service</i> from <i>provider</i>. The service is e.g. | |
| * "Signature", and the algorithm "DSA". | |
| * | |
| * @param service The service name. | |
| * @param algorithm The name of the algorithm to get. | |
| * @param provider The provider to get the implementation from. | |
| * @return The engine class for the specified algorithm; the object | |
| * returned is typically a subclass of the SPI class for that | |
| * service, but callers should check that this is so. | |
| * @throws NoSuchAlgorithmException If the implementation cannot be | |
| * found or cannot be instantiated. | |
| * @throws InvocationTargetException If the SPI class's constructor | |
| * throws an exception. | |
| * @throws IllegalArgumentException If any of the three arguments are null. | |
| */ | |
| public static Object getInstance(String service, String algorithm, | |
| Provider provider) | |
| throws InvocationTargetException, NoSuchAlgorithmException | |
| { | |
| return getInstance(service, algorithm, provider, NO_ARGS); | |
| } | |
| /** | |
| * Get the implementation for <i>algorithm</i> for service | |
| * <i>service</i> from <i>provider</i>, passing <i>initArgs</i> to the | |
| * SPI class's constructor (which cannot be null; pass a zero-length | |
| * array if the SPI takes no arguments). The service is e.g. | |
| * "Signature", and the algorithm "DSA". | |
| * | |
| * @param service The service name. | |
| * @param algorithm The name of the algorithm to get. | |
| * @param provider The provider to get the implementation from. | |
| * @param initArgs The arguments to pass to the SPI class's | |
| * constructor (cannot be null). | |
| * @return The engine class for the specified algorithm; the object | |
| * returned is typically a subclass of the SPI class for that | |
| * service, but callers should check that this is so. | |
| * @throws NoSuchAlgorithmException If the implementation cannot be | |
| * found or cannot be instantiated. | |
| * @throws InvocationTargetException If the SPI class's constructor | |
| * throws an exception. | |
| * @throws IllegalArgumentException If any of the four arguments are null. | |
| */ | |
| public static Object getInstance(String service, String algorithm, | |
| Provider provider, Object[] initArgs) | |
| throws InvocationTargetException, NoSuchAlgorithmException | |
| { | |
| if (service != null) | |
| service = service.trim(); | |
| if (algorithm != null) | |
| algorithm = algorithm.trim(); | |
| if (service == null || service.length() == 0 | |
| || algorithm == null || algorithm.length() == 0 | |
| || provider == null || initArgs == null) | |
| throw new IllegalArgumentException(); | |
| Enumeration enumer = provider.propertyNames(); | |
| String key; | |
| String alias; | |
| int count = 0; | |
| boolean algorithmFound = false; | |
| while (enumer.hasMoreElements()) | |
| { | |
| key = (String) enumer.nextElement(); | |
| if (key.equalsIgnoreCase(service + "." + algorithm)) | |
| { | |
| // remove the service portion from the key | |
| algorithm = key.substring(service.length() + 1); | |
| algorithmFound = true; | |
| break; | |
| } | |
| else if (key.equalsIgnoreCase(ALG_ALIAS + service + "." + algorithm)) | |
| { | |
| alias = (String) provider.getProperty(key); | |
| if (! algorithm.equalsIgnoreCase(alias)) // does not refer to itself | |
| { | |
| algorithm = alias; | |
| if (count++ > MAX_ALIASES) | |
| throw new NoSuchAlgorithmException("too many aliases"); | |
| // need to reset enumeration to now look for the alias | |
| enumer = provider.propertyNames(); | |
| } | |
| } | |
| } | |
| if (! algorithmFound) | |
| { | |
| throw new NoSuchAlgorithmException(algorithm); | |
| } | |
| // Find and instantiate the implementation. | |
| Class clazz = null; | |
| ClassLoader loader = provider.getClass().getClassLoader(); | |
| Constructor constructor = null; | |
| String error = algorithm; | |
| try | |
| { | |
| if (loader != null) | |
| clazz = loader.loadClass(provider.getProperty(service+"."+algorithm)); | |
| else | |
| clazz = Class.forName(provider.getProperty(service+"."+algorithm)); | |
| constructor = getCompatibleConstructor(clazz, initArgs); | |
| return constructor.newInstance(initArgs); | |
| } | |
| catch (ClassNotFoundException cnfe) | |
| { | |
| error = "class not found: " + algorithm; | |
| } | |
| catch (IllegalAccessException iae) | |
| { | |
| error = "illegal access: " + iae.getMessage(); | |
| } | |
| catch (InstantiationException ie) | |
| { | |
| error = "instantiation exception: " + ie.getMessage(); | |
| } | |
| catch (ExceptionInInitializerError eiie) | |
| { | |
| error = "exception in initializer: " + eiie.getMessage(); | |
| } | |
| catch (SecurityException se) | |
| { | |
| error = "security exception: " + se.getMessage(); | |
| } | |
| catch (NoSuchMethodException nsme) | |
| { | |
| error = "no appropriate constructor found"; | |
| } | |
| throw new NoSuchAlgorithmException(error); | |
| } | |
| // Own methods. | |
| // ------------------------------------------------------------------------ | |
| /** | |
| * Find a constructor in the given class that can take the specified | |
| * argument list, allowing any of which to be null. | |
| * | |
| * @param clazz The class from which to get the constructor. | |
| * @param initArgs The argument list to be passed to the constructor. | |
| * @return The constructor. | |
| * @throws NoSuchMethodException If no constructor of the given class | |
| * can take the specified argument array. | |
| */ | |
| private static Constructor getCompatibleConstructor(Class clazz, | |
| Object[] initArgs) | |
| throws NoSuchMethodException | |
| { | |
| Constructor[] c = clazz.getConstructors(); | |
| outer:for (int i = 0; i < c.length; i++) | |
| { | |
| Class[] argTypes = c[i].getParameterTypes(); | |
| if (argTypes.length != initArgs.length) | |
| continue; | |
| for (int j = 0; j < argTypes.length; j++) | |
| { | |
| if (initArgs[j] != null && | |
| !argTypes[j].isAssignableFrom(initArgs[j].getClass())) | |
| continue outer; | |
| } | |
| // If we reach this point, we know this constructor (c[i]) has | |
| // the same number of parameters as the target parameter list, | |
| // and all our parameters are either (1) null, or (2) assignable | |
| // to the target parameter type. | |
| return c[i]; | |
| } | |
| throw new NoSuchMethodException(); | |
| } | |
| } |