Last active
July 29, 2018 18:48
-
-
Save jarrodhroberson/021444a8dbc87c0083c4 to your computer and use it in GitHub Desktop.
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
import com.google.common.base.Joiner; | |
import javax.annotation.Nonnull; | |
import java.net.MalformedURLException; | |
import java.net.URL; | |
import java.util.List; | |
import java.util.Map; | |
import static com.google.common.base.Preconditions.checkArgument; | |
import static com.google.common.base.Preconditions.checkNotNull; | |
import static com.google.common.base.Strings.isNullOrEmpty; | |
public class UrlBuilder | |
{ | |
public static URL parse(@Nonnull final String s) | |
{ | |
try | |
{ | |
return new URL(checkNotNull(s)); | |
} | |
catch (final MalformedURLException e) | |
{ | |
throw new RuntimeException(e); | |
} | |
} | |
private static final int DEFAULT_PORT = -1; | |
private final StringBuilder sb; | |
public UrlBuilder() | |
{ | |
this.sb = new StringBuilder(512); | |
} | |
@Nonnull | |
private URL build() | |
{ | |
try | |
{ | |
return new URL(UrlBuilder.this.sb.toString()); | |
} | |
catch (MalformedURLException e) | |
{ | |
throw new RuntimeException(e); | |
} | |
} | |
@Nonnull | |
public Authority scheme(@Nonnull final String scheme) | |
{ | |
this.sb.append(checkNotNull(scheme)).append("://"); | |
return new Authority() { | |
@Nonnull | |
@Override | |
public URL build() | |
{ | |
return UrlBuilder.this.build(); | |
} | |
@Nonnull | |
@Override | |
public Builder fragment(@Nonnull final String fragment) | |
{ | |
return new Fragment() { | |
@Nonnull | |
@Override | |
public Builder fragment(@Nonnull String fragment) | |
{ | |
if (!isNullOrEmpty(fragment)) | |
{ | |
UrlBuilder.this.sb.append("#").append(fragment); | |
} | |
return this; | |
} | |
@Nonnull | |
@Override | |
public URL build() | |
{ | |
return UrlBuilder.this.build(); | |
} | |
}; | |
} | |
@Nonnull | |
@Override | |
public Query path(@Nonnull final List<String> path) | |
{ | |
return this.path(Joiner.on('/').join(path)); | |
} | |
@Nonnull | |
@Override | |
public Query path(@Nonnull final String path) | |
{ | |
checkArgument(!path.startsWith("//"), "%s is not a valid path, path can not start with //", path); | |
if (!isNullOrEmpty(path)) | |
{ | |
UrlBuilder.this.sb.append(path); | |
} | |
return new Query() { | |
@Nonnull | |
@Override | |
public Fragment query(@Nonnull final Map<String, String> query) | |
{ | |
return query(query, "&"); | |
} | |
@Nonnull | |
@Override | |
public Fragment query(@Nonnull final Map<String, String> query, @Nonnull final String separator) | |
{ | |
final String q = Joiner.on(separator).withKeyValueSeparator("=").join(checkNotNull(query)); | |
if (!isNullOrEmpty(q)) | |
{ | |
UrlBuilder.this.sb.append("?").append(q); | |
} | |
return this; | |
} | |
@Nonnull | |
@Override | |
public Builder fragment(@Nonnull final String fragment) | |
{ | |
if (!isNullOrEmpty(fragment)) | |
{ | |
UrlBuilder.this.sb.append("#").append(fragment); | |
} | |
return this; | |
} | |
@Nonnull | |
@Override | |
public URL build() | |
{ | |
return UrlBuilder.this.build(); | |
} | |
}; | |
} | |
@Nonnull | |
@Override | |
public Host userInfo(@Nonnull final String userName) | |
{ | |
return this.userInfo(userName, ""); | |
} | |
@Nonnull | |
@Override | |
public Host userInfo(@Nonnull final String userName, @Nonnull final String password) | |
{ | |
if (!isNullOrEmpty(userName)) | |
{ | |
UrlBuilder.this.sb.append(userName); | |
if (!isNullOrEmpty(password)) | |
{ | |
UrlBuilder.this.sb.append(":").append(password); | |
} | |
UrlBuilder.this.sb.append("@"); | |
} | |
return this; | |
} | |
@Nonnull | |
public Path host(@Nonnull final String hostName) | |
{ | |
return host(hostName, DEFAULT_PORT); | |
} | |
@Nonnull | |
public Path host(@Nonnull final String hostName, final int port) | |
{ | |
if (!isNullOrEmpty(hostName)) | |
{ | |
UrlBuilder.this.sb.append(hostName); | |
if (port > DEFAULT_PORT) | |
{ | |
checkArgument(port >= 1 && port <= 65535, "%s is out of bounds, port must be between 1 - 65535", port); | |
UrlBuilder.this.sb.append(":").append(port); | |
} | |
} | |
return new Path() { | |
@Nonnull | |
@Override | |
public Query path(@Nonnull final List<String> path) | |
{ | |
return this.path(Joiner.on('/').join(path)); | |
} | |
@Nonnull | |
@Override | |
public Query path(@Nonnull final String path) | |
{ | |
checkArgument(!path.startsWith("//"), "%s is not a valid path, path can not start with //", path); | |
if (!isNullOrEmpty(path)) | |
{ | |
UrlBuilder.this.sb.append(path); | |
} | |
return new Query() { | |
@Nonnull | |
@Override | |
public Fragment query(@Nonnull final Map<String, String> query) | |
{ | |
return query(query, "&"); | |
} | |
@Nonnull | |
@Override | |
public Fragment query(@Nonnull final Map<String, String> query, @Nonnull final String separator) | |
{ | |
final String q = Joiner.on(separator).withKeyValueSeparator("=").join(checkNotNull(query)); | |
if (!isNullOrEmpty(q)) | |
{ | |
UrlBuilder.this.sb.append("?").append(q); | |
} | |
return this; | |
} | |
@Nonnull | |
@Override | |
public Builder fragment(@Nonnull final String fragment) | |
{ | |
if (!isNullOrEmpty(fragment)) | |
{ | |
UrlBuilder.this.sb.append("#").append(fragment); | |
} | |
return this; | |
} | |
@Nonnull | |
@Override | |
public URL build() | |
{ | |
return UrlBuilder.this.build(); | |
} | |
}; | |
} | |
@Nonnull | |
@Override | |
public Builder fragment(@Nonnull final String fragment) | |
{ | |
if (!isNullOrEmpty(fragment)) | |
{ | |
UrlBuilder.this.sb.append("#").append(fragment); | |
} | |
return this; | |
} | |
@Nonnull | |
@Override | |
public URL build() | |
{ | |
return UrlBuilder.this.build(); | |
} | |
}; | |
} | |
}; | |
} | |
public interface Scheme | |
{ | |
@Nonnull | |
public Authority scheme(@Nonnull final String scheme); | |
} | |
public interface Authority extends Host | |
{ | |
@Nonnull | |
public Host userInfo(@Nonnull final String userName); | |
@Nonnull | |
public Host userInfo(@Nonnull final String userName, @Nonnull final String password); | |
} | |
public interface Host extends Path | |
{ | |
@Nonnull | |
public Path host(@Nonnull final String hostName); | |
@Nonnull | |
public Path host(@Nonnull final String hostName, final int port); | |
} | |
public interface Path extends Fragment | |
{ | |
@Nonnull | |
public Query path(@Nonnull final String path); | |
@Nonnull | |
public Query path(@Nonnull final List<String> path); | |
} | |
public interface Query extends Fragment | |
{ | |
@Nonnull | |
public Fragment query(@Nonnull final Map<String,String> query); | |
@Nonnull | |
public Fragment query(@Nonnull final Map<String,String> query, @Nonnull final String separator); | |
} | |
public interface Fragment extends Builder | |
{ | |
@Nonnull | |
public Builder fragment(@Nonnull final String fragment); | |
} | |
public interface Builder | |
{ | |
@Nonnull | |
public URL build(); | |
} | |
} |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment