< 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     /**


 142 
 143         try {
 144             Class spFactory = ServiceLoaderUtil.safeLoadClass(className, PLATFORM_DEFAULT_FACTORY_CLASS, classLoader);
 145             return newInstance(contextPath, spFactory, classLoader, properties);
 146         } catch (ClassNotFoundException x) {
 147             throw new JAXBException(Messages.format(Messages.PROVIDER_NOT_FOUND, className), x);
 148 
 149         } catch (RuntimeException x) {
 150             // avoid wrapping RuntimeException to JAXBException,
 151             // because it indicates a bug in this code.
 152             throw x;
 153         } catch (Exception x) {
 154             // can't catch JAXBException because the method is hidden behind
 155             // reflection.  Root element collisions detected in the call to
 156             // createContext() are reported as JAXBExceptions - just re-throw it
 157             // some other type of exception - just wrap it
 158             throw new JAXBException(Messages.format(Messages.COULD_NOT_INSTANTIATE, className, x), x);
 159         }
 160     }
 161 
 162     static JAXBContext newInstance(String contextPath, Class spFactory, ClassLoader classLoader, Map properties) throws JAXBException {



 163 
 164         try {
 165             /*
 166              * javax.xml.bind.context.factory points to a class which has a
 167              * static method called 'createContext' that
 168              * returns a javax.xml.JAXBContext.
 169              */
 170 
 171             Object context = null;
 172 
 173             // first check the method that takes Map as the third parameter.
 174             // this is added in 2.0.
 175             try {
 176                 Method m = spFactory.getMethod("createContext", String.class, ClassLoader.class, Map.class);
 177                 // any failure in invoking this method would be considered fatal
 178                 context = m.invoke(null, contextPath, classLoader, properties);
 179             } catch (NoSuchMethodException e) {
 180                 // it's not an error for the provider not to have this method.
 181             }
 182 


 222 
 223         Class spi;
 224         try {
 225             spi = ServiceLoaderUtil.safeLoadClass(className, PLATFORM_DEFAULT_FACTORY_CLASS, getContextClassLoader());
 226         } catch (ClassNotFoundException e) {
 227             throw new JAXBException(e);
 228         }
 229 
 230         if (logger.isLoggable(Level.FINE)) {
 231             // extra check to avoid costly which operation if not logged
 232             logger.log(Level.FINE, "loaded {0} from {1}", new Object[]{className, which(spi)});
 233         }
 234 
 235         return newInstance(classes, properties, spi);
 236     }
 237 
 238     static JAXBContext newInstance(Class[] classes,
 239                                    Map properties,
 240                                    Class spFactory) throws JAXBException {
 241         try {

 242             Method m = spFactory.getMethod("createContext", Class[].class, Map.class);
 243             Object context = m.invoke(null, classes, properties);
 244             if (!(context instanceof JAXBContext)) {
 245                 // the cast would fail, so generate an exception with a nice message
 246                 throw handleClassCastException(context.getClass(), JAXBContext.class);
 247             }
 248             return (JAXBContext) context;
 249         } catch (NoSuchMethodException e) {
 250             throw new JAXBException(e);
 251         } catch (IllegalAccessException e) {
 252             throw new JAXBException(e);

 253         } catch (InvocationTargetException e) {
 254             handleInvocationTargetException(e);
 255 
 256             Throwable x = e;
 257             if (e.getTargetException() != null)
 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);
 397         }


 463                         public java.lang.Object run() {
 464                             return c.getClassLoader();
 465                         }
 466                     });
 467         }
 468     }
 469 
 470     private static ClassLoader getSystemClassLoader() {
 471         if (System.getSecurityManager() == null) {
 472             return ClassLoader.getSystemClassLoader();
 473         } else {
 474             return (ClassLoader) java.security.AccessController.doPrivileged(
 475                     new java.security.PrivilegedAction() {
 476                         public java.lang.Object run() {
 477                             return ClassLoader.getSystemClassLoader();
 478                         }
 479                     });
 480         }
 481     }
 482 
 483     // TODO: to be removed - SPEC change required
 484     //    ServiceLoaderUtil.firstByServiceLoaderDeprecated should be used instead.
 485     @Deprecated
 486     static String firstByServiceLoaderDeprecated(Class spiClass, ClassLoader classLoader) throws JAXBException {


 487         final String jaxbContextFQCN = spiClass.getName();
 488 
 489         logger.fine("Searching META-INF/services");
 490 
 491         // search META-INF services next
 492         BufferedReader r = null;
 493         final String resource = new StringBuilder().append("META-INF/services/").append(jaxbContextFQCN).toString();
 494         try {
 495             final InputStream resourceStream =
 496                     (classLoader == null) ?
 497                             ClassLoader.getSystemResourceAsStream(resource) :
 498                             classLoader.getResourceAsStream(resource);
 499 
 500             if (resourceStream != null) {
 501                 r = new BufferedReader(new InputStreamReader(resourceStream, "UTF-8"));
 502                 String factoryClassName = r.readLine();
 503                 if (factoryClassName != null) {
 504                     factoryClassName = factoryClassName.trim();
 505                 }
 506                 r.close();
 507                 logger.log(Level.FINE, "Configured factorty class:{0}", factoryClassName);
 508                 return factoryClassName;
 509             } else {
 510                 logger.log(Level.FINE, "Unable to load:{0}", resource);
 511                 return null;
 512             }
 513         } catch (UnsupportedEncodingException e) {
 514             // should never happen
 515             throw new JAXBException(e);
 516         } catch (IOException e) {
 517             throw new JAXBException(e);
 518         } finally {
 519             try {
 520                 if (r != null) {
 521                     r.close();
 522                 }
 523             } catch (IOException ex) {
 524                 logger.log(Level.SEVERE, "Unable to close resource: " + resource, ex);
 525             }
 526         }
 527     }
 528 
 529 }


  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 =
  99             new ServiceLoaderUtil.ExceptionHandler<JAXBException>() {
 100                 @Override
 101                 public JAXBException createException(Throwable throwable, String message) {
 102                     return new JAXBException(message, throwable);
 103                 }
 104             };
 105 
 106     /**
 107      * If the {@link InvocationTargetException} wraps an exception that shouldn't be wrapped,
 108      * throw the wrapped exception.
 109      */
 110     private static void handleInvocationTargetException(InvocationTargetException x) throws JAXBException {
 111         Throwable t = x.getTargetException();
 112         if (t != null) {
 113             if (t instanceof JAXBException)
 114                 // one of our exceptions, just re-throw
 115                 throw (JAXBException) t;
 116             if (t instanceof RuntimeException)
 117                 // avoid wrapping exceptions unnecessarily
 118                 throw (RuntimeException) t;
 119             if (t instanceof Error)
 120                 throw (Error) t;
 121         }
 122     }
 123 
 124 
 125     /**


 153 
 154         try {
 155             Class spFactory = ServiceLoaderUtil.safeLoadClass(className, PLATFORM_DEFAULT_FACTORY_CLASS, classLoader);
 156             return newInstance(contextPath, spFactory, classLoader, properties);
 157         } catch (ClassNotFoundException x) {
 158             throw new JAXBException(Messages.format(Messages.PROVIDER_NOT_FOUND, className), x);
 159 
 160         } catch (RuntimeException x) {
 161             // avoid wrapping RuntimeException to JAXBException,
 162             // because it indicates a bug in this code.
 163             throw x;
 164         } catch (Exception x) {
 165             // can't catch JAXBException because the method is hidden behind
 166             // reflection.  Root element collisions detected in the call to
 167             // createContext() are reported as JAXBExceptions - just re-throw it
 168             // some other type of exception - just wrap it
 169             throw new JAXBException(Messages.format(Messages.COULD_NOT_INSTANTIATE, className, x), x);
 170         }
 171     }
 172 
 173     static JAXBContext newInstance(String contextPath,
 174                                    Class spFactory,
 175                                    ClassLoader classLoader,
 176                                    Map properties) throws JAXBException {
 177 
 178         try {
 179             /*
 180              * javax.xml.bind.context.factory points to a class which has a
 181              * static method called 'createContext' that
 182              * returns a javax.xml.JAXBContext.
 183              */
 184 
 185             Object context = null;
 186 
 187             // first check the method that takes Map as the third parameter.
 188             // this is added in 2.0.
 189             try {
 190                 Method m = spFactory.getMethod("createContext", String.class, ClassLoader.class, Map.class);
 191                 // any failure in invoking this method would be considered fatal
 192                 context = m.invoke(null, contextPath, classLoader, properties);
 193             } catch (NoSuchMethodException e) {
 194                 // it's not an error for the provider not to have this method.
 195             }
 196 


 236 
 237         Class spi;
 238         try {
 239             spi = ServiceLoaderUtil.safeLoadClass(className, PLATFORM_DEFAULT_FACTORY_CLASS, getContextClassLoader());
 240         } catch (ClassNotFoundException e) {
 241             throw new JAXBException(e);
 242         }
 243 
 244         if (logger.isLoggable(Level.FINE)) {
 245             // extra check to avoid costly which operation if not logged
 246             logger.log(Level.FINE, "loaded {0} from {1}", new Object[]{className, which(spi)});
 247         }
 248 
 249         return newInstance(classes, properties, spi);
 250     }
 251 
 252     static JAXBContext newInstance(Class[] classes,
 253                                    Map properties,
 254                                    Class spFactory) throws JAXBException {
 255         try {
 256 
 257             Method m = spFactory.getMethod("createContext", Class[].class, Map.class);
 258             Object context = m.invoke(null, classes, properties);
 259             if (!(context instanceof JAXBContext)) {
 260                 // the cast would fail, so generate an exception with a nice message
 261                 throw handleClassCastException(context.getClass(), JAXBContext.class);
 262             }
 263             return (JAXBContext) context;
 264 
 265         } catch (NoSuchMethodException | IllegalAccessException e) {

 266             throw new JAXBException(e);
 267 
 268         } catch (InvocationTargetException e) {
 269             handleInvocationTargetException(e);
 270 
 271             Throwable x = e;
 272             if (e.getTargetException() != null)
 273                 x = e.getTargetException();
 274 
 275             throw new JAXBException(x);
 276         }
 277     }
 278 
 279     static JAXBContext find(String factoryId,
 280                             String contextPath,
 281                             ClassLoader classLoader,
 282                             Map properties) throws JAXBException {
 283 
 284         StringTokenizer packages = new StringTokenizer(contextPath, ":");
 285         if (!packages.hasMoreTokens()) {
 286             // no context is specified
 287             throw new JAXBException(Messages.format(Messages.NO_PACKAGE_IN_CONTEXTPATH));
 288         }
 289 
 290         // search for jaxb.properties in the class loader of each class first
 291         logger.fine("Searching jaxb.properties");
 292         while (packages.hasMoreTokens()) {
 293             // com.acme.foo - > com/acme/foo/jaxb.properties
 294             String factoryClassName =
 295                     classNameFromPackageProperties(
 296                         classLoader,
 297                         packages.nextToken(":").replace('.', '/'),
 298                         factoryId,
 299                         JAXB_CONTEXT_FACTORY_DEPRECATED);
 300 
 301             if (factoryClassName != null) {
 302                 return newInstance(contextPath, factoryClassName, classLoader, properties);
 303             }
 304         }
 305 
 306         String factoryName = classNameFromSystemProperties();
 307         if (factoryName != null) return newInstance(contextPath, factoryName, classLoader, properties);
 308 
 309         JAXBContextFactory obj = ServiceLoaderUtil.firstByServiceLoader(
 310                 JAXBContextFactory.class, logger, EXCEPTION_HANDLER);


 311 
 312         if (obj != null) return obj.createContext(contextPath, classLoader, properties);


 313 
 314         // to ensure backwards compatibility
 315         factoryName = firstByServiceLoaderDeprecated(JAXBContext.class, classLoader);
 316         if (factoryName != null) return newInstance(contextPath, factoryName, classLoader, properties);
 317 
 318         Class ctxFactory = (Class) ServiceLoaderUtil.lookupUsingOSGiServiceLoader(
 319                 "javax.xml.bind.JAXBContext", logger);
 320 
 321         if (ctxFactory != null) {
 322             return newInstance(contextPath, ctxFactory, classLoader, properties);
 323         }
 324 
 325         // else no provider found
 326         logger.fine("Trying to create the platform default provider");
 327         return newInstance(contextPath, PLATFORM_DEFAULT_FACTORY_CLASS, classLoader, properties);
 328     }
 329 
 330     static JAXBContext find(Class<?>[] classes, Map<String, ?> properties) throws JAXBException {
 331 
 332         // search for jaxb.properties in the class loader of each class first
 333         logger.fine("Searching jaxb.properties");
 334         for (final Class c : classes) {
 335             // this classloader is used only to load jaxb.properties, so doing this should be safe.
 336             // this is possible for primitives, arrays, and classes that are
 337             // loaded by poorly implemented ClassLoaders
 338             if (c.getPackage() == null) continue;
 339 
 340             // TODO: do we want to optimize away searching the same package?  org.Foo, org.Bar, com.Baz
 341             // classes from the same package might come from different class loades, so it might be a bad idea
 342             // TODO: it's easier to look things up from the class
 343             // c.getResourceAsStream("jaxb.properties");
 344 
 345             String factoryClassName =
 346                     classNameFromPackageProperties(
 347                             getClassClassLoader(c),
 348                             c.getPackage().getName().replace('.', '/'),
 349                             JAXBContext.JAXB_CONTEXT_FACTORY, JAXB_CONTEXT_FACTORY_DEPRECATED);
 350 
 351             if (factoryClassName != null) return newInstance(classes, properties, factoryClassName);
 352         }
 353 
 354         String factoryClassName = classNameFromSystemProperties();
 355         if (factoryClassName != null) return newInstance(classes, properties, factoryClassName);
 356 
 357         JAXBContextFactory factory =
 358                 ServiceLoaderUtil.firstByServiceLoader(JAXBContextFactory.class, logger, EXCEPTION_HANDLER);
 359 
 360         if (factory != null) return factory.createContext(classes, properties);
 361 
 362         // to ensure backwards compatibility
 363         String className = firstByServiceLoaderDeprecated(JAXBContext.class, getContextClassLoader());
 364         if (className != null) return newInstance(classes, properties, className);
 365 
 366         logger.fine("Trying to create the platform default provider");
 367         Class ctxFactoryClass =
 368                 (Class) ServiceLoaderUtil.lookupUsingOSGiServiceLoader("javax.xml.bind.JAXBContext", logger);
 369 
 370         if (ctxFactoryClass != null) {
 371             return newInstance(classes, properties, ctxFactoryClass);
 372         }
 373 
 374         // else no provider found
 375         logger.fine("Trying to create the platform default provider");
 376         return newInstance(classes, properties, PLATFORM_DEFAULT_FACTORY_CLASS);
 377     }
 378 
 379 
 380     /**
 381      * first factoryId should be the preffered one,
 382      * more of those can be provided to support backwards compatibility
 383      */
 384     private static String classNameFromPackageProperties(ClassLoader classLoader,
 385                                                          String packageName,
 386                                                          String ... factoryIds) throws JAXBException {
 387 
 388         String resourceName = packageName + "/jaxb.properties";
 389         logger.log(Level.FINE, "Trying to locate {0}", resourceName);
 390         Properties props = loadJAXBProperties(classLoader, resourceName);
 391         if (props != null) {
 392             for(String factoryId : factoryIds) {
 393                 if (props.containsKey(factoryId)) {
 394                     return props.getProperty(factoryId);


 395                 }
 396             }
 397             throw new JAXBException(Messages.format(Messages.MISSING_PROPERTY, packageName, factoryIds[0]));
 398         }
 399         return null;
 400     }
 401 
 402     private static String classNameFromSystemProperties() throws JAXBException {
 403 
 404         String factoryClassName = getSystemProperty(JAXBContext.JAXB_CONTEXT_FACTORY);

 405         if (factoryClassName != null) {

 406             return factoryClassName;
 407         }
 408         // leave this here to assure compatibility
 409         factoryClassName = getDeprecatedSystemProperty(JAXB_CONTEXT_FACTORY_DEPRECATED);

 410         if (factoryClassName != null) {

 411             return factoryClassName;


 412         }
 413         // leave this here to assure compatibility
 414         factoryClassName = getDeprecatedSystemProperty(JAXBContext.class.getName());
 415         if (factoryClassName != null) {
 416             return factoryClassName;
 417         }
 418         return null;
 419     }
 420 
 421     private static String getDeprecatedSystemProperty(String property) {
 422         String value = getSystemProperty(property);
 423         if (value != null) {
 424             logger.log(Level.WARNING, "Using non-standard property: {0}. Property {1} should be used instead.",
 425                     new Object[] {property, JAXBContext.JAXB_CONTEXT_FACTORY});
 426         }
 427         return value;
 428     }
 429 
 430     private static String getSystemProperty(String property) {
 431         logger.log(Level.FINE, "Checking system property {0}", property);
 432         String value = AccessController.doPrivileged(new GetPropertyAction(property));
 433         if (value != null) {
 434             logger.log(Level.FINE, "  found {0}", value);
 435         } else {
 436             logger.log(Level.FINE, "  not found");
 437         }
 438         return value;
 439     }
 440 
 441     private static Properties loadJAXBProperties(ClassLoader classLoader,
 442                                                  String propFileName) throws JAXBException {
 443 
 444         Properties props = null;
 445         try {
 446             URL url;
 447             if (classLoader == null)
 448                 url = ClassLoader.getSystemResource(propFileName);
 449             else
 450                 url = classLoader.getResource(propFileName);
 451 
 452             if (url != null) {
 453                 logger.log(Level.FINE, "loading props from {0}", url);
 454                 props = new Properties();
 455                 InputStream is = url.openStream();
 456                 props.load(is);
 457                 is.close();
 458             }
 459         } catch (IOException ioe) {
 460             logger.log(Level.FINE, "Unable to load " + propFileName, ioe);
 461             throw new JAXBException(ioe.toString(), ioe);
 462         }


 528                         public java.lang.Object run() {
 529                             return c.getClassLoader();
 530                         }
 531                     });
 532         }
 533     }
 534 
 535     private static ClassLoader getSystemClassLoader() {
 536         if (System.getSecurityManager() == null) {
 537             return ClassLoader.getSystemClassLoader();
 538         } else {
 539             return (ClassLoader) java.security.AccessController.doPrivileged(
 540                     new java.security.PrivilegedAction() {
 541                         public java.lang.Object run() {
 542                             return ClassLoader.getSystemClassLoader();
 543                         }
 544                     });
 545         }
 546     }
 547 

 548     // ServiceLoaderUtil.firstByServiceLoaderDeprecated should be used instead.
 549     @Deprecated
 550     static String firstByServiceLoaderDeprecated(Class spiClass,
 551                                                  ClassLoader classLoader) throws JAXBException {
 552 
 553         final String jaxbContextFQCN = spiClass.getName();
 554 
 555         logger.fine("Searching META-INF/services");
 556 
 557         // search META-INF services next
 558         BufferedReader r = null;
 559         final String resource = "META-INF/services/" + jaxbContextFQCN;
 560         try {
 561             final InputStream resourceStream =
 562                     (classLoader == null) ?
 563                             ClassLoader.getSystemResourceAsStream(resource) :
 564                             classLoader.getResourceAsStream(resource);
 565 
 566             if (resourceStream != null) {
 567                 r = new BufferedReader(new InputStreamReader(resourceStream, "UTF-8"));
 568                 String factoryClassName = r.readLine();
 569                 if (factoryClassName != null) {
 570                     factoryClassName = factoryClassName.trim();
 571                 }
 572                 r.close();
 573                 logger.log(Level.FINE, "Configured factorty class:{0}", factoryClassName);
 574                 return factoryClassName;
 575             } else {
 576                 logger.log(Level.FINE, "Unable to load:{0}", resource);
 577                 return null;
 578             }



 579         } catch (IOException e) {
 580             throw new JAXBException(e);
 581         } finally {
 582             try {
 583                 if (r != null) {
 584                     r.close();
 585                 }
 586             } catch (IOException ex) {
 587                 logger.log(Level.SEVERE, "Unable to close resource: " + resource, ex);
 588             }
 589         }
 590     }
 591 
 592 }
< prev index next >