diff options
Diffstat (limited to 'archiva-modules/archiva-web/archiva-webdav/src/main/java/it/could/util')
14 files changed, 0 insertions, 4620 deletions
diff --git a/archiva-modules/archiva-web/archiva-webdav/src/main/java/it/could/util/StreamTools.java b/archiva-modules/archiva-web/archiva-webdav/src/main/java/it/could/util/StreamTools.java deleted file mode 100644 index 17ebb7e9c..000000000 --- a/archiva-modules/archiva-web/archiva-webdav/src/main/java/it/could/util/StreamTools.java +++ /dev/null @@ -1,125 +0,0 @@ -/* ========================================================================== * - * 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; - -import java.io.IOException; -import java.io.InputStream; -import java.io.OutputStream; - -/** - * <p>An utility class providing various static methods operating on - * {@link InputStream input} and {@link OutputStream output} streams.</p> - * - * @author <a href="http://could.it/">Pier Fumagalli</a> - */ -public final class StreamTools { - - /** <p>Deny construction.</p> */ - private StreamTools() { }; - - /** - * <p>Copy every byte from the specified {@link InputStream} to the specifed - * {@link OutputStream} and then close both of them.</p> - * - * <p>This method is equivalent to a call to the following method: - * {@link #copy(InputStream,OutputStream,boolean) copy(in, out, true)}.</p> - * - * @param in the {@link InputStream} to read bytes from. - * @param out the {@link OutputStream} to write bytes to. - * @return the number of bytes copied. - * @throws IOException if an I/O error occurred copying the data. - */ - public static long copy(InputStream in, OutputStream out) - throws IOException { - return copy(in, out, true); - } - - /** - * <p>Copy every byte from the specified {@link InputStream} to the specifed - * {@link OutputStream} and then optionally close both of them.</p> - * - * @param in the {@link InputStream} to read bytes from. - * @param out the {@link OutputStream} to write bytes to. - * @param close whether to close the streams or not. - * @return the number of bytes copied. - * @throws IOException if an I/O error occurred copying the data. - */ - public static long copy(InputStream in, OutputStream out, boolean close) - throws IOException { - if (in == null) throw new NullPointerException("Null input"); - if (out == null) throw new NullPointerException("Null output"); - - final byte buffer[] = new byte[4096]; - int length = -1; - long total = 0; - while ((length = in.read(buffer)) >= 0) { - out.write(buffer, 0, length); - total += length; - } - - if (close) { - in.close(); - out.close(); - } - - return total; - } - - /** - * Closes the output stream. The output stream can be null and any IOException's will be swallowed. - * - * @param outputStream The stream to close. - */ - public static void close( OutputStream outputStream ) - { - if ( outputStream == null ) - { - return; - } - - try - { - outputStream.close(); - } - catch( IOException ex ) - { - // ignore - } - } - - /** - * Closes the input stream. The input stream can be null and any IOException's will be swallowed. - * - * @param inputStream The stream to close. - */ - public static void close( InputStream inputStream ) - { - if ( inputStream == null ) - { - return; - } - - try - { - inputStream.close(); - } - catch( IOException ex ) - { - // ignore - } - } -} diff --git a/archiva-modules/archiva-web/archiva-webdav/src/main/java/it/could/util/StringTools.java b/archiva-modules/archiva-web/archiva-webdav/src/main/java/it/could/util/StringTools.java deleted file mode 100644 index 3b0eb14ea..000000000 --- a/archiva-modules/archiva-web/archiva-webdav/src/main/java/it/could/util/StringTools.java +++ /dev/null @@ -1,214 +0,0 @@ -/* ========================================================================== * - * 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; - -import it.could.util.encoding.Encodable; - -import java.text.ParseException; -import java.text.SimpleDateFormat; -import java.util.ArrayList; -import java.util.Date; -import java.util.List; -import java.util.Locale; -import java.util.TimeZone; - -/** - * <p>An utility class providing various static methods operating on - * {@link String}s.</p> - * - * <p>This class implement the {@link Encodable} interface from which it - * inherits its {@link Encodable#DEFAULT_ENCODING default encoding}.</p> - * - * @author <a href="http://could.it/">Pier Fumagalli</a> - */ -public final class StringTools { - - /** <p>The {@link SimpleDateFormat} RFC-822 date format.</p> */ - private static final String FORMAT_822 = "EEE, dd MMM yyyy HH:mm:ss 'GMT'"; - /** <p>The {@link SimpleDateFormat} RFC-822 date format.</p> */ - private static final String FORMAT_ISO = "yyyy-MM-dd'T'HH:mm:ss'Z'"; - /** <p>The {@link TimeZone} to use for dates.</p> */ - private static final TimeZone TIMEZONE = TimeZone.getTimeZone("GMT"); - /** <p>The {@link Locale} to use for dates.</p> */ - private static final Locale LOCALE = Locale.US; - - /** <p>Deny construction.</p> */ - private StringTools() { } - - /* ====================================================================== */ - /* NUMBER AND DATE PARSING AND FORMATTING */ - /* ====================================================================== */ - - /** - * <p>Format a {@link Number} into a {@link String} making sure that - * {@link NullPointerException}s are not thrown.</p> - * - * @param number the {@link Number} to format. - * @return a {@link String} instance or <b>null</b> if the object was null. - */ - public static String formatNumber(Number number) { - if (number == null) return null; - return (number.toString()); - } - - /** - * <p>Parse a {@link String} into a {@link Long}.</p> - * - * @param string the {@link String} to parse. - * @return a {@link Long} instance or <b>null</b> if the date was null or - * if there was an error parsing the specified {@link String}. - */ - public static Long parseNumber(String string) { - if (string == null) return null; - try { - return new Long(string); - } catch (NumberFormatException exception) { - return null; - } - } - - /** - * <p>Format a {@link Date} according to the HTTP/1.1 RFC.</p> - * - * @param date the {@link Date} to format. - * @return a {@link String} instance or <b>null</b> if the date was null. - */ - public static String formatHttpDate(Date date) { - if (date == null) return null; - SimpleDateFormat formatter = new SimpleDateFormat(FORMAT_822, LOCALE); - formatter.setTimeZone(TIMEZONE); - return formatter.format(date); - } - - /** - * <p>Format a {@link Date} according to the ISO 8601 specification.</p> - * - * @param date the {@link Date} to format. - * @return a {@link String} instance or <b>null</b> if the date was null. - */ - public static String formatIsoDate(Date date) { - if (date == null) return null; - SimpleDateFormat formatter = new SimpleDateFormat(FORMAT_ISO, LOCALE); - formatter.setTimeZone(TIMEZONE); - return formatter.format(date); - } - - /** - * <p>Parse a {@link String} into a {@link Date} according to the - * HTTP/1.1 RFC (<code>Mon, 31 Jan 2000 11:59:00 GMT</code>).</p> - * - * @param string the {@link String} to parse. - * @return a {@link Date} instance or <b>null</b> if the date was null or - * if there was an error parsing the specified {@link String}. - */ - public static Date parseHttpDate(String string) { - if (string == null) return null; - SimpleDateFormat formatter = new SimpleDateFormat(FORMAT_822, LOCALE); - formatter.setTimeZone(TIMEZONE); - try { - return formatter.parse(string); - } catch (ParseException exception) { - return null; - } - } - - /** - * <p>Parse a {@link String} into a {@link Date} according to the ISO 8601 - * specification (<code>2000-12-31T11:59:00Z</code>).</p> - * - * @param string the {@link String} to parse. - * @return a {@link Date} instance or <b>null</b> if the date was null or - * if there was an error parsing the specified {@link String}. - */ - public static Date parseIsoDate(String string) { - if (string == null) return null; - SimpleDateFormat formatter = new SimpleDateFormat(FORMAT_ISO, LOCALE); - formatter.setTimeZone(TIMEZONE); - try { - return formatter.parse(string); - } catch (ParseException exception) { - return null; - } - } - - /* ====================================================================== */ - /* STRING SPLITTING */ - /* ====================================================================== */ - - /** - * <p>Split the specified string in two parts according to the specified - * delimiter, and any resulting path of zero length will be converted to - * <b>null</b>.</p> - */ - public static String[] splitOnce(String source, char delimiter, - boolean noDelimReturnSecond) { - if (source == null) return new String[] { null, null }; - final int position = source.indexOf(delimiter); - if (position < 0) { // --> first - if (noDelimReturnSecond) return new String[] { null, source }; - else return new String[] { source, null }; - } else if (position == 0) { - if (source.length() == 1) { // --> | - return new String[] { null, null }; - } else { // --> |second - return new String[] { null, source.substring(1) }; - } - } else { - final String first = source.substring(0, position); - if (source.length() -1 == position) { // --> first| - return new String[] { first, null }; - } else { // --> first|second - return new String[] { first, source.substring(position + 1) }; - } - } - } - - /** - * <p>Split the specified string according to the specified delimiter, and - * any resulting path of zero length will be converted to <b>null</b>.</p> - */ - public static String[] splitAll(String source, char delimiter) { - final List strings = new ArrayList(); - String current = source; - while (current != null) { - String split[] = splitOnce(current, delimiter, false); - strings.add(split[0]); - current = split[1]; - } - if (current != null) strings.add(current); - final int length = source.length(); - if ((length > 0) && (source.charAt(length - 1) == delimiter)) { - strings.add(null); - } - return (String []) strings.toArray(new String[strings.size()]); - } - - /** - * <p>Find the first occurrence of one of the specified delimiter characters - * in the specified source string.</p> - */ - public static int findFirst(String source, String delimiters) { - final char array[] = source.toCharArray(); - final char delim[] = delimiters.toCharArray(); - for (int x = 0; x < array.length; x ++) { - for (int y = 0; y < delim.length; y ++) { - if (array[x] == delim[y]) return x; - } - } - return -1; - } -} diff --git a/archiva-modules/archiva-web/archiva-webdav/src/main/java/it/could/util/encoding/Encodable.java b/archiva-modules/archiva-web/archiva-webdav/src/main/java/it/could/util/encoding/Encodable.java deleted file mode 100644 index 2f644f9a0..000000000 --- a/archiva-modules/archiva-web/archiva-webdav/src/main/java/it/could/util/encoding/Encodable.java +++ /dev/null @@ -1,48 +0,0 @@ -/* ========================================================================== * - * 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.encoding; - -import java.io.UnsupportedEncodingException; - -/** - * <p>The {@link Encodable} interface describes an {@link Object} whose - * {@link String} representation can vary depending on the encoding used.</p> - * - * @author <a href="http://could.it/">Pier Fumagalli</a> - */ -public interface Encodable extends EncodingAware { - - /** - * <p>Return the {@link String} representation of this instance.</p> - * - * <p>This method is equivalent to a call to - * {@link #toString(String) toString}({@link EncodingAware#DEFAULT_ENCODING - * DEFAULT_ENCODING})</p> - */ - public String toString(); - - /** - * <p>Return the {@link String} representation of this instance given - * a specific character encoding.</p> - * - * @throws UnsupportedEncodingException if the specified encoding is not - * supported by the platform. - */ - public String toString(String encoding) - throws UnsupportedEncodingException; - -} diff --git a/archiva-modules/archiva-web/archiva-webdav/src/main/java/it/could/util/encoding/EncodingAware.java b/archiva-modules/archiva-web/archiva-webdav/src/main/java/it/could/util/encoding/EncodingAware.java deleted file mode 100644 index 0690a175b..000000000 --- a/archiva-modules/archiva-web/archiva-webdav/src/main/java/it/could/util/encoding/EncodingAware.java +++ /dev/null @@ -1,37 +0,0 @@ -/* ========================================================================== * - * 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.encoding; - -import java.io.ByteArrayOutputStream; -import java.io.OutputStreamWriter; - -/** - * <p>The {@link EncodingAware} interface describes an {@link Object} aware - * of multiple encodings existing withing the platform.</p> - * - * @author <a href="http://could.it/">Pier Fumagalli</a> - */ -public interface EncodingAware { - - /** <p>The default encoding is specified as being <code>UTF-8</code>.</p> */ - public static final String DEFAULT_ENCODING = "UTF-8"; - - /** <p>The platform encoding is evaluated at runtime from the JVM.</p> */ - public static final String PLATFORM_ENCODING = - new OutputStreamWriter(new ByteArrayOutputStream()).getEncoding(); - -} diff --git a/archiva-modules/archiva-web/archiva-webdav/src/main/java/it/could/util/encoding/EncodingTools.java b/archiva-modules/archiva-web/archiva-webdav/src/main/java/it/could/util/encoding/EncodingTools.java deleted file mode 100644 index c0c2e7adb..000000000 --- a/archiva-modules/archiva-web/archiva-webdav/src/main/java/it/could/util/encoding/EncodingTools.java +++ /dev/null @@ -1,274 +0,0 @@ -/* ========================================================================== * - * 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.encoding; - -import java.io.UnsupportedEncodingException; -import java.net.URLDecoder; -import java.net.URLEncoder; - -/** - * <p>An utility class providing various static methods dealing with - * encodings and {@link Encodable} objects..</p> - * - * @author <a href="http://could.it/">Pier Fumagalli</a> - */ -public final class EncodingTools implements EncodingAware { - - /** <p>The Base-64 alphabet.</p> */ - private static final char ALPHABET[] = { - 'A', 'B', 'C', 'D', 'E', 'F', 'G', 'H', 'I', 'J', 'K', 'L', 'M', - 'N', 'O', 'P', 'Q', 'R', 'S', 'T', 'U', 'V', 'W', 'X', 'Y', 'Z', - 'a', 'b', 'c', 'd', 'e', 'f', 'g', 'h', 'i', 'j', 'k', 'l', 'm', - 'n', 'o', 'p', 'q', 'r', 's', 't', 'u', 'v', 'w', 'x', 'y', 'z', - '0', '1', '2', '3', '4', '5', '6', '7', '8', '9', '+', '/', '=' }; - - /** <p>Deny construction of this class.</p> */ - private EncodingTools() { } - - /* ====================================================================== */ - /* URL ENCODING / DECODING */ - /* ====================================================================== */ - - /** - * <p>Return the {@link String} representation of the specified - * {@link Encodable} object using the {@link EncodingAware#DEFAULT_ENCODING - * default encoding}.</p> - * - * throws NullPointerException if the {@link Encodable} was <b>null</b>. - */ - public static String toString(Encodable encodable) { - try { - return encodable.toString(DEFAULT_ENCODING); - } catch (UnsupportedEncodingException exception) { - final String message = "Default encoding \"" + DEFAULT_ENCODING + - "\" not supported by the platform"; - final InternalError error = new InternalError(message); - throw (InternalError) error.initCause(exception); - } - } - - /* ====================================================================== */ - /* URL ENCODING / DECODING */ - /* ====================================================================== */ - - /** - * <p>URL-encode the specified string.</p> - */ - public static String urlEncode(String source, String encoding) - throws UnsupportedEncodingException { - if (source == null) return null; - if (encoding == null) encoding = DEFAULT_ENCODING; - return URLEncoder.encode(source, encoding); - } - - /** - * <p>URL-encode the specified string.</p> - */ - public static String urlEncode(String source) { - if (source == null) return null; - try { - return URLEncoder.encode(source, DEFAULT_ENCODING); - } catch (UnsupportedEncodingException exception) { - final String message = "Unsupported encoding " + DEFAULT_ENCODING; - final InternalError error = new InternalError(message); - throw (InternalError) error.initCause(exception); - } - } - - /** - * <p>URL-decode the specified string.</p> - */ - public static String urlDecode(String source, String encoding) - throws UnsupportedEncodingException { - if (source == null) return null; - if (encoding == null) encoding = DEFAULT_ENCODING; - return URLDecoder.decode(source, encoding); - } - - /** - * <p>URL-decode the specified string.</p> - */ - public static String urlDecode(String source) { - if (source == null) return null; - try { - return URLDecoder.decode(source, DEFAULT_ENCODING); - } catch (UnsupportedEncodingException exception) { - final String message = "Unsupported encoding " + DEFAULT_ENCODING; - final InternalError error = new InternalError(message); - throw (InternalError) error.initCause(exception); - } - } - - /* ====================================================================== */ - /* BASE 64 ENCODING / DECODING */ - /* ====================================================================== */ - - /** - * <p>Encode the specified string in base 64 using the specified - * encoding.</p> - */ - public static final String base64Encode(String string, String encoding) - throws UnsupportedEncodingException { - /* Check the source string for null or the empty string. */ - if (string == null) return (null); - if (string.length() == 0) return ""; - - /* Check the encoding */ - if (encoding == null) encoding = DEFAULT_ENCODING; - - /* Prepare the buffers that we'll use to encode in Base 64 */ - final byte bsrc[] = string.getBytes(encoding); - final char bdst[] = new char[(bsrc.length + 2) / 3 * 4]; - - /* Iterate into the source in chunks of three bytes */ - int psrc = -1; - int pdst = 0; - int temp = 0; - while ((psrc = psrc + 3) < bsrc.length) { - /* For every three bytes processed ... */ - temp = ((bsrc[psrc - 2] << 16) & 0xFF0000) | - ((bsrc[psrc - 1] << 8) & 0x00FF00) | - ((bsrc[psrc ] ) & 0x0000FF); - /* ... we append four bytes to the buffer */ - bdst[pdst ++] = ALPHABET[(temp >> 18) & 0x3f]; - bdst[pdst ++] = ALPHABET[(temp >> 12) & 0x3f]; - bdst[pdst ++] = ALPHABET[(temp >> 6) & 0x3f]; - bdst[pdst ++] = ALPHABET[(temp ) & 0x3f]; - } - - /* Let's check whether we still have some bytes to encode */ - switch (psrc - bsrc.length) { - case 0: /* Two bytes left to encode */ - temp = ((bsrc[psrc - 2] & 0xFF) << 8) | (bsrc[psrc - 1] & 0xFF); - bdst[pdst ++] = ALPHABET[(temp >> 10) & 0x3f]; - bdst[pdst ++] = ALPHABET[(temp >> 4) & 0x3f]; - bdst[pdst ++] = ALPHABET[(temp << 2) & 0x3c]; - bdst[pdst ++] = ALPHABET[64]; - break; - case 1: /* One byte left to encode */ - temp = (bsrc[psrc - 2] & 0xFF); - bdst[pdst ++] = ALPHABET[(temp >> 2) & 0x3f]; - bdst[pdst ++] = ALPHABET[(temp << 4) & 0x30]; - bdst[pdst ++] = ALPHABET[64]; - bdst[pdst ++] = ALPHABET[64]; - } - - /* Convert the character array into a proper string */ - return new String(bdst); - } - - /** - * <p>Encode the specified string in base 64 using the default encoding.</p> - */ - public static final String base64Encode(String string) { - try { - return (base64Encode(string, DEFAULT_ENCODING)); - } catch (UnsupportedEncodingException exception) { - final String message = "Unsupported encoding " + DEFAULT_ENCODING; - final InternalError error = new InternalError(message); - throw (InternalError) error.initCause(exception); - } - } - - /** - * <p>Decode the specified base 64 string using the specified encoding.</p> - */ - public static final String base64Decode(String string, String encoding) - throws UnsupportedEncodingException { - /* Check the source string for null or the empty string. */ - if (string == null) return (null); - if (string.length() == 0) return ""; - - /* Check the encoding */ - if (encoding == null) encoding = DEFAULT_ENCODING; - - /* Retrieve the array of characters of the source string. */ - final char characters[] = string.toCharArray(); - - /* Check the length, which must be dividible by 4. */ - if ((characters.length & 0x03) != 0) - throw new IllegalArgumentException("Invalid length for the "+ - "encoded string (" + characters.length + ")"); - - /* The bytes array length is 3/4th of the characters array length */ - byte bytes[] = new byte[characters.length - (characters.length >> 2)]; - - /* - * Since this might take a while check now for the last 4 characters - * token: it must contain at most two == and those need to be in the - * last two positions in the array (the only valid sequences are: - * "????", "???=" and "??=="). - */ - if (((characters[characters.length - 4] == '=') || - (characters[characters.length - 3] == '=')) || - ((characters[characters.length - 2] == '=') && - (characters[characters.length - 1] != '='))) { - throw new IllegalArgumentException("Invalid pattern for last " + - "Base64 token in string to decode: " + - characters[characters.length - 4] + - characters[characters.length - 3] + - characters[characters.length - 2] + - characters[characters.length - 1]); - } - - /* Translate the Base64-encoded String in chunks of 4 characters. */ - int coff = 0; - int boff = 0; - while (coff < characters.length) { - boolean last = (coff == (characters.length - 4)); - int curr = ((value(characters[coff ], last) << 0x12) | - (value(characters[coff + 1], last) << 0x0c) | - (value(characters[coff + 2], last) << 0x06) | - (value(characters[coff + 3], last) )); - bytes[boff + 2] = (byte)((curr ) & 0xff); - bytes[boff + 1] = (byte)((curr >> 0x08) & 0xff); - bytes[boff ] = (byte)((curr >> 0x10) & 0xff); - coff += 4; - boff += 3; - } - - /* Get the real decoded string length, checking out the trailing '=' */ - if (characters[coff - 1] == '=') boff--; - if (characters[coff - 2] == '=') boff--; - - /* All done */ - return (new String(bytes, 0, boff, encoding)); - } - - /** - * <p>Decode the specified base 64 string using the default encoding.</p> - */ - public static final String base64Decode(String string) { - try { - return (base64Decode(string, DEFAULT_ENCODING)); - } catch (UnsupportedEncodingException exception) { - final String message = "Unsupported encoding " + DEFAULT_ENCODING; - final InternalError error = new InternalError(message); - throw (InternalError) error.initCause(exception); - } - } - - /* ====================================================================== */ - - /** <p>Retrieve the offset of a character in the base 64 alphabet.</p> */ - private static final int value(char character, boolean last) { - for (int x = 0; x < 64; x++) if (ALPHABET[x] == character) return (x); - if (last && (character == ALPHABET[65])) return(0); - final String message = "Character \"" + character + "\" invalid"; - throw new IllegalArgumentException(message); - } -} diff --git a/archiva-modules/archiva-web/archiva-webdav/src/main/java/it/could/util/encoding/package.html b/archiva-modules/archiva-web/archiva-webdav/src/main/java/it/could/util/encoding/package.html deleted file mode 100644 index 675ba3f58..000000000 --- a/archiva-modules/archiva-web/archiva-webdav/src/main/java/it/could/util/encoding/package.html +++ /dev/null @@ -1,61 +0,0 @@ -<html> - <head> - <title>Encoding Utilities</title> - </head> - <body> - <p> - This package contains a number of utility classes dealing with generic - encoding of {@link java.lang.String}s. - </p> - <p> - Although this might sound useless at first (as {@link java.lang.String}s - do support encoding internally already), this class deals with a very - subtle problem encountered when merging Java {@link java.lang.String}s - and old byte-based (non internationalized) transports, such as - Base 64 and URL encoding. - </p> - <p> - Let's consider (as an example) the URL encoded {@link java.lang.String} - <code>%C2%A3 100</code> can be easily decomposed in a byte array using - URL decoding techniques: we would end up with the following byte array: - <code>0x0C2 0x0A3 0x20 0x31 0x30 0x30</code>. - </p> - <p> - This byte-array, though, doesn't tell us anything about how to represent - this as a readable and usable {@link java.lang.String} in Java. To be - able to convert this we have to decode it again using a charset (or an - encoding). - </p> - <p> - So, for example, if we were to decode the above mentioned byte array using - the <b>ISO-8859-1</b> encoding, we would obtain the string - "<code>£ 100</code>", or in details: - </p> - <ul> - <li>a latin capital letter "A" with a circumflex accent</li> - <li>the pound sign</li> - <li>a space</li> - <li>the number 1</li> - <li>the number 0</li> - <li>the number 0</li> - </ul> - <p> - If we were to decode the same byte sequence using <b>UTF-8</b>, on the - other hand, we would obtain the (quite different) string - "<code>£ 100</code>", or in details: - </p> - <ul> - <li>the pound sign</li> - <li>a space</li> - <li>the number 1</li> - <li>the number 0</li> - <li>the number 0</li> - </ul> - <p> - Therefore, as a conclusion, when Java {@link java.lang.String}s are - encoded using Base 64, URL encoding, or similar techiques, one always - have to remember that encoding (or decoding) must be done twice, and - this package provides a way to deal with this mechanism. - </p> - </body> -</html>
\ No newline at end of file diff --git a/archiva-modules/archiva-web/archiva-webdav/src/main/java/it/could/util/http/HttpClient.java b/archiva-modules/archiva-web/archiva-webdav/src/main/java/it/could/util/http/HttpClient.java deleted file mode 100644 index 75884e0a2..000000000 --- a/archiva-modules/archiva-web/archiva-webdav/src/main/java/it/could/util/http/HttpClient.java +++ /dev/null @@ -1,1070 +0,0 @@ -/* ========================================================================== * - * 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.http; - -import it.could.util.encoding.EncodingTools; -import it.could.util.location.Location; - -import java.io.IOException; -import java.io.InputStream; -import java.io.OutputStream; -import java.io.UnsupportedEncodingException; -import java.net.MalformedURLException; -import java.net.Socket; -import java.util.ArrayList; -import java.util.Collections; -import java.util.HashMap; -import java.util.Iterator; -import java.util.List; -import java.util.Map; - -/** - * <p>A class implementing an extremely simple HTTP 1.0 connector with - * basic authentication support.</p> - * - * @author <a href="http://could.it/">Pier Fumagalli</a> - */ -public class HttpClient { - - /** <p>The default HTTP method to use.</p> */ - public static final String DEFAULT_METHOD = "GET"; - - /* ====================================================================== */ - - /** <p>The byte sequence CR LF (the end of the request).</p> */ - private static final byte CRLF[] = { 0x0d, 0x0a }; - /** <p>The byte sequence for " HTTP/1.0\r\n" (the request signature).</p> */ - private static final byte HTTP[] = { 0x20, 0x48, 0x54, 0x54, 0x50, 0x2f, - 0x31, 0x2e, 0x30, 0x0d, 0x0a }; - - /* ====================================================================== */ - - /** <p>The buffer used to parse lines in the response.</p> */ - private final byte buffer[] = new byte[4096]; - /** <p>The map of the current request headers.</p> */ - private final Map requestHeaders = new HashMap(); - /** <p>The map of the current response headers.</p> */ - private final Map responseHeaders = new HashMap(); - - /* ====================================================================== */ - - /** <p>The {@link Location} pointing to the current request.</p> */ - private Location location; - /** <p>The status of the current request.</p> */ - private Status status = null; - /** <p>An array of acceptable statuses to verify upon connection.</p> */ - private int acceptable[] = null; - - /* ====================================================================== */ - - /** <p>The limited input stream associated with this request.</p> */ - private Input xinput = null; - /** <p>The limited output stream associated with this request.</p> */ - private Output xoutput = null; - /** <p>The socket associated with this request.</p> */ - private Socket xsocket = null; - - /* ====================================================================== */ - - /** - * <p>Create a new {@link HttpClient} instance associated with the - * specified location in string format.</p> - * - * @throws MalformedURLException if the location couldn't be parsed. - */ - public HttpClient(String location) - throws MalformedURLException { - this.location = Location.parse(location); - } - - /** - * <p>Create a new {@link HttpClient} instance associated with the - * specified location in string format.</p> - * - * @throws MalformedURLException if the location couldn't be parsed. - */ - public HttpClient(String location, String encoding) - throws MalformedURLException, UnsupportedEncodingException { - this.location = Location.parse(location, encoding); - } - - /** - * <p>Create a new {@link HttpClient} instance associated with the - * specified {@link Location}.</p> - */ - public HttpClient(Location location) { - if (location == null) throw new NullPointerException("Null location"); - if (! location.isAbsolute()) - throw new IllegalArgumentException("Relative location supplied"); - if (! "http".equals(location.getSchemes().toString())) { - throw new IllegalArgumentException("Scheme is not HTTP"); - } - this.location = location; - } - - /* ====================================================================== */ - /* CONNECTION VERIFICATION METHODS */ - /* ====================================================================== */ - - /** - * <p>Set an HTTP response status code considered to be acceptable when - * verifying the connection.</p> - */ - public HttpClient setAcceptableStatus(int status) { - return this.setAcceptableStatuses(new int[] { status }); - } - - /** - * <p>Set an array of HTTP response status codes considered to be acceptable - * when verifying the connection.</p> - * - * <p>If the array is <b>null</b> status code checking is disabled.</p> - */ - public HttpClient setAcceptableStatuses(int statuses[]) { - if (statuses == null) { - this.acceptable = null; - return this; - } - for (int x = 0; x < statuses.length; x ++) { - final int status = statuses[x]; - if ((status < 100) || (status > 599)) - throw new IllegalArgumentException("Wrong status " + status); - } - this.acceptable = statuses; - return this; - } - - /* ====================================================================== */ - /* CONNECTION METHODS */ - /* ====================================================================== */ - - /** - * <p>Connect to the {@link Location} specified at construction using the - * default method <code>GET</code>.</p> - * - * <p>This is equivalent to {@link #connect(boolean) connect(true)}.</p> - * - * @return this {@link HttpClient} instance. - * @throws IOException if an I/O or a network error occurred. - */ - public HttpClient connect() - throws IOException { - return this.connect(DEFAULT_METHOD, true, 0); - } - - /** - * <p>Connect to the {@link Location} specified at construction using the - * default method <code>GET</code> allowing for a specified amount of - * content to be written into the request.</p> - * - * @return this {@link HttpClient} instance. - * @throws IOException if an I/O or a network error occurred. - */ - public HttpClient connect(long contentLength) - throws IOException { - return this.connect(DEFAULT_METHOD, false, contentLength); - } - - /** - * <p>Connect to the {@link Location} specified at construction using the - * default method <code>GET</code> and optionally following redirects.</p> - * - * @return this {@link HttpClient} instance. - * @throws IOException if an I/O or a network error occurred. - */ - public HttpClient connect(boolean followRedirects) - throws IOException { - return this.connect(DEFAULT_METHOD, followRedirects, 0); - } - - /** - * <p>Connect to the {@link Location} specified at construction with the - * specified method.</p> - * - * <p>This is equivalent to {@link #connect(String,boolean) - * connect(method, true)}.</p> - * - * @return this {@link HttpClient} instance. - * @throws IOException if an I/O or a network error occurred. - */ - public HttpClient connect(String method) - throws IOException { - return this.connect(method, true, 0); - } - - /** - * <p>Connect to the {@link Location} specified at construction with the - * specified method allowing for a specified amount of content to be - * written into the request.</p> - * - * @return this {@link HttpClient} instance. - * @throws IOException if an I/O or a network error occurred. - */ - public HttpClient connect(String method, long contentLength) - throws IOException { - return this.connect(method, false, contentLength); - } - - /** - * <p>Connect to the {@link Location} specified at construction with the - * specified method and optionally following redirects.</p> - * - * @return this {@link HttpClient} instance. - * @throws IOException if an I/O or a network error occurred. - */ - public HttpClient connect(String method, boolean followRedirects) - throws IOException { - return this.connect(method, followRedirects, 0); - } - - /** - * <p>Disconnect from the remote endpoint and terminate the request.</p> - * - * <p>Note that request and response headers, the resultin status and - * acceptable statuses are <b>not</b> cleared by this method.</p> - * - * @return this {@link HttpClient} instance. - * @throws IOException if an I/O or a network error occurred. - */ - public HttpClient disconnect() - throws IOException { - return this.disconnect(false); - } - - /** - * <p>Disconnect from the remote endpoint and terminate the request.</p> - * - * @param reset whether to reset all headers, status and acceptable response - * status codes or not. - * @return this {@link HttpClient} instance. - * @throws IOException if an I/O or a network error occurred. - */ - public HttpClient disconnect(boolean reset) - throws IOException { - final Socket socket = this.xsocket; - if (socket != null) try { - /* Make sure that we mark this instance as being closed */ - this.xsocket = null; - - /* Close the input stream if necessary */ - if (this.xinput != null) { - if (! this.xinput.closed) this.xinput.close(); - this.xinput = null; - } - - /* Close the output stream if necessary */ - if (this.xoutput != null) { - if (! this.xoutput.closed) this.xoutput.close(); - this.xoutput = null; - } - - } finally { - /* Ensure that the socket is closed */ - socket.close(); - } - - if (reset) { - this.requestHeaders.clear(); - this.responseHeaders.clear(); - this.status = null; - this.acceptable = null; - } - return this; - } - - /* ====================================================================== */ - /* INTERNAL CONNECTION HANDLER */ - /* ====================================================================== */ - - /** - * <p>Internal method actually connecting to the remote HTTP server.</p> - */ - private HttpClient connect(String method, boolean redirect, long length) - throws IOException { - /* Check if (by any chance) we have been connected already */ - if (this.xsocket != null) - throw new IllegalStateException("Already connected"); - - /* Check for both follow redirects and content length */ - if (length < 0) throw new IOException("Negative length"); - if ((length > 0) && redirect) - throw new InternalError("Can't follow redirects and write request"); - - /* Verify any authentication token */ - final String userinfo = this.location.getAuthority().getUserInfo(); - if (userinfo != null) { - final String encoded = EncodingTools.base64Encode(userinfo); - this.addRequestHeader("Authorization", "Basic " + encoded); - } - - /* All methods in HTTP are upper case */ - method = method.toUpperCase(); - - /* Make sure we close the connection at the end of the request */ - this.addRequestHeader("Connection", "close", false); - - /* The content length of the request is forced to be valid */ - this.addRequestHeader("Content-Length", Long.toString(length), false); - - /* Enter in a loop for redirections */ - int redirs = 20; - while (true) { - /* If we have been redirected too many times, fail */ - if ((--redirs) < 0) throw new IOException("Too many redirections"); - - /* Get the authority, once and for all */ - final Location.Authority auth = this.location.getAuthority(); - - /* Prepare a normalized host header */ - final String host = auth.getHost(); - final int port = auth.getPort() < 0 ? 80 : auth.getPort(); - this.addRequestHeader("Host", host + ":" + port, false); - - /* Connect to the remote endpoint */ - final Socket sock = new Socket(auth.getHost(), port); - final InputStream in = sock.getInputStream(); - final OutputStream out = sock.getOutputStream(); - - /* Write the request line */ - out.write((method + " ").getBytes("US-ASCII")); - out.write(this.location.getPath().toString().getBytes("US-ASCII")); - out.write(HTTP); /* SPACE HTTP/1.0 CR LF */ - - /* Write all the headers */ - final Iterator headers = this.requestHeaders.values().iterator(); - while (headers.hasNext()) { - final RequestHeader header = (RequestHeader) headers.next(); - final Iterator values = header.values.iterator(); - while (values.hasNext()) { - out.write(header.name); - out.write((byte []) values.next()); - } - } - - /* Write the final CRLF, read the status and the headers */ - out.write(CRLF); - out.flush(); - - /* Return now if we have to write content */ - if (length > 0) { - this.xsocket = sock; - this.xoutput = new Output(this, in, out, length); - this.xinput = null; - return this; - } - - this.readStatusLine(in); - this.readHeaders(in); - - /* If we have to follow redirects, let's inspect the response */ - final int code = this.status.status; - if (redirect && ((code == 301) || (code == 302) || (code == 307))) { - final String location = this.getResponseHeader("Location"); - if (location != null) { - in.close(); - out.close(); - sock.close(); - this.location = this.location.resolve(location); - continue; - } - } - - /* No further redirections, so verify if the status code is ok */ - this.verify(); - - /* Evaluate the content length specified by the server */ - final String len = this.getResponseHeader("Content-Length"); - long bytesLength = -1; - if (len != null) try { - bytesLength = Long.parseLong(len); - } catch (NumberFormatException exception) { - /* Swallow this, be liberal in what we accept */ - } - - /* Return an output stream if the content length was not zero */ - this.xsocket = sock; - this.xoutput = null; - this.xinput = new Input(this, in, bytesLength); - return this; - } - } - - private void verify() - throws IOException { - /* No further redirections, sov erify if the status code is ok */ - if (this.acceptable != null) { - boolean accepted = false; - for (int x = 0; x < this.acceptable.length; x ++) { - if (this.status.status != this.acceptable[x]) continue; - accepted = true; - break; - } - if (! accepted) { - this.disconnect(); - throw new IOException("Connection to " + this.location + - " returned unacceptable status " + - this.status.status + " (" + - this.status.message + ")"); - } - } - } - - /* ====================================================================== */ - /* INPUT / OUTPUT METHODS */ - /* ====================================================================== */ - - /** - * <p>Return an {@link InputStream} where the content of the HTTP response - * can be read from.</p> - * - * @throws IllegalStateException if this instance is not connected yet, or - * the request body was not fully written yet. - */ - public InputStream getResponseStream() - throws IllegalStateException { - if (this.xsocket == null) - throw new IllegalStateException("Connection not available"); - if ((this.xoutput != null) && (this.xoutput.remaining != 0)) - throw new IllegalStateException("Request body not fully written"); - return this.xinput; - } - - /** - * <p>Return an {@link OutputStream} where the content of the HTTP request - * can be written to.</p> - * - * @throws IllegalStateException if this instance is not connected yet or if - * upon connection the size of the request was - * not specifed or <b>zero</b>. - */ - public OutputStream getRequestStream() - throws IllegalStateException { - if (this.xsocket == null) - throw new IllegalStateException("Connection not available"); - if (this.xoutput == null) - throw new IllegalStateException("No request body to write to"); - return this.xoutput; - } - - /* ====================================================================== */ - /* REQUEST AND RESPONSE METHODS */ - /* ====================================================================== */ - - /** - * <p>Return the {@link Location} of this connection.</p> - * - * <p>This might be different from the {@link Location} specified at - * construction time if upon connecting HTTP redirections were followed.</p> - */ - public Location getLocation() { - return this.location; - } - - /** - * <p>Add a new header that will be sent with the HTTP request.</p> - * - * <p>This method will remove any header value previously associated with - * the specified name, in other words this method is equivalent to - * {@link #addRequestHeader(String, String, boolean) - * addRequestHeader(name, value, false)}.</p> - * - * @param name the name of the request header to add. - * @param value the value of the request header to add. - * @return this {@link HttpClient} instance. - * @throws NullPointerException the name or value were <b>null</b>. - */ - public HttpClient addRequestHeader(String name, String value) { - return this.addRequestHeader(name, value, false); - } - - /** - * <p>Add a new header that will be sent with the HTTP request.</p> - * - * @param name the name of the request header to add. - * @param value the value of the request header to add. - * @param appendValue if the current value should be appended, or in other - * words, that two headers with the same can coexist. - * @return this {@link HttpClient} instance. - * @throws NullPointerException the name or value were <b>null</b>. - */ - public HttpClient addRequestHeader(String name, String value, - boolean appendValue) { - final String key = name.toLowerCase(); - try { - RequestHeader header; - if (appendValue) { - header = (RequestHeader) this.requestHeaders.get(key); - if (header == null) { - header = new RequestHeader(name); - this.requestHeaders.put(key, header); - } - } else { - header = new RequestHeader(name); - this.requestHeaders.put(key, header); - } - header.values.add((value + "\r\n").getBytes("ISO-8859-1")); - return this; - } catch (UnsupportedEncodingException exception) { - Error error = new InternalError("Standard encoding not supported"); - throw (InternalError) error.initCause(exception); - } - } - - /** - * <p>Remove the named header from the current HTTP request.</p> - * - * @param name the name of the request header to add. - * @return this {@link HttpClient} instance. - * @throws NullPointerException the name was <b>null</b>. - */ - public HttpClient removeRequestHeader(String name) { - final String key = name.toLowerCase(); - this.requestHeaders.remove(key); - return this; - } - - /** - * <p>Remove all headers from the current HTTP request.</p> - * - * @return this {@link HttpClient} instance. - */ - public HttpClient removeRequestHeaders() { - this.requestHeaders.clear(); - return this; - } - - /** - * <p>Return the first value for the specified response header.</p> - * - * @param name the name of the header whose value needs to be returned. - * @return a {@link String} or <b>null</b> if no such header exists. - */ - public String getResponseHeader(String name) { - final String key = name.toLowerCase(); - ResponseHeader header = (ResponseHeader) this.responseHeaders.get(key); - if (header == null) return null; - return (String) header.values.get(0); - } - - /** - * <p>Return all the values for the specified response header.</p> - * - * @param name the name of the header whose values needs to be returned. - * @return a {@link List} or <b>null</b> if no such header exists. - */ - public List getResponseHeaderValues(String name) { - final String key = name.toLowerCase(); - ResponseHeader header = (ResponseHeader) this.responseHeaders.get(key); - if (header == null) return null; - return Collections.unmodifiableList(header.values); - } - - /** - * <p>Return an {@link Iterator} over all response header names.</p> - * - * @return a <b>non-null</b> {@link Iterator}. - */ - public Iterator getResponseHeaderNames() { - final Iterator iterator = this.responseHeaders.values().iterator(); - return new Iterator() { - public boolean hasNext() { - return iterator.hasNext(); - } - public Object next() { - return ((ResponseHeader) iterator.next()).name; - } - public void remove() { - throw new UnsupportedOperationException(); - } - }; - } - - /** - * <p>Return the protocol returned by the remote HTTP server.</p> - * - * @return a <b>non-null</b> {@link String} like <code>HTTP/1.0</code>. - * @throws IllegalStateException if the connection was never connected. - */ - public String getResponseProtocol() { - if (this.status == null) throw new IllegalStateException(); - return this.status.protocol; - } - - /** - * <p>Return the status returned by the remote HTTP server.</p> - * - * @return a number representing the HTTP status of the response. - * @throws IllegalStateException if the connection was never connected. - */ - public int getResponseStatus() { - if (this.status == null) throw new IllegalStateException(); - return this.status.status; - } - - /** - * <p>Return the status message returned by the remote HTTP server.</p> - * - * @return a <b>non-null</b> {@link String} like <code>OK</code>. - * @throws IllegalStateException if the connection was never connected. - */ - public String getResponseMessage() { - if (this.status == null) throw new IllegalStateException(); - return this.status.message; - } - - /* ====================================================================== */ - /* PRIVATE METHODS TO USE WHEN CONNECTING */ - /* ====================================================================== */ - - /** - * <p>Read a single line of the HTTP response from the specified - * {@link InputStream} into a byte array (trailing CRLF are removed).</p> - */ - private byte[] readLine(InputStream input) - throws IOException { - int x = 0; - while (true) { - int b = input.read(); - if (b == -1) break; - if (b == 0x0A) break; - if (x == this.buffer.length) break; - this.buffer[x ++] = (byte) b; - } - if ((x > 0) && (this.buffer[x - 1] == 0x0D)) x--; - final byte array[] = new byte[x]; - System.arraycopy(this.buffer, 0, array, 0, x); - return array; - } - - /** - * <p>Read the status line from the specified {@link InputStream} and - * setup the {@link #status} field.</p> - */ - private void readStatusLine(InputStream input) - throws IOException { - /* Prepare the different buffers required for parsing */ - final byte line[] = this.readLine(input); - final byte buff[] = new byte[line.length]; - final String comp[] = new String[3]; - int lpos = 0; - int bpos = 0; - int cpos = 0; - boolean spc = true; - - /* Iterate every single byte in the line, splitting up components */ - while (lpos < line.length) { - final byte b = line[lpos ++]; - if (spc) { - if ((b == 0x09) || (b == 0x20)) continue; - buff[bpos ++] = b; - if (cpos == 2) break; - else spc = false; - } else { - if ((b == 0x09) || (b == 0x20)) { - comp[cpos ++] = new String(buff, 0, bpos, "US-ASCII"); - bpos = 0; - spc = true; - continue; - } - buff[bpos ++] = b; - } - - } - /* - * Copy remaining bytes out of the line buffer and ensure all - * components in the status line are not null; - */ - while (lpos < line.length) buff[bpos ++] = line[lpos++]; - if (bpos > 0) comp[cpos++] = new String(buff, 0, bpos, "US-ASCII"); - for (int x = cpos; x < 3; x++) comp[x] = ""; - - /* Create the status object */ - this.status = new Status(comp[0], comp[1], comp[2]); - } - - /** - * <p>Read all the response headers from the specified {@link InputStream} - * and setup the {@link #responseHeaders} field.</p> - */ - private void readHeaders(InputStream input) - throws IOException { - /* Clear out any previous header */ - this.responseHeaders.clear(); - - /* Process the input stream until we find an empty line */ - while (true) { - final byte array[] = this.readLine(input); - if (array.length == 0) break; - - /* Identify where the colon is in the header */ - int pos = -1; - while (pos < array.length) if (array[++ pos] == 0x03A) break; - if (pos == 0) continue; - if (pos == array.length - 1) continue; - - /* Prepare strings for name and value */ - final int o = pos + 1; - final int l = array.length - o; - final String name = new String(array, 0, pos, "US-ASCII").trim(); - final String value = new String(array, o, l, "ISO-8859-1").trim(); - if ((name.length() == 0) || (value.length() == 0)) continue; - - /* Store the header value in a list for now */ - final String key = name.toLowerCase(); - ResponseHeader hdr = (ResponseHeader) this.responseHeaders.get(key); - if (hdr == null) { - hdr = new ResponseHeader(name); - this.responseHeaders.put(key, hdr); - } - hdr.values.add(value); - } - } - - /* ====================================================================== */ - /* INTERNAL CLASS REPRESENTNG THE STATUS LINE AND AN ENCODED HEADER */ - /* ====================================================================== */ - - /** - * <p>A simple internal class representing a response status line.</p> - */ - private static final class Status { - - /** <p>The response protocol, like <code>HTTP/1.0</code> */ - private final String protocol; - /** <p>The response status code, like <code>302</code> */ - private final int status; - /** <p>The response message, like <code>Moved permanently</code> */ - private final String message; - - /** - * <p>Create a new {@link Status} verifying the supplied parameters.</p> - * - * @throws IOException if an error occurred verifying the parameters. - */ - private Status(String protocol, String status, String message) - throws IOException { - - /* Verify the protocol */ - if ("HTTP/1.0".equals(protocol) || "HTTP/1.1".equals(protocol)) { - this.protocol = protocol; - } else { - throw new IOException("Unknown protocol \"" + protocol + "\""); - } - - /* Verify the status */ - try { - this.status = Integer.parseInt(status); - if ((this.status < 100) || (this.status > 599)) { - throw new IOException("Invalid status \"" + status + "\""); - } - } catch (RuntimeException exception) { - final String error = "Can't parse status \"" + status + "\""; - IOException throwable = new IOException(error); - throw (IOException) throwable.initCause(exception); - } - - /* Decode the message */ - if ("".equals(message)) this.message = "No message"; - else this.message = EncodingTools.urlDecode(message, "ISO-8859-1"); - } - } - - /** - * <p>A simple internal class representing a request header.</p> - */ - private static final class RequestHeader { - - /** <p>The byte array of the header's name.</p> */ - private final byte name[]; - /** <p>A {@link List} of all the header's values.</p> */ - private final List values; - - /** <p>Create a new {@link RequestHeader} instance.</p> */ - private RequestHeader(String name) - throws UnsupportedEncodingException { - this.name = (name + ": ").getBytes("US-ASCII"); - this.values = new ArrayList(); - } - } - - /** - * <p>A simple internal class representing a response header.</p> - */ - private static final class ResponseHeader { - - /** <p>The real name of the response header.</p> */ - private final String name; - /** <p>A {@link List} of all the header's values.</p> */ - private final List values; - - /** <p>Create a new {@link ResponseHeader} instance.</p> */ - private ResponseHeader(String name) - throws UnsupportedEncodingException { - this.name = name; - this.values = new ArrayList(); - } - } - - /* ====================================================================== */ - /* LIMITED STREAMS */ - /* ====================================================================== */ - - /** - * <p>A simple {@link OutputStream} writing at most the number of bytes - * specified at construction.</p> - */ - private static final class Output extends OutputStream { - - /** <p>The {@link OutputStream} wrapped by this instance.</p> */ - private final OutputStream output; - /** <p>The {@link InputStream} wrapped by this instance.</p> */ - private final InputStream input; - /** <p>The {@link HttpClient} wrapped by this instance.</p> */ - private final HttpClient client; - /** <p>The number of bytes yet to write.</p> */ - private long remaining; - /** <p>A flag indicating whether this instance was closed.</p> */ - private boolean closed; - - /** - * <p>Create a new {@link Output} instance with the specified limit - * of bytes to write.</p> - * - * @param output the {@link OutputStream} to wrap. - * @param remainig the maximum number of bytes to write. - */ - private Output(HttpClient client, InputStream input, - OutputStream output, long remaining) { - if (input == null) throw new NullPointerException(); - if (output == null) throw new NullPointerException(); - if (client == null) throw new NullPointerException(); - this.remaining = remaining; - this.client = client; - this.output = output; - this.input = input; - } - - public void write(byte buf[]) - throws IOException { - this.write(buf, 0, buf.length); - } - - public void write(byte buf[], int off, int len) - throws IOException { - if (len > this.remaining) { - throw new IOException("Too much data to write"); - } else try { - this.output.write(buf, off, len); - } finally { - this.remaining -= len; - if (this.remaining < 1) this.close(); - } - } - - public void write(int b) - throws IOException { - if (this.remaining < 1) { - throw new IOException("Too much data to write"); - } else try { - this.output.write(b); - } finally { - this.remaining -= 1; - if (this.remaining < 1) this.close(); - } - } - - public void flush() - throws IOException { - this.output.flush(); - } - - public void close() - throws IOException { - if (this.closed) return; - if (this.remaining > 0) - throw new IOException(this.remaining + " bytes left to write"); - this.closed = true; - this.output.flush(); - - /* Read the status and headers from the connection and verify */ - this.client.readStatusLine(this.input); - this.client.readHeaders(this.input); - this.client.verify(); - - /* Evaluate the content length specified by the server */ - final String slen = this.client.getResponseHeader("Content-Length"); - long blen = -1; - if (slen != null) try { - blen = Long.parseLong(slen); - } catch (NumberFormatException exception) { - /* Swallow this, be liberal in what we accept */ - } - - /* Return an output stream if the content length was not zero */ - this.client.xoutput = null; - this.client.xinput = new Input(this.client, this.input, blen); - } - - protected void finalize() - throws Throwable { - try { - this.close(); - } finally { - super.finalize(); - } - } - } - - /** - * <p>A simple {@link InputStream} reading at most the number of bytes - * specified at construction.</p> - */ - private static final class Input extends InputStream { - - /** <p>The {@link InputStream} wrapped by this instance.</p> */ - private final InputStream input; - /** <p>The {@link HttpClient} wrapped by this instance.</p> */ - private final HttpClient client; - /** <p>The number of bytes yet to write or -1 if unknown.</p> */ - private long remaining; - /** <p>A flag indicating whether this instance was closed.</p> */ - private boolean closed; - - /** - * <p>Create a new {@link Input} instance with the specified limit - * of bytes to read.</p> - * - * @param input the {@link InputStream} to wrap. - * @param remainig the maximum number of bytes to read or -1 if unknown. - */ - private Input(HttpClient client, InputStream input, long remaining) { - if (input == null) throw new NullPointerException(); - if (client == null) throw new NullPointerException(); - this.remaining = remaining < 0 ? Long.MAX_VALUE : remaining; - this.client = client; - this.input = input; - } - - public int read() - throws IOException { - if (this.remaining < 1) { - return -1; - } else try { - return this.input.read(); - } finally { - this.remaining -= 1; - if (this.remaining < 1) this.close(); - } - } - - public int read(byte buf[]) - throws IOException { - return read(buf, 0, buf.length); - } - - public int read(byte buf[], int off, int len) - throws IOException { - if (this.remaining <= 0) return -1; - if (len > this.remaining) len = (int) this.remaining; - int count = 0; - try { - count = this.input.read(buf, off, len); - } finally { - this.remaining -= count; - if (this.remaining < 1) this.close(); - } - return count; - } - - public long skip(long n) - throws IOException { - if (this.remaining <= 0) return -1; - if (n > this.remaining) n = this.remaining; - long count = 0; - try { - count = this.input.skip(n); - } finally { - this.remaining -= count; - if (this.remaining < 1) this.close(); - } - return count; - } - - public int available() - throws IOException { - int count = this.input.available(); - if (count < this.remaining) return count; - return (int) this.remaining; - } - - public void close() - throws IOException { - if (this.closed) return; - this.closed = true; - try { - this.input.close(); - } finally { - this.client.disconnect(); - } - } - - public void mark(int readlimit) { - this.input.mark(readlimit); - } - - public void reset() - throws IOException { - this.input.reset(); - } - - public boolean markSupported() { - return this.input.markSupported(); - } - - protected void finalize() - throws Throwable { - try { - this.close(); - } finally { - super.finalize(); - } - } - } - - /* ====================================================================== */ - /* UTILITY FETCHER */ - /* ====================================================================== */ - - /** - * <p><b>Utility method:</b> fetch the location specified on the command - * line following redirects if necessary.</p> - * - * <p>The final location fetched (in case of redirections it might change) - * will be reported on the {@link System#err system error stream} alongside - * with any errors encountered while processing.</p> - */ - public static final void main(String args[]) { - try { - final HttpClient c = new HttpClient(args[0]).connect(); - final InputStream i = c.getResponseStream(); - for (int b = i.read(); b >= 0; b = i.read()) System.out.write(b); - c.disconnect(); - } catch (Throwable throwable) { - throwable.printStackTrace(System.err); - } - } -} diff --git a/archiva-modules/archiva-web/archiva-webdav/src/main/java/it/could/util/http/WebDavClient.java b/archiva-modules/archiva-web/archiva-webdav/src/main/java/it/could/util/http/WebDavClient.java deleted file mode 100644 index fe0eba41b..000000000 --- a/archiva-modules/archiva-web/archiva-webdav/src/main/java/it/could/util/http/WebDavClient.java +++ /dev/null @@ -1,901 +0,0 @@ -/* ========================================================================== * - * 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.http; - -import it.could.util.StreamTools; -import it.could.util.StringTools; -import it.could.util.location.Location; -import it.could.util.location.Path; -import org.xml.sax.Attributes; -import org.xml.sax.InputSource; -import org.xml.sax.SAXException; -import org.xml.sax.helpers.DefaultHandler; - -import javax.xml.parsers.ParserConfigurationException; -import javax.xml.parsers.SAXParser; -import javax.xml.parsers.SAXParserFactory; -import java.io.BufferedOutputStream; -import java.io.BufferedReader; -import java.io.ByteArrayOutputStream; -import java.io.File; -import java.io.FileInputStream; -import java.io.FileOutputStream; -import java.io.IOException; -import java.io.InputStream; -import java.io.InputStreamReader; -import java.io.OutputStream; -import java.io.PrintStream; -import java.net.MalformedURLException; -import java.text.SimpleDateFormat; -import java.util.ArrayList; -import java.util.Collections; -import java.util.Date; -import java.util.HashMap; -import java.util.Iterator; -import java.util.List; -import java.util.Map; -import java.util.Stack; -import java.util.StringTokenizer; - -/** - * <p>A class implementing an extremely simple WebDAV Level 1 client based on - * the {@link HttpClient}.</p> - * - * <p>Once opened this class will represent a WebDAV collection. Users of this - * class can then from an instance of this, deal with relative parent and - * children resources.</p> - * - * @author <a href="http://could.it/">Pier Fumagalli</a> - */ -public class WebDavClient { - - /** <p>The WebDAV resource asociated with this instance.</p> */ - private Resource resource; - /** <p>A map of children resources of this instance.</p> */ - private Map children; - - /** - * <p>Create a new {@link WebDavClient} instance opening the collection - * identified by the specified {@link Location}.</p> - * - * @param location the {@link Location} of the WebDAV collection to open. - * @throws IOException if an I/O or network error occurred, or if the - * {@link Location} specified does not point to a - * WebDAV collection. - * @throws NullPointerException if the {@link Location} was <b>null</b>. - */ - public WebDavClient(Location location) - throws NullPointerException, IOException { - if (location == null) throw new NullPointerException("Null location"); - this.reload(location); - } - - /* ====================================================================== */ - /* ACTIONS */ - /* ====================================================================== */ - - /** - * <p>Refresh this {@link WebDavClient} instance re-connecting to the remote - * collection and re-reading its properties.</p> - * - * @return this {@link WebDavClient} instance. - */ - public WebDavClient refresh() - throws IOException { - this.reload(this.resource.location); - return this; - } - - /** - * <p>Fetch the contents of the specified child resource of the collection - * represented by this {@link WebDavClient} instance.</p> - * - * @see #isCollection(String) - * @return a <b>non-null</b> {@link InputStream}. - * @throws IOException if an I/O or network error occurred, or if the - * child specified represents a collection. - * @throws NullPointerException if the child was <b>null</b>. - */ - public InputStream get(String child) - throws NullPointerException, IOException { - if (child == null) throw new NullPointerException("Null child"); - if (! this.isCollection(child)) { - final Location location = this.getLocation(child); - final HttpClient client = new HttpClient(location); - client.setAcceptableStatus(200).connect("GET"); - return client.getResponseStream(); - } - throw new IOException("Child \"" + child + "\" is a collection"); - } - - /** - * <p>Delete the child resource (or collection) of the collection - * represented by this {@link WebDavClient} instance.</p> - * - * @return this {@link WebDavClient} instance. - * @throws IOException if an I/O or network error occurred, or if the - * child specified represents a collection. - * @throws NullPointerException if the child was <b>null</b>. - */ - public WebDavClient delete(String child) - throws NullPointerException, IOException { - if (child == null) throw new NullPointerException("Null child"); - final HttpClient client = new HttpClient(this.getLocation(child)); - client.setAcceptableStatus(204).connect("DELETE").disconnect(); - return this.refresh(); - } - - /** - * <p>Create a new collection as a child of the collection represented - * by this {@link WebDavClient} instance.</p> - * - * <p>In comparison to {@link #put(String)} and {@link #put(String, long)} - * this method will fail if the specified child already exist.</p> - * - * @see #hasChild(String) - * @return this {@link WebDavClient} instance. - * @throws IOException if an I/O or network error occurred, or if the - * child specified already exist. - * @throws NullPointerException if the child was <b>null</b>. - */ - public WebDavClient mkcol(String child) - throws NullPointerException, IOException { - if (child == null) throw new NullPointerException("Null child"); - if (this.hasChild(child)) - throw new IOException("Child \"" + child + "\" already exists"); - final Location location = this.resource.location.resolve(child); - final HttpClient client = new HttpClient(location); - client.setAcceptableStatus(201).connect("MKCOL").disconnect(); - return this.refresh(); - } - - /** - * <p>Create a new (or update the contents of a) child of of the collection - * represented by this {@link WebDavClient} instance.</p> - * - * <p>This method will behave exactly like the {@link #put(String, long)} - * method, but the data written to the returned {@link OutputStream} will - * be <i>buffered in memory</i> and will be transmitted to the remote - * server only when the {@link OutputStream#close()} method is called.</p> - * - * <p>If the returned {@link OutputStream} is garbage collected before the - * {@link OutputStream#close() close()} method is called, the entire - * transaction will be aborted and no connection to the remote server will - * be established.</p> - * - * <p>Use this method in extreme cases. In normal circumstances always rely - * on the {@link #put(String, long)} method.</p> - * - * @see #put(String, long) - * @return a <b>non-null</b> {@link OutputStream} instance. - * @throws NullPointerException if the child was <b>null</b>. - */ - public OutputStream put(final String child) - throws NullPointerException { - if (child == null) throw new NullPointerException("Null child"); - final WebDavClient client = this; - return new ByteArrayOutputStream() { - private boolean closed = false; - public void close() - throws IOException { - if (this.closed) return; - this.flush(); - OutputStream output = client.put(child, this.buf.length); - output.write(this.buf); - output.flush(); - output.close(); - } - - protected void finalize() - throws Throwable { - this.closed = true; - super.finalize(); - } - }; - } - - /** - * <p>Create a new (or update the contents of a) child of of the collection - * represented by this {@link WebDavClient} instance.</p> - * - * <p>If the specified child {@link #hasChild(String) already exists} on - * the remote server, it will be {@link #delete(String) deleted} before - * writing.</p> - * - * @return a <b>non-null</b> {@link OutputStream} instance. - * @throws NullPointerException if the child was <b>null</b>. - * @throws IOException if an I/O or network error occurred, or if the - * child specified already exist. - */ - public OutputStream put(String child, long length) - throws NullPointerException, IOException { - if (child == null) throw new NullPointerException("Null child"); - if (this.hasChild(child)) this.delete(child); - final Location location = this.resource.location.resolve(child); - final HttpClient client = new HttpClient(location); - client.setAcceptableStatuses(new int[] { 201, 204 }); - client.connect("PUT", length); - - final WebDavClient webdav = this; - return new BufferedOutputStream(client.getRequestStream()) { - boolean closed = false; - public void close() - throws IOException { - if (this.closed) return; - try { - super.close(); - } finally { - this.closed = true; - webdav.refresh(); - } - } - protected void finalize() - throws Throwable { - try { - this.close(); - } finally { - super.finalize(); - } - } - }; - } - - /** - * <p>Open the specified child collection of the collection represented by - * this {@link WebDavClient} as a new {@link WebDavClient} instance.</p> - * - * <p>If the specified child is "<code>.</code>" this method - * will behave exactly like {@link #refresh()} and <i>this instance</i> - * will be returned.</p> - * - * <p>If the specified child is "<code>..</code>" this method - * will behave exactly like {@link #parent()}.</p> - * - * @return a <b>non-null</b> {@link WebDavClient} instance. - * @throws NullPointerException if the child was <b>null</b>. - * @throws IOException if an I/O or network error occurred, or if the - * child specified did not exist. - */ - public WebDavClient open(String child) - throws NullPointerException, IOException { - if (child == null) throw new NullPointerException("Null child"); - if (".".equals(child)) return this.refresh(); - if ("..".equals(child)) return this.parent(); - if (resource.collection) { - Location loc = this.getLocation().resolve(this.getLocation(child)); - return new WebDavClient(loc); - } - throw new IOException("Child \"" + child + "\" is not a collection"); - } - - /** - * <p>Open the parent collection of the collection represented by this - * {@link WebDavClient} as a new {@link WebDavClient} instance.</p> - * - * @return a <b>non-null</b> {@link WebDavClient} instance. - * @throws IOException if an I/O or network error occurred, or if the - * child specified did not exist. - */ - public WebDavClient parent() - throws IOException { - final Location location = this.resource.location.resolve(".."); - return new WebDavClient(location); - } - - /* ====================================================================== */ - /* ACCESSOR METHODS */ - /* ====================================================================== */ - - /** - * <p>Return an {@link Iterator} over {@link String}s for all the children - * of the collection represented by this {@link WebDavClient} instance.</p> - */ - public Iterator iterator() { - return this.children.keySet().iterator(); - } - - /** - * <p>Checks if the collection represented by this {@link WebDavClient} - * contains the specified child.</p> - */ - public boolean hasChild(String child) { - return this.children.containsKey(child); - } - - /** - * <p>Return the {@link Location} associated with the collection - * represented by this {@link WebDavClient}.</p> - * - * <p>The returned {@link Location} can be different from the one specified - * at construction, in case the server redirected us upon connection.</p> - */ - public Location getLocation() { - return this.resource.location; - } - - /** - * <p>Return the content length (in bytes) of the collection represented - * by this {@link WebDavClient} as passed to us by the WebDAV server.</p> - */ - public long getContentLength() { - return this.resource.contentLength; - } - - /** - * <p>Return the content type (mime-type) of the collection represented - * by this {@link WebDavClient} as passed to us by the WebDAV server.</p> - */ - public String getContentType() { - return this.resource.contentType; - } - - /** - * <p>Return the last modified {@link Date} of the collection represented - * by this {@link WebDavClient} as passed to us by the WebDAV server.</p> - */ - public Date getLastModified() { - return this.resource.lastModified; - } - - /** - * <p>Return the creation {@link Date} of the collection represented - * by this {@link WebDavClient} as passed to us by the WebDAV server.</p> - */ - public Date getCreationDate() { - return this.resource.creationDate; - } - - /** - * <p>Return the {@link Location} associated with the specified child of - * the collection represented by this {@link WebDavClient}.</p> - * - * @throws IOException if the specified child does not exist. - * @throws NullPointerException if the specified child was <b>null</b>. - */ - public Location getLocation(String child) - throws IOException { - Location location = this.getResource(child).location; - return this.resource.location.resolve(location); - } - - /** - * <p>Checks if the specified child of the collection represented by this - * {@link WebDavClient} instance is a collection.</p> - */ - public boolean isCollection(String child) - throws IOException { - return this.getResource(child).collection; - } - - /** - * <p>Return the content length (in bytes) associated with the specified - * child of the collection represented by this {@link WebDavClient}.</p> - * - * @throws IOException if the specified child does not exist. - * @throws NullPointerException if the specified child was <b>null</b>. - */ - public long getContentLength(String child) - throws IOException { - return this.getResource(child).contentLength; - } - - /** - * <p>Return the content type (mime-type) associated with the specified - * child of the collection represented by this {@link WebDavClient}.</p> - * - * @throws IOException if the specified child does not exist. - * @throws NullPointerException if the specified child was <b>null</b>. - */ - public String getContentType(String child) - throws IOException { - return this.getResource(child).contentType; - } - - /** - * <p>Return the last modified {@link Date} associated with the specified - * child of the collection represented by this {@link WebDavClient}.</p> - * - * @throws IOException if the specified child does not exist. - * @throws NullPointerException if the specified child was <b>null</b>. - */ - public Date getLastModified(String child) - throws IOException { - return this.getResource(child).lastModified; - } - - /** - * <p>Return the creation {@link Date} associated with the specified - * child of the collection represented by this {@link WebDavClient}.</p> - * - * @throws IOException if the specified child does not exist. - * @throws NullPointerException if the specified child was <b>null</b>. - */ - public Date getCreationDate(String child) - throws IOException { - return this.getResource(child).creationDate; - } - - /* ====================================================================== */ - /* INTERNAL METHODS */ - /* ====================================================================== */ - - /** - * <p>Return the resource associated with the specified child.</p> - * - * @throws IOException if the specified child does not exist. - * @throws NullPointerException if the specified child was <b>null</b>. - */ - private Resource getResource(String child) - throws IOException { - if (child == null) throw new NullPointerException(); - final Resource resource = (Resource) this.children.get(child); - if (resource == null) throw new IOException("Not found: " + child); - return resource; - } - - /** - * <p>Contact the remote WebDAV server and fetch all properties.</p> - */ - private void reload(Location location) - throws IOException { - - /* Do an OPTIONS over onto the location */ - location = this.options(location); - - /* Do a PROPFIND to figure out the properties and the children */ - final Iterator iterator = this.propfind(location).iterator(); - final Map children = new HashMap(); - while (iterator.hasNext()) { - final Resource resource = (Resource) iterator.next(); - final Path path = resource.location.getPath(); - if (path.size() == 0) { - resource.location = location.resolve(resource.location); - this.resource = resource; - } else if (path.size() == 1) { - final Path.Element element = (Path.Element) path.get(0); - if ("..".equals(element.getName())) continue; - children.put(element.toString(), resource); - } - } - - /* Check if the current resource was discovered */ - if (this.resource == null) - throw new IOException("Current resource not returned in PROOPFIND"); - - /* Don't actually allow resources to be modified */ - this.children = Collections.unmodifiableMap(children); - } - - /** - * <p>Contact the remote WebDAV server and do an OPTIONS lookup.</p> - */ - private Location options(Location location) - throws IOException { - /* Create the new HttpClient instance associated with the location */ - final HttpClient client = new HttpClient(location); - client.setAcceptableStatus(200).connect("OPTIONS", true).disconnect(); - - /* Check that the remote server returned the "Dav" header */ - final List davHeader = client.getResponseHeaderValues("dav"); - if (davHeader == null) { - throw new IOException("Server did not respond with a DAV header"); - } - - /* Check if the OPTIONS request contained the DAV header */ - final Iterator iterator = davHeader.iterator(); - boolean foundLevel1 = false; - while (iterator.hasNext() && (! foundLevel1)) { - String value = (String) iterator.next(); - StringTokenizer tokenizer = new StringTokenizer(value, ","); - while (tokenizer.hasMoreTokens()) { - if (! "1".equals(tokenizer.nextToken().trim())) continue; - foundLevel1 = true; - break; - } - } - - /* Return the (possibly redirected) location or fail miserably */ - if (foundLevel1) return client.getLocation(); - throw new IOException("Server doesn't support DAV Level 1"); - } - - /** - * <p>Contact the remote WebDAV server and do a PROPFIND lookup, returning - * a {@link List} of all scavenged resources.</p> - */ - private List propfind(Location location) - throws IOException { - /* Create the new HttpClient instance associated with the location */ - final HttpClient client = new HttpClient(location); - client.addRequestHeader("Depth", "1"); - client.setAcceptableStatus(207).connect("PROPFIND", true); - - /* Get the XML SAX Parser and parse the output of the PROPFIND */ - try { - final SAXParserFactory factory = SAXParserFactory.newInstance(); - factory.setValidating(false); - factory.setNamespaceAware(true); - final SAXParser parser = factory.newSAXParser(); - final String systemId = location.toString(); - final InputSource source = new InputSource(systemId); - final Handler handler = new Handler(location); - source.setByteStream(client.getResponseStream()); - parser.parse(source, handler); - return handler.list; - - } catch (ParserConfigurationException exception) { - Exception throwable = new IOException("Error creating XML parser"); - throw (IOException) throwable.initCause(exception); - } catch (SAXException exception) { - Exception throwable = new IOException("Error creating XML parser"); - throw (IOException) throwable.initCause(exception); - } finally { - client.disconnect(); - } - } - - /* ====================================================================== */ - /* INTERNAL CLASSES */ - /* ====================================================================== */ - - /** - * <p>An internal XML {@link DefaultHandler} used to parse out the various - * details of a PROPFIND response.</p> - */ - private static final class Handler extends DefaultHandler { - - /* ================================================================== */ - /* PSEUDO-XPATH LOCATIONS FOR QUICK-AND-DIRTY LOCATION LOOKUP */ - /* ================================================================== */ - private static final String RESPONSE_PATH = "/multistatus/response"; - private static final String HREF_PATH = "/multistatus/response/href"; - private static final String COLLECTION_PATH = - "/multistatus/response/propstat/prop/resourcetype/collection"; - private static final String GETCONTENTTYPE_PATH = - "/multistatus/response/propstat/prop/getcontenttype"; - private static final String GETLASTMODIFIED_PATH = - "/multistatus/response/propstat/prop/getlastmodified"; - private static final String GETCONTENTLENGTH_PATH = - "/multistatus/response/propstat/prop/getcontentlength"; - private static final String CREATIONDATE_PATH = - "/multistatus/response/propstat/prop/creationdate"; - - /** <p>The {@link Location} for resolving all other links.</p> */ - private final Location base; - /** <p>The {@link List} of all scavenged resources.</p> */ - private final List list = new ArrayList(); - /** <p>The resource currently being processed.</p> */ - private Resource rsrc = null; - /** <p>A {@link StringBuffer} holding character data.</p> */ - private StringBuffer buff = null; - /** <p>A {@link Stack} for quick-and-dirty pseudo XPath lookups.</p> */ - private Stack stack = new Stack(); - - /** - * <p>Create a new instance specifying the base {@link Location}.</p> - */ - private Handler(Location location) { - this.base = location; - } - - /** - * <p>Push an element name in the stack for pseudo-XPath lookups.</p> - * - * @return a {@link String} like <code>/element/element/element</code>. - */ - private String pushPath(String path) { - this.stack.push(path.toLowerCase()); - final StringBuffer buffer = new StringBuffer(); - for (int x = 0; x < this.stack.size(); x ++) - buffer.append('/').append(this.stack.get(x)); - return buffer.toString(); - } - - /** - * <p>Pop the last element name from the pseudo-XPath lookup stack.</p> - * - * @return a {@link String} like <code>/element/element/element</code>. - */ - private String popPath(String path) - throws SAXException { - final StringBuffer buffer = new StringBuffer(); - final String last = (String) this.stack.pop(); - if (path.toLowerCase().equals(last)) { - for (int x = 0; x < this.stack.size(); x ++) - buffer.append('/').append(this.stack.get(x)); - return buffer.append('/').append(last).toString(); - } - throw new SAXException("Tag <" + path + "/> unbalanced at path \"" - + pushPath(last) + "\""); - } - - /** - * <p>Handle the start-of-element SAX event.</p> - */ - public void startElement(String uri, String l, String q, Attributes a) - throws SAXException { - if (! "DAV:".equals(uri.toUpperCase())) return; - final String path = this.pushPath(l); - - if (RESPONSE_PATH.equals(path)) { - this.rsrc = new Resource(); - - } else if (COLLECTION_PATH.equals(path)) { - if (this.rsrc != null) this.rsrc.collection = true; - - } else if (GETCONTENTTYPE_PATH.equals(path) || - GETLASTMODIFIED_PATH.equals(path) || - GETCONTENTLENGTH_PATH.equals(path) || - CREATIONDATE_PATH.equals(path) || - HREF_PATH.equals(path)) { - this.buff = new StringBuffer(); - } - } - - /** - * <p>Handle the end-of-element SAX event.</p> - */ - public void endElement(String uri, String l, String q) - throws SAXException { - if (! "DAV:".equals(uri.toUpperCase())) return; - final String path = this.popPath(l); - final String data = this.resetBuffer(); - - if (RESPONSE_PATH.equals(path)) { - if (this.rsrc != null) { - if (this.rsrc.location != null) { - if (this.rsrc.location.isAbsolute()) { - final String z = this.rsrc.location.toString(); - throw new SAXException("Unresolved location " + z); - } else { - this.list.add(this.rsrc); - } - } else { - throw new SAXException("Null location for resource"); - } - } - - } else if (HREF_PATH.equals(path)) { - if (this.rsrc != null) try { - final Location resolved = this.base.resolve(data); - this.rsrc.location = this.base.relativize(resolved); - if (! this.rsrc.location.isRelative()) - throw new SAXException("Unable to relativize location " - + this.rsrc.location); - } catch (MalformedURLException exception) { - final String msg = "Unable to resolve URL \"" + data + "\""; - SAXException throwable = new SAXException(msg, exception); - throw (SAXException) throwable.initCause(exception); - } - - } else if (CREATIONDATE_PATH.equals(path)) { - if (this.rsrc != null) - this.rsrc.creationDate = StringTools.parseIsoDate(data); - - } else if (GETCONTENTTYPE_PATH.equals(path)) { - if (this.rsrc != null) this.rsrc.contentType = data; - - } else if (GETLASTMODIFIED_PATH.equals(path)) { - if (this.rsrc != null) - this.rsrc.lastModified = StringTools.parseHttpDate(data); - - } else if (GETCONTENTLENGTH_PATH.equals(path)) { - if (this.rsrc != null) { - Long length = StringTools.parseNumber(data); - if (length != null) { - this.rsrc.contentLength = length.longValue(); - } - } - } - } - - /** - * <p>Handle SAX characters notification.</p> - */ - public void characters(char buffer[], int offset, int length) { - if (this.buff != null) this.buff.append(buffer, offset, length); - } - - /** - * <p>Reset the current characters buffer and return it as a - * {@link String}.</p> - */ - private String resetBuffer() { - if (this.buff == null) return null; - if (this.buff.length() == 0) { - this.buff = null; - return null; - } - final String value = this.buff.toString(); - this.buff = null; - return value; - } - } - - /** - * <p>A simple class holding the core resource properties.</p> - */ - private static class Resource { - private Location location = null; - private boolean collection = false; - private long contentLength = -1; - private String contentType = null; - private Date lastModified = null; - private Date creationDate = null; - } - - /* ====================================================================== */ - /* COMMAND LINE CLIENT */ - /* ====================================================================== */ - - /** - * <p>A command-line interface to a WebDAV repository.</p> - * - * <p>When invoked from the command line, this class requires one only - * argument, the URL location of the WebDAV repository to connect to.</p> - * - * <p>After connection this method will interact with the user using an - * extremely simple console-based interface.</p> - */ - public static void main(String args[]) - throws IOException { - final InputStreamReader r = new InputStreamReader(System.in); - final BufferedReader in = new BufferedReader(r); - WebDavClient client = new WebDavClient(Location.parse(args[0])); - - while (true) try { - System.out.print("[" + client.getLocation() + "] -> "); - args = parse(in.readLine()); - if (args == null) break; - if (args[0].equals("list")) { - if (args[1] == null) list(client, System.out); - else list(client.open(args[1]), System.out); - - } else if (args[0].equals("refresh")) { - client = client.refresh(); - - } else if (args[0].equals("get")) { - if (args[1] != null) { - final InputStream input = client.get(args[1]); - final File file = new File(args[2]).getCanonicalFile(); - final OutputStream output = new FileOutputStream(file); - final long bytes = StreamTools.copy(input, output); - System.out.println("Fetched child \"" + args[1] + - "\" to file \"" + file + "\" (" + - bytes + " bytes)"); - } - else System.out.print("Can't \"get\" null"); - - } else if (args[0].equals("put")) { - if (args[1] != null) { - final File file = new File(args[1]).getCanonicalFile(); - final InputStream input = new FileInputStream(file); - final OutputStream output = client.put(args[2], file.length()); - final long bytes = StreamTools.copy(input, output); - System.out.println("Uploaded file \"" + file + - "\" to child \"" + args[2] + "\" (" + - bytes + " bytes)"); - } - else System.out.print("Can't \"put\" null"); - - } else if (args[0].equals("mkcol")) { - if (args[1] != null) { - client.mkcol(args[1]); - System.out.println("Created \"" + args[1] + "\""); - } - else System.out.print("Can't \"mkcol\" null"); - - } else if (args[0].equals("delete")) { - if (args[1] != null) { - client.delete(args[1]); - System.out.println("Deleted \"" + args[1] + "\""); - } - else System.out.print("Can't \"delete\" null"); - - } else if (args[0].equals("cd")) { - if (args[1] != null) client = client.open(args[1]); - else System.out.print("Can't \"cd\" to null"); - - } else if (args[0].equals("quit")) { - break; - - } else { - System.out.print("Invalid command \"" + args[0] + "\". "); - System.out.println("Valid commands are:"); - System.out.println(" - \"list\" list the children child"); - System.out.println(" - \"get\" fetch the specified child"); - System.out.println(" - \"put\" put the specified child"); - System.out.println(" - \"mkcol\" create a collection"); - System.out.println(" - \"delete\" delete a child"); - System.out.println(" - \"put\" put the specified resource"); - System.out.println(" - \"cd\" change the location"); - System.out.println(" - \"refresh\" refresh this location"); - System.out.println(" - \"quit\" quit this application"); - } - } catch (Exception exception) { - exception.printStackTrace(System.err); - } - System.err.println(); - } - - /** - * <p>Parse a line entered by the user returning a three-tokens argument - * list (command, argument 1, argument 2)</p> - */ - private static String[] parse(String line) { - if (line == null) return null; - final String array[] = new String[3]; - final StringTokenizer tokenizer = new StringTokenizer(line); - int offset = 0; - while (tokenizer.hasMoreTokens() && (offset < 3)) - array[offset ++] = tokenizer.nextToken(); - if (array[0] == null) return null; - if (array[2] == null) array[2] = array[1]; - return array; - } - - /** - * <p>Pseudo-nicely display a list of the children of a collection</p> - */ - private static void list(WebDavClient client, PrintStream out) - throws IOException { - out.print("C | "); - out.print("CONTENT TYPE | "); - out.print("CREATED | "); - out.print("MODIFIED | "); - out.print("SIZE | "); - out.println("NAME "); - for (Iterator iterator = client.iterator(); iterator.hasNext() ; ) { - final StringBuffer buffer = new StringBuffer(); - String child = (String) iterator.next(); - if (client.isCollection(child)) buffer.append("* | "); - else buffer.append(" | "); - format(buffer, client.getContentType(child), 15).append(" | "); - format(buffer, client.getCreationDate(child), 19).append(" | "); - format(buffer, client.getLastModified(child), 19).append(" | "); - format(buffer, client.getContentLength(child), 10).append(" | "); - out.println(buffer.append(child)); - } - } - - /** <p>Format a number aligning it to the right of a string.</p> */ - private static StringBuffer format(StringBuffer buf, long num, int len) { - final String data; - if (num < 0) data = ""; - else data = Long.toString(num); - final int spaces = len - data.length(); - for (int x = 0; x < spaces; x++) buf.append(' '); - buf.append(data); - return buf; - } - - /** <p>Format a string into an exact number of characters.</p> */ - private static StringBuffer format(StringBuffer buf, Object obj, int len) { - final String string; - if (obj == null) { - string = ("[null]"); - } else if (obj instanceof Date) { - SimpleDateFormat f = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss"); - string = f.format((Date) obj); - } else { - string = obj.toString(); - } - final StringBuffer buffer = new StringBuffer(string); - for (int x = string.length(); x < len; x ++) buffer.append(' '); - return buf.append(buffer.substring(0, len)); - } -} diff --git a/archiva-modules/archiva-web/archiva-webdav/src/main/java/it/could/util/http/package.html b/archiva-modules/archiva-web/archiva-webdav/src/main/java/it/could/util/http/package.html deleted file mode 100644 index 9ca0cb4fa..000000000 --- a/archiva-modules/archiva-web/archiva-webdav/src/main/java/it/could/util/http/package.html +++ /dev/null @@ -1,12 +0,0 @@ -<html> - <head> - <title>HTTP Utilities</title> - </head> - <body> - <p> - This package contains a number of utility classes to access - <a href="http://www.rfc-editor.org/rfc/rfc2616.txt">HTTP</a> and - <a href="http://www.rfc-editor.org/rfc/rfc2518.txt">WebDAV</a> servers. - </p> - </body> -</html>
\ No newline at end of file diff --git a/archiva-modules/archiva-web/archiva-webdav/src/main/java/it/could/util/location/Location.java b/archiva-modules/archiva-web/archiva-webdav/src/main/java/it/could/util/location/Location.java deleted file mode 100644 index 24964795c..000000000 --- a/archiva-modules/archiva-web/archiva-webdav/src/main/java/it/could/util/location/Location.java +++ /dev/null @@ -1,805 +0,0 @@ -/* ========================================================================== * - * 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.net.MalformedURLException; -import java.util.AbstractList; -import java.util.ArrayList; -import java.util.HashMap; -import java.util.List; -import java.util.Map; - - -/** - * <p>An utility class representing an HTTP-like URL.</p> - * - * <p>This class can be used to represent any URL that roughly uses the HTTP - * format. Compared to the standard {@link java.net.URL} class, the scheme part - * of the a {@link Location} is never checked, and it's up to the application - * to verify its correctness, while compared to the {@link java.net.URI} class, - * its parsing mechanism is a lot more relaxed (be liberal in what you accept, - * be strict in what you send).</p> - * - * <p>For a bigger picture on how this class works, this is an easy-to-read - * representation of what the different parts of a {@link Location} are:</p> - * - * <div align="center"> - * <a href="url.pdf" target="_new" title="PDF Version"> - * <img src="url.gif" alt="URL components" border="0"> - * </a> - * </div> - * - * <p>One important difference between this implementation and the description - * of <a href="http://www.ietf.org/rfc/rfc1738.txt">URLs</a> and - * <a href="http://www.ietf.org/rfc/rfc2396.txt">URIs</a> is that parameter - * paths are represented <i>only at the end of the entire path structure</i> - * rather than for each path element. This over-simplification allows easy - * relativization of {@link Location}s when used with servlet containers, which - * normally use path parameters to encode the session id.</p> - * - * @author <a href="http://could.it/">Pier Fumagalli</a> - */ -public class Location implements Encodable { - - /** <p>A {@link Map} of schemes and their default port number.</p> */ - private static final Map schemePorts = new HashMap(); - static { - schemePorts.put("acap", new Integer( 674)); - schemePorts.put("dav", new Integer( 80)); - schemePorts.put("ftp", new Integer( 21)); - schemePorts.put("gopher", new Integer( 70)); - schemePorts.put("http", new Integer( 80)); - schemePorts.put("https", new Integer( 443)); - schemePorts.put("imap", new Integer( 143)); - schemePorts.put("ldap", new Integer( 389)); - schemePorts.put("mailto", new Integer( 25)); - schemePorts.put("news", new Integer( 119)); - schemePorts.put("nntp", new Integer( 119)); - schemePorts.put("pop", new Integer( 110)); - schemePorts.put("rtsp", new Integer( 554)); - schemePorts.put("sip", new Integer(5060)); - schemePorts.put("sips", new Integer(5061)); - schemePorts.put("snmp", new Integer( 161)); - schemePorts.put("telnet", new Integer( 23)); - schemePorts.put("tftp", new Integer( 69)); - } - - /** <p>The {@link List} of schemes of this {@link Location}.</p> */ - private final Schemes schemes; - /** <p>The {@link Authority} of this {@link Location}.</p> */ - private final Authority authority; - /** <p>The {@link Path} of this {@link Location}.</p> */ - private final Path path; - /** <p>The {@link Parameters} of this {@link Location}.</p> */ - private final Parameters parameters; - /** <p>The fragment part of this {@link Location}.</p> */ - private final String fragment; - /** <p>The string representation of this {@link Location}.</p> */ - private final String string; - - /** - * <p>Create a new {@link Location} instance.</p> - */ - public Location(Schemes schemes, Authority authority, Path path, - Parameters parameters, String fragment) - throws MalformedURLException { - if ((schemes == null) && (authority != null)) - throw new MalformedURLException("No schemes specified"); - if ((schemes != null) && (authority == null)) - throw new MalformedURLException("No authority specified"); - if (path == null) throw new MalformedURLException("No path specified"); - - this.schemes = schemes; - this.authority = authority; - this.path = path; - this.parameters = parameters; - this.fragment = fragment; - this.string = EncodingTools.toString(this); - } - - /* ====================================================================== */ - /* STATIC CONSTRUCTION METHODS */ - /* ====================================================================== */ - - public static Location parse(String url) - throws MalformedURLException { - try { - return parse(url, DEFAULT_ENCODING); - } catch (UnsupportedEncodingException exception) { - final String message = "Unsupported encoding " + DEFAULT_ENCODING; - final InternalError error = new InternalError(message); - throw (InternalError) error.initCause(exception); - } - } - - public static Location parse(String url, String encoding) - throws MalformedURLException, UnsupportedEncodingException { - if (url == null) return null;; - if (encoding == null) encoding = DEFAULT_ENCODING; - final String components[] = parseComponents(url); - final Schemes schemes = parseSchemes(components[0], encoding); - final int port = findPort(schemes, encoding); - final Authority auth = parseAuthority(components[1], port, encoding); - final Path path = Path.parse(components[2], encoding); - final Parameters params = Parameters.parse(components[3], '&', encoding); - final String fragment = components[4]; - return new Location(schemes, auth, path, params, fragment); - } - - /* ====================================================================== */ - /* ACCESSOR METHODS */ - /* ====================================================================== */ - - /** - * <p>Return an unmodifiable {@link Schemes list of all schemes} for this - * {@link Location} instance or <b>null</b>.</p> - */ - public Schemes getSchemes() { - return this.schemes; - } - - /** - * <p>Return the {@link Location.Authority Authority} part for this - * {@link Location} or <b>null</b>.</p> - */ - public Authority getAuthority() { - return this.authority; - } - - /** - * <p>Return the <b>non-null</b> {@link Path Path} structure - * associated with this {@link Location} instance.</p> - */ - public Path getPath() { - return this.path; - } - - /** - * <p>Return an unmodifiable {@link Parameters list of all parameters} - * parsed from this {@link Location}'s query string or <b>null</b>.</p> - */ - public Parameters getParameters() { - return this.parameters; - } - - /** - * <p>Return the fragment of this {@link Location} unencoded.</p> - */ - public String getFragment() { - return this.fragment; - } - - /* ====================================================================== */ - /* OBJECT METHODS */ - /* ====================================================================== */ - - /** - * <p>Check if the specified {@link Object} is equal to this instance.</p> - * - * <p>The specified {@link Object} must be a <b>non-null</b> - * {@link Location} instance whose {@link #toString() string value} equals - * this one's.</p> - */ - public boolean equals(Object object) { - if ((object != null) && (object instanceof Location)) { - return this.string.equals(((Location)object).string); - } else { - return false; - } - } - - /** - * <p>Return the hash code value for this {@link Location} instance.</p> - */ - public int hashCode() { - return this.string.hashCode(); - } - - /** - * <p>Return the {@link String} representation of this {@link Location} - * instance.</p> - */ - public String toString() { - return this.string; - } - - /** - * <p>Return the {@link String} representation of this {@link Location} - * instance using the specified character encoding.</p> - */ - public String toString(String encoding) - throws UnsupportedEncodingException { - final StringBuffer buffer = new StringBuffer(); - - /* Render the schemes */ - if (this.schemes != null) - buffer.append(this.schemes.toString(encoding)).append("://"); - - /* Render the authority part */ - if (this.authority != null) - buffer.append(this.authority.toString(encoding)); - - /* Render the paths */ - buffer.append(this.path.toString(encoding)); - - /* Render the query string */ - if (this.parameters != null) - buffer.append('?').append(this.parameters.toString(encoding)); - - /* Render the fragment */ - if (this.fragment != null) { - buffer.append('#'); - buffer.append(EncodingTools.urlEncode(this.fragment, encoding)); - } - - /* Return the string */ - return buffer.toString(); - } - - /* ====================================================================== */ - /* PUBLIC METHODS */ - /* ====================================================================== */ - - /** - * <p>Checks whether this {@link Location} is absolute or not.</p> - * - * <p>This method must not be confused with the similarly named - * {@link Path#isAbsolute() Path.isAbsolute()} method. - * This method will check whether the full {@link Location} is absolute (it - * has a scheme), while the one exposed by the {@link Path Path} - * class will check if the path is absolute.</p> - */ - public boolean isAbsolute() { - return this.schemes != null && this.authority != null; - } - - public boolean isRelative() { - return ! (this.isAbsolute() || this.path.isAbsolute()); - } - - public boolean isAuthoritative(Location location) { - if (! this.isAbsolute()) return false; - if (! location.isAbsolute()) return true; - return this.schemes.equals(location.schemes) && - this.authority.equals(location.authority); - } - - /* ====================================================================== */ - /* RESOLUTION METHODS */ - /* ====================================================================== */ - - public Location resolve(String url) - throws MalformedURLException { - try { - return this.resolve(parse(url, DEFAULT_ENCODING)); - } catch (UnsupportedEncodingException exception) { - final String message = "Unsupported encoding " + DEFAULT_ENCODING; - final InternalError error = new InternalError(message); - throw (InternalError) error.initCause(exception); - } - } - - public Location resolve(String url, String encoding) - throws MalformedURLException, UnsupportedEncodingException { - if (encoding == null) encoding = DEFAULT_ENCODING; - return this.resolve(parse(url, encoding)); - } - - public Location resolve(Location location) { - if (! this.isAuthoritative(location)) return location; - - /* Schemes are the same */ - final Schemes schemes = this.schemes; - - /* Authority needs to be merged (for username and password) */ - final Authority auth; - if (location.authority != null) { - final String username = location.authority.username != null ? - location.authority.username : - this.authority.username; - final String password = location.authority.password != null ? - location.authority.password : - this.authority.password; - final String host = location.authority.host; - final int port = location.authority.port; - auth = new Authority(username, password, host, port); - } else { - auth = this.authority; - } - - /* Path can be resolved */ - final Path path = this.path.resolve(location.path); - - /* Parametrs and fragment are the ones of the target */ - final Parameters params = location.parameters; - final String fragment = location.fragment; - - /* Create a new {@link Location} instance */ - try { - return new Location(schemes, auth, path, params, fragment); - } catch (MalformedURLException exception) { - /* Should really never happen */ - Error error = new InternalError("Can't instantiate Location"); - throw (Error) error.initCause(exception); - } - } - - /* ====================================================================== */ - /* RELATIVIZATION METHODS */ - /* ====================================================================== */ - - public Location relativize(String url) - throws MalformedURLException { - try { - return this.relativize(parse(url, DEFAULT_ENCODING)); - } catch (UnsupportedEncodingException exception) { - final String message = "Unsupported encoding " + DEFAULT_ENCODING; - final InternalError error = new InternalError(message); - throw (InternalError) error.initCause(exception); - } - } - - public Location relativize(String url, String encoding) - throws MalformedURLException, UnsupportedEncodingException { - if (encoding == null) encoding = DEFAULT_ENCODING; - return this.relativize(parse(url, encoding)); - } - - public Location relativize(Location location) { - final Path path; - if (!location.isAbsolute()) { - /* Target location is not absolute, its path might */ - path = this.path.relativize(location.path); - } else { - if (this.isAuthoritative(location)) { - /* Target location is not on the same authority, process path */ - path = this.path.relativize(location.path); - } else { - /* Not authoritative for a non-relative location, yah! */ - return location; - } - } - try { - return new Location(null, null, path, location.parameters, - location.fragment); - } catch (MalformedURLException exception) { - /* Should really never happen */ - Error error = new InternalError("Can't instantiate Location"); - throw (Error) error.initCause(exception); - } - } - - /* ====================================================================== */ - /* INTERNAL PARSING ROUTINES */ - /* ====================================================================== */ - - /** - * <p>Return the port number associated with the specified schemes.</p> - */ - public static int findPort(List schemes, String encoding) - throws UnsupportedEncodingException { - if (schemes == null) return -1; - if (schemes.size() < 1) return -1; - Integer p = (Integer) schemePorts.get(schemes.get(schemes.size() - 1)); - return p == null ? -1 : p.intValue(); - } - - /** - * <p>Parse <code>scheme://authority/path?query#fragment</code>.</p> - * - * @return an array of five {@link String}s: scheme (0), authority (1), - * path (2), query (3) and fragment (4). - */ - private static String[] parseComponents(String url) - throws MalformedURLException { - /* Scheme, easy and simple */ - final String scheme; - final String afterScheme; - final int schemeEnd = url.indexOf(":/"); - if (schemeEnd > 0) { - scheme = url.substring(0, schemeEnd).toLowerCase(); - afterScheme = url.substring(schemeEnd + 2); - } else if (schemeEnd == 0) { - throw new MalformedURLException("Missing scheme"); - } else { - scheme = null; - afterScheme = url; - } - - /* Authority (can be tricky because it can be emtpy) */ - final String auth; - final String afterAuth; - if (scheme == null) { - // --> /path... or path... - afterAuth = afterScheme; - auth = null; - } else if (afterScheme.length() > 0 && afterScheme.charAt(0) == '/') { - // --> scheme://... - final int pathStart = afterScheme.indexOf('/', 1); - if (pathStart == 1) { - // --> scheme:///path... - afterAuth = afterScheme.substring(pathStart); - auth = null; - } else if (pathStart > 1) { - // --> scheme://authority/path... - afterAuth = afterScheme.substring(pathStart); - auth = afterScheme.substring(1, pathStart); - } else { - // --> scheme://authority (but no slashes for the path) - final int authEnds = StringTools.findFirst(afterScheme, "?#"); - if (authEnds < 0) { - // --> scheme://authority (that's it, return) - auth = afterScheme.substring(1); - return new String[] { scheme, auth, "/", null, null }; - } - // --> scheme://authority?... or scheme://authority#... - auth = afterScheme.substring(1, authEnds); - afterAuth = "/" + afterScheme.substring(authEnds); - } - } else { - // --> scheme:/path... - afterAuth = url.substring(schemeEnd + 1); - auth = null; - } - - /* Path, can be terminated by '?' or '#' whichever is first */ - final int pathEnds = StringTools.findFirst(afterAuth, "?#"); - if (pathEnds < 0) { - // --> ...path... (no fragment or query, return now) - return new String[] { scheme, auth, afterAuth, null, null }; - } - - /* We have either a query, a fragment or both after the path */ - final String path = afterAuth.substring(0, pathEnds); - final String afterPath = afterAuth.substring(pathEnds + 1); - - /* Query? The query can contain a "#" and has an extra fragment */ - if (afterAuth.charAt(pathEnds) == '?') { - final int fragmPos = afterPath.indexOf('#'); - if (fragmPos < 0) { - // --> ...path...?... (no fragment) - return new String[] { scheme, auth, path, afterPath, null }; - } - - // --> ...path...?...#... (has also a fragment) - final String query = afterPath.substring(1, fragmPos); - final String fragm = afterPath.substring(fragmPos + 1); - return new String[] { scheme, auth, path, query, fragm }; - } - - // --> ...path...#... (a path followed by a fragment but no query) - return new String[] { scheme, auth, path, null, afterPath }; - } - - /** - * <p>Parse <code>scheme:scheme:scheme...</code>.</p> - */ - private static Schemes parseSchemes(String scheme, String encoding) - throws MalformedURLException, UnsupportedEncodingException { - if (scheme == null) return null; - final String split[] = StringTools.splitAll(scheme, ':'); - List list = new ArrayList(); - for (int x = 0; x < split.length; x++) { - if (split[x] == null) continue; - list.add(EncodingTools.urlDecode(split[x], encoding)); - } - if (list.size() != 0) return new Schemes(list); - throw new MalformedURLException("Empty scheme detected"); - } - - /** - * <p>Parse <code>username:password@hostname:port</code>.</p> - */ - private static Authority parseAuthority(String auth, int defaultPort, - String encoding) - throws MalformedURLException, UnsupportedEncodingException { - if (auth == null) return null; - final String split[] = StringTools.splitOnce(auth, '@', true); - final String uinfo[] = StringTools.splitOnce(split[0], ':', false); - final String hinfo[] = StringTools.splitOnce(split[1], ':', false); - final int port; - - if ((split[0] != null) && (split[1] == null)) - throw new MalformedURLException("Missing required host info part"); - if ((uinfo[0] == null) && (uinfo[1] != null)) - throw new MalformedURLException("Password specified without user"); - if ((hinfo[0] == null) && (hinfo[1] != null)) - throw new MalformedURLException("Port specified without host"); - try { - if (hinfo[1] != null) { - final int parsedPort = Integer.parseInt(hinfo[1]); - if ((parsedPort < 1) || (parsedPort > 65535)) { - final String message = "Invalid port number " + parsedPort; - throw new MalformedURLException(message); - } - /* If the specified port is the default one, ignore it! */ - if (defaultPort == parsedPort) port = -1; - else port = parsedPort; - } else { - port = -1; - } - } catch (NumberFormatException exception) { - throw new MalformedURLException("Specified port is not a number"); - } - return new Authority(EncodingTools.urlDecode(uinfo[0], encoding), - EncodingTools.urlDecode(uinfo[1], encoding), - EncodingTools.urlDecode(hinfo[0], encoding), - port); - } - - /* ====================================================================== */ - /* PUBLIC INNER CLASSES */ - /* ====================================================================== */ - - /** - * <p>The {@link Location.Schemes Schemes} class represents an unmodifiable - * ordered collection of {@link String} schemes for a {@link Location}.</p> - * - * @author <a href="http://could.it/">Pier Fumagalli</a> - */ - public static class Schemes extends AbstractList implements Encodable { - /** <p>All the {@link String} schemes in order.</p> */ - private final String schemes[]; - /** <p>The {@link String} representation of this instance.</p> */ - private final String string; - - /** - * <p>Create a new {@link Schemes} instance.</p> - */ - private Schemes(List schemes) { - final int size = schemes.size(); - this.schemes = (String []) schemes.toArray(new String[size]); - this.string = EncodingTools.toString(this); - } - - /** - * <p>Return the {@link String} scheme at the specified index.</p> - */ - public Object get(int index) { - return this.schemes[index]; - } - - /** - * <p>Return the number of {@link String} schemes contained by this - * {@link Location.Schemes Schemes} instance.</p> - */ - public int size() { - return this.schemes.length; - } - - /** - * <p>Return the URL-encoded {@link String} representation of this - * {@link Location.Schemes Schemes} instance.</p> - */ - public String toString() { - return this.string; - } - - /** - * <p>Return the URL-encoded {@link String} representation of this - * {@link Location.Schemes Schemes} instance using the specified - * character encoding.</p> - */ - public String toString(String encoding) - throws UnsupportedEncodingException { - final StringBuffer buffer = new StringBuffer(); - for (int x = 0; x < this.schemes.length; x ++) { - buffer.append(':'); - buffer.append(EncodingTools.urlEncode(this.schemes[x], encoding)); - } - return buffer.substring(1); - } - - /** - * <p>Return the hash code value for this - * {@link Location.Schemes Schemes} instance.</p> - */ - public int hashCode() { - return this.string.hashCode(); - } - - /** - * <p>Check if the specified {@link Object} is equal to this - * {@link Location.Schemes Schemes} instance.</p> - * - * <p>The specified {@link Object} is considered equal to this one if - * it is <b>non-null</b>, it is a {@link Location.Schemes Schemes} - * instance, and its {@link #toString() string representation} equals - * this one's.</p> - */ - public boolean equals(Object object) { - if ((object != null) && (object instanceof Schemes)) { - return this.string.equals(((Schemes) object).string); - } else { - return false; - } - } - } - - /* ====================================================================== */ - - /** - * <p>The {@link Location.Authority Authority} class represents the autority - * and user information for a {@link Location}.</p> - * - * @author <a href="http://could.it/">Pier Fumagalli</a> - */ - public static class Authority implements Encodable { - /** <p>The username of this instance (decoded).</p> */ - private final String username; - /** <p>The password of this instance (decoded).</p> */ - private final String password; - /** <p>The host name of this instance (decoded).</p> */ - private final String host; - /** <p>The port number of this instance.</p> */ - private final int port; - /** <p>The encoded host and port representation.</p> */ - private final String hostinfo; - /** <p>The encoded string representation of this instance.</p> */ - private final String string; - - /** - * <p>Create a new {@link Location.Authority Authority} instance.</p> - */ - private Authority(String user, String pass, String host, int port) { - this.username = user; - this.password = pass; - this.host = host; - this.port = port; - try { - this.hostinfo = this.getHostInfo(DEFAULT_ENCODING); - this.string = this.toString(DEFAULT_ENCODING); - } catch (UnsupportedEncodingException exception) { - final String message = "Default encoding \"" + DEFAULT_ENCODING - + "\" not supported by the platform"; - final InternalError error = new InternalError(message); - throw (InternalError) error.initCause(exception); - } - } - - /** - * <p>Returns the decoded user name.</p> - */ - public String getUsername() { - return this.username; - } - - /** - * <p>Returns the decoded password.</p> - */ - public String getPassword() { - return this.password; - } - - /** - * <p>Returns the "user info" field.</p> - * - * <p>This method will concatenate the username and password using the - * colon character and return a <b>non-null</b> {@link String} only if - * both of them are <b>non-null</b>.</p> - */ - public String getUserInfo() { - if ((this.username == null) || (this.password == null)) return null; - return this.username + ':' + this.password; - } - - /** - * <p>Returns the decoded host name.</p> - */ - public String getHost() { - return this.host; - } - - /** - * <p>Returns the port number.</p> - */ - public int getPort() { - return this.port; - } - - /** - * <p>Returns the host info part of the - * {@link Location.Authority Authority}.</p> - * - * <p>This is the encoded representation of the - * {@link #getUsername() user name} optionally follwed by the colon (:) - * character and the encoded {@link #getPassword() password}.</p> - */ - public String getHostInfo() { - return this.hostinfo; - } - - /** - * <p>Returns the host info part of the - * {@link Location.Authority Authority} using the specified character - * encoding.</p> - * - * <p>This is the encoded representation of the - * {@link #getUsername() user name} optionally follwed by the colon (:) - * character and the encoded {@link #getPassword() password}.</p> - */ - public String getHostInfo(String encoding) - throws UnsupportedEncodingException { - final StringBuffer hostinfo = new StringBuffer(); - hostinfo.append(EncodingTools.urlEncode(this.host, encoding)); - if (port >= 0) hostinfo.append(':').append(port); - return hostinfo.toString(); - } - - /** - * <p>Return the URL-encoded {@link String} representation of this - * {@link Location.Authority Authority} instance.</p> - */ - public String toString() { - return this.string; - } - - /** - * <p>Return the URL-encoded {@link String} representation of this - * {@link Location.Authority Authority} instance using the specified - * character encoding.</p> - */ - public String toString(String encoding) - throws UnsupportedEncodingException { - final StringBuffer buffer; - if (this.username != null) { - buffer = new StringBuffer(); - buffer.append(EncodingTools.urlEncode(this.username, encoding)); - if (this.password != null) { - buffer.append(':'); - buffer.append(EncodingTools.urlEncode(this.password, encoding)); - } - } else { - buffer = null; - } - - if (buffer == null) return this.getHostInfo(encoding); - buffer.append('@').append(this.getHostInfo(encoding)); - return buffer.toString(); - } - - /** - * <p>Return the hash code value for this - * {@link Location.Authority Authority} instance.</p> - */ - public int hashCode() { - return this.hostinfo.hashCode(); - } - - /** - * <p>Check if the specified {@link Object} is equal to this - * {@link Location.Authority Authority} instance.</p> - * - * <p>The specified {@link Object} is considered equal to this one if - * it is <b>non-null</b>, it is a {@link Location.Authority Authority} - * instance, and its {@link #getHostInfo() host info} equals - * this one's.</p> - */ - public boolean equals(Object object) { - if ((object != null) && (object instanceof Authority)) { - return this.hostinfo.equals(((Authority) object).hostinfo); - } else { - return false; - } - } - } -} diff --git a/archiva-modules/archiva-web/archiva-webdav/src/main/java/it/could/util/location/Parameters.java b/archiva-modules/archiva-web/archiva-webdav/src/main/java/it/could/util/location/Parameters.java deleted file mode 100644 index 3ffa0bac7..000000000 --- a/archiva-modules/archiva-web/archiva-webdav/src/main/java/it/could/util/location/Parameters.java +++ /dev/null @@ -1,474 +0,0 @@ -/* ========================================================================== * - * 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 diff --git a/archiva-modules/archiva-web/archiva-webdav/src/main/java/it/could/util/location/Path.java b/archiva-modules/archiva-web/archiva-webdav/src/main/java/it/could/util/location/Path.java deleted file mode 100644 index 722a0d46b..000000000 --- a/archiva-modules/archiva-web/archiva-webdav/src/main/java/it/could/util/location/Path.java +++ /dev/null @@ -1,559 +0,0 @@ -/* ========================================================================== * - * 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 diff --git a/archiva-modules/archiva-web/archiva-webdav/src/main/java/it/could/util/location/package.html b/archiva-modules/archiva-web/archiva-webdav/src/main/java/it/could/util/location/package.html deleted file mode 100644 index 155907e08..000000000 --- a/archiva-modules/archiva-web/archiva-webdav/src/main/java/it/could/util/location/package.html +++ /dev/null @@ -1,29 +0,0 @@ -<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 diff --git a/archiva-modules/archiva-web/archiva-webdav/src/main/java/it/could/util/package.html b/archiva-modules/archiva-web/archiva-webdav/src/main/java/it/could/util/package.html deleted file mode 100644 index 97f56c6e2..000000000 --- a/archiva-modules/archiva-web/archiva-webdav/src/main/java/it/could/util/package.html +++ /dev/null @@ -1,11 +0,0 @@ -<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 |