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
101
102
103
104
105
106
107 public Bundle getBundle()
108 {
109 return _contributor;
110 }
111
112
113 @Override
114 public Enumeration<URL> getResources(String name) throws IOException
115 {
116 Enumeration<URL> osgiUrls = _osgiBundleClassLoader.getResources(name);
117 Enumeration<URL> urls = super.getResources(name);
118 if (_lookInOsgiFirst)
119 {
120 return Collections.enumeration(toList(osgiUrls, urls));
121 }
122 else
123 {
124 return Collections.enumeration(toList(urls, osgiUrls));
125 }
126 }
127
128
129
130
131 @Override
132 public URL getResource(String name)
133 {
134 if (_lookInOsgiFirst)
135 {
136 URL url = _osgiBundleClassLoader.getResource(name);
137 return url != null ? url : super.getResource(name);
138 }
139 else
140 {
141 URL url = super.getResource(name);
142 return url != null ? url : _osgiBundleClassLoader.getResource(name);
143 }
144 }
145
146
147
148
149 private List<URL> toList(Enumeration<URL> e, Enumeration<URL> e2)
150 {
151 List<URL> list = new ArrayList<URL>();
152 while (e != null && e.hasMoreElements())
153 list.add(e.nextElement());
154 while (e2 != null && e2.hasMoreElements())
155 list.add(e2.nextElement());
156 return list;
157 }
158
159
160
161 protected Class<?> findClass(String name) throws ClassNotFoundException
162 {
163 try
164 {
165 return _lookInOsgiFirst ? _osgiBundleClassLoader.loadClass(name) : super.findClass(name);
166 }
167 catch (ClassNotFoundException cne)
168 {
169 try
170 {
171 return _lookInOsgiFirst ? super.findClass(name) : _osgiBundleClassLoader.loadClass(name);
172 }
173 catch (ClassNotFoundException cne2)
174 {
175 throw cne;
176 }
177 }
178 }
179
180
181
182
183
184
185
186
187 @Override
188 public void addClassPath(String classPath) throws IOException
189 {
190
191 StringTokenizer tokenizer = new StringTokenizer(classPath, ",;");
192 while (tokenizer.hasMoreTokens())
193 {
194 String path = tokenizer.nextToken();
195 Resource resource = getContext().newResource(path);
196
197
198 File file = resource.getFile();
199 if (file != null && isAcceptableLibrary(file, JAR_WITH_SUCH_CLASS_MUST_BE_EXCLUDED))
200 {
201 super.addClassPath(path);
202 }
203 else
204 {
205 __logger.info("Did not add " + path + " to the classloader of the webapp " + getContext());
206 }
207 }
208
209 }
210
211
212
213
214
215
216
217 private boolean isAcceptableLibrary(File file, Set<String> pathToClassFiles)
218 {
219 try
220 {
221 if (file.isDirectory())
222 {
223 for (String criteria : pathToClassFiles)
224 {
225 if (new File(file, criteria).exists()) { return false; }
226 }
227 }
228 else
229 {
230 JarFile jar = null;
231 try
232 {
233 jar = new JarFile(file);
234 for (String criteria : pathToClassFiles)
235 {
236 if (jar.getEntry(criteria) != null) { return false; }
237 }
238 }
239 finally
240 {
241 if (jar != null) try
242 {
243 jar.close();
244 }
245 catch (IOException ioe)
246 {
247 }
248 }
249 }
250 }
251 catch (IOException e)
252 {
253
254 __logger.ignore(e);
255 }
256 return true;
257 }
258
259 private static Field _contextField;
260
261
262
263
264
265
266
267
268
269
270 public void setWebappContext(WebAppContext webappContext)
271 {
272 try
273 {
274 if (_contextField == null)
275 {
276 _contextField = WebAppClassLoader.class.getDeclaredField("_context");
277 _contextField.setAccessible(true);
278 }
279 _contextField.set(this, webappContext);
280 if (webappContext.getExtraClasspath() != null)
281 {
282 addClassPath(webappContext.getExtraClasspath());
283 }
284 }
285 catch (Throwable t)
286 {
287
288 __logger.warn("Unable to set webappcontext", t);
289 }
290 }
291 }