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