View Javadoc

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.Collection;
25  import java.util.Collections;
26  import java.util.HashSet;
27  import java.util.List;
28  import java.util.Set;
29  import java.util.StringTokenizer;
30  import java.util.regex.Pattern;
31  
32  import org.eclipse.jetty.deploy.DeploymentManager;
33  import org.eclipse.jetty.osgi.boot.OSGiWebInfConfiguration;
34  import org.eclipse.jetty.osgi.boot.utils.BundleFileLocatorHelper;
35  import org.eclipse.jetty.osgi.boot.utils.WebappRegistrationCustomizer;
36  import org.osgi.framework.Bundle;
37  import org.osgi.framework.FrameworkUtil;
38  
39  /**
40   * Plug bundles that contains tld files so that jasper will discover them and
41   * set them up in jetty.
42   * 
43   * For example:
44   * -Dorg.eclipse.jetty.osgi.tldbundles=org.springframework.web.servlet
45   * ,com.opensymphony.module.sitemesh Otherwise use an attribute to the
46   * WebAppDeployer <New
47   * class="org.eclipse.jetty.deploy.providers.WebAppProvider"> .... <Set
48   * name="tldBundles">&ltProperty name="org.eclipse.jetty.osgi.tldsbundles"
49   * default="" /></Set> <New>
50   */
51  public class PluggableWebAppRegistrationCustomizerImpl implements WebappRegistrationCustomizer
52  {
53      /**
54       * To plug into jasper bundles that contain tld files please use a list of
55       * bundle's symbolic names:
56       * -Djetty.osgi.tldbundles=org.springframework.web.servlet
57       * ,com.opensymphony.module.sitemesh
58       */
59      public static final String SYS_PROP_TLD_BUNDLES = "org.eclipse.jetty.osgi.tldbundles";
60  
61      /**
62       * Union of the tld bundles defined system wide and the one defines as an
63       * attribute of the AppProvider.
64       * 
65       * @param provider
66       * @return
67       */
68      private static Collection<String> getTldBundles(DeploymentManager deploymentManager)
69      {
70          String sysprop = System.getProperty(SYS_PROP_TLD_BUNDLES);
71          String att = (String) deploymentManager.getContextAttribute(OSGiWebInfConfiguration.CONTAINER_BUNDLE_PATTERN);
72          if (sysprop == null && att == null) { return Collections.emptySet(); }
73          if (att == null)
74          {
75              att = sysprop;
76          }
77          else if (sysprop != null)
78          {
79              att = att + "," + sysprop;
80          }
81  
82          Collection<String> tldbundles = new HashSet<String>();
83          StringTokenizer tokenizer = new StringTokenizer(att, ", \n\r\t", false);
84          while (tokenizer.hasMoreTokens())
85          {
86              tldbundles.add(tokenizer.nextToken());
87          }
88          return tldbundles;
89      }
90  
91      /**
92       * @return The location of the jars that contain tld files. Jasper will
93       *         discover them.
94       */
95      public URL[] getJarsWithTlds(DeploymentManager deploymentManager, BundleFileLocatorHelper locatorHelper) throws Exception
96      {
97          // naive way of finding those bundles.
98          // lots of assumptions: for example we assume a single version of each
99          // bundle that would contain tld files.
100         // this is probably good enough as those tlds are loaded system-wide on
101         // jetty.
102         // to do better than this we need to do it on a per webapp basis.
103         // probably using custom properties in the ContextHandler service
104         // and mirroring those in the MANIFEST.MF
105 
106         Bundle[] bundles = FrameworkUtil.getBundle(PluggableWebAppRegistrationCustomizerImpl.class).getBundleContext().getBundles();
107         HashSet<URL> urls = new HashSet<URL>();
108         String tmp = System.getProperty(SYS_PROP_TLD_BUNDLES); //comma separated exact names
109         List<String> sysNames =   new ArrayList<String>();
110         if (tmp != null)
111         {
112             StringTokenizer tokenizer = new StringTokenizer(tmp, ", \n\r\t", false);
113             while (tokenizer.hasMoreTokens())
114                 sysNames.add(tokenizer.nextToken());
115         }
116         tmp = (String) deploymentManager.getContextAttribute(OSGiWebInfConfiguration.CONTAINER_BUNDLE_PATTERN); //bundle name patterns
117         Pattern pattern = (tmp==null? null : Pattern.compile(tmp));
118         for (Bundle bundle : bundles)
119         {
120             if (sysNames.contains(bundle.getSymbolicName()))
121                 registerTldBundle(locatorHelper, bundle, urls);
122            
123             if (pattern != null && pattern.matcher(bundle.getSymbolicName()).matches())
124                 registerTldBundle(locatorHelper, bundle, urls);
125         }
126 
127         return urls.toArray(new URL[urls.size()]);
128 
129     }
130 
131     /**
132      * Resolves the bundle that contains tld files as a set of URLs that will be
133      * passed to jasper as a URLClassLoader later on. Usually that would be a
134      * single URL per bundle. But we do some more work if there are jars
135      * embedded in the bundle.
136      * 
137      * The jasper TldScanner expects a URLClassloader to parse a jar for the
138      * /META-INF/*.tld it may contain. We place the bundles that we know contain
139      * such tag-libraries. Please note that it will work if and only if the
140      * bundle is a jar (!) Currently we just hardcode the bundle that contains
141      * the jstl implemenation.
142      * 
143      * A workaround when the tld cannot be parsed with this method is to copy
144      * and paste it inside the WEB-INF of the webapplication where it is used.
145      * 
146      * Support only 2 types of packaging for the bundle: - the bundle is a jar
147      * (recommended for runtime.) - the bundle is a folder and contain jars in
148      * the root and/or in the lib folder (nice for PDE developement situations)
149      * Unsupported: the bundle is a jar that embeds more jars.
150      * 
151      * @param locatorHelper
152      * @param bundle
153      * @param urls
154      * @throws Exception
155      */
156     private void registerTldBundle(BundleFileLocatorHelper locatorHelper, Bundle bundle, Set<URL> urls) throws Exception
157     {
158         File jasperLocation = locatorHelper.getBundleInstallLocation(bundle);
159         if (jasperLocation.isDirectory())
160         {
161             for (File f : jasperLocation.listFiles())
162             {
163                 if (f.getName().endsWith(".jar") && f.isFile())
164                 {
165                     urls.add(f.toURI().toURL());
166                 }
167                 else if (f.isDirectory() && f.getName().equals("lib"))
168                 {
169                     for (File f2 : jasperLocation.listFiles())
170                     {
171                         if (f2.getName().endsWith(".jar") && f2.isFile())
172                         {
173                             urls.add(f2.toURI().toURL());
174                         }
175                     }
176                 }
177             }
178             urls.add(jasperLocation.toURI().toURL());
179         }
180         else
181         {
182             urls.add(jasperLocation.toURI().toURL());
183         }
184 
185     }
186 
187 }