harmony-commits mailing list archives

Site index · List index
Message view « Date » · « Thread »
Top « Date » · « Thread »
From ge...@apache.org
Subject svn commit: r350181 [112/198] - in /incubator/harmony/enhanced/trunk/sandbox/contribs/ibm_core: ./ depends/ depends/files/ depends/jars/ depends/libs/ depends/libs/linux.IA32/ depends/libs/win.IA32/ depends/oss/ depends/oss/linux.IA32/ depends/oss/win....
Date Thu, 01 Dec 2005 06:04:00 GMT
Added: incubator/harmony/enhanced/trunk/sandbox/contribs/ibm_core/java-src/luni/src/java/net/URI.java
URL: http://svn.apache.org/viewcvs/incubator/harmony/enhanced/trunk/sandbox/contribs/ibm_core/java-src/luni/src/java/net/URI.java?rev=350181&view=auto
==============================================================================
--- incubator/harmony/enhanced/trunk/sandbox/contribs/ibm_core/java-src/luni/src/java/net/URI.java (added)
+++ incubator/harmony/enhanced/trunk/sandbox/contribs/ibm_core/java-src/luni/src/java/net/URI.java Wed Nov 30 21:29:27 2005
@@ -0,0 +1,1431 @@
+/* Copyright 2004, 2005 The Apache Software Foundation or its licensors, as applicable
+ * 
+ * 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 java.net;
+
+
+import java.io.IOException;
+import java.io.ObjectInputStream;
+import java.io.ObjectOutputStream;
+import java.io.Serializable;
+import java.io.UnsupportedEncodingException;
+import java.util.StringTokenizer;
+
+import com.ibm.oti.util.Msg;
+
+/**
+ * This class represents an instance of a URI as defined by RFC 2396.
+ */
+public final class URI implements Comparable, Serializable {
+
+	private static final long serialVersionUID = -6052424284110960213l;
+
+	static final String unreserved = "_-!.~\'()*";
+
+	static final String punct = ",;:$&+=";
+
+	static final String reserved = punct + "?/[]@";
+
+	static final String someLegal = unreserved + punct;
+
+	static final String allLegal = unreserved + reserved;
+
+	private String string = null;
+
+	private transient String scheme = null;
+
+	private transient String schemespecificpart = null;
+
+	private transient String authority = null;
+
+	private transient String userinfo = null;
+
+	private transient String host = null;
+
+	private transient int port = -1;
+
+	private transient String path = null;
+
+	private transient String query = null;
+
+	private transient String fragment = null;
+
+	private transient boolean opaque;
+
+	private transient boolean absolute;
+
+	private transient boolean serverAuthority = false;
+
+	private transient int hash = -1;
+
+	private URI() {
+	}
+
+	public URI(String uri) throws URISyntaxException {
+		new Helper().parseURI(uri, false);
+	}
+
+	public URI(String scheme, String ssp, String frag)
+			throws URISyntaxException {
+		StringBuffer uri = new StringBuffer();
+		if (scheme != null) {
+			uri.append(scheme);
+			uri.append(':');
+		}
+		if (ssp != null) {
+			// QUOTE ILLEGAL CHARACTERS
+			uri.append(quoteComponent(ssp, allLegal));
+		}
+		if (frag != null) {
+			uri.append('#');
+			// QUOTE ILLEGAL CHARACTERS
+			uri.append(quoteComponent(frag, allLegal));
+		}
+
+		new Helper().parseURI(uri.toString(), false);
+	}
+
+	public URI(String scheme, String userinfo, String host, int port,
+			String path, String query, String fragment)
+			throws URISyntaxException {
+
+		if (scheme != null && path != null && path.length() > 0
+				&& path.charAt(0) != '/') {
+			throw new URISyntaxException(path, Msg.getString("K0302"));
+		}
+
+		StringBuffer uri = new StringBuffer();
+		if (scheme != null) {
+			uri.append(scheme);
+			uri.append(':');
+		}
+
+		if (userinfo != null || host != null || port != -1)
+			uri.append("//");
+
+		if (userinfo != null) {
+			// QUOTE ILLEGAL CHARACTERS in userinfo
+			uri.append(quoteComponent(userinfo, someLegal));
+			uri.append('@');
+		}
+
+		if (host != null) {
+			// check for ipv6 addresses that hasn't been enclosed
+			// in square brackets
+			if (host.indexOf(':') != -1 && host.indexOf(']') == -1
+					&& host.indexOf('[') == -1)
+				host = "[" + host + "]";
+			uri.append(host);
+		}
+
+		if (port != -1) {
+			uri.append(':');
+			uri.append(port);
+		}
+
+		if (path != null) {
+			// QUOTE ILLEGAL CHARS
+			uri.append(quoteComponent(path, "/@" + someLegal));
+		}
+
+		if (query != null) {
+			uri.append('?');
+			// QUOTE ILLEGAL CHARS
+			uri.append(quoteComponent(query, allLegal));
+		}
+
+		if (fragment != null) {
+			// QUOTE ILLEGAL CHARS
+			uri.append('#');
+			uri.append(quoteComponent(fragment, allLegal));
+		}
+
+		new Helper().parseURI(uri.toString(), true);
+	}
+
+	public URI(String scheme, String host, String path, String fragment)
+			throws URISyntaxException {
+		this(scheme, null, host, -1, path, null, fragment);
+	}
+
+	public URI(String scheme, String authority, String path, String query,
+			String fragment) throws URISyntaxException {
+		if (scheme != null && path != null && path.length() > 0
+				&& path.charAt(0) != '/') {
+			throw new URISyntaxException(path, Msg.getString("K0302"));
+		}
+
+		StringBuffer uri = new StringBuffer();
+		if (scheme != null) {
+			uri.append(scheme);
+			uri.append(':');
+		}
+		if (authority != null) {
+			uri.append("//");
+			// QUOTE ILLEGAL CHARS
+			uri.append(quoteComponent(authority, "@" + someLegal));
+		}
+
+		if (path != null) {
+			// QUOTE ILLEGAL CHARS
+			uri.append(quoteComponent(path, "/@" + someLegal));
+		}
+		if (query != null) {
+			// QUOTE ILLEGAL CHARS
+			uri.append('?');
+			uri.append(quoteComponent(query, allLegal));
+		}
+		if (fragment != null) {
+			// QUOTE ILLEGAL CHARS
+			uri.append('#');
+			uri.append(quoteComponent(fragment, allLegal));
+		}
+
+		new Helper().parseURI(uri.toString(), false);
+	}
+
+	private class Helper {
+
+		private void parseURI(String uri, boolean forceServer)
+				throws URISyntaxException {
+			String temp = uri;
+			int index, index1, index2, index3;
+			// parse into Fragment, Scheme, and SchemeSpecificPart
+			// then parse SchemeSpecificPart if necessary
+
+			// Fragment
+			index = temp.indexOf('#');
+			if (index != -1) {
+				// remove the fragment from the end
+				fragment = temp.substring(index + 1);
+				validateFragment(uri, fragment, index + 1);
+				temp = temp.substring(0, index);
+			}
+
+			// Scheme and SchemeSpecificPart
+			index = index1 = temp.indexOf(':');
+			index2 = temp.indexOf('/');
+			index3 = temp.indexOf('?');
+
+			// if a '/' or '?' occurs before the first ':' the uri has no
+			// specified scheme, and is therefore not absolute
+			if (index != -1 && (index2 >= index || index2 == -1)
+					&& (index3 >= index || index3 == -1)) {
+				// the characters up to the first ':' comprise the scheme
+				absolute = true;
+				scheme = temp.substring(0, index);
+				validateScheme(uri, scheme, 0);
+				schemespecificpart = temp.substring(index + 1);
+				if (schemespecificpart.length() == 0) {
+					throw new URISyntaxException(uri, Msg.getString("K0303"),
+							index + 1);
+				}
+			} else {
+				absolute = false;
+				schemespecificpart = temp;
+			}
+
+			if (scheme == null || schemespecificpart.length() > 0
+					&& schemespecificpart.charAt(0) == '/') {
+				opaque = false;
+				// the URI is hierarchical
+
+				// Query
+				temp = schemespecificpart;
+				index = temp.indexOf('?');
+				if (index != -1) {
+					query = temp.substring(index + 1);
+					temp = temp.substring(0, index);
+					validateQuery(uri, query, index2 + 1 + index);
+				}
+
+				// Authority and Path
+				if (temp.startsWith("//")) {
+					index = temp.indexOf('/', 2);
+					if (index != -1) {
+						authority = temp.substring(2, index);
+						path = temp.substring(index);
+					} else {
+						authority = temp.substring(2);
+						if (authority.length() == 0 && query == null
+								&& fragment == null) {
+							throw new URISyntaxException(uri, Msg
+									.getString("K0304"), uri.length());
+						}
+
+						path = "";
+						// nothing left, so path is empty (not null, path should
+						// never be null)
+					}
+					validateAuthority(uri, authority, index1 + 3);
+				} else { // no authority specified
+					path = temp;
+				}
+
+				validatePath(uri, path, index2 + index);
+			} else { // if not hierarchical, URI is opaque
+				opaque = true;
+				validateSsp(uri, schemespecificpart, index2 + 2 + index);
+			}
+
+			parseAuthority(forceServer);
+		}
+
+		private void validateScheme(String uri, String schemeValue, int index)
+				throws URISyntaxException {
+			// first char needs to be an alpha char
+			char ch = schemeValue.charAt(0);
+			if (!((ch >= 'a' && ch <= 'z') || (ch >= 'A' && ch <= 'Z'))) {
+				throw new URISyntaxException(uri, Msg.getString("K0305"), 0);
+			}
+
+			try {
+				URIEncoderDecoder.validateSimple(schemeValue, "+-.");
+			} catch (URISyntaxException e) {
+				throw new URISyntaxException(uri, Msg.getString("K0305"), index
+						+ e.getIndex());
+			}
+		}
+
+		private void validateSsp(String uri, String ssp, int index)
+				throws URISyntaxException {
+			try {
+				URIEncoderDecoder.validate(ssp, allLegal);
+			} catch (URISyntaxException e) {
+				throw new URISyntaxException(uri, Msg.getString("K0306", e
+						.getReason()), index + e.getIndex());
+			}
+		}
+
+		private void validateAuthority(String uri, String authorityValue,
+				int index) throws URISyntaxException {
+			try {
+				URIEncoderDecoder.validate(authorityValue, "@[]" + someLegal);
+			} catch (URISyntaxException e) {
+				throw new URISyntaxException(uri, Msg.getString("K0307", e
+						.getReason()), index + e.getIndex());
+			}
+		}
+
+		private void validatePath(String uri, String pathValue, int index)
+				throws URISyntaxException {
+			try {
+				URIEncoderDecoder.validate(pathValue, "/@" + someLegal);
+			} catch (URISyntaxException e) {
+				throw new URISyntaxException(uri, Msg.getString("K0308", e
+						.getReason()), index + e.getIndex());
+			}
+		}
+
+		private void validateQuery(String uri, String queryValue, int index)
+				throws URISyntaxException {
+			try {
+				URIEncoderDecoder.validate(queryValue, allLegal);
+			} catch (URISyntaxException e) {
+				throw new URISyntaxException(uri, Msg.getString("K0309", e
+						.getReason()), index + e.getIndex());
+
+			}
+		}
+
+		private void validateFragment(String uri, String fragmentValue,
+				int index) throws URISyntaxException {
+			try {
+				URIEncoderDecoder.validate(fragmentValue, allLegal);
+			} catch (URISyntaxException e) {
+				throw new URISyntaxException(uri, Msg.getString("K030a", e
+						.getReason()), index + e.getIndex());
+			}
+		}
+
+		/**
+		 * determine the host, port and userinfo if the authority parses
+		 * successfully to a server based authority
+		 * 
+		 * behavour in error cases: if forceServer is true, throw
+		 * URISyntaxException with the proper diagnostic messages. if
+		 * forceServer is false assume this is a registry based uri, and just
+		 * return leaving the host, port and userinfo fields undefined.
+		 * 
+		 * and there are some error cases where URISyntaxException is thrown
+		 * regardless of the forceServer parameter e.g. malformed ipv6 address
+		 */
+		private void parseAuthority(boolean forceServer)
+				throws URISyntaxException {
+			if (authority == null || authority.equals(""))
+				return;
+
+			String temp, tempUserinfo = null, tempHost = null;
+			int index, hostindex = 0;
+			int tempPort = -1;
+
+			temp = authority;
+			index = temp.indexOf('@');
+			if (index != -1) {
+				// remove user info
+				tempUserinfo = temp.substring(0, index);
+				validateUserinfo(authority, tempUserinfo, 0);
+				temp = temp.substring(index + 1); // host[:port] is left
+				hostindex = index + 1;
+			}
+
+			index = temp.lastIndexOf(':');
+			int endindex = temp.indexOf(']');
+
+			if (index != -1 && endindex < index) {
+				// determine port and host
+				tempHost = temp.substring(0, index);
+				try {
+					tempPort = Integer.parseInt(temp.substring(index + 1));
+				} catch (NumberFormatException e) {
+					if (forceServer)
+						throw new URISyntaxException(authority, Msg
+								.getString("K00b1"), hostindex + index + 1);
+					return;
+				}
+			} else
+				tempHost = temp;
+
+			if (tempHost.equals("")) {
+				if (forceServer)
+					throw new URISyntaxException(authority, Msg
+							.getString("K030c"), hostindex);
+				return;
+			}
+
+			if (!isValidHost(forceServer, tempHost))
+				return;
+
+			// this is a server based uri,
+			// fill in the userinfo, host and port fields
+			userinfo = tempUserinfo;
+			host = tempHost;
+			port = tempPort;
+			serverAuthority = true;
+		}
+
+		private void validateUserinfo(String uri, String userinfoValue,
+				int index) throws URISyntaxException {
+			for (int i = 0; i < userinfoValue.length(); i++) {
+				char ch = userinfoValue.charAt(i);
+				if (ch == ']' || ch == '[') {
+					throw new URISyntaxException(uri, Msg.getString("K030d"),
+							index + i);
+				}
+
+			}
+		}
+
+		/**
+		 * distinguish between IPv4, IPv6, domain name and validate it based on
+		 * its type
+		 */
+		private boolean isValidHost(boolean forceServer, String hostValue)
+				throws URISyntaxException {
+			if (hostValue.charAt(0) == '[') {
+				// ipv6 address
+				if (hostValue.charAt(hostValue.length() - 1) != ']') {
+					throw new URISyntaxException(hostValue, Msg
+							.getString("K030e"), 0);
+				}
+				if (!isValidIP6Address(hostValue)) {
+					throw new URISyntaxException(hostValue, Msg
+							.getString("K030f"));
+				}
+				return true;
+			}
+
+			// '[' and ']' can only be the first char and last char
+			// of the host name
+			if (hostValue.indexOf('[') != -1 || hostValue.indexOf(']') != -1) {
+				throw new URISyntaxException(hostValue, Msg.getString("K0310"),
+						0);
+			}
+
+			int index = hostValue.lastIndexOf('.');
+			if (index < 0 || index == hostValue.length() - 1
+					|| !Character.isDigit(hostValue.charAt(index + 1))) {
+				// domain name
+				if (isValidDomainName(hostValue)) {
+					return true;
+				}
+				if (forceServer) {
+					throw new URISyntaxException(hostValue, Msg
+							.getString("K0310"), 0);
+				}
+				return false;
+			}
+
+			// IPv4 address
+			if (isValidIPv4Address(hostValue)) {
+				return true;
+			}
+			if (forceServer) {
+				throw new URISyntaxException(hostValue, Msg.getString("K0311"),
+						0);
+			}
+			return false;
+		}
+
+		private boolean isValidDomainName(String hostValue) {
+			try {
+				URIEncoderDecoder.validateSimple(hostValue, "-.");
+			} catch (URISyntaxException e) {
+				return false;
+			}
+
+			String label = null;
+			StringTokenizer st = new StringTokenizer(hostValue, ".");
+			while (st.hasMoreTokens()) {
+				label = st.nextToken();
+				if (label.startsWith("-") || label.endsWith("-"))
+					return false;
+			}
+
+			if (!label.equals(hostValue)) {
+				char ch = label.charAt(0);
+				if (ch >= '0' && ch <= '9')
+					return false;
+			}
+			return true;
+		}
+
+		private boolean isValidIPv4Address(String hostString) {
+			int index;
+			int index2;
+			try {
+				int num;
+				index = hostString.indexOf('.');
+				num = Integer.parseInt(hostString.substring(0, index));
+				if (num < 0 || num > 255)
+					return false;
+				index2 = hostString.indexOf('.', index + 1);
+				num = Integer.parseInt(hostString.substring(index + 1, index2));
+				if (num < 0 || num > 255)
+					return false;
+				index = hostString.indexOf('.', index2 + 1);
+				num = Integer.parseInt(hostString.substring(index2 + 1, index));
+				if (num < 0 || num > 255)
+					return false;
+				num = Integer.parseInt(hostString.substring(index + 1));
+				if (num < 0 || num > 255)
+					return false;
+			} catch (Exception e) {
+				return false;
+			}
+			return true;
+		}
+
+		private boolean isValidIP6Address(String ipAddress) {
+			int length = ipAddress.length();
+			boolean doubleColon = false;
+			int numberOfColons = 0;
+			int numberOfPeriods = 0;
+			String word = "";
+			char c = 0;
+			char prevChar = 0;
+			int offset = 0; // offset for [] ip addresses
+
+			if (length < 2)
+				return false;
+
+			for (int i = 0; i < length; i++) {
+				prevChar = c;
+				c = ipAddress.charAt(i);
+				switch (c) {
+
+				// case for an open bracket [x:x:x:...x]
+				case '[':
+					if (i != 0)
+						return false; // must be first character
+					if (ipAddress.charAt(length - 1) != ']')
+						return false; // must have a close ]
+					offset = 1;
+					if (length < 4)
+						return false;
+					break;
+
+				// case for a closed bracket at end of IP [x:x:x:...x]
+				case ']':
+					if (i != length - 1)
+						return false; // must be last charcter
+					if (ipAddress.charAt(0) != '[')
+						return false; // must have a open [
+					break;
+
+				// case for the last 32-bits represented as IPv4
+				// x:x:x:x:x:x:d.d.d.d
+				case '.':
+					numberOfPeriods++;
+					if (numberOfPeriods > 3)
+						return false;
+					if (!isValidIP4Word(word))
+						return false;
+					if (numberOfColons != 6 && !doubleColon)
+						return false;
+					// a special case ::1:2:3:4:5:d.d.d.d allows 7 colons with
+					// an IPv4 ending, otherwise 7 :'s is bad
+					if (numberOfColons == 7
+							&& ipAddress.charAt(0 + offset) != ':'
+							&& ipAddress.charAt(1 + offset) != ':')
+						return false;
+					word = "";
+					break;
+
+				case ':':
+					numberOfColons++;
+					if (numberOfColons > 7)
+						return false;
+					if (numberOfPeriods > 0)
+						return false;
+					if (prevChar == ':') {
+						if (doubleColon)
+							return false;
+						doubleColon = true;
+					}
+					word = "";
+					break;
+
+				default:
+					if (word.length() > 3)
+						return false;
+					if (!isValidHexChar(c))
+						return false;
+					word += c;
+				}
+			}
+
+			// Check if we have an IPv4 ending
+			if (numberOfPeriods > 0) {
+				if (numberOfPeriods != 3 || !isValidIP4Word(word))
+					return false;
+			} else {
+				// If we're at then end and we haven't had 7 colons then there
+				// is a problem
+				// unless we encountered a doubleColon
+				if (numberOfColons != 7 && !doubleColon) {
+					return false;
+				}
+
+				// If we have an empty word at the end, it means we ended in
+				// either a : or a .
+				// If we did not end in :: then this is invalid
+				if (word == "" && ipAddress.charAt(length - 1 - offset) != ':'
+						&& ipAddress.charAt(length - 2 - offset) != ':') {
+					return false;
+				}
+			}
+
+			return true;
+		}
+
+		private boolean isValidIP4Word(String word) {
+			char c;
+			if (word.length() < 1 || word.length() > 3)
+				return false;
+			for (int i = 0; i < word.length(); i++) {
+				c = word.charAt(i);
+				if (!(c >= '0' && c <= '9'))
+					return false;
+			}
+			if (Integer.parseInt(word) > 255)
+				return false;
+			return true;
+		}
+
+		private boolean isValidHexChar(char c) {
+
+			return (c >= '0' && c <= '9') || (c >= 'A' && c <= 'F')
+					|| (c >= 'a' && c <= 'f');
+		}
+
+	}
+
+	/*
+	 * Quote illegal chars for each component, but not the others
+	 * 
+	 * @param component java.lang.String the component to be converted @param
+	 * legalset java.lang.String the legal character set allowed in the
+	 * component s @return java.lang.String the converted string
+	 */
+	private String quoteComponent(String component, String legalset) {
+		try {
+			/*
+			 * Use a different encoder than URLEncoder since: 1. chars like "/",
+			 * "#", "@" etc needs to be preserved instead of being encoded, 2.
+			 * UTF-8 char set needs to be used for encoding instead of default
+			 * platform one
+			 */
+			return URIEncoderDecoder.quoteIllegal(component, legalset);
+		} catch (UnsupportedEncodingException e) {
+			throw new RuntimeException(e.toString());
+		}
+	}
+
+	public int compareTo(Object o) {
+		if (!(o instanceof URI))
+			throw new ClassCastException();
+
+		URI uri = (URI) o;
+		int ret = 0;
+
+		// compare schemes
+		if (scheme == null && uri.scheme != null)
+			return -1;
+		else if (scheme != null && uri.scheme == null)
+			return 1;
+		else if (scheme != null && uri.scheme != null) {
+			ret = scheme.compareToIgnoreCase(uri.scheme);
+			if (ret != 0)
+				return ret;
+		}
+
+		// compare opacities
+		if (!opaque && uri.opaque)
+			return -1;
+		else if (opaque && !uri.opaque)
+			return 1;
+		else if (opaque && uri.opaque) {
+			ret = schemespecificpart.compareTo(uri.schemespecificpart);
+			if (ret != 0)
+				return ret;
+		} else {
+
+			// otherwise both must be hierarchical
+
+			// compare authorities
+			if (authority != null && uri.authority == null)
+				return -1;
+			else if (authority == null && uri.authority != null)
+				return 1;
+			else if (authority != null && uri.authority != null) {
+				if (host != null && uri.host != null) {
+					// both are server based, so compare userinfo, host, port
+					if (userinfo != null && uri.userinfo == null)
+						return -1;
+					else if (userinfo == null && uri.userinfo != null)
+						return 1;
+					else if (userinfo != null && uri.userinfo != null) {
+						ret = userinfo.compareTo(uri.userinfo);
+						if (ret != 0)
+							return ret;
+					}
+
+					// userinfo's are the same, compare hostname
+					ret = host.compareTo(uri.host);
+					if (ret != 0)
+						return ret;
+
+					// compare port
+					if (port != uri.port)
+						return port - uri.port;
+				} else { // one or both are registry based, compare the whole
+					// authority
+					ret = authority.compareTo(uri.authority);
+					if (ret != 0)
+						return ret;
+				}
+			}
+
+			// authorities are the same
+			// compare paths
+			ret = path.compareTo(uri.path);
+			if (ret != 0)
+				return ret;
+
+			// compare queries
+
+			if (query != null && uri.query == null)
+				return -1;
+			else if (query == null && uri.query != null)
+				return 1;
+			else if (query != null && uri.query != null) {
+				ret = query.compareTo(uri.query);
+				if (ret != 0)
+					return ret;
+			}
+
+		}
+
+		// everything else is identical, so compare fragments
+		if (fragment != null && uri.fragment == null)
+			return -1;
+		else if (fragment == null && uri.fragment != null)
+			return 1;
+		else if (fragment != null && uri.fragment != null) {
+			ret = fragment.compareTo(uri.fragment);
+			if (ret != 0)
+				return ret;
+		}
+
+		// identical
+		return 0;
+	}
+
+	public static URI create(String uri) {
+		URI result = null;
+		try {
+			result = new URI(uri);
+		} catch (URISyntaxException e) {
+			throw new IllegalArgumentException(e.getMessage());
+		}
+		return result;
+	}
+
+	private URI duplicate() {
+		URI clone = new URI();
+		clone.absolute = absolute;
+		clone.authority = authority;
+		clone.fragment = fragment;
+		clone.host = host;
+		clone.opaque = opaque;
+		clone.path = path;
+		clone.port = port;
+		clone.query = query;
+		clone.scheme = scheme;
+		clone.schemespecificpart = schemespecificpart;
+		clone.userinfo = userinfo;
+		clone.serverAuthority = serverAuthority;
+		return clone;
+	}
+
+	private String convertHexToLowerCase(String s) {
+		// takes a string that may contain hex sequences like %F1 or %2b
+		// and converts the hex values following the '%' to lowercase
+		StringBuffer result = new StringBuffer("");
+		if (s.indexOf('%') == -1)
+			return s;
+
+		int index = 0, previndex = 0;
+		while ((index = s.indexOf('%', previndex)) != -1) {
+			result.append(s.substring(previndex, index + 1));
+			result.append(s.substring(index + 1, index + 3).toLowerCase());
+			index += 3;
+			previndex = index;
+		}
+		return result.toString();
+	}
+
+	private boolean equalsHexCaseInsensitive(String first, String second) {
+		// takes two strings that may contain hex sequences like %F1 or %2b
+		// and compares them, ignoring case for the hex values
+		// hex values must always occur in pairs like above
+
+		if (first.indexOf('%') != second.indexOf('%'))
+			return first.equals(second);
+
+		int index = 0, previndex = 0;
+		while ((index = first.indexOf('%', previndex)) != -1
+				&& second.indexOf('%', previndex) == index) {
+			boolean match = first.substring(previndex, index).equals(
+					second.substring(previndex, index));
+			if (!match)
+				return false;
+
+			match = first.substring(index + 1, index + 3).equalsIgnoreCase(
+					second.substring(index + 1, index + 3));
+			if (!match)
+				return false;
+
+			index += 3;
+			previndex = index;
+		}
+		if (first.length() != 0 && previndex == first.length())
+			return true;
+		return first.substring(previndex).equals(second.substring(previndex));
+	}
+
+	public boolean equals(Object o) {
+		if (!(o instanceof URI))
+			return false;
+		URI uri = (URI) o;
+
+		if (uri.fragment == null && fragment != null || uri.fragment != null
+				&& fragment == null)
+			return false;
+		else if (uri.fragment != null && fragment != null)
+			if (!equalsHexCaseInsensitive(uri.fragment, fragment))
+				return false;
+
+		if (uri.scheme == null && scheme != null || uri.scheme != null
+				&& scheme == null)
+			return false;
+		else if (uri.scheme != null && scheme != null)
+			if (!uri.scheme.equalsIgnoreCase(scheme))
+				return false;
+
+		if (uri.opaque && opaque) {
+			return equalsHexCaseInsensitive(uri.schemespecificpart,
+					schemespecificpart);
+		} else if (!uri.opaque && !opaque) {
+			if (!equalsHexCaseInsensitive(path, uri.path))
+				return false;
+
+			if (uri.query != null && query == null || uri.query == null
+					&& query != null)
+				return false;
+			else if (uri.query != null && query != null)
+				if (!equalsHexCaseInsensitive(uri.query, query))
+					return false;
+
+			if (uri.authority != null && authority == null
+					|| uri.authority == null && authority != null)
+				return false;
+			else if (uri.authority != null && authority != null) {
+				if (uri.host != null && host == null || uri.host == null
+						&& host != null)
+					return false;
+				else if (uri.host == null && host == null) {
+					// both are registry based, so compare the whole authority
+					return equalsHexCaseInsensitive(uri.authority, authority);
+				} else { // uri.host != null && host != null, so server-based
+					if (!host.equalsIgnoreCase(uri.host))
+						return false;
+
+					if (port != uri.port)
+						return false;
+
+					if (uri.userinfo != null && userinfo == null
+							|| uri.userinfo == null && userinfo != null)
+						return false;
+					else if (uri.userinfo != null && userinfo != null)
+						return equalsHexCaseInsensitive(userinfo, uri.userinfo);
+					else
+						return true;
+				}
+			} else
+				// no authority
+				return true;
+
+		} else
+			// one is opaque, the other hierarchical
+			return false;
+
+	}
+
+	public String getAuthority() {
+		if (authority == null || authority.equals(""))
+			return null;
+		return decode(authority);
+	}
+
+	/**
+	 * Returns the fragment component.
+	 * 
+	 * @return String
+	 */
+	public String getFragment() {
+		return decode(fragment);
+	}
+
+	/**
+	 * Returns the host component.
+	 * 
+	 * @return String
+	 */
+	public String getHost() {
+		return host;
+	}
+
+	/**
+	 * Returns the path component.
+	 * 
+	 * @return String
+	 */
+	public String getPath() {
+		return decode(path);
+	}
+
+	/**
+	 * Returns the port number.
+	 * 
+	 * @return int
+	 */
+	public int getPort() {
+		return port;
+	}
+
+	/**
+	 * Returns the query component.
+	 * 
+	 * @return String
+	 */
+	public String getQuery() {
+		return decode(query);
+	}
+
+	/**
+	 * Returns the authority component in raw form.
+	 * 
+	 * @return String
+	 */
+	public String getRawAuthority() {
+		if (authority == null || authority.equals(""))
+			return null;
+		return authority;
+	}
+
+	/**
+	 * Returns the fragment component in raw form.
+	 * 
+	 * @return String
+	 */
+	public String getRawFragment() {
+		return fragment;
+	}
+
+	/**
+	 * Returns the path component in raw form.
+	 * 
+	 * @return String
+	 */
+	public String getRawPath() {
+		return path;
+	}
+
+	/**
+	 * Returns the query component in raw form.
+	 * 
+	 * @return String
+	 */
+	public String getRawQuery() {
+		return query;
+	}
+
+	/**
+	 * Returns the scheme-specific part component in raw form.
+	 * 
+	 * @return String
+	 */
+	public String getRawSchemeSpecificPart() {
+		return schemespecificpart;
+	}
+
+	/**
+	 * Returns the user-info component in raw form.
+	 * 
+	 * @return String
+	 */
+	public String getRawUserInfo() {
+		return userinfo;
+	}
+
+	/**
+	 * Returns the scheme.
+	 * 
+	 * @return String
+	 */
+	public String getScheme() {
+		return scheme;
+	}
+
+	/**
+	 * Returns the scheme-specific part component.
+	 * 
+	 * @return String
+	 */
+	public String getSchemeSpecificPart() {
+		return decode(schemespecificpart);
+	}
+
+	/**
+	 * Returns the userinfo.
+	 * 
+	 * @return String
+	 */
+	public String getUserInfo() {
+		return decode(userinfo);
+	}
+
+	public int hashCode() {
+		if (hash == -1)
+			hash = getHashString().hashCode();
+		return hash;
+	}
+
+	/**
+	 * Indicates whether this URI is absolute
+	 * 
+	 * @return boolean
+	 */
+	public boolean isAbsolute() {
+		return absolute;
+	}
+
+	/**
+	 * Indicates whether this URI is opaque
+	 * 
+	 * @return true if the URI is opaque, otherwise false
+	 */
+	public boolean isOpaque() {
+		return opaque;
+	}
+
+	/*
+	 * Normalize path, and return the resulting string
+	 */
+	private String normalize(String fullPath) {
+
+		int index = fullPath.indexOf(':');
+		int index2 = fullPath.indexOf('/');
+
+		StringBuffer newpath = new StringBuffer();
+
+		index = 0;
+		index2 = 0;
+		int pathlen = fullPath.length();
+		index = -1;
+		// count the number of '/'s, to determine number of segments
+		int size = 0;
+		if (pathlen > 0 && fullPath.charAt(0) != '/')
+			size++;
+		while ((index = fullPath.indexOf('/', index + 1)) != -1)
+			if (index + 1 < pathlen && fullPath.charAt(index + 1) != '/')
+				size++;
+
+		String[] seglist = new String[size];
+		boolean[] include = new boolean[size];
+
+		// break the path into segments and store in the list
+		int current = 0;
+		index = (pathlen > 0 && fullPath.charAt(0) == '/') ? 1 : 0;
+		while ((index2 = fullPath.indexOf('/', index + 1)) != -1) {
+			seglist[current++] = fullPath.substring(index, index2);
+			index = index2 + 1;
+		}
+
+		// if current==size, then the last character was a slash
+		// and there are no more segments
+		if (current < size)
+			seglist[current] = fullPath.substring(index);
+
+		// determine which segments get included in the normalized path
+		for (int i = 0; i < size; i++) {
+			include[i] = true;
+			if (seglist[i].equals("..")) {
+				int remove = i - 1;
+				// search back to find a segment to remove, if possible
+				while (remove > -1 && !include[remove]) {
+					remove--;
+				}
+				// if we find a segment to remove, remove it and the ".."
+				// segment
+				if (remove > -1 && !seglist[remove].equals("..")) {
+					include[remove] = false;
+					include[i] = false;
+				}
+			} else if (seglist[i].equals(".")) // remove the "." segment
+				include[i] = false;
+		}
+
+		// put the path back together
+		newpath = new StringBuffer();
+		if (fullPath.startsWith("/"))
+			newpath.append('/');
+
+		for (int i = 0; i < seglist.length; i++)
+			if (include[i]) {
+				newpath.append(seglist[i]);
+				newpath.append('/');
+			}
+
+		// if we used at least one segment
+		// and the path previously ended with a slash
+		// and the last segment is still used, then
+		// delete the extra trailing '/'
+		if (!fullPath.endsWith("/") && seglist.length > 0
+				&& include[seglist.length - 1])
+			newpath.deleteCharAt(newpath.length() - 1);
+
+		String result = newpath.toString();
+
+		// check for a ':' in the first segment
+		// if one exists, prepend "./" to normalize
+		index = result.indexOf(':');
+		index2 = result.indexOf('/');
+		if (index != -1 && (index < index2 || index2 == -1)) {
+			newpath.insert(0, "./");
+			result = newpath.toString();
+		}
+		return result;
+	}
+
+	public URI normalize() {
+		if (opaque) {
+			return this;
+		}
+		URI result = duplicate(); // get an exact copy of the URI
+		result.path = normalize(path);
+		// re-calculate the scheme specific part since
+		// the path of the normalized URI is different from this URI.
+		result.setSchemeSpecificPart();
+		return result;
+	}
+
+	/**
+	 * Return this uri instance if it has already been determined as a
+	 * ServerAuthority Otherwise try to parse it again as a server authority to
+	 * produce a URISyntaxException with the proper diagnostic message.
+	 */
+	public URI parseServerAuthority() throws URISyntaxException {
+		if (!serverAuthority)
+			new Helper().parseAuthority(true);
+		return this;
+	}
+
+	public URI relativize(URI relative) {
+		if (relative.opaque || opaque)
+			return relative;
+		if (!(scheme == null && relative.scheme == null)
+				&& !scheme.equals(relative.scheme))
+			return relative;
+		if (!(authority == null && relative.authority == null)
+				&& !authority.equals(relative.authority))
+			return relative;
+
+		// append a slash to the end if necessary
+		// (for a case like: "dir1" against "dir1/hi" should return "hi", not
+		// "/hi")
+		String tempPath = null;
+		if (path.endsWith("/"))
+			tempPath = path;
+		else
+			tempPath = path + "/";
+
+		// normalize both paths
+		String normrel = normalize(relative.path);
+		tempPath = normalize(tempPath);
+
+		if (!normrel.startsWith(tempPath))
+			return relative;
+
+		URI result = new URI();
+		result.fragment = relative.fragment;
+		result.query = relative.fragment;
+		result.path = normrel.substring(tempPath.length());
+
+		return result;
+	}
+
+	public URI resolve(URI relative) {
+		if (relative.absolute || opaque)
+			return relative;
+
+		URI result;
+		if (relative.path.equals("") && relative.scheme == null
+				&& relative.authority == null && relative.query == null
+				&& relative.fragment != null) {
+			// if the relative URI only consists of fragment,
+			// the resulved URI is very similar to this URI,
+			// except that it has the fragement from the relative URI.
+			result = duplicate();
+			result.fragment = relative.fragment;
+			// no need to re-calculate the scheme specific part,
+			// since fragment is not part of scheme specific part.
+			return result;
+		}
+
+		if (relative.authority != null) {
+			// if the relative URI has authority,
+			// the resolved URI is almost the same as the relative URI,
+			// except that it has the scheme of this URI.
+			result = relative.duplicate();
+			result.scheme = scheme;
+			result.absolute = absolute;
+		} else {
+			// since relative URI has no authority,
+			// the resolved URI is very similar to this URI,
+			// except that it has the query and fragment of the relative URI,
+			// and the path is different.
+			result = duplicate();
+			result.fragment = relative.fragment;
+			result.query = relative.query;
+			if (relative.path.startsWith("/")) {
+				result.path = relative.path;
+			} else {
+				// resolve a relative reference
+				int endindex = path.lastIndexOf('/') + 1;
+				result.path = normalize(path.substring(0, endindex)
+						+ relative.path);
+			}
+			// re-calculate the scheme specific part since
+			// query and path of the resolved URI is different from this URI.
+			result.setSchemeSpecificPart();
+		}
+		return result;
+	}
+
+	/**
+	 * Helper method used to re-calculate the scheme specific part of the
+	 * resolved or normalized URIs
+	 */
+	private void setSchemeSpecificPart() {
+		// ssp = [//authority][path][?query]
+		StringBuffer ssp = new StringBuffer();
+		if (authority != null)
+			ssp.append("//" + authority);
+		if (path != null)
+			ssp.append(path);
+		if (query != null)
+			ssp.append("?" + query);
+		schemespecificpart = ssp.toString();
+	}
+
+	public URI resolve(String relative) {
+		return resolve(create(relative));
+	}
+
+	/*
+	 * Encode unicode chars that are not part of US-ASCII char set into the
+	 * escaped form
+	 * 
+	 * i.e. The Euro currency symbol is encoded as "%E2%82%AC".
+	 * 
+	 * @param component java.lang.String the component to be converted @param
+	 * legalset java.lang.String the legal character set allowed in the
+	 * component s @return java.lang.String the converted string
+	 */
+	private String encodeOthers(String s) {
+		try {
+			/*
+			 * Use a different encoder than URLEncoder since: 1. chars like "/",
+			 * "#", "@" etc needs to be preserved instead of being encoded, 2.
+			 * UTF-8 char set needs to be used for encoding instead of default
+			 * platform one 3. Only other chars need to be converted
+			 */
+			return URIEncoderDecoder.encodeOthers(s);
+		} catch (UnsupportedEncodingException e) {
+			throw new RuntimeException(e.toString());
+		}
+	}
+
+	private String decode(String s) {
+		if (s == null)
+			return s;
+
+		try {
+			return URIEncoderDecoder.decode(s);
+		} catch (UnsupportedEncodingException e) {
+			throw new RuntimeException(e.toString());
+		}
+	}
+
+	public String toASCIIString() {
+		return encodeOthers(toString());
+	}
+
+	public String toString() {
+		if (string == null) {
+			StringBuffer result = new StringBuffer();
+			if (scheme != null) {
+				result.append(scheme);
+				result.append(':');
+			}
+			if (opaque)
+				result.append(schemespecificpart);
+			else {
+				if (authority != null) {
+					result.append("//");
+					result.append(authority);
+				}
+
+				if (path != null)
+					result.append(path);
+
+				if (query != null) {
+					result.append('?');
+					result.append(query);
+				}
+			}
+
+			if (fragment != null) {
+				result.append('#');
+				result.append(fragment);
+			}
+
+			string = result.toString();
+		}
+		return string;
+	}
+
+	/*
+	 * Form a string from the components of this URI, similarly to the
+	 * toString() method. But this method converts scheme and host to lowercase,
+	 * and converts escaped octets to lowercase.
+	 */
+	private String getHashString() {
+		StringBuffer result = new StringBuffer();
+		if (scheme != null) {
+			result.append(scheme.toLowerCase());
+			result.append(':');
+		}
+		if (opaque)
+			result.append(schemespecificpart);
+		else {
+			if (authority != null) {
+				result.append("//");
+				if (host == null)
+					result.append(authority);
+				else {
+					if (userinfo != null)
+						result.append(userinfo + "@");
+					result.append(host.toLowerCase());
+					if (port != -1)
+						result.append(":" + port);
+				}
+			}
+
+			if (path != null)
+				result.append(path);
+
+			if (query != null) {
+				result.append('?');
+				result.append(query);
+			}
+		}
+
+		if (fragment != null) {
+			result.append('#');
+			result.append(fragment);
+		}
+
+		return convertHexToLowerCase(result.toString());
+	}
+
+	public URL toURL() throws MalformedURLException {
+		if (!absolute) {
+			throw new IllegalArgumentException(Msg.getString("K0312") + ": "
+					+ toString());
+		}
+		return new URL(toString());
+	}
+
+	private void readObject(ObjectInputStream in) throws IOException,
+			ClassNotFoundException {
+		in.defaultReadObject();
+		try {
+			new Helper().parseURI(string, false);
+		} catch (URISyntaxException e) {
+			throw new IOException(e.toString());
+		}
+	}
+
+	private void writeObject(ObjectOutputStream out) throws IOException,
+			ClassNotFoundException {
+		// call toString() to ensure the value of string field is calculated
+		toString();
+		out.defaultWriteObject();
+	}
+}

Added: incubator/harmony/enhanced/trunk/sandbox/contribs/ibm_core/java-src/luni/src/java/net/URIEncoderDecoder.java
URL: http://svn.apache.org/viewcvs/incubator/harmony/enhanced/trunk/sandbox/contribs/ibm_core/java-src/luni/src/java/net/URIEncoderDecoder.java?rev=350181&view=auto
==============================================================================
--- incubator/harmony/enhanced/trunk/sandbox/contribs/ibm_core/java-src/luni/src/java/net/URIEncoderDecoder.java (added)
+++ incubator/harmony/enhanced/trunk/sandbox/contribs/ibm_core/java-src/luni/src/java/net/URIEncoderDecoder.java Wed Nov 30 21:29:27 2005
@@ -0,0 +1,221 @@
+/* Copyright 2004, 2005 The Apache Software Foundation or its licensors, as applicable
+ * 
+ * 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 java.net;
+
+
+import java.io.ByteArrayOutputStream;
+import java.io.UnsupportedEncodingException;
+
+import com.ibm.oti.util.Msg;
+
+/**
+ * This class is used to encode a string using the format required by
+ * <code>application/x-www-form-urlencoded</code> MIME content type.
+ * 
+ * It contains helper methods used by the URI class, and performs encoding and
+ * decoding in a slightly different way than URLEncoder and URLDecoder.
+ */
+class URIEncoderDecoder {
+
+	static final String digits = "0123456789ABCDEF";
+
+	static final String encoding = "UTF8";
+
+	/**
+	 * Validate a string by checking if it contains any characters other than:
+	 * 
+	 * 1. letters ('a'..'z', 'A'..'Z') 2. numbers ('0'..'9') 3. characters in
+	 * the legalset parameter 4. others (Unicode characters that are not in
+	 * US-ASCII set, and are not ISO Control or are not ISO Space characters)
+	 * <p>
+	 * called from URI.Helper.parseURI() to validate each component
+	 * <p>
+	 * 
+	 * @param s
+	 *            java.lang.String the string to be validated
+	 * @param legal
+	 *            java.lang.String the characters allowed in the String s
+	 * 
+	 */
+	static void validate(String s, String legal) throws URISyntaxException {
+		for (int i = 0; i < s.length();) {
+			char ch = s.charAt(i);
+			if (ch == '%') {
+				do {
+					if (i + 2 >= s.length()) {
+						throw new URISyntaxException(s, Msg.getString("K0313"),
+								i);
+					}
+					int d1 = Character.digit(s.charAt(i + 1), 16);
+					int d2 = Character.digit(s.charAt(i + 2), 16);
+					if (d1 == -1 || d2 == -1) {
+						throw new URISyntaxException(s, Msg.getString("K0314",
+								s.substring(i, i + 3)), i);
+					}
+
+					i += 3;
+				} while (i < s.length() && s.charAt(i) == '%');
+
+				continue;
+			}
+			if (!((ch >= 'a' && ch <= 'z') || (ch >= 'A' && ch <= 'Z')
+					|| (ch >= '0' && ch <= '9') || legal.indexOf(ch) > -1 || (ch > 127
+					&& !Character.isSpaceChar(ch) && !Character
+					.isISOControl(ch)))) {
+				throw new URISyntaxException(s, Msg.getString("K00c1"), i);
+			}
+			i++;
+		}
+	}
+
+	static void validateSimple(String s, String legal)
+			throws URISyntaxException {
+		for (int i = 0; i < s.length();) {
+			char ch = s.charAt(i);
+			if (!((ch >= 'a' && ch <= 'z') || (ch >= 'A' && ch <= 'Z')
+					|| (ch >= '0' && ch <= '9') || legal.indexOf(ch) > -1)) {
+				throw new URISyntaxException(s, Msg.getString("K00c1"), i);
+			}
+			i++;
+		}
+	}
+
+	/**
+	 * All characters except letters ('a'..'z', 'A'..'Z') and numbers ('0'..'9')
+	 * and legal characters are converted into their hexidecimal value prepended
+	 * by '%'.
+	 * <p>
+	 * For example: '#' -> %23
+	 * <p>
+	 * Other characters, which are Unicode chars that are not US-ASCII, and are
+	 * not ISO Control or are not ISO Space chars, are preserved.
+	 * <p>
+	 * Called from URI.quoteComponent() (for multiple argument constructors)
+	 * <p>
+	 * 
+	 * @param s
+	 *            java.lang.String the string to be converted
+	 * @param legal
+	 *            java.lang.String the characters allowed to be preserved in the
+	 *            string s
+	 * @return java.lang.String the converted string
+	 */
+	static String quoteIllegal(String s, String legal)
+			throws UnsupportedEncodingException {
+		StringBuffer buf = new StringBuffer();
+		for (int i = 0; i < s.length(); i++) {
+			char ch = s.charAt(i);
+			if ((ch >= 'a' && ch <= 'z')
+					|| (ch >= 'A' && ch <= 'Z')
+					|| (ch >= '0' && ch <= '9')
+					|| legal.indexOf(ch) > -1
+					|| (ch > 127 && !Character.isSpaceChar(ch) && !Character
+							.isISOControl(ch))) {
+				buf.append(ch);
+			} else {
+				byte[] bytes = new String(new char[] { ch }).getBytes(encoding);
+				for (int j = 0; j < bytes.length; j++) {
+					buf.append('%');
+					buf.append(digits.charAt((bytes[j] & 0xf0) >> 4));
+					buf.append(digits.charAt(bytes[j] & 0xf));
+				}
+			}
+		}
+		return buf.toString();
+	}
+
+	/**
+	 * Other characters, which are Unicode chars that are not US-ASCII, and are
+	 * not ISO Control or are not ISO Space chars are not preserved. They are
+	 * converted into their hexidecimal value prepended by '%'.
+	 * <p>
+	 * For example: Euro currency symbol -> "%E2%82%AC".
+	 * <p>
+	 * Called from URI.toASCIIString()
+	 * <p>
+	 * 
+	 * @param s
+	 *            java.lang.String the string to be converted
+	 * @return java.lang.String the converted string
+	 */
+	static String encodeOthers(String s) throws UnsupportedEncodingException {
+		StringBuffer buf = new StringBuffer();
+		for (int i = 0; i < s.length(); i++) {
+			char ch = s.charAt(i);
+			if (ch <= 127)
+				buf.append(ch);
+			else {
+				byte[] bytes = new String(new char[] { ch }).getBytes(encoding);
+				for (int j = 0; j < bytes.length; j++) {
+					buf.append('%');
+					buf.append(digits.charAt((bytes[j] & 0xf0) >> 4));
+					buf.append(digits.charAt(bytes[j] & 0xf));
+				}
+			}
+		}
+		return buf.toString();
+	}
+
+	/**
+	 * Decodes the string argument which is assumed to be encoded in the
+	 * <code>x-www-form-urlencoded</code> MIME content type using the UTF-8
+	 * encoding scheme.
+	 * <p>
+	 * '%' and two following hex digit characters are converted to the
+	 * equivalent byte value. All other characters are passed through
+	 * unmodified.
+	 * 
+	 * <p>
+	 * e.g. "A%20B%20C %24%25" -> "A B C $%"
+	 * <p>
+	 * Called from URI.getXYZ() methods
+	 * <p>
+	 * 
+	 * @param s
+	 *            java.lang.String The encoded string.
+	 * @return java.lang.String The decoded version.
+	 */
+	static String decode(String s) throws UnsupportedEncodingException {
+
+		StringBuffer result = new StringBuffer();
+		ByteArrayOutputStream out = new ByteArrayOutputStream();
+		for (int i = 0; i < s.length();) {
+			char c = s.charAt(i);
+			if (c == '%') {
+				out.reset();
+				do {
+					if (i + 2 >= s.length())
+						throw new IllegalArgumentException(Msg.getString(
+								"K01fe", i));
+					int d1 = Character.digit(s.charAt(i + 1), 16);
+					int d2 = Character.digit(s.charAt(i + 2), 16);
+					if (d1 == -1 || d2 == -1)
+						throw new IllegalArgumentException(Msg.getString(
+								"K01ff", s.substring(i, i + 3), String
+										.valueOf(i)));
+					out.write((byte) ((d1 << 4) + d2));
+					i += 3;
+				} while (i < s.length() && s.charAt(i) == '%');
+				result.append(out.toString(encoding));
+				continue;
+			}
+			result.append(c);
+			i++;
+		}
+		return result.toString();
+	}
+
+}

Added: incubator/harmony/enhanced/trunk/sandbox/contribs/ibm_core/java-src/luni/src/java/net/URISyntaxException.java
URL: http://svn.apache.org/viewcvs/incubator/harmony/enhanced/trunk/sandbox/contribs/ibm_core/java-src/luni/src/java/net/URISyntaxException.java?rev=350181&view=auto
==============================================================================
--- incubator/harmony/enhanced/trunk/sandbox/contribs/ibm_core/java-src/luni/src/java/net/URISyntaxException.java (added)
+++ incubator/harmony/enhanced/trunk/sandbox/contribs/ibm_core/java-src/luni/src/java/net/URISyntaxException.java Wed Nov 30 21:29:27 2005
@@ -0,0 +1,121 @@
+/* Copyright 2004, 2005 The Apache Software Foundation or its licensors, as applicable
+ * 
+ * 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 java.net;
+
+import com.ibm.oti.util.Msg;
+
+
+/**
+ * Represents an exception that occurred during parsing of a URI.
+ */
+public class URISyntaxException extends Exception {
+
+	private String input;
+
+	private int index;
+
+	/**
+	 * Constructs a URISyntaxException, containing the input that caused the
+	 * exception, a description of the problem, and the index at which the error
+	 * occurred.
+	 * 
+	 * @param input
+	 * @param reason
+	 * @param index
+	 * @exception NullPointerException
+	 *                if input or reason is null
+	 * @exception IllegalArgumentException
+	 *                if index < -1
+	 */
+	public URISyntaxException(String input, String reason, int index) {
+		super(reason);
+
+		if (input == null || reason == null)
+			throw new NullPointerException();
+
+		if (index < -1)
+			throw new IllegalArgumentException();
+
+		this.input = input;
+		this.index = index;
+	}
+
+	/**
+	 * Constructs a URISyntaxException containing the string that caused the
+	 * exception and a description of the error.
+	 * 
+	 * @param input
+	 * @param reason
+	 * 
+	 * @exception NullPointerException
+	 *                if input or reason is null
+	 */
+	public URISyntaxException(String input, String reason) {
+		super(reason);
+
+		if (input == null || reason == null)
+			throw new NullPointerException();
+
+		this.input = input;
+		index = -1;
+	}
+
+	/**
+	 * Answers the index at which the syntax error was found, or -1 if the index
+	 * is unknown/unavailable.
+	 * 
+	 * @return the index of the syntax error
+	 */
+	public int getIndex() {
+		return index;
+	}
+
+	/**
+	 * Answers a String describing the syntax error in the URI string
+	 * 
+	 * @return a String describing the syntax error
+	 */
+	public String getReason() {
+		return super.getMessage();
+	}
+
+	/**
+	 * Answers the String that contained the syntax error
+	 * 
+	 * @return the String that caused the exception
+	 */
+	public String getInput() {
+		return input;
+	}
+
+	/**
+	 * Returns a description of the exception, including the reason, the string
+	 * that had the syntax error, and the index of the syntax error if
+	 * available.
+	 * 
+	 * @return a String containing information about the exception.
+	 * @see java.lang.Throwable#getMessage()
+	 */
+	public String getMessage() {
+		String reason = super.getMessage();
+
+		if (index != -1) {
+			return Msg.getString("K0326", new String[] { reason,
+					Integer.toString(index), input });
+		}
+		return Msg.getString("K0327", new String[] { reason, input });
+	}
+}

Added: incubator/harmony/enhanced/trunk/sandbox/contribs/ibm_core/java-src/luni/src/java/net/URL.java
URL: http://svn.apache.org/viewcvs/incubator/harmony/enhanced/trunk/sandbox/contribs/ibm_core/java-src/luni/src/java/net/URL.java?rev=350181&view=auto
==============================================================================
--- incubator/harmony/enhanced/trunk/sandbox/contribs/ibm_core/java-src/luni/src/java/net/URL.java (added)
+++ incubator/harmony/enhanced/trunk/sandbox/contribs/ibm_core/java-src/luni/src/java/net/URL.java Wed Nov 30 21:29:27 2005
@@ -0,0 +1,837 @@
+/* Copyright 1998, 2005 The Apache Software Foundation or its licensors, as applicable
+ * 
+ * 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 java.net;
+
+
+import java.io.IOException;
+import java.io.InputStream;
+import java.security.AccessController;
+import java.util.Hashtable;
+import java.util.StringTokenizer;
+
+import com.ibm.oti.util.PriviAction;
+
+/**
+ * An instance of class URL specifies the location of a resource on the world
+ * wide web as specified by RFC 1738.
+ * 
+ */
+
+public final class URL implements java.io.Serializable {
+	static final long serialVersionUID = -7627629688361524110L;
+
+	private static final NetPermission specifyStreamHandlerPermission = new NetPermission(
+			"specifyStreamHandler");
+
+	private int hashCode;
+
+	/**
+	 * The receiver's filename.
+	 * 
+	 * @serial the file of this URL
+	 * 
+	 */
+	private String file;
+
+	/**
+	 * The receiver's protocol identifier.
+	 * 
+	 * @serial the protocol of this URL (http, file)
+	 * 
+	 */
+	private String protocol = null;
+
+	/**
+	 * The receiver's host name.
+	 * 
+	 * @serial the host of this URL
+	 * 
+	 */
+	private String host;
+
+	/**
+	 * The receiver's port number.
+	 * 
+	 * @serial the port of this URL
+	 * 
+	 */
+	private int port = -1;
+
+	/**
+	 * The receiver's authority.
+	 * 
+	 * @serial the authority of this URL
+	 * 
+	 */
+	private String authority = null;
+
+	/**
+	 * The receiver's userInfo.
+	 */
+	private transient String userInfo = null;
+
+	/**
+	 * The receiver's path.
+	 */
+	private transient String path = null;
+
+	/**
+	 * The receiver's query.
+	 */
+	private transient String query = null;
+
+	/**
+	 * The receiver's reference.
+	 * 
+	 * @serial the reference of this URL
+	 * 
+	 */
+	private String ref = null;
+
+	/**
+	 * Cache for storing protocol handler
+	 */
+	private static Hashtable streamHandlers = new Hashtable();
+
+	/**
+	 * The URL Stream (protocol) Handler
+	 */
+	transient URLStreamHandler strmHandler;
+
+	/**
+	 * The factory responsible for producing URL Stream (protocol) Handler
+	 */
+	private static URLStreamHandlerFactory streamHandlerFactory;
+
+	/**
+	 * Sets the URL Stream (protocol) handler factory. This method can be
+	 * invoked only once during an application's lifetime.
+	 * <p>
+	 * A security check is performed to verify that the current Policy allows
+	 * the stream handler factory to be set.
+	 * 
+	 * @param streamFactory
+	 *            URLStreamHandlerFactory The factory to use for finding stream
+	 *            handlers.
+	 */
+	public static synchronized void setURLStreamHandlerFactory(
+			URLStreamHandlerFactory streamFactory) {
+		if (streamHandlerFactory != null)
+			throw new Error(com.ibm.oti.util.Msg.getString("K004b"));
+		SecurityManager sm = System.getSecurityManager();
+		if (sm != null)
+			sm.checkSetFactory();
+		streamHandlers.clear();
+		streamHandlerFactory = streamFactory;
+	}
+
+	/**
+	 * Constructs a new URL instance by parsing the specification.
+	 * 
+	 * @param spec
+	 *            java.lang.String a URL specification.
+	 * 
+	 * @throws MalformedURLException
+	 *             if the spec could not be parsed as an URL.
+	 */
+	public URL(String spec) throws MalformedURLException {
+		this((URL) null, spec, (URLStreamHandler) null);
+	}
+
+	/**
+	 * Constructs a new URL by parsing the specification given by
+	 * <code>spec</code> and using the context provided by
+	 * <code>context</code>.
+	 * <p>
+	 * The protocol of the specification is obtained by parsing the
+	 * <code> spec </code> string.
+	 * <p>
+	 * If the <code>spec</code> does not specify a protocol:
+	 * <ul>
+	 * <li>If the context is <code>null</code>, then a
+	 * <code>MalformedURLException</code>.</li>
+	 * <li>If the context is not <code>null</code>, then the protocol is
+	 * obtained from the context.</li>
+	 * </ul>
+	 * If the <code>spec</code> does specify a protocol:
+	 * <ul>
+	 * <li>If the context is <code>null</code>, or specifies a different
+	 * protocol than the spec, the context is ignored.</li>
+	 * <li>If the context is not <code>null</code> and specifies the same
+	 * protocol as the specification, the properties of the new <code>URL</code>
+	 * are obtained from the context.</li>
+	 * </ul>
+	 * 
+	 * @param context
+	 *            java.net.URL URL to use as context.
+	 * @param spec
+	 *            java.lang.String a URL specification.
+	 * 
+	 * @throws MalformedURLException
+	 *             if the spec could not be parsed as an URL.
+	 */
+	public URL(URL context, String spec) throws MalformedURLException {
+		this(context, spec, (URLStreamHandler) null);
+	}
+
+	/**
+	 * Constructs a new URL by parsing the specification given by
+	 * <code>spec</code> and using the context provided by
+	 * <code>context</code>.
+	 * <p>
+	 * If the handler argument is non-null, a security check is made to verify
+	 * that user-defined protocol handlers can be specified.
+	 * <p>
+	 * The protocol of the specification is obtained by parsing the
+	 * <code> spec </code> string.
+	 * <p>
+	 * If the <code>spec</code> does not specify a protocol:
+	 * <ul>
+	 * <li>If the context is <code>null</code>, then a
+	 * <code>MalformedURLException</code>.</li>
+	 * <li>If the context is not <code>null</code>, then the protocol is
+	 * obtained from the context.</li>
+	 * </ul>
+	 * If the <code>spec</code> does specify a protocol:
+	 * <ul>
+	 * <li>If the context is <code>null</code>, or specifies a different
+	 * protocol than the spec, the context is ignored.</li>
+	 * <li>If the context is not <code>null</code> and specifies the same
+	 * protocol as the specification, the properties of the new <code>URL</code>
+	 * are obtained from the context.</li>
+	 * </ul>
+	 * 
+	 * @param context
+	 *            java.net.URL URL to use as context.
+	 * @param spec
+	 *            java.lang.String a URL specification.
+	 * @param handler
+	 *            java.net.URLStreamHandler a URLStreamHandler.
+	 * 
+	 * @throws MalformedURLException
+	 *             if the spec could not be parsed as an URL
+	 */
+	public URL(URL context, String spec, URLStreamHandler handler)
+			throws MalformedURLException {
+		if (handler != null) {
+			SecurityManager sm = System.getSecurityManager();
+			if (sm != null)
+				sm.checkPermission(specifyStreamHandlerPermission);
+			strmHandler = handler;
+		}
+
+		if (spec == null) {
+			throw new MalformedURLException();
+		}
+		spec = spec.trim();
+
+		// The spec includes a protocol if it includes a colon character
+		// before the first occurance of a slash character. Note that,
+		// "protocol" is the field which holds this URLs protocol.
+		int index;
+		try {
+			index = spec.indexOf(':');
+		} catch (NullPointerException e) {
+			throw new MalformedURLException(e.toString());
+		}
+		int startIPv6Addr = spec.indexOf('[');
+		if (index >= 0) {
+			if ((startIPv6Addr == -1) || (index < startIPv6Addr)) {
+				protocol = spec.substring(0, index);
+				if (protocol.indexOf('/') >= 0) {
+					protocol = null;
+					index = -1;
+				} else
+					// Ignore case in protocol names.
+					protocol = protocol.toLowerCase();
+			}
+		}
+
+		if (protocol != null) {
+			// If the context was specified, and it had the same protocol
+			// as the spec, then fill in the receiver's slots from the values
+			// in the context but still allow them to be over-ridden later
+			// by the values in the spec.
+			if (context != null && protocol.equals(context.getProtocol())) {
+				String cPath = context.getPath();
+				if (cPath != null && cPath.startsWith("/")) {
+					set(protocol, context.getHost(), context.getPort(), context
+							.getAuthority(), context.getUserInfo(), cPath,
+							context.getQuery(), null);
+				}
+				if (strmHandler == null)
+					strmHandler = context.strmHandler;
+			}
+		} else {
+			// If the spec did not include a protocol, then the context
+			// *must* be specified. Fill in the receiver's slots from the
+			// values in the context, but still allow them to be over-ridden
+			// by the values in the ("relative") spec.
+			if (context == null)
+				throw new MalformedURLException(com.ibm.oti.util.Msg.getString(
+						"K00d8", spec));
+			set(context.getProtocol(), context.getHost(), context.getPort(),
+					context.getAuthority(), context.getUserInfo(), context
+							.getPath(), context.getQuery(), null);
+			if (strmHandler == null)
+				strmHandler = context.strmHandler;
+		}
+
+		// If the stream handler has not been determined, set it
+		// to the default for the specified protocol.
+		if (strmHandler == null) {
+			setupStreamHandler();
+			if (strmHandler == null)
+				throw new MalformedURLException(com.ibm.oti.util.Msg.getString(
+						"K00b3", protocol));
+		}
+
+		// Let the handler parse the URL. If the handler throws
+		// any exception, throw MalformedURLException instead.
+		//
+		// Note: We want "index" to be the index of the start of the scheme
+		// specific part of the URL. At this point, it will be either
+		// -1 or the index of the colon after the protocol, so we
+		// increment it to point at either character 0 or the character
+		// after the colon.
+		try {
+			strmHandler.parseURL(this, spec, ++index, spec.length());
+		} catch (Exception e) {
+			throw new MalformedURLException(e.toString());
+		}
+
+		if (port < -1 || port > 65535)
+			throw new MalformedURLException(com.ibm.oti.util.Msg.getString(
+					"K0325", port)); //$NON-NLS-1$
+	}
+
+	/**
+	 * Constructs a new URL instance using the arguments provided.
+	 * 
+	 * @param protocol
+	 *            String the protocol for the URL.
+	 * @param host
+	 *            String the name of the host.
+	 * @param file
+	 *            the name of the resource.
+	 * 
+	 * @throws MalformedURLException
+	 *             if the parameters do not represent a valid URL.
+	 */
+	public URL(String protocol, String host, String file)
+			throws MalformedURLException {
+		this(protocol, host, -1, file, (URLStreamHandler) null);
+	}
+
+	/**
+	 * Constructs a new URL instance using the arguments provided.
+	 * 
+	 * @param protocol
+	 *            String the protocol for the URL.
+	 * @param host
+	 *            String the name of the host.
+	 * @param port
+	 *            int the port number.
+	 * @param file
+	 *            String the name of the resource.
+	 * 
+	 * @throws MalformedURLException
+	 *             if the parameters do not represent a valid URL.
+	 */
+	public URL(String protocol, String host, int port, String file)
+			throws MalformedURLException {
+		this(protocol, host, port, file, (URLStreamHandler) null);
+	}
+
+	/**
+	 * Constructs a new URL instance using the arguments provided.
+	 * <p>
+	 * If the handler argument is non-null, a security check is made to verify
+	 * that user-defined protocol handlers can be specified.
+	 * 
+	 * @param protocol
+	 *            the protocol for the URL.
+	 * @param host
+	 *            the name of the host.
+	 * @param port
+	 *            the port number.
+	 * @param file
+	 *            the name of the resource.
+	 * @param handler
+	 *            the stream handler that this URL uses.
+	 * 
+	 * @throws MalformedURLException
+	 *             if the parameters do not represent an URL.
+	 */
+	public URL(String protocol, String host, int port, String file,
+			URLStreamHandler handler) throws MalformedURLException {
+		if (port < -1 || port > 65535)
+			throw new MalformedURLException(com.ibm.oti.util.Msg.getString(
+					"K0325", port)); //$NON-NLS-1$
+
+		// Set the fields from the arguments. Handle the case where the
+		// passed in "file" includes both a file and a ref part.
+		int index = -1;
+		index = file.indexOf("#", file.lastIndexOf("/"));
+		if (index >= 0)
+			set(protocol, host, port, file.substring(0, index), file
+					.substring(index + 1));
+		else
+			set(protocol, host, port, file, null);
+
+		// Set the stream handler for the URL either to the handler
+		// argument if it was specified, or to the default for the
+		// receiver's protocol if the handler was null.
+		if (handler == null) {
+			setupStreamHandler();
+			if (strmHandler == null)
+				throw new MalformedURLException(com.ibm.oti.util.Msg.getString(
+						"K00b3", protocol));
+		} else {
+			SecurityManager sm = System.getSecurityManager();
+			if (sm != null)
+				sm.checkPermission(specifyStreamHandlerPermission);
+			strmHandler = handler;
+		}
+	}
+
+	void fixURL() {
+		int index;
+		if (host != null && host.length() > 0) {
+			authority = host;
+			if (port != -1)
+				authority = authority + ":" + port;
+		}
+		if (host != null && (index = host.lastIndexOf('@')) > -1) {
+			userInfo = host.substring(0, index);
+			host = host.substring(index + 1);
+		} else {
+			userInfo = null;
+		}
+		if (file != null && (index = file.indexOf('?')) > -1) {
+			query = file.substring(index + 1);
+			path = file.substring(0, index);
+		} else {
+			query = null;
+			path = file;
+		}
+	}
+
+	/**
+	 * Sets the properties of this URL using the provided arguments. This method
+	 * is used both within this class and by the <code>URLStreamHandler</code>
+	 * code.
+	 * 
+	 * @param protocol
+	 *            the new protocol.
+	 * @param host
+	 *            the new host name.
+	 * @param port
+	 *            the new port number.
+	 * @param file
+	 *            the new file component.
+	 * @param ref
+	 *            the new reference.
+	 * 
+	 * @see URL
+	 * @see URLStreamHandler
+	 */
+	protected void set(String protocol, String host, int port, String file,
+			String ref) {
+		if (this.protocol == null) // The protocol cannot be changed
+			this.protocol = protocol;
+		this.host = host;
+		this.file = file;
+		this.port = port;
+		this.ref = ref;
+		hashCode = 0;
+		fixURL();
+	}
+
+	/**
+	 * Compares the argument to the receiver, and answers true if they represent
+	 * the same URL. Two URLs are equal if they have the same file, host, port,
+	 * protocol, and ref components.
+	 * 
+	 * @param o
+	 *            the object to compare with this URL.
+	 * @return <code>true</code> if the object is the same as this URL,
+	 *         <code>false</code> otherwise.
+	 * 
+	 * @see #hashCode
+	 */
+	public boolean equals(Object o) {
+		if (o == null)
+			return false;
+		if (this == o)
+			return true;
+		if (this.getClass() != o.getClass())
+			return false;
+		return strmHandler.equals(this, (URL) o);
+	}
+
+	/**
+	 * Answers true if the receiver and the argument refer to the same file. All
+	 * components except the reference are compared.
+	 * 
+	 * @param otherURL
+	 *            URL to compare against.
+	 * @return true if the same resource, false otherwise
+	 */
+	public boolean sameFile(URL otherURL) {
+		return strmHandler.sameFile(this, otherURL);
+	}
+
+	/**
+	 * Answers a hash code for this URL object.
+	 * 
+	 * @return the hashcode for hashtable indexing
+	 */
+	public int hashCode() {
+		if (hashCode == 0)
+			hashCode = strmHandler.hashCode(this);
+		return hashCode;
+	}
+
+	/**
+	 * Sets the receiver's stream handler to one which is appropriate for its
+	 * protocol. Throws a MalformedURLException if no reasonable handler is
+	 * available.
+	 * <p>
+	 * Note that this will overwrite any existing stream handler with the new
+	 * one. Senders must check if the strmHandler is null before calling the
+	 * method if they do not want this behavior (a speed optimization).
+	 */
+
+	void setupStreamHandler() {
+		// Check for a cached (previously looked up) handler for
+		// the requested protocol.
+		strmHandler = (URLStreamHandler) streamHandlers.get(protocol);
+		if (strmHandler != null)
+			return;
+
+		// If there is a stream handler factory, then attempt to
+		// use it to create the handler.
+		if (streamHandlerFactory != null) {
+			strmHandler = streamHandlerFactory.createURLStreamHandler(protocol);
+			if (strmHandler != null) {
+				streamHandlers.put(protocol, strmHandler);
+				return;
+			}
+		}
+
+		// Check if there is a list of packages which can provide handlers.
+		// If so, then walk this list looking for an applicable one.
+		String packageList = (String) AccessController
+				.doPrivileged(new PriviAction("java.protocol.handler.pkgs"));
+		if (packageList != null) {
+			StringTokenizer st = new StringTokenizer(packageList, "|");
+			while (st.hasMoreTokens()) {
+				String className = st.nextToken() + "." + protocol + ".Handler";
+				try {
+					strmHandler = (URLStreamHandler) Class.forName(className,
+							true, ClassLoader.getSystemClassLoader())
+							.newInstance();
+					streamHandlers.put(protocol, strmHandler);
+					return;
+				} catch (Exception e) {
+				}
+			}
+		}
+
+		// No one else has provided a handler, so try our internal one.
+		try {
+			String className = "com.ibm.oti.net.www.protocol." + protocol
+					+ ".Handler";
+			strmHandler = (URLStreamHandler) Class.forName(className)
+					.newInstance();
+			streamHandlers.put(protocol, strmHandler);
+		} catch (Exception e) {
+		}
+	}
+
+	/**
+	 * Answers an Object representing the resource referenced by this URL.
+	 * 
+	 * @return The object of the resource pointed by this URL.
+	 * 
+	 * @throws IOException
+	 *             If an error occured obtaining the content.
+	 */
+	public final Object getContent() throws IOException {
+		return openConnection().getContent();
+	}
+
+	/**
+	 * Answers an Object representing the resource referenced by this URL.
+	 * 
+	 * @param types
+	 *            The list of acceptable content types
+	 * @return The object of the resource pointed by this URL, or null if the
+	 *         content does not match a specified content type.
+	 * 
+	 * @throws IOException
+	 *             If an error occured obtaining the content.
+	 */
+	public final Object getContent(Class[] types) throws IOException {
+		return openConnection().getContent(types);
+	}
+
+	/**
+	 * Answers a stream for reading from this URL.
+	 * 
+	 * @return a stream on the contents of the resource.
+	 * 
+	 * @throws IOException
+	 *             if a stream could not be created.
+	 */
+	public final InputStream openStream() throws java.io.IOException {
+		return openConnection().getInputStream();
+	}
+
+	/**
+	 * Creates a connection to this URL using the appropriate ProtocolHandler.
+	 * 
+	 * @return The connection to this URL.
+	 * 
+	 * @throws IOException
+	 *             if the connection to the URL is not possible.
+	 */
+	public URLConnection openConnection() throws IOException {
+		return strmHandler.openConnection(this);
+	}
+
+	/**
+	 * Answers a string containing a concise, human-readable description of the
+	 * receiver.
+	 * 
+	 * @return a printable representation for the receiver.
+	 */
+	public String toString() {
+		return toExternalForm();
+	}
+
+	/**
+	 * Create and return the String representation of this URL.
+	 * 
+	 * @return the external representation of this URL.
+	 * 
+	 * @see #toString()
+	 * @see URL
+	 * @see URLStreamHandler#toExternalForm(URL)
+	 */
+	public String toExternalForm() {
+		if (strmHandler == null)
+			return "unknown protocol(" + protocol + ")://" + host + file;
+		return strmHandler.toExternalForm(this);
+	}
+
+	/**
+	 * This method is called to restore the state of a URL object that has been
+	 * serialized. The stream handler is determined from the URL's protocol.
+	 * 
+	 * @param stream
+	 *            the stream to read from.
+	 * 
+	 * @throws IOException
+	 *             if an IO Exception occurs while reading the stream or the
+	 *             handler can not be found.
+	 */
+	private void readObject(java.io.ObjectInputStream stream)
+			throws java.io.IOException {
+		try {
+			stream.defaultReadObject();
+			if (host != null && authority == null)
+				fixURL();
+			else if (authority != null) {
+				int index;
+				if ((index = authority.lastIndexOf('@')) > -1)
+					userInfo = authority.substring(0, index);
+				if (file != null && (index = file.indexOf('?')) > -1) {
+					query = file.substring(index + 1);
+					path = file.substring(0, index);
+				} else {
+					path = file;
+				}
+			}
+			setupStreamHandler();
+			if (strmHandler == null)
+				throw new IOException(com.ibm.oti.util.Msg.getString("K00b3",
+						protocol));
+		} catch (ClassNotFoundException e) {
+			throw new java.io.IOException(e.toString());
+		}
+	}
+
+	/**
+	 * This method is called to write any non-transient, non-static variables
+	 * into the output stream.
+	 * <p>
+	 * Note that, we really only need the readObject method but the spec that
+	 * says readObject will be ignored if no writeObject is present.
+	 * 
+	 * @param s
+	 *            the stream to write to.
+	 * 
+	 * @throws IOException
+	 *             if an IO Exception occurs during the write.
+	 */
+	private void writeObject(java.io.ObjectOutputStream s)
+			throws java.io.IOException {
+		s.defaultWriteObject();
+	}
+
+	// Slot accessors follow...
+
+	/**
+	 * Answers the file component of this URL.
+	 * 
+	 * @return the receiver's file.
+	 */
+	public String getFile() {
+		return file;
+	}
+
+	/**
+	 * Answers the host component of this URL.
+	 * 
+	 * @return the receiver's host.
+	 */
+	public String getHost() {
+		return host;
+	}
+
+	/**
+	 * Answers the port component of this URL.
+	 * 
+	 * @return the receiver's port.
+	 */
+	public int getPort() {
+		return port;
+	}
+
+	/**
+	 * Answers the protocol component of this URL.
+	 * 
+	 * @return the receiver's protocol.
+	 */
+	public String getProtocol() {
+		return protocol;
+	}
+
+	/**
+	 * Answers the reference component of this URL.
+	 * 
+	 * @return the receiver's reference component.
+	 */
+	public String getRef() {
+		return ref;
+	}
+
+	/**
+	 * Answers the query component of this URL.
+	 * 
+	 * @return the receiver's query.
+	 */
+	public String getQuery() {
+		return query;
+	}
+
+	/**
+	 * Answers the path component of this URL.
+	 * 
+	 * @return the receiver's path.
+	 */
+	public String getPath() {
+		return path;
+	}
+
+	/**
+	 * Answers the user info component of this URL.
+	 * 
+	 * @return the receiver's user info.
+	 */
+	public String getUserInfo() {
+		return userInfo;
+	}
+
+	/**
+	 * Answers the authority component of this URL.
+	 * 
+	 * @return the receiver's authority.
+	 */
+	public String getAuthority() {
+		return authority;
+	}
+
+	/**
+	 * Sets the properties of this URL using the provided arguments. This method
+	 * is used both within this class and by the <code>URLStreamHandler</code>
+	 * code.
+	 * 
+	 * @param protocol
+	 *            the new protocol.
+	 * @param host
+	 *            the new host name.
+	 * @param port
+	 *            the new port number.
+	 * @param authority
+	 *            the new authority.
+	 * @param userInfo
+	 *            the new user info.
+	 * @param path
+	 *            the new path component.
+	 * @param query
+	 *            the new query.
+	 * @param ref
+	 *            the new reference.
+	 * 
+	 * @see URL
+	 * @see URLStreamHandler
+	 */
+	protected void set(String protocol, String host, int port,
+			String authority, String userInfo, String path, String query,
+			String ref) {
+		String file = path;
+		if (query != null && !query.equals("")) {
+			if (file != null)
+				file = file + "?" + query;
+			else
+				file = "?" + query;
+		}
+		set(protocol, host, port, file, ref);
+		this.authority = authority;
+		this.userInfo = userInfo;
+		this.path = path;
+		this.query = query;
+	}
+
+	URLStreamHandler getStreamHandler() {
+		return strmHandler;
+	}
+
+	/**
+	 * Returns the default port for this URL as
+	 * defined by the URLStreamHandler.
+	 *
+	 * @return the default port for this URL
+	 *
+	 * @see 		URLStreamHandler#getDefaultPort
+	 */
+	public int getDefaultPort() {
+		return strmHandler.getDefaultPort();
+	}
+}



Mime
View raw message