jackrabbit-dev mailing list archives

Site index · List index
Message view « Date » · « Thread »
Top « Date » · « Thread »
From "Roland Porath" <rol...@exari.com>
Subject RE: properties with XML-Values; patch
Date Wed, 20 Feb 2008 00:35:42 GMT


> -----Original Message-----
> From: Julian Reschke [mailto:julian.reschke@gmx.de]
> Sent: Tuesday, 19 February 2008 8:58 PM
> To: dev@jackrabbit.apache.org
> Subject: Re: properties with XML-Values; patch
> 
> Hm,
> 
> the code contains some ugly parts, I have to say.

Agree with that. Looking for a better way
> 
> I'm not sure how exactly this is supposed to work, because JCR doesn't
> have an XML property type. Are you trying to map this to child nodes, or
> are you trying to persist this as a JCR string property?

You have to realise there's two issues here:
1. persisting a property that has a string containing XML as a value;
Try 
propset someresource xmlProperty
<propValue><subValue>valueOfSubValue1</subValue><subValue>valueOfSubValue2</
subValue></propValue>
in cadaver then do propget; it will look like this:
xmlProperty = [propValue: null]
so any xml string in a prop value is set to the value of [propValue: null];
I'd say this is a bug in jackrabbit or to be more specific in
WebdavRequestImpl.parsePropPatchRequest() irrespective of jackrabbit having
the concept of XML properties.

2. after patching WebdavRequestImpl I was able to persist a string
containing xml.
A propget request results in a response looking somewhat like this:
Someresponsestuff .....&lt;propvalue&gt;.....somemoreresponsestuff ONLY for
properties I added. Derived properties like supportedlock were not html
encoded but plain xml
Someresponsestuff .....<lockEntry><lockscope>.... somemoreresponsestuff
This happens in the serialisation.
Now what the client makes of this is an entirely different matter; cadaver
does not care, Dav Explorer interprets plain xml as xml and encoded xml as a
plain vanilla string. I don't know who's right but most of our clients use
Dav Explorer so I gotta make it work.

Methinks the heart of the matter is that jackrabbit is a bit confused as to
what to do with XML; on the one hand you say it has no concept of xml
properties which is fair enough. On the other hand it quite clearly has when
it comes to derived properties.

Sorry bout being a bit unclear in the first post, I just thought the code
said it all;
Hope this clears matters up a bit

Cheers
roland
> 
> BR, Julian
> 
> 
> 
> Angela Schreiber wrote:
> > hi roland
> >
> > are you sure, it's not simply a bug in the dav-library?
> >
> > assuming your client sends a valid and well-formed
> > PROPPATCH body, i'd say that it should simply work
> > without you having to create patches. and if it doesn't
> > there might something wrong in the library.
> >
> > that's what i would prefer to know first.
> > am i missing something?
> > angela
> >
> > Roland Porath wrote:
> >> 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 {@link
> >> 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
> {@link
> >> DavPropertyName},
> >>      * while the element's content forms the property value. The
> >> following
> >> logic
> >>      * is applied:
> >>      * <pre>
> >>      * - empty Element           -&gt; <code>null</code> value
> >>      * - single Text content     -&gt; <code>String</code> value
> >>      * - single non-Text content -&gt; 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;
> >>     }
> >> }
> >>
> >>
> >>
> >>
> >>
> >>
> >
> 
> 
> !DSPAM:47baa849130921899120660!



Mime
View raw message