1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50 package org.exolab.castor.xml.util;
51
52 import java.util.ArrayList;
53 import java.util.HashMap;
54 import java.util.Iterator;
55 import java.util.List;
56 import java.util.Map;
57 import java.util.concurrent.locks.ReentrantReadWriteLock;
58
59 import org.apache.commons.logging.Log;
60 import org.apache.commons.logging.LogFactory;
61 import org.castor.xml.InternalContext;
62 import org.exolab.castor.mapping.ClassDescriptor;
63 import org.exolab.castor.mapping.MappingLoader;
64 import org.exolab.castor.xml.Introspector;
65 import org.exolab.castor.xml.ResolverException;
66 import org.exolab.castor.xml.XMLClassDescriptor;
67 import org.exolab.castor.xml.XMLClassDescriptorResolver;
68 import org.exolab.castor.xml.util.resolvers.ResolveHelpers;
69
70
71
72
73
74
75
76 public class XMLClassDescriptorResolverImpl implements XMLClassDescriptorResolver {
77
78
79
80 private static final Log LOG = LogFactory.getLog(XMLClassDescriptorResolverImpl.class);
81
82
83
84
85 private DescriptorCacheImpl _descriptorCache;
86
87
88
89 private MappingLoader _mappingLoader;
90
91
92
93 private ClassLoader _classLoader;
94
95
96
97 private Boolean _useIntrospector;
98
99
100
101
102 private Boolean _loadPackageMappings;
103
104
105
106 private Introspector _introspector;
107
108
109
110
111 private ResolverStrategy _resolverStrategy;
112
113
114
115
116
117
118
119 public XMLClassDescriptorResolverImpl() {
120 super();
121 _descriptorCache = new DescriptorCacheImpl();
122 }
123
124
125
126
127
128
129 public void setInternalContext(final InternalContext internalContext) {
130 _mappingLoader = internalContext.getMappingLoader();
131 _classLoader = internalContext.getClassLoader();
132 _useIntrospector = internalContext.getUseIntrospector();
133 _loadPackageMappings = internalContext.getLoadPackageMapping();
134 _introspector = internalContext.getIntrospector();
135 _resolverStrategy = internalContext.getResolverStrategy();
136 }
137
138
139
140
141 public MappingLoader getMappingLoader() {
142 return _mappingLoader;
143 }
144
145
146
147
148 public void setClassLoader(final ClassLoader loader) {
149 _classLoader = loader;
150 }
151
152
153
154
155 public void setUseIntrospection(final boolean enable) {
156 _useIntrospector = Boolean.valueOf(enable);
157 }
158
159
160
161
162 public void setLoadPackageMappings(final boolean loadPackageMappings) {
163 _loadPackageMappings = Boolean.valueOf(loadPackageMappings);
164 }
165
166
167
168
169 public void setMappingLoader(final MappingLoader mappingLoader) {
170 _mappingLoader = mappingLoader;
171 if (mappingLoader != null) {
172 for (ClassDescriptor classDescriptor : mappingLoader.getDescriptors()) {
173 _descriptorCache.addDescriptor(classDescriptor.getJavaClass().getName(),
174 (XMLClassDescriptor) classDescriptor);
175 }
176 }
177 }
178
179
180
181
182 public void setIntrospector(final Introspector introspector) {
183 _introspector = introspector;
184 }
185
186
187
188
189 public void setResolverStrategy(final ResolverStrategy resolverStrategy) {
190 _resolverStrategy = resolverStrategy;
191 }
192
193
194
195
196
197
198
199
200
201 private ResolverStrategy getResolverStrategy() {
202 setAttributesIntoStrategy();
203 return _resolverStrategy;
204 }
205
206
207
208
209 public ClassDescriptor resolve(final Class<?> type) throws ResolverException {
210 if (type == null) {
211 String message = "Type argument must not be null for resolve";
212 LOG.warn(message);
213 throw new IllegalArgumentException(message);
214 }
215
216 if (_descriptorCache.isMissingDescriptor(type.getName())) {
217 if (LOG.isTraceEnabled()) {
218 LOG.trace("Descriptor for " + type.getName() + " already marked as *MISSING*.");
219 }
220 return null;
221 }
222
223 if (_descriptorCache.getDescriptor(type.getName()) != null) {
224 return _descriptorCache.getDescriptor(type.getName());
225 }
226
227 ClassLoader l = _classLoader;
228 if (l == null) { l = type.getClassLoader(); }
229 if (l == null) { l = Thread.currentThread().getContextClassLoader(); }
230
231 return this.resolve(type.getName(), l);
232 }
233
234
235
236
237 public XMLClassDescriptor resolve(final String className) throws ResolverException {
238 if (className == null || className.length() == 0) {
239 String message = "Cannot resolve a null or zero-length class name.";
240 LOG.warn(message);
241 throw new IllegalArgumentException(message);
242 }
243
244 if (_descriptorCache.isMissingDescriptor(className)) {
245 if (LOG.isTraceEnabled()) {
246 LOG.trace("Descriptor for " + className + " already marked as *MISSING*.");
247 }
248 return null;
249 }
250
251 if (_descriptorCache.getDescriptor(className) != null) {
252 return _descriptorCache.getDescriptor(className);
253 }
254
255 ClassLoader l = _classLoader;
256 if (l == null) { l = Thread.currentThread().getContextClassLoader(); }
257
258 return this.resolve(className, l);
259 }
260
261
262
263
264 public XMLClassDescriptor resolve(final String className, final ClassLoader loader)
265 throws ResolverException {
266 if (className == null || className.length() == 0) {
267 String message = "Cannot resolve a null or zero-length class name.";
268 LOG.warn(message);
269 throw new IllegalArgumentException(message);
270 }
271
272 if (_descriptorCache.isMissingDescriptor(className)) {
273 if (LOG.isTraceEnabled()) {
274 LOG.trace("Descriptor for " + className + " already marked as *MISSING*.");
275 }
276 return null;
277 }
278
279 if (_descriptorCache.getDescriptor(className) != null) {
280 return _descriptorCache.getDescriptor(className);
281 }
282
283 ClassLoader l = loader;
284 if (l == null) { l = _classLoader; }
285 if (l == null) { l = Thread.currentThread().getContextClassLoader(); }
286
287 getResolverStrategy().setProperty(ResolverStrategy.PROPERTY_CLASS_LOADER, l);
288 return (XMLClassDescriptor) getResolverStrategy().resolveClass(_descriptorCache, className);
289 }
290
291
292
293
294 public XMLClassDescriptor resolveByXMLName(final String xmlName, final String namespaceURI,
295 final ClassLoader loader) {
296
297 if (xmlName == null || xmlName.length() == 0) {
298 String message = "Cannot resolve a null or zero-length class name.";
299 LOG.warn(message);
300 throw new IllegalArgumentException(message);
301 }
302
303
304
305 List<ClassDescriptor> possibleMatches = _descriptorCache.getDescriptors(xmlName);
306 if (possibleMatches.size() == 0) {
307
308 return null;
309 }
310 if (possibleMatches.size() == 1) {
311
312
313
314 return (XMLClassDescriptor) possibleMatches.get(0);
315 }
316
317
318 for (Iterator<ClassDescriptor> i = possibleMatches.iterator(); i.hasNext(); ) {
319 XMLClassDescriptor descriptor = (XMLClassDescriptor) i.next();
320
321 if (ResolveHelpers.namespaceEquals(namespaceURI, descriptor.getNameSpaceURI())) {
322 return descriptor;
323 }
324 }
325
326
327 return null;
328 }
329
330
331
332
333 public Iterator<ClassDescriptor> resolveAllByXMLName(final String xmlName,
334 final String namespaceURI, final ClassLoader loader) {
335
336 if (xmlName == null || xmlName.length() == 0) {
337 String message = "Cannot resolve a null or zero-length xml name.";
338 LOG.warn(message);
339 throw new IllegalArgumentException(message);
340 }
341
342
343 return _descriptorCache.getDescriptors(xmlName).iterator();
344 }
345
346
347
348
349 public void addClass(final String className) throws ResolverException {
350 this.resolve(className);
351 }
352
353
354
355
356 public void addClasses(final String[] classNames) throws ResolverException {
357 for (int i = 0; i < classNames.length; i++) {
358 String className = classNames[i];
359 this.addClass(className);
360 }
361 }
362
363
364
365
366 public void addClass(final Class<?> clazz) throws ResolverException {
367 this.resolve(clazz);
368 }
369
370
371
372
373 public void addClasses(final Class<?>[] clazzes) throws ResolverException {
374 for (int i = 0; i < clazzes.length; i++) {
375 Class<?> clazz = clazzes[i];
376 this.addClass(clazz);
377 }
378 }
379
380
381
382
383 public void addPackage(final String packageName) throws ResolverException {
384 if (packageName == null || packageName.length() == 0) {
385 String message = "Cannot resolve a null or zero-length package name.";
386 LOG.warn(message);
387 throw new IllegalArgumentException(message);
388 }
389
390 getResolverStrategy().resolvePackage(_descriptorCache, packageName);
391 }
392
393
394
395
396 public void addPackages(final String[] packageNames) throws ResolverException {
397 for (int i = 0; i < packageNames.length; i++) {
398 String packageName = packageNames[i];
399 this.addPackage(packageName);
400 }
401 }
402
403
404
405
406
407 public void loadClassDescriptors(final String packageName) throws ResolverException {
408 String message = "Already deprecated in the interface!";
409 LOG.warn(message);
410 throw new UnsupportedOperationException();
411 }
412
413
414
415
416
417 private void setAttributesIntoStrategy() {
418 ResolverStrategy strategy = _resolverStrategy;
419 strategy.setProperty(
420 ResolverStrategy.PROPERTY_LOAD_PACKAGE_MAPPINGS,
421 _loadPackageMappings);
422 strategy.setProperty(
423 ResolverStrategy.PROPERTY_USE_INTROSPECTION, _useIntrospector);
424 strategy.setProperty(
425 ResolverStrategy.PROPERTY_MAPPING_LOADER, _mappingLoader);
426 strategy.setProperty(
427 ResolverStrategy.PROPERTY_INTROSPECTOR, _introspector);
428 }
429
430
431
432
433
434
435
436
437
438
439
440
441
442
443
444 private static class DescriptorCacheImpl implements ResolverStrategy.ResolverResults {
445
446 private static final Log LOG2 = LogFactory.getLog(DescriptorCacheImpl.class);
447
448 private static final String INTERNAL_CONTAINER_NAME = "-error-if-this-is-used-";
449
450
451 private final List<String> _missingTypes;
452
453
454 private final Map<String, ClassDescriptor> _typeMap;
455
456
457 private final Map<String, List<ClassDescriptor>> _xmlNameMap;
458
459
460 private final ReentrantReadWriteLock _lock;
461
462
463
464
465
466
467 public DescriptorCacheImpl() {
468 super();
469
470 LOG2.debug("New instance!");
471
472 _typeMap = new HashMap<String, ClassDescriptor>();
473 _xmlNameMap = new HashMap<String, List<ClassDescriptor>>();
474 _missingTypes = new ArrayList<String>();
475 _lock = new ReentrantReadWriteLock();
476 }
477
478
479
480
481
482
483
484
485
486
487
488
489
490
491
492
493
494
495
496 public void addDescriptor(final String className, final XMLClassDescriptor descriptor) {
497 if ((className == null) || (className.length() == 0)) {
498 String message = "Class name to insert ClassDescriptor must not be null";
499 LOG2.warn(message);
500 throw new IllegalArgumentException(message);
501 }
502
503
504 _lock.writeLock().lock();
505 try {
506
507 if (descriptor == null) {
508 if (LOG2.isDebugEnabled()) {
509 LOG2.debug("Adding class name to missing classes: " + className);
510 }
511 _missingTypes.add(className);
512 return;
513 }
514
515 if (LOG2.isDebugEnabled()) {
516 LOG2.debug("Adding descriptor class for: "
517 + className + " descriptor: " + descriptor);
518 }
519 _typeMap.put(className, descriptor);
520
521 String xmlName = descriptor.getXMLName();
522
523 if (xmlName == null || xmlName.length() == 0) {
524 return;
525 }
526
527
528 if (INTERNAL_CONTAINER_NAME.equals(xmlName)) {
529 return;
530 }
531
532
533 List<ClassDescriptor> descriptorList = _xmlNameMap.get(xmlName);
534 if (descriptorList == null) {
535 descriptorList = new ArrayList<ClassDescriptor>();
536 _xmlNameMap.put(xmlName, descriptorList);
537 }
538 if (!descriptorList.contains(descriptor)) {
539 descriptorList.add(descriptor);
540 }
541
542 _missingTypes.remove(className);
543 } finally {
544 _lock.writeLock().unlock();
545 }
546 }
547
548
549
550
551
552
553
554
555 public XMLClassDescriptor getDescriptor(final String className) {
556
557
558 _lock.readLock().lock();
559 try {
560
561 if ((className == null)
562 || ("".equals(className))
563 || (_missingTypes.contains(className))) {
564 return null;
565 }
566
567 XMLClassDescriptor ret = (XMLClassDescriptor) _typeMap.get(className);
568 if (LOG2.isDebugEnabled()) {
569 LOG2.debug("Get descriptor for: " + className + " found: " + ret);
570 }
571 return ret;
572 } finally {
573 _lock.readLock().unlock();
574 }
575 }
576
577
578
579
580
581
582
583
584
585
586
587
588 public List<ClassDescriptor> getDescriptors(final String xmlName) {
589
590
591 _lock.readLock().lock();
592 List<ClassDescriptor> list = _xmlNameMap.get(xmlName);
593 _lock.readLock().unlock();
594
595 if (list == null) {
596
597
598 list = new ArrayList<ClassDescriptor>();
599 } else {
600
601
602 list = new ArrayList<ClassDescriptor>(list);
603 }
604 return list;
605 }
606
607
608
609
610
611
612
613
614
615
616
617
618
619
620
621
622
623
624
625 public boolean isMissingDescriptor(final String className) {
626
627
628 _lock.readLock().lock();
629 try {
630 return _missingTypes.contains(className);
631 } finally {
632 _lock.readLock().unlock();
633 }
634 }
635
636
637
638
639
640
641 public void addAllDescriptors(final Map descriptors) {
642 if ((descriptors == null) || (descriptors.isEmpty())) {
643 LOG2.debug("Called addAllDescriptors with null or empty descriptor map");
644 return;
645 }
646
647 for (Iterator<String> iter = descriptors.keySet().iterator(); iter.hasNext(); ) {
648 String clsName = iter.next();
649 this.addDescriptor(clsName, (XMLClassDescriptor) descriptors.get(clsName));
650 }
651 }
652 }
653
654
655
656
657
658 public void cleanDescriptorCache() {
659 _descriptorCache = new DescriptorCacheImpl();
660 }
661 }