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