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.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 }