001package com.avaje.ebean.config;
002
003
004/**
005 * Helper to find classes taking into account the context class loader.
006 */
007public class ClassLoadConfig {
008
009  protected final ClassLoaderContext context;
010
011  /**
012   * Construct with the default classLoader search with context classLoader first.
013   */
014  public ClassLoadConfig() {
015    this(null);
016  }
017
018  /**
019   * Specify the classLoader to use for class detection and new instance creation.
020   */
021  public ClassLoadConfig(ClassLoader classLoader) {
022    this.context = new ClassLoaderContext(classLoader);
023  }
024
025  /**
026   * Return true if the Java.time types are available and should be supported.
027   */
028  public boolean isJavaTimePresent() {
029    return isPresent("java.time.LocalDate");
030  }
031
032  /**
033   * Return true if the Joda types are available and should be supported.
034   */
035  public boolean isJodaTimePresent() {
036    return isPresent("org.joda.time.LocalDateTime");
037  }
038
039  /**
040   * Return true if javax validation annotations like Size and NotNull are present.
041   */
042  public boolean isJavaxValidationAnnotationsPresent() {
043    return isPresent("javax.validation.constraints.NotNull");
044  }
045
046  /**
047   * Return true if Jackson annotations like JsonIgnore are present.
048   */
049  public boolean isJacksonAnnotationsPresent() {
050    return isPresent("com.fasterxml.jackson.annotation.JsonIgnore");
051  }
052
053  /**
054   * Return true if Jackson ObjectMapper is present.
055   */
056  public boolean isJacksonObjectMapperPresent() {
057    return isPresent("com.fasterxml.jackson.databind.ObjectMapper");
058  }
059
060  /**
061   * Return a new instance of the class using the default constructor.
062   */
063  public Object newInstance(String className) {
064
065    try {
066      Class<?> cls = forName(className);
067      return cls.newInstance();
068    } catch (Exception e) {
069      throw new IllegalArgumentException("Error constructing " + className, e);
070    }
071  }
072
073  /**
074   * Return true if the given class is present.
075   */
076  protected boolean isPresent(String className) {
077    try {
078      forName(className);
079      return true;
080    } catch (Throwable ex) {
081      // Class or one of its dependencies is not present...
082      return false;
083    }
084  }
085
086  /**
087   * Load a class taking into account a context class loader (if present).
088   */
089  protected Class<?> forName(String name) throws ClassNotFoundException {
090    return context.forName(name);
091  }
092
093  /**
094   * Wraps the preferred, caller and context class loaders.
095   */
096  protected class ClassLoaderContext {
097
098    /**
099     * Optional - if set only use this classLoader (no fallback).
100     */
101    protected final ClassLoader preferredLoader;
102
103    protected final ClassLoader contextLoader;
104
105    protected final ClassLoader callerLoader;
106
107    ClassLoaderContext(ClassLoader preferredLoader) {
108      this.preferredLoader = preferredLoader;
109      this.callerLoader = ServerConfig.class.getClassLoader();
110      this.contextLoader = contextLoader();
111    }
112
113    ClassLoader contextLoader() {
114      ClassLoader loader = Thread.currentThread().getContextClassLoader();
115      return (loader != null) ? loader: callerLoader;
116    }
117
118    Class<?> forName(String name) throws ClassNotFoundException {
119
120      if (preferredLoader != null) {
121        // only use the explicitly set classLoader
122        return classForName(name, preferredLoader);
123      }
124      try {
125        // try the context loader first
126        return classForName(name, contextLoader);
127      } catch (ClassNotFoundException e) {
128        if (callerLoader == contextLoader) {
129          throw e;
130        } else {
131          // fallback to the caller classLoader
132          return classForName(name, callerLoader);
133        }
134      }
135    }
136
137    Class<?> classForName(String name, ClassLoader classLoader) throws ClassNotFoundException {
138      return Class.forName(name, true, classLoader);
139    }
140
141  }
142}
143