View Javadoc

1   // ========================================================================
2   // Copyright (c) 2004-2011 Mort Bay Consulting Pty. Ltd.
3   // ------------------------------------------------------------------------
4   // All rights reserved. This program and the accompanying materials
5   // are made available under the terms of the Eclipse Public License v1.0
6   // and Apache License v2.0 which accompanies this distribution.
7   // The Eclipse Public License is available at 
8   // http://www.eclipse.org/legal/epl-v10.html
9   // The Apache License v2.0 is available at
10  // http://www.opensource.org/licenses/apache2.0.php
11  // You may elect to redistribute this code under either of these licenses. 
12  // ========================================================================
13  package org.eclipse.jetty.osgi.boot.jsp;
14  
15  import java.io.IOException;
16  import java.net.URL;
17  import java.util.Collection;
18  import java.util.Enumeration;
19  import java.util.LinkedHashSet;
20  
21  import org.eclipse.jetty.osgi.boot.OSGiWebappConstants;
22  import org.eclipse.jetty.osgi.boot.utils.internal.DefaultFileLocatorHelper;
23  import org.eclipse.jetty.util.log.Log;
24  import org.eclipse.jetty.util.log.Logger;
25  import org.eclipse.jetty.util.resource.Resource;
26  import org.eclipse.jetty.webapp.TagLibConfiguration;
27  import org.eclipse.jetty.webapp.WebAppContext;
28  import org.osgi.framework.Bundle;
29  import org.osgi.framework.BundleReference;
30  import org.osgi.service.packageadmin.PackageAdmin;
31  import org.osgi.util.tracker.ServiceTracker;
32  
33  /**
34   * <p>
35   * Replacement for {@link TagLibConfiguration} for the OSGi integration.
36   * </p>
37   * <p>
38   * In the case of a WAB, tlds can be located in OSGi bundles that are
39   * dependencies of the WAB. It is expected that each WAB lists the
40   * symbolic-names of the bundles that contain tld files. The list is defined as
41   * the value of the header 'Require-TldBundle'
42   * </p>
43   * <p>
44   * Discussions about this are logged in
45   * https://bugs.eclipse.org/bugs/show_bug.cgi?id=306971
46   * </p>
47   */
48  public class TagLibOSGiConfiguration extends TagLibConfiguration
49  {
50      private static final Logger LOG = Log.getLogger(TagLibOSGiConfiguration.class);
51  
52      private ServiceTracker packageAdminServiceTracker = null;
53  
54      /**
55       * Override the preConfigure; locates the bundles that contain tld files
56       * according to the value of the manifest header Require-TldBundle.
57       * <p>
58       * Set or add to the property TldProcessor.TLDResources the list of located
59       * jars so that the super class will scan those.
60       * </p>
61       */
62      public void preConfigure(WebAppContext context) throws Exception
63      {
64          String requireTldBundle = (String) context.getAttribute(OSGiWebappConstants.REQUIRE_TLD_BUNDLE);
65          if (requireTldBundle != null)
66          {
67              Collection<Resource> resources = getRequireTldBundleAsJettyResources(context, requireTldBundle);
68              if (resources != null && !resources.isEmpty())
69              {
70                  Collection<Resource> previouslySet = (Collection<Resource>) context.getAttribute(TagLibConfiguration.TLD_RESOURCES);
71                  if (previouslySet != null)
72                  {
73                      resources.addAll(previouslySet);
74                  }
75                  context.setAttribute(TagLibConfiguration.TLD_RESOURCES, resources);
76              }
77          }
78          super.preConfigure(context);
79  
80      }
81  
82      /**
83       * @param requireTldBundle The comma separated list of bundles' symbolic
84       *            names that contain tld for this osgi webapp.
85       * @return The collection of jars or folders that match those bundles.
86       */
87      private Collection<Resource> getRequireTldBundleAsJettyResources(WebAppContext context, String requireTldBundle)
88      {
89          Bundle bundle = (Bundle) context.getAttribute(OSGiWebappConstants.JETTY_OSGI_BUNDLE);
90          PackageAdmin packAdmin = getBundleAdmin();
91          String[] symbNames = requireTldBundle.split(", ");
92          Collection<Resource> tlds = new LinkedHashSet<Resource>();
93          for (String symbName : symbNames)
94          {
95              Bundle[] bs = packAdmin.getBundles(symbName, null);
96              if (bs == null || bs.length == 0) 
97              { 
98                  throw new IllegalArgumentException("Unable to locate the bundle '" + symbName
99                                                                                     + "' specified in the "
100                                                                                    + OSGiWebappConstants.REQUIRE_TLD_BUNDLE
101                                                                                    + " of the manifest of "
102                                                                                    + bundle.getSymbolicName()); 
103             }
104             // take the first one as it is the most recent version?
105             Enumeration<URL> en = bs[0].findEntries("META-INF", "*.tld", false);
106             boolean atLeastOneTldFound = false;
107             while (en.hasMoreElements())
108             {
109                 atLeastOneTldFound = true;
110                 URL oriUrl = en.nextElement();
111                 URL url = DefaultFileLocatorHelper.getLocalURL(oriUrl);
112                 Resource tldResource;
113                 try
114                 {
115                     tldResource = Resource.newResource(url);
116                 }
117                 catch (IOException e)
118                 {
119                     throw new IllegalArgumentException("Unable to locate the " + "tld resource in '"
120                                                        + url.toString()
121                                                        + "' in the bundle '"
122                                                        + bs[0].getSymbolicName()
123                                                        + "' while registering the "
124                                                        + OSGiWebappConstants.REQUIRE_TLD_BUNDLE
125                                                        + " of the manifest of "
126                                                        + bundle.getSymbolicName(), e);
127                 }
128                 tlds.add(tldResource);
129             }
130             if (!atLeastOneTldFound)
131             {
132                 LOG.warn("No '/META-INF/*.tld' resources were found " + " in the bundle '"
133                          + bs[0].getSymbolicName()
134                          + "' while registering the "
135                          + OSGiWebappConstants.REQUIRE_TLD_BUNDLE
136                          + " of the manifest of "
137                          + bundle.getSymbolicName());
138             }
139         }
140         return tlds;
141     }
142 
143     private PackageAdmin getBundleAdmin()
144     {
145         if (packageAdminServiceTracker == null)
146         {
147             Bundle bootBundle = ((BundleReference) OSGiWebappConstants.class.getClassLoader()).getBundle();
148             packageAdminServiceTracker = new ServiceTracker(bootBundle.getBundleContext(), PackageAdmin.class.getName(), null);
149             packageAdminServiceTracker.open();
150         }
151         return (PackageAdmin) packageAdminServiceTracker.getService();
152     }
153 
154 }