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