/*
* $Header: /home/cvs/jakarta-slide/src/webdav/server/org/apache/slide/webdav/method/PropPatchMethod.java,v 1.86 2004/08/03 09:37:48 ozeigermann Exp $
* $Revision: 1.86 $
* $Date: 2004/08/03 09:37:48 $
*
* ====================================================================
*
* 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.io.Writer;
import java.util.Date;
import java.util.Iterator;
import java.util.List;
import java.util.StringTokenizer;
import org.apache.slide.common.NamespaceAccessToken;
import org.apache.slide.common.PropertyParseException;
import org.apache.slide.common.RequestedPropertiesImpl;
import org.apache.slide.common.RequestedProperty;
import org.apache.slide.common.RequestedPropertyImpl;
import org.apache.slide.common.ServiceAccessException;
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.event.EventDispatcher;
import org.apache.slide.structure.LinkedObjectNotFoundException;
import org.apache.slide.util.Configuration;
import org.apache.slide.util.XMLValue;
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.AclConstants;
import org.apache.slide.webdav.util.DeltavConstants;
import org.apache.slide.webdav.util.PreconditionViolationException;
import org.apache.slide.webdav.util.PropertyHelper;
import org.apache.slide.webdav.util.UriHandler;
import org.apache.slide.webdav.util.VersioningHelper;
import org.apache.slide.webdav.util.ViolatedPrecondition;
import org.apache.slide.webdav.util.WebdavStatus;
import org.apache.slide.webdav.util.resourcekind.AbstractResourceKind;
import org.apache.slide.webdav.util.resourcekind.CheckedInVersionControlled;
import org.apache.slide.webdav.util.resourcekind.ResourceKind;
import org.jdom.CDATA;
import org.jdom.Comment;
import org.jdom.Document;
import org.jdom.Element;
import org.jdom.EntityRef;
import org.jdom.JDOMException;
import org.jdom.Namespace;
import org.jdom.ProcessingInstruction;
import org.jdom.Text;
import org.jdom.output.Format;
import org.jdom.output.XMLOutputter;
/**
* PROPPATCH method.
*
*/
public class PropPatchMethod extends AbstractWebdavMethod implements DeltavConstants, AclConstants, WriteMethod {
// -------------------------------------------------------------- Constants
// ----------------------------------------------------- Instance Variables
/**
* The helpers used by this instance.
*/
protected VersioningHelper versioningHelper = null;
protected PropertyHelper propertyHelper = null;
/**
* Properties to set.
*/
private PropPatchProperties propertiesToSet;
/**
* Properties to remove.
*/
private PropPatchProperties propertiesToRemove;
/**
* Resource which will have its properties updated.
*/
private String resourcePath;
/**
* If true, the last modified date will be updated.
*/
private boolean updateLastModified;
// ----------------------------------------------------------- Constructors
/**
* Constructor.
*
* @param token the token for accessing the namespace
* @param config configuration of the WebDAV servlet
*/
public PropPatchMethod(NamespaceAccessToken token,
WebdavServletConfig config) {
super(token, config);
}
// ------------------------------------------------------ Protected Methods
/**
* Parse the request.
*
* @exception WebdavException Bad request
*/
protected void parseRequest()
throws WebdavException {
versioningHelper =
VersioningHelper.getVersioningHelper( slideToken, token, req, resp, config );
propertyHelper =
PropertyHelper.getPropertyHelper( slideToken, token, getConfig() );
// readRequestContent();
updateLastModified = getBooleanInitParameter( "updateLastModified" );
resourcePath = requestUri;
if (resourcePath == null) {
resourcePath = "/";
}
propertiesToSet = new PropPatchProperties();
propertiesToRemove = new PropPatchProperties();
if (req.getContentLength() != 0) {
try {
Iterator childrenIterator = parseRequestContent(E_PROPERTYUPDATE).getChildren().iterator();
Element child = null;
while (childrenIterator.hasNext()) {
child = (Element)childrenIterator.next();
if (E_SET.equals(child.getName())) {
propertiesToSet.add(getPropElement(child));
}
else if (E_REMOVE.equals(child.getName())) {
propertiesToRemove.add(getPropElement(child));
}
else {
throw new JDOMException("Expected <"+E_SET+"> or <"+E_REMOVE+"> element");
}
}
}
catch( Exception e ) {
int statusCode = getErrorCode( e );
sendError( statusCode, e );
throw new WebdavException( statusCode );
}
}
else {
int statusCode = WebdavStatus.SC_BAD_REQUEST;
sendError( statusCode, getClass().getName()+".missingRequestBody" );
throw new WebdavException( statusCode );
}
}
/**
* Checks if the given Element has exactly one child named
* <code><prop></code>. If the check succeeds the
* <code><prop></code> element is returned, otherwise a
* JDOMException is thrown.
*
* @param parent the parent Element of the <code><prop></code>.
*
* @return the <code><prop></code> element.
*
* @throws JDOMException if the check fails.
*/
private Element getPropElement(Element parent) throws JDOMException {
List childrenList = parent.getChildren();
if ( (childrenList.size() != 1) ||
( ! E_PROP.equals(((Element)childrenList.get(0)).getName()) ) ) {
throw new JDOMException("Expected <"+E_PROP+"> element");
}
return (Element)childrenList.get(0);
}
/**
* Execute the request.
*
* @exception WebdavException
*/
protected void executeRequest()
throws WebdavException, IOException {
boolean allOperationsExcecuted = true;
// Prevent dirty reads
slideToken.setForceStoreEnlistment(true);
// check lock-null resources
try {
if (isLockNull(resourcePath)) {
int statusCode = WebdavStatus.SC_NOT_FOUND;
sendError( statusCode, "lock-null resource", new Object[]{resourcePath} );
throw new WebdavException( statusCode );
}
}
catch (ServiceAccessException e) {
int statusCode = getErrorCode((Exception)e);
sendError( statusCode, e );
throw new WebdavException( statusCode );
}
try {
if ( WebdavEvent.PROPPATCH.isEnabled() ) EventDispatcher.getInstance().fireVetoableEvent(WebdavEvent.PROPPATCH, new WebdavEvent(this));
VersioningHelper vHelp =
VersioningHelper.getVersioningHelper(slideToken, token, req, resp, getConfig() );
NodeRevisionDescriptors revisionDescriptors =
content.retrieve(slideToken, resourcePath);
NodeRevisionNumber revisionNumber =
revisionDescriptors.getLatestRevision();
NodeRevisionDescriptor revisionDescriptor = null;
if (revisionNumber != null) {
try {
revisionDescriptor = content.retrieve
(slideToken, revisionDescriptors);
} catch (RevisionDescriptorNotFoundException e) {
}
}
if (revisionDescriptor == null) {
revisionDescriptor = new NodeRevisionDescriptor(0);
}
ResourceKind resourceKind = AbstractResourceKind.determineResourceKind(token, resourcePath, revisionDescriptor);
// check preconditions
ViolatedPrecondition violatedPrecondition = getPreconditionViolation(revisionDescriptors, revisionDescriptor, resourceKind);
if (violatedPrecondition != null) {
throw new PreconditionViolationException(violatedPrecondition, resourcePath);
}
// Changed for DeltaV --start--
boolean mustCheckIn = false;
if( Configuration.useVersionControl() &&
(resourceKind instanceof CheckedInVersionControlled) &&
versioningHelper.mustCheckoutAutoVersionedVCR(revisionDescriptors, revisionDescriptor) ) {
vHelp.checkout(revisionDescriptors, revisionDescriptor, false, false, true );
mustCheckIn = versioningHelper.mustCheckinAutoVersionedVCR(slideToken, revisionDescriptors, revisionDescriptor);
}
// Modifying the properties
Iterator propertyIterator = null;
propertyIterator = propertiesToSet.iterator();
PropPatchProperty currentProperty = null;
while (propertyIterator.hasNext()) {
currentProperty = (PropPatchProperty)propertyIterator.next();
if (checkPropertyModification(currentProperty, revisionDescriptor, resourceKind)) {
// Convert absolute URIs to relative ones, because Slide
// converts them to absolute ones in the result of queries.
String finalValue = currentProperty.getValue();
Element property = new Element(currentProperty.getName(), currentProperty.getNamespace());
String propertyValue = currentProperty.getValue();
if ( (propertyValue != null) && (propertyValue.toString().length() > 0)) {
if( propertyValue.toString().indexOf('<') >= 0 ) {
try {
XMLValue xmlValue = new XMLValue(propertyValue.toString(), Namespace.getNamespace(currentProperty.getNamespace()));
if (AbstractResourceKind.isLiveProperty(currentProperty.getName())) {
convertHrefValueToRelativeURL (xmlValue, getSlideContextPath(), 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);
}
finalValue = new XMLOutputter(Format.getRawFormat()).outputString(property.getContent());
}
catch (JDOMException e) {
// Fallback to original value
}
}
}
NodeProperty newProperty =
new NodeProperty(currentProperty.getName(),
finalValue,
currentProperty.getNamespace());
revisionDescriptor.setProperty(newProperty);
}
else {
allOperationsExcecuted = false;
}
}
propertyIterator = propertiesToRemove.iterator();
while (propertyIterator.hasNext()) {
currentProperty = (PropPatchProperty)propertyIterator.next();
if (checkPropertyModification(currentProperty, revisionDescriptor, resourceKind)) {
revisionDescriptor.removeProperty(currentProperty.getName(),
currentProperty.getNamespace());
}
else {
allOperationsExcecuted = false;
}
}
if (updateLastModified) {
revisionDescriptor.setLastModified(new Date());
}
if (allOperationsExcecuted) {
content.store(slideToken, resourcePath, revisionDescriptor, null);
}
// Changed for DeltaV --start--
if( Configuration.useVersionControl() && mustCheckIn) {
vHelp.checkin(revisionDescriptors, revisionDescriptor, false, false, true ); //forkOk=false, keepCheckedOut=false
}
// Changed for DeltaV --end--
resp.setContentType(TEXT_XML_UTF_8);
resp.setStatus(WebdavStatus.SC_MULTI_STATUS);
}
catch (PreconditionViolationException e) {
sendPreconditionViolation(e);
throw e;
}
catch (Exception e) {
int statusCode = getErrorCode( e );
sendError( statusCode, e );
throw new WebdavException( statusCode );
}
// No serious errors. Printing the XML report.
writeReport();
if (!allOperationsExcecuted) {
throw new WebdavException( WebdavStatus.SC_ACCEPTED ); // abort the TA
}
}
/**
* Get return status based on exception type.
*/
protected int getErrorCode(Exception ex) {
try {
throw ex;
} catch (LinkedObjectNotFoundException e) {
return WebdavStatus.SC_NOT_FOUND;
} catch (PropertyParseException e) {
return WebdavStatus.SC_BAD_REQUEST;
} catch (JDOMException e) {
return WebdavStatus.SC_BAD_REQUEST;
} catch (Exception e) {
return super.getErrorCode(e);
}
}
// -------------------------------------------------------- Private Methods
/**
* Check if the property is a live property which should have its value
* enforced by the server.
*
* @param property The property object
* @param rd the revision descriptor containing all properties
* @param resourceKind the kind of the resource to patch.
*/
private boolean checkPropertyModification(PropPatchProperty property, NodeRevisionDescriptor rd, ResourceKind resourceKind) {
boolean result = false;
ViolatedPrecondition violatedPrecondition = getPropertySpecificPreconditionViolation(property);
if (violatedPrecondition != null) {
property.setViolatedPrecondition(violatedPrecondition);
}
else {
NodeProperty originalProperty = rd.getProperty(property.getName(), property.getNamespace());
if (originalProperty == null) {
// computed properties can not be modified
result = (!AbstractResourceKind.isComputedProperty(property.getName()));
}
else {
result = !originalProperty.isProtected();
}
if ( ! result ) {
property.setErrorMessage("Property " + property.getQualifiedNameAsElementString() + " is protected");
}
if ( result && !isSupportedPropertyValue(property, resourceKind) ) {
property.setErrorMessage("Value " + property.getValue() + " is not supported by property " + property.getQualifiedNameAsElementString());
result = false;
}
if (!result) property.setStatusCode(WebdavStatus.SC_CONFLICT);
}
return result;
}
/**
* Return <code>true</code> if the given <code>property</code> value is supported
* for that property of the <code>resourceKind</code>
*
* @param property the property to check.
* @param resourceKind the ResourceKind.
*
* @return <code>true</code> if the value is supported.
*/
private boolean isSupportedPropertyValue(PropPatchProperty property, ResourceKind resourceKind) {
boolean isSupportedValue = true;
if (property.getValue() != null) {
if ( ! resourceKind.isSupportedPropertyValue(property.getName(), property.getValue()) ) {
isSupportedValue = false;
}
if (P_GETCONTENTLANGUAGE.equals(property.getName())) {
StringTokenizer tokenizer = new StringTokenizer(property.getValue(), "-");
String token = null;
while ( isSupportedValue && tokenizer.hasMoreTokens() ) {
token = tokenizer.nextToken();
isSupportedValue = ( (token.length() >= 1) && (token.length() <= 8) );
int i = 0;
while (isSupportedValue && (i < token.length()) ) {
char character = token.charAt(i);
isSupportedValue =
((character >= 'a') && (character <= 'z')) ||
((character >= 'A') && (character <= 'Z'));
++i;
}
}
}
}
return isSupportedValue;
}
/**
* Write the report.
*/
private void writeReport()
throws WebdavException {
Element multistatus = new Element(E_MULTISTATUS, DNSP);
Element response = new Element(E_RESPONSE, DNSP);
multistatus.addContent(response);
Element href = new Element(E_HREF, DNSP);
href.setText(getFullPath(requestUri));
response.addContent(href);
// Parse the two properties list, and printout their status
addPropstatElements(propertiesToSet, response);
addPropstatElements(propertiesToRemove, response);
try {
resp.setContentType(TEXT_XML_UTF_8);
Writer writer = resp.getWriter();
org.jdom.output.Format format = org.jdom.output.Format.getPrettyFormat();
format.setIndent(XML_RESPONSE_INDENT);
new XMLOutputter(format).
output(new Document(multistatus), writer);
writer.flush();
} catch (Exception e) {
int statusCode = WebdavStatus.SC_INTERNAL_SERVER_ERROR;
sendError( statusCode, e );
throw new WebdavException( statusCode );
}
}
/**
* Adds the <code><propstat></code> elements for the given
* <code>properties</code> to the given <code><response></code>
* element.
*
* @param properties the PropPatchProperties for which to add the
* <code><propstat></code> elements.
* @param response the <code><response></code> element to add
* the <code><propstat></code> elements to.
*/
private void addPropstatElements(PropPatchProperties properties, Element response) {
Iterator propertyIterator = properties.iterator();
while(propertyIterator.hasNext()) {
PropPatchProperty property = (PropPatchProperty) propertyIterator.next();
Element propstat = createPropstatElement(property);
response.addContent(propstat);
if (property.getViolatedPrecondition() != null) {
Element responseDescription = new Element(E_RESPONSEDESCRIPTION, DNSP);
responseDescription.addContent(MethodUtil.getPreconditionViolationError(property.getViolatedPrecondition()));
propstat.addContent(responseDescription);
}
else if (property.getErrorMessage() != null) {
Element responseDescription = new Element(E_RESPONSEDESCRIPTION, DNSP);
responseDescription.addContent(property.getErrorMessage());
propstat.addContent(responseDescription);
}
}
}
/**
* Creates a <code><propstat></code> element for the given
* <code>property</code>.
*
* @param property the PropPatchProperty for which to create a
* <code><propstat></code> element.
*
* @return the created <code><propstat></code> element.
*/
private Element createPropstatElement(PropPatchProperty property) {
Element propstat = new Element(E_PROPSTAT, DNSP);
Element prop = new Element(E_PROP, DNSP);
propstat.addContent(prop);
Namespace namespace = Namespace.NO_NAMESPACE;
if (property.getNamespace() != null) {
namespace = NamespaceCache.getNamespace(property.getNamespace());
}
Element propertyElement = new Element(property.getName(), namespace);
prop.addContent(propertyElement);
Element status = new Element(E_STATUS, DNSP);
status.setText("HTTP/1.1 " + property.statusCode + " "
+ WebdavStatus.getStatusText(property.statusCode));
propstat.addContent(status);
return propstat;
}
/**
* Checks the (DeltaV) preconditions
* <ul>
* <li><DAV:cannot-modify-version-controlled-property></li>
* <li><DAV:cannot-modify-version></li>
* <li><DAV:cannot-modify-protected-property></li>
* <li><DAV:supported-live-property></li>
* </ul>
*
* @param revisionDescriptors the NodeRevisionDescriptors of the resource
* to perform the <code>PUT</code> on.
* @param revisionDescriptor the NodeRevisionDescriptor of the resource
* to perform the <code>PUT</code> on.
* @param resourceKind the ResourceKind of the resource.
*
* @return the precondition that has been violated (if any).
*/
private ViolatedPrecondition getPreconditionViolation(NodeRevisionDescriptors revisionDescriptors, NodeRevisionDescriptor revisionDescriptor, ResourceKind resourceKind)
throws ServiceAccessException {
if( Configuration.useVersionControl() ) {
if (resourceKind instanceof CheckedInVersionControlled) {
// check precondition DAV:cannot-modify-version-controlled-property
String autoVersion = versioningHelper.getAutoVersionElementName(revisionDescriptor);
if (autoVersion == null) {
autoVersion = "";
}
if ( !E_CHECKOUT_CHECKIN.equals(autoVersion) &&
!E_CHECKOUT_UNLOCKED_CHECKIN.equals(autoVersion) &&
!E_CHECKOUT.equals(autoVersion) &&
!E_CHECKOUT_IGNORE_UNLOCK.equals(autoVersion) &&
!E_LOCKED_CHECKOUT.equals(autoVersion) ) {
return new ViolatedPrecondition(C_CANNOT_MODIFY_VERSION_CONTROLLED_PROPERTY,
WebdavStatus.SC_FORBIDDEN);
}
if (E_LOCKED_CHECKOUT.equals(autoVersion)) {
if ( !versioningHelper.isWriteLocked(slideToken, revisionDescriptors) ) {
return new ViolatedPrecondition(C_CANNOT_MODIFY_VERSION_CONTROLLED_PROPERTY,
WebdavStatus.SC_FORBIDDEN);
}
}
}
// check precondition DAV:cannot-modify-version
UriHandler uriHandler = UriHandler.getUriHandler(resourcePath);
if (uriHandler.isVersionUri()) {
return new ViolatedPrecondition(C_CANNOT_MODIFY_VERSION,
WebdavStatus.SC_FORBIDDEN);
}
}
return null;
}
/**
* Checks the property specific preconditions
* <ul>
* <li><DAV:cannot-modify-protected-property></li>
* <li><DAV:supported-live-property></li>
* </ul>
*
* @param property the PropPatchProperty to check.
*
* @return the precondition that has been violated (if any,
* otherwise <code>null</code>).
*/
private ViolatedPrecondition getPropertySpecificPreconditionViolation(PropPatchProperty property) {
// check precondition DAV:cannot-modify-protected-property
if ( AbstractResourceKind.isProtectedProperty(property.getName()) &&
DeltavConstants.DELTAV_PROPERTY_LIST.contains(property.getName()) ) {
return new ViolatedPrecondition(C_CANNOT_MODIFY_PROTECTED_PROPERTY,
WebdavStatus.SC_CONFLICT);
}
// check precondition DAV:supported-live-property
// ...is there any property to check here yet ?
return null;
}
/**
* If the given <code>xmlValue</code> contains <code><href></code>
* elements (at any depth), absolute URIs are converted to relative ones.
*
* This method modifies <code>xmlValue</code> (and its children).
*
* @param xmlValue The XMLValue that might contain
* <code><href></code> values to convert.
* @param servletContextPath The prefix which when added to a relative URI
* makes it an absolute one.
* @param config Configuration of the WebDAV servlet.
*/
private static void convertHrefValueToRelativeURL (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;
convertHrefValueToRelativeURL(element, servletContextPath, config);
}
}
}
}
/**
* If the given <code>Element</code> contains <code><href></code>
* elements (at any depth), the absolute URI is converted to a relative
* one.
*
* This method modifies the <code>Element</code> (and its children).
*
* @param element The <code>Element</code> that might contain
* <code><href></code> values to convert.
* @param servletContextPath The prefix which when added to a relative URI
* makes it an absolute one.
* @param config Configuration of the WebDAV servlet.
*/
private static void convertHrefValueToRelativeURL (Element element,
String servletContextPath,
WebdavServletConfig config) {
if (element.getChildren().size() > 0) {
Iterator i = element.getChildren().iterator();
while (i.hasNext()) {
Element child = (Element) i.next();
convertHrefValueToRelativeURL(child, servletContextPath, config);
}
}
if ( E_HREF.equals(element.getName()) && (element.getText() != null) ) {
if ( PropertyHelper.isAbsoluteURL(servletContextPath, element.getText()) ) {
element.setText(element.getText().substring(servletContextPath.length()));
}
}
}
/**
* An extension of the RequestedProperties class manages PropPatchProperty
* instead of RequestedProperty.
*/
public class PropPatchProperties extends RequestedPropertiesImpl {
/**
* Default constructor.
*/
public PropPatchProperties() {
super();
}
/**
* Constructs a List of PropPatchProperty from a <DAV:prop> element.
*
* @param propElement the <DAV:prop> from which to create the
* List of PropPatchProperty.
*
* @throws PropertyParseException if parsing the property fails for any reason.
*/
public PropPatchProperties (Element propElement) throws PropertyParseException {
super(propElement);
}
/**
* Creates a RequestedProperty from the given parameters. This method
* may be overwritten by subclasses in order to create appropriate
* implementations of RequestedProperty.
*
* @param name the name of the propery.
* @param namespacePrefix the namespace prefix of the propery.
* @param namespaceUri the namespace URI of the propery.
* @param text the text of the propery element.
* @param children the children of the propery element.
*
* @return the created RequestedProperty.
*/
protected RequestedProperty createRequestedProperty(String name, String namespacePrefix, String namespaceUri, List content) {
String value = "";
if (content.size() == 1 && content.get(0) instanceof Text) {
value = ((Text)content.get(0)).getText();
}
else if (content.size() > 0) {
XMLValue xmlVal = new XMLValue(content);
if (P_GROUP_MEMBER_SET.equals(name) && S_DAV.equals(namespaceUri)) {
xmlVal.stripServletContext(getSlideContextPath());
}
value = xmlVal.toString();
}
// register prefix/URI at NamespaceCache
NamespaceCache.getNamespace(namespacePrefix, namespaceUri);
return new PropPatchProperty(name, namespaceUri, value);
}
}
/**
* An extension of the RequestedProperty class which supports a property value.
*/
public static class PropPatchProperty extends RequestedPropertyImpl {
/**
* The value of the property.
*/
protected String value = null;
/**
* The status of the PropPatch operation on this property.
*/
protected int statusCode = WebdavStatus.SC_OK;
/**
* The precondition that has been violated when trying to patch this
* property.
*/
protected ViolatedPrecondition violatedPrecondition = null;
/**
* If the code returned by {@link #getStatusCode getStatusCode} is not
* <code>200 (OK)</code> this String provides more details about the error.
*/
protected String errorMessage = null;
/**
* Provides the qualified name of the property as an Element String,
* i.e. if the name of the property is <code>munster</code> with
* the namespace <code>DAV:</code> this String is
* <code><munster xmlns="DAV:" /></code>.
*/
protected String qualifiedNameAsElement = null;
/**
* Constructs a PropPatchProperty using the default namespace as defined
* in NodeProperty.
*
* @param propertyName the name of the property.
*/
public PropPatchProperty (String propertyName) {
super(propertyName);
}
/**
* Constructs a PropPatchProperty.
*
* @param propertyName the name of the property.
* @param namespace the namespace of the property.
*/
public PropPatchProperty (String propertyName, String namespace) {
super(propertyName, namespace);
}
/**
* Constructs a PropPatchProperty.
*
* @param propertyName the name of the property.
* @param namespace the namespace of the property.
* @param value the value of the property.
*/
public PropPatchProperty (String propertyName, String namespace, String value) {
super(propertyName, namespace);
this.value = value;
}
/**
* Returns the value of the property.
*
* @return the value of the property.
*/
public String getValue() {
return value;
}
/**
* Sets the status of the PropPatch operation on this property.
*
* @param statusCode the status code of the PropPatch operation
* on this property.
*/
public void setStatusCode(int statusCode) {
this.statusCode = statusCode;
}
/**
* Returns the status of the PropPatch operation on this property.
*
* @return the status of the PropPatch operation on this property.
*/
public int getStatusCode() {
return statusCode;
}
/**
* Sets the error message of this property.
*
* @param errorMessage the error message.
*
* @see #getErrorMessage
*/
public void setErrorMessage(String errorMessage) {
this.errorMessage = errorMessage;
}
/**
* If the code returned by {@link #getStatusCode getStatusCode} is not
* <code>200 (OK)</code> this String provides more details about the error.
*
* @return the error message.
*/
public String getErrorMessage() {
return errorMessage;
}
/**
* Sets the precondition that has been violated when trying to patch this
* property. If the <code>violatedPrecondition</code> is not <code>null</code>
* the status will be set to those of the ViolatedPrecondition.
*
* @param violatedPrecondition the precondition that has been violated
* when trying to patch this property.
*/
public void setViolatedPrecondition(ViolatedPrecondition violatedPrecondition) {
this.violatedPrecondition = violatedPrecondition;
if (violatedPrecondition != null) {
setStatusCode(violatedPrecondition.getStatusCode());
}
}
/**
* Returns the precondition that has been violated when trying to patch
* this property.
*
* @return the precondition that has been violated when trying to
* patch this property.
*/
public ViolatedPrecondition getViolatedPrecondition() {
return violatedPrecondition;
}
/**
* Provides the qualified name of the property as an Element String,
* i.e. if the name of the property is <code>munster</code> with
* the namespace <code>DAV:</code> this method returns
* <code><munster xmlns="DAV:" /></code>.
*
* @return the qualified name of the property as an Element String
*/
public String getQualifiedNameAsElementString() {
if (qualifiedNameAsElement == null) {
StringBuffer buffer = new StringBuffer();
buffer.append("<");
buffer.append(getName());
if ( (getNamespace() != null) && (getNamespace().length() > 0) ) {
buffer.append(" xmlns=\"");
buffer.append(getNamespace());
buffer.append("\"");
buffer.append(" />");
}
qualifiedNameAsElement = buffer.toString();
}
return qualifiedNameAsElement;
}
/**
* Returns a String representation of this instance.
*
* @return a String representation of this instance.
*/
public String toString() {
return getNamespace()+":"+getName()+"["+getValue()+"]";
}
}
}