I started a discussion about properties with xml-values on users.
Seems I got a patch to do just that.
Just thought I'd send it to the dev list. Maybe somebody finds it
interesting, maybe somebody finds a flaw in the code or the basic
assumptions.
Seems like there were two separate problems:
1. when trying to set the property
WebdavRequestImpl.parsePropPatchRequest
did not recognise a property value as being xml
To patch that without having to patch the jars I created my own
servlet that
instatiates my new implementation of WebdavRequest. (ExariWebdavRequest)
2. on propget the html encoding in the serialisation did some damage
to my
beloved xml. (especially < and > turned into something scary, you know
the
problem)
The fix was to create my own WebdavProperty implementation
(ExariWebdavProperty)
I apologise for the somewhat jingoistic terminology.
There's one snag however. Like I said I tried to keep the patch self
contained but currently I need to patch DavResourceImp.setProperty to
instantiate my property type instead of the default one. Any ideas how
that
could be done better?
Can you find anything that might cause trouble in my code? All my
tests seem
to work fine but I can see my old mate Confirmation Bias lurking
somewhere
in the corner.
Here comes the code.
Feedback and questions are more than welcome
Cheers
Roland
CUT HERE
+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
/*
* Licensed to the Apache Software Foundation (ASF) under one or more
* contributor license agreements. See the NOTICE file distributed with
* this work for additional information regarding copyright ownership.
* The ASF licenses this file to You 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.jackrabbit.webdav.property;
import java.io.IOException;
import java.io.StringReader;
import java.util.List;
import javax.xml.parsers.DocumentBuilderFactory;
import javax.xml.parsers.FactoryConfigurationError;
import javax.xml.parsers.ParserConfigurationException;
import org.apache.jackrabbit.webdav.xml.DomUtil;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.w3c.dom.Document;
import org.w3c.dom.Element;
import org.w3c.dom.Node;
import org.w3c.dom.NodeList;
import org.w3c.dom.Text;
import org.xml.sax.InputSource;
import org.xml.sax.SAXException;
/**
* <code>DefaultDavProperty</code>...
*/
public class ExariWebdavProperty extends AbstractDavProperty {
private static Logger log =
LoggerFactory.getLogger(ExariWebdavProperty.class);
protected Node node = null;
/**
* the value of the property
*/
private final Object value;
protected boolean isXML;
/**
* instantiate a Property from a Node
* if this ctor is called we know that it is a property containing
xml
* @param node
*/
private ExariWebdavProperty(Node node)
{
this(DavPropertyName.createFromXml((Element)node),
node.getNodeValue(), false);
this.node = node; this.isXML = true;
}
/**
* Creates a new WebDAV property with the given
<code>DavPropertyName</code>
* and value. If the property is meant to be protected the
'isProtected'
* flag must be set to true.
*
* @param name the name of the property
* @param value the value of the property
* @param isProtected A value of true, defines this property to be
protected.
* It will not be returned in a [EMAIL PROTECTED]
org.apache.jackrabbit.webdav.DavConstants#PROPFIND_ALL_PROP DAV:allprop}
* PROPFIND request and cannot be set/removed with a PROPPATCH
request.
*/
private ExariWebdavProperty(DavPropertyName name, Object value,
boolean
isProtected) {
super(name, isProtected);
this.value = value;
}
/**
* Creates a new non- protected WebDAV property with the given
* <code>DavPropertyName</code> and value.
*
* @param name the name of the property
* @param value the value of the property
*/
public ExariWebdavProperty(DavPropertyName name, Object value) {
this(name, value, false);
try
{
Document doc =
DocumentBuilderFactory.newInstance().newDocumentBuilder().newDocument();
node = DomUtil.createElement(doc, name.getName(), null);
Node valueNode =
DocumentBuilderFactory.newInstance().newDocumentBuilder().
parse(new InputSource(new
StringReader((String) value))).getFirstChild();
node.appendChild(doc.importNode(valueNode, true));
isXML = true;
} catch (SAXException e)
{
//this is quite ugly; we're using the exception to
determine if the content is xml
//the exeption produces consoleoutput
isXML= false;
} catch (IOException e)
{
e.printStackTrace();
} catch (ParserConfigurationException e)
{
e.printStackTrace();
} catch (FactoryConfigurationError e)
{
e.printStackTrace();
}
if (log.isDebugEnabled()) log.debug("created: name=" +
name.getName() + ", value=" + value + ", isXML=" + isXML);
}
/**
* from AbstractDavProperty
* @return the value of this property
*/
public Object getValue() {
return value;
}
/**
* Create a new <code>DefaultDavProperty</code> instance from the
given
Xml
* element. Name and namespace of the element are building the [EMAIL
PROTECTED]
DavPropertyName},
* while the element's content forms the property value. The
following
logic
* is applied:
* <pre>
* - empty Element -> <code>null</code> value
* - single Text content -> <code>String</code> value
* - single non-Text content -> Element.getContent(0) is used as
value
* - other: List obtained from Element.getContent() is used as value
* </pre>
*
* @param propertyElement
* @return
*/
public static ExariWebdavProperty createFromXml(Element
propertyElement)
{
if (propertyElement == null) {
throw new IllegalArgumentException("Cannot create a new
DavProperty from a 'null' element.");
}
DavPropertyName name =
DavPropertyName.createFromXml(propertyElement);
Object value;
if (!DomUtil.hasContent(propertyElement)) {
value = null;
} else {
List c = DomUtil.getContent(propertyElement);
value = getXmlPropertyValue((Node)c.get(0));
}
return new ExariWebdavProperty(name, value, false);
}
private static Object getXmlPropertyValue(Node node)
{
if (node.getNodeName().equals("#text"))
{
return node.getNodeValue();
}
else
{
return new ExariWebdavProperty(node);
}
}
public Element toXml(Document document)
{
if (isXML)
{
return (Element) document.importNode(node, true);
}
else
{
Element property =
document.createElement(getName().getName());
Text propValue =
document.createTextNode((String)value);
property.appendChild(propValue);
return property;
}
}
public String toString()
{
return toXMLString(node);
}
private String toXMLString(Node node)
{
String result = "";
NodeList kids = node.getChildNodes();
if (node.getNodeName().equals("#text"))
{
result = result + node.getNodeValue();
}
else
{
result = result + "<" + node.getNodeName() + ">";
for (int kidCount=0; kidCount<kids.getLength();
kidCount++)
{
result = result +
toXMLString(kids.item(kidCount));
}
result = result + "</" + node.getNodeName() + ">";
}
return result;
}
}