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