/*
* $Header: /home/cvs/jakarta-slide/src/webdav/server/org/apache/slide/webdav/WebdavServlet.java,v 1.54.2.3 2004/04/01 13:46:39 ozeigermann Exp $
* $Revision: 1.54.2.3 $
* $Date: 2004/04/01 13:46:39 $
*
* ====================================================================
*
* Copyright 1999-2002 The Apache Software Foundation
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*
*/
package org.apache.slide.webdav;
import java.io.IOException;
import java.net.URL;
import java.text.SimpleDateFormat;
import java.util.Date;
import javax.servlet.RequestDispatcher;
import javax.servlet.ServletConfig;
import javax.servlet.ServletException;
import javax.servlet.UnavailableException;
import javax.servlet.http.HttpServlet;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import org.apache.slide.authenticate.SecurityToken;
import org.apache.slide.common.Domain;
import org.apache.slide.common.DomainInitializationFailedError;
import org.apache.slide.common.NamespaceAccessToken;
import org.apache.slide.common.SlideException;
import org.apache.slide.common.SlideToken;
import org.apache.slide.common.SlideTokenWrapper;
import org.apache.slide.security.AccessDeniedException;
import org.apache.slide.structure.LinkedObjectNotFoundException;
import org.apache.slide.structure.ObjectNotFoundException;
import org.apache.slide.util.logger.Logger;
import org.apache.slide.webdav.util.DirectoryIndexGenerator;
import org.apache.slide.webdav.util.WebdavUtils;
import org.apache.util.DOMUtils;
import org.apache.util.WebdavStatus;
/**
* The WebDAV servlet. It is responsible for dispatching incoming requests to
* implementations of the WebdavMethod interface.
*
* @author <a href="mailto:remm@apache.org">Remy Maucherat</a>
* @author Dirk Verbeeck
* @author <a href="mailto:cmlenz@apache.org">Christopher Lenz</a>
* @version $Revision: 1.54.2.3 $
*/
public class WebdavServlet
extends HttpServlet {
// -------------------------------------------------------------- Constants
/**
* Name of the log channel used by the WebDAV servlet.
*/
private static final String LOG_CHANNEL = WebdavServlet.class.getName();
/**
* Name under which the namespace access token is stored in the application
* attributes. This is used when the WebDAV servlet doesn't initialize
* Slide itself, but rather the initialization is done outside.
*/
public static final String ATTRIBUTE_NAME =
"org.apache.slide.NamespaceAccessToken";
// ----------------------------------------------------- Instance Variables
/**
* Access token to the namespace.
*/
protected NamespaceAccessToken token;
/**
* Directory browsing enabled.
*/
protected boolean directoryBrowsing = true;
/**
* RequestDispatcher to the directory browsing template, if specified.
*/
protected RequestDispatcher directoryBrowsingTemplate;
/**
* Directory browsing enabled.
*/
protected DirectoryIndexGenerator directoryIndexGenerator;
/**
* Set to true if the servlet is handling the lifecycle of the domain.
*/
protected boolean handleLifecycle = true;
/**
* Instance of the WebdavMethodFactory to use by this servlet.
*/
protected WebdavMethodFactory methodFactory;
// -------------------------------------------------------- Servlet Methods
protected void service (HttpServletRequest req, HttpServletResponse resp)
throws ServletException, IOException {
SimpleDateFormat sdf = new SimpleDateFormat();
if( token.getLogger().isEnabled(LOG_CHANNEL, Logger.DEBUG) )
token.getLogger().log("==> "+req.getMethod()+" start: "+sdf.format(new Date(System.currentTimeMillis()))+" ["+Thread.currentThread().getName()+"]", LOG_CHANNEL, Logger.DEBUG);
req.setAttribute("slide_uri", WebdavUtils.getRelativePath(req, (WebdavServletConfig) getServletConfig()));
try {
if (token == null) {
String namespaceName = req.getContextPath();
if ((namespaceName == null) || (namespaceName.equals(""))) {
namespaceName = Domain.getDefaultNamespace();
}
while (namespaceName.startsWith("/")) {
namespaceName = namespaceName.substring(1);
}
token = Domain.accessNamespace(new SecurityToken(this), namespaceName);
}
resp.setStatus(WebdavStatus.SC_OK);
String methodName = req.getMethod();
if ((methodName.equalsIgnoreCase("GET") ||
methodName.equalsIgnoreCase("POST")) &&
isCollection(req)) {
// let the standard doGet() / doPost() methods handle
// GET/POST requests on collections (to display a directory
// index pag or something similar)
super.service(req, resp);
} else {
WebdavMethod method = methodFactory.createMethod(methodName);
if (method == null) {
throw new WebdavException(WebdavStatus.SC_METHOD_NOT_ALLOWED);
} else {
method.run(req, resp);
}
}
} catch (WebdavException e) {
// There has been an error somewhere ...
token.getLogger().log(e,LOG_CHANNEL, Logger.ERROR);
try { resp.sendError(e.getStatusCode()); } catch (Throwable ex) { }
} catch (Throwable e) {
// If something goes really wrong ...
token.getLogger().log(e,LOG_CHANNEL, Logger.ERROR);
try { resp.sendError(WebdavStatus.SC_INTERNAL_SERVER_ERROR); } catch (Throwable ex) { }
}
finally {
if( token.getLogger().isEnabled(LOG_CHANNEL, Logger.DEBUG) )
token.getLogger().log("<== "+req.getMethod()+" end: "+sdf.format(new Date(System.currentTimeMillis()))+" ["+Thread.currentThread().getName()+"]", LOG_CHANNEL, Logger.DEBUG);
}
}
private boolean isCollection(HttpServletRequest req) {
SlideToken slideToken = new SlideTokenWrapper(WebdavUtils.getSlideToken(req), false);
slideToken.setForceSecurity(false);
slideToken.setForceLock(false);
return WebdavUtils.isCollection(token, slideToken, WebdavUtils.getRelativePath(req, (WebdavServletConfig)getServletConfig()));
}
/**
* Implemented to wrap the ServletConfig object inside a
* WebdavServletConfig
*/
public void init(ServletConfig config)
throws ServletException {
super.init(new WebdavServletConfig(config));
// all the actual initialization is inside init()
}
/**
* Manages some initialization stuff on the server.
*/
public void init()
throws ServletException {
if (!DOMUtils.isDocumentBuilderDOM2Compliant()) {
System.out.println("======================================================");
System.out.println("!!! Unable to start Slide Servlet !!!");
System.out.println("------------------------------------------------------");
System.out.println("You are using using an incorrect older XML parser");
System.out.println("that doesn't provide Element::getElementsByTagNameNS");
System.out.println("consult the documentation for a list of valid XML parsers.");
System.out.println("======================================================");
log("======================================================");
log("!!! Unable to start Slide Servlet !!!");
log("------------------------------------------------------");
log("======================================================");
log("You are using using an incorrect older XML parser");
log("that doesn't provide Element::getElementsByTagNameNS");
log("consult the documentation for a list of valid XML parsers.");
log("======================================================");
throw new ServletException("Invalid XML parser");
}
String value = null;
// Lookup for the NAT using JNDI
// FIXME
// Lookup for the NAT using the servlet context
token = (NamespaceAccessToken)
getServletContext().getAttribute(ATTRIBUTE_NAME);
if (token == null) {
// Dafault initialization
String namespaceName = null;
String domainConfigFile = null;
value = getInitParameter("namespace");
if (value != null) {
namespaceName = value;
}
value = getInitParameter("domain");
if (value != null) {
domainConfigFile = value;
}
try {
if (domainConfigFile != null) {
URL domainConfigFileURL =
getServletContext().getResource(domainConfigFile);
if (domainConfigFileURL != null) {
Domain.init(domainConfigFileURL);
}
}
if (namespaceName == null) {
namespaceName = Domain.getDefaultNamespace();
log("No namespace specified, will use default namespace: " +
namespaceName);
}
token = Domain.accessNamespace
(new SecurityToken(this), namespaceName);
if (token == null) {
log("Could not access namespace " + namespaceName + ".");
throw new UnavailableException("Namespace " + namespaceName +
" not accessible");
}
getServletContext().setAttribute(ATTRIBUTE_NAME, token);
} catch (DomainInitializationFailedError e) {
log("Could not initialize domain", e);
throw new UnavailableException(e.toString());
} catch (Throwable t) {
t.printStackTrace();
throw new ServletException(t.toString());
}
} else {
handleLifecycle = false;
}
// Setup the method factory
methodFactory =
WebdavMethodFactory.newInstance((WebdavServletConfig)getServletConfig());
// Check whether directory browsing is enabled, and how it should be
// accomplished
value = getInitParameter("directory-browsing");
if (value != null) {
if (value.startsWith("/")) {
directoryBrowsingTemplate =
getServletContext().getRequestDispatcher(value);
if (directoryBrowsingTemplate == null) {
directoryBrowsing = false;
}
} else {
directoryBrowsing = Boolean.valueOf(value).booleanValue();
}
}
if (directoryBrowsing) {
directoryIndexGenerator =
new DirectoryIndexGenerator
(token, (WebdavServletConfig)getServletConfig());
}
}
/**
* Destroy servlet.
*/
public void destroy() {
if (handleLifecycle) {
if (token != null) {
Domain.closeNamespace(token);
}
}
}
// ------------------------------------------------------ Protected Methods
/**
* Handle a GET request on a collection resource.
*/
protected void doGet(HttpServletRequest req, HttpServletResponse res)
throws ServletException, IOException {
if (directoryBrowsing) {
if (directoryBrowsingTemplate != null) {
// attributes used by the tag library
req.setAttribute("org.apache.slide.NamespaceName",
token.getName());
// attributes for general use
req.setAttribute("slide_namespace", token.getName());
directoryBrowsingTemplate.forward(req, res);
} else {
try {
directoryIndexGenerator.generate(req, res);
} catch (AccessDeniedException e) {
res.sendError(WebdavStatus.SC_FORBIDDEN);
} catch (ObjectNotFoundException e) {
res.sendError(WebdavStatus.SC_NOT_FOUND);
} catch (LinkedObjectNotFoundException e) {
res.sendError(WebdavStatus.SC_NOT_FOUND);
} catch (SlideException e) {
res.setStatus(WebdavStatus.SC_INTERNAL_SERVER_ERROR);
}
}
} else {
res.sendError(WebdavStatus.SC_FORBIDDEN);
}
}
}