blob: dda6ebbb1d196b083945714d9d1bc65290f577da [file] [log] [blame]
J. Duke319a3b92007-12-01 00:00:00 +00001/*
2 * Copyright 2005-2006 Sun Microsystems, Inc. All Rights Reserved.
3 * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
4 *
5 * This code is free software; you can redistribute it and/or modify it
6 * under the terms of the GNU General Public License version 2 only, as
7 * published by the Free Software Foundation. Sun designates this
8 * particular file as subject to the "Classpath" exception as provided
9 * by Sun in the LICENSE file that accompanied this code.
10 *
11 * This code is distributed in the hope that it will be useful, but WITHOUT
12 * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
13 * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
14 * version 2 for more details (a copy is included in the LICENSE file that
15 * accompanied this code).
16 *
17 * You should have received a copy of the GNU General Public License version
18 * 2 along with this work; if not, write to the Free Software Foundation,
19 * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
20 *
21 * Please contact Sun Microsystems, Inc., 4150 Network Circle, Santa Clara,
22 * CA 95054 USA or visit www.sun.com if you need additional information or
23 * have any questions.
24 */
25/*
26 * $Id: TransformService.java,v 1.6.4.1 2005/09/15 12:42:11 mullan Exp $
27 */
28package javax.xml.crypto.dsig;
29
30import java.security.InvalidAlgorithmParameterException;
31import java.security.NoSuchAlgorithmException;
32import java.security.NoSuchProviderException;
33import java.security.Provider;
34import java.security.Provider.Service;
35import java.security.Security;
36import java.util.*;
37import javax.xml.crypto.MarshalException;
38import javax.xml.crypto.XMLStructure;
39import javax.xml.crypto.XMLCryptoContext;
40import javax.xml.crypto.dsig.spec.TransformParameterSpec;
41
42import sun.security.jca.*;
43import sun.security.jca.GetInstance.Instance;
44
45/**
46 * A Service Provider Interface for transform and canonicalization algorithms.
47 *
48 * <p>Each instance of <code>TransformService</code> supports a specific
49 * transform or canonicalization algorithm and XML mechanism type. To create a
50 * <code>TransformService</code>, call one of the static
51 * {@link #getInstance getInstance} methods, passing in the algorithm URI and
52 * XML mechanism type desired, for example:
53 *
54 * <blockquote><code>
55 * TransformService ts = TransformService.getInstance(Transform.XPATH2, "DOM");
56 * </code></blockquote>
57 *
58 * <p><code>TransformService</code> implementations are registered and loaded
59 * using the {@link java.security.Provider} mechanism. Each
60 * <code>TransformService</code> service provider implementation should include
61 * a <code>MechanismType</code> service attribute that identifies the XML
62 * mechanism type that it supports. If the attribute is not specified,
63 * "DOM" is assumed. For example, a service provider that supports the
64 * XPath Filter 2 Transform and DOM mechanism would be specified in the
65 * <code>Provider</code> subclass as:
66 * <pre>
67 * put("TransformService." + Transform.XPATH2,
68 * "org.example.XPath2TransformService");
69 * put("TransformService." + Transform.XPATH2 + " MechanismType", "DOM");
70 * </pre>
71 * <code>TransformService</code> implementations that support the DOM
72 * mechanism type must abide by the DOM interoperability requirements defined
73 * in the
74 * <a href="../../../../../technotes/guides/security/xmldsig/overview.html#DOM Mechanism Requirements">
75 * DOM Mechanism Requirements</a> section of the API overview. See the
76 * <a href="../../../../../technotes/guides/security/xmldsig/overview.html#Service Provider">
77 * Service Providers</a> section of the API overview for a list of standard
78 * mechanism types.
79 * <p>
80 * Once a <code>TransformService</code> has been created, it can be used
81 * to process <code>Transform</code> or <code>CanonicalizationMethod</code>
82 * objects. If the <code>Transform</code> or <code>CanonicalizationMethod</code>
83 * exists in XML form (for example, when validating an existing
84 * <code>XMLSignature</code>), the {@link #init(XMLStructure, XMLCryptoContext)}
85 * method must be first called to initialize the transform and provide document
86 * context (even if there are no parameters). Alternatively, if the
87 * <code>Transform</code> or <code>CanonicalizationMethod</code> is being
88 * created from scratch, the {@link #init(TransformParameterSpec)} method
89 * is called to initialize the transform with parameters and the
90 * {@link #marshalParams marshalParams} method is called to marshal the
91 * parameters to XML and provide the transform with document context. Finally,
92 * the {@link #transform transform} method is called to perform the
93 * transformation.
94 * <p>
95 * <b>Concurrent Access</b>
96 * <p>The static methods of this class are guaranteed to be thread-safe.
97 * Multiple threads may concurrently invoke the static methods defined in this
98 * class with no ill effects.
99 *
100 * <p>However, this is not true for the non-static methods defined by this
101 * class. Unless otherwise documented by a specific provider, threads that
102 * need to access a single <code>TransformService</code> instance
103 * concurrently should synchronize amongst themselves and provide the
104 * necessary locking. Multiple threads each manipulating a different
105 * <code>TransformService</code> instance need not synchronize.
106 *
107 * @author Sean Mullan
108 * @author JSR 105 Expert Group
109 * @since 1.6
110 */
111public abstract class TransformService implements Transform {
112
113 private String algorithm;
114 private String mechanism;
115 private Provider provider;
116
117 /**
118 * Default constructor, for invocation by subclasses.
119 */
120 protected TransformService() {}
121
122 /**
123 * Returns a <code>TransformService</code> that supports the specified
124 * algorithm URI (ex: {@link Transform#XPATH2}) and mechanism type
125 * (ex: DOM).
126 *
127 * <p>This method uses the standard JCA provider lookup mechanism to
128 * locate and instantiate a <code>TransformService</code> implementation
129 * of the desired algorithm and <code>MechanismType</code> service
130 * attribute. It traverses the list of registered security
131 * <code>Provider</code>s, starting with the most preferred
132 * <code>Provider</code>. A new <code>TransformService</code> object
133 * from the first <code>Provider</code> that supports the specified
134 * algorithm and mechanism type is returned.
135 *
136 * <p> Note that the list of registered providers may be retrieved via
137 * the {@link Security#getProviders() Security.getProviders()} method.
138 *
139 * @param algorithm the URI of the algorithm
140 * @param mechanismType the type of the XML processing mechanism and
141 * representation
142 * @return a new <code>TransformService</code>
143 * @throws NullPointerException if <code>algorithm</code> or
144 * <code>mechanismType</code> is <code>null</code>
145 * @throws NoSuchAlgorithmException if no <code>Provider</code> supports a
146 * <code>TransformService</code> implementation for the specified
147 * algorithm and mechanism type
148 * @see Provider
149 */
150 public static TransformService getInstance
151 (String algorithm, String mechanismType)
152 throws NoSuchAlgorithmException {
153 if (mechanismType == null || algorithm == null) {
154 throw new NullPointerException();
155 }
156 boolean dom = false;
157 if (mechanismType.equals("DOM")) {
158 dom = true;
159 }
160 List services = GetInstance.getServices("TransformService", algorithm);
161 for (Iterator t = services.iterator(); t.hasNext(); ) {
162 Service s = (Service)t.next();
163 String value = s.getAttribute("MechanismType");
164 if ((value == null && dom) ||
165 (value != null && value.equals(mechanismType))) {
166 Instance instance = GetInstance.getInstance(s, null);
167 TransformService ts = (TransformService) instance.impl;
168 ts.algorithm = algorithm;
169 ts.mechanism = mechanismType;
170 ts.provider = instance.provider;
171 return ts;
172 }
173 }
174 throw new NoSuchAlgorithmException
175 (algorithm + " algorithm and " + mechanismType
176 + " mechanism not available");
177 }
178
179 /**
180 * Returns a <code>TransformService</code> that supports the specified
181 * algorithm URI (ex: {@link Transform#XPATH2}) and mechanism type
182 * (ex: DOM) as supplied by the specified provider. Note that the specified
183 * <code>Provider</code> object does not have to be registered in the
184 * provider list.
185 *
186 * @param algorithm the URI of the algorithm
187 * @param mechanismType the type of the XML processing mechanism and
188 * representation
189 * @param provider the <code>Provider</code> object
190 * @return a new <code>TransformService</code>
191 * @throws NullPointerException if <code>provider</code>,
192 * <code>algorithm</code>, or <code>mechanismType</code> is
193 * <code>null</code>
194 * @throws NoSuchAlgorithmException if a <code>TransformService</code>
195 * implementation for the specified algorithm and mechanism type is not
196 * available from the specified <code>Provider</code> object
197 * @see Provider
198 */
199 public static TransformService getInstance
200 (String algorithm, String mechanismType, Provider provider)
201 throws NoSuchAlgorithmException {
202 if (mechanismType == null || algorithm == null || provider == null) {
203 throw new NullPointerException();
204 }
205
206 boolean dom = false;
207 if (mechanismType.equals("DOM")) {
208 dom = true;
209 }
210 Service s = GetInstance.getService
211 ("TransformService", algorithm, provider);
212 String value = s.getAttribute("MechanismType");
213 if ((value == null && dom) ||
214 (value != null && value.equals(mechanismType))) {
215 Instance instance = GetInstance.getInstance(s, null);
216 TransformService ts = (TransformService) instance.impl;
217 ts.algorithm = algorithm;
218 ts.mechanism = mechanismType;
219 ts.provider = instance.provider;
220 return ts;
221 }
222 throw new NoSuchAlgorithmException
223 (algorithm + " algorithm and " + mechanismType
224 + " mechanism not available");
225 }
226
227 /**
228 * Returns a <code>TransformService</code> that supports the specified
229 * algorithm URI (ex: {@link Transform#XPATH2}) and mechanism type
230 * (ex: DOM) as supplied by the specified provider. The specified provider
231 * must be registered in the security provider list.
232 *
233 * <p>Note that the list of registered providers may be retrieved via
234 * the {@link Security#getProviders() Security.getProviders()} method.
235 *
236 * @param algorithm the URI of the algorithm
237 * @param mechanismType the type of the XML processing mechanism and
238 * representation
239 * @param provider the string name of the provider
240 * @return a new <code>TransformService</code>
241 * @throws NoSuchProviderException if the specified provider is not
242 * registered in the security provider list
243 * @throws NullPointerException if <code>provider</code>,
244 * <code>mechanismType</code>, or <code>algorithm</code> is
245 * <code>null</code>
246 * @throws NoSuchAlgorithmException if a <code>TransformService</code>
247 * implementation for the specified algorithm and mechanism type is not
248 * available from the specified provider
249 * @see Provider
250 */
251 public static TransformService getInstance
252 (String algorithm, String mechanismType, String provider)
253 throws NoSuchAlgorithmException, NoSuchProviderException {
254 if (mechanismType == null || algorithm == null || provider == null) {
255 throw new NullPointerException();
256 } else if (provider.length() == 0) {
257 throw new NoSuchProviderException();
258 }
259 boolean dom = false;
260 if (mechanismType.equals("DOM")) {
261 dom = true;
262 }
263 Service s = GetInstance.getService
264 ("TransformService", algorithm, provider);
265 String value = s.getAttribute("MechanismType");
266 if ((value == null && dom) ||
267 (value != null && value.equals(mechanismType))) {
268 Instance instance = GetInstance.getInstance(s, null);
269 TransformService ts = (TransformService) instance.impl;
270 ts.algorithm = algorithm;
271 ts.mechanism = mechanismType;
272 ts.provider = instance.provider;
273 return ts;
274 }
275 throw new NoSuchAlgorithmException
276 (algorithm + " algorithm and " + mechanismType
277 + " mechanism not available");
278 }
279
280 private static class MechanismMapEntry implements Map.Entry {
281 private final String mechanism;
282 private final String algorithm;
283 private final String key;
284 MechanismMapEntry(String algorithm, String mechanism) {
285 this.algorithm = algorithm;
286 this.mechanism = mechanism;
287 this.key = "TransformService." + algorithm + " MechanismType";
288 }
289 public boolean equals(Object o) {
290 if (!(o instanceof Map.Entry)) {
291 return false;
292 }
293 Map.Entry e = (Map.Entry) o;
294 return (getKey()==null ?
295 e.getKey()==null : getKey().equals(e.getKey())) &&
296 (getValue()==null ?
297 e.getValue()==null : getValue().equals(e.getValue()));
298 }
299 public Object getKey() {
300 return key;
301 }
302 public Object getValue() {
303 return mechanism;
304 }
305 public Object setValue(Object value) {
306 throw new UnsupportedOperationException();
307 }
308 public int hashCode() {
309 return (getKey()==null ? 0 : getKey().hashCode()) ^
310 (getValue()==null ? 0 : getValue().hashCode());
311 }
312 }
313
314 /**
315 * Returns the mechanism type supported by this <code>TransformService</code>.
316 *
317 * @return the mechanism type
318 */
319 public final String getMechanismType() {
320 return mechanism;
321 }
322
323 /**
324 * Returns the URI of the algorithm supported by this
325 * <code>TransformService</code>.
326 *
327 * @return the algorithm URI
328 */
329 public final String getAlgorithm() {
330 return algorithm;
331 }
332
333 /**
334 * Returns the provider of this <code>TransformService</code>.
335 *
336 * @return the provider
337 */
338 public final Provider getProvider() {
339 return provider;
340 }
341
342 /**
343 * Initializes this <code>TransformService</code> with the specified
344 * parameters.
345 *
346 * <p>If the parameters exist in XML form, the
347 * {@link #init(XMLStructure, XMLCryptoContext)} method should be used to
348 * initialize the <code>TransformService</code>.
349 *
350 * @param params the algorithm parameters (may be <code>null</code> if
351 * not required or optional)
352 * @throws InvalidAlgorithmParameterException if the specified parameters
353 * are invalid for this algorithm
354 */
355 public abstract void init(TransformParameterSpec params)
356 throws InvalidAlgorithmParameterException;
357
358 /**
359 * Marshals the algorithm-specific parameters. If there are no parameters
360 * to be marshalled, this method returns without throwing an exception.
361 *
362 * @param parent a mechanism-specific structure containing the parent
363 * node that the marshalled parameters should be appended to
364 * @param context the <code>XMLCryptoContext</code> containing
365 * additional context (may be <code>null</code> if not applicable)
366 * @throws ClassCastException if the type of <code>parent</code> or
367 * <code>context</code> is not compatible with this
368 * <code>TransformService</code>
369 * @throws NullPointerException if <code>parent</code> is <code>null</code>
370 * @throws MarshalException if the parameters cannot be marshalled
371 */
372 public abstract void marshalParams
373 (XMLStructure parent, XMLCryptoContext context)
374 throws MarshalException;
375
376 /**
377 * Initializes this <code>TransformService</code> with the specified
378 * parameters and document context.
379 *
380 * @param parent a mechanism-specific structure containing the parent
381 * structure
382 * @param context the <code>XMLCryptoContext</code> containing
383 * additional context (may be <code>null</code> if not applicable)
384 * @throws ClassCastException if the type of <code>parent</code> or
385 * <code>context</code> is not compatible with this
386 * <code>TransformService</code>
387 * @throws NullPointerException if <code>parent</code> is <code>null</code>
388 * @throws InvalidAlgorithmParameterException if the specified parameters
389 * are invalid for this algorithm
390 */
391 public abstract void init(XMLStructure parent, XMLCryptoContext context)
392 throws InvalidAlgorithmParameterException;
393}