diff options
Diffstat (limited to 'jetty-osgi/jetty-osgi-boot-jsp/src/main/java/org')
3 files changed, 178 insertions, 49 deletions
diff --git a/jetty-osgi/jetty-osgi-boot-jsp/src/main/java/org/eclipse/jetty/osgi/boot/jasper/ContainerTldBundleDiscoverer.java b/jetty-osgi/jetty-osgi-boot-jsp/src/main/java/org/eclipse/jetty/osgi/boot/jasper/ContainerTldBundleDiscoverer.java index b88fda629d..7979d7bd47 100644 --- a/jetty-osgi/jetty-osgi-boot-jsp/src/main/java/org/eclipse/jetty/osgi/boot/jasper/ContainerTldBundleDiscoverer.java +++ b/jetty-osgi/jetty-osgi-boot-jsp/src/main/java/org/eclipse/jetty/osgi/boot/jasper/ContainerTldBundleDiscoverer.java @@ -27,10 +27,15 @@ import java.util.Set; import java.util.StringTokenizer; import java.util.regex.Pattern; +import javax.servlet.jsp.JspFactory; + import org.eclipse.jetty.deploy.DeploymentManager; +import org.eclipse.jetty.osgi.boot.JettyBootstrapActivator; import org.eclipse.jetty.osgi.boot.OSGiWebInfConfiguration; import org.eclipse.jetty.osgi.boot.utils.BundleFileLocatorHelper; import org.eclipse.jetty.osgi.boot.utils.TldBundleDiscoverer; +import org.eclipse.jetty.util.log.Log; +import org.eclipse.jetty.util.log.Logger; import org.osgi.framework.Bundle; import org.osgi.framework.FrameworkUtil; @@ -39,15 +44,24 @@ import org.osgi.framework.FrameworkUtil; /** * ContainerTldBundleDiscoverer * + * Finds bundles that are considered as on the container classpath that + * contain tlds. + * + * The System property org.eclipse.jetty.osgi.tldbundles is a comma + * separated list of exact symbolic names of bundles that have container classpath + * tlds. * - * Use a System property to define bundles that contain tlds that need to - * be treated by jasper as if they were on the jetty container's classpath. + * The DeploymentManager context attribute "org.eclipse.jetty.server.webapp.containerIncludeBundlePattern" + * can be used to define a pattern of symbolic names of bundles that contain container + * classpath tlds. * - * The value of the property is evaluated against the DeploymentManager - * context attribute "org.eclipse.jetty.server.webapp.containerIncludeBundlePattern", - * which defines a pattern of matching bundle names. + * The matching bundles are converted to URLs that are put onto a special classloader that acts as the + * parent classloader for contexts deployed by the jetty Server instance (see ServerInstanceWrapper). * - * The bundle locations are converted to URLs for jasper's use. + * It also discovers the bundle that contains the jstl taglib and adds it into the + * "org.eclipse.jetty.server.webapp.containerIncludeBundlePattern" (if it is not already there) so + * that the WebInfOSGiConfiguration class will add the jstl taglib bundle into the list of container + * resources. * * Eg: * -Dorg.eclipse.jetty.osgi.tldbundles=org.springframework.web.servlet,com.opensymphony.module.sitemesh @@ -55,16 +69,20 @@ import org.osgi.framework.FrameworkUtil; */ public class ContainerTldBundleDiscoverer implements TldBundleDiscoverer { - /** - * Comma separated list of names of bundles that contain tld files that should be - * discoved by jasper as if they were on the container's classpath. - * Eg: - * -Djetty.osgi.tldbundles=org.springframework.web.servlet,com.opensymphony.module.sitemesh - */ - public static final String SYS_PROP_TLD_BUNDLES = "org.eclipse.jetty.osgi.tldbundles"; + private static final Logger LOG = Log.getLogger(ContainerTldBundleDiscoverer.class); + + private static String DEFAULT_JSP_FACTORY_IMPL_CLASS = "org.apache.jasper.runtime.JspFactoryImpl"; + /** + * Default name of a class that belongs to the jstl bundle. From that class + * we locate the corresponding bundle and register it as a bundle that + * contains tld files. + */ + private static String DEFAULT_JSTL_BUNDLE_CLASS = "org.apache.taglibs.standard.tag.el.core.WhenTag"; + private Bundle jstlBundle = null; + /** * Check the System property "org.eclipse.jetty.osgi.tldbundles" for names of * bundles that contain tlds and convert to URLs. @@ -72,19 +90,18 @@ public class ContainerTldBundleDiscoverer implements TldBundleDiscoverer * @return The location of the jars that contain tld files as URLs. */ public URL[] getUrlsForBundlesWithTlds(DeploymentManager deploymentManager, BundleFileLocatorHelper locatorHelper) throws Exception - { - // naive way of finding those bundles. - // lots of assumptions: for example we assume a single version of each - // bundle that would contain tld files. - // this is probably good enough as those tlds are loaded system-wide on - // jetty. - // to do better than this we need to do it on a per webapp basis. - // probably using custom properties in the ContextHandler service - // and mirroring those in the MANIFEST.MF + { + if (!isJspAvailable()) + { + return new URL[0]; + } + + if (jstlBundle == null) + jstlBundle = findJstlBundle(); Bundle[] bundles = FrameworkUtil.getBundle(ContainerTldBundleDiscoverer.class).getBundleContext().getBundles(); HashSet<URL> urls = new HashSet<URL>(); - String tmp = System.getProperty(SYS_PROP_TLD_BUNDLES); //comma separated exact names + String tmp = System.getProperty(OSGiWebInfConfiguration.SYS_PROP_TLD_BUNDLES); //comma separated exact names List<String> sysNames = new ArrayList<String>(); if (tmp != null) { @@ -93,13 +110,33 @@ public class ContainerTldBundleDiscoverer implements TldBundleDiscoverer sysNames.add(tokenizer.nextToken()); } tmp = (String) deploymentManager.getContextAttribute(OSGiWebInfConfiguration.CONTAINER_BUNDLE_PATTERN); //bundle name patterns + Pattern pattern = (tmp==null? null : Pattern.compile(tmp)); + + //check that the jstl bundle is not already included in the pattern, and include it if it is not because + //subsequent classes such as OSGiWebInfConfiguration use this pattern to determine which jars are + //considered to be on the container classpath + if (jstlBundle != null) + { + if (pattern == null) + { + pattern = Pattern.compile(jstlBundle.getSymbolicName()); + deploymentManager.setContextAttribute(OSGiWebInfConfiguration.CONTAINER_BUNDLE_PATTERN, jstlBundle.getSymbolicName()); + } + else if (!(pattern.matcher(jstlBundle.getSymbolicName()).matches())) + { + String s = tmp+"|"+jstlBundle.getSymbolicName(); + pattern = Pattern.compile(s); + deploymentManager.setContextAttribute(OSGiWebInfConfiguration.CONTAINER_BUNDLE_PATTERN, s); + } + } + + for (Bundle bundle : bundles) { if (sysNames.contains(bundle.getSymbolicName())) - convertBundleLocationToURL(locatorHelper, bundle, urls); - - if (pattern != null && pattern.matcher(bundle.getSymbolicName()).matches()) + convertBundleLocationToURL(locatorHelper, bundle, urls); + else if (pattern != null && pattern.matcher(bundle.getSymbolicName()).matches()) convertBundleLocationToURL(locatorHelper, bundle, urls); } @@ -108,6 +145,79 @@ public class ContainerTldBundleDiscoverer implements TldBundleDiscoverer } /** + * Check that jsp is on the classpath + * @return + */ + public boolean isJspAvailable() + { + try + { + getClass().getClassLoader().loadClass("org.apache.jasper.servlet.JspServlet"); + } + catch (Exception e) + { + LOG.warn("Unable to locate the JspServlet: jsp support unavailable.", e); + return false; + } + return true; + } + + + /** + * + * Some versions of JspFactory do Class.forName, which probably won't work in an + * OSGi environment. + */ + public void fixJspFactory () + { + try + { + Class<javax.servlet.ServletContext> servletContextClass = javax.servlet.ServletContext.class; + // bug #299733 + JspFactory fact = JspFactory.getDefaultFactory(); + if (fact == null) + { // bug #299733 + // JspFactory does a simple + // Class.getForName("org.apache.jasper.runtime.JspFactoryImpl") + // however its bundles does not import the jasper package + // so it fails. let's help things out: + fact = (JspFactory) JettyBootstrapActivator.class.getClassLoader().loadClass(DEFAULT_JSP_FACTORY_IMPL_CLASS).newInstance(); + JspFactory.setDefaultFactory(fact); + } + } + catch (Exception e) + { + LOG.warn("Unable to set the JspFactory: jsp support incomplete.", e); + } + } + + + /** + * Find the bundle that contains a jstl implementation class, which assumes that + * the jstl taglibs will be inside the same bundle. + * @return + */ + public Bundle findJstlBundle () + { + Class<?> jstlClass = null; + + try + { + jstlClass = JSTLBundleDiscoverer.class.getClassLoader().loadClass(DEFAULT_JSTL_BUNDLE_CLASS); + } + catch (ClassNotFoundException e) + { + LOG.info("jstl not on classpath", e); + } + + if (jstlClass != null) + //get the bundle containing jstl + return FrameworkUtil.getBundle(jstlClass); + + return null; + } + + /** * Resolves a bundle that contains tld files as a URL. The URLs are * used by jasper to discover the tld files. * diff --git a/jetty-osgi/jetty-osgi-boot-jsp/src/main/java/org/eclipse/jetty/osgi/boot/jasper/JSTLBundleDiscoverer.java b/jetty-osgi/jetty-osgi-boot-jsp/src/main/java/org/eclipse/jetty/osgi/boot/jasper/JSTLBundleDiscoverer.java index 04cdc72420..3857664942 100644 --- a/jetty-osgi/jetty-osgi-boot-jsp/src/main/java/org/eclipse/jetty/osgi/boot/jasper/JSTLBundleDiscoverer.java +++ b/jetty-osgi/jetty-osgi-boot-jsp/src/main/java/org/eclipse/jetty/osgi/boot/jasper/JSTLBundleDiscoverer.java @@ -20,9 +20,11 @@ package org.eclipse.jetty.osgi.boot.jasper; import java.io.File; import java.io.InputStream; +import java.lang.reflect.Field; import java.net.URL; import java.util.ArrayList; import java.util.HashSet; +import java.util.Set; import javax.servlet.Servlet; import javax.servlet.jsp.JspContext; @@ -30,7 +32,6 @@ import javax.servlet.jsp.JspFactory; import org.apache.jasper.Constants; import org.apache.jasper.compiler.Localizer; -import org.apache.jasper.xmlparser.ParserUtils; import org.eclipse.jetty.deploy.DeploymentManager; import org.eclipse.jetty.osgi.boot.JettyBootstrapActivator; import org.eclipse.jetty.osgi.boot.utils.BundleFileLocatorHelper; @@ -85,10 +86,12 @@ public class JSTLBundleDiscoverer implements TldBundleDiscoverer * implementation. bug #299733 */ private static String DEFAULT_JSP_FACTORY_IMPL_CLASS = "org.apache.jasper.runtime.JspFactoryImpl"; + + private static final Set<URL> __tldBundleCache = new HashSet<URL>(); public JSTLBundleDiscoverer() { - fixupDtdResolution(); + //fixupDtdResolution(); try { @@ -102,6 +105,7 @@ public class JSTLBundleDiscoverer implements TldBundleDiscoverer } try { + Class<javax.servlet.ServletContext> servletContextClass = javax.servlet.ServletContext.class; // bug #299733 JspFactory fact = JspFactory.getDefaultFactory(); if (fact == null) @@ -143,7 +147,7 @@ public class JSTLBundleDiscoverer implements TldBundleDiscoverer { ArrayList<URL> urls = new ArrayList<URL>(); - HashSet<Class<?>> classesToAddToTheTldBundles = new HashSet<Class<?>>(); + Class<?> jstlClass = null; // Look for the jstl bundle // We assume the jstl's tlds are defined there. @@ -151,18 +155,21 @@ public class JSTLBundleDiscoverer implements TldBundleDiscoverer // So we can look for this class using this bundle's classloader: try { - Class<?> jstlClass = JSTLBundleDiscoverer.class.getClassLoader().loadClass(DEFAULT_JSTL_BUNDLE_CLASS); - - classesToAddToTheTldBundles.add(jstlClass); + jstlClass = JSTLBundleDiscoverer.class.getClassLoader().loadClass(DEFAULT_JSTL_BUNDLE_CLASS); } catch (ClassNotFoundException e) { LOG.info("jstl not on classpath", e); } - for (Class<?> cl : classesToAddToTheTldBundles) + + if (jstlClass != null) { - Bundle tldBundle = FrameworkUtil.getBundle(cl); + //get the bundle containing jstl + Bundle tldBundle = FrameworkUtil.getBundle(jstlClass); File tldBundleLocation = locatorHelper.getBundleInstallLocation(tldBundle); + + System.err.println("jstl bundle: "+tldBundle); + System.err.println("jstl bundle location: "+tldBundleLocation); if (tldBundleLocation != null && tldBundleLocation.isDirectory()) { // try to find the jar files inside this folder @@ -170,6 +177,7 @@ public class JSTLBundleDiscoverer implements TldBundleDiscoverer { if (f.getName().endsWith(".jar") && f.isFile()) { + System.err.println("Tld jar in dir: "+f.toURI()); urls.add(f.toURI().toURL()); } else if (f.isDirectory() && f.getName().equals("lib")) @@ -178,6 +186,7 @@ public class JSTLBundleDiscoverer implements TldBundleDiscoverer { if (f2.getName().endsWith(".jar") && f2.isFile()) { + System.err.println("Tld jar in lib dir: "+f2.toURI()); urls.add(f2.toURI().toURL()); } } @@ -187,9 +196,20 @@ public class JSTLBundleDiscoverer implements TldBundleDiscoverer } else if (tldBundleLocation != null) { + System.err.println("Tld bundle uri: "+tldBundleLocation.toURI()); urls.add(tldBundleLocation.toURI().toURL()); + + String pattern = (String)deployer.getContextAttribute("org.eclipse.jetty.server.webapp.containerIncludeBundlePattern"); + pattern = (pattern==null?"":pattern); + if (!pattern.contains(tldBundle.getSymbolicName())) + { + pattern += "|"+tldBundle.getSymbolicName(); + deployer.setContextAttribute("org.eclipse.jetty.server.webapp.containerIncludeBundlePattern", pattern); + } + System.err.println("PATTERN: "+pattern); } } + return urls.toArray(new URL[urls.size()]); } @@ -209,11 +229,12 @@ public class JSTLBundleDiscoverer implements TldBundleDiscoverer * new value on a static friendly field :( * </p> */ - void fixupDtdResolution() + void fixupDtdResolution() { try { - ParserUtils.setEntityResolver(new MyFixedupEntityResolver()); + // ParserUtils.setEntityResolver(new MyFixedupEntityResolver()); + } catch (Exception e) @@ -227,21 +248,21 @@ public class JSTLBundleDiscoverer implements TldBundleDiscoverer * Instead of using the ParserUtil's classloader, we use a class that is * indeed next to the resource for sure. */ - static class MyFixedupEntityResolver implements EntityResolver - { + //static class MyFixedupEntityResolver implements EntityResolver + //{ /** * Same values than in ParserUtils... */ - static final String[] CACHED_DTD_PUBLIC_IDS = { Constants.TAGLIB_DTD_PUBLIC_ID_11, Constants.TAGLIB_DTD_PUBLIC_ID_12, + /* static final String[] CACHED_DTD_PUBLIC_IDS = { Constants.TAGLIB_DTD_PUBLIC_ID_11, Constants.TAGLIB_DTD_PUBLIC_ID_12, Constants.WEBAPP_DTD_PUBLIC_ID_22, Constants.WEBAPP_DTD_PUBLIC_ID_23, }; static final String[] CACHED_DTD_RESOURCE_PATHS = { Constants.TAGLIB_DTD_RESOURCE_PATH_11, Constants.TAGLIB_DTD_RESOURCE_PATH_12, Constants.WEBAPP_DTD_RESOURCE_PATH_22, Constants.WEBAPP_DTD_RESOURCE_PATH_23, }; static final String[] CACHED_SCHEMA_RESOURCE_PATHS = { Constants.TAGLIB_SCHEMA_RESOURCE_PATH_20, Constants.TAGLIB_SCHEMA_RESOURCE_PATH_21, - Constants.WEBAPP_SCHEMA_RESOURCE_PATH_24, Constants.WEBAPP_SCHEMA_RESOURCE_PATH_25, }; + Constants.WEBAPP_SCHEMA_RESOURCE_PATH_24, Constants.WEBAPP_SCHEMA_RESOURCE_PATH_25, };*/ - public InputSource resolveEntity(String publicId, String systemId) throws SAXException + /* public InputSource resolveEntity(String publicId, String systemId) throws SAXException { for (int i = 0; i < CACHED_DTD_PUBLIC_IDS.length; i++) { @@ -255,11 +276,11 @@ public class JSTLBundleDiscoverer implements TldBundleDiscoverer { input = JspContext.class.getResourceAsStream(resourcePath); if (input == null) - { + {*/ // if that failed try again with the original code: // although it is likely not changed. - input = this.getClass().getResourceAsStream(resourcePath); - } + /* input = this.getClass().getResourceAsStream(resourcePath); + } } if (input == null) { throw new SAXException(Localizer.getMessage("jsp.error.internal.filenotfound", resourcePath)); } InputSource isrc = new InputSource(input); @@ -269,6 +290,6 @@ public class JSTLBundleDiscoverer implements TldBundleDiscoverer return null; } - } + }*/ } diff --git a/jetty-osgi/jetty-osgi-boot-jsp/src/main/java/org/eclipse/jetty/osgi/boot/jsp/FragmentActivator.java b/jetty-osgi/jetty-osgi-boot-jsp/src/main/java/org/eclipse/jetty/osgi/boot/jsp/FragmentActivator.java index d9bd9b69e8..7417580102 100644 --- a/jetty-osgi/jetty-osgi-boot-jsp/src/main/java/org/eclipse/jetty/osgi/boot/jsp/FragmentActivator.java +++ b/jetty-osgi/jetty-osgi-boot-jsp/src/main/java/org/eclipse/jetty/osgi/boot/jsp/FragmentActivator.java @@ -18,17 +18,16 @@ package org.eclipse.jetty.osgi.boot.jsp; -import org.eclipse.jetty.osgi.boot.BundleWebAppProvider; + import org.eclipse.jetty.osgi.boot.internal.serverfactory.ServerInstanceWrapper; import org.eclipse.jetty.osgi.boot.jasper.ContainerTldBundleDiscoverer; -import org.eclipse.jetty.osgi.boot.jasper.JSTLBundleDiscoverer; import org.osgi.framework.BundleActivator; import org.osgi.framework.BundleContext; /** * FragmentActivator * - * Sets up support for jsp. All relevant jsp jars must also be installed + * Sets up support for jsp and jstl. All relevant jsp jars must also be installed * into the osgi environment. * <p> * Note that as this is part of a bundle fragment, this activator is NOT @@ -54,7 +53,6 @@ public class FragmentActivator implements BundleActivator //set up some classes that will look for bundles with tlds that must be converted //to urls and treated as if they are on the Jetty container's classpath so that //jasper can deal with them - ServerInstanceWrapper.addContainerTldBundleDiscoverer(new JSTLBundleDiscoverer()); ServerInstanceWrapper.addContainerTldBundleDiscoverer(new ContainerTldBundleDiscoverer()); } |