📄 taglibfactory.java
字号:
/* * Copyright (c) 2003 The Visigoth Software Society. All rights * reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions * are met: * * 1. Redistributions of source code must retain the above copyright * notice, this list of conditions and the following disclaimer. * * 2. Redistributions in binary form must reproduce the above copyright * notice, this list of conditions and the following disclaimer in * the documentation and/or other materials provided with the * distribution. * * 3. The end-user documentation included with the redistribution, if * any, must include the following acknowledgement: * "This product includes software developed by the * Visigoth Software Society (http://www.visigoths.org/)." * Alternately, this acknowledgement may appear in the software itself, * if and wherever such third-party acknowledgements normally appear. * * 4. Neither the name "FreeMarker", "Visigoth", nor any of the names of the * project contributors may be used to endorse or promote products derived * from this software without prior written permission. For written * permission, please contact visigoths@visigoths.org. * * 5. Products derived from this software may not be called "FreeMarker" or "Visigoth" * nor may "FreeMarker" or "Visigoth" appear in their names * without prior written permission of the Visigoth Software Society. * * THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESSED OR IMPLIED * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE * DISCLAIMED. IN NO EVENT SHALL THE VISIGOTH SOFTWARE SOCIETY OR * ITS CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF * USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT * OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF * SUCH DAMAGE. * ==================================================================== * * This software consists of voluntary contributions made by many * individuals on behalf of the Visigoth Software Society. For more * information on the Visigoth Software Society, please see * http://www.visigoths.org/ */package freemarker.ext.jsp;import java.beans.IntrospectionException;import java.io.ByteArrayInputStream;import java.io.FilterInputStream;import java.io.IOException;import java.io.InputStream;import java.net.MalformedURLException;import java.util.ArrayList;import java.util.HashMap;import java.util.Iterator;import java.util.List;import java.util.Map;import java.util.Set;import java.util.zip.ZipEntry;import java.util.zip.ZipInputStream;import javax.servlet.ServletContext;import javax.servlet.http.HttpServletRequest;import javax.xml.parsers.ParserConfigurationException;import javax.xml.parsers.SAXParserFactory;import org.xml.sax.Attributes;import org.xml.sax.EntityResolver;import org.xml.sax.InputSource;import org.xml.sax.Locator;import org.xml.sax.SAXException;import org.xml.sax.SAXParseException;import org.xml.sax.XMLReader;import org.xml.sax.helpers.DefaultHandler;import freemarker.core.Environment;import freemarker.ext.servlet.FreemarkerServlet;import freemarker.ext.servlet.HttpRequestHashModel;import freemarker.log.Logger;import freemarker.template.TemplateHashModel;import freemarker.template.TemplateModel;import freemarker.template.TemplateModelException;import freemarker.template.utility.ClassUtil;/** * A hash model associated with a servlet context that can load JSP tag * libraries associated with that servlet context. An instance of this class is * made available in the root data model of templates executed by * {@link freemarker.ext.servlet.FreemarkerServlet} under key * <tt>JspTaglibs</tt>. It can be added to custom servlets as well to enable JSP * taglib integration in them as well. * @version $Id: TaglibFactory.java,v 1.26 2005/06/13 20:52:55 szegedia Exp $ * @author Attila Szegedi */public class TaglibFactory implements TemplateHashModel { private static final Logger logger = Logger.getLogger("freemarker.jsp"); // No TLDs have been looked up yet private static final int LOOKUP_NONE = 0; // Only explicit TLDs in web.xml have been looked up private static final int LOOKUP_WEB_XML = 1; // Both explicit TLDs and those in JARs have been looked up private static final int LOOKUP_JARS = 2; private final ServletContext ctx; private final Map taglibs = new HashMap(); private final Map locations = new HashMap(); private int lookupPhase = LOOKUP_NONE; /** * Creates a new JSP taglib factory that will be used to load JSP taglibs * for the web application represented by the passed servlet context. * @param ctx the servlet context whose JSP tag libraries will this factory * load. */ public TaglibFactory(ServletContext ctx) { this.ctx = ctx; } /** * Retrieves a JSP tag library identified by an URI. The matching of the URI * to a JSP taglib is done as described in the JSP 1.2 FCS specification. * @param uri the URI that describes the JSP taglib. It can be any of the * three forms allowed by the JSP specification: absolute URI, root relative * URI and non-root relative URI. Note that if a non-root relative URI is * used it is resolved relative to the URL of the current request. In this * case, the current request is obtained by looking up a * {@link HttpRequestHashModel} object named <tt>Request</tt> in the root * data model. FreemarkerServlet provides this object under the expected * name, and custom servlets that want to integrate JSP taglib support * should do the same. * @return a hash model representing the JSP taglib. Each element of this * hash model represents a single custom tag from the library, implemented * as a {@link freemarker.template.TemplateTransformModel}. */ public TemplateModel get(String uri) throws TemplateModelException { uri = resolveRelativeUri(uri); synchronized (taglibs) { Taglib taglib = null; taglib = (Taglib) taglibs.get(uri); if(taglib != null) { return taglib; } taglib = new Taglib(); try { do { if(taglib.load(uri, ctx, locations)) { taglibs.put(uri, taglib); return taglib; } } while(getMoreTaglibLocations()); } catch(TemplateModelException e) { throw e; } catch(Exception e) { throw new TemplateModelException("Could not load taglib information", e); } return null; } } /** * Returns false. */ public boolean isEmpty() { return false; } private boolean getMoreTaglibLocations() throws MalformedURLException, ParserConfigurationException, IOException, SAXException { switch(lookupPhase) { case LOOKUP_NONE: { getLocationsFromWebXml(); lookupPhase = LOOKUP_WEB_XML; return true; } case LOOKUP_WEB_XML: { getLocationsFromLibJars(); lookupPhase = LOOKUP_JARS; return true; } default : { return false; } } } private void getLocationsFromWebXml() throws MalformedURLException, ParserConfigurationException, IOException, SAXException { WebXmlParser webXmlParser = new WebXmlParser(locations); InputStream in = ctx.getResourceAsStream("/WEB-INF/web.xml"); if (in == null) { // No /WEB-INF/web.xml - do nothing return; } try { parseXml(in, ctx.getResource("/WEB-INF/web.xml").toExternalForm(), webXmlParser); } finally { in.close(); } } private static class WebXmlParser extends DefaultHandler { private final Map locations; private StringBuffer buf; private String uri; private String location; WebXmlParser(Map locations) { this.locations = locations; } public void startElement( String nsuri, String localName, String qName, Attributes atts) { if ("taglib-uri".equals(qName) || "taglib-location".equals(qName)) { buf = new StringBuffer(); } } public void characters(char[] chars, int off, int len) { if (buf != null) { buf.append(chars, off, len); } } public void endElement(String nsuri, String localName, String qName) { if ("taglib-uri".equals(qName)) { uri = buf.toString().trim(); buf = null; } else if ("taglib-location".equals(qName)) { location = buf.toString().trim(); if(location.indexOf("://") == -1 && !location.startsWith("/")) { location = "/WEB-INF/" + location; } buf = null; } else if ("taglib".equals(qName)) { String[] loc = new String[2]; loc[0] = location; if(location.endsWith(".jar") || location.endsWith(".zip")) { loc[1] = "META-INF/taglib.tld"; } locations.put(uri, loc); if(logger.isDebugEnabled()) { logger.debug("web.xml assigned URI " + uri + " to location " + loc[0] + (loc[1] != null ? "!" + loc[1] : "")); } } } } private void getLocationsFromLibJars() throws ParserConfigurationException, IOException, SAXException { Set libs = ctx.getResourcePaths("/WEB-INF/lib"); for (Iterator iter = libs.iterator(); iter.hasNext();) { String path = (String) iter.next(); if(path.endsWith(".jar") || path.endsWith(".zip")) { ZipInputStream zin = new ZipInputStream(ctx.getResourceAsStream(path)); // Make stream uncloseable by XML parsers InputStream uin = new FilterInputStream(zin) { public void close() { } }; try { for(;;) { ZipEntry ze = zin.getNextEntry(); if(ze == null) { break; } String zname = ze.getName(); if(zname.startsWith("META-INF/") && zname.endsWith(".tld")) { String url = "jar:" + ctx.getResource(path).toExternalForm() + "!" + zname; String loc = getTldUri(uin, url); if(loc != null) { locations.put(loc, new String[] { path, zname }); if(logger.isDebugEnabled()) { logger.debug("libjar assigned URI " + loc + " to location " + path + "!" + zname); } } } } } finally { zin.close(); } } } } private String getTldUri(InputStream in, String url) throws ParserConfigurationException, IOException, SAXException { TldUriReader tur = new TldUriReader(); parseXml(in, url, tur); return tur.getUri(); } private static class TldUriReader extends DefaultHandler { private StringBuffer buf; private String uri; TldUriReader() { } String getUri() { return uri; } public void startElement(
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -