Skip to content

Commit

Permalink
Path methods to path/pathSegments. Closes #15.
Browse files Browse the repository at this point in the history
  • Loading branch information
smola committed Jan 7, 2014
1 parent a221904 commit 2a3d430
Show file tree
Hide file tree
Showing 5 changed files with 105 additions and 99 deletions.
114 changes: 61 additions & 53 deletions src/main/java/io/mola/galimatias/URL.java
Original file line number Diff line number Diff line change
Expand Up @@ -26,7 +26,9 @@
import java.net.MalformedURLException;
import java.net.URI;
import java.net.URISyntaxException;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.List;

/**
* A parsed URL. Immutable.
Expand All @@ -39,24 +41,32 @@
*/
public class URL implements Serializable {

private static final String[] EMPTY_PATH = new String[0];

private final String scheme;
private final String schemeData;
private final String username;
private final String password;
private final Host host;
private final int port;
private final String[] path;
private final String path;
private final String query;
private final String fragment;

private final boolean isHierarchical;

URL(final String scheme, final String schemeData,
final String username, final String password,
final Host host, final int port,
final Iterable<String> pathSegments,
final String query, final String fragment,
final boolean isHierarchical) {
this(scheme, schemeData, username, password, host, port, pathSegmentsToString(pathSegments),
query, fragment, isHierarchical);
}

URL(final String scheme, final String schemeData,
final String username, final String password,
final Host host, final int port,
final String[] path,
final String path,
final String query, final String fragment,
final boolean isHierarchical) {
this.scheme = scheme;
Expand All @@ -65,11 +75,7 @@ public class URL implements Serializable {
this.password = password;
this.host = host;
this.port = port;
if (path != null && path.length > 0 && (path.length > 1 || !path[0].equals(""))) {
this.path = Arrays.copyOf(path, path.length);
} else {
this.path = EMPTY_PATH;
}
this.path = path;
this.query = query;
this.fragment = fragment;
this.isHierarchical = isHierarchical;
Expand Down Expand Up @@ -140,23 +146,15 @@ public int defaultPort() {
return Integer.parseInt(defaultPort);
}

public String[] path() {
return Arrays.copyOf(path, path.length);
public String path() {
return path;
}

public String pathString() {
public List<String> pathSegments() {
if (!isHierarchical) {
return null;
}
StringBuilder output = new StringBuilder();
output.append('/');
if (path.length > 0) {
output.append(path[0]);
for (int i = 1; i < path.length; i++) {
output.append('/').append(path[i]);
}
}
return output.toString();
return pathStringToSegments(path);
}

public String query() {
Expand All @@ -167,18 +165,16 @@ public String fragment() {
return fragment;
}

protected String file() {
final String pathString = pathString();
if (pathString == null && query == null && fragment == null) {
public String file() {
if (path == null && query == null) {
return "";
}
final StringBuilder output = new StringBuilder(
((pathString != null)? pathString.length() : 0) +
((query != null)? query.length() + 1 : 0) +
((fragment != null)? fragment.length() + 1 : 0)
((path != null)? path.length() : 0) +
((query != null)? query.length() + 1 : 0)
);
if (pathString != null) {
output.append(pathString);
if (path != null) {
output.append(path);
}
if (query != null) {
output.append('?').append(query);
Expand All @@ -194,6 +190,37 @@ public boolean isOpaque() {
return !isHierarchical;
}

private static String pathSegmentsToString(final Iterable<String> segments) {
if (segments == null) {
return null;
}
final StringBuilder output = new StringBuilder();
for (final String segment : segments) {
output.append('/').append(segment);
}
if (output.length() == 0) {
return "/";
}
return output.toString();
}

private static List<String> pathStringToSegments(String path) {
if (path == null) {
return new ArrayList<String>();
}
if (path.startsWith("/")) {
path = path.substring(1);
}
final String[] segments = path.split("/", -1);
final List<String> result = new ArrayList<String>(segments.length + 1);
if (segments.length == 0) {
result.add("");
return result;
}
result.addAll(Arrays.asList(segments));
return result;
}

/**
* Resolves a relative reference to an absolute URL.
*
Expand Down Expand Up @@ -471,12 +498,8 @@ public String toString() {
if (port != -1) {
output.append(':').append(port);
}
output.append('/');
if (path.length > 0) {
output.append(path[0]);
for (int i = 1; i < path.length; i++) {
output.append('/').append(path[i]);
}
if (path != null) {
output.append(path);
}
} else {
output.append(schemeData);
Expand Down Expand Up @@ -508,27 +531,12 @@ public boolean equals(final Object obj) {
((password == null)? other.password == null : password.equals(other.password)) &&
((host == null)? other.host == null : host.equals(other.host)) &&
port == other.port &&
((path == null)? other.host == null : path.equals(other.path)) &&
((fragment == null)? other.fragment == null : fragment.equals(other.fragment)) &&
((query == null)? other.query == null : query.equals(other.query)) &&
arrayEquals(path, other.path)
((query == null)? other.query == null : query.equals(other.query))
;
}

private static boolean arrayEquals(final String[] one, final String[] other) {
if (one == other) {
return true;
}
if (one.length != other.length) {
return false;
}
for (int i = 0; i < one.length; i++) {
if (!one[i].equals(other[i])) {
return false;
}
}
return true;
}

@Override
public int hashCode() {
int result = scheme != null ? scheme.hashCode() : 0;
Expand All @@ -537,7 +545,7 @@ public int hashCode() {
result = 31 * result + (password != null ? password.hashCode() : 0);
result = 31 * result + (host != null ? host.hashCode() : 0);
result = 31 * result + (port != -1 ? port : 0);
result = 31 * result + Arrays.hashCode(path);
result = 31 * result + (path != null? path.hashCode() : 0);
result = 31 * result + (query != null ? query.hashCode() : 0);
result = 31 * result + (fragment != null ? fragment.hashCode() : 0);
result = 31 * result + (isHierarchical ? 1 : 0);
Expand Down
34 changes: 16 additions & 18 deletions src/main/java/io/mola/galimatias/URLParser.java
Original file line number Diff line number Diff line change
Expand Up @@ -23,7 +23,9 @@
package io.mola.galimatias;

import java.nio.charset.Charset;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.List;
import java.util.Locale;

import static io.mola.galimatias.URLUtils.*;
Expand Down Expand Up @@ -158,7 +160,7 @@ public URL parse() throws GalimatiasParseException {
boolean relativeFlag = (url != null) && url.isHierarchical();
boolean atFlag = false; // @-flag
boolean bracketsFlag = false; // []-flag
String[] path = (url == null || stateOverride == ParseURLState.RELATIVE_PATH_START)? new String[0] : url.path();
List<String> pathSegments = (url == null || stateOverride == ParseURLState.RELATIVE_PATH_START)? new ArrayList<String>() : url.pathSegments();
StringBuilder query = (url == null || url.query() == null || stateOverride == ParseURLState.QUERY)? null : new StringBuilder(url.query());
StringBuilder fragment = (url == null || url.fragment() == null|| stateOverride == ParseURLState.FRAGMENT)? null : new StringBuilder(url.fragment());

Expand Down Expand Up @@ -353,7 +355,7 @@ else if (c == '#') {
if (isEOF) {
host = (base == null)? null : base.host();
port = (base == null || base.port() == base.defaultPort())? -1 : base.port();
path = (base == null)? null : base.path();
pathSegments = (base == null)? null : base.pathSegments();
query = (base == null || base.query() == null)? null : new StringBuilder(base.query());
} else if (c == '/' || c == '\\') {
if (c == '\\') {
Expand All @@ -363,13 +365,13 @@ else if (c == '#') {
} else if (c == '?') {
host = (base == null)? null : base.host();
port = (base == null || base.port() == base.defaultPort())? -1 : base.port();
path = (base == null)? null : base.path();
pathSegments = (base == null)? null : base.pathSegments();
query = new StringBuilder();
state = ParseURLState.QUERY;
} else if (c == '#') {
host = (base == null)? null : base.host();
port = (base == null || base.port() == base.defaultPort())? -1 : base.port();
path = (base == null)? null : base.path();
pathSegments = (base == null)? null : base.pathSegments();
query = (base == null)? null : new StringBuilder(base.query());
fragment = new StringBuilder();
state = ParseURLState.FRAGMENT;
Expand All @@ -384,10 +386,10 @@ else if (c == '#') {

host = (base == null)? null : base.host();
port = (base == null || base.port() == base.defaultPort())? -1 : base.port();
path = (base == null)? new String[0] : base.path();
pathSegments = (base == null)? new ArrayList<String>() : base.pathSegments();
// Pop path
if (path.length > 0) {
path = Arrays.copyOf(path, path.length - 1);
if (!pathSegments.isEmpty()) {
pathSegments.remove(pathSegments.size() - 1);
}
}
state = ParseURLState.RELATIVE_PATH;
Expand Down Expand Up @@ -634,27 +636,23 @@ else if (c == '#') {
}
if ("..".equals(buffer.toString())) {
// Pop path
if (path.length > 0) {
path = Arrays.copyOf(path, path.length - 1);
if (!pathSegments.isEmpty()) {
pathSegments.remove(pathSegments.size() - 1);
}
if (c != '/' && c != '\\') {
path = Arrays.copyOf(path, path.length + 1);
path[path.length - 1] = "";
pathSegments.add("");
}
//FIX: It is not clear in the spec how a path should be pop'd

} else if (".".equals(buffer.toString()) && c != '/' && c != '\\') {
path = Arrays.copyOf(path, path.length + 1);
path[path.length - 1] = "";
pathSegments.add("");
} else if (!".".equals(buffer.toString())) {
if ("file".equals(scheme) && path.length == 0 &&
if ("file".equals(scheme) && pathSegments.isEmpty() &&
buffer.length() == 2 &&
isASCIIAlpha(buffer.charAt(0)) &&
buffer.charAt(1) == '|') {
buffer.setCharAt(1, ':');
}
path = Arrays.copyOf(path, path.length + 1);
path[path.length - 1] = buffer.toString();
pathSegments.add(buffer.toString());
}
buffer.setLength(0);
if (c == '?') {
Expand Down Expand Up @@ -789,7 +787,7 @@ else if (c == '#') {

return new URL(scheme, schemeData.toString(),
username, password,
host, port, path,
host, port, pathSegments,
(query == null)? null : query.toString(),
(fragment == null)? null : fragment.toString(),
relativeFlag);
Expand Down
4 changes: 2 additions & 2 deletions src/main/java/io/mola/galimatias/cli/CLI.java
Original file line number Diff line number Diff line change
Expand Up @@ -59,8 +59,8 @@ private static void printResult(URL url) {
if (url.port() != -1) {
System.out.println("\t\tPort: " + url.port());
}
if (url.pathString() != null) {
System.out.println("\t\tPath: " + url.pathString());
if (url.path() != null) {
System.out.println("\t\tPath: " + url.path());
}
if (url.query() != null) {
System.out.println("\t\tQuery: " + url.query());
Expand Down
Loading

0 comments on commit 2a3d430

Please sign in to comment.