< prev index next >

src/java.xml.bind/share/classes/javax/xml/bind/ContextFinder.java

Print this page




  51  * @author <ul><li>Ryan Shoemaker, Sun Microsystems, Inc.</li></ul>
  52  * @see JAXBContext
  53  */
  54 class ContextFinder {
  55 
  56     /**
  57      * When JAXB is in J2SE, rt.jar has to have a JAXB implementation.
  58      * However, rt.jar cannot have META-INF/services/javax.xml.bind.JAXBContext
  59      * because if it has, it will take precedence over any file that applications have
  60      * in their jar files.
  61      *
  62      * <p>
  63      * When the user bundles his own JAXB implementation, we'd like to use it, and we
  64      * want the platform default to be used only when there's no other JAXB provider.
  65      *
  66      * <p>
  67      * For this reason, we have to hard-code the class name into the API.
  68      */
  69     private static final String PLATFORM_DEFAULT_FACTORY_CLASS = "com.sun.xml.internal.bind.v2.ContextFactory";
  70 



  71     private static final Logger logger;
  72 
  73     static {
  74         logger = Logger.getLogger("javax.xml.bind");
  75         try {
  76             if (AccessController.doPrivileged(new GetPropertyAction("jaxb.debug")) != null) {
  77                 // disconnect the logger from a bigger framework (if any)
  78                 // and take the matters into our own hands
  79                 logger.setUseParentHandlers(false);
  80                 logger.setLevel(Level.ALL);
  81                 ConsoleHandler handler = new ConsoleHandler();
  82                 handler.setLevel(Level.ALL);
  83                 logger.addHandler(handler);
  84             } else {
  85                 // don't change the setting of this logger
  86                 // to honor what other frameworks
  87                 // have done on configurations.
  88             }
  89         } catch (Throwable t) {
  90             // just to be extra safe. in particular System.getProperty may throw
  91             // SecurityException.
  92         }
  93     }
  94 







  95     /**
  96      * If the {@link InvocationTargetException} wraps an exception that shouldn't be wrapped,
  97      * throw the wrapped exception.
  98      */
  99     private static void handleInvocationTargetException(InvocationTargetException x) throws JAXBException {
 100         Throwable t = x.getTargetException();
 101         if (t != null) {
 102             if (t instanceof JAXBException)
 103                 // one of our exceptions, just re-throw
 104                 throw (JAXBException) t;
 105             if (t instanceof RuntimeException)
 106                 // avoid wrapping exceptions unnecessarily
 107                 throw (RuntimeException) t;
 108             if (t instanceof Error)
 109                 throw (Error) t;
 110         }
 111     }
 112 
 113 
 114     /**


 258                 x = e.getTargetException();
 259 
 260             throw new JAXBException(x);
 261         }
 262     }
 263 
 264     static JAXBContext find(String factoryId, String contextPath, ClassLoader classLoader, Map properties) throws JAXBException {
 265 
 266         // TODO: do we want/need another layer of searching in $java.home/lib/jaxb.properties like JAXP?
 267 
 268         StringTokenizer packages = new StringTokenizer(contextPath, ":");
 269         if (!packages.hasMoreTokens()) {
 270             // no context is specified
 271             throw new JAXBException(Messages.format(Messages.NO_PACKAGE_IN_CONTEXTPATH));
 272         }
 273 
 274         // search for jaxb.properties in the class loader of each class first
 275         logger.fine("Searching jaxb.properties");
 276         while (packages.hasMoreTokens()) {
 277             // com.acme.foo - > com/acme/foo/jaxb.properties
 278             String className = classNameFromPackageProperties(factoryId, classLoader, packages.nextToken(":").replace('.', '/'));
 279             if (className != null) return newInstance(contextPath, className, classLoader, properties);
 280         }
 281 
 282         String factoryName = classNameFromSystemProperties();
 283         if (factoryName != null) return newInstance(contextPath, factoryName, classLoader, properties);
 284 








 285         Class ctxFactory = (Class) ServiceLoaderUtil.lookupUsingOSGiServiceLoader("javax.xml.bind.JAXBContext", logger);
 286         if (ctxFactory != null) {
 287             return newInstance(contextPath, ctxFactory, classLoader, properties);
 288         }
 289 
 290         // TODO: SPEC change required! This is supposed to be!
 291         // JAXBContext obj = firstByServiceLoader(JAXBContext.class, EXCEPTION_HANDLER);
 292         // if (obj != null) return obj;
 293 
 294         // TODO: Deprecated - SPEC change required!
 295         factoryName = firstByServiceLoaderDeprecated(JAXBContext.class, classLoader);
 296         if (factoryName != null) return newInstance(contextPath, factoryName, classLoader, properties);
 297 
 298         // else no provider found
 299         logger.fine("Trying to create the platform default provider");
 300         return newInstance(contextPath, PLATFORM_DEFAULT_FACTORY_CLASS, classLoader, properties);
 301     }
 302 
 303     static JAXBContext find(Class[] classes, Map properties) throws JAXBException {
 304 
 305         // search for jaxb.properties in the class loader of each class first
 306         logger.fine("Searching jaxb.properties");
 307         for (final Class c : classes) {
 308             // this classloader is used only to load jaxb.properties, so doing this should be safe.
 309             if (c.getPackage() == null) continue;       // this is possible for primitives, arrays, and classes that are loaded by poorly implemented ClassLoaders
 310 
 311             // TODO: do we want to optimize away searching the same package?  org.Foo, org.Bar, com.Baz
 312             // classes from the same package might come from different class loades, so it might be a bad idea
 313             // TODO: it's easier to look things up from the class
 314             // c.getResourceAsStream("jaxb.properties");
 315 
 316             String className = classNameFromPackageProperties(JAXBContext.JAXB_CONTEXT_FACTORY, getClassClassLoader(c), c.getPackage().getName().replace('.', '/'));
 317             if (className != null) return newInstance(classes, properties, className);
 318         }
 319 
 320         String factoryName = classNameFromSystemProperties();
 321         if (factoryName != null) return newInstance(classes, properties, factoryName);
 322 
 323         Class ctxFactoryClass = (Class) ServiceLoaderUtil.lookupUsingOSGiServiceLoader("javax.xml.bind.JAXBContext", logger);
 324         if (ctxFactoryClass != null) {
 325             return newInstance(classes, properties, ctxFactoryClass);
 326         }
 327 
 328         // TODO: to be removed - deprecated!!! Requires SPEC change!!!
 329         String className = firstByServiceLoaderDeprecated(JAXBContext.class, getContextClassLoader());
 330         if (className != null) return newInstance(classes, properties, className);
 331 
 332         //    // TODO: supposed to be:
 333         //    obj = firstByServiceLoader(JAXBContext.class, EXCEPTION_HANDLER);
 334         //    if (obj != null) return obj;


 335 
 336         // else no provider found
 337         logger.fine("Trying to create the platform default provider");
 338         return newInstance(classes, properties, PLATFORM_DEFAULT_FACTORY_CLASS);
 339     }
 340 
 341 
 342     private static String classNameFromPackageProperties(String factoryId, ClassLoader classLoader, String packageName) throws JAXBException {



 343         String resourceName = packageName + "/jaxb.properties";
 344         logger.log(Level.FINE, "Trying to locate {0}", resourceName);
 345         Properties props = loadJAXBProperties(classLoader, resourceName);
 346         if (props != null) {

 347             if (props.containsKey(factoryId)) {
 348                 return props.getProperty(factoryId);
 349             } else {
 350                 throw new JAXBException(Messages.format(Messages.MISSING_PROPERTY, packageName, factoryId));
 351             }
 352         }


 353         return null;
 354     }
 355 
 356     private static String classNameFromSystemProperties() throws JAXBException {
 357         logger.log(Level.FINE, "Checking system property {0}", JAXBContext.JAXB_CONTEXT_FACTORY);
 358         // search for a system property second (javax.xml.bind.JAXBContext)
 359         String factoryClassName = AccessController.doPrivileged(new GetPropertyAction(JAXBContext.JAXB_CONTEXT_FACTORY));
 360         if (factoryClassName != null) {
 361             logger.log(Level.FINE, "  found {0}", factoryClassName);
 362             return factoryClassName;
 363         } else { // leave this here to assure compatibility
 364             logger.fine("  not found");
 365             logger.log(Level.FINE, "Checking system property {0}", JAXBContext.class.getName());
 366             factoryClassName = AccessController.doPrivileged(new GetPropertyAction(JAXBContext.class.getName()));
 367             if (factoryClassName != null) {
 368                 logger.log(Level.FINE, "  found {0}", factoryClassName);
 369                 return factoryClassName;
 370             } else {
 371                 logger.fine("  not found");
 372             }




 373         }
 374         return null;
 375     }
 376 




















 377     private static Properties loadJAXBProperties(ClassLoader classLoader, String propFileName) throws JAXBException {
 378 
 379         Properties props = null;
 380         try {
 381             URL url;
 382             if (classLoader == null)
 383                 url = ClassLoader.getSystemResource(propFileName);
 384             else
 385                 url = classLoader.getResource(propFileName);
 386 
 387             if (url != null) {
 388                 logger.log(Level.FINE, "loading props from {0}", url);
 389                 props = new Properties();
 390                 InputStream is = url.openStream();
 391                 props.load(is);
 392                 is.close();
 393             }
 394         } catch (IOException ioe) {
 395             logger.log(Level.FINE, "Unable to load " + propFileName, ioe);
 396             throw new JAXBException(ioe.toString(), ioe);




  51  * @author <ul><li>Ryan Shoemaker, Sun Microsystems, Inc.</li></ul>
  52  * @see JAXBContext
  53  */
  54 class ContextFinder {
  55 
  56     /**
  57      * When JAXB is in J2SE, rt.jar has to have a JAXB implementation.
  58      * However, rt.jar cannot have META-INF/services/javax.xml.bind.JAXBContext
  59      * because if it has, it will take precedence over any file that applications have
  60      * in their jar files.
  61      *
  62      * <p>
  63      * When the user bundles his own JAXB implementation, we'd like to use it, and we
  64      * want the platform default to be used only when there's no other JAXB provider.
  65      *
  66      * <p>
  67      * For this reason, we have to hard-code the class name into the API.
  68      */
  69     private static final String PLATFORM_DEFAULT_FACTORY_CLASS = "com.sun.xml.internal.bind.v2.ContextFactory";
  70 
  71     // previous value of JAXBContext.JAXB_CONTEXT_FACTORY, using also this to ensure backwards compatibility
  72     private static final String JAXB_CONTEXT_FACTORY_DEPRECATED = "javax.xml.bind.context.factory";
  73 
  74     private static final Logger logger;
  75 
  76     static {
  77         logger = Logger.getLogger("javax.xml.bind");
  78         try {
  79             if (AccessController.doPrivileged(new GetPropertyAction("jaxb.debug")) != null) {
  80                 // disconnect the logger from a bigger framework (if any)
  81                 // and take the matters into our own hands
  82                 logger.setUseParentHandlers(false);
  83                 logger.setLevel(Level.ALL);
  84                 ConsoleHandler handler = new ConsoleHandler();
  85                 handler.setLevel(Level.ALL);
  86                 logger.addHandler(handler);
  87             } else {
  88                 // don't change the setting of this logger
  89                 // to honor what other frameworks
  90                 // have done on configurations.
  91             }
  92         } catch (Throwable t) {
  93             // just to be extra safe. in particular System.getProperty may throw
  94             // SecurityException.
  95         }
  96     }
  97 
  98     private static ServiceLoaderUtil.ExceptionHandler<JAXBException> EXCEPTION_HANDLER = new ServiceLoaderUtil.ExceptionHandler<JAXBException>() {
  99         @Override
 100         public JAXBException createException(Throwable throwable, String message) {
 101             return new JAXBException(message, throwable);
 102         }
 103     };
 104 
 105     /**
 106      * If the {@link InvocationTargetException} wraps an exception that shouldn't be wrapped,
 107      * throw the wrapped exception.
 108      */
 109     private static void handleInvocationTargetException(InvocationTargetException x) throws JAXBException {
 110         Throwable t = x.getTargetException();
 111         if (t != null) {
 112             if (t instanceof JAXBException)
 113                 // one of our exceptions, just re-throw
 114                 throw (JAXBException) t;
 115             if (t instanceof RuntimeException)
 116                 // avoid wrapping exceptions unnecessarily
 117                 throw (RuntimeException) t;
 118             if (t instanceof Error)
 119                 throw (Error) t;
 120         }
 121     }
 122 
 123 
 124     /**


 268                 x = e.getTargetException();
 269 
 270             throw new JAXBException(x);
 271         }
 272     }
 273 
 274     static JAXBContext find(String factoryId, String contextPath, ClassLoader classLoader, Map properties) throws JAXBException {
 275 
 276         // TODO: do we want/need another layer of searching in $java.home/lib/jaxb.properties like JAXP?
 277 
 278         StringTokenizer packages = new StringTokenizer(contextPath, ":");
 279         if (!packages.hasMoreTokens()) {
 280             // no context is specified
 281             throw new JAXBException(Messages.format(Messages.NO_PACKAGE_IN_CONTEXTPATH));
 282         }
 283 
 284         // search for jaxb.properties in the class loader of each class first
 285         logger.fine("Searching jaxb.properties");
 286         while (packages.hasMoreTokens()) {
 287             // com.acme.foo - > com/acme/foo/jaxb.properties
 288             String factoryClassName = classNameFromPackageProperties(classLoader, packages.nextToken(":").replace('.', '/'), factoryId, JAXB_CONTEXT_FACTORY_DEPRECATED);
 289             if (factoryClassName != null) return newInstance(contextPath, factoryClassName, classLoader, properties);
 290         }
 291 
 292         String factoryName = classNameFromSystemProperties();
 293         if (factoryName != null) return newInstance(contextPath, factoryName, classLoader, properties);
 294 
 295         // TODO: SPEC change required! java.util.ServiceLoader
 296         JAXBContextFactory obj = ServiceLoaderUtil.firstByServiceLoader(JAXBContextFactory.class, logger, EXCEPTION_HANDLER);
 297         if (obj != null) return obj.createContext(contextPath, classLoader, properties);
 298 
 299         // to ensure backwards compatibility
 300         factoryName = firstByServiceLoaderDeprecated(JAXBContext.class, classLoader);
 301         if (factoryName != null) return newInstance(contextPath, factoryName, classLoader, properties);
 302 
 303         Class ctxFactory = (Class) ServiceLoaderUtil.lookupUsingOSGiServiceLoader("javax.xml.bind.JAXBContext", logger);
 304         if (ctxFactory != null) {
 305             return newInstance(contextPath, ctxFactory, classLoader, properties);
 306         }
 307 








 308         // else no provider found
 309         logger.fine("Trying to create the platform default provider");
 310         return newInstance(contextPath, PLATFORM_DEFAULT_FACTORY_CLASS, classLoader, properties);
 311     }
 312 
 313     static JAXBContext find(Class<?>[] classes, Map<String, ?> properties) throws JAXBException {
 314 
 315         // search for jaxb.properties in the class loader of each class first
 316         logger.fine("Searching jaxb.properties");
 317         for (final Class c : classes) {
 318             // this classloader is used only to load jaxb.properties, so doing this should be safe.
 319             if (c.getPackage() == null) continue;       // this is possible for primitives, arrays, and classes that are loaded by poorly implemented ClassLoaders
 320 
 321             // TODO: do we want to optimize away searching the same package?  org.Foo, org.Bar, com.Baz
 322             // classes from the same package might come from different class loades, so it might be a bad idea
 323             // TODO: it's easier to look things up from the class
 324             // c.getResourceAsStream("jaxb.properties");
 325 
 326             String factoryClassName = classNameFromPackageProperties(getClassClassLoader(c), c.getPackage().getName().replace('.', '/'), JAXBContext.JAXB_CONTEXT_FACTORY, JAXB_CONTEXT_FACTORY_DEPRECATED);
 327             if (factoryClassName != null) return newInstance(classes, properties, factoryClassName);
 328         }
 329 
 330         String factoryClassName = classNameFromSystemProperties();
 331         if (factoryClassName != null) return newInstance(classes, properties, factoryClassName);
 332 
 333         // TODO: SPEC change required! java.util.ServiceLoader
 334         JAXBContextFactory factory = ServiceLoaderUtil.firstByServiceLoader(JAXBContextFactory.class, logger, EXCEPTION_HANDLER);
 335         if (factory != null) return factory.createContext(classes, properties);

 336 
 337         // to ensure backwards compatibility
 338         String className = firstByServiceLoaderDeprecated(JAXBContext.class, getContextClassLoader());
 339         if (className != null) return newInstance(classes, properties, className);
 340 
 341         logger.fine("Trying to create the platform default provider");
 342         Class ctxFactoryClass = (Class) ServiceLoaderUtil.lookupUsingOSGiServiceLoader("javax.xml.bind.JAXBContext", logger);
 343         if (ctxFactoryClass != null) {
 344             return newInstance(classes, properties, ctxFactoryClass);
 345         }
 346 
 347         // else no provider found
 348         logger.fine("Trying to create the platform default provider");
 349         return newInstance(classes, properties, PLATFORM_DEFAULT_FACTORY_CLASS);
 350     }
 351 
 352 
 353     /**
 354      * first factoryId should be the preffered one, more of those can be provided to support backwards compatibility
 355      */
 356     private static String classNameFromPackageProperties(ClassLoader classLoader, String packageName, String ... factoryIds) throws JAXBException {
 357         String resourceName = packageName + "/jaxb.properties";
 358         logger.log(Level.FINE, "Trying to locate {0}", resourceName);
 359         Properties props = loadJAXBProperties(classLoader, resourceName);
 360         if (props != null) {
 361             for(String factoryId : factoryIds) {
 362                 if (props.containsKey(factoryId)) {
 363                     return props.getProperty(factoryId);


 364                 }
 365             }
 366             throw new JAXBException(Messages.format(Messages.MISSING_PROPERTY, packageName, factoryIds[0]));
 367         }
 368         return null;
 369     }
 370 
 371     private static String classNameFromSystemProperties() throws JAXBException {
 372         String factoryClassName = getSystemProperty(JAXBContext.JAXB_CONTEXT_FACTORY);


 373         if (factoryClassName != null) {

 374             return factoryClassName;
 375         }
 376         // leave this here to assure compatibility
 377         factoryClassName = getDeprecatedSystemProperty(JAXB_CONTEXT_FACTORY_DEPRECATED);

 378         if (factoryClassName != null) {

 379             return factoryClassName;


 380         }
 381         // leave this here to assure compatibility
 382         factoryClassName = getDeprecatedSystemProperty(JAXBContext.class.getName());
 383         if (factoryClassName != null) {
 384             return factoryClassName;
 385         }
 386         return null;
 387     }
 388 
 389     private static String getDeprecatedSystemProperty(String property) {
 390         String value = getSystemProperty(property);
 391         if (value != null) {
 392             logger.log(Level.WARNING, "Using non-standard property: {0}. Property {1} should be used instead.",
 393                     new Object[] {property, JAXBContext.JAXB_CONTEXT_FACTORY});
 394         }
 395         return value;
 396     }
 397 
 398     private static String getSystemProperty(String property) {
 399         logger.log(Level.FINE, "Checking system property {0}", property);
 400         String value = AccessController.doPrivileged(new GetPropertyAction(property));
 401         if (value != null) {
 402             logger.log(Level.FINE, "  found {0}", value);
 403         } else {
 404             logger.log(Level.FINE, "  not found");
 405         }
 406         return value;
 407     }
 408 
 409     private static Properties loadJAXBProperties(ClassLoader classLoader, String propFileName) throws JAXBException {
 410 
 411         Properties props = null;
 412         try {
 413             URL url;
 414             if (classLoader == null)
 415                 url = ClassLoader.getSystemResource(propFileName);
 416             else
 417                 url = classLoader.getResource(propFileName);
 418 
 419             if (url != null) {
 420                 logger.log(Level.FINE, "loading props from {0}", url);
 421                 props = new Properties();
 422                 InputStream is = url.openStream();
 423                 props.load(is);
 424                 is.close();
 425             }
 426         } catch (IOException ioe) {
 427             logger.log(Level.FINE, "Unable to load " + propFileName, ioe);
 428             throw new JAXBException(ioe.toString(), ioe);


< prev index next >