/*
* $Header: /home/cvs/jakarta-slide/src/webdav/server/org/apache/slide/webdav/util/PropertyRetrieverImpl.java,v 1.39.2.1 2004/12/02 21:21:05 ozeigermann Exp $
* $Revision: 1.39.2.1 $
* $Date: 2004/12/02 21:21:05 $
*
* ====================================================================
*
* 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.util;
import java.util.ArrayList;
import java.util.Enumeration;
import java.util.HashMap;
import java.util.Iterator;
import java.util.List;
import java.util.Map;
import org.apache.slide.common.NamespaceAccessToken;
import org.apache.slide.common.PropertyName;
import org.apache.slide.common.RequestedProperties;
import org.apache.slide.common.RequestedPropertiesImpl;
import org.apache.slide.common.RequestedProperty;
import org.apache.slide.common.RequestedPropertyImpl;
import org.apache.slide.common.SlideException;
import org.apache.slide.common.SlideToken;
import org.apache.slide.common.UriPath;
import org.apache.slide.content.Content;
import org.apache.slide.content.NodeProperty;
import org.apache.slide.content.NodeRevisionDescriptor;
import org.apache.slide.content.NodeRevisionDescriptors;
import org.apache.slide.content.NodeRevisionNumber;
import org.apache.slide.content.RevisionDescriptorNotFoundException;
import org.apache.slide.content.NodeProperty.NamespaceCache;
import org.apache.slide.lock.Lock;
import org.apache.slide.search.RequestedResource;
import org.apache.slide.security.AccessDeniedException;
import org.apache.slide.security.Security;
import org.apache.slide.structure.Structure;
import org.apache.slide.util.Configuration;
import org.apache.slide.util.XMLValue;
import org.apache.slide.webdav.WebdavServletConfig;
import org.apache.slide.webdav.util.resourcekind.AbstractResourceKind;
import org.apache.slide.webdav.util.resourcekind.ResourceKind;
import org.jdom.CDATA;
import org.jdom.Comment;
import org.jdom.Element;
import org.jdom.EntityRef;
import org.jdom.JDOMException;
import org.jdom.Namespace;
import org.jdom.ProcessingInstruction;
import org.jdom.Text;
/**
* This class is used to retrieve the properties of a resource as a
* <code><propstat></code> element. The main code of this class
* has been copied from the <code>PropFindMethod</code>. All methods
* providing property information (<code>PropFindMethod</code>,
* <code>ReportMethod</code>) should use this class.
*
* @version $Revision: 1.39.2.1 $
*
*/
public class PropertyRetrieverImpl extends AbstractWebdavHelper implements PropertyRetriever, WebdavConstants, DeltavConstants, AclConstants, BindConstants {
/**
* The Content helper.
*/
protected Content content = null;
/**
* The Lock helper used to access the locks.
*/
protected Lock lock = null;
/**
* The Security helper.
*/
protected Security security = null;
/**
* The Structure helper.
*/
protected Structure structure = null;
/**
* The PropertyHelper used to access the (computed) properties.
*/
protected PropertyHelper propertyHelper = null;
/**
* the webdavservlet configuration
*/
protected WebdavServletConfig config = null;
/**
* Creates a PropertyRetriever from the given parameters.
*
* @param token the NamespaceAccessToken used to access the helpers.
* @param slideToken the SlideToken used to retrieve the NodeRevisionDescriptor(s).
*/
public PropertyRetrieverImpl(NamespaceAccessToken token, SlideToken slideToken, WebdavServletConfig sConf) {
super(slideToken, token);
this.structure = token.getStructureHelper();
this.content = token.getContentHelper();
this.security = token.getSecurityHelper();
this.lock = token.getLockHelper();
this.config = sConf;
propertyHelper = PropertyHelper.getPropertyHelper(slideToken, token, sConf);
}
/** deprecated */
// public PropertyRetrieverImpl(NamespaceAccessToken token, SlideToken slideToken) {
// super(slideToken, token);
// this.structure = token.getStructureHelper();
// this.content = token.getContentHelper();
// this.security = token.getSecurityHelper();
// this.lock = token.getLockHelper();
//
// propertyHelper = PropertyHelper.getPropertyHelper(slideToken, token, null);
// }
/**
* Returns the PropertyHelper used to access the (computed) properties.
*
* @return the PropertyHelper used to access the (computed) properties.
*/
protected PropertyHelper getPropertyHelper() {
return propertyHelper;
}
/**
* Returns the requested properties of the last revision of the resource
* identified by the given <code>uri</code> as list of <code><propstat></code>
* JDOM Elements.
*
* @param requestedProperties the requested properties.
* @param uri the URI of the resource.
* @param contextPath a String , the result of HttpRequest.getContextPath()
* @param servletPath a String, the result of HttpRequest.getServletPath()
* @param extendedAllprop indicates if the <code>DeltaV</code> specific
* properties should be included in case
* all properties are requested.
*
* @return the requested properties as list of <code><propstat></code>
* JDOM Element.
*
* @throws SlideException
* @throws JDOMException if creating the JDOM Element fails.
*/
public List getPropertiesOfObject(RequestedProperties requestedProperties, String uri, String servletContextPath, boolean extendedAllprop) throws SlideException, JDOMException {
NodeRevisionDescriptors revisionDescriptors = null;
NodeRevisionDescriptor revisionDescriptor = null;
//boolean isCollection = false;
try {
revisionDescriptors =
content.retrieve(sToken, uri);
try {
revisionDescriptor = content.retrieve(sToken,
revisionDescriptors);
//isCollection = WebdavUtils.isCollection(revisionDescriptor);
} catch (RevisionDescriptorNotFoundException e) {
// The object doesn't have any revision, we create a dummy
// NodeRevisionDescriptor object
//isCollection = true;
revisionDescriptor = new NodeRevisionDescriptor(0);
if (!Configuration.useBinding(nsaToken.getUri(sToken, uri).getStore())) {
revisionDescriptor.setName(new UriPath(uri).lastSegment());
}
}
} catch (AccessDeniedException e) {
if (revisionDescriptor == null) {
revisionDescriptor = new NodeRevisionDescriptor(0);
}
}
// catch (Exception e) {
// // resp.setStatus(getErrorCode(e));
// throw new WebdavException(getErrorCode(e)); // abort the TA
// }
return getPropertiesOfObject(requestedProperties, revisionDescriptors, revisionDescriptor, servletContextPath, extendedAllprop);
}
/**
* Returns the requested properties of the resource identified by the given
* <code>uri</code> and <code>revisionNumber</code> as list of
* <code><propstat></code> JDOM Elements.
*
* @param requestedProperties the requested properties.
* @param uri the URI of the resource.
* @param revisionNumber the revision number of the requested resource.
* @param contextPath a String , the result of HttpRequest.getContextPath()
* @param servletPath a String, the result of HttpRequest.getServletPath()
* @param extendedAllprop indicates if the <code>DeltaV</code> specific
* properties should be included in case
* all properties are requested.
*
* @return the requested properties as list of <code><propstat></code>
* JDOM Element.
*
* @throws SlideException
* @throws JDOMException if creating the JDOM Element fails.
*/
public List getPropertiesOfObject(RequestedProperties requestedProperties, String uri, NodeRevisionNumber revisionNumber, String servletContextPath, boolean extendedAllprop) throws SlideException, JDOMException {
NodeRevisionDescriptors revisionDescriptors = content.retrieve(sToken, uri);
NodeRevisionDescriptor revisionDescriptor = content.retrieve(sToken,
revisionDescriptors,
revisionNumber);
return getPropertiesOfObject(requestedProperties, revisionDescriptors, revisionDescriptor, servletContextPath, extendedAllprop);
}
/**
* Returns the requested properties of the resource identified by the given
* <code>uri</code> and <code>revisionNumber</code> as list of
* <code><propstat></code> JDOM Elements.
*
* @param requestedProperties the requested properties.
* @param revisionDescriptors the NodeRevisionDescriptors of the resource.
* @param revisionDescriptor the NodeRevisionDescriptor of the resource.
* @param contextPath a String , the result of HttpRequest.getContextPath()
* @param servletPath a String, the result of HttpRequest.getServletPath()
* @param extendedAllprop indicates if the <code>DeltaV</code> specific
* properties should be included in case
* all properties are requested.
*
* @return the requested properties as list of <code><propstat></code>
* JDOM Element.
*
* @throws SlideException
* @throws JDOMException if creating the JDOM Element fails.
*/
public List getPropertiesOfObject(RequestedProperties requestedProperties, NodeRevisionDescriptors revisionDescriptors, NodeRevisionDescriptor revisionDescriptor, String servletContextPath, boolean extendedAllprop) throws SlideException, JDOMException {
ComputedPropertyProvider propertyProvider = new ComputedPropertyProvider(nsaToken,
sToken,
propertyHelper,
servletContextPath);
return getPropertiesOfObject(requestedProperties,
new ResourceWithProvidedProperties(revisionDescriptors,
revisionDescriptor,
propertyProvider),
servletContextPath,
extendedAllprop);
}
/**
* Returns the requested properties of the <code><requestedResource/code>
* as list of <code><propstat></code> JDOM Elements.
*
* @param requestedProperties the requested properties.
* @param requestedResource the resource for which to return the properties.
* @param contextPath a String , the result of HttpRequest.getContextPath()
* @param servletPath a String, the result of HttpRequest.getServletPath()
* @param extendedAllprop indicates if the <code>DeltaV</code> specific
* properties should be included in case
* all properties are requested.
*
* @return the requested properties as list of <code><propstat></code>
* JDOM Element.
*
* @throws SlideException
* @throws JDOMException if creating the JDOM Element fails.
*/
public List getPropertiesOfObject(RequestedProperties requestedProperties, RequestedResource requestedResource, String servletContextPath, boolean extendedAllprop) throws SlideException, JDOMException {
List elementList = new ArrayList();
// String status = new String("HTTP/1.1 " + WebdavStatus.SC_OK + " "
// + WebdavStatus.getStatusText
// (WebdavStatus.SC_OK));
if (requestedProperties.isAllProp()) {
elementList = getAllPropertiesOfObject(requestedResource, servletContextPath, extendedAllprop);
}
else {
elementList = getRequestedPropertiesOfObject(requestedProperties, requestedResource, servletContextPath);
}
return elementList;
}
/**
* Returns the requested properties of the <code><requestedResource/code>
* as list of <code><propstat></code> JDOM Elements.
*
* @param requestedProperties the requested properties.
* @param requestedResource the resource for which to return the properties.
* @param contextPath a String , the result of HttpRequest.getContextPath()
* @param servletPath a String, the result of HttpRequest.getServletPath()
*
* @return the requested properties as list of <code><propstat></code>
* JDOM Element.
*
* @throws SlideException
*/
protected List getRequestedPropertiesOfObject(RequestedProperties requestedProperties, RequestedResource requestedResource, String servletContextPath) throws SlideException {
List elementList = new ArrayList();
Iterator propertyIterator = requestedProperties.getRequestedProperties();
Element propstat = new Element(E_PROPSTAT, NamespaceCache.DEFAULT_NAMESPACE);
Element prop = new Element(E_PROP, NamespaceCache.DEFAULT_NAMESPACE);
propstat.addContent(prop);
Element propertyElement = null;
boolean anyPropertyFound = false;
// maps the code of the error (that occurred when retrieving the property)
// to the List of RequestedProperty that caused that error
Map erroneousPropertiesMap = new HashMap();
String status = new String("HTTP/1.1 " + WebdavStatus.SC_OK
+ " " + WebdavStatus.getStatusText
(WebdavStatus.SC_OK));
while (propertyIterator.hasNext()) {
RequestedProperty property = (RequestedProperty)propertyIterator.next();
NodeProperty currentProperty = null;
Integer errorCode = null;
try {
currentProperty = requestedResource.getProperty(property.getName(),
property.getNamespace());
if (currentProperty == null) {
errorCode = new Integer(WebdavStatus.SC_NOT_FOUND);
}
}
catch (AccessDeniedException e) {
errorCode = new Integer(WebdavStatus.SC_FORBIDDEN);
}
if (errorCode != null) {
List erroneousPropertiesList = (List)erroneousPropertiesMap.get(errorCode);
if (erroneousPropertiesList == null) {
erroneousPropertiesList = new ArrayList();
erroneousPropertiesMap.put(errorCode, erroneousPropertiesList);
}
erroneousPropertiesList.add(new PropertyName(property.getName(), property.getNamespace()));
}
else {
propertyElement = getPropertyElement(currentProperty, servletContextPath);
if (propertyElement != null) {
anyPropertyFound = true;
prop.addContent(propertyElement);
}
}
}
if (anyPropertyFound) {
Element statusElement = new Element(E_STATUS, NamespaceCache.DEFAULT_NAMESPACE);
statusElement.setText(status);
propstat.addContent(statusElement);
elementList.add(propstat);
}
elementList.addAll(getPropstatForErroneousProperties(erroneousPropertiesMap, servletContextPath));
return elementList;
}
/**
* Returns all properties of the <code><requestedResource/code>
* as list of <code><propstat></code> JDOM Elements.
*
* @param requestedResource the resource for which to return the properties.
* @param contextPath a String , the result of HttpRequest.getContextPath()
* @param servletPath a String, the result of HttpRequest.getServletPath()
* @param extendedAllprop indicates if the <code>DeltaV</code> specific
* properties should be included in case
* all properties are requested.
*
* @return the requested properties as list of <code><propstat></code>
* JDOM Element.
*
* @throws SlideException
*/
protected List getAllPropertiesOfObject(RequestedResource requestedResource, String servletContextPath, boolean extendedAllprop) throws SlideException {
List elementList = new ArrayList();
Element propstat = new Element(E_PROPSTAT, NamespaceCache.DEFAULT_NAMESPACE);
elementList.add(propstat);
Element prop = new Element(E_PROP, NamespaceCache.DEFAULT_NAMESPACE);
propstat.addContent(prop);
Element propertyElement = null;
// maps the code of the error (that occurred when retrieving the property)
// to the List of RequestedProperty that caused that error
Map erroneousPropertiesMap = new HashMap();
String status = new String("HTTP/1.1 " + WebdavStatus.SC_OK
+ " " + WebdavStatus.getStatusText
(WebdavStatus.SC_OK));
Iterator propertyNameIterator = requestedResource.getAllPropertiesNames();
while (propertyNameIterator.hasNext()) {
PropertyName currentPropertyName = (PropertyName) propertyNameIterator.next();
if (currentPropertyName != null) {
if ( !extendedAllprop && S_DAV.equals(currentPropertyName.getNamespace()) && (
DeltavConstants.DELTAV_PROPERTY_LIST.contains(currentPropertyName.getName()) ||
BindConstants.BIND_PROPERTY_LIST.contains(currentPropertyName.getName()) ||
AclConstants.ACL_PROPERTY_LIST.contains(currentPropertyName.getName())
)
) {
// skip properties from specification extensions
continue;
}
NodeProperty currentProperty = null;
Integer errorCode = null;
try {
currentProperty = requestedResource.getProperty(currentPropertyName);
if (currentProperty == null) {
errorCode = new Integer(WebdavStatus.SC_NOT_FOUND);
}
}
catch (AccessDeniedException e) {
errorCode = new Integer(WebdavStatus.SC_FORBIDDEN);
}
if (errorCode != null) {
List erroneousPropertiesList = (List)erroneousPropertiesMap.get(errorCode);
if (erroneousPropertiesList == null) {
erroneousPropertiesList = new ArrayList();
erroneousPropertiesMap.put(errorCode, erroneousPropertiesList);
}
erroneousPropertiesList.add(currentPropertyName);
}
else {
propertyElement = getPropertyElement(currentProperty, servletContextPath);
if (propertyElement != null) {prop.addContent(propertyElement);}
}
}
}
Element statusElement = new Element(E_STATUS, NamespaceCache.DEFAULT_NAMESPACE);
statusElement.setText(status);
propstat.addContent(statusElement);
elementList.addAll(getPropstatForErroneousProperties(erroneousPropertiesMap, servletContextPath));
return elementList;
}
/**
* Returns a list of <code><propstat></code> JDOM Elements for the properties
* that could not be retrieved due to an error.
*
* @param erroneousPropertiesMap maps the (Integer) code of the error (that occurred
* when retrieving the property) to the List of
* PropertyName that caused that error.
* @param contextPath a String , the result of HttpRequest.getContextPath()
* @param servletPath a String, the result of HttpRequest.getServletPath()
*
* @return A List of <code><propstat></code> JDOM Elements for the erroneous properties.
*/
protected List getPropstatForErroneousProperties(Map erroneousPropertiesMap, String servletContextPath) {
List elementList = new ArrayList();
Iterator iterator = erroneousPropertiesMap.keySet().iterator();
while (iterator.hasNext()) {
Integer errorCode = (Integer)iterator.next();
List erroneousPropertiesList = (List)erroneousPropertiesMap.get(errorCode);
Element propstat = new Element(E_PROPSTAT, NamespaceCache.DEFAULT_NAMESPACE);
elementList.add(propstat);
Element prop = new Element(E_PROP, NamespaceCache.DEFAULT_NAMESPACE);
propstat.addContent(prop);
String status = new String("HTTP/1.1 " + errorCode.intValue()
+ " " + WebdavStatus.getStatusText(errorCode.intValue()));
Iterator propertyIterator = erroneousPropertiesList.iterator();
while (propertyIterator.hasNext()) {
PropertyName erroneousProperty =
(PropertyName) propertyIterator.next();
Element propertyElement = getPropertyElement(erroneousProperty.getNamespace(),
erroneousProperty.getName(),
null,
servletContextPath);
if (propertyElement != null) {prop.addContent(propertyElement);}
}
Element statusElement = new Element(E_STATUS, NamespaceCache.DEFAULT_NAMESPACE);
statusElement.setText(status);
propstat.addContent(statusElement);
}
return elementList;
}
/**
* Returns the JDOM Element for the given <code>property</code>.
*
* @param property the property for which to return the Element.
* @param contextPath a String , the result of HttpRequest.getContextPath()
* @param servletPath a String, the result of HttpRequest.getServletPath()
*
* @return the JDOM Element for the given <code>property</code>.
*/
private Element getPropertyElement(NodeProperty property, String servletContextPath) {
if (property != null) {
return getPropertyElement(property.getNamespace(),
property.getName(),
property.getValue(),
servletContextPath);
}
return null;
}
/**
* Returns the JDOM Element for the given <code>property</code>.
*
* @param namespaceString the property namespace.
* @param propertyName the property Name.
* @param propertyValue the property Value.
* @param contextPath a String , the result of HttpRequest.getContextPath()
* @param servletPath a String, the result of HttpRequest.getServletPath()
*
* @return the JDOM Element for the given <code>property</code>.
*/
private Element getPropertyElement(String namespaceString,
String propertyName,
Object propertyValue,
String servletContextPath) {
Element property = null;
Namespace namespace = Namespace.NO_NAMESPACE;
Namespace valueDefaultNamespace = null;
if (namespaceString != null) {
namespace = NamespaceCache.getNamespace(namespaceString);
if (NamespaceCache.DEFAULT_URI.equals(namespace.getURI())) {
// use the DAV: as the default namespace
// for XML values of DAV: properties
valueDefaultNamespace = namespace;
}
}
property = new Element(propertyName, namespace);
if ( (propertyValue != null) && (propertyValue.toString().length() > 0)) {
if( propertyValue.toString().indexOf('<') >= 0 ) {
try {
XMLValue xmlValue = new XMLValue(propertyValue.toString(), valueDefaultNamespace);
if (AbstractResourceKind.isLiveProperty(propertyName)) {
convertHrefValueToAbsoluteURL (xmlValue, servletContextPath, config);
}
Iterator iterator = xmlValue.iterator();
while (iterator.hasNext()) {
Object o = iterator.next();
if( o instanceof Element )
property.addContent((Element)o);
else if( o instanceof Text )
property.addContent((Text)o);
else if( o instanceof Comment )
property.addContent((Comment)o);
else if( o instanceof ProcessingInstruction )
property.addContent((ProcessingInstruction)o);
else if( o instanceof CDATA )
property.addContent((CDATA)o);
else if( o instanceof EntityRef )
property.addContent((EntityRef)o);
}
}
catch (JDOMException e) {
property.setText(propertyValue.toString());
}
}
else {
property.setText(propertyValue.toString());
}
}
return property;
}
/**
* If the given <code>xmlValue</code> contains <code><href></code> elements,
* the relative URI is converted to an absolute one.
*
* @param xmlValue the XMLValue that might contain <code><href></code>
* values to convert.
* @param contextPath a String , the result of HttpRequest.getContextPath()
* @param servletPath a String, the result of HttpRequest.getServletPath()
*/
protected static void convertHrefValueToAbsoluteURL (XMLValue xmlValue,
String servletContextPath,
WebdavServletConfig config) {
if (xmlValue != null) {
Iterator iterator = xmlValue.iterator();
Element element = null;
while (iterator.hasNext()) {
Object o = iterator.next();
if( o instanceof Element ) {
element = (Element)o;
convertHrefValueToAbsoluteURL(element, servletContextPath, config);
}
}
}
}
private static void convertHrefValueToAbsoluteURL (Element element,
String servletContextPath,
WebdavServletConfig config) {
if (element.getChildren().size() > 0) {
Iterator i = element.getChildren().iterator();
while (i.hasNext()) {
Element child = (Element)i.next();
// hrefs for owner and active locks have to be left untouched (issue 32436)
if (!(element.getName().equals("activelock") && child.getName().equals("owner"))) {
convertHrefValueToAbsoluteURL(child, servletContextPath, config);
}
}
}
if ( E_HREF.equals(element.getName()) && (element.getText() != null) ) {
if ( !PropertyHelper.isAbsoluteURL(servletContextPath, element.getText()) ) {
element.setText(WebdavUtils.getAbsolutePath (element.getText(),
servletContextPath, config));
}
}
}
/**
* Discover what properties exist or are supported by a resource.
* @param resourcePath a String
* @param liveOnly only live properties
* @return a RequestedProperties
* @throws SlideException
*/
public RequestedProperties getAllPropertyNames(String resourcePath, boolean liveOnly) throws SlideException {
NodeRevisionDescriptor nrd =
content.retrieve(sToken, content.retrieve(sToken, resourcePath));
ResourceKind resourceKind = AbstractResourceKind.determineResourceKind(nsaToken, resourcePath, nrd);
RequestedPropertiesImpl result = (RequestedPropertiesImpl)getAllPropertyNames(resourceKind);
if (!liveOnly) {
// add this resource's dead properties
Enumeration props = nrd.enumerateProperties();
while (props.hasMoreElements()) {
NodeProperty np = (NodeProperty)props.nextElement();
if (!result.contains(np)) {
result.addProperty(new RequestedPropertyImpl(np.getName(), np.getNamespace()));
}
}
}
return result;
}
/**
* Discover what properties are supported by the specified resourcetype.
*
* @param resourceKind a ResourceKind
*
* @return a RequestedProperties
*
* @throws SlideException
*
*/
public RequestedProperties getAllPropertyNames(ResourceKind resourceKind) throws SlideException {
RequestedPropertiesImpl result = new RequestedPropertiesImpl();
Iterator liveprops = resourceKind.getSupportedLiveProperties().iterator();
while (liveprops.hasNext()) {
result.addProperty(new RequestedPropertyImpl((String)liveprops.next(), DNSP.getURI()));
}
return result;
}
}