001: /*
002: * Copyright 2005 Joe Walker
003: *
004: * Licensed under the Apache License, Version 2.0 (the "License");
005: * you may not use this file except in compliance with the License.
006: * You may obtain a copy of the License at
007: *
008: * http://www.apache.org/licenses/LICENSE-2.0
009: *
010: * Unless required by applicable law or agreed to in writing, software
011: * distributed under the License is distributed on an "AS IS" BASIS,
012: * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
013: * See the License for the specific language governing permissions and
014: * limitations under the License.
015: */
016: package org.directwebremoting.impl;
017:
018: import java.io.InputStream;
019: import java.util.ArrayList;
020: import java.util.List;
021: import java.util.StringTokenizer;
022:
023: import javax.servlet.ServletContext;
024: import javax.xml.parsers.DocumentBuilder;
025: import javax.xml.parsers.DocumentBuilderFactory;
026:
027: import org.apache.commons.logging.LogFactory;
028: import org.apache.commons.logging.Log;
029: import org.directwebremoting.WebContext;
030: import org.directwebremoting.WebContextFactory;
031: import org.directwebremoting.extend.PageNormalizer;
032: import org.directwebremoting.servlet.PathConstants;
033: import org.directwebremoting.util.DomUtil;
034: import org.directwebremoting.util.EmptyEntityResolver;
035: import org.directwebremoting.util.LogErrorHandler;
036: import org.w3c.dom.Document;
037: import org.w3c.dom.Element;
038: import org.w3c.dom.NodeList;
039: import org.xml.sax.InputSource;
040:
041: /**
042: * The default implementation of PageNormalizer attempts to read from
043: * <code>WEB-INF/web.xml</code> to find a <code>welcome-files</code> element,
044: * and uses a default of removing "<code>index.html</code>" and
045: * "<code>index.jsp</code>" if this procedure fails.
046: * @author Joe Walker [joe at getahead dot ltd dot uk]
047: */
048: public class DefaultPageNormalizer implements PageNormalizer {
049: /* (non-Javadoc)
050: * @see org.directwebremoting.extend.PageNormalizer#normalizePage(java.lang.String)
051: */
052: public String normalizePage(String unnormalized) {
053: synchronized (initLock) {
054: if (welcomeFiles == null) {
055: if (servletContext != null) {
056: welcomeFiles = getWebXmlWelcomeFileList(servletContext);
057: } else {
058: WebContext webContext = WebContextFactory.get();
059: if (webContext == null) {
060: log
061: .warn("Can't find ServletContext to check for <welcome-file-list> in web.xml. Assuming defaults.");
062: log
063: .warn(" - To prevent this message from happening, either call the PageNormalizer from a DWR thread");
064: log
065: .warn(" - Or seed the PageNormalizer with a ServletContext before access from outside a DWR thread");
066: } else {
067: ServletContext threadServletContext = webContext
068: .getServletContext();
069: welcomeFiles = getWebXmlWelcomeFileList(threadServletContext);
070: }
071: }
072: }
073:
074: if (welcomeFiles == null) {
075: log
076: .debug("Using default welcome file list (index.[jsp|htm[l]])");
077: welcomeFiles = getDefaultWelcomeFileList();
078: }
079: }
080:
081: if (unnormalized == null) {
082: return null;
083: }
084:
085: String normalized = unnormalized;
086:
087: if (!normalizeIncludesQueryString) {
088: int queryPos = normalized.indexOf('?');
089: if (queryPos != -1) {
090: normalized = normalized.substring(0, queryPos);
091: }
092: }
093:
094: for (String welcomeFile : welcomeFiles) {
095: if (normalized.endsWith(welcomeFile)) {
096: normalized = normalized.substring(0, normalized
097: .length()
098: - welcomeFile.length());
099: break;
100: }
101: }
102:
103: return normalized;
104: }
105:
106: /**
107: * Accessor for the list of components to strip to normalize a filename
108: * @param context Our route to reading web.xml
109: * @return A list of the welcome files from web.xml or null if none are found there
110: */
111: protected static List<String> getWebXmlWelcomeFileList(
112: ServletContext context) {
113: try {
114: InputStream in = context
115: .getResourceAsStream(PathConstants.RESOURCE_WEB_XML);
116: if (in == null) {
117: log.warn("Missing " + PathConstants.RESOURCE_WEB_XML);
118: return null;
119: }
120:
121: synchronized (DefaultPageNormalizer.class) {
122: if (buildFactory == null) {
123: buildFactory = DocumentBuilderFactory.newInstance();
124: buildFactory.setValidating(false);
125: }
126: }
127:
128: DocumentBuilder builder = buildFactory.newDocumentBuilder();
129: builder.setEntityResolver(new EmptyEntityResolver());
130: builder.setErrorHandler(new LogErrorHandler());
131:
132: InputSource is = new InputSource(in);
133: Document doc = builder.parse(is);
134:
135: Element webapp = doc.getDocumentElement();
136: NodeList welcomeFileListNodes = webapp
137: .getElementsByTagName("welcome-file-list");
138: if (welcomeFileListNodes.getLength() == 0) {
139: log
140: .debug("web.xml contains no <welcome-file-list> element");
141: return null;
142: }
143:
144: List<String> reply = new ArrayList<String>();
145: for (int i = 0; i < welcomeFileListNodes.getLength(); i++) {
146: Element welcomeFileListNode = (Element) welcomeFileListNodes
147: .item(i);
148: NodeList welcomeFileNodes = welcomeFileListNode
149: .getElementsByTagName("welcome-file");
150: for (int j = 0; j < welcomeFileNodes.getLength(); j++) {
151: Element welcomeFileNode = (Element) welcomeFileNodes
152: .item(j);
153: String welcomeFile = DomUtil
154: .getText(welcomeFileNode);
155: reply.add(welcomeFile);
156:
157: log.debug("Adding welcome-file: " + welcomeFile);
158: }
159: }
160:
161: return reply;
162: } catch (Exception ex) {
163: log.warn("Failed to calculate welcome files from web.xml.",
164: ex);
165: return null;
166: }
167: }
168:
169: /**
170: * Use the default list of components to strip to normalize a filename
171: * @return A list of the default welcome files
172: */
173: protected static List<String> getDefaultWelcomeFileList() {
174: List<String> reply = new ArrayList<String>();
175: reply.add("index.html");
176: reply.add("index.htm");
177: reply.add("index.jsp");
178: return reply;
179: }
180:
181: /**
182: * Accessor for the list of components to strip to normalize a filename
183: * @param welcomeFiles the welcomeFiles to set
184: */
185: public void setWelcomeFileList(List<String> welcomeFiles) {
186: this .welcomeFiles = welcomeFiles;
187: }
188:
189: /**
190: * Accessor for the list of components to strip to normalize a filename
191: * @param welcomeFileNames the welcomeFiles to set as a comma or newline
192: * separated list.
193: */
194: public void setWelcomeFiles(String welcomeFileNames) {
195: StringTokenizer st = new StringTokenizer(welcomeFileNames,
196: "\n,");
197: while (st.hasMoreTokens()) {
198: welcomeFiles.add(st.nextToken());
199: }
200: }
201:
202: /**
203: * Does the page normalizer include query strings in it's definition of
204: * pages?
205: * @param normalizeIncludesQueryString The new value
206: */
207: public void setNormalizeIncludesQueryString(
208: boolean normalizeIncludesQueryString) {
209: this .normalizeIncludesQueryString = normalizeIncludesQueryString;
210: }
211:
212: /**
213: * @param servletContext the servletContext to set
214: */
215: public void setServletContext(ServletContext servletContext) {
216: this .servletContext = servletContext;
217: }
218:
219: /**
220: * We need one of these to do the init process.
221: */
222: private ServletContext servletContext = null;
223:
224: /**
225: * Does the page normalizer include query strings in it's definition of
226: * pages?
227: */
228: protected boolean normalizeIncludesQueryString = false;
229:
230: /**
231: * How we create new documents
232: */
233: private static DocumentBuilderFactory buildFactory = null;
234:
235: /**
236: * The lock to prevent 2 things from calling init at the same time
237: */
238: protected static final Object initLock = new Object();
239:
240: /**
241: * The list of filename components to strip to normalize a filename
242: */
243: private List<String> welcomeFiles;
244:
245: /**
246: * The log stream
247: */
248: private static final Log log = LogFactory
249: .getLog(DefaultPageNormalizer.class);
250: }
|