1 //
2 // ========================================================================
3 // Copyright (c) 1995-2013 Mort Bay Consulting Pty. Ltd.
4 // ------------------------------------------------------------------------
5 // All rights reserved. This program and the accompanying materials
6 // are made available under the terms of the Eclipse Public License v1.0
7 // and Apache License v2.0 which accompanies this distribution.
8 //
9 // The Eclipse Public License is available at
10 // http://www.eclipse.org/legal/epl-v10.html
11 //
12 // The Apache License v2.0 is available at
13 // http://www.opensource.org/licenses/apache2.0.php
14 //
15 // You may elect to redistribute this code under either of these licenses.
16 // ========================================================================
17 //
18
19 package org.eclipse.jetty.osgi.boot.jasper;
20
21 import java.io.File;
22 import java.net.URL;
23 import java.util.ArrayList;
24 import java.util.HashSet;
25 import java.util.List;
26 import java.util.Set;
27 import java.util.StringTokenizer;
28 import java.util.regex.Pattern;
29
30 import org.eclipse.jetty.deploy.DeploymentManager;
31 import org.eclipse.jetty.osgi.boot.OSGiWebInfConfiguration;
32 import org.eclipse.jetty.osgi.boot.utils.BundleFileLocatorHelper;
33 import org.eclipse.jetty.osgi.boot.utils.TldBundleDiscoverer;
34 import org.osgi.framework.Bundle;
35 import org.osgi.framework.FrameworkUtil;
36
37
38
39 /**
40 * ContainerTldBundleDiscoverer
41 *
42 *
43 * Use a System property to define bundles that contain tlds that need to
44 * be treated by jasper as if they were on the jetty container's classpath.
45 *
46 * The value of the property is evaluated against the DeploymentManager
47 * context attribute "org.eclipse.jetty.server.webapp.containerIncludeBundlePattern",
48 * which defines a pattern of matching bundle names.
49 *
50 * The bundle locations are converted to URLs for jasper's use.
51 *
52 * Eg:
53 * -Dorg.eclipse.jetty.osgi.tldbundles=org.springframework.web.servlet,com.opensymphony.module.sitemesh
54 *
55 */
56 public class ContainerTldBundleDiscoverer implements TldBundleDiscoverer
57 {
58 /**
59 * Comma separated list of names of bundles that contain tld files that should be
60 * discoved by jasper as if they were on the container's classpath.
61 * Eg:
62 * -Djetty.osgi.tldbundles=org.springframework.web.servlet,com.opensymphony.module.sitemesh
63 */
64 public static final String SYS_PROP_TLD_BUNDLES = "org.eclipse.jetty.osgi.tldbundles";
65
66
67
68 /**
69 * Check the System property "org.eclipse.jetty.osgi.tldbundles" for names of
70 * bundles that contain tlds and convert to URLs.
71 *
72 * @return The location of the jars that contain tld files as URLs.
73 */
74 public URL[] getUrlsForBundlesWithTlds(DeploymentManager deploymentManager, BundleFileLocatorHelper locatorHelper) throws Exception
75 {
76 // naive way of finding those bundles.
77 // lots of assumptions: for example we assume a single version of each
78 // bundle that would contain tld files.
79 // this is probably good enough as those tlds are loaded system-wide on
80 // jetty.
81 // to do better than this we need to do it on a per webapp basis.
82 // probably using custom properties in the ContextHandler service
83 // and mirroring those in the MANIFEST.MF
84
85 Bundle[] bundles = FrameworkUtil.getBundle(ContainerTldBundleDiscoverer.class).getBundleContext().getBundles();
86 HashSet<URL> urls = new HashSet<URL>();
87 String tmp = System.getProperty(SYS_PROP_TLD_BUNDLES); //comma separated exact names
88 List<String> sysNames = new ArrayList<String>();
89 if (tmp != null)
90 {
91 StringTokenizer tokenizer = new StringTokenizer(tmp, ", \n\r\t", false);
92 while (tokenizer.hasMoreTokens())
93 sysNames.add(tokenizer.nextToken());
94 }
95 tmp = (String) deploymentManager.getContextAttribute(OSGiWebInfConfiguration.CONTAINER_BUNDLE_PATTERN); //bundle name patterns
96 Pattern pattern = (tmp==null? null : Pattern.compile(tmp));
97 for (Bundle bundle : bundles)
98 {
99 if (sysNames.contains(bundle.getSymbolicName()))
100 convertBundleLocationToURL(locatorHelper, bundle, urls);
101
102 if (pattern != null && pattern.matcher(bundle.getSymbolicName()).matches())
103 convertBundleLocationToURL(locatorHelper, bundle, urls);
104 }
105
106 return urls.toArray(new URL[urls.size()]);
107
108 }
109
110 /**
111 * Resolves a bundle that contains tld files as a URL. The URLs are
112 * used by jasper to discover the tld files.
113 *
114 * Support only 2 types of packaging for the bundle: - the bundle is a jar
115 * (recommended for runtime.) - the bundle is a folder and contain jars in
116 * the root and/or in the lib folder (nice for PDE developement situations)
117 * Unsupported: the bundle is a jar that embeds more jars.
118 *
119 * @param locatorHelper
120 * @param bundle
121 * @param urls
122 * @throws Exception
123 */
124 private void convertBundleLocationToURL(BundleFileLocatorHelper locatorHelper, Bundle bundle, Set<URL> urls) throws Exception
125 {
126 File jasperLocation = locatorHelper.getBundleInstallLocation(bundle);
127 if (jasperLocation.isDirectory())
128 {
129 for (File f : jasperLocation.listFiles())
130 {
131 if (f.getName().endsWith(".jar") && f.isFile())
132 {
133 urls.add(f.toURI().toURL());
134 }
135 else if (f.isDirectory() && f.getName().equals("lib"))
136 {
137 for (File f2 : jasperLocation.listFiles())
138 {
139 if (f2.getName().endsWith(".jar") && f2.isFile())
140 {
141 urls.add(f2.toURI().toURL());
142 }
143 }
144 }
145 }
146 urls.add(jasperLocation.toURI().toURL());
147 }
148 else
149 {
150 urls.add(jasperLocation.toURI().toURL());
151 }
152 }
153 }