Skip to content

Commit

Permalink
Add UrlTokenizer and make UrlBuilder use it (Azure#316)
Browse files Browse the repository at this point in the history
  • Loading branch information
Dan Schulte authored Dec 6, 2017
1 parent f9f781c commit 482df1b
Show file tree
Hide file tree
Showing 6 changed files with 772 additions and 102 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -247,7 +247,7 @@ private HttpRequest createHttpRequest(SwaggerMethodParser methodParser, Object[]
.withPath(methodParser.path(args));

for (final EncodedParameter queryParameter : methodParser.encodedQueryParameters(args)) {
urlBuilder.withQueryParameter(queryParameter.name(), queryParameter.encodedValue());
urlBuilder.addQueryParameter(queryParameter.name(), queryParameter.encodedValue());
}

final String url = urlBuilder.toString();
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -6,15 +6,13 @@

package com.microsoft.rest.v2.http;

import java.net.URL;

/**
* A builder class that is used to create URLs.
*/
public class UrlBuilder {
private String scheme;
private String host;
private Integer port;
private String port;
private String path;
private String query;

Expand All @@ -24,8 +22,7 @@ public class UrlBuilder {
* @return This UrlBuilder so that multiple setters can be chained together.
*/
public UrlBuilder withScheme(String scheme) {
this.scheme = scheme;
return this;
return with(scheme, UrlTokenizer.State.SCHEME);
}

/**
Expand All @@ -42,19 +39,7 @@ public String scheme() {
* @return This UrlBuilder so that multiple setters can be chained together.
*/
public UrlBuilder withHost(String host) {
if (host != null) {
if (host.endsWith("/")) {
host = host.substring(0, host.length() - 1);
}

if (host.contains("://")) {
final String[] hostParts = host.split("://");
withScheme(hostParts[0]);
host = hostParts[1];
}
}
this.host = host;
return this;
return with(host, UrlTokenizer.State.SCHEME_OR_HOST);
}

/**
Expand All @@ -65,22 +50,30 @@ public String host() {
return host;
}

/**
* Set the port that will be used to build the final URL.
* @param port The port that will be used to build the final URL.
* @return This UrlBuilder so that multiple setters can be chained together.
*/
public UrlBuilder withPort(String port) {
return with(port, UrlTokenizer.State.PORT);
}

/**
* Set the port that will be used to build the final URL.
* @param port The port that will be used to build the final URL.
* @return This UrlBuilder so that multiple setters can be chained together.
*/
public UrlBuilder withPort(int port) {
this.port = port;
return this;
return withPort(Integer.toString(port));
}

/**
* Get the port that has been assigned to this UrlBuilder.
* @return the port that has been assigned to this UrlBuilder.
*/
public Integer port() {
return port;
return port == null ? null : Integer.valueOf(port);
}

/**
Expand All @@ -89,22 +82,7 @@ public Integer port() {
* @return This UrlBuilder so that multiple setters can be chained together.
*/
public UrlBuilder withPath(String path) {
if (path != null) {
String[] parts = path.split("\\?");
this.path = parts[0];
if (parts.length > 1) {
String[] queryPairs = parts[1].split("&");
for (String queryPair : queryPairs) {
String[] nameAndValue = queryPair.split("=");
if (nameAndValue.length != 2) {
throw new IllegalArgumentException("Path contained malformed query: " + path);
}

withQueryParameter(nameAndValue[0], nameAndValue[1]);
}
}
}
return this;
return with(path, UrlTokenizer.State.PATH);
}

/**
Expand All @@ -122,9 +100,9 @@ public String path() {
* @return The provided query parameter name and encoded value to query string for the final
* URL.
*/
public UrlBuilder withQueryParameter(String queryParameterName, String queryParameterEncodedValue) {
public UrlBuilder addQueryParameter(String queryParameterName, String queryParameterEncodedValue) {
if (query == null) {
query = "?";
query = "";
}
else {
query += "&";
Expand All @@ -139,11 +117,7 @@ public UrlBuilder withQueryParameter(String queryParameterName, String queryPara
* @return This UrlBuilder so that multiple setters can be chained together.
*/
public UrlBuilder withQuery(String query) {
if (query != null && !query.startsWith("/")) {
query = "?" + query;
}
this.query = query;
return this;
return with(query, UrlTokenizer.State.QUERY);
}

/**
Expand All @@ -154,6 +128,40 @@ public String query() {
return query;
}

private UrlBuilder with(String text, UrlTokenizer.State startState) {
final UrlTokenizer tokenizer = new UrlTokenizer(text, startState);
while (tokenizer.next()) {
final UrlToken token = tokenizer.current();
final String tokenText = token.text();
final UrlToken.Type tokenType = token.type();
switch (tokenType) {
case SCHEME:
scheme = emptyToNull(tokenText);
break;

case HOST:
host = emptyToNull(tokenText);
break;

case PORT:
port = emptyToNull(tokenText);
break;

case PATH:
path = emptyToNull(tokenText);
break;

case QUERY:
query = emptyToNull(tokenText);
break;

default:
break;
}
}
return this;
}

/**
* Get the string representation of the URL that is being built.
* @return The string representation of the URL that is being built.
Expand Down Expand Up @@ -189,6 +197,9 @@ public String toString() {
}

if (query != null) {
if (!query.startsWith("?")) {
result.append('?');
}
result.append(query);
}

Expand All @@ -201,45 +212,12 @@ public String toString() {
* @return The UrlBuilder that was parsed from the string.
*/
public static UrlBuilder parse(String url) {
UrlBuilder result = null;

if (url != null && !url.isEmpty()) {
boolean addedProtocol = false;
if (!url.contains("://")) {
url = "http://" + url;
addedProtocol = true;
}

URL javaUrl = null;
try {
javaUrl = new URL(url);
}
catch (Exception ignored) {
}

if (javaUrl != null) {
result = new UrlBuilder();

if (!addedProtocol) {
result.withScheme(javaUrl.getProtocol());
}

result.withHost(javaUrl.getHost());

final int port = javaUrl.getPort();
if (port != -1) {
result.withPort(port);
}

final String path = javaUrl.getPath();
if (path != null && !path.isEmpty()) {
result.withPath(path);
}

result.withQuery(javaUrl.getQuery());
}
}

final UrlBuilder result = new UrlBuilder();
result.with(url, UrlTokenizer.State.SCHEME_OR_HOST);
return result;
}

private static String emptyToNull(String value) {
return value == null || value.isEmpty() ? null : value;
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,76 @@
/**
* Copyright (c) Microsoft Corporation. All rights reserved.
* Licensed under the MIT License. See License.txt in the project root for
* license information.
*/

package com.microsoft.rest.v2.http;

class UrlToken {
private final String text;
private final Type type;

UrlToken(String text, Type type) {
this.text = text;
this.type = type;
}

String text() {
return text;
}

Type type() {
return type;
}

@Override
public boolean equals(Object rhs) {
return rhs instanceof UrlToken && equals((UrlToken) rhs);
}

public boolean equals(UrlToken rhs) {
return rhs != null && text.equals(rhs.text) && type == rhs.type;
}

@Override
public String toString() {
return "\"" + text + "\" (" + type + ")";
}

@Override
public int hashCode() {
return (text == null ? 0 : text.hashCode()) ^ type.hashCode();
}

static UrlToken scheme(String text) {
return new UrlToken(text, Type.SCHEME);
}

static UrlToken host(String text) {
return new UrlToken(text, Type.HOST);
}

static UrlToken port(String text) {
return new UrlToken(text, Type.PORT);
}

static UrlToken path(String text) {
return new UrlToken(text, Type.PATH);
}

static UrlToken query(String text) {
return new UrlToken(text, Type.QUERY);
}

enum Type {
SCHEME,

HOST,

PORT,

PATH,

QUERY,
}
}
Loading

0 comments on commit 482df1b

Please sign in to comment.