| /* |
| * Copyright (c) 2005, 2017, 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. |
| */ |
| /* |
| * $Id: TransformService.java,v 1.6.4.1 2005/09/15 12:42:11 mullan Exp $ |
| */ |
| package javax.xml.crypto.dsig; |
| |
| import java.security.InvalidAlgorithmParameterException; |
| import java.security.NoSuchAlgorithmException; |
| import java.security.NoSuchProviderException; |
| import java.security.Provider; |
| import java.security.Provider.Service; |
| import java.security.Security; |
| import java.util.*; |
| import javax.xml.crypto.MarshalException; |
| import javax.xml.crypto.XMLStructure; |
| import javax.xml.crypto.XMLCryptoContext; |
| import javax.xml.crypto.dsig.spec.TransformParameterSpec; |
| |
| |
| /** |
| * A Service Provider Interface for transform and canonicalization algorithms. |
| * |
| * <p>Each instance of <code>TransformService</code> supports a specific |
| * transform or canonicalization algorithm and XML mechanism type. To create a |
| * <code>TransformService</code>, call one of the static |
| * {@link #getInstance getInstance} methods, passing in the algorithm URI and |
| * XML mechanism type desired, for example: |
| * |
| * <blockquote><code> |
| * TransformService ts = TransformService.getInstance(Transform.XPATH2, "DOM"); |
| * </code></blockquote> |
| * |
| * <p><code>TransformService</code> implementations are registered and loaded |
| * using the {@link java.security.Provider} mechanism. Each |
| * <code>TransformService</code> service provider implementation should include |
| * a <code>MechanismType</code> service attribute that identifies the XML |
| * mechanism type that it supports. If the attribute is not specified, |
| * "DOM" is assumed. For example, a service provider that supports the |
| * XPath Filter 2 Transform and DOM mechanism would be specified in the |
| * <code>Provider</code> subclass as: |
| * <pre> |
| * put("TransformService." + Transform.XPATH2, |
| * "org.example.XPath2TransformService"); |
| * put("TransformService." + Transform.XPATH2 + " MechanismType", "DOM"); |
| * </pre> |
| * <code>TransformService</code> implementations that support the DOM |
| * mechanism type must abide by the DOM interoperability requirements defined |
| * in the |
| * {@extLink security_guide_xmldsig_rqmts DOM Mechanism Requirements} section |
| * of the API overview. See the |
| * {@extLink security_guide_xmldsig_provider Service Providers} section of |
| * the API overview for a list of standard mechanism types. |
| * <p> |
| * Once a <code>TransformService</code> has been created, it can be used |
| * to process <code>Transform</code> or <code>CanonicalizationMethod</code> |
| * objects. If the <code>Transform</code> or <code>CanonicalizationMethod</code> |
| * exists in XML form (for example, when validating an existing |
| * <code>XMLSignature</code>), the {@link #init(XMLStructure, XMLCryptoContext)} |
| * method must be first called to initialize the transform and provide document |
| * context (even if there are no parameters). Alternatively, if the |
| * <code>Transform</code> or <code>CanonicalizationMethod</code> is being |
| * created from scratch, the {@link #init(TransformParameterSpec)} method |
| * is called to initialize the transform with parameters and the |
| * {@link #marshalParams marshalParams} method is called to marshal the |
| * parameters to XML and provide the transform with document context. Finally, |
| * the {@link #transform transform} method is called to perform the |
| * transformation. |
| * <p> |
| * <b>Concurrent Access</b> |
| * <p>The static methods of this class are guaranteed to be thread-safe. |
| * Multiple threads may concurrently invoke the static methods defined in this |
| * class with no ill effects. |
| * |
| * <p>However, this is not true for the non-static methods defined by this |
| * class. Unless otherwise documented by a specific provider, threads that |
| * need to access a single <code>TransformService</code> instance |
| * concurrently should synchronize amongst themselves and provide the |
| * necessary locking. Multiple threads each manipulating a different |
| * <code>TransformService</code> instance need not synchronize. |
| * |
| * @author Sean Mullan |
| * @author JSR 105 Expert Group |
| * @since 1.6 |
| */ |
| public abstract class TransformService implements Transform { |
| |
| private String algorithm; |
| private String mechanism; |
| private Provider provider; |
| |
| /** |
| * Default constructor, for invocation by subclasses. |
| */ |
| protected TransformService() {} |
| |
| /** |
| * Returns a <code>TransformService</code> that supports the specified |
| * algorithm URI (ex: {@link Transform#XPATH2}) and mechanism type |
| * (ex: DOM). |
| * |
| * <p>This method uses the standard JCA provider lookup mechanism to |
| * locate and instantiate a <code>TransformService</code> implementation |
| * of the desired algorithm and <code>MechanismType</code> service |
| * attribute. It traverses the list of registered security |
| * <code>Provider</code>s, starting with the most preferred |
| * <code>Provider</code>. A new <code>TransformService</code> object |
| * from the first <code>Provider</code> that supports the specified |
| * algorithm and mechanism type is returned. |
| * |
| * <p> Note that the list of registered providers may be retrieved via |
| * the {@link Security#getProviders() Security.getProviders()} method. |
| * |
| * @implNote |
| * The JDK Reference Implementation additionally uses the |
| * {@code jdk.security.provider.preferred} |
| * {@link Security#getProperty(String) Security} property to determine |
| * the preferred provider order for the specified algorithm. This |
| * may be different than the order of providers returned by |
| * {@link Security#getProviders() Security.getProviders()}. |
| * |
| * @param algorithm the URI of the algorithm |
| * @param mechanismType the type of the XML processing mechanism and |
| * representation |
| * @return a new <code>TransformService</code> |
| * @throws NullPointerException if <code>algorithm</code> or |
| * <code>mechanismType</code> is <code>null</code> |
| * @throws NoSuchAlgorithmException if no <code>Provider</code> supports a |
| * <code>TransformService</code> implementation for the specified |
| * algorithm and mechanism type |
| * @see Provider |
| */ |
| public static TransformService getInstance |
| (String algorithm, String mechanismType) |
| throws NoSuchAlgorithmException { |
| if (mechanismType == null || algorithm == null) { |
| throw new NullPointerException(); |
| } |
| boolean dom = false; |
| if (mechanismType.equals("DOM")) { |
| dom = true; |
| } |
| |
| Provider[] provs = Security.getProviders(); |
| for (Provider p : provs) { |
| Service s = p.getService("TransformService", algorithm); |
| if (s != null) { |
| String value = s.getAttribute("MechanismType"); |
| if ((value == null && dom) || |
| (value != null && value.equals(mechanismType))) { |
| Object obj = s.newInstance(null); |
| if (obj instanceof TransformService) { |
| TransformService ts = (TransformService) obj; |
| ts.algorithm = algorithm; |
| ts.mechanism = mechanismType; |
| ts.provider = p; |
| return ts; |
| } |
| } |
| } |
| } |
| throw new NoSuchAlgorithmException |
| (algorithm + " algorithm and " + mechanismType |
| + " mechanism not available"); |
| } |
| |
| /** |
| * Returns a <code>TransformService</code> that supports the specified |
| * algorithm URI (ex: {@link Transform#XPATH2}) and mechanism type |
| * (ex: DOM) as supplied by the specified provider. Note that the specified |
| * <code>Provider</code> object does not have to be registered in the |
| * provider list. |
| * |
| * @param algorithm the URI of the algorithm |
| * @param mechanismType the type of the XML processing mechanism and |
| * representation |
| * @param provider the <code>Provider</code> object |
| * @return a new <code>TransformService</code> |
| * @throws NullPointerException if <code>provider</code>, |
| * <code>algorithm</code>, or <code>mechanismType</code> is |
| * <code>null</code> |
| * @throws NoSuchAlgorithmException if a <code>TransformService</code> |
| * implementation for the specified algorithm and mechanism type is not |
| * available from the specified <code>Provider</code> object |
| * @see Provider |
| */ |
| public static TransformService getInstance |
| (String algorithm, String mechanismType, Provider provider) |
| throws NoSuchAlgorithmException { |
| if (mechanismType == null || algorithm == null || provider == null) { |
| throw new NullPointerException(); |
| } |
| |
| boolean dom = false; |
| if (mechanismType.equals("DOM")) { |
| dom = true; |
| } |
| Service s = provider.getService("TransformService", algorithm); |
| if (s != null) { |
| String value = s.getAttribute("MechanismType"); |
| if ((value == null && dom) || |
| (value != null && value.equals(mechanismType))) { |
| Object obj = s.newInstance(null); |
| if (obj instanceof TransformService) { |
| TransformService ts = (TransformService) obj; |
| ts.algorithm = algorithm; |
| ts.mechanism = mechanismType; |
| ts.provider = provider; |
| return ts; |
| } |
| } |
| } |
| throw new NoSuchAlgorithmException |
| (algorithm + " algorithm and " + mechanismType |
| + " mechanism not available from " + provider.getName()); |
| } |
| |
| /** |
| * Returns a <code>TransformService</code> that supports the specified |
| * algorithm URI (ex: {@link Transform#XPATH2}) and mechanism type |
| * (ex: DOM) as supplied by the specified provider. The specified provider |
| * must be registered in the security provider list. |
| * |
| * <p>Note that the list of registered providers may be retrieved via |
| * the {@link Security#getProviders() Security.getProviders()} method. |
| * |
| * @param algorithm the URI of the algorithm |
| * @param mechanismType the type of the XML processing mechanism and |
| * representation |
| * @param provider the string name of the provider |
| * @return a new <code>TransformService</code> |
| * @throws NoSuchProviderException if the specified provider is not |
| * registered in the security provider list |
| * @throws NullPointerException if <code>provider</code>, |
| * <code>mechanismType</code>, or <code>algorithm</code> is |
| * <code>null</code> |
| * @throws NoSuchAlgorithmException if a <code>TransformService</code> |
| * implementation for the specified algorithm and mechanism type is not |
| * available from the specified provider |
| * @see Provider |
| */ |
| public static TransformService getInstance |
| (String algorithm, String mechanismType, String provider) |
| throws NoSuchAlgorithmException, NoSuchProviderException { |
| if (mechanismType == null || algorithm == null || provider == null) { |
| throw new NullPointerException(); |
| } else if (provider.length() == 0) { |
| throw new NoSuchProviderException(); |
| } |
| boolean dom = false; |
| if (mechanismType.equals("DOM")) { |
| dom = true; |
| } |
| Provider p = Security.getProvider(provider); |
| if (p == null) { |
| throw new NoSuchProviderException("No such provider: " + |
| provider); |
| } |
| Service s = p.getService("TransformService", algorithm); |
| if (s != null) { |
| String value = s.getAttribute("MechanismType"); |
| if ((value == null && dom) || |
| (value != null && value.equals(mechanismType))) { |
| Object obj = s.newInstance(null); |
| if (obj instanceof TransformService) { |
| TransformService ts = (TransformService) obj; |
| ts.algorithm = algorithm; |
| ts.mechanism = mechanismType; |
| ts.provider = p; |
| return ts; |
| } |
| } |
| } |
| throw new NoSuchAlgorithmException |
| (algorithm + " algorithm and " + mechanismType |
| + " mechanism not available from " + provider); |
| } |
| |
| private static class MechanismMapEntry implements Map.Entry<String,String> { |
| private final String mechanism; |
| private final String algorithm; |
| private final String key; |
| MechanismMapEntry(String algorithm, String mechanism) { |
| this.algorithm = algorithm; |
| this.mechanism = mechanism; |
| this.key = "TransformService." + algorithm + " MechanismType"; |
| } |
| public boolean equals(Object o) { |
| if (!(o instanceof Map.Entry)) { |
| return false; |
| } |
| Map.Entry<?,?> e = (Map.Entry<?,?>) o; |
| return (getKey()==null ? |
| e.getKey()==null : getKey().equals(e.getKey())) && |
| (getValue()==null ? |
| e.getValue()==null : getValue().equals(e.getValue())); |
| } |
| public String getKey() { |
| return key; |
| } |
| public String getValue() { |
| return mechanism; |
| } |
| public String setValue(String value) { |
| throw new UnsupportedOperationException(); |
| } |
| public int hashCode() { |
| return (getKey()==null ? 0 : getKey().hashCode()) ^ |
| (getValue()==null ? 0 : getValue().hashCode()); |
| } |
| } |
| |
| /** |
| * Returns the mechanism type supported by this <code>TransformService</code>. |
| * |
| * @return the mechanism type |
| */ |
| public final String getMechanismType() { |
| return mechanism; |
| } |
| |
| /** |
| * Returns the URI of the algorithm supported by this |
| * <code>TransformService</code>. |
| * |
| * @return the algorithm URI |
| */ |
| public final String getAlgorithm() { |
| return algorithm; |
| } |
| |
| /** |
| * Returns the provider of this <code>TransformService</code>. |
| * |
| * @return the provider |
| */ |
| public final Provider getProvider() { |
| return provider; |
| } |
| |
| /** |
| * Initializes this <code>TransformService</code> with the specified |
| * parameters. |
| * |
| * <p>If the parameters exist in XML form, the |
| * {@link #init(XMLStructure, XMLCryptoContext)} method should be used to |
| * initialize the <code>TransformService</code>. |
| * |
| * @param params the algorithm parameters (may be <code>null</code> if |
| * not required or optional) |
| * @throws InvalidAlgorithmParameterException if the specified parameters |
| * are invalid for this algorithm |
| */ |
| public abstract void init(TransformParameterSpec params) |
| throws InvalidAlgorithmParameterException; |
| |
| /** |
| * Marshals the algorithm-specific parameters. If there are no parameters |
| * to be marshalled, this method returns without throwing an exception. |
| * |
| * @param parent a mechanism-specific structure containing the parent |
| * node that the marshalled parameters should be appended to |
| * @param context the <code>XMLCryptoContext</code> containing |
| * additional context (may be <code>null</code> if not applicable) |
| * @throws ClassCastException if the type of <code>parent</code> or |
| * <code>context</code> is not compatible with this |
| * <code>TransformService</code> |
| * @throws NullPointerException if <code>parent</code> is <code>null</code> |
| * @throws MarshalException if the parameters cannot be marshalled |
| */ |
| public abstract void marshalParams |
| (XMLStructure parent, XMLCryptoContext context) |
| throws MarshalException; |
| |
| /** |
| * Initializes this <code>TransformService</code> with the specified |
| * parameters and document context. |
| * |
| * @param parent a mechanism-specific structure containing the parent |
| * structure |
| * @param context the <code>XMLCryptoContext</code> containing |
| * additional context (may be <code>null</code> if not applicable) |
| * @throws ClassCastException if the type of <code>parent</code> or |
| * <code>context</code> is not compatible with this |
| * <code>TransformService</code> |
| * @throws NullPointerException if <code>parent</code> is <code>null</code> |
| * @throws InvalidAlgorithmParameterException if the specified parameters |
| * are invalid for this algorithm |
| */ |
| public abstract void init(XMLStructure parent, XMLCryptoContext context) |
| throws InvalidAlgorithmParameterException; |
| } |