You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@archiva.apache.org by br...@apache.org on 2008/03/13 19:28:50 UTC

svn commit: r636822 [4/9] - in /maven/archiva/branches/springy: ./ archiva-base/archiva-common/ archiva-base/archiva-consumers/archiva-database-consumers/src/test/java/org/apache/maven/archiva/consumers/database/ archiva-base/archiva-consumers/archiva-...

Added: maven/archiva/branches/springy/archiva-web/archiva-webdav/src/main/java/it/could/util/location/Parameters.java
URL: http://svn.apache.org/viewvc/maven/archiva/branches/springy/archiva-web/archiva-webdav/src/main/java/it/could/util/location/Parameters.java?rev=636822&view=auto
==============================================================================
--- maven/archiva/branches/springy/archiva-web/archiva-webdav/src/main/java/it/could/util/location/Parameters.java (added)
+++ maven/archiva/branches/springy/archiva-web/archiva-webdav/src/main/java/it/could/util/location/Parameters.java Thu Mar 13 11:28:26 2008
@@ -0,0 +1,474 @@
+/* ========================================================================== *
+ *         Copyright (C) 2004-2006, Pier Fumagalli <http://could.it/>         *
+ *                            All rights reserved.                            *
+ * ========================================================================== *
+ *                                                                            *
+ * 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 it.could.util.location;
+
+import it.could.util.StringTools;
+import it.could.util.encoding.Encodable;
+import it.could.util.encoding.EncodingTools;
+
+import java.io.UnsupportedEncodingException;
+import java.util.AbstractList;
+import java.util.ArrayList;
+import java.util.Collections;
+import java.util.HashMap;
+import java.util.Iterator;
+import java.util.List;
+import java.util.Map;
+import java.util.Set;
+
+
+/**
+ * <p>The {@link Parameters Parameters} class represents a never empty and
+ * immutable {@link List} of {@link Parameters.Parameter Parameter} instances,
+ * normally created parsing a query string.</p>
+ *
+ * @author <a href="http://could.it/">Pier Fumagalli</a>
+ */
+public class Parameters extends AbstractList implements Encodable {
+
+    /** <p>The default delimiter for a {@link Parameters} instance.</p> */
+    public static final char DEFAULT_DELIMITER = '&';
+
+    /** <p>All the {@link Parameter}s in order.</p> */
+    private final Parameter parameters[];
+    /** <p>The {@link Map} view over all parameters (names are keys).</p> */
+    private final Map map;
+    /** <p>The {@link Set} of all parameter names.</p> */
+    final Set names;
+    /** <p>The character delimiting different parameters.</p> */
+    private final char delimiter;
+    /** <p>The encoded {@link String} representation of this.</p> */
+    private final String string;
+
+    /**
+     * <p>Create a new {@link Parameters Parameters} instance from
+     * a {@link List} of {@link Parameters.Parameter Parameter} instances
+     * using the {@link #DEFAULT_DELIMITER default parameter delimiter}.</p>
+     * 
+     * @throws NullPointerExceptoin if the {@link List} was <b>null</b>.
+     * @throws IllegalArgumentException if the {@link List} was empty.
+     * @throws ClassCastException if any of the elements in the {@link List} was
+     *                            not a {@link Parameters.Parameter Parameter}.
+     */
+    public Parameters(List parameters) {
+        this(parameters, DEFAULT_DELIMITER);
+    }
+
+    /**
+     * <p>Create a new {@link Parameters Parameters} instance from
+     * a {@link List} of {@link Parameters.Parameter Parameter} instances
+     * using the specified character as the parameters delimiter.</p>
+     * 
+     * @throws NullPointerExceptoin if the {@link List} was <b>null</b>.
+     * @throws IllegalArgumentException if the {@link List} was empty.
+     * @throws ClassCastException if any of the elements in the {@link List} was
+     *                            not a {@link Parameters.Parameter Parameter}.
+     */
+    public Parameters(List parameters, char delimiter) {
+        if (parameters.size() == 0) throw new IllegalArgumentException();
+        final Parameter array[] = new Parameter[parameters.size()];
+        final Map map = new HashMap();
+        for (int x = 0; x < array.length; x ++) {
+            final Parameter parameter = (Parameter) parameters.get(x);
+            final String key = parameter.getName();
+            List values = (List) map.get(key);
+            if (values == null) {
+                values = new ArrayList();
+                map.put(key, values);
+            }
+            values.add(parameter.getValue());
+            array[x] = parameter;
+        }
+
+        /* Make all parameter value lists unmodifiable */
+        for (Iterator iter = map.entrySet().iterator(); iter.hasNext(); ) {
+            final Map.Entry entry = (Map.Entry) iter.next();
+            final List list = (List) entry.getValue();
+            entry.setValue(Collections.unmodifiableList(list));
+        }
+
+        /* Store the current values */
+        this.delimiter = delimiter;
+        this.map = Collections.unmodifiableMap(map);
+        this.names = Collections.unmodifiableSet(map.keySet());
+        this.parameters = array;
+        this.string = EncodingTools.toString(this);
+    }
+
+    /* ====================================================================== */
+    /* STATIC CONSTRUCTION METHODS                                            */
+    /* ====================================================================== */
+
+    /**
+     * <p>Utility method to create a new {@link Parameters} instance from a
+     * {@link List} of {@link Parameters.Parameter Parameter} instances.</p>
+     *
+     * @return a <b>non-null</b> and not empty {@link Parameters} instance or
+     *         <b>null</b> if the specified {@link List} was <b>null</b>, empty
+     *         or did not contain any {@link Parameters.Parameter Parameter}.
+     * @throws ClassCastException if any of the elements in the {@link List} was
+     *                            not a {@link Parameters.Parameter Parameter}.
+     */
+    public static Parameters create(List parameters) {
+        return create(parameters, DEFAULT_DELIMITER);
+    }
+
+    /**
+     * <p>Utility method to create a new {@link Parameters} instance from a
+     * {@link List} of {@link Parameters.Parameter Parameter} instances.</p>
+     *
+     * @return a <b>non-null</b> and not empty {@link Parameters} instance or
+     *         <b>null</b> if the specified {@link List} was <b>null</b>, empty
+     *         or did not contain any {@link Parameters.Parameter Parameter}.
+     * @throws ClassCastException if any of the elements in the {@link List} was
+     *                            not a {@link Parameters.Parameter Parameter}.
+     */
+    public static Parameters create(List parameters, char delimiter) {
+        if (parameters == null) return null;
+        final List dedupes = new ArrayList();
+        for (Iterator iter = parameters.iterator(); iter.hasNext(); ) {
+            Object next = iter.next();
+            if (dedupes.contains(next)) continue;
+            dedupes.add(next);
+        }
+        if (dedupes.size() == 0) return null;
+        return new Parameters(dedupes, delimiter);
+    }
+
+    /**
+     * <p>Parse the specified parameters {@link String} into a
+     * {@link Parameters} instance using the {@link #DEFAULT_DELIMITER default
+     * parameter delimiter}.</p>
+     *
+     * @return a <b>non-null</b> and not empty {@link Parameters} instance or
+     *         <b>null</b> if the specified string was <b>null</b>, empty or
+     *         did not contain any {@link Parameters.Parameter Parameter}.
+     */
+    public static Parameters parse(String parameters) {
+        try {
+            return parse(parameters, DEFAULT_DELIMITER, DEFAULT_ENCODING);
+        } catch (UnsupportedEncodingException exception) {
+            final String message = "Unsupported encoding " + DEFAULT_ENCODING;
+            final InternalError error = new InternalError(message);
+            throw (InternalError) error.initCause(exception);
+        }
+    }
+
+    /**
+     * <p>Parse the specified parameters {@link String} into a
+     * {@link Parameters} instance using the specified character as the
+     * parameters delimiter.</p>
+     *
+     * @return a <b>non-null</b> and not empty {@link Parameters} instance or
+     *         <b>null</b> if the specified string was <b>null</b>, empty or
+     *         did not contain any {@link Parameters.Parameter Parameter}.
+     */
+    public static Parameters parse(String parameters, char delimiter) {
+        try {
+            return parse(parameters, delimiter, DEFAULT_ENCODING);
+        } catch (UnsupportedEncodingException exception) {
+            final String message = "Unsupported encoding " + DEFAULT_ENCODING;
+            final InternalError error = new InternalError(message);
+            throw (InternalError) error.initCause(exception);
+        }
+    }
+
+    /**
+     * <p>Parse the specified parameters {@link String} into a
+     * {@link Parameters} instance using the {@link #DEFAULT_DELIMITER default
+     * parameter delimiter}.</p>
+     *
+     * @return a <b>non-null</b> and not empty {@link Parameters} instance or
+     *         <b>null</b> if the specified string was <b>null</b>, empty or
+     *         did not contain any {@link Parameters.Parameter Parameter}.
+     */
+    public static Parameters parse(String parameters, String encoding)
+    throws UnsupportedEncodingException {
+        return parse(parameters, DEFAULT_DELIMITER, encoding);
+    }
+
+    /**
+     * <p>Parse the specified parameters {@link String} into a
+     * {@link Parameters} instance using the specified character as the
+     * parameters delimiter.</p>
+     *
+     * @return a <b>non-null</b> and not empty {@link Parameters} instance or
+     *         <b>null</b> if the specified string was <b>null</b>, empty or
+     *         did not contain any {@link Parameters.Parameter Parameter}.
+     */
+    public static Parameters parse(String parameters, char delimiter,
+                                   String encoding)
+    throws UnsupportedEncodingException {
+        if (parameters == null) return null;
+        if (parameters.length() == 0) return null;
+        if (encoding == null) encoding = DEFAULT_ENCODING;
+        final String split[] = StringTools.splitAll(parameters, delimiter);
+        final List list = new ArrayList();
+        for (int x = 0; x < split.length; x ++) {
+            if (split[x] == null) continue;
+            if (split[x].length() == 0) continue;
+            Parameter parameter = Parameter.parse(split[x], encoding);
+            if (parameter != null) list.add(parameter); 
+        }
+        if (list.size() == 0) return null;
+        return new Parameters(list, delimiter);
+    }
+
+    /* ====================================================================== */
+    /* PUBLIC EXPOSED METHODS                                                 */
+    /* ====================================================================== */
+
+    /**
+     * <p>Return the number of {@link Parameters.Parameter Parameter}s
+     * contained by this instance.</p>
+     */
+    public int size() {
+        return this.parameters.length;
+    }
+
+    /**
+     * <p>Return the {@link Parameters.Parameter Parameter} stored by this\
+     * instance at the specified index.</p>
+     */
+    public Object get(int index) {
+        return this.parameters[index];
+    }
+    
+    /**
+     * <p>Return an immutable {@link Set} of {@link String}s containing all
+     * known {@link Parameters.Parameter Parameter}
+     * {@link Parameters.Parameter#getName() names}.</p>
+     */
+    public Set getNames() {
+        return this.names;
+    }
+
+    /**
+     * <p>Return the first {@link String} value associated with the
+     * specified parameter name, or <b>null</b>.</p> 
+     */
+    public String getValue(String name) {
+        final List values = (List) this.map.get(name);
+        return values == null ? null : (String) values.get(0);
+    }
+
+    /**
+     * <p>Return an immutable {@link List} of all {@link String} values
+     * associated with the specified parameter name, or <b>null</b>.</p> 
+     */
+    public List getValues(String name) {
+        return (List) this.map.get(name);
+    }
+
+    /* ====================================================================== */
+    /* OBJECT METHODS                                                         */
+    /* ====================================================================== */
+
+    /**
+     * <p>Return the URL-encoded {@link String} representation of this
+     * {@link Parameters Parameters} instance.</p>
+     */
+    public String toString() {
+        return this.string;
+    }
+
+    /**
+     * <p>Return the URL-encoded {@link String} representation of this
+     * {@link Parameters Parameters} instance using the specified
+     * character encoding.</p>
+     */
+    public String toString(String encoding)
+    throws UnsupportedEncodingException {
+        StringBuffer buffer = new StringBuffer();
+        for (int x = 0; x < this.parameters.length; x ++) {
+            buffer.append(this.delimiter);
+            buffer.append(this.parameters[x].toString(encoding));
+        }
+        return buffer.substring(1);
+    }
+
+    /**
+     * <p>Return the hash code value of this
+     * {@link Parameters Parameters} instance.</p>
+     */
+    public int hashCode() {
+        return this.string.hashCode();
+    }
+
+    /**
+     * <p>Check if the specified {@link Object} is equal to this
+     * {@link Parameters Parameters} instance.</p>
+     * 
+     * <p>The specified {@link Object} is considered equal to this one if
+     * it is <b>non-null</b>, it is a {@link Parameters Parameters}
+     * instance, and its {@link #toString() string representation} equals
+     * this one's.</p>
+     */
+    public boolean equals(Object object) {
+        if ((object != null) && (object instanceof Parameters)) {
+            return this.string.equals(((Parameters) object).string);
+        } else {
+            return false;
+        }
+    }
+
+    /* ====================================================================== */
+    /* PUBLIC INNER CLASSES                                                   */
+    /* ====================================================================== */
+
+    /**
+     * <p>The {@link Parameters.Parameter Parameter} class represents a single
+     * parameter either parsed from a query string or a path element.</p>
+     * 
+     * @author <a href="http://could.it/">Pier Fumagalli</a>
+     */
+    public static class Parameter implements Encodable {
+        /** <p>The name of the parameter (decoded).</p> */
+        private final String name;
+        /** <p>The value of the parameter (decoded).</p> */
+        private final String value;
+        /** <p>The encoded {@link String} representation of this.</p> */
+        private final String string;
+
+        /**
+         * <p>Create a new {@link Parameters.Parameter Parameter} given an
+         * encoded parameter name and value.</p>
+         * 
+         * @throws NullPointerException if the name was <b>null</b>.
+         * @throws IllegalArgumentException if the name was an empty string.
+         */
+        public Parameter(String name, String value) {
+            if (name == null) throw new NullPointerException();
+            if (name.length() == 0) throw new IllegalArgumentException();
+            this.name = name;
+            this.value = value;
+            this.string = EncodingTools.toString(this);
+        }
+
+        /* ================================================================== */
+        /* STATIC CONSTRUCTION METHODS                                        */
+        /* ================================================================== */
+
+        /**
+         * <p>Parse the specified parameters {@link String} into a
+         * {@link Parameters.Parameter} instance.</p>
+         *
+         * @return a <b>non-null</b> and not empty {@link Parameters.Parameter}
+         *         instance or <b>null</b> if the specified string was
+         *         <b>null</b> or empty.
+         */
+        public static Parameter parse(String parameter)
+        throws UnsupportedEncodingException {
+            try {
+                return parse(parameter, DEFAULT_ENCODING);
+            } catch (UnsupportedEncodingException exception) {
+                final String message = "Unsupported encoding " + DEFAULT_ENCODING;
+                final InternalError error = new InternalError(message);
+                throw (InternalError) error.initCause(exception);
+            }
+        }
+
+        /**
+         * <p>Parse the specified parameters {@link String} into a
+         * {@link Parameters.Parameter} instance.</p>
+         *
+         * @return a <b>non-null</b> and not empty {@link Parameters.Parameter}
+         *         instance or <b>null</b> if the specified string was
+         *         <b>null</b> or empty.
+         */
+        public static Parameter parse(String parameter, String encoding)
+        throws UnsupportedEncodingException {
+            if (parameter == null) return null;
+            if (encoding == null) encoding = DEFAULT_ENCODING;
+            String split[] = StringTools.splitOnce(parameter, '=', false);
+            if (split[0] == null) return null;
+            return new Parameter(split[0], split[1]);
+        }
+
+        /* ================================================================== */
+        /* PUBLIC EXPOSED METHODS                                             */
+        /* ================================================================== */
+
+        /**
+         * <p>Return the URL-decoded name of this
+         * {@link Parameters.Parameter Parameter} instance.</p>
+         */
+        public String getName() {
+            return this.name;
+        }
+    
+        /**
+         * <p>Return the URL-decoded value of this
+         * {@link Parameters.Parameter Parameter} instance.</p>
+         */
+        public String getValue() {
+            return this.value;
+        }
+    
+        /* ================================================================== */
+        /* OBJECT METHODS                                                     */
+        /* ================================================================== */
+
+        /**
+         * <p>Return the URL-encoded {@link String} representation of this
+         * {@link Parameters.Parameter Parameter} instance.</p>
+         */
+        public String toString() {
+            return this.string;
+        }
+    
+        /**
+         * <p>Return the URL-encoded {@link String} representation of this
+         * {@link Parameters.Parameter Parameter} instance using the specified
+         * character encoding.</p>
+         */
+        public String toString(String encoding)
+        throws UnsupportedEncodingException {
+            if (this.value != null) {
+                return EncodingTools.urlEncode(this.name, encoding) + "=" +
+                       EncodingTools.urlEncode(this.value, encoding);
+            } else {
+                return EncodingTools.urlEncode(this.name, encoding);
+            }
+        }
+
+        /**
+         * <p>Return the hash code value for this
+         * {@link Parameters.Parameter Parameter} instance.</p>
+         */
+        public int hashCode() {
+            return this.string.hashCode();
+        }
+    
+        /**
+         * <p>Check if the specified {@link Object} is equal to this
+         * {@link Parameters.Parameter Parameter} instance.</p>
+         * 
+         * <p>The specified {@link Object} is considered equal to this one if
+         * it is <b>non-null</b>, it is a {@link Parameters.Parameter Parameter}
+         * instance, and its {@link #toString() string representation} equals
+         * this one's.</p>
+         */
+        public boolean equals(Object object) {
+            if ((object != null) && (object instanceof Parameter)) {
+                return this.string.equals(((Parameter) object).string);
+            } else {
+                return false;
+            }
+        }
+    }
+}
\ No newline at end of file

Propchange: maven/archiva/branches/springy/archiva-web/archiva-webdav/src/main/java/it/could/util/location/Parameters.java
------------------------------------------------------------------------------
    svn:eol-style = native

Added: maven/archiva/branches/springy/archiva-web/archiva-webdav/src/main/java/it/could/util/location/Path.java
URL: http://svn.apache.org/viewvc/maven/archiva/branches/springy/archiva-web/archiva-webdav/src/main/java/it/could/util/location/Path.java?rev=636822&view=auto
==============================================================================
--- maven/archiva/branches/springy/archiva-web/archiva-webdav/src/main/java/it/could/util/location/Path.java (added)
+++ maven/archiva/branches/springy/archiva-web/archiva-webdav/src/main/java/it/could/util/location/Path.java Thu Mar 13 11:28:26 2008
@@ -0,0 +1,559 @@
+/* ========================================================================== *
+ *         Copyright (C) 2004-2006, Pier Fumagalli <http://could.it/>         *
+ *                            All rights reserved.                            *
+ * ========================================================================== *
+ *                                                                            *
+ * 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 it.could.util.location;
+
+import it.could.util.StringTools;
+import it.could.util.encoding.Encodable;
+import it.could.util.encoding.EncodingTools;
+
+import java.io.UnsupportedEncodingException;
+import java.util.AbstractList;
+import java.util.ArrayList;
+import java.util.Iterator;
+import java.util.List;
+import java.util.Stack;
+
+
+/**
+ * <p>The {@link Path Path} class is an ordered collection of
+ * {@link Path.Element Element} instances representing a path
+ * structure.</p>
+ *
+ * @author <a href="http://could.it/">Pier Fumagalli</a>
+ */
+public class Path extends AbstractList implements Encodable {
+
+    /** <p>The array of {@link Path.Element Element}s.</p> */ 
+    private final Element paths[];
+    /** <p>The current {@link Parameters} instance or <b>null</b>.</p> */
+    private final Parameters parameters;
+    /** <p>A flag indicating whether this path is absolute or not.</p> */
+    private final boolean absolute;
+    /** <p>A flag indicating if this path is a collection or not.</p> */
+    private final boolean collection;
+    /** <p>The {@link String} representation of this (encoded).</p> */
+    private final String string;
+
+    /**
+     * <p>Create a new {@link Path Path} instance.</p>
+     * 
+     * @throws ClassCastException if any of the elements in the {@link List}
+     *                            was not a {@link Path.Element Element}.
+     */
+    public Path(List elements, boolean absolute, boolean collection) {
+        this(elements, absolute, collection, null);
+    }
+
+    /**
+     * <p>Create a new {@link Path Path} instance.</p>
+     * 
+     * @throws ClassCastException if any of the elements in the {@link List}
+     *                            was not a {@link Path.Element Element}.
+     */
+    public Path(List elements, boolean absolute, boolean collection,
+                Parameters parameters) {
+        final Stack resolved = resolve(null, absolute, elements);
+        final Element array[] = new Element[resolved.size()];
+        this.paths = (Element []) resolved.toArray(array);
+        this.parameters = parameters;
+        this.absolute = absolute;
+        this.collection = collection;
+        this.string = EncodingTools.toString(this);
+    }
+
+    /* ====================================================================== */
+    /* STATIC CONSTRUCTION METHODS                                            */
+    /* ====================================================================== */
+
+    /**
+     * <p>Parse the specified {@link String} into a {@link Path} structure.</p>
+     */
+    public static Path parse(String path) {
+        try {
+            return parse(path, DEFAULT_ENCODING);
+        } catch (UnsupportedEncodingException exception) {
+            final String message = "Unsupported encoding " + DEFAULT_ENCODING;
+            final InternalError error = new InternalError(message);
+            throw (InternalError) error.initCause(exception);
+        }
+    }
+
+    /**
+     * <p>Parse the specified {@link String} into a {@link Path} structure.</p>
+     */
+    public static Path parse(String path, String encoding)
+    throws UnsupportedEncodingException {
+        final List params = new ArrayList();
+        final List elems = new ArrayList();
+        
+        /* No path, flog it! */
+        if ((path == null) || (path.length() == 0)) {
+            return new Path(elems, false, false, null);
+        }
+        
+        /* Check for a proper encoding */
+        if (encoding == null) encoding = DEFAULT_ENCODING;
+
+        /* Split up the path structure into its path element components */
+        final String split[] = StringTools.splitAll(path, '/');
+
+        /* Check if this path is an absolute path */
+        final boolean absolute = path.charAt(0) == '/';
+
+        /* Check every single path element and append it to the current one */
+        Element element = null;
+        for (int x = 0; x < split.length; x++) {
+            if (split[x] == null) continue; /* Collapse double slashes */
+            element = parsePath(split[x], params, encoding); 
+            if (element != null) elems.add(element);
+        }
+
+        /* Check if this is a collection */
+        final boolean collection =  ((split[split.length - 1] == null)
+                                    || (element == null)
+                                    || element.getName().equals(".")
+                                    || element.getName().equals(".."));
+
+        /* Setup the last path in our chain and return the first one */
+        final Parameters parameters = Parameters.create(params, ';');
+        return new Path(elems, absolute, collection, parameters);
+    }
+
+    /* ====================================================================== */
+
+    /**
+     * <p>Parse a single path element like <code>path!extra;param</code>.</p>
+     */
+    private static Element parsePath(String path, List parameters,
+                                     String encoding)
+    throws UnsupportedEncodingException {
+        final int pathEnds = StringTools.findFirst(path, "!;");
+        final Element element;
+
+        if (pathEnds < 0) {
+            element = new Element(EncodingTools.urlDecode(path, encoding), null);
+        } else if (path.charAt(pathEnds) == ';') {
+            // --> pathname;pathparameter
+            final String name = path.substring(0, pathEnds);
+            final String param = path.substring(pathEnds + 1);
+            final Parameters params = Parameters.parse(param, ';', encoding);
+            if (params != null) parameters.addAll(params);
+            element = new Element(EncodingTools.urlDecode(name, encoding), null);
+        } else {
+            // --> pathname!extra...
+            final String name = path.substring(0, pathEnds);
+            final String more = path.substring(pathEnds + 1);
+            final String split[] = StringTools.splitOnce(more, ';', false);
+            final Parameters params = Parameters.parse(split[1], ';', encoding);
+            if (params != null) parameters.addAll(params);
+            element = new Element(EncodingTools.urlDecode(name, encoding),
+                                  EncodingTools.urlDecode(split[0], encoding));
+        }
+        if (element.toString().length() == 0) return null;
+        return element;
+    }
+
+    /* ====================================================================== */
+    /* RESOLUTION METHODS                                                     */
+    /* ====================================================================== */
+
+    /**
+     * <p>Resolve the specified {@link Path} against this one.</p>
+     */
+    public Path resolve(Path path) {
+        /* Merge the parameters */
+        final List params = new ArrayList();
+        if (this.parameters != null) params.addAll(this.parameters);
+        if (path.parameters != null) params.addAll(path.parameters);
+        final Parameters parameters = Parameters.create(params, ';');
+
+        /* No path, return this instance */
+        if (path == null) return this;
+
+        /* If the target is absolute, only merge the parameters */ 
+        if (path.absolute)
+            return new Path(path, true, path.collection, parameters);
+
+        /* Resolve the path */
+        final Stack source = new Stack();
+        source.addAll(this);
+        if (! this.collection && (source.size() > 0)) source.pop();
+        final List resolved = resolve(source, this.absolute, path);
+
+        /* Figure out if the resolved path is a collection and return it */
+        final boolean c = path.size() == 0 ? this.collection : path.collection;
+        return new Path(resolved, this.absolute, c, parameters);
+    }
+
+    /**
+     * <p>Parse the specified {@link String} into a {@link Path} and resolve it
+     * against this one.</p>
+     */
+    public Path resolve(String path) {
+        try {
+            return this.resolve(parse(path, DEFAULT_ENCODING));
+        } catch (UnsupportedEncodingException exception) {
+            final String message = "Unsupported encoding " + DEFAULT_ENCODING;
+            final InternalError error = new InternalError(message);
+            throw (InternalError) error.initCause(exception);
+        }
+    }
+
+    /**
+     * <p>Parse the specified {@link String} into a {@link Path} and resolve it
+     * against this one.</p>
+     * 
+     * @throws NullPointerException if the path {@link String} was <b>null</b>.
+     */
+    public Path resolve(String path, String encoding)
+    throws UnsupportedEncodingException {
+        if (encoding == null) encoding = DEFAULT_ENCODING;
+        if (path == null) return this;
+        return this.resolve(parse(path, encoding));
+    }
+
+    /* ====================================================================== */
+    
+    private static Stack resolve(Stack stack, boolean absolute, List elements) {
+        /* If we have no source stack we create a new empty one */
+        if (stack == null) stack = new Stack();
+        /* A flag indicating whether we are at the "root" path element. */
+        boolean atroot = absolute && stack.empty();
+        /* Iterate through the current path elements to see what to do. */
+        for (Iterator iter = elements.iterator(); iter.hasNext(); ) {
+            final Element element = (Element) iter.next();
+            /* If this is the "." (current) path element, skip it. */
+            if (".".equals(element.getName())) continue;
+            /* If this is the ".." (parent) path element, it gets nasty. */
+            if ("..".equals(element.getName())) {
+                /* The root path's parent is always itself */
+                if (atroot) continue;
+                /* We're not at root and have the stack, relative ".." */
+                if (stack.size() == 0) {
+                    stack.push(element);
+                /* We're not at root, but we have stuff in the stack */
+                } else {
+                    /* Get the last element in the stack */
+                    final Element prev = (Element) stack.peek();
+                    /* If the last element is "..", add another one */
+                    if ("..".equals(prev.getName())) stack.push(element);
+                    /* The last element was not "..", pop it out */
+                    else stack.pop();
+                    /* If absoulte and stack is empty, we're at root */
+                    if (absolute) atroot = stack.size() == 0;
+                }
+            } else {
+                /* Normal element processing follows... */
+                stack.push(element);
+                atroot = false;
+            }
+        }
+        return stack;
+    }
+
+    /* ====================================================================== */
+    /* RELATIVIZATION METHODS                                                 */
+    /* ====================================================================== */
+    
+    /**
+     * <p>Parse the specified {@link String} into a {@link Path} and relativize
+     * it against this one.</p>
+     */
+    public Path relativize(String path) {
+        try {
+            return this.relativize(parse(path, DEFAULT_ENCODING));
+        } catch (UnsupportedEncodingException exception) {
+            final String message = "Unsupported encoding " + DEFAULT_ENCODING;
+            final InternalError error = new InternalError(message);
+            throw (InternalError) error.initCause(exception);
+        }
+    }
+
+    /**
+     * <p>Parse the specified {@link String} into a {@link Path} and relativize
+     * it against this one.</p>
+     */
+    public Path relativize(String path, String encoding)
+    throws UnsupportedEncodingException {
+        if (encoding == null) encoding = DEFAULT_ENCODING;
+        return this.relativize(parse(path, encoding));
+    }
+
+    /**
+     * <p>Retrieve the relativization path from this {@link Path} to the
+     * specified {@link Path}.</p>
+     */
+    public Path relativize(Path path) {
+        /* No matter what, always return the aggregate of all parameters */
+        final List parameters = new ArrayList();
+        if (this.parameters != null) parameters.addAll(this.parameters);
+        if (path.parameters != null) parameters.addAll(path.parameters);
+        final Parameters params = Parameters.create(parameters, ';');
+
+        /* We are absolute and the specified path is absolute, we process */
+        if ((path.absolute) && (this.absolute)) {
+            /* Find the max number of paths we should examine */
+            final int num  = this.collection ? this.size() : this.size() - 1;
+
+            /* Process the two absolute paths to check common elements */
+            int skip = 0;
+            for (int x = 0; (x < num) && (x < path.size()); x ++) {
+                if (path.paths[x].equals(this.paths[x])) skip ++;
+                else break;
+            }
+
+            /* Figure out if the resulting path is a collection */
+            final boolean collection;
+            if (path.size() > skip) collection = path.collection;
+            else if (this.size() > skip) collection = true;
+            else collection = this.collection;
+
+            /* Recreate the path to return by adding ".." and the paths */
+            final List elems = new ArrayList();
+            for (int x = skip; x < num; x ++) elems.add(new Element("..", null));
+            elems.addAll(path.subList(skip, path.size()));
+            return new Path(elems, false, collection);
+        }
+
+        /*
+         * Here we are in one of the following cases:
+         * - the specified path is already relative, so why bother?
+         * - we are relative and the specified path is absolute: in this case
+         *   we can't possibly know how far away we are located from the root
+         *   so, we only have one option, to return the absolute path.
+         * In all cases, though, before returning the specified path, we just
+         * merge ours and the path's parameters. 
+         */
+        if (this.absolute && (! path.absolute)) {
+            /*
+             * Ok, let's bother, we're absolute and the specified is not. This
+             * means that if we resolve the path, we can find another absolute
+             * path, and therefore we can do a better job at relativizin it.
+             */
+            return this.relativize(this.resolve(path));
+        }
+        /* We'll never going to be able to do better than this */
+        return new Path(path, path.absolute, path.collection, params);
+    }
+
+    /* ====================================================================== */
+    /* PUBLIC EXPOSED METHODS                                                 */
+    /* ====================================================================== */
+
+    /**
+     * <p>Return the {@link Path.Element Element} instance at
+     * the specified index.</p>
+     */
+    public Object get(int index) {
+        return this.paths[index];
+    }
+
+    /**
+     * <p>Return the number of {@link Path.Element Element}
+     * instances contained by this instance.</p>
+     */
+    public int size() {
+        return this.paths.length;
+    }
+
+    /**
+     * <p>Checks if this {@link Path Path} instance represents
+     * an absolute path.</p>
+     */
+    public boolean isAbsolute() {
+        return this.absolute;
+    }
+
+    /**
+     * <p>Checks if this {@link Path Path} instance represents
+     * a collection.</p>
+     */
+    public boolean isCollection() {
+        return this.collection;
+    }
+
+    /**
+     * <p>Returns the collection of {@link Parameters Parameters}
+     * contained by this instance or <b>null</b>.</p>
+     */
+    public Parameters getParameters() {
+        return this.parameters;
+    }
+
+    /* ====================================================================== */
+    /* OBJECT METHODS                                                         */
+    /* ====================================================================== */
+
+    /**
+     * <p>Return the URL-encoded {@link String} representation of this
+     * {@link Path Path} instance.</p>
+     */
+    public String toString() {
+        return this.string;
+    }
+
+    /**
+     * <p>Return the URL-encoded {@link String} representation of this
+     * {@link Path Path} instance using the specified
+     * character encoding.</p>
+     */
+    public String toString(String encoding)
+    throws UnsupportedEncodingException {
+        StringBuffer buffer = new StringBuffer();
+        if (this.absolute) buffer.append('/');
+        final int last = this.paths.length - 1;
+        for (int x = 0; x < last; x ++) {
+            buffer.append(this.paths[x].toString(encoding)).append('/');
+        }
+        if (last >= 0) {
+            buffer.append(this.paths[last].toString(encoding));
+            if (this.collection) buffer.append('/');
+        }
+        if (this.parameters != null)
+            buffer.append(';').append(this.parameters.toString(encoding));
+        return buffer.toString();
+    }
+
+    /**
+     * <p>Return the hash code value of this
+     * {@link Path Path} instance.</p>
+     */
+    public int hashCode() {
+        return this.string.hashCode();
+    }
+
+    /**
+     * <p>Check if the specified {@link Object} is equal to this
+     * {@link Path Path} instance.</p>
+     * 
+     * <p>The specified {@link Object} is considered equal to this one if
+     * it is <b>non-null</b>, is a {@link Path Path}
+     * instance and its {@link #toString() string representation} equals
+     * this one's.</p>
+     */
+    public boolean equals(Object object) {
+        if ((object != null) && (object instanceof Path)) {
+            return this.string.equals(((Path) object).string);
+        }
+        return false;
+    }
+
+    /* ====================================================================== */
+    /* PUBLIC INNER CLASSES                                                   */
+    /* ====================================================================== */
+
+    /**
+     * <p>The {@link Path.Element Element} class represents a path
+     * element within the {@link Path Path} structure.</p>
+     *
+     * @author <a href="http://could.it/">Pier Fumagalli</a>
+     */
+    public static class Element implements Encodable {
+
+        /** <p>The name of this path element (decoded).</p> */
+        private final String name;
+        /** <p>The extra path information of this path element (decoded).</p> */
+        private final String extra;
+        /** <p>The {@link String} representation of this (encoded).</p> */
+        private final String string;
+
+        /**
+         * <p>Create a new {@link Path.Element Element} instance given its
+         * url-decoded components name and extra.</p>
+         * 
+         * @throws NullPointerException if the specified name was <b>null</b>.
+         */ 
+        public Element(String name, String extra) {
+            if (name == null) throw new NullPointerException("Null path name");
+            this.name = name;
+            this.extra = extra;
+            this.string = EncodingTools.toString(this);
+        }
+
+        /* ================================================================== */
+        /* PUBLIC EXPOSED METHODS                                             */
+        /* ================================================================== */
+
+        /**
+         * <p>Return the url-decoded {@link String} name of this
+         * {@link Path.Element Element}.</p>
+         */
+        public String getName() {
+            return this.name;
+        }
+    
+        /**
+         * <p>Return the url-decoded {@link String} extra path of this
+         * {@link Path.Element Element}.</p>
+         */
+        public String getExtra() {
+            return this.extra;
+        }
+
+        /* ================================================================== */
+        /* OBJECT METHODS                                                     */
+        /* ================================================================== */
+
+        /**
+         * <p>Return the URL-encoded {@link String} representation of this
+         * {@link Path.Element Element} instance.</p>
+         */
+        public String toString() {
+            return this.string;
+        }
+    
+        /**
+         * <p>Return the URL-encoded {@link String} representation of this
+         * {@link Path.Element Element} instance using the specified
+         * character encoding.</p>
+         */
+        public String toString(String encoding)
+        throws UnsupportedEncodingException {
+            final StringBuffer buffer = new StringBuffer();
+            buffer.append(EncodingTools.urlEncode(this.name, encoding));
+            if (this.extra != null) {
+                buffer.append('!');
+                buffer.append(EncodingTools.urlEncode(this.extra, encoding));
+            }
+            return buffer.toString();
+        }
+
+        /**
+         * <p>Return the hash code value of this
+         * {@link Path.Element Element} instance.</p>
+         */
+        public int hashCode() {
+            return this.string.hashCode();
+        }
+
+        /**
+         * <p>Check if the specified {@link Object} is equal to this
+         * {@link Path.Element Element} instance.</p>
+         * 
+         * <p>The specified {@link Object} is considered equal to this one if
+         * it is <b>non-null</b>, is a {@link Path.Element Element}
+         * instance and its {@link #toString() string representation} equals
+         * this one's.</p>
+         */
+        public boolean equals(Object object) {
+            if ((object != null) && (object instanceof Element)) {
+                return this.string.equals(((Element) object).string);
+            }
+            return false;
+        }
+    }
+}
\ No newline at end of file

Propchange: maven/archiva/branches/springy/archiva-web/archiva-webdav/src/main/java/it/could/util/location/Path.java
------------------------------------------------------------------------------
    svn:eol-style = native

Added: maven/archiva/branches/springy/archiva-web/archiva-webdav/src/main/java/it/could/util/location/package.html
URL: http://svn.apache.org/viewvc/maven/archiva/branches/springy/archiva-web/archiva-webdav/src/main/java/it/could/util/location/package.html?rev=636822&view=auto
==============================================================================
--- maven/archiva/branches/springy/archiva-web/archiva-webdav/src/main/java/it/could/util/location/package.html (added)
+++ maven/archiva/branches/springy/archiva-web/archiva-webdav/src/main/java/it/could/util/location/package.html Thu Mar 13 11:28:26 2008
@@ -0,0 +1,29 @@
+<html>
+  <head>
+    <title>Location Utilities</title>
+  </head>
+  <body>
+    <p>
+      This package contains a number of utility classes to parse and
+      work with URLs.
+    </p>
+    <p>
+      The {@link java.net.URL} class already provides most of the functionality
+      covered by this package, but certain limitations in its implementation
+      (for example, all schemes <i>must</i> be registered with the
+      {java.net.URLStreamHandler} class before they can be used), prompted
+      the re-development of a similar API.
+    </p>
+    <p>
+      For further details on what the different classes in this package mean
+      and how they interact, see the {@link it.could.util.location.Location}
+      class documentation, but as a reference, this is a picture outlining
+      the structure:
+    </p>
+	<div align="center">
+	  <a href="url.pdf" target="_new" title="PDF Version">
+	    <img src="url.gif" alt="URL components" border="0">
+	  </a>
+	</div>
+  </body>
+</html>
\ No newline at end of file

Propchange: maven/archiva/branches/springy/archiva-web/archiva-webdav/src/main/java/it/could/util/location/package.html
------------------------------------------------------------------------------
    svn:eol-style = native

Added: maven/archiva/branches/springy/archiva-web/archiva-webdav/src/main/java/it/could/util/location/url.gif
URL: http://svn.apache.org/viewvc/maven/archiva/branches/springy/archiva-web/archiva-webdav/src/main/java/it/could/util/location/url.gif?rev=636822&view=auto
==============================================================================
Binary file - no diff available.

Propchange: maven/archiva/branches/springy/archiva-web/archiva-webdav/src/main/java/it/could/util/location/url.gif
------------------------------------------------------------------------------
    svn:mime-type = application/octet-stream

Added: maven/archiva/branches/springy/archiva-web/archiva-webdav/src/main/java/it/could/util/location/url.pdf
URL: http://svn.apache.org/viewvc/maven/archiva/branches/springy/archiva-web/archiva-webdav/src/main/java/it/could/util/location/url.pdf?rev=636822&view=auto
==============================================================================
Binary file - no diff available.

Propchange: maven/archiva/branches/springy/archiva-web/archiva-webdav/src/main/java/it/could/util/location/url.pdf
------------------------------------------------------------------------------
    svn:mime-type = application/pdf

Added: maven/archiva/branches/springy/archiva-web/archiva-webdav/src/main/java/it/could/util/package.html
URL: http://svn.apache.org/viewvc/maven/archiva/branches/springy/archiva-web/archiva-webdav/src/main/java/it/could/util/package.html?rev=636822&view=auto
==============================================================================
--- maven/archiva/branches/springy/archiva-web/archiva-webdav/src/main/java/it/could/util/package.html (added)
+++ maven/archiva/branches/springy/archiva-web/archiva-webdav/src/main/java/it/could/util/package.html Thu Mar 13 11:28:26 2008
@@ -0,0 +1,11 @@
+<html>
+  <head>
+    <title>Encoding Utilities</title>
+  </head>
+  <body>
+    <p>
+      This package contains a number of utility classes which can come handy
+      from time to time when writing Java code.
+    </p>
+  </body>
+</html>
\ No newline at end of file

Propchange: maven/archiva/branches/springy/archiva-web/archiva-webdav/src/main/java/it/could/util/package.html
------------------------------------------------------------------------------
    svn:eol-style = native

Added: maven/archiva/branches/springy/archiva-web/archiva-webdav/src/main/java/it/could/webdav/DAVException.java
URL: http://svn.apache.org/viewvc/maven/archiva/branches/springy/archiva-web/archiva-webdav/src/main/java/it/could/webdav/DAVException.java?rev=636822&view=auto
==============================================================================
--- maven/archiva/branches/springy/archiva-web/archiva-webdav/src/main/java/it/could/webdav/DAVException.java (added)
+++ maven/archiva/branches/springy/archiva-web/archiva-webdav/src/main/java/it/could/webdav/DAVException.java Thu Mar 13 11:28:26 2008
@@ -0,0 +1,132 @@
+/* ========================================================================== *
+ *         Copyright (C) 2004-2006, Pier Fumagalli <http://could.it/>         *
+ *                            All rights reserved.                            *
+ * ========================================================================== *
+ *                                                                            *
+ * 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 it.could.webdav;
+
+import java.io.IOException;
+import java.io.PrintWriter;
+
+
+/**
+ * <p>A {@link RuntimeException} representing a
+ * <a href="http://www.rfc-editor.org/rfc/rfc2518.txt">WebDAV</a>
+ * response for a specified {@link DAVResource}.</p> 
+ *
+ * @author <a href="http://could.it/">Pier Fumagalli</a>
+ */
+public class DAVException extends RuntimeException {
+    
+    private DAVResource resource = null;
+    private int status = 0;
+
+    /**
+     * <p>Create a new {@link DAVException} instance.</p>
+     */
+    public DAVException(int status, String message) {
+        this(status, message, null, null);
+    }
+
+    /**
+     * <p>Create a new {@link DAVException} instance.</p>
+     */
+    public DAVException(int status, String message, Throwable throwable) {
+        this(status, message, throwable, null);
+    }
+
+    /**
+     * <p>Create a new {@link DAVException} instance.</p>
+     */
+    public DAVException(int status, String message, DAVResource resource) {
+        this(status, message, null, resource);
+    }
+
+    /**
+     * <p>Create a new {@link DAVException} instance.</p>
+     */
+    public DAVException(int s, String m, Throwable t, DAVResource r) {
+        super(m, t);
+        this.resource = r;
+        this.status = s;
+    }
+
+    /**
+     * <p>Return the status code associated with this instance.</p>
+     */
+    public int getStatus() {
+        return this.status;
+    }
+
+    /**
+     * <p>Return the {@link DAVResource} associated with this instance.</p>
+     */
+    public DAVResource getResource() {
+        return this.resource;
+    }
+
+    /**
+     * <p>Write the body of this {@link DAVException} to the specified
+     * {@link DAVTransaction}'s output.</p>
+     */
+    public void write(DAVTransaction transaction)
+    throws IOException {
+        transaction.setContentType("text/html; charset=\"UTF-8\"");
+        transaction.setStatus(this.getStatus());
+
+        /* Prepare and log the error message */
+        String message = DAVUtilities.getStatusMessage(this.getStatus()); 
+        if (message == null) {
+            transaction.setStatus(500);
+            message = Integer.toString(this.getStatus()) + " Unknown";
+        }
+
+        /* Write the error message to the client */
+        PrintWriter out = transaction.write("UTF-8");
+        out.println("<html>");
+        out.print("<head><title>Error ");
+        out.print(message);
+        out.println("</title></head>");
+        out.println("<body>");
+        out.print("<p><b>Error ");
+        out.print(message);
+        out.println("</b></p>");
+        
+        /* Check if we have a resource associated with the extension */
+        if (this.getResource() != null) {
+            String r = transaction.lookup(this.getResource()).toASCIIString();
+            out.print("<p>Resource in error: <a href=\"");
+            out.print(r);
+            out.println("\">");
+            out.print(r);
+            out.println("</a></p>");
+        }
+
+        /* Process any exception and its cause */
+        Throwable throwable = this;
+        out.println("<hr /><p>Exception details:</p>");
+        while (throwable != null) {
+            out.print("<pre>");
+            throwable.printStackTrace(out);
+            out.println("</pre>");
+            throwable = throwable.getCause();
+            if (throwable != null) out.println("<hr /><p>Caused by:</p>");
+        }
+
+        /* Close up the HTML */
+        out.println("</body>");
+        out.println("</html>");
+        out.flush();
+    }
+}

Propchange: maven/archiva/branches/springy/archiva-web/archiva-webdav/src/main/java/it/could/webdav/DAVException.java
------------------------------------------------------------------------------
    svn:eol-style = native

Added: maven/archiva/branches/springy/archiva-web/archiva-webdav/src/main/java/it/could/webdav/DAVInputStream.java
URL: http://svn.apache.org/viewvc/maven/archiva/branches/springy/archiva-web/archiva-webdav/src/main/java/it/could/webdav/DAVInputStream.java?rev=636822&view=auto
==============================================================================
--- maven/archiva/branches/springy/archiva-web/archiva-webdav/src/main/java/it/could/webdav/DAVInputStream.java (added)
+++ maven/archiva/branches/springy/archiva-web/archiva-webdav/src/main/java/it/could/webdav/DAVInputStream.java Thu Mar 13 11:28:26 2008
@@ -0,0 +1,165 @@
+/* ========================================================================== *
+ *         Copyright (C) 2004-2006, Pier Fumagalli <http://could.it/>         *
+ *                            All rights reserved.                            *
+ * ========================================================================== *
+ *                                                                            *
+ * 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 it.could.webdav;
+
+import java.io.FileInputStream;
+import java.io.IOException;
+import java.io.InputStream;
+
+
+/**
+ * <p>A specialized {@link InputStream} to read from {@link DAVResource}s.</p>
+ * 
+ * <p>This specialized {@link InputStream} never throws {@link IOException}s,
+ * but rather relies on the unchecked {@link DAVException} to notify the
+ * framework of the correct DAV errors.</p>
+ *
+ * @author <a href="http://could.it/">Pier Fumagalli</a>
+ */
+public class DAVInputStream extends InputStream {
+
+    /** <p>The {@link InputStream} of the source {@link File}. </p> */
+    protected InputStream input = null;
+    /** <p>The {@link DAVResource} associated with this instance. </p> */
+    private DAVResource resource = null;
+
+    /**
+     * <p>Create a new {@link DAVInputStream} instance.</p>
+     */
+    protected DAVInputStream(DAVResource resource) {
+        if (resource == null) throw new NullPointerException();
+        init(resource);
+    }
+    
+    protected void init(DAVResource resource)
+    {
+        try {
+            this.input = new FileInputStream(resource.getFile());
+        } catch (IOException e) {
+            String message = "Unable to read from resource";
+            throw new DAVException (403, message, e, resource);
+        }
+    }
+
+    /**
+     * <p>Read data from this {@link InputStream}.</p>
+     */
+    public int read() {
+        if (this.input == null) throw new IllegalStateException("Closed");
+        try {
+            return input.read();
+        } catch (IOException e) {
+            throw new DAVException(403, "Can't read data", e, this.resource);
+        }
+    }
+
+    /**
+     * <p>Read data from this {@link InputStream}.</p>
+     */
+    public int read(byte b[]) {
+        if (this.input == null) throw new IllegalStateException("Closed");
+        try {
+            return input.read(b);
+        } catch (IOException e) {
+            throw new DAVException(403, "Can't read data", e, this.resource);
+        }
+    }
+
+    /**
+     * <p>Read data from this {@link InputStream}.</p>
+     */
+    public int read(byte b[], int off, int len) {
+        if (this.input == null) throw new IllegalStateException("Closed");
+        try {
+            return input.read(b, off, len);
+        } catch (IOException e) {
+            throw new DAVException(403, "Can't read data", e, this.resource);
+        }
+    }
+
+    /**
+     * <p>Skip a specified amount of data reading from this
+     * {@link InputStream}.</p>
+     */
+    public long skip(long n) {
+        if (this.input == null) throw new IllegalStateException("Closed");
+        try {
+            return input.skip(n);
+        } catch (IOException e) {
+            throw new DAVException(403, "Can't skip over", e, this.resource);
+        }
+    }
+
+    /**
+     * <p>Return the number of bytes that can be read or skipped from this
+     * {@link InputStream} without blocking.</p>
+     */
+    public int available() {
+        if (this.input == null) throw new IllegalStateException("Closed");
+        try {
+            return input.available();
+        } catch (IOException e) {
+            throw new DAVException(403, "Can't skip over", e, this.resource);
+        }
+    }
+
+    /**
+     * <p>Return the number of bytes that can be read or skipped from this
+     * {@link InputStream} without blocking.</p>
+     */
+    public void close() {
+        if (this.input == null) return;
+        try {
+            this.input.close();
+        } catch (IOException e) {
+            throw new DAVException(403, "Can't close", e, this.resource);
+        } finally {
+            this.input = null;
+        }
+    }
+    
+    /**
+     * <p>Marks the current position in this {@link InputStream}.</p>
+     */
+    public void mark(int readlimit) {
+        if (this.input == null) throw new IllegalStateException("Closed");
+        this.input.mark(readlimit);
+    }
+    
+    /**
+     * <p>Repositions this stream to the position at the time the
+     * {@link #mark(int)} method was last called on this
+     * {@link InputStream}.</p>
+     */
+    public void reset() {
+        if (this.input == null) throw new IllegalStateException("Closed");
+        try {
+            input.reset();
+        } catch (IOException e) {
+            throw new DAVException(403, "Can't reset", e, this.resource);
+        }
+    }
+    
+    /**
+     * <p>Tests if this {@link InputStream} supports the {@link #mark(int)}
+     * and {@link #reset()} methods.</p>
+     */
+    public boolean markSupported() {
+        if (this.input == null) throw new IllegalStateException("Closed");
+        return this.input.markSupported();
+    }
+}

Propchange: maven/archiva/branches/springy/archiva-web/archiva-webdav/src/main/java/it/could/webdav/DAVInputStream.java
------------------------------------------------------------------------------
    svn:eol-style = native

Added: maven/archiva/branches/springy/archiva-web/archiva-webdav/src/main/java/it/could/webdav/DAVListener.java
URL: http://svn.apache.org/viewvc/maven/archiva/branches/springy/archiva-web/archiva-webdav/src/main/java/it/could/webdav/DAVListener.java?rev=636822&view=auto
==============================================================================
--- maven/archiva/branches/springy/archiva-web/archiva-webdav/src/main/java/it/could/webdav/DAVListener.java (added)
+++ maven/archiva/branches/springy/archiva-web/archiva-webdav/src/main/java/it/could/webdav/DAVListener.java Thu Mar 13 11:28:26 2008
@@ -0,0 +1,46 @@
+/* ========================================================================== *
+ *         Copyright (C) 2004-2006, Pier Fumagalli <http://could.it/>         *
+ *                            All rights reserved.                            *
+ * ========================================================================== *
+ *                                                                            *
+ * 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 it.could.webdav;
+
+/**
+ * <p>A simple interface identifying a {@link DAVRepository} event listener.</p> 
+ *
+ * @author <a href="http://could.it/">Pier Fumagalli</a>
+ */
+public interface DAVListener {
+
+    /** <p>An event representing the creation of a collection.</p> */
+    public static final int COLLECTION_CREATED = 1;
+    /** <p>An event representing the deletion of a collection.</p> */
+    public static final int COLLECTION_REMOVED = 2;
+    /** <p>An event representing the creation of a resource.</p> */
+    public static final int RESOURCE_CREATED = 3;
+    /** <p>An event representing the deletion of a resource.</p> */
+    public static final int RESOURCE_REMOVED = 4;
+    /** <p>An event representing the modification of a resource.</p> */
+    public static final int RESOURCE_MODIFIED = 5;
+    
+    /**
+     * <p>Notify this {@link DAVListener} of an action occurred on a
+     * specified {@link DAVResource}.</p>
+     * 
+     * @param resource the {@link DAVResource} associated with the notification.
+     * @param event a number identifying the type of the notification.
+     */
+    public void notify(DAVResource resource, int event);
+
+}

Propchange: maven/archiva/branches/springy/archiva-web/archiva-webdav/src/main/java/it/could/webdav/DAVListener.java
------------------------------------------------------------------------------
    svn:eol-style = native

Added: maven/archiva/branches/springy/archiva-web/archiva-webdav/src/main/java/it/could/webdav/DAVLogger.java
URL: http://svn.apache.org/viewvc/maven/archiva/branches/springy/archiva-web/archiva-webdav/src/main/java/it/could/webdav/DAVLogger.java?rev=636822&view=auto
==============================================================================
--- maven/archiva/branches/springy/archiva-web/archiva-webdav/src/main/java/it/could/webdav/DAVLogger.java (added)
+++ maven/archiva/branches/springy/archiva-web/archiva-webdav/src/main/java/it/could/webdav/DAVLogger.java Thu Mar 13 11:28:26 2008
@@ -0,0 +1,86 @@
+/* ========================================================================== *
+ *         Copyright (C) 2004-2006, Pier Fumagalli <http://could.it/>         *
+ *                            All rights reserved.                            *
+ * ========================================================================== *
+ *                                                                            *
+ * 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 it.could.webdav;
+
+import javax.servlet.ServletConfig;
+import javax.servlet.ServletContext;
+
+/**
+ * <p>A simplicisting class defining an esay way to log stuff to the
+ * {@link ServletContext}.</p> 
+ *
+ * @author <a href="http://could.it/">Pier Fumagalli</a>
+ */
+public class DAVLogger {
+    
+    private final ServletContext context;
+    private final String servletName;
+    private final boolean debug;
+
+    /**
+     * <p>Create a new {@link DAVLogger} from a {@link ServletConfig}.</p>
+     */
+    public DAVLogger(ServletConfig config, boolean debug) {
+        this.context = config.getServletContext();
+        this.servletName = config.getServletName();
+        this.debug = debug;
+    }
+
+    /**
+     * <p>Log a debug message to the context logger.</p>
+     */
+    public void debug(String message) {
+        if (this.debug) this.doLog(message, null);
+    }
+
+    /**
+     * <p>Log a debug message and related exception to the context logger.</p>
+     */
+    public void debug(String message, Throwable throwable) {
+        if (this.debug) this.doLog(message, throwable);
+    }
+
+    /**
+     * <p>Log a message to the context logger.</p>
+     */
+    public void log(String message) {
+        this.doLog(message, null);
+    }
+
+    /**
+     * <p>Log a message and related exception to the context logger.</p>
+     */
+    public void log(String message, Throwable throwable) {
+        this.doLog(message, throwable);
+    }
+
+    /**
+     * <p>Internal method for formatting messages and logging.</p>
+     */
+    private void doLog(String message, Throwable throwable) {
+        if ((message == null) && (throwable == null)) return;
+        if ((message == null) || ("".equals(message))) message = "No message";
+
+        StringBuffer buffer = new StringBuffer();
+        buffer.append('[');
+        buffer.append(this.servletName);
+        buffer.append("] ");
+        buffer.append(message);
+        if (throwable == null) this.context.log(buffer.toString());
+        else this.context.log(buffer.toString(), throwable);
+    }
+}

Propchange: maven/archiva/branches/springy/archiva-web/archiva-webdav/src/main/java/it/could/webdav/DAVLogger.java
------------------------------------------------------------------------------
    svn:eol-style = native

Added: maven/archiva/branches/springy/archiva-web/archiva-webdav/src/main/java/it/could/webdav/DAVMethod.java
URL: http://svn.apache.org/viewvc/maven/archiva/branches/springy/archiva-web/archiva-webdav/src/main/java/it/could/webdav/DAVMethod.java?rev=636822&view=auto
==============================================================================
--- maven/archiva/branches/springy/archiva-web/archiva-webdav/src/main/java/it/could/webdav/DAVMethod.java (added)
+++ maven/archiva/branches/springy/archiva-web/archiva-webdav/src/main/java/it/could/webdav/DAVMethod.java Thu Mar 13 11:28:26 2008
@@ -0,0 +1,41 @@
+/* ========================================================================== *
+ *         Copyright (C) 2004-2006, Pier Fumagalli <http://could.it/>         *
+ *                            All rights reserved.                            *
+ * ========================================================================== *
+ *                                                                            *
+ * 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 it.could.webdav;
+
+import java.io.IOException;
+
+
+/**
+ * <p>An interface describing the implementation of a 
+ * <a href="http://www.rfc-editor.org/rfc/rfc2518.txt">WebDAV</a>
+ * method.</p> 
+ *
+ * @author <a href="http://could.it/">Pier Fumagalli</a>
+ */
+public interface DAVMethod {
+
+    /**
+     * <p>Process the specified {@link DAVTransaction}.</p>
+     * 
+     * @param transaction An object encapsulaing a WebDAV request/response.
+     * @param resource The {@link DAVResource} to process.
+     * @throws IOException If an I/O error occurred.
+     */
+    public void process(DAVTransaction transaction, DAVResource resource)
+    throws IOException;
+
+}

Propchange: maven/archiva/branches/springy/archiva-web/archiva-webdav/src/main/java/it/could/webdav/DAVMethod.java
------------------------------------------------------------------------------
    svn:eol-style = native

Added: maven/archiva/branches/springy/archiva-web/archiva-webdav/src/main/java/it/could/webdav/DAVMultiStatus.java
URL: http://svn.apache.org/viewvc/maven/archiva/branches/springy/archiva-web/archiva-webdav/src/main/java/it/could/webdav/DAVMultiStatus.java?rev=636822&view=auto
==============================================================================
--- maven/archiva/branches/springy/archiva-web/archiva-webdav/src/main/java/it/could/webdav/DAVMultiStatus.java (added)
+++ maven/archiva/branches/springy/archiva-web/archiva-webdav/src/main/java/it/could/webdav/DAVMultiStatus.java Thu Mar 13 11:28:26 2008
@@ -0,0 +1,149 @@
+/* ========================================================================== *
+ *         Copyright (C) 2004-2006, Pier Fumagalli <http://could.it/>         *
+ *                            All rights reserved.                            *
+ * ========================================================================== *
+ *                                                                            *
+ * 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 it.could.webdav;
+
+import java.io.IOException;
+import java.io.PrintWriter;
+import java.util.HashSet;
+import java.util.Iterator;
+import java.util.Set;
+
+
+/**
+ * <p>A {@link DAVException} representing a
+ * <a href="http://www.rfc-editor.org/rfc/rfc2518.txt">WebDAV</a>
+ * <code>207</code> (Multi-Status) response.</p> 
+ *
+ * @author <a href="http://could.it/">Pier Fumagalli</a>
+ */
+public class DAVMultiStatus extends DAVException {
+    
+    private Set responses = new HashSet();
+
+    /**
+     * <p>Create a new {@link DAVMultiStatus} instance.</p>
+     */
+    public DAVMultiStatus() {
+        super(207, "Multi-Status response");
+    }
+
+    /**
+     * <p>Write the body of the multi-status response to the specified
+     * {@link DAVTransaction}'s output.</p>
+     */
+    public void write(DAVTransaction transaction)
+    throws IOException {
+        /* What to do on a collection resource */
+        transaction.setStatus(207);
+        transaction.setContentType("text/xml; charset=\"UTF-8\"");
+        PrintWriter out = transaction.write("UTF-8");
+
+        /* Output the XML declaration and the root document tag */
+        out.println("<?xml version=\"1.0\" encoding=\"UTF-8\"?>");
+        out.println("<D:multistatus xmlns:D=\"DAV:\">");
+        
+        Iterator responses = this.responses.iterator();
+        while (responses.hasNext()) {
+            Response response = (Response) responses.next();
+            out.println(" <D:response>");
+            out.print("  <D:href>");
+            out.print(transaction.lookup(response.resource));
+            out.println("</D:href>");
+
+            if (response.status != 0) {
+                out.print("  <D:status>HTTP/1.1 ");
+                out.print(DAVUtilities.getStatusMessage(response.status));
+                out.println("</D:status>");
+            }
+
+            if (response.message != null) {
+                out.print("  <D:responsedescription>");
+                out.print(response.message);
+                out.println("</D:responsedescription>");
+            }
+
+            out.println(" </D:response>");
+        }
+        
+        out.println("</D:multistatus>");
+        out.flush();
+    }
+
+    /**
+     * <p>Return the number of responses held in this instance.</p>
+     */
+    public int size() {
+        return this.responses.size();
+    }
+
+    /**
+     * <p>Merge the responses held into the specified {@link DAVMultiStatus}
+     * into this instance.</p>
+     */
+    public void merge(DAVMultiStatus multistatus) {
+        if (multistatus == null) return;
+        Iterator iterator = multistatus.responses.iterator();
+        while (iterator.hasNext()) this.responses.add(iterator.next());
+    }
+
+    /**
+     * <p>Merge the details held into the specified {@link DAVException}
+     * into this instance.</p>
+     */
+    public void merge(DAVException exception) {
+        DAVResource resource = exception.getResource();
+        if (resource == null) throw exception;
+
+        int status = exception.getStatus();
+        String message = exception.getMessage();
+        this.responses.add(new Response(resource, status, message));
+    }
+
+    private static class Response implements Comparable {
+        private DAVResource resource = null;
+        private int status = 0;
+        private String message = null;
+
+        public Response(Response response) {
+            this(response.resource, response.status, response.message);
+        }
+
+        public Response(DAVResource resource, int status, String message) {
+            if (resource == null) throw new NullPointerException();
+            this.resource = resource;
+            this.status = status;
+            this.message = message;
+        }
+
+        public int hashCode() {
+            return this.resource.hashCode();
+        }
+
+        public int compareTo(Object object) {
+            Response response = (Response) object;
+            return (this.resource.compareTo(response.resource));
+        }
+
+        public boolean equals(Object object) {
+            if (object instanceof Response) {
+                Response response = (Response) object;
+                return (this.resource.equals(response.resource));
+            }
+            return false;
+        }
+    }
+}

Propchange: maven/archiva/branches/springy/archiva-web/archiva-webdav/src/main/java/it/could/webdav/DAVMultiStatus.java
------------------------------------------------------------------------------
    svn:eol-style = native

Added: maven/archiva/branches/springy/archiva-web/archiva-webdav/src/main/java/it/could/webdav/DAVNotModified.java
URL: http://svn.apache.org/viewvc/maven/archiva/branches/springy/archiva-web/archiva-webdav/src/main/java/it/could/webdav/DAVNotModified.java?rev=636822&view=auto
==============================================================================
--- maven/archiva/branches/springy/archiva-web/archiva-webdav/src/main/java/it/could/webdav/DAVNotModified.java (added)
+++ maven/archiva/branches/springy/archiva-web/archiva-webdav/src/main/java/it/could/webdav/DAVNotModified.java Thu Mar 13 11:28:26 2008
@@ -0,0 +1,56 @@
+/* ========================================================================== *
+ *         Copyright (C) 2004-2006, Pier Fumagalli <http://could.it/>         *
+ *                            All rights reserved.                            *
+ * ========================================================================== *
+ *                                                                            *
+ * 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 it.could.webdav;
+
+import java.io.IOException;
+
+/**
+ * <p>A simple {@link DAVException} encapsulating an
+ * <a href="http://www.rfc-editor.org/rfc/rfc2616.txt">HTTP</a> not modified
+ * response.</p>
+ *
+ * @author <a href="http://could.it/">Pier Fumagalli</a>
+ */
+public class DAVNotModified extends DAVException {
+
+    private DAVResource resource = null;
+
+    /**
+     * <p>Create a new {@link DAVNotModified} instance.</p>
+     */
+    public DAVNotModified(DAVResource resource) {
+        super(304, "Resource Not Modified");
+        this.resource = resource;
+    }
+
+    /**
+     * <p>Write the body of this {@link DAVNotModified} to the specified
+     * {@link DAVTransaction}'s output.</p>
+     */
+    public void write(DAVTransaction transaction)
+    throws IOException {
+        transaction.setStatus(this.getStatus());
+
+        /* Figure out what we're dealing with here */
+        String etag = resource.getEntityTag();
+        String lmod = DAVUtilities.formatHttpDate(resource.getLastModified());
+
+        /* Set the normal headers that are required for a GET */
+        if (etag != null) transaction.setHeader("ETag", etag);
+        if (lmod != null) transaction.setHeader("Last-Modified", lmod);
+    }
+}

Propchange: maven/archiva/branches/springy/archiva-web/archiva-webdav/src/main/java/it/could/webdav/DAVNotModified.java
------------------------------------------------------------------------------
    svn:eol-style = native