You are viewing a plain text version of this content. The canonical link for it is here.
Posted to dev@tomcat.apache.org by re...@locus.apache.org on 2000/07/31 08:28:03 UTC
cvs commit: jakarta-tomcat/proposals/catalina/src/share/org/apache/tomcat/util XMLWriter.java
remm 00/07/30 23:28:02
Modified: proposals/catalina/src/share/org/apache/tomcat/resources
FileResources.java
proposals/catalina/src/share/org/apache/tomcat/servlets
DefaultServlet.java LocalStrings.properties
Added: proposals/catalina/src/share/org/apache/tomcat/servlets
WebdavServlet.java
proposals/catalina/src/share/org/apache/tomcat/util
XMLWriter.java
Log:
- New WebdavServlet class in servlets package. Use it instead
of DefaultServlet to get DAV functionality.
- Adds limited read only WebDAV support. Only PROPFIND is
supported right now. I tested with IE 5 and it works :-)
- More DAV support coming soon. Full DAV level 2 support is planned.
- The new WebdavServlet is an extension of DefaultServlet. It is
based on code from the Jakarta Slide project.
- Fix to the file implementation of
Resources.getCollectionMembers(). The path needs to be translated a bit.
- Add an XML elements generation utility class (XMLWriter), which
was also taken from Slide.
Revision Changes Path
1.4 +15 -7 jakarta-tomcat/proposals/catalina/src/share/org/apache/tomcat/resources/FileResources.java
Index: FileResources.java
===================================================================
RCS file: /home/cvs/jakarta-tomcat/proposals/catalina/src/share/org/apache/tomcat/resources/FileResources.java,v
retrieving revision 1.3
retrieving revision 1.4
diff -u -r1.3 -r1.4
--- FileResources.java 2000/07/30 23:20:22 1.3
+++ FileResources.java 2000/07/31 06:27:59 1.4
@@ -1,7 +1,7 @@
/*
- * $Header: /home/cvs/jakarta-tomcat/proposals/catalina/src/share/org/apache/tomcat/resources/FileResources.java,v 1.3 2000/07/30 23:20:22 remm Exp $
- * $Revision: 1.3 $
- * $Date: 2000/07/30 23:20:22 $
+ * $Header: /home/cvs/jakarta-tomcat/proposals/catalina/src/share/org/apache/tomcat/resources/FileResources.java,v 1.4 2000/07/31 06:27:59 remm Exp $
+ * $Revision: 1.4 $
+ * $Date: 2000/07/31 06:27:59 $
*
* ====================================================================
*
@@ -89,7 +89,7 @@
* since they were cached.
*
* @author Craig R. McClanahan
- * @version $Revision: 1.3 $ $Date: 2000/07/30 23:20:22 $
+ * @version $Revision: 1.4 $ $Date: 2000/07/31 06:27:59 $
*/
public final class FileResources extends ResourcesBase {
@@ -469,10 +469,18 @@
validate(path);
File file = file(normalize(path));
- if (file != null)
- return (file.list());
- else
+ if (file != null) {
+ String normalized = normalize(path);
+ if (normalized == null)
+ return (null);
+ String[] dirList = file.list();
+ for (int i=0; i<dirList.length; i++) {
+ dirList[i] = normalize(normalized + "/" + dirList[i]);
+ }
+ return dirList;
+ } else {
return (null);
+ }
}
1.15 +198 -219 jakarta-tomcat/proposals/catalina/src/share/org/apache/tomcat/servlets/DefaultServlet.java
Index: DefaultServlet.java
===================================================================
RCS file: /home/cvs/jakarta-tomcat/proposals/catalina/src/share/org/apache/tomcat/servlets/DefaultServlet.java,v
retrieving revision 1.14
retrieving revision 1.15
diff -u -r1.14 -r1.15
--- DefaultServlet.java 2000/07/30 23:23:34 1.14
+++ DefaultServlet.java 2000/07/31 06:28:00 1.15
@@ -1,7 +1,7 @@
/*
- * $Header: /home/cvs/jakarta-tomcat/proposals/catalina/src/share/org/apache/tomcat/servlets/DefaultServlet.java,v 1.14 2000/07/30 23:23:34 remm Exp $
- * $Revision: 1.14 $
- * $Date: 2000/07/30 23:23:34 $
+ * $Header: /home/cvs/jakarta-tomcat/proposals/catalina/src/share/org/apache/tomcat/servlets/DefaultServlet.java,v 1.15 2000/07/31 06:28:00 remm Exp $
+ * $Revision: 1.15 $
+ * $Date: 2000/07/31 06:28:00 $
*
* ====================================================================
*
@@ -108,77 +108,62 @@
*
* @author Craig R. McClanahan
* @author Remy Maucherat
- * @version $Revision: 1.14 $ $Date: 2000/07/30 23:23:34 $
+ * @version $Revision: 1.15 $ $Date: 2000/07/31 06:28:00 $
*/
-public final class DefaultServlet
+public class DefaultServlet
extends HttpServlet {
- // -------------------------------------------------------------- Constants
-
-
- /**
- * Maximum file size for which content is cached. 32 ko by default.
- */
- public static final long MAX_SIZE_CACHE = 32768;
-
-
- /**
- * Cache entry timeout. 10s by default.
- */
- public static final long CACHE_ENTRY_TIMEOUT = 10000;
-
-
// ----------------------------------------------------- Instance Variables
/**
* The debugging detail level for this servlet.
*/
- private int debug = 0;
+ protected int debug = 0;
/**
* The input buffer size to use when serving resources.
*/
- private int input = 2048;
+ protected int input = 2048;
/**
* Should we generate directory listings when no welcome file is present?
*/
- private boolean listings = true;
+ protected boolean listings = true;
/**
* The output buffer size to use when serving resources.
*/
- private int output = 2048;
+ protected int output = 2048;
/**
* The set of welcome files for this web application
*/
- private String welcomes[] = new String[0];
+ protected String welcomes[] = new String[0];
/**
* MD5 message digest provider.
*/
- private static MessageDigest md5Helper;
+ protected static MessageDigest md5Helper;
/**
* The MD5 helper object for this class.
*/
- private static final MD5Encoder md5Encoder = new MD5Encoder();
+ protected static final MD5Encoder md5Encoder = new MD5Encoder();
/**
* The set of SimpleDateFormat formats to use in getDateHeader().
*/
- private static final SimpleDateFormat formats[] = {
+ protected static final SimpleDateFormat formats[] = {
new SimpleDateFormat("EEE, dd MMM yyyy HH:mm:ss zzz", Locale.US),
new SimpleDateFormat("EEEEEE, dd-MMM-yy HH:mm:ss zzz", Locale.US),
new SimpleDateFormat("EEE MMMM d HH:mm:ss yyyy", Locale.US)
@@ -188,19 +173,13 @@
/**
* MIME multipart separation string
*/
- private static final String mimeSeparation = "THIS_STRING_SEPARATES";
+ protected static final String mimeSeparation = "CATALINA_MIME_BOUNDARY";
/**
- * File descriptor cache
- */
- private Hashtable fileCache = new Hashtable();
-
-
- /**
* The string manager for this package.
*/
- private static StringManager sm =
+ protected static StringManager sm =
StringManager.getManager(Constants.Package);
@@ -337,6 +316,188 @@
+ // ------------------------------------------------------ Protected Methods
+
+
+ /**
+ * Check if the conditions specified in the optional If headers are
+ * satisfied.
+ *
+ * @param request The servlet request we are processing
+ * @param response The servlet response we are creating
+ * @param resourceInfo File object
+ * @return boolean true if the resource meets all the specified conditions,
+ * and false if any of the conditions is not satisfied, in which case
+ * request processing is stopped
+ */
+ protected boolean checkIfHeaders(HttpServletRequest request,
+ HttpServletResponse response,
+ ResourceInfo resourceInfo)
+ throws IOException {
+
+ String eTag = getETag(resourceInfo, true);
+ long fileLength = resourceInfo.length;
+ long lastModified = resourceInfo.date;
+
+ StringTokenizer commaTokenizer;
+
+ String headerValue;
+
+ // Checking If-Match
+ headerValue = request.getHeader("If-Match");
+ if (headerValue != null) {
+ if (headerValue.indexOf("*") == -1) {
+
+ commaTokenizer = new StringTokenizer(headerValue, ",");
+ boolean conditionSatisfied = false;
+
+ while (!conditionSatisfied && commaTokenizer.hasMoreTokens()) {
+ String currentToken = commaTokenizer.nextToken();
+ if (currentToken.trim().equals(eTag))
+ conditionSatisfied = true;
+ }
+
+ // If none of the given ETags match, 412 Precodition failed is
+ // sent back
+ if (!conditionSatisfied) {
+ response.sendError
+ (HttpServletResponse.SC_PRECONDITION_FAILED);
+ return false;
+ }
+
+ }
+ }
+
+ // Checking If-Modified-Since
+ headerValue = request.getHeader("If-Modified-Since");
+ if (headerValue != null) {
+
+ // If an If-None-Match header has been specified, if modified since
+ // is ignored.
+ if (request.getHeader("If-None-Match") == null) {
+
+ Date date = null;
+
+ // Parsing the HTTP Date
+ for (int i = 0; (date == null) && (i < formats.length); i++) {
+ try {
+ date = formats[i].parse(headerValue);
+ } catch (ParseException e) {
+ ;
+ }
+ }
+
+ if ((date != null)
+ && (lastModified <= (date.getTime() + 1000)) ) {
+ // The entity has not been modified since the date
+ // specified by the client. This is not an error case.
+ response.sendError
+ (HttpServletResponse.SC_NOT_MODIFIED);
+ System.out.println("Not modified");
+ return false;
+ }
+
+ }
+
+ }
+
+ // Checking If-None-Match
+ headerValue = request.getHeader("If-None-Match");
+ if (headerValue != null) {
+ if (headerValue.indexOf("*") == -1) {
+
+ commaTokenizer = new StringTokenizer(headerValue, ",");
+ boolean conditionSatisfied = false;
+
+ while (!conditionSatisfied && commaTokenizer.hasMoreTokens()) {
+ String currentToken = commaTokenizer.nextToken();
+ if (currentToken.trim().equals(eTag))
+ conditionSatisfied = true;
+ }
+
+ if (conditionSatisfied) {
+
+ // For GET and HEAD, we should respond with
+ // 304 Not Modified.
+ // For every other method, 412 Precondition Failed is sent
+ // back.
+ if ( ("GET".equals(request.getMethod()))
+ || ("HEAD".equals(request.getMethod())) ) {
+ response.sendError
+ (HttpServletResponse.SC_NOT_MODIFIED);
+ return false;
+ } else {
+ response.sendError
+ (HttpServletResponse.SC_PRECONDITION_FAILED);
+ return false;
+ }
+ }
+
+ } else {
+ if (resourceInfo.exists()) {
+
+ }
+ }
+ }
+
+ // Checking If-Unmodified-Since
+ headerValue = request.getHeader("If-Unmodified-Since");
+ if (headerValue != null) {
+
+ Date date = null;
+
+ // Parsing the HTTP Date
+ for (int i = 0; (date == null) && (i < formats.length); i++) {
+ try {
+ date = formats[i].parse(headerValue);
+ } catch (ParseException e) {
+ ;
+ }
+ }
+
+ if ( (date != null) && (lastModified > date.getTime()) ) {
+ // The entity has not been modified since the date
+ // specified by the client. This is not an error case.
+ response.sendError
+ (HttpServletResponse.SC_PRECONDITION_FAILED);
+ return false;
+ }
+
+ }
+
+ return true;
+ }
+
+
+ /**
+ * Get the ETag value associated with a file.
+ *
+ * @param resourceInfo File object
+ * @param strong True if we want a strong ETag, in which case a checksum
+ * of the file has to be calculated
+ */
+ protected String getETagValue(ResourceInfo resourceInfo, boolean strong) {
+ // FIXME : Compute a strong ETag if requested, using an MD5 digest
+ // of the file contents
+ return resourceInfo.length + "-" + resourceInfo.date;
+ }
+
+
+ /**
+ * Get the ETag associated with a file.
+ *
+ * @param resourceInfo File object
+ * @param strong True if we want a strong ETag, in which case a checksum
+ * of the file has to be calculated
+ */
+ protected String getETag(ResourceInfo resourceInfo, boolean strong) {
+ if (strong)
+ return "\"" + getETagValue(resourceInfo, strong) + "\"";
+ else
+ return "W/\"" + getETagValue(resourceInfo, strong) + "\"";
+ }
+
+
// -------------------------------------------------------- Private Methods
@@ -474,9 +635,6 @@
exception = copyRange(istream, ostream, currentRange.start,
currentRange.end);
- //ostream.println();
- //ostream.println();
-
try {
istream.close();
} catch (Throwable t) {
@@ -819,185 +977,6 @@
/**
- * Check if the conditions specified in the optional If headers are
- * satisfied.
- *
- * @param request The servlet request we are processing
- * @param response The servlet response we are creating
- * @param resourceInfo File object
- * @return boolean true if the resource meets all the specified conditions,
- * and false if any of the conditions is not satisfied, in which case
- * request processing is stopped
- */
- private boolean checkIfHeaders(HttpServletRequest request,
- HttpServletResponse response,
- ResourceInfo resourceInfo)
- throws IOException {
-
- String eTag = getETag(resourceInfo, true);
- long fileLength = resourceInfo.length;
- long lastModified = resourceInfo.date;
-
- StringTokenizer commaTokenizer;
-
- String headerValue;
-
- // Checking If-Match
- headerValue = request.getHeader("If-Match");
- if (headerValue != null) {
- if (headerValue.indexOf("*") == -1) {
-
- commaTokenizer = new StringTokenizer(headerValue, ",");
- boolean conditionSatisfied = false;
-
- while (!conditionSatisfied && commaTokenizer.hasMoreTokens()) {
- String currentToken = commaTokenizer.nextToken();
- if (currentToken.trim().equals(eTag))
- conditionSatisfied = true;
- }
-
- // If none of the given ETags match, 412 Precodition failed is
- // sent back
- if (!conditionSatisfied) {
- response.sendError
- (HttpServletResponse.SC_PRECONDITION_FAILED);
- return false;
- }
-
- }
- }
-
- // Checking If-Modified-Since
- headerValue = request.getHeader("If-Modified-Since");
- if (headerValue != null) {
-
- // If an If-None-Match header has been specified, if modified since
- // is ignored.
- if (request.getHeader("If-None-Match") == null) {
-
- Date date = null;
-
- // Parsing the HTTP Date
- for (int i = 0; (date == null) && (i < formats.length); i++) {
- try {
- date = formats[i].parse(headerValue);
- } catch (ParseException e) {
- ;
- }
- }
-
- if ((date != null)
- && (lastModified <= (date.getTime() + 1000)) ) {
- // The entity has not been modified since the date
- // specified by the client. This is not an error case.
- response.sendError
- (HttpServletResponse.SC_NOT_MODIFIED);
- System.out.println("Not modified");
- return false;
- }
-
- }
-
- }
-
- // Checking If-None-Match
- headerValue = request.getHeader("If-None-Match");
- if (headerValue != null) {
- if (headerValue.indexOf("*") == -1) {
-
- commaTokenizer = new StringTokenizer(headerValue, ",");
- boolean conditionSatisfied = false;
-
- while (!conditionSatisfied && commaTokenizer.hasMoreTokens()) {
- String currentToken = commaTokenizer.nextToken();
- if (currentToken.trim().equals(eTag))
- conditionSatisfied = true;
- }
-
- if (conditionSatisfied) {
-
- // For GET and HEAD, we should respond with
- // 304 Not Modified.
- // For every other method, 412 Precondition Failed is sent
- // back.
- if ( ("GET".equals(request.getMethod()))
- || ("HEAD".equals(request.getMethod())) ) {
- response.sendError
- (HttpServletResponse.SC_NOT_MODIFIED);
- return false;
- } else {
- response.sendError
- (HttpServletResponse.SC_PRECONDITION_FAILED);
- return false;
- }
- }
-
- } else {
- if (resourceInfo.exists()) {
-
- }
- }
- }
-
- // Checking If-Unmodified-Since
- headerValue = request.getHeader("If-Unmodified-Since");
- if (headerValue != null) {
-
- Date date = null;
-
- // Parsing the HTTP Date
- for (int i = 0; (date == null) && (i < formats.length); i++) {
- try {
- date = formats[i].parse(headerValue);
- } catch (ParseException e) {
- ;
- }
- }
-
- if ( (date != null) && (lastModified > date.getTime()) ) {
- // The entity has not been modified since the date
- // specified by the client. This is not an error case.
- response.sendError
- (HttpServletResponse.SC_PRECONDITION_FAILED);
- return false;
- }
-
- }
-
- return true;
- }
-
-
- /**
- * Get the ETag value associated with a file.
- *
- * @param resourceInfo File object
- * @param strong True if we want a strong ETag, in which case a checksum
- * of the file has to be calculated
- */
- private String getETagValue(ResourceInfo resourceInfo, boolean strong) {
- // FIXME : Compute a strong ETag if requested, using an MD5 digest
- // of the file contents
- return resourceInfo.length + "-" + resourceInfo.date;
- }
-
-
- /**
- * Get the ETag associated with a file.
- *
- * @param resourceInfo File object
- * @param strong True if we want a strong ETag, in which case a checksum
- * of the file has to be calculated
- */
- private String getETag(ResourceInfo resourceInfo, boolean strong) {
- if (strong)
- return "\"" + getETagValue(resourceInfo, strong) + "\"";
- else
- return "W/\"" + getETagValue(resourceInfo, strong) + "\"";
- }
-
-
- /**
* Parse the range header.
*
* @param request The servlet request we are processing
@@ -1155,7 +1134,7 @@
// ---------------------------------------------- ResourceInfo Inner Class
- private class ResourceInfo {
+ protected class ResourceInfo {
/**
1.2 +1 -0 jakarta-tomcat/proposals/catalina/src/share/org/apache/tomcat/servlets/LocalStrings.properties
Index: LocalStrings.properties
===================================================================
RCS file: /home/cvs/jakarta-tomcat/proposals/catalina/src/share/org/apache/tomcat/servlets/LocalStrings.properties,v
retrieving revision 1.1
retrieving revision 1.2
diff -u -r1.1 -r1.2
--- LocalStrings.properties 2000/06/24 19:48:56 1.1
+++ LocalStrings.properties 2000/07/31 06:28:01 1.2
@@ -2,3 +2,4 @@
defaultservlet.upto=Up to:
defaultservlet.subdirectories=Subdirectories:
defaultservlet.files=Files:
+webdavservlet.jaxpfailed=JAXP initialization failed
1.1 jakarta-tomcat/proposals/catalina/src/share/org/apache/tomcat/servlets/WebdavServlet.java
Index: WebdavServlet.java
===================================================================
/*
* $Header: /home/cvs/jakarta-tomcat/proposals/catalina/src/share/org/apache/tomcat/servlets/WebdavServlet.java,v 1.1 2000/07/31 06:28:01 remm Exp $
* $Revision: 1.1 $
* $Date: 2000/07/31 06:28:01 $
*
* ====================================================================
*
* The Apache Software License, Version 1.1
*
* Copyright (c) 1999 The Apache Software Foundation. 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 acknowlegement:
* "This product includes software developed by the
* Apache Software Foundation (http://www.apache.org/)."
* Alternately, this acknowlegement may appear in the software itself,
* if and wherever such third-party acknowlegements normally appear.
*
* 4. The names "The Jakarta Project", "Tomcat", and "Apache Software
* Foundation" must not be used to endorse or promote products derived
* from this software without prior written permission. For written
* permission, please contact apache@apache.org.
*
* 5. Products derived from this software may not be called "Apache"
* nor may "Apache" appear in their names without prior written
* permission of the Apache Group.
*
* 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 APACHE SOFTWARE FOUNDATION 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 Apache Software Foundation. For more
* information on the Apache Software Foundation, please see
* <http://www.apache.org/>.
*
* [Additional notices, if required by prior licensing conditions]
*
*/
package org.apache.tomcat.servlets;
import java.io.BufferedInputStream;
import java.io.File;
import java.io.FileInputStream;
import java.io.InputStream;
import java.io.IOException;
import java.io.PrintWriter;
import java.io.Writer;
import java.net.MalformedURLException;
import java.net.URL;
import java.sql.Timestamp;
import java.util.Date;
import java.util.Enumeration;
import java.util.Vector;
import java.util.Stack;
import java.util.StringTokenizer;
import java.util.Locale;
import java.util.Hashtable;
import java.text.ParseException;
import java.text.SimpleDateFormat;
import java.security.MessageDigest;
import java.security.NoSuchAlgorithmException;
import javax.servlet.RequestDispatcher;
import javax.servlet.ServletException;
import javax.servlet.ServletContext;
import javax.servlet.ServletOutputStream;
import javax.servlet.http.HttpServlet;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import org.w3c.dom.Node;
import org.w3c.dom.NodeList;
import org.w3c.dom.Element;
import org.w3c.dom.Document;
import org.xml.sax.InputSource;
import javax.xml.parsers.DocumentBuilder;
import javax.xml.parsers.DocumentBuilderFactory;
import javax.xml.parsers.ParserConfigurationException;
import org.apache.tomcat.Resources;
import org.apache.tomcat.core.ApplicationContext;
import org.apache.tomcat.resources.ResourceBean;
import org.apache.tomcat.resources.DirectoryBean;
import org.apache.tomcat.util.MD5Encoder;
import org.apache.tomcat.util.StringManager;
import org.apache.tomcat.util.XMLWriter;
import org.apache.tomcat.util.xml.SaxContext;
import org.apache.tomcat.util.xml.XmlAction;
import org.apache.tomcat.util.xml.XmlMapper;
/**
* Servlet which adds support for WebDAV level 2. All the basic HTTP requests
* are handled by the DefaultServlet.
*
* @author Remy Maucherat
* @version $Revision: 1.1 $ $Date: 2000/07/31 06:28:01 $
*/
public final class WebdavServlet
extends DefaultServlet {
// -------------------------------------------------------------- Constants
private static final String METHOD_PROPFIND = "PROPFIND";
private static final String METHOD_PROPPATCH = "PROPPATCH";
private static final String METHOD_MKCOL = "MKCOL";
private static final String METHOD_COPY = "COPY";
private static final String METHOD_MOVE = "MOVE";
private static final String METHOD_LOCK = "LOCK";
private static final String METHOD_UNLOCK = "UNLOCK";
/**
* Default depth is infite.
*/
private static final int INFINITY = 3; // To limit tree browsing a bit
/**
* PROPFIND - Specify a property mask.
*/
private static final int FIND_BY_PROPERTY = 0;
/**
* PROPFIND - Display all properties.
*/
private static final int FIND_ALL_PROP = 1;
/**
* PROPFIND - Return property names.
*/
private static final int FIND_PROPERTY_NAMES = 2;
// ----------------------------------------------------- Instance Variables
/**
* JAXP Document builder.
*/
private DocumentBuilder documentBuilder;
/**
* Read only flag. By default, it's set to true.
*/
private boolean readOnly = true;
/**
* Lock token repository.
*/
private Hashtable lockStore = new Hashtable();
// --------------------------------------------------------- Public Methods
/**
* Initialize this servlet.
*/
public void init()
throws ServletException {
super.init();
try {
documentBuilder =
DocumentBuilderFactory.newInstance().newDocumentBuilder();
} catch(ParserConfigurationException e) {
throw new ServletException
(sm.getString("webdavservlet.jaxpfailed"));
}
// Set our properties from the initialization parameters
String value = null;
try {
value = getServletConfig().getInitParameter("readonly");
readOnly = (new Boolean(value)).booleanValue();
} catch (Throwable t) {
;
}
}
// ------------------------------------------------------ Protected Methods
/**
* Handles the special WebDAV methods.
*/
protected void service(HttpServletRequest req, HttpServletResponse resp)
throws ServletException, IOException {
String method = req.getMethod();
if (method.equals(METHOD_PROPFIND)) {
doPropfind(req, resp);
} else if (method.equals(METHOD_PROPPATCH)) {
doProppatch(req, resp);
} else if (method.equals(METHOD_MKCOL)) {
doMkcol(req, resp);
} else if (method.equals(METHOD_COPY)) {
doCopy(req, resp);
} else if (method.equals(METHOD_MOVE)) {
doMove(req, resp);
} else if (method.equals(METHOD_LOCK)) {
doLock(req, resp);
} else if (method.equals(METHOD_UNLOCK)) {
doUnlock(req, resp);
} else {
// DefailtServlet processing
super.service(req, resp);
}
}
/**
* Check if the conditions specified in the optional If headers are
* satisfied.
*
* @param request The servlet request we are processing
* @param response The servlet response we are creating
* @param resourceInfo File object
* @return boolean true if the resource meets all the specified conditions,
* and false if any of the conditions is not satisfied, in which case
* request processing is stopped
*/
protected boolean checkIfHeaders(HttpServletRequest request,
HttpServletResponse response,
ResourceInfo resourceInfo)
throws IOException {
if (!super.checkIfHeaders(request, response, resourceInfo))
return false;
// TODO : Checking the WebDAV If header
return true;
}
/**
* OPTIONS Method.
*/
protected void doOptions(HttpServletRequest req, HttpServletResponse resp)
throws ServletException, IOException {
resp.addHeader("DAV", "1,2");
String methodsAllowed = "OPTIONS, GET, HEAD, POST, DELETE, TRACE, "
+ "PROPFIND, PROPPATCH, COPY, MOVE, LOCK, UNLOCK, PUT";
resp.addHeader("Allow", methodsAllowed);
}
/**
* PROPFIND Method.
*/
protected void doPropfind(HttpServletRequest req, HttpServletResponse resp)
throws ServletException, IOException {
if (!listings) {
resp.sendError(WebdavStatus.SC_METHOD_NOT_ALLOWED);
return;
}
String servletPath = req.getServletPath();
if (servletPath == null)
servletPath = "/";
// Properties which are to be displayed.
Vector properties = null;
// Propfind depth
int depth = INFINITY;
// Propfind type
int type = FIND_ALL_PROP;
String depthStr = req.getHeader("Depth");
if (depthStr == null) {
depth = INFINITY;
} else {
if (depthStr.equals("0")) {
depth = 0;
} else if (depthStr.equals("1")) {
depth = 1;
} else if (depthStr.equals("infinity")) {
depth = INFINITY;
}
}
Node propNode = null;
try {
Document document = documentBuilder.parse
(new InputSource(req.getInputStream()));
// Get the root element of the document
Element rootElement = document.getDocumentElement();
NodeList childList = rootElement.getChildNodes();
for (int i=0; i < childList.getLength(); i++) {
Node currentNode = childList.item(i);
switch (currentNode.getNodeType()) {
case Node.TEXT_NODE:
break;
case Node.ELEMENT_NODE:
if (currentNode.getNodeName().endsWith("prop")) {
type = FIND_BY_PROPERTY;
propNode = currentNode;
}
if (currentNode.getNodeName().endsWith("propname")) {
type = FIND_PROPERTY_NAMES;
}
if (currentNode.getNodeName().endsWith("allprop")) {
type = FIND_ALL_PROP;
}
break;
}
}
} catch(Exception e) {
// Most likely there was no content : we use the defaults.
// TODO : Enhance that !
}
if (type == FIND_BY_PROPERTY) {
properties = new Vector();
NodeList childList = propNode.getChildNodes();
for (int i=0; i < childList.getLength(); i++) {
Node currentNode = childList.item(i);
switch (currentNode.getNodeType()) {
case Node.TEXT_NODE:
break;
case Node.ELEMENT_NODE:
String nodeName = currentNode.getNodeName();
String propertyName = null;
if (nodeName.indexOf(':') != -1) {
propertyName = nodeName.substring
(nodeName.indexOf(':') + 1);
} else {
propertyName = nodeName;
}
// href is a live property which is handled differently
properties.addElement(propertyName);
break;
}
}
}
// Retrieve the Catalina context
ApplicationContext context = (ApplicationContext) getServletContext();
// Convert the resource path to a URL
URL resourceURL = null;
try {
resourceURL = context.getResource(servletPath);
} catch (MalformedURLException e) {
;
}
if (resourceURL == null) {
resp.sendError(HttpServletResponse.SC_NOT_FOUND, servletPath);
return;
}
resp.setStatus(WebdavStatus.SC_MULTI_STATUS);
Resources resources = context.getResources();
// Create multistatus object
XMLWriter generatedXML = new XMLWriter();
generatedXML.writeElement("d", "DAV", "multistatus",
XMLWriter.OPENING);
if (depth == 0) {
parseProperties(resources, generatedXML, servletPath, type,
properties);
} else {
// The stack always contains the object of the current level
Stack stack = new Stack();
stack.push(servletPath);
// Stack of the objects one level below
Stack stackBelow = new Stack();
while ((!stack.isEmpty()) && (depth >= 0)) {
String currentPath = (String) stack.pop();
parseProperties(resources, generatedXML, currentPath, type,
properties);
if (resources.isCollection(currentPath)) {
String[] children =
resources.getCollectionMembers(currentPath);
for (int i=0; i<children.length; i++) {
stackBelow.push(children[i]);
}
}
if (stack.isEmpty()) {
depth--;
stack = stackBelow;
stackBelow = new Stack();
}
}
}
generatedXML.writeElement("d", "multistatus",
XMLWriter.CLOSING);
Writer writer = resp.getWriter();
writer.write(generatedXML.toString());
writer.flush();
}
/**
* PROPPATCH Method.
*/
protected void doProppatch(HttpServletRequest req,
HttpServletResponse resp)
throws ServletException, IOException {
}
/**
* MKCOL Method.
*/
protected void doMkcol(HttpServletRequest req, HttpServletResponse resp)
throws ServletException, IOException {
}
/**
* DELETE Method.
*/
protected void doDelete(HttpServletRequest req, HttpServletResponse resp)
throws ServletException, IOException {
}
/**
* PUT Method.
*/
protected void doPut(HttpServletRequest req, HttpServletResponse resp)
throws ServletException, IOException {
}
/**
* COPY Method.
*/
protected void doCopy(HttpServletRequest req, HttpServletResponse resp)
throws ServletException, IOException {
}
/**
* MOVE Method.
*/
protected void doMove(HttpServletRequest req, HttpServletResponse resp)
throws ServletException, IOException {
}
/**
* LOCK Method.
*/
protected void doLock(HttpServletRequest req, HttpServletResponse resp)
throws ServletException, IOException {
}
/**
* UNLOCK Method.
*/
protected void doUnlock(HttpServletRequest req, HttpServletResponse resp)
throws ServletException, IOException {
}
// -------------------------------------------------------- Private Methods
/**
* Propfind helper method.
*
* @param resources Resources object associated with this context
* @param generatedXML XML response to the Propfind request
* @param path Path of the current resource
* @param type Propfind type
* @param propertiesVector If the propfind type is find properties by
* name, then this Vector contains those properties
*/
private void parseProperties(Resources resources, XMLWriter generatedXML,
String path, int type,
Vector propertiesVector) {
ResourceInfo resourceInfo = new ResourceInfo(path, resources);
generatedXML.writeElement("d", "response", XMLWriter.OPENING);
String status = new String("HTTP/1.1 " + WebdavStatus.SC_OK + " "
+ WebdavStatus.getStatusText
(WebdavStatus.SC_OK));
// Generating href element
generatedXML.writeElement("d", "href", XMLWriter.OPENING);
generatedXML.writeText(path);
if ((resourceInfo.collection) && (!path.equals("/")))
generatedXML.writeText("/");
generatedXML.writeElement("d", "href", XMLWriter.CLOSING);
switch (type) {
case FIND_ALL_PROP :
generatedXML.writeElement("d", "propstat", XMLWriter.OPENING);
generatedXML.writeElement("d", "prop", XMLWriter.OPENING);
generatedXML.writeProperty("d", "DAV", "creationdate",
formats[0].format(new Date
(resourceInfo.creationDate)));
generatedXML.writeProperty("d", "DAV", "displayname",
resourceInfo.path);
generatedXML.writeProperty("d", "DAV", "getcontentlanguage",
Locale.getDefault().toString());
generatedXML.writeProperty("d", "DAV", "getlastmodified",
resourceInfo.httpDate);
if (!resourceInfo.collection) {
generatedXML.writeProperty
("d", "DAV", "getcontentlength",
String.valueOf(resourceInfo.length));
generatedXML.writeProperty
("d", "DAV", "getcontenttype",
getServletContext().getMimeType(resourceInfo.path));
generatedXML.writeProperty("d", "DAV", "getetag",
getETagValue(resourceInfo, true));
generatedXML.writeElement("d", "DAV", "resourcetype",
XMLWriter.NO_CONTENT);
} else {
generatedXML.writeElement("d", "DAV", "resourcetype",
XMLWriter.OPENING);
generatedXML.writeElement("d", "collection",
XMLWriter.NO_CONTENT);
generatedXML.writeElement("d", "resourcetype",
XMLWriter.CLOSING);
}
generatedXML.writeProperty("d", "DAV", "source", "");
String supportedLocks = "<d:lockentry>"
+ "<d:lockscope><d:exclusive/></d:lockscope>"
+ "<d:locktype><d:write/></d:locktype>"
+ "</d:lockentry>";
generatedXML.writeProperty("d", "DAV", "supportedlock",
supportedLocks);
// TODO : Lock discovery property
generatedXML.writeElement("d", "prop", XMLWriter.CLOSING);
generatedXML.writeProperty("d", "status", status);
generatedXML.writeElement("d", "propstat", XMLWriter.CLOSING);
break;
case FIND_PROPERTY_NAMES :
generatedXML.writeElement("d", "propstat", XMLWriter.OPENING);
generatedXML.writeElement("d", "prop", XMLWriter.OPENING);
generatedXML.writeElement("d", "DAV", "creationdate",
XMLWriter.NO_CONTENT);
generatedXML.writeElement("d", "DAV", "displayname",
XMLWriter.NO_CONTENT);
if (!resourceInfo.collection) {
generatedXML.writeElement("d", "DAV", "getcontentlanguage",
XMLWriter.NO_CONTENT);
generatedXML.writeElement("d", "DAV", "getcontentlength",
XMLWriter.NO_CONTENT);
generatedXML.writeElement("d", "DAV", "getcontenttype",
XMLWriter.NO_CONTENT);
generatedXML.writeElement("d", "DAV", "getetag",
XMLWriter.NO_CONTENT);
generatedXML.writeElement("d", "DAV", "getlastmodified",
XMLWriter.NO_CONTENT);
}
generatedXML.writeElement("d", "DAV", "resourcetype",
XMLWriter.NO_CONTENT);
generatedXML.writeElement("d", "DAV", "source",
XMLWriter.NO_CONTENT);
generatedXML.writeElement("d", "DAV", "lockdiscovery",
XMLWriter.NO_CONTENT);
generatedXML.writeElement("d", "prop", XMLWriter.CLOSING);
generatedXML.writeProperty("d", "status", status);
generatedXML.writeElement("d", "propstat", XMLWriter.CLOSING);
break;
case FIND_BY_PROPERTY :
Vector propertiesNotFound = new Vector();
// Parse the list of properties
generatedXML.writeElement("d", "propstat", XMLWriter.OPENING);
generatedXML.writeElement("d", "prop", XMLWriter.OPENING);
Enumeration properties = propertiesVector.elements();
while (properties.hasMoreElements()) {
String property = (String) properties.nextElement();
if (property.equals("creationdate")) {
generatedXML.writeProperty
("d", "DAV", "creationdate", formats[0].format
(new Date(resourceInfo.creationDate)));
} else if (property.equals("displayname")) {
generatedXML.writeProperty("d", "DAV", "displayname",
resourceInfo.path);
} else if (property.equals("getcontentlanguage")) {
if (resourceInfo.collection) {
propertiesNotFound.addElement(property);
} else {
generatedXML.writeProperty
("d", "DAV", "getcontentlanguage",
Locale.getDefault().toString());
}
} else if (property.equals("getcontentlength")) {
if (resourceInfo.collection) {
propertiesNotFound.addElement(property);
} else {
generatedXML.writeProperty
("d", "DAV", "getcontentlength",
(String.valueOf(resourceInfo.length)));
}
} else if (property.equals("getcontenttype")) {
if (resourceInfo.collection) {
propertiesNotFound.addElement(property);
} else {
generatedXML.writeProperty
("d", "DAV", "getcontenttype",
getServletContext().getMimeType
(resourceInfo.path));
}
} else if (property.equals("getetag")) {
if (resourceInfo.collection) {
propertiesNotFound.addElement(property);
} else {
generatedXML.writeProperty
("d", "DAV", "getetag",
getETagValue(resourceInfo, true));
}
} else if (property.equals("getlastmodified")) {
if (resourceInfo.collection) {
propertiesNotFound.addElement(property);
} else {
generatedXML.writeProperty("d", "DAV",
"getlastmodified",
resourceInfo.httpDate);
}
} else if (property.equals("resourcetype")) {
if (resourceInfo.collection) {
generatedXML.writeElement("d", "DAV", "resourcetype",
XMLWriter.OPENING);
generatedXML.writeElement("d", "collection",
XMLWriter.NO_CONTENT);
generatedXML.writeElement("d", "resourcetype",
XMLWriter.CLOSING);
} else {
generatedXML.writeElement("d", "DAV", "resourcetype",
XMLWriter.NO_CONTENT);
}
} else if (property.equals("source")) {
generatedXML.writeProperty("d", "DAV", "source", "");
} else if (property.equals("supportedlock")) {
supportedLocks = "<d:lockentry>"
+ "<d:lockscope><d:exclusive/></d:lockscope>"
+ "<d:locktype><d:write/></d:locktype>"
+ "</d:lockentry>";
generatedXML.writeProperty("d", "DAV", "supportedlock",
supportedLocks);
} else if (property.equals("lockdiscovery")) {
// TODO : Implement locks !!!
generatedXML.writeProperty("d", "DAV",
"lockdiscovery", "");
} else {
propertiesNotFound.addElement(property);
}
}
generatedXML.writeElement("d", "prop", XMLWriter.CLOSING);
generatedXML.writeProperty("d", "status", status);
generatedXML.writeElement("d", "propstat", XMLWriter.CLOSING);
Enumeration propertiesNotFoundList = propertiesNotFound.elements();
if (propertiesNotFoundList.hasMoreElements()) {
status = new String("HTTP/1.1 " + WebdavStatus.SC_NOT_FOUND
+ " " + WebdavStatus.getStatusText
(WebdavStatus.SC_NOT_FOUND));
generatedXML.writeElement("d", "propstat", XMLWriter.OPENING);
generatedXML.writeElement("d", "prop", XMLWriter.OPENING);
while (propertiesNotFoundList.hasMoreElements()) {
generatedXML.writeElement
(null, (String) propertiesNotFoundList.nextElement(),
XMLWriter.NO_CONTENT);
}
generatedXML.writeElement("d", "prop", XMLWriter.CLOSING);
generatedXML.writeProperty("d", "status", status);
generatedXML.writeElement("d", "propstat", XMLWriter.CLOSING);
}
break;
}
generatedXML.writeElement("d", "response", XMLWriter.CLOSING);
}
// -------------------------------------------------- LockInfo Inner Class
private class LockInfo {
/**
* Constructor.
*
* @param pathname Path name of the file
*/
public LockInfo() {
}
}
};
// -------------------------------------------------------- WebdavStatus Class
/**
* Wraps the HttpServletResponse class to abstract the
* specific protocol used. To support other protocols
* we would only need to modify this class and the
* WebDavRetCode classes.
*
* @author Marc Eaddy
* @version 1.0, 16 Nov 1997
*/
class WebdavStatus {
// ----------------------------------------------------- Instance Variables
/**
* This Hashtable contains the mapping of HTTP and WebDAV
* status codes to descriptive text. This is a static
* variable.
*/
private static Hashtable mapStatusCodes = new Hashtable();
// ------------------------------------------------------ HTTP Status Codes
/**
* Status code (200) indicating the request succeeded normally.
*/
public static final int SC_OK = HttpServletResponse.SC_OK;
/**
* Status code (201) indicating the request succeeded and created
* a new resource on the server.
*/
public static final int SC_CREATED = HttpServletResponse.SC_CREATED;
/**
* Status code (202) indicating that a request was accepted for
* processing, but was not completed.
*/
public static final int SC_ACCEPTED = HttpServletResponse.SC_ACCEPTED;
/**
* Status code (204) indicating that the request succeeded but that
* there was no new information to return.
*/
public static final int SC_NO_CONTENT = HttpServletResponse.SC_NO_CONTENT;
/**
* Status code (301) indicating that the resource has permanently
* moved to a new location, and that future references should use a
* new URI with their requests.
*/
public static final int SC_MOVED_PERMANENTLY =
HttpServletResponse.SC_MOVED_PERMANENTLY;
/**
* Status code (302) indicating that the resource has temporarily
* moved to another location, but that future references should
* still use the original URI to access the resource.
*/
public static final int SC_MOVED_TEMPORARILY =
HttpServletResponse.SC_MOVED_TEMPORARILY;
/**
* Status code (304) indicating that a conditional GET operation
* found that the resource was available and not modified.
*/
public static final int SC_NOT_MODIFIED =
HttpServletResponse.SC_NOT_MODIFIED;
/**
* Status code (400) indicating the request sent by the client was
* syntactically incorrect.
*/
public static final int SC_BAD_REQUEST =
HttpServletResponse.SC_BAD_REQUEST;
/**
* Status code (401) indicating that the request requires HTTP
* authentication.
*/
public static final int SC_UNAUTHORIZED =
HttpServletResponse.SC_UNAUTHORIZED;
/**
* Status code (403) indicating the server understood the request
* but refused to fulfill it.
*/
public static final int SC_FORBIDDEN = HttpServletResponse.SC_FORBIDDEN;
/**
* Status code (404) indicating that the requested resource is not
* available.
*/
public static final int SC_NOT_FOUND = HttpServletResponse.SC_NOT_FOUND;
/**
* Status code (500) indicating an error inside the HTTP service
* which prevented it from fulfilling the request.
*/
public static final int SC_INTERNAL_SERVER_ERROR =
HttpServletResponse.SC_INTERNAL_SERVER_ERROR;
/**
* Status code (501) indicating the HTTP service does not support
* the functionality needed to fulfill the request.
*/
public static final int SC_NOT_IMPLEMENTED =
HttpServletResponse.SC_NOT_IMPLEMENTED;
/**
* Status code (502) indicating that the HTTP server received an
* invalid response from a server it consulted when acting as a
* proxy or gateway.
*/
public static final int SC_BAD_GATEWAY =
HttpServletResponse.SC_BAD_GATEWAY;
/**
* Status code (503) indicating that the HTTP service is
* temporarily overloaded, and unable to handle the request.
*/
public static final int SC_SERVICE_UNAVAILABLE =
HttpServletResponse.SC_SERVICE_UNAVAILABLE;
/**
* Status code (100) indicating the client may continue with
* its request. This interim response is used to inform the
* client that the initial part of the request has been
* received and has not yet been rejected by the server.
*/
public static final int SC_CONTINUE = 100;
/**
* Status code (405) indicating the method specified is not
* allowed for the resource.
*/
public static final int SC_METHOD_NOT_ALLOWED = 405;
/**
* Status code (409) indicating that the request could not be
* completed due to a conflict with the current state of the
* resource.
*/
public static final int SC_CONFLICT = 409;
/**
* Status code (412) indicating the precondition given in one
* or more of the request-header fields evaluated to false
* when it was tested on the server.
*/
public static final int SC_PRECONDITION_FAILED = 412;
/**
* Status code (413) indicating the server is refusing to
* process a request because the request entity is larger
* than the server is willing or able to process.
*/
public static final int SC_REQUEST_TOO_LONG = 413;
/**
* Status code (415) indicating the server is refusing to service
* the request because the entity of the request is in a format
* not supported by the requested resource for the requested
* method.
*/
public static final int SC_UNSUPPORTED_MEDIA_TYPE = 415;
// -------------------------------------------- Extended WebDav status code
/**
* Status code (207) indicating that the response requires
* providing status for multiple independent operations.
*/
public static final int SC_MULTI_STATUS = 207;
// This one colides with HTTP 1.1
// "207 Parital Update OK"
/**
* Status code (418) indicating the entity body submitted with
* the PATCH method was not understood by the resource.
*/
public static final int SC_UNPROCESSABLE_ENTITY = 418;
// This one colides with HTTP 1.1
// "418 Reauthentication Required"
/**
* Status code (419) indicating that the resource does not have
* sufficient space to record the state of the resource after the
* execution of this method.
*/
public static final int SC_INSUFFICIENT_SPACE_ON_RESOURCE = 419;
// This one colides with HTTP 1.1
// "419 Proxy Reauthentication Required"
/**
* Status code (420) indicating the method was not executed on
* a particular resource within its scope because some part of
* the method's execution failed causing the entire method to be
* aborted.
*/
public static final int SC_METHOD_FAILURE = 420;
/**
* Status code (423) indicating the destination resource of a
* method is locked, and either the request did not contain a
* valid Lock-Info header, or the Lock-Info header identifies
* a lock held by another principal.
*/
public static final int SC_LOCKED = 423;
// ------------------------------------------------------------ Initializer
static {
// HTTP 1.0 tatus Code
addStatusCodeMap(SC_OK, "OK");
addStatusCodeMap(SC_CREATED, "Created");
addStatusCodeMap(SC_ACCEPTED, "Accepted");
addStatusCodeMap(SC_NO_CONTENT, "No Content");
addStatusCodeMap(SC_MOVED_PERMANENTLY, "Moved Permanently");
addStatusCodeMap(SC_MOVED_TEMPORARILY, "Moved Temporarily");
addStatusCodeMap(SC_NOT_MODIFIED, "Not Modified");
addStatusCodeMap(SC_BAD_REQUEST, "Bad Request");
addStatusCodeMap(SC_UNAUTHORIZED, "Unauthorized");
addStatusCodeMap(SC_FORBIDDEN, "Forbidden");
addStatusCodeMap(SC_NOT_FOUND, "Not Found");
addStatusCodeMap(SC_INTERNAL_SERVER_ERROR, "Internal Server Error");
addStatusCodeMap(SC_NOT_IMPLEMENTED, "Not Implemented");
addStatusCodeMap(SC_BAD_GATEWAY, "Bad Gateway");
addStatusCodeMap(SC_SERVICE_UNAVAILABLE, "Service Unavailable");
addStatusCodeMap(SC_CONTINUE, "Continue");
addStatusCodeMap(SC_METHOD_NOT_ALLOWED, "Method Not Allowed");
addStatusCodeMap(SC_CONFLICT, "Conflict");
addStatusCodeMap(SC_PRECONDITION_FAILED, "Precondition Failed");
addStatusCodeMap(SC_REQUEST_TOO_LONG, "Request Too Long");
addStatusCodeMap(SC_UNSUPPORTED_MEDIA_TYPE, "Unsupported Media Type");
// WebDav Status Codes
addStatusCodeMap(SC_MULTI_STATUS, "Multi-Status");
addStatusCodeMap(SC_UNPROCESSABLE_ENTITY, "Unprocessable Entity");
addStatusCodeMap(SC_INSUFFICIENT_SPACE_ON_RESOURCE,
"Insufficient Space On Resource");
addStatusCodeMap(SC_METHOD_FAILURE, "Method Failure");
addStatusCodeMap(SC_LOCKED, "Locked");
}
// --------------------------------------------------------- Public Methods
/**
* Returns the HTTP status text for the HTTP or WebDav status code
* specified by looking it up in the static mapping. This is a
* static function.
*
* @param nHttpStatusCode [IN] HTTP or WebDAV status code
* @return A string with a short descriptive phrase for the
* HTTP status code (e.g., "OK").
*/
public static String getStatusText(int nHttpStatusCode) {
Integer intKey = new Integer(nHttpStatusCode);
if (!mapStatusCodes.containsKey(intKey)) {
return "";
} else {
return (String) mapStatusCodes.get(intKey);
}
}
// -------------------------------------------------------- Private Methods
/**
* Adds a new status code -> status text mapping. This is a static
* method because the mapping is a static variable.
*
* @param nKey [IN] HTTP or WebDAV status code
* @param strVal [IN] HTTP status text
*/
private static void addStatusCodeMap(int nKey, String strVal) {
mapStatusCodes.put(new Integer(nKey), strVal);
}
};
1.1 jakarta-tomcat/proposals/catalina/src/share/org/apache/tomcat/util/XMLWriter.java
Index: XMLWriter.java
===================================================================
/*
* $Header: /home/cvs/jakarta-tomcat/proposals/catalina/src/share/org/apache/tomcat/util/XMLWriter.java,v 1.1 2000/07/31 06:28:02 remm Exp $
* $Revision: 1.1 $
* $Date: 2000/07/31 06:28:02 $
*
* ====================================================================
*
* The Apache Software License, Version 1.1
*
* Copyright (c) 1999 The Apache Software Foundation. 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 acknowlegement:
* "This product includes software developed by the
* Apache Software Foundation (http://www.apache.org/)."
* Alternately, this acknowlegement may appear in the software itself,
* if and wherever such third-party acknowlegements normally appear.
*
* 4. The names "The Jakarta Project", "Tomcat", and "Apache Software
* Foundation" must not be used to endorse or promote products derived
* from this software without prior written permission. For written
* permission, please contact apache@apache.org.
*
* 5. Products derived from this software may not be called "Apache"
* nor may "Apache" appear in their names without prior written
* permission of the Apache Group.
*
* 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 APACHE SOFTWARE FOUNDATION 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 Apache Software Foundation. For more
* information on the Apache Software Foundation, please see
* <http://www.apache.org/>.
*
* [Additional notices, if required by prior licensing conditions]
*
*/
package org.apache.tomcat.util;
/**
* XMLWriter helper class.
*
* @author Remy Maucherat
*/
public class XMLWriter {
// -------------------------------------------------------------- Constants
/**
* Opening tag.
*/
public static final int OPENING = 0;
/**
* Closing tag.
*/
public static final int CLOSING = 1;
/**
* Element with no content.
*/
public static final int NO_CONTENT = 2;
// ----------------------------------------------------- Instance Variables
/**
* Buffer.
*/
protected StringBuffer buffer;
// ----------------------------------------------------------- Constructors
/**
* Constructor.
*/
public XMLWriter() {
buffer = new StringBuffer();
}
// --------------------------------------------------------- Public Methods
/**
* Retrieve generated XML.
*
* @return String containing the generated XML
*/
public String toString() {
return buffer.toString();
}
/**
* Write property to the XML.
*
* @param namespace Namespace
* @param namespaceInfo Namespace info
* @param name Property name
* @param value Property value
*/
public void writeProperty(String namespace, String namespaceInfo,
String name, String value) {
writeElement(namespace, namespaceInfo, name, OPENING);
buffer.append(value);
writeElement(namespace, namespaceInfo, name, CLOSING);
}
/**
* Write property to the XML.
*
* @param namespace Namespace
* @param name Property name
* @param value Property value
*/
public void writeProperty(String namespace, String name, String value) {
writeElement(namespace, name, OPENING);
buffer.append(value);
writeElement(namespace, name, CLOSING);
}
/**
* Write property to the XML.
*
* @param namespace Namespace
* @param name Property name
*/
public void writeProperty(String namespace, String name) {
writeElement(namespace, name, NO_CONTENT);
}
/**
* Write an element.
*
* @param name Element name
* @param namespace Namespace abbreviation
* @param type Element type
*/
public void writeElement(String namespace, String name, int type) {
writeElement(namespace, null, name, type);
}
/**
* Write an element.
*
* @param namespace Namespace abbreviation
* @param namespaceInfo Namespace info
* @param name Element name
* @param type Element type
*/
public void writeElement(String namespace, String namespaceInfo,
String name, int type) {
if ((namespace != null) && (namespace.length() > 0)) {
switch (type) {
case OPENING:
if (namespaceInfo != null) {
buffer.append("<" + namespace + ":" + name + " xmlns:"
+ namespace + "=\""
+ namespaceInfo + ":\">");
} else {
buffer.append("<" + namespace + ":" + name + ">");
}
break;
case CLOSING:
buffer.append("</" + namespace + ":" + name + ">\n");
break;
case NO_CONTENT:
default:
if (namespaceInfo != null) {
buffer.append("<" + namespace + ":" + name + " xmlns:"
+ namespace + "=\""
+ namespaceInfo + ":\"/>");
} else {
buffer.append("<" + namespace + ":" + name + "/>");
}
break;
}
} else {
switch (type) {
case OPENING:
buffer.append("<" + name + ">");
break;
case CLOSING:
buffer.append("</" + name + ">\n");
break;
case NO_CONTENT:
default:
buffer.append("<" + name + "/>");
break;
}
}
}
/**
* Write text.
*
* @param text Text to append
*/
public void writeText(String text) {
buffer.append(text);
}
/**
* Write XML Header.
*/
public void writeXMLHeader() {
buffer.append("<?xml version=\"1.0\" encoding=\"utf-8\" ?>\n");
}
}