1
40
41 package javax.xml.bind;
42
43 import java.io.BufferedReader;
44 import java.io.IOException;
45 import java.io.InputStream;
46 import java.io.InputStreamReader;
47 import java.lang.reflect.InvocationTargetException;
48 import java.lang.reflect.Method;
49 import java.net.URL;
50 import java.security.AccessController;
51 import java.security.PrivilegedActionException;
52 import java.security.PrivilegedExceptionAction;
53 import java.util.Map;
54 import java.util.Properties;
55 import java.util.StringTokenizer;
56 import java.util.logging.ConsoleHandler;
57 import java.util.logging.Level;
58 import java.util.logging.Logger;
59
60
61
70 class ContextFinder {
71
72
85 private static final String PLATFORM_DEFAULT_FACTORY_CLASS = "com.sun.xml.internal.bind.v2.ContextFactory";
86
87
88 private static final String JAXB_CONTEXT_FACTORY_DEPRECATED = "javax.xml.bind.context.factory";
89
90 private static final Logger logger;
91
92 static {
93 logger = Logger.getLogger("javax.xml.bind");
94 try {
95 if (AccessController.doPrivileged(new GetPropertyAction("jaxb.debug")) != null) {
96
97
98 logger.setUseParentHandlers(false);
99 logger.setLevel(Level.ALL);
100 ConsoleHandler handler = new ConsoleHandler();
101 handler.setLevel(Level.ALL);
102 logger.addHandler(handler);
103 } else {
104
105
106
107 }
108 } catch (Throwable t) {
109
110
111 }
112 }
113
114 private static ServiceLoaderUtil.ExceptionHandler<JAXBException> EXCEPTION_HANDLER =
115 new ServiceLoaderUtil.ExceptionHandler<JAXBException>() {
116 @Override
117 public JAXBException createException(Throwable throwable, String message) {
118 return new JAXBException(message, throwable);
119 }
120 };
121
122
126 private static Throwable handleInvocationTargetException(InvocationTargetException x) throws JAXBException {
127 Throwable t = x.getTargetException();
128 if (t != null) {
129 if (t instanceof JAXBException)
130
131 throw (JAXBException) t;
132 if (t instanceof RuntimeException)
133
134 throw (RuntimeException) t;
135 if (t instanceof Error)
136 throw (Error) t;
137 return t;
138 }
139 return x;
140 }
141
142
143
154 private static JAXBException handleClassCastException(Class originalType, Class targetType) {
155 final URL targetTypeURL = which(targetType);
156
157 return new JAXBException(Messages.format(Messages.ILLEGAL_CAST,
158
159
160 getClassClassLoader(originalType).getResource("javax/xml/bind/JAXBContext.class"),
161 targetTypeURL));
162 }
163
164
167 static JAXBContext newInstance(String contextPath,
168 Class[] contextPathClasses,
169 String className,
170 ClassLoader classLoader,
171 Map properties) throws JAXBException {
172
173 try {
174 Class spFactory = ServiceLoaderUtil.safeLoadClass(className, PLATFORM_DEFAULT_FACTORY_CLASS, classLoader);
175 return newInstance(contextPath, contextPathClasses, spFactory, classLoader, properties);
176 } catch (ClassNotFoundException x) {
177 throw new JAXBException(Messages.format(Messages.DEFAULT_PROVIDER_NOT_FOUND), x);
178
179 } catch (RuntimeException | JAXBException x) {
180
181
182
183 throw x;
184 } catch (Exception x) {
185
186
187
188
189 throw new JAXBException(Messages.format(Messages.COULD_NOT_INSTANTIATE, className, x), x);
190 }
191 }
192
193 static JAXBContext newInstance(String contextPath,
194 Class[] contextPathClasses,
195 Class spFactory,
196 ClassLoader classLoader,
197 Map properties) throws JAXBException {
198
199 try {
200
201 ModuleUtil.delegateAddOpensToImplModule(contextPathClasses, spFactory);
202
203
208
209 Object context = null;
210
211
212
213 try {
214 Method m = spFactory.getMethod("createContext", String.class, ClassLoader.class, Map.class);
215
216 Object obj = instantiateProviderIfNecessary(spFactory);
217 context = m.invoke(obj, contextPath, classLoader, properties);
218 } catch (NoSuchMethodException ignored) {
219
220 }
221
222 if (context == null) {
223
224
225 Method m = spFactory.getMethod("createContext", String.class, ClassLoader.class);
226 Object obj = instantiateProviderIfNecessary(spFactory);
227
228 context = m.invoke(obj, contextPath, classLoader);
229 }
230
231 if (!(context instanceof JAXBContext)) {
232
233 throw handleClassCastException(context.getClass(), JAXBContext.class);
234 }
235
236 return (JAXBContext) context;
237 } catch (InvocationTargetException x) {
238
239
240 Throwable e = handleInvocationTargetException(x);
241 throw new JAXBException(Messages.format(Messages.COULD_NOT_INSTANTIATE, spFactory, e), e);
242
243 } catch (Exception x) {
244
245
246
247
248 throw new JAXBException(Messages.format(Messages.COULD_NOT_INSTANTIATE, spFactory, x), x);
249 }
250 }
251
252 private static Object instantiateProviderIfNecessary(final Class<?> implClass) throws JAXBException {
253 try {
254 if (JAXBContextFactory.class.isAssignableFrom(implClass)) {
255 return AccessController.doPrivileged(new PrivilegedExceptionAction<Object>() {
256 @Override
257 public Object run() throws Exception {
258 return implClass.newInstance();
259 }
260 });
261 }
262 return null;
263 } catch (PrivilegedActionException x) {
264 Throwable e = (x.getCause() == null) ? x : x.getCause();
265 throw new JAXBException(Messages.format(Messages.COULD_NOT_INSTANTIATE, implClass, e), e);
266 }
267 }
268
269
272 static JAXBContext newInstance(Class[] classes, Map properties, String className) throws JAXBException {
273
274 Class spi;
275 try {
276 spi = ServiceLoaderUtil.safeLoadClass(className, PLATFORM_DEFAULT_FACTORY_CLASS, getContextClassLoader());
277 } catch (ClassNotFoundException e) {
278 throw new JAXBException(Messages.format(Messages.DEFAULT_PROVIDER_NOT_FOUND), e);
279 }
280
281 if (logger.isLoggable(Level.FINE)) {
282
283 logger.log(Level.FINE, "loaded {0} from {1}", new Object[]{className, which(spi)});
284 }
285
286 return newInstance(classes, properties, spi);
287 }
288
289 static JAXBContext newInstance(Class[] classes,
290 Map properties,
291 Class spFactory) throws JAXBException {
292 try {
293 ModuleUtil.delegateAddOpensToImplModule(classes, spFactory);
294
295 Method m = spFactory.getMethod("createContext", Class[].class, Map.class);
296 Object obj = instantiateProviderIfNecessary(spFactory);
297 Object context = m.invoke(obj, classes, properties);
298 if (!(context instanceof JAXBContext)) {
299
300 throw handleClassCastException(context.getClass(), JAXBContext.class);
301 }
302 return (JAXBContext) context;
303
304 } catch (NoSuchMethodException | IllegalAccessException e) {
305 throw new JAXBException(e);
306 } catch (InvocationTargetException e) {
307
308
309 Throwable x = handleInvocationTargetException(e);
310
311 throw new JAXBException(x);
312 }
313 }
314
315 static JAXBContext find(String factoryId,
316 String contextPath,
317 ClassLoader classLoader,
318 Map properties) throws JAXBException {
319
320 if (contextPath == null || contextPath.isEmpty()) {
321
322 throw new JAXBException(Messages.format(Messages.NO_PACKAGE_IN_CONTEXTPATH));
323 }
324
325
326 Class[] contextPathClasses = ModuleUtil.getClassesFromContextPath(contextPath, classLoader);
327
328
329 String factoryClassName = jaxbProperties(contextPath, classLoader, factoryId);
330 if (factoryClassName == null && contextPathClasses != null) {
331
332 factoryClassName = jaxbProperties(contextPathClasses, factoryId);
333 }
334
335 if (factoryClassName != null) {
336 return newInstance(contextPath, contextPathClasses, factoryClassName, classLoader, properties);
337 }
338
339
340 String factoryName = classNameFromSystemProperties();
341 if (factoryName != null) return newInstance(contextPath, contextPathClasses, factoryName, classLoader, properties);
342
343 JAXBContextFactory obj = ServiceLoaderUtil.firstByServiceLoader(
344 JAXBContextFactory.class, logger, EXCEPTION_HANDLER);
345
346 if (obj != null) {
347 ModuleUtil.delegateAddOpensToImplModule(contextPathClasses, obj.getClass());
348 return obj.createContext(contextPath, classLoader, properties);
349 }
350
351
352 factoryName = firstByServiceLoaderDeprecated(JAXBContext.class, classLoader);
353 if (factoryName != null) return newInstance(contextPath, contextPathClasses, factoryName, classLoader, properties);
354
355 Class ctxFactory = (Class) ServiceLoaderUtil.lookupUsingOSGiServiceLoader(
356 "javax.xml.bind.JAXBContext", logger);
357
358 if (ctxFactory != null) {
359 return newInstance(contextPath, contextPathClasses, ctxFactory, classLoader, properties);
360 }
361
362
363 logger.fine("Trying to create the platform default provider");
364 return newInstance(contextPath, contextPathClasses, PLATFORM_DEFAULT_FACTORY_CLASS, classLoader, properties);
365 }
366
367 static JAXBContext find(Class<?>[] classes, Map<String, ?> properties) throws JAXBException {
368
369
370 logger.fine("Searching jaxb.properties");
371 for (final Class c : classes) {
372
373
374
375 if (c.getPackage() == null) continue;
376
377
378
379
380
381
382 URL jaxbPropertiesUrl = getResourceUrl(c, "jaxb.properties");
383
384 if (jaxbPropertiesUrl != null) {
385
386 String factoryClassName =
387 classNameFromPackageProperties(
388 jaxbPropertiesUrl,
389 JAXBContext.JAXB_CONTEXT_FACTORY, JAXB_CONTEXT_FACTORY_DEPRECATED);
390
391 return newInstance(classes, properties, factoryClassName);
392 }
393
394 }
395
396 String factoryClassName = classNameFromSystemProperties();
397 if (factoryClassName != null) return newInstance(classes, properties, factoryClassName);
398
399 JAXBContextFactory factory =
400 ServiceLoaderUtil.firstByServiceLoader(JAXBContextFactory.class, logger, EXCEPTION_HANDLER);
401
402 if (factory != null) {
403 ModuleUtil.delegateAddOpensToImplModule(classes, factory.getClass());
404 return factory.createContext(classes, properties);
405 }
406
407
408 String className = firstByServiceLoaderDeprecated(JAXBContext.class, getContextClassLoader());
409 if (className != null) return newInstance(classes, properties, className);
410
411 logger.fine("Trying to create the platform default provider");
412 Class ctxFactoryClass =
413 (Class) ServiceLoaderUtil.lookupUsingOSGiServiceLoader("javax.xml.bind.JAXBContext", logger);
414
415 if (ctxFactoryClass != null) {
416 return newInstance(classes, properties, ctxFactoryClass);
417 }
418
419
420 logger.fine("Trying to create the platform default provider");
421 return newInstance(classes, properties, PLATFORM_DEFAULT_FACTORY_CLASS);
422 }
423
424
425
429 private static String classNameFromPackageProperties(URL packagePropertiesUrl,
430 String ... factoryIds) throws JAXBException {
431
432 logger.log(Level.FINE, "Trying to locate {0}", packagePropertiesUrl.toString());
433 Properties props = loadJAXBProperties(packagePropertiesUrl);
434 for(String factoryId : factoryIds) {
435 if (props.containsKey(factoryId)) {
436 return props.getProperty(factoryId);
437 }
438 }
439
440 String propertiesUrl = packagePropertiesUrl.toExternalForm();
441 String packageName = propertiesUrl.substring(0, propertiesUrl.indexOf("/jaxb.properties"));
442 throw new JAXBException(Messages.format(Messages.MISSING_PROPERTY, packageName, factoryIds[0]));
443 }
444
445 private static String classNameFromSystemProperties() throws JAXBException {
446
447 String factoryClassName = getSystemProperty(JAXBContext.JAXB_CONTEXT_FACTORY);
448 if (factoryClassName != null) {
449 return factoryClassName;
450 }
451
452 factoryClassName = getDeprecatedSystemProperty(JAXB_CONTEXT_FACTORY_DEPRECATED);
453 if (factoryClassName != null) {
454 return factoryClassName;
455 }
456
457 factoryClassName = getDeprecatedSystemProperty(JAXBContext.class.getName());
458 if (factoryClassName != null) {
459 return factoryClassName;
460 }
461 return null;
462 }
463
464 private static String getDeprecatedSystemProperty(String property) {
465 String value = getSystemProperty(property);
466 if (value != null) {
467 logger.log(Level.WARNING, "Using non-standard property: {0}. Property {1} should be used instead.",
468 new Object[] {property, JAXBContext.JAXB_CONTEXT_FACTORY});
469 }
470 return value;
471 }
472
473 private static String getSystemProperty(String property) {
474 logger.log(Level.FINE, "Checking system property {0}", property);
475 String value = AccessController.doPrivileged(new GetPropertyAction(property));
476 if (value != null) {
477 logger.log(Level.FINE, " found {0}", value);
478 } else {
479 logger.log(Level.FINE, " not found");
480 }
481 return value;
482 }
483
484 private static Properties loadJAXBProperties(URL url) throws JAXBException {
485
486 try {
487 Properties props;
488 logger.log(Level.FINE, "loading props from {0}", url);
489 props = new Properties();
490 InputStream is = url.openStream();
491 props.load(is);
492 is.close();
493 return props;
494 } catch (IOException ioe) {
495 logger.log(Level.FINE, "Unable to load " + url.toString(), ioe);
496 throw new JAXBException(ioe.toString(), ioe);
497 }
498 }
499
500
507 private static URL getResourceUrl(ClassLoader classLoader, String resourceName) {
508 URL url;
509 if (classLoader == null)
510 url = ClassLoader.getSystemResource(resourceName);
511 else
512 url = classLoader.getResource(resourceName);
513 return url;
514 }
515
516 private static URL getResourceUrl(Class<?> clazz, String resourceName) {
517 return clazz.getResource(resourceName);
518 }
519
520
521
533 static URL which(Class clazz, ClassLoader loader) {
534
535 String classnameAsResource = clazz.getName().replace('.', '/') + ".class";
536
537 if (loader == null) {
538 loader = getSystemClassLoader();
539 }
540
541 return loader.getResource(classnameAsResource);
542 }
543
544
556 static URL which(Class clazz) {
557 return which(clazz, getClassClassLoader(clazz));
558 }
559
560 @SuppressWarnings("unchecked")
561 private static ClassLoader getContextClassLoader() {
562 if (System.getSecurityManager() == null) {
563 return Thread.currentThread().getContextClassLoader();
564 } else {
565 return (ClassLoader) java.security.AccessController.doPrivileged(
566 new java.security.PrivilegedAction() {
567 @Override
568 public java.lang.Object run() {
569 return Thread.currentThread().getContextClassLoader();
570 }
571 });
572 }
573 }
574
575 @SuppressWarnings("unchecked")
576 private static ClassLoader getClassClassLoader(final Class c) {
577 if (System.getSecurityManager() == null) {
578 return c.getClassLoader();
579 } else {
580 return (ClassLoader) java.security.AccessController.doPrivileged(
581 new java.security.PrivilegedAction() {
582 @Override
583 public java.lang.Object run() {
584 return c.getClassLoader();
585 }
586 });
587 }
588 }
589
590 private static ClassLoader getSystemClassLoader() {
591 if (System.getSecurityManager() == null) {
592 return ClassLoader.getSystemClassLoader();
593 } else {
594 return (ClassLoader) java.security.AccessController.doPrivileged(
595 new java.security.PrivilegedAction() {
596 @Override
597 public java.lang.Object run() {
598 return ClassLoader.getSystemClassLoader();
599 }
600 });
601 }
602 }
603
604
605 @Deprecated
606 static String firstByServiceLoaderDeprecated(Class spiClass,
607 ClassLoader classLoader) throws JAXBException {
608
609 final String jaxbContextFQCN = spiClass.getName();
610
611 logger.fine("Searching META-INF/services");
612
613
614 BufferedReader r = null;
615 final String resource = "META-INF/services/" + jaxbContextFQCN;
616 try {
617 final InputStream resourceStream =
618 (classLoader == null) ?
619 ClassLoader.getSystemResourceAsStream(resource) :
620 classLoader.getResourceAsStream(resource);
621
622 if (resourceStream != null) {
623 r = new BufferedReader(new InputStreamReader(resourceStream, "UTF-8"));
624 String factoryClassName = r.readLine();
625 if (factoryClassName != null) {
626 factoryClassName = factoryClassName.trim();
627 }
628 r.close();
629 logger.log(Level.FINE, "Configured factorty class:{0}", factoryClassName);
630 return factoryClassName;
631 } else {
632 logger.log(Level.FINE, "Unable to load:{0}", resource);
633 return null;
634 }
635 } catch (IOException e) {
636 throw new JAXBException(e);
637 } finally {
638 try {
639 if (r != null) {
640 r.close();
641 }
642 } catch (IOException ex) {
643 logger.log(Level.SEVERE, "Unable to close resource: " + resource, ex);
644 }
645 }
646 }
647
648 private static String jaxbProperties(String contextPath, ClassLoader classLoader, String factoryId) throws JAXBException {
649 String[] packages = contextPath.split(":");
650
651 for (String pkg : packages) {
652 String pkgUrl = pkg.replace('.', '/');
653 URL jaxbPropertiesUrl = getResourceUrl(classLoader, pkgUrl + "/jaxb.properties");
654 if (jaxbPropertiesUrl != null) {
655 return classNameFromPackageProperties(jaxbPropertiesUrl,
656 factoryId, JAXB_CONTEXT_FACTORY_DEPRECATED);
657 }
658 }
659 return null;
660 }
661
662 private static String jaxbProperties(Class[] classesFromContextPath, String factoryId) throws JAXBException {
663 for (Class c : classesFromContextPath) {
664 URL jaxbPropertiesUrl = getResourceUrl(c, "jaxb.properties");
665 if (jaxbPropertiesUrl != null) {
666 return classNameFromPackageProperties(jaxbPropertiesUrl, factoryId, JAXB_CONTEXT_FACTORY_DEPRECATED);
667 }
668 }
669 return null;
670 }
671
672 }
673