/* * WebletContextListener.java * * Created on November 29, 2006, 12:40 AM * * To change this template, choose Tools | Template Manager * and open the template in the editor. */ package net.java.dev.weblets.impl; import java.io.IOException; import java.io.InputStream; import java.net.MalformedURLException; import java.net.URL; import java.text.MessageFormat; import java.util.regex.Pattern; import java.util.Set; import java.util.HashSet; import java.util.Iterator; import java.util.Enumeration; import javax.servlet.ServletContext; import javax.servlet.ServletContextEvent; import javax.servlet.ServletContextListener; import net.java.dev.weblets.WebletContainer; import net.java.dev.weblets.WebletsServlet; import net.java.dev.weblets.impl.misc.ReflectUtils; import net.java.dev.weblets.impl.parse.DisconnectedEntityResolver; import net.java.dev.weblets.impl.util.ConfigurationUtils; import org.apache.commons.digester.Digester; import org.apache.commons.logging.Log; import org.apache.commons.logging.LogFactory; import org.xml.sax.SAXException; /** * @author john.fallows * @changes Werner Punz <p/> Changes from 0.4 to 1.0 <p/> Clear calling order of weblets servlets and jsf servlets <p/> Last references into the view handler * have been removed <p/> We have enforced a path trigger pattern Weblets servlet overrides any other entry it has higher priority than the faces * servlet pattern <p/> A simplified regexp handling of the pattern parsing parts Changes from 1.0 to 1.1 multiple weblet configs added as optional * context param */ public class WebletsContextListenerImpl implements ServletContextListener { public void contextInitialized(ServletContextEvent event) { ServletContext context = event.getServletContext(); WebletContainer container = createContainer(context); } public void contextDestroyed(ServletContextEvent event) { WebletContainerImpl container = (WebletContainerImpl) WebletContainerImpl.getInstance(); if (container != null) container.destroy(); } private WebletContainer createContainer(ServletContext context) { try { URL webXml = context.getResource("/WEB-INF/web.xml"); String triggerPattern = "/faces/*"; String contextPath = ""; boolean multipleConfigs = false; if (webXml != null) { InputStream in = webXml.openStream(); try { WebXmlParser parser = new WebXmlParser(); Digester digester = new Digester(); digester.setValidating(false); digester.setEntityResolver(DisconnectedEntityResolver.sharedInstance()); digester.push(parser); digester.addCallMethod("web-app/servlet", "addServlet", 2); digester.addCallParam("web-app/servlet/servlet-name", 0); digester.addCallParam("web-app/servlet/servlet-class", 1); digester.addCallMethod("web-app/servlet-mapping", "addServletMapping", 2); digester.addCallParam("web-app/servlet-mapping/servlet-name", 0); digester.addCallParam("web-app/servlet-mapping/url-pattern", 1); digester.addCallMethod("web-app/context-param", "addContextParam", 2); digester.addCallParam("web-app/context-param/param-name", 0); digester.addCallParam("web-app/context-param/param-value", 1); digester.parse(in); if (parser.getWebletPattern() != null && !parser.getWebletPattern().trim().equals("")) triggerPattern = parser.getWebletPattern(); else if (parser.getFacesPattern() != null && !parser.getFacesPattern().trim().equals("")) triggerPattern = parser.getFacesPattern(); multipleConfigs = parser.isMultipleWebletConfigs(); contextPath = ReflectUtils.calculateContextPath(parser, context); handlePathPatternWarnings(parser); } catch (SAXException e) { throw new RuntimeException(e); } finally { in.close(); } } // TODO: determine Faces Weblets ViewIds, assumes /weblets/* String webletsViewIds = "/weblets/*";// we add a dedicated // weblets/ to our url for // the filter // auto-prepend leading slash in case it is missing from web.xml // entry if (!triggerPattern.startsWith("/")) { triggerPattern = "/" + triggerPattern; } // to avoid any conflicts we reserve the weblets subnamespace // anything under /weblets is a clear // reference into a weblet resource url, anything before is the // trigger and anything after // is the version and path String formatPattern = triggerPattern.replaceFirst("/\\*", webletsViewIds).replaceFirst("/\\*", "{0}"); // TODO remove some double weblets pattern to reduce urls String webletsPattern = triggerPattern.replaceAll("\\.", "\\\\.").replaceAll("\\*", "weblets(/.*)"); MessageFormat format = new MessageFormat(formatPattern); WebletContainerImpl container = new WebletContainerImpl(context, contextPath, format, Pattern.compile(webletsPattern), multipleConfigs); // TODO we have to add the multiple configs here as well if needed try { // this is code duplication with the container we probably have to move // all of this into our utils if (multipleConfigs) { Set configs = new HashSet(); // Enumeration e = getConfigEnumeration("weblets-config.xml"); /*lets find the root configs first*/ if (multipleConfigs) { ConfigurationUtils.getValidConfigFiles("/WEB-INF/", "web.xml", configs); ConfigurationUtils.getValidConfigFiles("/META-INF/", "weblets-config.xml", configs); ConfigurationUtils.getValidConfigFiles("/META-INF/", "MANIFEST.MF", configs); ConfigurationUtils.getValidConfigFiles("/META-INF/", "context.xml", configs); } Iterator configNameIterator = configs.iterator(); // Defensive: Glassfish.v2.b25 produces duplicates in Enumeration // returned by loader.getResources() Set urls = new HashSet(); // urls.add(element); while (configNameIterator.hasNext()) { Enumeration theUrlEnum = ConfigurationUtils.getConfigEnumeration("META-INF/", (String) configNameIterator.next()); while (theUrlEnum.hasMoreElements()) { URL resource = (URL) theUrlEnum.nextElement(); urls.add(resource); } } Iterator urlIterator = urls.iterator(); while (urlIterator.hasNext()) { URL resource = (URL) urlIterator.next(); container.registerConfig(resource); } } else { URL resource = context.getResource("/WEB-INF/weblets-config.xml"); if (resource != null) container.registerConfig(resource); resource = context.getResource("/META-INF/weblets-config.xml"); if (resource != null) container.registerConfig(resource); } } catch (MalformedURLException e) { context.log("Unabled to register /WEB-INF/weblets-config.xml", e); } return container; } catch (IOException e) { throw new RuntimeException(e); } } private void handlePathPatternWarnings(WebXmlParser parser) { if (!isPathPattern(parser.getFacesPattern()) && parser.isJSFEnabled()) { Log logger = LogFactory.getLog(this.getClass()); logger.warn("JSF Enabled Weblets but path pattern is missing, some relatively referenced resources might not load "); } else if (!isPathPattern(parser.getWebletPattern()) && parser.isServletEnabled()) { Log logger = LogFactory.getLog(this.getClass()); logger.warn("Servlet Enabled Weblets but path pattern is missing, some relatively referenced resources might not load "); } } static public class WebXmlParser { public void addServlet(String servletName, String servletClass) { if ("javax.faces.webapp.FacesServlet".equals(servletClass)) _facesServletName = servletName; if (WebletsServlet.class.getName().equals(servletClass)) _webletServletName = servletName; } public void addServletMapping(String servletName, String urlPattern) { if (servletName.equals(_facesServletName)) if (_facesPattern == null || _facesPattern.trim().equals("") || isPathPattern(urlPattern)) _facesPattern = urlPattern; if (servletName.equals(_webletServletName)) if (_webletPattern == null || _webletPattern.trim().equals("") || isPathPattern(urlPattern)) _webletPattern = urlPattern; } public void addContextParam(String contextName, String contextValue) { if (contextName != null && contextName.matches(_contextPathPattern)) { _webletsContextPath = contextValue.trim(); } else if (contextName != null && contextName.matches(_multipleConfigFiles)) { _multipleWebletConfigs = true; } } public boolean isServletEnabled() { return _webletServletName != null && !_webletServletName.trim().equals(""); } public boolean isJSFEnabled() { return _facesServletName != null && !_facesServletName.trim().equals(""); } public String getFacesPattern() { return _facesPattern; } public String getWebletPattern() { return _webletPattern; } public String getWebletsContextPath() { return _webletsContextPath; } public boolean isMultipleWebletConfigs() { return _multipleWebletConfigs; } public void setMultipleWebletConfigs(boolean multipleWebletConfigs) { _multipleWebletConfigs = multipleWebletConfigs; } private String _facesServletName; private String _facesPattern; private String _webletServletName; private String _webletPattern; private String _webletsContextPath; private boolean _multipleWebletConfigs = false; /* optional servlet context params to enforce the weblt initialisation */ /** * first one allows an override of a given context path */ private static String _contextPathPattern = "^\\s*net\\.java\\.dev\\.weblets\\.contextpath\\s*$"; /** * if this one is set to true a multiple config file path search is enabled either a weblets-config must be present or a Manifest.mf all other files are * *weblets-config*.xml */ private static String _multipleConfigFiles = "\\s*net\\.java\\.dev\\.weblets\\.multipleconfigs\\s*$"; } private static boolean isPathPattern(String in) { if (in == null) return false; return in.trim().matches("^(.)*\\/.*\\/(\\*){0,1}$"); } }