/*
* $Header: /home/cvs/jakarta-slide/src/webdav/server/org/apache/slide/webdav/method/SearchMethod.java,v 1.47.2.1 2004/09/25 20:38:43 luetzkendorf Exp $
* $Revision: 1.47.2.1 $
* $Date: 2004/09/25 20:38:43 $
*
* ====================================================================
*
* 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.method;
import java.io.IOException;
import java.util.Iterator;
import java.util.List;
import org.apache.slide.common.NamespaceAccessToken;
import org.apache.slide.common.RequestedProperties;
import org.apache.slide.common.SlideException;
import org.apache.slide.event.EventDispatcher;
import org.apache.slide.search.BadGatewayException;
import org.apache.slide.search.BadQueryException;
import org.apache.slide.search.InvalidQueryException;
import org.apache.slide.search.InvalidScopeException;
import org.apache.slide.search.QueryScope;
import org.apache.slide.search.RequestedResource;
import org.apache.slide.search.Search;
import org.apache.slide.search.SearchQuery;
import org.apache.slide.search.SearchQueryResult;
import org.apache.slide.search.basic.IBasicQuery;
import org.apache.slide.security.AccessDeniedException;
import org.apache.slide.structure.ObjectNotFoundException;
import org.apache.slide.structure.StructureException;
import org.apache.slide.util.Configuration;
import org.apache.slide.webdav.WebdavException;
import org.apache.slide.webdav.WebdavServletConfig;
import org.apache.slide.webdav.event.WebdavEvent;
import org.apache.slide.webdav.util.ComputedPropertyProvider;
import org.apache.slide.webdav.util.PropertyRetriever;
import org.apache.slide.webdav.util.PropertyRetrieverImpl;
import org.apache.slide.webdav.util.WebdavConstants;
import org.apache.slide.webdav.util.WebdavStatus;
import org.apache.slide.webdav.util.WebdavUtils;
import org.jdom.Document;
import org.jdom.Element;
import org.jdom.JDOMException;
import org.jdom.output.XMLOutputter;
/**
* SEARCH method.
*
*/
public class SearchMethod extends AbstractWebdavMethod implements WebdavConstants, ReadMethod {
// ----------------------------------------------------- Instance variables
private SearchQuery searchQuery = null;
private Search searchHelper = null;
private RequestedProperties requestedProperties = null;
private PropertyRetriever retriever;
/** if true, an ALL_PROP request will include computed props */
protected boolean extendedAllprop = false;
// ----------------------------------------------------------- Constructors
/**
* Constructor.
*
* @param token the token for accessing the namespace
* @param config configuration of the WebDAV servlet
*/
public SearchMethod(NamespaceAccessToken token,
WebdavServletConfig config) {
super(token, config);
}
/**
* Method parseRequest
*
* @throws WebdavException
*/
protected void parseRequest() throws WebdavException {
searchHelper = token.getSearchHelper();
retriever = new PropertyRetrieverImpl(token, slideToken, getConfig());
String slidePath = null;
extendedAllprop = getBooleanInitParameter( "extendedAllprop" );
if (Configuration.useSearch ()) {
try {
Element queryElement = getQueryElement();
String grammarNamespace = queryElement.getNamespaceURI();
// SearchLanguage language = searchHelper.getLanguage (grammarNamespace);
int maxDepth = getConfig().getDepthLimit();
searchQuery = searchHelper.createSearchQuery
(grammarNamespace, queryElement, slideToken, maxDepth,
new ComputedPropertyProvider(token, slideToken,
getSlideContextPath(), getConfig()),
req.getRequestURI ());
requestedProperties = searchQuery.requestedProperties ();
if (searchQuery instanceof IBasicQuery)
{
QueryScope scope = ((IBasicQuery)searchQuery).getScope();
slidePath = ((IBasicQuery)searchQuery).getSlidePath();
// check, if scope is accessible (ACL)
token.getContentHelper().retrieve(slideToken, slidePath);
scope.setIsCollection (
WebdavUtils.isCollection (token, slideToken, slidePath));
}
}
catch (JDOMException e) {
resp.setStatus(WebdavStatus.SC_BAD_REQUEST);
resp.setContentType (TEXT_XML_UTF_8);
createErrorResult (SearchQueryResult.STATUS_BAD_QUERY,
e.getMessage());
throw new WebdavException(WebdavStatus.SC_BAD_REQUEST);
}
catch (InvalidQueryException e) {
resp.setStatus(WebdavStatus.SC_UNPROCESSABLE_ENTITY);
resp.setContentType (TEXT_XML_UTF_8);
createErrorResult (SearchQueryResult.STATUS_UNPROCESSABLE_ENTITY,
e.getMessage());
throw new WebdavException(WebdavStatus.SC_UNPROCESSABLE_ENTITY);
}
catch (BadGatewayException e) {
resp.setStatus(WebdavStatus.SC_BAD_GATEWAY);
resp.setContentType (TEXT_XML_UTF_8);
createErrorResult (SearchQueryResult.STATUS_BAD_GATEWAY,
e.getMessage());
throw new WebdavException(WebdavStatus.SC_BAD_GATEWAY);
}
catch (InvalidScopeException e) {
resp.setStatus(WebdavStatus.SC_BAD_REQUEST);
resp.setContentType (TEXT_XML_UTF_8);
createErrorResult (SearchQueryResult.STATUS_INVALID_SCOPE,
e.getMessage());
throw new WebdavException (WebdavStatus.SC_BAD_REQUEST);
}
catch (BadQueryException e) {
resp.setStatus(WebdavStatus.SC_BAD_REQUEST);
resp.setContentType (TEXT_XML_UTF_8);
createErrorResult (SearchQueryResult.STATUS_BAD_QUERY,
e.getMessage());
throw new WebdavException(WebdavStatus.SC_BAD_REQUEST);
}
catch (AccessDeniedException e) {
String contextPath = getSlideContextPath();
AccessDeniedException ade = new AccessDeniedException
(contextPath + e.getObjectUri(),
contextPath + e.getSubjectUri(),
contextPath + e.getActionUri());
String msg = ade.getMessage();
resp.setStatus(WebdavStatus.SC_FORBIDDEN);
resp.setContentType (TEXT_XML_UTF_8);
createErrorResult (SearchQueryResult.STATUS_FORBIDDEN, msg);
throw new WebdavException(WebdavStatus.SC_FORBIDDEN);
}
catch (ObjectNotFoundException e) {
resp.setStatus(WebdavStatus.SC_BAD_REQUEST);
resp.setContentType (TEXT_XML_UTF_8);
createErrorResult (SearchQueryResult.STATUS_INVALID_SCOPE,
"scope " + slidePath + " is invalid");
throw new WebdavException (WebdavStatus.SC_BAD_REQUEST);
}
catch (SlideException e) {
e.printStackTrace();
}
}
else {
resp.setStatus(WebdavStatus.SC_BAD_REQUEST);
resp.setContentType (TEXT_XML_UTF_8);
createErrorResult (SearchQueryResult.STATUS_BAD_QUERY, "SEARCH not implemented on this server");
throw new WebdavException(WebdavStatus.SC_BAD_REQUEST);
}
}
/**
* Method executeRequest
*
* @throws WebdavException
*
* @version 12/28/2001
*/
protected void executeRequest() throws WebdavException {
SearchQueryResult result = null;
try {
if ( WebdavEvent.SEARCH.isEnabled() ) EventDispatcher.getInstance().fireVetoableEvent(WebdavEvent.SEARCH, new WebdavEvent(this));
resp.setContentType (TEXT_XML_UTF_8);
result = searchHelper.search (slideToken, searchQuery);
WebdavResult webdavResult = new WebdavResult (result, retriever);
resp.setStatus (webdavResult.getWebdavStatus());
org.jdom.Document responseDoc = webdavResult.getWebdavResultDocument();
sendResult (responseDoc);
}
catch (StructureException e) {
try {
resp.sendError
(WebdavStatus.SC_NOT_FOUND,
WebdavStatus.getStatusText(WebdavStatus.SC_NOT_FOUND));
} catch(IOException ex) {
ex.printStackTrace();
}
throw new WebdavException(WebdavStatus.SC_NOT_FOUND);
} catch (RuntimeException e) {
e.printStackTrace();
resp.setStatus(getErrorCode(e)); // no special handling needed
throw new WebdavException(WebdavStatus.SC_ACCEPTED, false); // abort the TA
} catch (Exception e) {
resp.setStatus(getErrorCode(e)); // no special handling needed
throw new WebdavException(WebdavStatus.SC_ACCEPTED, false); // abort the TA
}
}
/**
* Method getSearchRequestElement
*
* @return an Element
*
* @throws WebdavException
*
* @version 12/28/2001
*/
private Element getQueryElement() throws WebdavException, JDOMException {
Element queryElement = null;
try
{
Document document = parseRequestContent(); // TODO: check root element name
Element rootElement = document.getRootElement();
List children = rootElement.getChildren();
if (children.size() > 0) {
queryElement = (Element)children.get(0);
}
return queryElement;
}
catch (IOException e) {
System.err.println(e.getMessage());
e.printStackTrace();
resp.setStatus(WebdavStatus.SC_INTERNAL_SERVER_ERROR);
throw new WebdavException
(WebdavStatus.SC_INTERNAL_SERVER_ERROR);
}
}
/**
* Method sendResult
*
* @param responseDoc a Document
*
* @throws JDOMException
* @throws IOException
*
*/
private void sendResult (org.jdom.Document responseDoc)
throws org.jdom.JDOMException, IOException
{
org.jdom.output.Format format = org.jdom.output.Format.getPrettyFormat();
format.setIndent(XML_RESPONSE_INDENT);
XMLOutputter xmlWriter = new XMLOutputter (format);
xmlWriter.output (responseDoc, resp.getWriter());
}
/**
* Method createErrorResult
*
* @param queryStatus an int
* @param message a String
*
*/
private void createErrorResult (int queryStatus, String message) {
SearchQueryResult result = new SearchQueryResult ();
result.setStatus (queryStatus);
result.setDescription (message);
result.setHref (getSlideContextPath());
try {
WebdavResult webdavResult = new WebdavResult (result, retriever);
org.jdom.Document responseDoc = webdavResult.getWebdavResultDocument();
sendResult (responseDoc);
}
catch (Exception e) {}
}
/**
* Represents the webdav result for a SEARCH. It encapsulates the response
* body, and the status of the response. It contains a list of response
* elements with propstat elements and optional a response element with
* an error status and a responsedescription
*/
class WebdavResult {
private SearchQueryResult queryResult;
private org.jdom.Document responseDoc;
private PropertyRetriever retriever;
/** the status of the response */
private int webdavStatus = WebdavStatus.SC_MULTI_STATUS;
/**
* constructs a WebdavResult
*
* @param queryResult the result of the query
* @param retriever the retriever to get the properties
*
* @throws JDOMException
* @throws SlideException
*
*/
WebdavResult (SearchQueryResult queryResult, PropertyRetriever retriever)
throws org.jdom.JDOMException, SlideException
{
this.queryResult = queryResult;
this.retriever = retriever;
init();
}
/**
* Method getWebdavStatus
*
* @return an int
*
*/
int getWebdavStatus () {
return webdavStatus;
}
/**
* Method getWebdabResultDocument
*
* @return a Document
*
*/
org.jdom.Document getWebdavResultDocument () {
return responseDoc;
}
/**
* Method init
*
* @throws JDOMException
* @throws SlideException
*
*/
private void init () throws org.jdom.JDOMException, SlideException {
String href = null;
int errorStatus = webdavStatus;
org.jdom.Element rootElement =
new org.jdom.Element (E_MULTISTATUS, DNSP);
responseDoc = new org.jdom.Document (rootElement);
Iterator it = queryResult.iterator();
while (it.hasNext()) {
org.jdom.Element responseElement =
new org.jdom.Element (E_RESPONSE, DNSP);
rootElement.addContent (responseElement);
org.jdom.Element hrefElement =
new org.jdom.Element (E_HREF, DNSP);
RequestedResource resource = (RequestedResource)it.next();
String internalUri = resource.getUri();
String absUri = WebdavUtils.getAbsolutePath (internalUri, req, getConfig());
hrefElement.addContent(absUri);
responseElement.addContent (hrefElement);
List propstatList= retriever.getPropertiesOfObject (requestedProperties,
resource,
getSlideContextPath(),
extendedAllprop);
Iterator iterator = propstatList.iterator();
while (iterator.hasNext()) {
responseElement.addContent((org.jdom.Element)iterator.next());
}
}
int status = queryResult.getStatus();
if (status != SearchQueryResult.STATUS_OK) {
//String webdavStatusText = null;
switch (status) {
case SearchQueryResult.STATUS_BAD_QUERY:
webdavStatus = WebdavStatus.SC_BAD_REQUEST;
errorStatus = WebdavStatus.SC_BAD_REQUEST;
href = queryResult.getHref();
break;
case SearchQueryResult.STATUS_INVALID_SCOPE:
webdavStatus = WebdavStatus.SC_BAD_REQUEST;
errorStatus = WebdavStatus.SC_NOT_FOUND;
href = queryResult.getHref();
break;
case SearchQueryResult.STATUS_PARTIAL_RESULT:
errorStatus = WebdavStatus.SC_INSUFFICIENT_STORAGE;
href = getSlideContextPath();
break;
case SearchQueryResult.STATUS_UNPROCESSABLE_ENTITY:
errorStatus = WebdavStatus.SC_UNPROCESSABLE_ENTITY;
href = getSlideContextPath();
break;
case SearchQueryResult.STATUS_BAD_GATEWAY:
errorStatus = WebdavStatus.SC_BAD_GATEWAY;
href = queryResult.getHref();
break;
case SearchQueryResult.STATUS_FORBIDDEN:
errorStatus = WebdavStatus.SC_FORBIDDEN;
href = queryResult.getHref();
break;
default:
throw new WebdavException
(WebdavStatus.SC_INTERNAL_SERVER_ERROR);
}
org.jdom.Element responseElement =
new org.jdom.Element (E_RESPONSE, DNSP);
org.jdom.Element hrefElement =
new org.jdom.Element (E_HREF, DNSP);
hrefElement.addContent (href);
org.jdom.Element statusElement =
new org.jdom.Element (E_STATUS, DNSP);
statusElement.addContent (getStatusText (errorStatus));
responseElement.addContent (hrefElement);
responseElement.addContent (statusElement);
String description = queryResult.getDescription();
if (description != null) {
org.jdom.Element responseDescriptionElement =
new org.jdom.Element (E_RESPONSEDESCRIPTION,
DNSP);
responseDescriptionElement.addContent (description);
responseElement.addContent (responseDescriptionElement);
}
if (status == SearchQueryResult.STATUS_INVALID_SCOPE) {
responseElement.addContent (
new org.jdom.Element ("scopeerror",
DNSP));
}
rootElement.addContent (responseElement);
}
}
/**
* Method getStatusText
*
* @param status an int
*
* @return a String
*
*/
private String getStatusText (int status) {
return "HTTP/1.1 " + status + " "
+ WebdavStatus.getStatusText (status);
}
}
}