package io.nextop;
import javax.annotation.Nullable;
// a url factored to work better with nextop concepts
// in nextop, Authority.local() is an alias for "$access-key.nextop.io",
// which the edge uses for control messages
public final class Route {
public static final Via LOCAL = new Via(Scheme.NEXTOP, Authority.local());
public static Route valueOf(String s) {
// the string version is a mesh of the via and target
// mirror the parsing rules in Target, but apply them in a custom way
try {
int n = s.length();
if (n <= 0) {
throw new IllegalArgumentException();
}
int i = s.indexOf(' ');
if (i < 0) {
throw new IllegalArgumentException();
}
String d = "://";
int j = s.indexOf(d, i + 1);
if (i < 0) {
throw new IllegalArgumentException();
}
int k = s.indexOf('/', j + d.length());
Method method = Method.valueOf(s.substring(0, i).toUpperCase());
Via via;
Path path;
if (k < 0) {
via = Via.valueOf(s.substring(i + 1, n));
path = Path.empty();
} else {
via = Via.valueOf(s.substring(i + 1, k));
path = Path.valueOf(s.substring(k + 1, n));
}
return new Route(new Target(method, path), via);
} catch (IllegalArgumentException e) {
throw new IllegalArgumentException(s, e);
}
}
public static Route create(Target target, Via via) {
return new Route(target, via);
}
public static Route local(Target target) {
return new Route(target, LOCAL);
}
public final Target target;
public final Via via;
private Route(Target target, Via via) {
this.target = target;
this.via = via;
}
@Override
public String toString() {
return String.format("%s %s%s", target.method, via, target.path);
}
@Override
public int hashCode() {
int c = target.hashCode();
c = 31 * c + via.hashCode();
return c;
}
@Override
public boolean equals(Object obj) {
if (!(obj instanceof Route)) {
return false;
}
Route b = (Route) obj;
return target.equals(b.target) && via.equals(b.via);
}
public static enum Method {
GET,
HEAD,
POST,
PUT
// FIXME expand HTTP methods
}
public static enum Scheme {
HTTP,
HTTPS,
NEXTOP,
/////// ANDROID ///////
/* these are supported only on Android, at the Android layer */
CONTENT
}
public static class Target {
public static Target valueOf(String s) {
// e.g. "GET /"
int n = s.length();
int i = s.indexOf(' ');
if (i < 0) {
throw new IllegalArgumentException();
}
Method method = Method.valueOf(s.substring(0, i).toUpperCase());
Path path = Path.valueOf(s.substring(i + 1, n));
return new Target(method, path);
}
public static Target create(Method method, Path path) {
return new Target(method, path);
}
public final Method method;
public final Path path;
private Target(Method method, Path path) {
this.method = method;
this.path = path;
}
@Override
public String toString() {
return String.format("%s %s", method, path);
}
@Override
public int hashCode() {
int c = method.hashCode();
c = 31 * c + path.hashCode();
return c;
}
@Override
public boolean equals(Object obj) {
if (!(obj instanceof Target)) {
return false;
}
Target b = (Target) obj;
return method.equals(b.method) && path.equals(b.path);
}
}
public static class Via {
public static Via valueOf(String s) {
// e.g. "https://nextop.io"
String d = "://";
int n = s.length();
int i = s.indexOf(d);
if (i < 0) {
throw new IllegalArgumentException();
}
Scheme scheme = Scheme.valueOf(s.substring(0, i).toUpperCase());
Authority authority = Authority.valueOf(s.substring(i + d.length(), n));
return new Via(scheme, authority);
}
public static Via create(Scheme scheme, Authority authority) {
return new Via(scheme, authority);
}
public final Scheme scheme;
public final Authority authority;
private Via(Scheme scheme, Authority authority) {
this.scheme = scheme;
this.authority = authority;
}
public boolean isLocal() {
return LOCAL.equals(this);
}
@Override
public String toString() {
return String.format("%s://%s", scheme.toString().toLowerCase(), authority);
}
@Override
public int hashCode() {
int c = scheme.hashCode();
c = 31 * c + authority.hashCode();
return c;
}
@Override
public boolean equals(Object obj) {
if (!(obj instanceof Via)) {
return false;
}
Via b = (Via) obj;
return scheme.equals(b.scheme) && authority.equals(b.authority);
}
}
}