/*
* $Header: /home/cvs/jakarta-slide/src/webdav/server/org/apache/slide/webdav/WebdavServlet.java,v 1.63.2.1 2004/10/30 18:29:16 ozeigermann Exp $
* $Revision: 1.63.2.1 $
* $Date: 2004/10/30 18:29:16 $
*
* ====================================================================
*
* 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 javax.xml.parsers.DocumentBuilderFactory;
import javax.xml.parsers.FactoryConfigurationError;
import javax.xml.parsers.ParserConfigurationException;
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.WebdavConstants;
import org.apache.slide.webdav.util.WebdavStatus;
import org.apache.slide.webdav.util.WebdavUtils;
/**
* The WebDAV servlet. It is responsible for dispatching incoming requests to
* implementations of the WebdavMethod interface.
*
* @version $Revision: 1.63.2.1 $
*/
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();
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 isExtTx(HttpServletRequest req) {
String hTxIdStr = req.getHeader(WebdavConstants.H_TRANSACTION);
return (hTxIdStr != null);
}
private boolean isCollection(HttpServletRequest req) {
SlideToken slideToken = new SlideTokenWrapper(WebdavUtils.getSlideToken(req));
// necessary as no transaction has been started, yet
slideToken.setForceStoreEnlistment(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 (!isDomLevel2Parser()) {
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);
// }
// }
static boolean isDomLevel2Parser() {
try {
return DocumentBuilderFactory.newInstance().newDocumentBuilder()
.getDOMImplementation().hasFeature("Core", "2.0");
} catch (ParserConfigurationException e) {
return false;
} catch (FactoryConfigurationError e) {
return false;
}
}
}