mirror of git://gcc.gnu.org/git/gcc.git
				
				
				
			
		
			
				
	
	
		
			283 lines
		
	
	
		
			11 KiB
		
	
	
	
		
			Java
		
	
	
	
			
		
		
	
	
			283 lines
		
	
	
		
			11 KiB
		
	
	
	
		
			Java
		
	
	
	
/* 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 gnu.java.lang.CPStringBuilder;
 | 
						|
 | 
						|
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() { }
 | 
						|
 | 
						|
  /**
 | 
						|
   * Return 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 is null.
 | 
						|
   */
 | 
						|
  public static Object getInstance(String service, String algorithm,
 | 
						|
                                   Provider provider)
 | 
						|
      throws InvocationTargetException, NoSuchAlgorithmException
 | 
						|
  {
 | 
						|
    return getInstance(service, algorithm, provider, NO_ARGS);
 | 
						|
  }
 | 
						|
 | 
						|
  /**
 | 
						|
   * Return 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 is
 | 
						|
   *           <code>null</code> or if either <code>service</code>, or
 | 
						|
   *           <code>algorithm</code> is an empty string.
 | 
						|
   */
 | 
						|
  public static Object getInstance(String service, String algorithm,
 | 
						|
                                   Provider provider, Object[] initArgs)
 | 
						|
      throws InvocationTargetException, NoSuchAlgorithmException
 | 
						|
  {
 | 
						|
    if (service == null)
 | 
						|
      throw new IllegalArgumentException("service MUST NOT be null");
 | 
						|
    service = service.trim();
 | 
						|
    if (service.length() == 0)
 | 
						|
      throw new IllegalArgumentException("service MUST NOT be empty");
 | 
						|
    if (algorithm == null)
 | 
						|
      throw new IllegalArgumentException("algorithm MUST NOT be null");
 | 
						|
    algorithm = algorithm.trim();
 | 
						|
    if (algorithm.length() == 0)
 | 
						|
      throw new IllegalArgumentException("algorithm MUST NOT be empty");
 | 
						|
    if (provider == null)
 | 
						|
      throw new IllegalArgumentException("provider MUST NOT be null");
 | 
						|
    if (initArgs == null)
 | 
						|
      throw new IllegalArgumentException("Constructor's parameters MUST NOT be null");
 | 
						|
 | 
						|
    Enumeration enumer = provider.propertyNames();
 | 
						|
    String key = null;
 | 
						|
    String alias;
 | 
						|
    int count = 0;
 | 
						|
    boolean algorithmFound = false;
 | 
						|
    CPStringBuilder sb = new CPStringBuilder();
 | 
						|
    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 = provider.getProperty(key);
 | 
						|
            if (! algorithm.equalsIgnoreCase(alias)) // does not refer to itself
 | 
						|
              {
 | 
						|
                algorithm = alias;
 | 
						|
                if (count++ > MAX_ALIASES)
 | 
						|
                  {
 | 
						|
                    sb.append("Algorithm [").append(algorithm)
 | 
						|
                        .append("] of type [").append(service)
 | 
						|
                        .append("] from provider [").append(provider)
 | 
						|
                        .append("] has too many aliases");
 | 
						|
                    throw new NoSuchAlgorithmException(sb.toString());
 | 
						|
                  }
 | 
						|
                // need to reset enumeration to now look for the alias
 | 
						|
                enumer = provider.propertyNames();
 | 
						|
              }
 | 
						|
          }
 | 
						|
      }
 | 
						|
 | 
						|
    if (! algorithmFound)
 | 
						|
      {
 | 
						|
        sb.append("Algorithm [").append(algorithm).append("] of type [")
 | 
						|
            .append(service).append("] from provider [")
 | 
						|
            .append(provider).append("] is not found");
 | 
						|
        throw new NoSuchAlgorithmException(sb.toString());
 | 
						|
      }
 | 
						|
 | 
						|
    // Find and instantiate the implementation
 | 
						|
    Class clazz = null;
 | 
						|
    ClassLoader loader = provider.getClass().getClassLoader();
 | 
						|
    Constructor constructor = null;
 | 
						|
    String className = provider.getProperty(key);
 | 
						|
    sb.append("Class [").append(className).append("] for algorithm [")
 | 
						|
        .append(algorithm).append("] of type [").append(service)
 | 
						|
        .append("] from provider [").append(provider).append("] ");
 | 
						|
    Throwable cause = null;
 | 
						|
    try
 | 
						|
      {
 | 
						|
        if (loader != null)
 | 
						|
          clazz = loader.loadClass(className);
 | 
						|
        else
 | 
						|
          clazz = Class.forName(className);
 | 
						|
        constructor = getCompatibleConstructor(clazz, initArgs);
 | 
						|
        return constructor.newInstance(initArgs);
 | 
						|
      }
 | 
						|
    catch (ClassNotFoundException x)
 | 
						|
      {
 | 
						|
        sb.append("cannot not be found");
 | 
						|
        cause = x;
 | 
						|
      }
 | 
						|
    catch (IllegalAccessException x)
 | 
						|
      {
 | 
						|
        sb.append("cannot be accessed");
 | 
						|
        cause = x;
 | 
						|
      }
 | 
						|
    catch (InstantiationException x)
 | 
						|
      {
 | 
						|
        sb.append("cannot be instantiated");
 | 
						|
        cause = x;
 | 
						|
      }
 | 
						|
    catch (ExceptionInInitializerError x)
 | 
						|
      {
 | 
						|
        sb.append("cannot be initialized");
 | 
						|
        cause = x;
 | 
						|
      }
 | 
						|
    catch (SecurityException x)
 | 
						|
      {
 | 
						|
        sb.append("caused a security violation");
 | 
						|
        cause = x;
 | 
						|
      }
 | 
						|
    catch (NoSuchMethodException x)
 | 
						|
      {
 | 
						|
        sb.append("does not have/expose an appropriate constructor");
 | 
						|
        cause = x;
 | 
						|
      }
 | 
						|
 | 
						|
    NoSuchAlgorithmException x = new NoSuchAlgorithmException(sb.toString());
 | 
						|
    x.initCause(cause);
 | 
						|
    throw x;
 | 
						|
  }
 | 
						|
 | 
						|
  /**
 | 
						|
   * 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();
 | 
						|
  }
 | 
						|
}
 |