Skip to content

Instantly share code, notes, and snippets.

@jarrodhroberson
Last active July 29, 2018 18:48
Show Gist options
  • Star 2 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save jarrodhroberson/021444a8dbc87c0083c4 to your computer and use it in GitHub Desktop.
Save jarrodhroberson/021444a8dbc87c0083c4 to your computer and use it in GitHub Desktop.
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