Source code: org/apache/axis/encoding/TypeMappingRegistryImpl.java
1 /*
2 * Copyright 2001-2004 The Apache Software Foundation.
3 *
4 * Licensed under the Apache License, Version 2.0 (the "License");
5 * you may not use this file except in compliance with the License.
6 * You may obtain a copy of the License at
7 *
8 * http://www.apache.org/licenses/LICENSE-2.0
9 *
10 * Unless required by applicable law or agreed to in writing, software
11 * distributed under the License is distributed on an "AS IS" BASIS,
12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 * See the License for the specific language governing permissions and
14 * limitations under the License.
15 */
16
17 package org.apache.axis.encoding;
18
19 import org.apache.axis.Constants;
20 import org.apache.axis.utils.Messages;
21
22 import java.util.HashMap;
23
24 /**
25 * <p>
26 * The TypeMappingRegistry keeps track of the individual TypeMappings.
27 * </p>
28 * <p>
29 * The TypeMappingRegistry for axis contains a default type mapping
30 * that is set for either SOAP 1.1 or SOAP 1.2
31 * The default type mapping is a singleton used for the entire
32 * runtime and should not have anything new registered in it.
33 * </p>
34 * <p>
35 * Instead the new TypeMappings for the deploy and service are
36 * made in a separate TypeMapping which is identified by
37 * the soap encoding. These new TypeMappings delegate back to
38 * the default type mapping when information is not found.
39 * </p>
40 * <p>
41 * So logically we have:
42 * <pre>
43 * TMR
44 * | |
45 * | +---------------> DefaultTM
46 * | ^
47 * | |
48 * +----> TM --delegate---+
49 * </pre>
50 *
51 * But in the implementation, the TMR references
52 * "delegate" TypeMappings (TM') which then reference the actual TM's
53 * </p>
54 * <p>
55 * So the picture is really:
56 * <pre>
57 * TMR
58 * | |
59 * | +-----------TM'------> DefaultTM
60 * | ^
61 * | |
62 * +-TM'-> TM ----+
63 * </pre>
64 *
65 * This extra indirection is necessary because the user may want to
66 * change the default type mapping. In such cases, the TMR
67 * just needs to adjust the TM' for the DefaultTM, and all of the
68 * other TMs will properly delegate to the new one. Here's the picture:
69 * <pre>
70 * TMR
71 * | |
72 * | +-----------TM'--+ DefaultTM
73 * | ^ |
74 * | | +---> New User Defined Default TM
75 * +-TM'-> TM ----+
76 * </pre>
77 *
78 * The other reason that it is necessary is when a deploy
79 * has a TMR, and then TMR's are defined for the individual services
80 * in such cases the delegate() method is invoked on the service
81 * to delegate to the deploy TMR
82 * <pre>
83 * Deploy TMR
84 * | |
85 * | +-----------TM'------> DefaultTM
86 * | ^
87 * | |
88 * +-TM'-> TM ----+
89 *
90 * Service TMR
91 * | |
92 * | +-----------TM'------> DefaultTM
93 * | ^
94 * | |
95 * +-TM'-> TM ----+
96 *
97 * ServiceTMR.delegate(DeployTMR)
98 *
99 * Deploy TMR
100 * | |
101 * | +------------TM'------> DefaultTM
102 * | ^ ^
103 * | | |
104 * +-TM'-> TM ----+ |
105 * ^ |
106 * +-------+ |
107 * | |
108 * | Service TMR |
109 * | | | |
110 * | | +----------TM'-+
111 * | |
112 * | |
113 * | +-TM'-> TM +
114 * | |
115 * +----------------+
116 * </pre>
117 *
118 * So now the service uses the DefaultTM of the Deploy TMR, and
119 * the Service TM properly delegates to the deploy's TM. And
120 * if either the deploy defaultTM or TMs change, the links are not broken.
121 * </p>
122 *
123 * @author James Snell (jasnell@us.ibm.com)
124 * @author Sam Ruby (rubys@us.ibm.com)
125 * Re-written for JAX-RPC Compliance by
126 * @author Rich Scheuerle (scheu@us.ibm.com
127 */
128 public class TypeMappingRegistryImpl implements TypeMappingRegistry {
129
130 private HashMap mapTM; // Type Mappings keyed with Namespace URI
131 private TypeMappingDelegate defaultDelTM; // Delegate to default Type Mapping
132 private boolean isDelegated = false;
133
134 /**
135 * Construct TypeMappingRegistry
136 * @param tm
137 */
138 public TypeMappingRegistryImpl(TypeMappingImpl tm) {
139 mapTM = new HashMap();
140 defaultDelTM = new TypeMappingDelegate(tm);
141 // TypeMappingDelegate del = new TypeMappingDelegate(new DefaultSOAPEncodingTypeMappingImpl());
142 // register(Constants.URI_SOAP11_ENC, del);
143 }
144
145 /**
146 * Construct TypeMappingRegistry
147 */
148 public TypeMappingRegistryImpl() {
149 this(true);
150 }
151
152 public TypeMappingRegistryImpl(boolean registerDefaults) {
153 mapTM = new HashMap();
154 if (registerDefaults) {
155 defaultDelTM = DefaultTypeMappingImpl.getSingletonDelegate();
156 TypeMappingDelegate del = new TypeMappingDelegate(new DefaultSOAPEncodingTypeMappingImpl());
157 register(Constants.URI_SOAP11_ENC, del);
158 } else {
159 defaultDelTM = new TypeMappingDelegate(TypeMappingDelegate.placeholder);
160 }
161 }
162
163 /**
164 * delegate
165 *
166 * Changes the contained type mappings to delegate to
167 * their corresponding types in the secondary TMR.
168 */
169 public void delegate(TypeMappingRegistry secondaryTMR) {
170
171 if (isDelegated || secondaryTMR == null || secondaryTMR == this) {
172 return;
173 }
174
175 isDelegated = true;
176 String[] keys = secondaryTMR.getRegisteredEncodingStyleURIs();
177 TypeMappingDelegate otherDefault =
178 ((TypeMappingRegistryImpl)secondaryTMR).defaultDelTM;
179 if (keys != null) {
180 for (int i=0; i < keys.length; i++) {
181 try {
182 String nsURI = keys[i];
183 TypeMappingDelegate tm = (TypeMappingDelegate) mapTM.get(nsURI);
184 if (tm == null) {
185 tm = (TypeMappingDelegate)createTypeMapping();
186 tm.setSupportedEncodings(new String[] { nsURI });
187 register(nsURI, tm);
188 }
189
190 if (tm != null) {
191 // Get the secondaryTMR's TM'
192 TypeMappingDelegate del = (TypeMappingDelegate)
193 ((TypeMappingRegistryImpl)secondaryTMR).mapTM.get(nsURI);
194
195 while (del.next != null) {
196 TypeMappingDelegate nu = new TypeMappingDelegate(del.delegate);
197 tm.setNext(nu);
198
199 if (del.next == otherDefault) {
200 nu.setNext(defaultDelTM);
201 break;
202 }
203 del = del.next;
204 tm = nu;
205 }
206 }
207
208 } catch (Exception e) {
209 }
210 }
211 }
212 // Change our defaultDelTM to delegate to the one in
213 // the secondaryTMR
214 if (defaultDelTM.delegate != TypeMappingDelegate.placeholder) {
215 defaultDelTM.setNext(otherDefault);
216 } else {
217 defaultDelTM.delegate = otherDefault.delegate;
218 }
219
220 }
221
222
223
224 /********* JAX-RPC Compliant Method Definitions *****************/
225
226 /**
227 * The method register adds a TypeMapping instance for a specific
228 * namespace
229 *
230 * @param namespaceURI
231 * @param mapping - TypeMapping for specific namespaces
232 *
233 * @return Previous TypeMapping associated with the specified namespaceURI,
234 * or null if there was no TypeMapping associated with the specified namespaceURI
235 *
236 */
237 public javax.xml.rpc.encoding.TypeMapping register(String namespaceURI,
238 javax.xml.rpc.encoding.TypeMapping mapping) {
239 // namespaceURI = "";
240 if (mapping == null ||
241 !(mapping instanceof TypeMappingDelegate)) {
242 throw new IllegalArgumentException(
243 Messages.getMessage("badTypeMapping"));
244 }
245 if (namespaceURI == null) {
246 throw new java.lang.IllegalArgumentException(
247 Messages.getMessage("nullNamespaceURI"));
248 }
249
250 TypeMappingDelegate del = (TypeMappingDelegate)mapping;
251 TypeMappingDelegate old = (TypeMappingDelegate)mapTM.get(namespaceURI);
252 if (old == null) {
253 del.setNext(defaultDelTM);
254 } else {
255 del.setNext(old);
256 }
257 mapTM.put(namespaceURI, del);
258 return old; // Needs works
259 }
260
261 /**
262 * The method register adds a default TypeMapping instance. If a specific
263 * TypeMapping is not found, the default TypeMapping is used.
264 *
265 * @param mapping - TypeMapping for specific type namespaces
266 *
267 * java.lang.IllegalArgumentException -
268 * if an invalid type mapping is specified or the delegate is already set
269 */
270 public void registerDefault(javax.xml.rpc.encoding.TypeMapping mapping) {
271 if (mapping == null ||
272 !(mapping instanceof TypeMappingDelegate)) {
273 throw new IllegalArgumentException(
274 Messages.getMessage("badTypeMapping"));
275 }
276
277 /* Don't allow this call after the delegate() method since
278 * the TMR's TypeMappings will be using the default type mapping
279 * of the secondary TMR.
280 */
281 if (defaultDelTM.getNext() != null) {
282 throw new IllegalArgumentException(
283 Messages.getMessage("defaultTypeMappingSet"));
284 }
285
286 defaultDelTM = (TypeMappingDelegate)mapping;
287 }
288
289 /**
290 * Set up the default type mapping (and the SOAP encoding type mappings)
291 * as per the passed "version" option.
292 *
293 * @param version
294 */
295 public void doRegisterFromVersion(String version) {
296 if (version == null || version.equals("1.0") || version.equals("1.2")) {
297 TypeMappingImpl.dotnet_soapenc_bugfix = false;
298 // Do nothing, just register SOAPENC mapping
299 } else if (version.equals("1.1")) {
300 TypeMappingImpl.dotnet_soapenc_bugfix = true;
301 // Do nothing, no SOAPENC mapping
302 return;
303 } else if (version.equals("1.3")) {
304 // Reset the default TM to the JAXRPC version, then register SOAPENC
305 defaultDelTM = new TypeMappingDelegate(
306 DefaultJAXRPC11TypeMappingImpl.getSingleton());
307 } else {
308 throw new RuntimeException(
309 Messages.getMessage("j2wBadTypeMapping00"));
310 }
311 registerSOAPENCDefault(
312 new TypeMappingDelegate(DefaultSOAPEncodingTypeMappingImpl.
313 getSingleton()));
314 }
315 /**
316 * Force registration of the given mapping as the SOAPENC default mapping
317 * @param mapping
318 */
319 private void registerSOAPENCDefault(TypeMappingDelegate mapping) {
320 // This get a bit ugly as we do not want to just overwrite
321 // an existing type mapping for SOAP encodings. This happens
322 // when {client,server}-config.wsdd defines a type mapping for
323 // instance.
324 if (!mapTM.containsKey(Constants.URI_SOAP11_ENC)) {
325 mapTM.put(Constants.URI_SOAP11_ENC, mapping);
326 } else {
327 // We have to make sure the default type mapping is
328 // at the end of the chain.
329 // This is important if the default is switched to
330 // the JAX_RPC 1.1 default type mapping!
331 TypeMappingDelegate del =
332 (TypeMappingDelegate) mapTM.get(Constants.URI_SOAP11_ENC);
333 while (del.getNext() != null && ! (del.delegate instanceof DefaultTypeMappingImpl)) {
334 del = del.getNext();
335 }
336 del.setNext(defaultDelTM);
337 }
338
339 if (!mapTM.containsKey(Constants.URI_SOAP12_ENC)) {
340 mapTM.put(Constants.URI_SOAP12_ENC, mapping);
341 } else {
342 // We have to make sure the default type mapping is
343 // at the end of the chain.
344 // This is important if the default is switched to
345 // the JAX_RPC 1.1 default type mapping!
346 TypeMappingDelegate del =
347 (TypeMappingDelegate) mapTM.get(Constants.URI_SOAP12_ENC);
348 while (del.getNext() != null && ! (del.delegate instanceof DefaultTypeMappingImpl)) {
349 del = del.getNext();
350 }
351 del.setNext(defaultDelTM);
352 }
353
354 // Just do this unconditionally in case we used mapping.
355 // This is important if the default is switched to
356 // the JAX_RPC 1.1 default type mapping!
357 mapping.setNext(defaultDelTM);
358 }
359
360 /**
361 * Gets the TypeMapping for the namespace. If not found, the default
362 * TypeMapping is returned.
363 *
364 * @param namespaceURI - The namespace URI of a Web Service
365 * @return The registered TypeMapping
366 * (which may be the default TypeMapping) or null.
367 */
368 public javax.xml.rpc.encoding.TypeMapping
369 getTypeMapping(String namespaceURI) {
370 // namespaceURI = "";
371 TypeMapping del = (TypeMappingDelegate) mapTM.get(namespaceURI);
372 if (del == null) {
373 del = (TypeMapping)getDefaultTypeMapping();
374 }
375 return del;
376 }
377
378 /**
379 * Obtain a type mapping for the given encodingStyle. If no specific
380 * mapping exists for this encodingStyle, we will create and register
381 * one before returning it.
382 *
383 * @param encodingStyle
384 * @return a registered TypeMapping for the given encodingStyle
385 */
386 public TypeMapping getOrMakeTypeMapping(String encodingStyle) {
387 TypeMappingDelegate del = (TypeMappingDelegate) mapTM.get(encodingStyle);
388 if (del == null || del.delegate instanceof DefaultTypeMappingImpl) {
389 del = (TypeMappingDelegate)createTypeMapping();
390 del.setSupportedEncodings(new String[] {encodingStyle});
391 register(encodingStyle, del);
392 }
393 return del;
394 }
395
396 /**
397 * Unregisters the TypeMapping for the namespace.
398 *
399 * @param namespaceURI - The namespace URI
400 * @return The registered TypeMapping .
401 */
402 public javax.xml.rpc.encoding.TypeMapping
403 unregisterTypeMapping(String namespaceURI) {
404 return (TypeMappingDelegate)mapTM.remove(namespaceURI);
405 }
406
407 /**
408 * Removes the TypeMapping for the namespace.
409 *
410 * @param mapping The type mapping to remove
411 * @return true if found and removed
412 */
413 public boolean removeTypeMapping(
414 javax.xml.rpc.encoding.TypeMapping mapping) {
415 String[] ns = getRegisteredEncodingStyleURIs();
416 boolean rc = false;
417 for (int i=0; i < ns.length; i++) {
418 if (getTypeMapping(ns[i]) == mapping) {
419 rc = true;
420 unregisterTypeMapping(ns[i]);
421 }
422 }
423 return rc;
424 }
425
426 /**
427 * Creates a new empty TypeMapping object for the specified
428 * encoding style or XML schema namespace.
429 *
430 * @return An empty generic TypeMapping object
431 */
432 public javax.xml.rpc.encoding.TypeMapping createTypeMapping() {
433 TypeMappingImpl impl = new TypeMappingImpl();
434 TypeMappingDelegate del = new TypeMappingDelegate(impl);
435 del.setNext(defaultDelTM);
436 return del;
437 }
438
439
440 /**
441 * Gets a list of namespace URIs registered with this TypeMappingRegistry.
442 *
443 * @return String[] containing names of all registered namespace URIs
444 */
445 public String[] getRegisteredEncodingStyleURIs() {
446 java.util.Set s = mapTM.keySet();
447 if (s != null) {
448 String[] rc = new String[s.size()];
449 int i = 0;
450 java.util.Iterator it = s.iterator();
451 while(it.hasNext()) {
452 rc[i++] = (String) it.next();
453 }
454 return rc;
455 }
456 return null;
457 }
458
459
460 /**
461 * Removes all TypeMappings and namespaceURIs from this TypeMappingRegistry.
462 */
463 public void clear() {
464 mapTM.clear();
465 }
466
467 /**
468 * Return the default TypeMapping
469 * @return TypeMapping or null
470 **/
471 public javax.xml.rpc.encoding.TypeMapping getDefaultTypeMapping() {
472 return defaultDelTM;
473 }
474
475 }