1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19 package org.eclipse.jetty.osgi.boot.internal.webapp;
20
21 import java.io.File;
22 import java.io.IOException;
23 import java.lang.reflect.Field;
24 import java.net.URL;
25 import java.util.ArrayList;
26 import java.util.Collections;
27 import java.util.Enumeration;
28 import java.util.HashSet;
29 import java.util.List;
30 import java.util.Set;
31 import java.util.StringTokenizer;
32 import java.util.jar.JarFile;
33
34 import javax.servlet.http.HttpServlet;
35
36 import org.eclipse.jetty.osgi.boot.utils.BundleClassLoaderHelperFactory;
37 import org.eclipse.jetty.util.log.Log;
38 import org.eclipse.jetty.util.log.Logger;
39 import org.eclipse.jetty.util.resource.Resource;
40 import org.eclipse.jetty.webapp.WebAppClassLoader;
41 import org.eclipse.jetty.webapp.WebAppContext;
42 import org.osgi.framework.Bundle;
43 import org.osgi.framework.BundleReference;
44
45
46
47
48
49
50
51 public class OSGiWebappClassLoader extends WebAppClassLoader implements BundleReference
52 {
53
54 private static final Logger __logger = Log.getLogger(OSGiWebappClassLoader.class.getName());
55
56
57
58
59
60 public static final Set<String> JAR_WITH_SUCH_CLASS_MUST_BE_EXCLUDED = new HashSet<String>();
61
62 public static void addClassThatIdentifiesAJarThatMustBeRejected(Class<?> zclass)
63 {
64 JAR_WITH_SUCH_CLASS_MUST_BE_EXCLUDED.add(zclass.getName().replace('.', '/') + ".class");
65 }
66
67 public static void addClassThatIdentifiesAJarThatMustBeRejected(String zclassName)
68 {
69 JAR_WITH_SUCH_CLASS_MUST_BE_EXCLUDED.add(zclassName.replace('.', '/') + ".class");
70 }
71
72 static
73 {
74 addClassThatIdentifiesAJarThatMustBeRejected(HttpServlet.class);
75 }
76
77 private ClassLoader _osgiBundleClassLoader;
78
79 private Bundle _contributor;
80
81 private boolean _lookInOsgiFirst = true;
82
83
84
85
86
87
88
89
90 public OSGiWebappClassLoader(ClassLoader parent, WebAppContext context, Bundle contributor)
91 throws IOException
92 {
93 super(parent, context);
94 _contributor = contributor;
95 _osgiBundleClassLoader = BundleClassLoaderHelperFactory.getFactory().getHelper().getBundleClassLoader(contributor);
96 }
97
98
99
100 @Override
101 public Class<?> loadClass(String name) throws ClassNotFoundException
102 {
103 return super.loadClass(name);
104 }
105
106
107
108
109
110
111
112
113 public Bundle getBundle()
114 {
115 return _contributor;
116 }
117
118
119 @Override
120 public Enumeration<URL> getResources(String name) throws IOException
121 {
122 Enumeration<URL> osgiUrls = _osgiBundleClassLoader.getResources(name);
123 Enumeration<URL> urls = super.getResources(name);
124 if (_lookInOsgiFirst)
125 {
126 return Collections.enumeration(toList(osgiUrls, urls));
127 }
128 else
129 {
130 return Collections.enumeration(toList(urls, osgiUrls));
131 }
132 }
133
134
135
136
137 @Override
138 public URL getResource(String name)
139 {
140 if (_lookInOsgiFirst)
141 {
142 URL url = _osgiBundleClassLoader.getResource(name);
143 return url != null ? url : super.getResource(name);
144 }
145 else
146 {
147 URL url = super.getResource(name);
148 return url != null ? url : _osgiBundleClassLoader.getResource(name);
149 }
150 }
151
152
153
154
155 private List<URL> toList(Enumeration<URL> e, Enumeration<URL> e2)
156 {
157 List<URL> list = new ArrayList<URL>();
158 while (e != null && e.hasMoreElements())
159 list.add(e.nextElement());
160 while (e2 != null && e2.hasMoreElements())
161 list.add(e2.nextElement());
162 return list;
163 }
164
165
166
167 protected Class<?> findClass(String name) throws ClassNotFoundException
168 {
169 try
170 {
171 return _lookInOsgiFirst ? _osgiBundleClassLoader.loadClass(name) : super.findClass(name);
172 }
173 catch (ClassNotFoundException cne)
174 {
175 try
176 {
177 return _lookInOsgiFirst ? super.findClass(name) : _osgiBundleClassLoader.loadClass(name);
178 }
179 catch (ClassNotFoundException cne2)
180 {
181 throw cne;
182 }
183 }
184 }
185
186
187
188
189
190
191
192
193 @Override
194 public void addClassPath(String classPath) throws IOException
195 {
196
197 StringTokenizer tokenizer = new StringTokenizer(classPath, ",;");
198 while (tokenizer.hasMoreTokens())
199 {
200 String path = tokenizer.nextToken();
201 Resource resource = getContext().newResource(path);
202
203
204 File file = resource.getFile();
205 if (file != null && isAcceptableLibrary(file, JAR_WITH_SUCH_CLASS_MUST_BE_EXCLUDED))
206 {
207 super.addClassPath(path);
208 }
209 else
210 {
211 __logger.info("Did not add " + path + " to the classloader of the webapp " + getContext());
212 }
213 }
214
215 }
216
217
218
219
220
221
222
223 private boolean isAcceptableLibrary(File file, Set<String> pathToClassFiles)
224 {
225 try
226 {
227 if (file.isDirectory())
228 {
229 for (String criteria : pathToClassFiles)
230 {
231 if (new File(file, criteria).exists()) { return false; }
232 }
233 }
234 else
235 {
236 JarFile jar = null;
237 try
238 {
239 jar = new JarFile(file);
240 for (String criteria : pathToClassFiles)
241 {
242 if (jar.getEntry(criteria) != null) { return false; }
243 }
244 }
245 finally
246 {
247 if (jar != null) try
248 {
249 jar.close();
250 }
251 catch (IOException ioe)
252 {
253 }
254 }
255 }
256 }
257 catch (IOException e)
258 {
259
260 __logger.ignore(e);
261 }
262 return true;
263 }
264
265 private static Field _contextField;
266
267
268
269
270
271
272
273
274
275
276
277 public void setWebappContext(WebAppContext webappContext)
278 {
279 try
280 {
281 if (_contextField == null)
282 {
283 _contextField = WebAppClassLoader.class.getDeclaredField("_context");
284 _contextField.setAccessible(true);
285 }
286 _contextField.set(this, webappContext);
287 if (webappContext.getExtraClasspath() != null)
288 {
289 addClassPath(webappContext.getExtraClasspath());
290 }
291 }
292 catch (Throwable t)
293 {
294
295 __logger.warn("Unable to set webappcontext", t);
296 }
297 }
298 }