/*
* @(#)Provider.java 1.56 06/10/10
*
* Copyright 1990-2008 Sun Microsystems, Inc. All Rights Reserved.
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER
*
* This program 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.
*
* This program 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 at /legal/license.txt).
*
* 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 Sun Microsystems, Inc., 4150 Network Circle, Santa
* Clara, CA 95054 or visit www.sun.com if you need additional
* information or have any questions.
*
*/
package java.security;
import java.io.*;
import java.util.*;
/**
* This class represents a "provider" for the
* Java Security API, where a provider implements some or all parts of
* Java Security. Services that a provider may implement include:
*
* <ul>
*
* <li>Algorithms (such as DSA, RSA, MD5 or SHA-1).
*
* <li>Key generation, conversion, and management facilities (such as for
* algorithm-specific keys).
*
*</ul>
*
* <p>Each provider has a name and a version number, and is configured
* in each runtime it is installed in.
*
* <p>See <a href =
* "../../../guide/security/CryptoSpec.html#Provider">The Provider Class</a>
* in the "Java Cryptography Architecture API Specification & Reference"
* for information about how a particular type of provider, the
* cryptographic service provider, works and is installed. However,
* please note that a provider can be used to implement any security
* service in Java that uses a pluggable architecture with a choice
* of implementations that fit underneath.
*
* @version 1.48, 02/02/00
* @author Benjamin Renaud
*/
public abstract class Provider extends Properties {
private static final sun.security.util.Debug debug =
sun.security.util.Debug.getInstance
("jca", "Provider");
/**
* The provider name.
*
* @serial
*/
private String name;
/**
* A description of the provider and its services.
*
* @serial
*/
private String info;
/**
* The provider version number.
*
* @serial
*/
private double version;
private transient Set entrySet = null;
private transient int entrySetCallCount = 0;
/**
* Constructs a provider with the specified name, version number,
* and information.
*
* @param name the provider name.
*
* @param version the provider version number.
*
* @param info a description of the provider and its services.
*/
protected Provider(String name, double version, String info) {
this.name = name;
this.version = version;
this.info = info;
}
/**
* Constructs a provider with the specified name. Assigns it
* version 1.0.
*
* @param name the provider name.
*/
Provider(String name) {
this(name, 1.0, "no information available");
}
/**
* Returns the name of this provider.
*
* @return the name of this provider.
*/
public String getName() {
return name;
}
/**
* Returns the version number for this provider.
*
* @return the version number for this provider.
*/
public double getVersion() {
return version;
}
/**
* Returns a human-readable description of the provider and its
* services. This may return an HTML page, with relevant links.
*
* @return a description of the provider and its services.
*/
public String getInfo() {
return info;
}
/*
* Instantiates a provider from its fully-qualified class name.
*
* <p>The assumption is made that providers configured in the
* security properties file will always be supplied as part
* of an INSTALLED extension or specified on the class path
* (and therefore can be loaded using the class loader returned by
* a call to <code>ClassLoader.getSystemClassLoader</code>, whose
* delegation parent is the extension class loader for installed
* extensions).
*
* <p>If an applet or application wants to install a provider that is
* supplied within a BUNDLED extension, it will be able to do so
* only at runtime, by calling the <code>Security.addProvider</code>
* method (which is subject to a security check).
*/
static Provider loadProvider(String name) {
try {
ClassLoader cl = ClassLoader.getSystemClassLoader();
Class provClass;
if (cl != null) {
provClass = cl.loadClass(name);
} else {
provClass = Class.forName(name);
}
Object obj = provClass.newInstance();
if (obj instanceof Provider) {
if (debug != null) {
debug.println("Loaded provider " + name);
}
return (Provider)obj;
} else {
if (debug != null) {
debug.println(name + " is not a provider");
}
}
} catch (Exception e) {
if (debug != null) {
debug.println("Error loading provider " + name);
e.printStackTrace();
}
}
return null;
}
/**
* Returns a string with the name and the version number
* of this provider.
*
* @return the string with the name and the version number
* for this provider.
*/
public String toString() {
return name + " version " + version;
}
/*
* override the following methods to ensure that provider
* information can only be changed if the caller has the appropriate
* permissions.
*/
/**
* Clears this provider so that it no longer contains the properties
* used to look up facilities implemented by the provider.
*
* <p>First, if there is a security manager, its <code>checkSecurityAccess</code>
* method is called with the string <code>"clearProviderProperties."+name</code>
* (where <code>name</code> is the provider name) to see if it's ok to clear this provider.
* If the default implementation of <code>checkSecurityAccess</code>
* is used (that is, that method is not overriden), then this results in
* a call to the security manager's <code>checkPermission</code> method with a
* <code>SecurityPermission("clearProviderProperties."+name)</code>
* permission.
*
* @throws SecurityException
* if a security manager exists and its <code>{@link
* java.lang.SecurityManager#checkSecurityAccess}</code> method denies
* access to clear this provider
*
* @since 1.2
*/
public synchronized void clear() {
check("clearProviderProperties."+name);
if (debug != null) {
debug.println("Remove " + name + " provider properties");
}
super.clear();
}
/**
* Reads a property list (key and element pairs) from the input stream.
*
* @param inStream the input stream.
* @exception IOException if an error occurred when reading from the
* input stream.
* @see java.util.Properties#load
*/
public synchronized void load(InputStream inStream) throws IOException {
check("putProviderProperty."+name);
if (debug != null) {
debug.println("Load " + name + " provider properties");
}
Properties tempProperties = new Properties();
tempProperties.load(inStream);
putAllInternal(tempProperties);
}
/**
* Copies all of the mappings from the specified Map to this provider.
* These mappings will replace any properties that this provider had
* for any of the keys currently in the specified Map.
*
* @since 1.2
*/
public synchronized void putAll(Map t) {
check("putProviderProperty."+name);
if (debug != null) {
debug.println("Put all " + name + " provider properties");
}
putAllInternal(t);
}
/**
* Copies all of the mappings from the specified Map to this provider.
* Internal method to be called AFTER the security check has been
* performed.
*/
private void putAllInternal(Map t) {
Iterator i = t.entrySet().iterator();
while (i.hasNext()) {
Map.Entry e = (Map.Entry) i.next();
super.put(e.getKey(), e.getValue());
}
}
/**
* Returns an unmodifiable Set view of the property entries contained
* in this Provider.
*
* @see java.util.Map.Entry
* @since 1.2
*/
public synchronized Set entrySet() {
if (entrySet == null) {
if (entrySetCallCount++ == 0) // Initial call
entrySet = Collections.unmodifiableMap(this).entrySet();
else
return super.entrySet(); // Recursive call
}
// This exception will be thrown if the implementation of
// Collections.unmodifiableMap.entrySet() is changed such that it
// no longer calls entrySet() on the backing Map. (Provider's
// entrySet implementation depends on this "implementation detail"
if (entrySetCallCount != 2)
throw new RuntimeException("Internal error.");
return entrySet;
}
/**
* Returns an unmodifiable Set view of the property keys contained in
* this provider.
*
* @since 1.2
*/
public Set keySet() {
return Collections.unmodifiableSet(super.keySet());
}
/**
* Returns an unmodifiable Collection view of the property values
* contained in this provider.
*
* @since 1.2
*/
public Collection values() {
return Collections.unmodifiableCollection(super.values());
}
/**
* Sets the <code>key</code> property to have the specified
* <code>value</code>.
*
* <p>First, if there is a security manager, its <code>checkSecurityAccess</code>
* method is called with the string <code>"putProviderProperty."+name</code>,
* where <code>name</code> is the provider name,
* to see if it's ok to set this provider's property values.
* If the default implementation of <code>checkSecurityAccess</code>
* is used (that is, that method is not overriden), then this results in
* a call to the security manager's <code>checkPermission</code> method with a
* <code>SecurityPermission("putProviderProperty."+name)</code>
* permission.
*
* @param key the property key.
*
* @param value the property value.
*
* @return the previous value of the specified property
* (<code>key</code>), or null if it did not have one.
*
* @throws SecurityException
* if a security manager exists and its <code>{@link
* java.lang.SecurityManager#checkSecurityAccess}</code> method denies
* access to set property values.
*
* @since 1.2
*/
public synchronized Object put(Object key, Object value) {
check("putProviderProperty."+name);
if (debug != null) {
debug.println("Set " + name + " provider property [" +
key + "/" + value +"]");
}
return super.put(key, value);
}
/**
* Removes the <code>key</code> property (and its corresponding
* <code>value</code>).
*
* <p>First, if there is a security manager, its <code>checkSecurityAccess</code>
* method is called with the string <code>""removeProviderProperty."+name</code>,
* where <code>name</code> is the provider name,
* to see if it's ok to remove this provider's properties.
* If the default implementation of <code>checkSecurityAccess</code>
* is used (that is, that method is not overriden), then this results in
* a call to the security manager's <code>checkPermission</code> method with a
* <code>SecurityPermission("removeProviderProperty."+name)</code>
* permission.
*
* @param key the key for the property to be removed.
*
* @return the value to which the key had been mapped,
* or null if the key did not have a mapping.
*
* @throws SecurityException
* if a security manager exists and its <code>{@link
* java.lang.SecurityManager#checkSecurityAccess}</code> method denies
* access to remove this provider's properties.
*
* @since 1.2
*/
public synchronized Object remove(Object key) {
check("removeProviderProperty."+name);
if (debug != null) {
debug.println("Remove " + name + " provider property " + key);
}
return super.remove(key);
}
private static void check(String directive) {
SecurityManager security = System.getSecurityManager();
if (security != null) {
security.checkSecurityAccess(directive);
}
}
// Declare serialVersionUID to be compatible with JDK1.1
static final long serialVersionUID = -4298000515446427739L;
}