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