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   * Return the classLoader to use for service loading etc.
095   */
096  public ClassLoader getClassLoader() {
097    return context.getClassLoader();
098  }
099
100  /**
101   * Wraps the preferred, caller and context class loaders.
102   */
103  protected class ClassLoaderContext {
104
105    /**
106     * Optional - if set only use this classLoader (no fallback).
107     */
108    protected final ClassLoader preferredLoader;
109
110    protected final ClassLoader contextLoader;
111
112    protected final ClassLoader callerLoader;
113
114    ClassLoaderContext(ClassLoader preferredLoader) {
115      this.preferredLoader = preferredLoader;
116      this.callerLoader = ServerConfig.class.getClassLoader();
117      this.contextLoader = contextLoader();
118    }
119
120    ClassLoader contextLoader() {
121      ClassLoader loader = Thread.currentThread().getContextClassLoader();
122      return (loader != null) ? loader: callerLoader;
123    }
124
125    Class<?> forName(String name) throws ClassNotFoundException {
126
127      if (preferredLoader != null) {
128        // only use the explicitly set classLoader
129        return classForName(name, preferredLoader);
130      }
131      try {
132        // try the context loader first
133        return classForName(name, contextLoader);
134      } catch (ClassNotFoundException e) {
135        if (callerLoader == contextLoader) {
136          throw e;
137        } else {
138          // fallback to the caller classLoader
139          return classForName(name, callerLoader);
140        }
141      }
142    }
143
144    Class<?> classForName(String name, ClassLoader classLoader) throws ClassNotFoundException {
145      return Class.forName(name, true, classLoader);
146    }
147
148    ClassLoader getClassLoader() {
149      return preferredLoader != null ? preferredLoader : contextLoader;
150    }
151  }
152}
153