URLpublic final class URL extends Object implements SerializableURL is designed to provide public APIs for parsing
and synthesizing Uniform Resource Locators as similar as possible to the
APIs of java.net.URL , but without the ability to open a
stream or connection. One of the consequences of this is that you can
construct URLs for protocols for which a URLStreamHandler is not
available (such as an "https" URL when JSSE is not installed).
WARNING - This class assumes that the string
representation of a URL conforms to the spec argument
as described in RFC 2396 "Uniform Resource Identifiers: Generic Syntax":
<scheme>//<authority><path>?<query>#<fragment>
FIXME - This class really ought to end up in a Commons
package someplace. |
Fields Summary |
---|
private String | authorityThe authority part of the URL. | private String | fileThe filename part of the URL. | private String | hostThe host name part of the URL. | private String | pathThe path part of the URL. | private int | portThe port number part of the URL. | private String | protocolThe protocol name part of the URL. | private String | queryThe query part of the URL. | private String | refThe reference part of the URL. | private String | userInfoThe user info part of the URL. |
Constructors Summary |
---|
public URL(String spec)Create a URL object from the specified String representation.
this(null, spec);
| public URL(URL context, String spec)Create a URL object by parsing a string representation relative
to a specified context. Based on logic from JDK 1.3.1's
java.net.URL .
String original = spec;
int i, limit, c;
int start = 0;
String newProtocol = null;
boolean aRef = false;
try {
// Eliminate leading and trailing whitespace
limit = spec.length();
while ((limit > 0) && (spec.charAt(limit - 1) <= ' ")) {
limit--;
}
while ((start < limit) && (spec.charAt(start) <= ' ")) {
start++;
}
// If the string representation starts with "url:", skip it
if (spec.regionMatches(true, start, "url:", 0, 4)) {
start += 4;
}
// Is this a ref relative to the context URL?
if ((start < spec.length()) && (spec.charAt(start) == '#")) {
aRef = true;
}
// Parse out the new protocol
for (i = start; !aRef && (i < limit) &&
((c = spec.charAt(i)) != '/"); i++) {
if (c == ':") {
String s = spec.substring(start, i).toLowerCase();
// Assume all protocols are valid
newProtocol = s;
start = i + 1;
break;
}
}
// Only use our context if the protocols match
protocol = newProtocol;
if ((context != null) && ((newProtocol == null) ||
newProtocol.equalsIgnoreCase(context.getProtocol()))) {
// If the context is a hierarchical URL scheme and the spec
// contains a matching scheme then maintain backwards
// compatibility and treat it as if the spec didn't contain
// the scheme; see 5.2.3 of RFC2396
if ((context.getPath() != null) &&
(context.getPath().startsWith("/")))
newProtocol = null;
if (newProtocol == null) {
protocol = context.getProtocol();
authority = context.getAuthority();
userInfo = context.getUserInfo();
host = context.getHost();
port = context.getPort();
file = context.getFile();
int question = file.lastIndexOf("?");
if (question < 0)
path = file;
else
path = file.substring(0, question);
}
}
if (protocol == null)
throw new MalformedURLException("no protocol: " + original);
// Parse out any ref portion of the spec
i = spec.indexOf('#", start);
if (i >= 0) {
ref = spec.substring(i + 1, limit);
limit = i;
}
// Parse the remainder of the spec in a protocol-specific fashion
parse(spec, start, limit);
if (context != null)
normalize();
} catch (MalformedURLException e) {
throw e;
} catch (Exception e) {
throw new MalformedURLException(e.toString());
}
| public URL(String protocol, String host, String file)Create a URL object from the specified components. The default port
number for the specified protocol will be used.
this(protocol, host, -1, file);
| public URL(String protocol, String host, int port, String file)Create a URL object from the specified components. Specifying a port
number of -1 indicates that the URL should use the default port for
that protocol. Based on logic from JDK 1.3.1's
java.net.URL .
this.protocol = protocol;
this.host = host;
this.port = port;
int hash = file.indexOf('#");
this.file = hash < 0 ? file : file.substring(0, hash);
this.ref = hash < 0 ? null : file.substring(hash + 1);
int question = file.lastIndexOf('?");
if (question >= 0) {
query = file.substring(question + 1);
path = file.substring(0, question);
} else
path = file;
if ((host != null) && (host.length() > 0))
authority = (port == -1) ? host : host + ":" + port;
|
Methods Summary |
---|
private boolean | compare(java.lang.String first, java.lang.String second)Compare to String values for equality, taking appropriate care if one
or both of the values are null .
if (first == null) {
if (second == null)
return (true);
else
return (false);
} else {
if (second == null)
return (false);
else
return (first.equals(second));
}
| public boolean | equals(java.lang.Object obj)Compare two URLs for equality. The result is true if and
only if the argument is not null, and is a URL object
that represents the same URL as this object. Two
URLs are equal if they have the same protocol and
reference the same host, the same port number on the host,
and the same file and anchor on the host.
// --------------------------------------------------------- Public Methods
if (obj == null)
return (false);
if (!(obj instanceof URL))
return (false);
URL other = (URL) obj;
if (!sameFile(other))
return (false);
return (compare(ref, other.getRef()));
| public java.lang.String | getAuthority()Return the authority part of the URL.
return (this.authority);
| public java.lang.String | getFile()Return the filename part of the URL. NOTE - For
compatibility with java.net.URL , this value includes
the query string if there was one. For just the path portion,
call getPath() instead.
if (file == null)
return ("");
return (this.file);
| public java.lang.String | getHost()Return the host name part of the URL.
return (this.host);
| public java.lang.String | getPath()Return the path part of the URL.
if (this.path == null)
return ("");
return (this.path);
| public int | getPort()Return the port number part of the URL.
return (this.port);
| public java.lang.String | getProtocol()Return the protocol name part of the URL.
return (this.protocol);
| public java.lang.String | getQuery()Return the query part of the URL.
return (this.query);
| public java.lang.String | getRef()Return the reference part of the URL.
return (this.ref);
| public java.lang.String | getUserInfo()Return the user info part of the URL.
return (this.userInfo);
| public int | hashCode()Returns the hash code value for this object.
int hashCode = 0;
if (getProtocol() != null) {
hashCode += getProtocol().hashCode();
}
if (getHost() != null) {
hashCode += getHost().hashCode();
}
hashCode += getPort();
if (getFile() != null) {
hashCode += getFile().hashCode();
}
if (getRef() != null) {
hashCode += getRef().hashCode();
}
return hashCode;
| public void | normalize()Normalize the path (and therefore file )
portions of this URL.
NOTE - This method is not part of the public API
of java.net.URL , but is provided as a value added
service of this implementation.
// Special case for null path
if (path == null) {
if (query != null)
file = "?" + query;
else
file = "";
return;
}
// Create a place for the normalized path
String normalized = path;
if (normalized.equals("/.")) {
path = "/";
if (query != null)
file = path + "?" + query;
else
file = path;
return;
}
// Normalize the slashes and add leading slash if necessary
if (normalized.indexOf('\\") >= 0)
normalized = normalized.replace('\\", '/");
if (!normalized.startsWith("/"))
normalized = "/" + normalized;
// Resolve occurrences of "//" in the normalized path
while (true) {
int index = normalized.indexOf("//");
if (index < 0)
break;
normalized = normalized.substring(0, index) +
normalized.substring(index + 1);
}
// Resolve occurrences of "/./" in the normalized path
while (true) {
int index = normalized.indexOf("/./");
if (index < 0)
break;
normalized = normalized.substring(0, index) +
normalized.substring(index + 2);
}
// Resolve occurrences of "/../" in the normalized path
while (true) {
int index = normalized.indexOf("/../");
if (index < 0)
break;
if (index == 0)
throw new MalformedURLException
("Invalid relative URL reference");
int index2 = normalized.lastIndexOf('/", index - 1);
normalized = normalized.substring(0, index2) +
normalized.substring(index + 3);
}
// Resolve occurrences of "/." at the end of the normalized path
if (normalized.endsWith("/."))
normalized = normalized.substring(0, normalized.length() - 1);
// Resolve occurrences of "/.." at the end of the normalized path
if (normalized.endsWith("/..")) {
int index = normalized.length() - 3;
int index2 = normalized.lastIndexOf('/", index - 1);
if (index2 < 0)
throw new MalformedURLException
("Invalid relative URL reference");
normalized = normalized.substring(0, index2 + 1);
}
// Return the normalized path that we have completed
path = normalized;
if (query != null)
file = path + "?" + query;
else
file = path;
| private void | parse(java.lang.String spec, int start, int limit)Parse the specified portion of the string representation of a URL,
assuming that it has a format similar to that for http .
FIXME - This algorithm can undoubtedly be optimized
for performance. However, that needs to wait until after sufficient
unit tests are implemented to guarantee correct behavior with no
regressions.
// Trim the query string (if any) off the tail end
int question = spec.lastIndexOf('?", limit - 1);
if ((question >= 0) && (question < limit)) {
query = spec.substring(question + 1, limit);
limit = question;
} else {
query = null;
}
// Parse the authority section
if (spec.indexOf("//", start) == start) {
int pathStart = spec.indexOf("/", start + 2);
if ((pathStart >= 0) && (pathStart < limit)) {
authority = spec.substring(start + 2, pathStart);
start = pathStart;
} else {
authority = spec.substring(start + 2, limit);
start = limit;
}
if (authority.length() > 0) {
int at = authority.indexOf('@");
if( at >= 0 ) {
userInfo = authority.substring(0,at);
}
int colon = authority.indexOf(':",at+1);
if (colon >= 0) {
try {
port =
Integer.parseInt(authority.substring(colon + 1));
} catch (NumberFormatException e) {
throw new MalformedURLException(e.toString());
}
host = authority.substring(at+1, colon);
} else {
host = authority.substring(at+1);
port = -1;
}
}
}
// Parse the path section
if (spec.indexOf("/", start) == start) { // Absolute path
path = spec.substring(start, limit);
if (query != null)
file = path + "?" + query;
else
file = path;
return;
}
// Resolve relative path against our context's file
if (path == null) {
if (query != null)
file = "?" + query;
else
file = null;
return;
}
if (!path.startsWith("/"))
throw new MalformedURLException
("Base path does not start with '/'");
if (!path.endsWith("/"))
path += "/../";
path += spec.substring(start, limit);
if (query != null)
file = path + "?" + query;
else
file = path;
return;
| public boolean | sameFile(org.apache.catalina.util.URL other)Compare two URLs, excluding the "ref" fields. Returns true
if this URL and the other argument both refer
to the same resource. The two URLs might not both contain
the same anchor.
if (!compare(protocol, other.getProtocol()))
return (false);
if (!compare(host, other.getHost()))
return (false);
if (port != other.getPort())
return (false);
if (!compare(file, other.getFile()))
return (false);
return (true);
| public java.lang.String | toExternalForm()Return a string representation of this URL. This follow the rules in
RFC 2396, Section 5.2, Step 7.
StringBuffer sb = new StringBuffer();
if (protocol != null) {
sb.append(protocol);
sb.append(":");
}
if (authority != null) {
sb.append("//");
sb.append(authority);
}
if (path != null)
sb.append(path);
if (query != null) {
sb.append('?");
sb.append(query);
}
if (ref != null) {
sb.append('#");
sb.append(ref);
}
return (sb.toString());
| public java.lang.String | toString()Return a string representation of this object.
StringBuffer sb = new StringBuffer("URL[");
sb.append("authority=");
sb.append(authority);
sb.append(", file=");
sb.append(file);
sb.append(", host=");
sb.append(host);
sb.append(", port=");
sb.append(port);
sb.append(", protocol=");
sb.append(protocol);
sb.append(", query=");
sb.append(query);
sb.append(", ref=");
sb.append(ref);
sb.append(", userInfo=");
sb.append(userInfo);
sb.append("]");
return (sb.toString());
// return (toExternalForm());
|
|