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.serverfactory;
20
21 import java.io.File;
22 import java.io.IOException;
23 import java.io.InputStream;
24 import java.net.URL;
25 import java.util.ArrayList;
26 import java.util.Collection;
27 import java.util.Dictionary;
28 import java.util.Enumeration;
29 import java.util.HashMap;
30 import java.util.List;
31 import java.util.Map;
32 import java.util.StringTokenizer;
33
34 import org.eclipse.jetty.deploy.AppLifeCycle;
35 import org.eclipse.jetty.deploy.AppProvider;
36 import org.eclipse.jetty.deploy.DeploymentManager;
37 import org.eclipse.jetty.deploy.bindings.StandardStarter;
38 import org.eclipse.jetty.deploy.bindings.StandardStopper;
39 import org.eclipse.jetty.osgi.boot.BundleContextProvider;
40 import org.eclipse.jetty.osgi.boot.BundleWebAppProvider;
41 import org.eclipse.jetty.osgi.boot.JettyBootstrapActivator;
42 import org.eclipse.jetty.osgi.boot.OSGiDeployer;
43 import org.eclipse.jetty.osgi.boot.OSGiServerConstants;
44 import org.eclipse.jetty.osgi.boot.OSGiUndeployer;
45 import org.eclipse.jetty.osgi.boot.ServiceContextProvider;
46 import org.eclipse.jetty.osgi.boot.ServiceWebAppProvider;
47 import org.eclipse.jetty.osgi.boot.internal.jsp.TldLocatableURLClassloader;
48 import org.eclipse.jetty.osgi.boot.internal.webapp.BundleFileLocatorHelperFactory;
49 import org.eclipse.jetty.osgi.boot.internal.webapp.LibExtClassLoaderHelper;
50 import org.eclipse.jetty.osgi.boot.internal.webapp.WebBundleTrackerCustomizer;
51 import org.eclipse.jetty.osgi.boot.utils.WebappRegistrationCustomizer;
52 import org.eclipse.jetty.server.Server;
53 import org.eclipse.jetty.server.handler.ContextHandlerCollection;
54 import org.eclipse.jetty.util.IO;
55 import org.eclipse.jetty.util.log.Log;
56 import org.eclipse.jetty.util.log.Logger;
57 import org.eclipse.jetty.util.resource.Resource;
58 import org.eclipse.jetty.xml.XmlConfiguration;
59 import org.xml.sax.SAXParseException;
60
61
62
63
64
65
66 public class ServerInstanceWrapper
67 {
68
69
70
71
72
73
74 public static final String PROPERTY_THIS_JETTY_XML_FOLDER_URL = "this.jetty.xml.parent.folder.url";
75
76 private static Logger LOG = Log.getLogger(ServerInstanceWrapper.class.getName());
77
78
79
80 private final String _managedServerName;
81
82
83
84
85 private Server _server;
86
87 private ContextHandlerCollection _ctxtCollection;
88
89
90
91
92
93
94 private ClassLoader _commonParentClassLoaderForWebapps;
95
96 private DeploymentManager _deploymentManager;
97
98
99
100 public ServerInstanceWrapper(String managedServerName)
101 {
102 _managedServerName = managedServerName;
103 }
104
105
106 public String getManagedServerName()
107 {
108 return _managedServerName;
109 }
110
111
112
113
114
115
116
117
118
119 public ClassLoader getParentClassLoaderForWebapps()
120 {
121 return _commonParentClassLoaderForWebapps;
122 }
123
124
125
126
127
128
129 public DeploymentManager getDeploymentManager()
130 {
131 return _deploymentManager;
132 }
133
134
135
136
137
138
139 public Server getServer()
140 {
141 return _server;
142 }
143
144
145
146
147
148 public ContextHandlerCollection getContextHandlerCollection()
149 {
150 return _ctxtCollection;
151 }
152
153
154
155 public void start(Server server, Dictionary props) throws Exception
156 {
157 _server = server;
158 ClassLoader contextCl = Thread.currentThread().getContextClassLoader();
159 try
160 {
161
162
163 ClassLoader libExtClassLoader = null;
164 String sharedURLs = (String) props.get(OSGiServerConstants.MANAGED_JETTY_SHARED_LIB_FOLDER_URLS);
165
166 List<File> shared = sharedURLs != null ? extractFiles(sharedURLs) : null;
167 libExtClassLoader = LibExtClassLoaderHelper.createLibExtClassLoader(shared, null, server, JettyBootstrapActivator.class.getClassLoader());
168
169 if (LOG.isDebugEnabled()) LOG.debug("LibExtClassLoader = "+libExtClassLoader);
170
171 Thread.currentThread().setContextClassLoader(libExtClassLoader);
172
173 configure(server, props);
174
175 init();
176
177 URL[] jarsWithTlds = getJarsWithTlds();
178 _commonParentClassLoaderForWebapps = jarsWithTlds == null ? libExtClassLoader : new TldLocatableURLClassloader(libExtClassLoader, jarsWithTlds);
179
180 if (LOG.isDebugEnabled()) LOG.debug("common classloader = "+_commonParentClassLoaderForWebapps);
181
182 server.start();
183 }
184 catch (Exception e)
185 {
186 if (server != null)
187 {
188 try
189 {
190 server.stop();
191 }
192 catch (Exception x)
193 {
194 LOG.ignore(x);
195 }
196 }
197 throw e;
198 }
199 finally
200 {
201 Thread.currentThread().setContextClassLoader(contextCl);
202 }
203 }
204
205
206 public void stop()
207 {
208 try
209 {
210 if (_server.isRunning())
211 {
212 _server.stop();
213 }
214 }
215 catch (Exception e)
216 {
217 LOG.warn(e);
218 }
219 }
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244 private URL[] getJarsWithTlds() throws Exception
245 {
246
247
248
249
250
251
252
253
254
255 ArrayList<URL> res = new ArrayList<URL>();
256 for (WebappRegistrationCustomizer regCustomizer : WebBundleTrackerCustomizer.JSP_REGISTRATION_HELPERS)
257 {
258 URL[] urls = regCustomizer.getJarsWithTlds(_deploymentManager, BundleFileLocatorHelperFactory.getFactory().getHelper());
259 for (URL url : urls)
260 {
261 if (!res.contains(url)) res.add(url);
262 }
263 }
264 if (!res.isEmpty())
265 return res.toArray(new URL[res.size()]);
266 else
267 return null;
268 }
269
270
271
272 private void configure(Server server, Dictionary props) throws Exception
273 {
274 String jettyConfigurationUrls = (String) props.get(OSGiServerConstants.MANAGED_JETTY_XML_CONFIG_URLS);
275 List<URL> jettyConfigurations = jettyConfigurationUrls != null ? extractResources(jettyConfigurationUrls) : null;
276 if (jettyConfigurations == null || jettyConfigurations.isEmpty()) { return; }
277 Map<String, Object> id_map = new HashMap<String, Object>();
278
279
280 id_map.put("Server", server);
281 id_map.put((String)props.get(OSGiServerConstants.MANAGED_JETTY_SERVER_NAME), server);
282
283 Map<String, String> properties = new HashMap<String, String>();
284 Enumeration<Object> en = props.keys();
285 while (en.hasMoreElements())
286 {
287 Object key = en.nextElement();
288 Object value = props.get(key);
289 String keyStr = String.valueOf(key);
290 String valStr = String.valueOf(value);
291 properties.put(keyStr, valStr);
292 server.setAttribute(keyStr, valStr);
293 }
294
295 for (URL jettyConfiguration : jettyConfigurations)
296 {
297 InputStream is = null;
298 try
299 {
300
301 Resource r = Resource.newResource(jettyConfiguration);
302 if (!r.exists())
303 {
304 LOG.warn("File does not exist "+r);
305 continue;
306 }
307 is = r.getInputStream();
308 XmlConfiguration config = new XmlConfiguration(is);
309 config.getIdMap().putAll(id_map);
310
311
312
313
314
315 String urlPath = jettyConfiguration.toString();
316 int lastSlash = urlPath.lastIndexOf('/');
317 if (lastSlash > 4)
318 {
319 urlPath = urlPath.substring(0, lastSlash);
320 Map<String, String> properties2 = new HashMap<String, String>(properties);
321 properties2.put(PROPERTY_THIS_JETTY_XML_FOLDER_URL, urlPath);
322 config.getProperties().putAll(properties2);
323 }
324 else
325 {
326 config.getProperties().putAll(properties);
327 }
328 config.configure();
329 id_map = config.getIdMap();
330 }
331 catch (SAXParseException saxparse)
332 {
333 LOG.warn("Unable to configure the jetty/etc file " + jettyConfiguration, saxparse);
334 throw saxparse;
335 }
336 finally
337 {
338 IO.close(is);
339 }
340 }
341
342 }
343
344
345
346
347
348
349
350 private void init()
351 {
352
353 _ctxtCollection = (ContextHandlerCollection) _server.getChildHandlerByClass(ContextHandlerCollection.class);
354
355 if (_ctxtCollection == null)
356 throw new IllegalStateException("ERROR: No ContextHandlerCollection configured in Server");
357
358 List<String> providerClassNames = new ArrayList<String>();
359
360
361 Collection<DeploymentManager> deployers = _server.getBeans(DeploymentManager.class);
362 if (deployers != null && !deployers.isEmpty())
363 {
364 _deploymentManager = deployers.iterator().next();
365
366 for (AppProvider provider : _deploymentManager.getAppProviders())
367 {
368 providerClassNames.add(provider.getClass().getName());
369 }
370 }
371 else
372 {
373
374 _deploymentManager = new DeploymentManager();
375 _deploymentManager.setContexts(_ctxtCollection);
376 _server.addBean(_deploymentManager);
377 }
378
379 _deploymentManager.setUseStandardBindings(false);
380 List<AppLifeCycle.Binding> deploymentLifeCycleBindings = new ArrayList<AppLifeCycle.Binding>();
381 deploymentLifeCycleBindings.add(new OSGiDeployer());
382 deploymentLifeCycleBindings.add(new StandardStarter());
383 deploymentLifeCycleBindings.add(new StandardStopper());
384 deploymentLifeCycleBindings.add(new OSGiUndeployer());
385 _deploymentManager.setLifeCycleBindings(deploymentLifeCycleBindings);
386
387 if (!providerClassNames.contains(BundleWebAppProvider.class.getName()))
388 {
389
390 try
391 {
392 BundleWebAppProvider webAppProvider = new BundleWebAppProvider(this);
393 _deploymentManager.addAppProvider(webAppProvider);
394 }
395 catch (Exception e)
396 {
397 LOG.warn(e);
398 }
399 }
400
401 if (!providerClassNames.contains(ServiceWebAppProvider.class.getName()))
402 {
403
404 try
405 {
406 ServiceWebAppProvider webAppProvider = new ServiceWebAppProvider(this);
407 _deploymentManager.addAppProvider(webAppProvider);
408 }
409 catch (Exception e)
410 {
411 LOG.warn(e);
412 }
413 }
414
415 if (!providerClassNames.contains(BundleContextProvider.class.getName()))
416 {
417 try
418 {
419 BundleContextProvider contextProvider = new BundleContextProvider(this);
420 _deploymentManager.addAppProvider(contextProvider);
421 }
422 catch (Exception e)
423 {
424 LOG.warn(e);
425 }
426 }
427
428 if (!providerClassNames.contains(ServiceContextProvider.class.getName()))
429 {
430 try
431 {
432 ServiceContextProvider contextProvider = new ServiceContextProvider(this);
433 _deploymentManager.addAppProvider(contextProvider);
434 }
435 catch (Exception e)
436 {
437 LOG.warn(e);
438 }
439 }
440 }
441
442
443
444
445
446
447
448
449 File getDefaultOSGiContextsHome(File jettyHome)
450 {
451 String jettyContextsHome = System.getProperty("jetty.osgi.contexts.home");
452 if (jettyContextsHome != null)
453 {
454 File contextsHome = new File(jettyContextsHome);
455 if (!contextsHome.exists() || !contextsHome.isDirectory())
456 {
457 throw new IllegalArgumentException("the ${jetty.osgi.contexts.home} '"
458 + jettyContextsHome
459 + " must exist and be a folder");
460 }
461 return contextsHome;
462 }
463 return new File(jettyHome, "/contexts");
464 }
465
466
467
468
469
470 private List<URL> extractResources(String propertyValue)
471 {
472 StringTokenizer tokenizer = new StringTokenizer(propertyValue, ",;", false);
473 List<URL> urls = new ArrayList<URL>();
474 while (tokenizer.hasMoreTokens())
475 {
476 String tok = tokenizer.nextToken();
477 try
478 {
479 urls.add(BundleFileLocatorHelperFactory.getFactory().getHelper().getLocalURL(new URL(tok)));
480 }
481 catch (Throwable mfe)
482 {
483 LOG.warn(mfe);
484 }
485 }
486 return urls;
487 }
488
489
490
491
492
493 private List<File> extractFiles(String propertyValue)
494 {
495 StringTokenizer tokenizer = new StringTokenizer(propertyValue, ",;", false);
496 List<File> files = new ArrayList<File>();
497 while (tokenizer.hasMoreTokens())
498 {
499 String tok = tokenizer.nextToken();
500 try
501 {
502 URL url = new URL(tok);
503 url = BundleFileLocatorHelperFactory.getFactory().getHelper().getFileURL(url);
504 if (url.getProtocol().equals("file"))
505 {
506 Resource res = Resource.newResource(url);
507 File folder = res.getFile();
508 if (folder != null)
509 {
510 files.add(folder);
511 }
512 }
513 }
514 catch (Throwable mfe)
515 {
516 LOG.warn(mfe);
517 }
518 }
519 return files;
520 }
521
522 }