001
014
015 package com.liferay.portal.module.framework;
016
017 import com.liferay.portal.kernel.util.ReflectionUtil;
018
019 import java.io.IOException;
020
021 import java.lang.reflect.Field;
022 import java.lang.reflect.Method;
023
024 import java.net.URL;
025 import java.net.URLClassLoader;
026
027 import java.util.ArrayList;
028 import java.util.Enumeration;
029 import java.util.Iterator;
030 import java.util.List;
031
032
035 public class ModuleFrameworkClassLoader extends URLClassLoader {
036
037 public ModuleFrameworkClassLoader(URL[] urls, ClassLoader parent) {
038 super(urls, parent);
039
040 Object tomcat8StartedState = null;
041 Field tomcat8StateField = null;
042
043 try {
044 Class<?> clazz = parent.getClass();
045 ClassLoader classLoader = clazz.getClassLoader();
046
047 Class<?> lifecycleStateClass = classLoader.loadClass(
048 "org.apache.catalina.LifecycleState");
049
050 Method valueOfMethod = lifecycleStateClass.getMethod(
051 "valueOf", String.class);
052
053 tomcat8StartedState = valueOfMethod.invoke(null, "STARTED");
054
055 Class<?> WebappClassLoaderBaseClass = classLoader.loadClass(
056 "org.apache.catalina.loader.WebappClassLoaderBase");
057
058 tomcat8StateField = ReflectionUtil.getDeclaredField(
059 WebappClassLoaderBaseClass, "state");
060 }
061 catch (Exception e) {
062 tomcat8StartedState = null;
063 tomcat8StateField = null;
064 }
065
066 _tomcat8StartedState = tomcat8StartedState;
067 _tomcat8StateField = tomcat8StateField;
068 }
069
070 @Override
071 public URL getResource(String name) {
072 URL url = findResource(name);
073
074 if (url == null) {
075 url = super.getResource(name);
076 }
077
078 return url;
079 }
080
081 @Override
082 public Enumeration<URL> getResources(String name) throws IOException {
083 final List<URL> urls = new ArrayList<>();
084
085 urls.addAll(_buildURLs(null));
086
087 Enumeration<URL> localURLs = findResources(name);
088
089 urls.addAll(_buildURLs(localURLs));
090
091 Enumeration<URL> parentURLs = null;
092
093 ClassLoader parentClassLoader = getParent();
094
095 if (parentClassLoader != null) {
096 parentURLs = parentClassLoader.getResources(name);
097 }
098
099 urls.addAll(_buildURLs(parentURLs));
100
101 return new Enumeration<URL>() {
102
103 final Iterator<URL> iterator = urls.iterator();
104
105 @Override
106 public boolean hasMoreElements() {
107 return iterator.hasNext();
108 }
109
110 @Override
111 public URL nextElement() {
112 return iterator.next();
113 }
114
115 };
116 }
117
118 @Override
119 protected Class<?> loadClass(String name, boolean resolve)
120 throws ClassNotFoundException {
121
122 Object lock = getClassLoadingLock(name);
123
124 synchronized (lock) {
125 Class<?> clazz = findLoadedClass(name);
126
127 if (clazz == null) {
128 try {
129 clazz = findClass(name);
130 }
131 catch (ClassNotFoundException cnfe) {
132 if (_tomcat8StateField == null) {
133 clazz = super.loadClass(name, resolve);
134 }
135 else {
136 clazz = _loadForTomcat8(cnfe, name, resolve);
137 }
138 }
139 }
140
141 if (resolve) {
142 resolveClass(clazz);
143 }
144
145 return clazz;
146 }
147 }
148
149 private List<URL> _buildURLs(Enumeration<URL> url) {
150 if (url == null) {
151 return new ArrayList<>();
152 }
153
154 List<URL> urls = new ArrayList<>();
155
156 while (url.hasMoreElements()) {
157 urls.add(url.nextElement());
158 }
159
160 return urls;
161 }
162
163 private Class<?> _loadForTomcat8(
164 ClassNotFoundException cnfe, String name, boolean resolve)
165 throws ClassNotFoundException {
166
167 ClassLoader classLoader = getParent();
168
169 try {
170 Object state = _tomcat8StateField.get(classLoader);
171
172 if (state == _tomcat8StartedState) {
173 return super.loadClass(name, resolve);
174 }
175
176 _tomcat8StateField.set(classLoader, _tomcat8StartedState);
177
178 try {
179 return super.loadClass(name, resolve);
180 }
181 finally {
182 _tomcat8StateField.set(classLoader, state);
183 }
184 }
185 catch (ReflectiveOperationException roe) {
186 cnfe.addSuppressed(roe);
187
188 throw cnfe;
189 }
190 }
191
192 static {
193 ClassLoader.registerAsParallelCapable();
194 }
195
196 private final Object _tomcat8StartedState;
197 private final Field _tomcat8StateField;
198
199 }