> getQueryParameters();
+
/**
* Return true
if this {@link Address} contains a query section, otherwise return false
.
*/
diff --git a/addressbuilder/src/main/java/org/ocpsoft/urlbuilder/AddressBuilder.java b/addressbuilder/src/main/java/org/ocpsoft/urlbuilder/AddressBuilder.java
index c5a15777e..5419413f5 100644
--- a/addressbuilder/src/main/java/org/ocpsoft/urlbuilder/AddressBuilder.java
+++ b/addressbuilder/src/main/java/org/ocpsoft/urlbuilder/AddressBuilder.java
@@ -18,6 +18,7 @@
import java.net.URI;
import java.net.URISyntaxException;
import java.util.ArrayList;
+import java.util.Collections;
import java.util.LinkedHashMap;
import java.util.List;
import java.util.Map;
@@ -27,7 +28,8 @@
import org.ocpsoft.urlbuilder.util.Encoder;
/**
- * Representation of a uniform resource locator, or web address. Internal state is not encoded, plain UTF-8.
+ * Representation of a uniform resource locator, or web address. Internal state is stored as it is originally provided,
+ * and must be encoded or decoded as necessary.
*
* @author Lincoln Baxter, III
*/
@@ -58,6 +60,21 @@ public static AddressBuilderBase begin()
* Generate an {@link Address} representing the current state of this {@link AddressBuilder}.
*/
protected Address build()
+ {
+ if (address == null)
+ {
+ address = new ParameterizedAddressResult(this);
+ }
+ return address;
+ }
+
+ /**
+ * Generate an {@link Address} representing the current literal state of this {@link AddressBuilder}.
+ *
+ * (Does not apply parameterization. E.g. The URL `/{foo}` will be treated as literal text, as opposed to calling
+ * {@link #build()}, which would result in `foo` being treated as a parameterized expression)
+ */
+ protected Address buildLiteral()
{
if (address == null)
{
@@ -67,8 +84,8 @@ protected Address build()
}
/**
- * Create a new {@link Address} from the given fully encoded URL. Improperly formatted or encoded URLs are not
- * parse-able and will result in an exception.
+ * Create a new {@link Address} from the given URL. Improperly formatted or encoded URLs are not parse-able and will
+ * result in an exception. No builder parameterization is possible using this method.
*
* @see http://en.wikipedia.org/wiki/URI_scheme
* @throws IllegalArgumentException when the input URL or URL fragment is not valid.
@@ -79,16 +96,18 @@ public static Address create(String url) throws IllegalArgumentException
URI u = new URI(url);
String scheme = u.getScheme();
String host = u.getHost();
- if(scheme != null && host == null)
- return AddressBuilder.begin().scheme(u.getScheme()).schemeSpecificPart(u.getRawSchemeSpecificPart()).build();
+ if (scheme != null && host == null)
+ return AddressBuilder.begin().scheme(u.getScheme()).schemeSpecificPart(u.getRawSchemeSpecificPart())
+ .buildLiteral();
else
- return AddressBuilder.begin().scheme(scheme).domain(host).port(u.getPort())
- .pathEncoded(u.getRawPath()).queryLiteral(u.getRawQuery()).anchor(u.getRawFragment()).build();
+ return AddressBuilder.begin().scheme(scheme).domain(host).port(u.getPort())
+ .path(u.getRawPath()).queryLiteral(u.getRawQuery()).anchor(u.getRawFragment()).buildLiteral();
}
catch (URISyntaxException e) {
throw new IllegalArgumentException(
"[" + url + "] is not a valid URL fragment. Consider encoding relevant portions of the URL with ["
- + Encoder.class + "]", e);
+ + Encoder.class
+ + "], or use the provided builder pattern via this class to specify part encoding.", e);
}
}
@@ -130,8 +149,8 @@ AddressBuilderPort port(int port)
}
/**
- * Set the non-encoded path section of this {@link Address}. The given value will be stored without additional
- * encoding or decoding.
+ * Set the path section of this {@link Address}. The given value will be stored without additional encoding or
+ * decoding.
*/
AddressBuilderPath path(CharSequence path)
{
@@ -140,31 +159,70 @@ AddressBuilderPath path(CharSequence path)
}
/**
- * Set the encoded path section of this {@link Address}. The given value will be decoded before it is stored.
+ * Set the path section of this {@link Address}. The given value will be decoded before it is stored.
*/
- AddressBuilderPath pathEncoded(CharSequence path)
+ AddressBuilderPath pathDecoded(CharSequence path)
{
this.path = Decoder.path(path);
return new AddressBuilderPath(this);
}
/**
- * Set a query-parameter to a value or multiple values. The given name and values will be encoded before they are
- * stored.
+ * Set the path section of this {@link Address}. The given value will be encoded before it is stored.
+ */
+ AddressBuilderPath pathEncoded(CharSequence path)
+ {
+ this.path = Encoder.path(path);
+ return new AddressBuilderPath(this);
+ }
+
+ /**
+ * Set a query-parameter to a value or multiple values. The given name and values will be stored without additional
+ * encoding or decoding.
*/
AddressBuilderQuery query(CharSequence name, Object... values)
{
- this.queries.put(Encoder.query(name.toString()), Parameter.create(name.toString(), true, values));
+ this.queries.put(name.toString(), Parameter.create(name.toString(), values));
+ return new AddressBuilderQuery(this);
+ }
+
+ /**
+ * Set a query-parameter value or multiple values. The given name and values be decoded before they are stored.
+ */
+ AddressBuilderQuery queryDecoded(CharSequence name, Object... values)
+ {
+ if (values != null)
+ {
+ List encodedValues = new ArrayList(values.length);
+ for (Object value : values)
+ {
+ if (value == null)
+ encodedValues.add(value);
+ else
+ encodedValues.add(Decoder.query(value.toString()));
+ }
+ this.queries.put(Decoder.query(name.toString()), Parameter.create(name.toString(), encodedValues));
+ }
return new AddressBuilderQuery(this);
}
/**
- * Set a pre-encoded query-parameter to a pre-encoded value or multiple values. The given name and values be stored
- * without additional encoding or decoding.
+ * Set a query-parameter to a value or multiple values. The given name and values be encoded before they are stored.
*/
AddressBuilderQuery queryEncoded(CharSequence name, Object... values)
{
- this.queries.put(name.toString(), Parameter.create(name.toString(), false, values));
+ if (values != null)
+ {
+ List encodedValues = new ArrayList(values.length);
+ for (Object value : values)
+ {
+ if (value == null)
+ encodedValues.add(value);
+ else
+ encodedValues.add(Encoder.query(value.toString()));
+ }
+ this.queries.put(Encoder.query(name.toString()), Parameter.create(name.toString(), encodedValues));
+ }
return new AddressBuilderQuery(this);
}
@@ -224,7 +282,7 @@ AddressBuilderQuery queryLiteral(String query)
}
for (Entry> entry : params.entrySet()) {
- queryEncoded(entry.getKey(), entry.getValue().toArray());
+ query(entry.getKey(), entry.getValue().toArray());
}
}
return new AddressBuilderQuery(this);
@@ -253,26 +311,102 @@ AddressBuilderAnchor anchor(CharSequence anchor)
}
/**
- * Set a parameter name and value or values. Any supplied values will be encoded appropriately for their location in
- * the {@link Address}.
+ * Set a parameter name and value or values. The supplied values will be stored without additional encoding.
*/
void set(CharSequence name, Object... values)
{
- this.parameters.put(name.toString(), Parameter.create(name.toString(), true, values));
+ this.parameters.put(name.toString(), Parameter.create(name.toString(), values));
}
/**
- * Set a pre-encoded parameter name and value or values. The values will be stored with no additional encoding or
- * decoding.
+ * Set a parameter name and value or values. The values will be decoded before they are stored.
+ */
+ void setDecoded(CharSequence name, Object... values)
+ {
+ if (values != null)
+ {
+ List encodedValues = new ArrayList(values.length);
+ for (Object value : values)
+ {
+ if (value == null)
+ encodedValues.add(value);
+ else
+ encodedValues.add(Decoder.path(value.toString()));
+ }
+ this.parameters.put(name.toString(), Parameter.create(name.toString(), encodedValues));
+ }
+ }
+
+ /**
+ * Set a parameter name and value or values. The values will be encoded before they are stored.
*/
void setEncoded(CharSequence name, Object... values)
{
- this.parameters.put(name.toString(), Parameter.create(name.toString(), false, values));
+ if (values != null)
+ {
+ List encodedValues = new ArrayList(values.length);
+ for (Object value : values)
+ {
+ if (value == null)
+ encodedValues.add(value);
+ else
+ encodedValues.add(Encoder.path(value.toString()));
+ }
+ this.parameters.put(name.toString(), Parameter.create(name.toString(), encodedValues));
+ }
}
@Override
public String toString()
{
- return build().toString();
+ return buildLiteral().toString();
+ }
+
+ /**
+ * Package private method for {@link Address} implementations to use for rendering.
+ */
+ static StringBuilder toString(Address address)
+ {
+ StringBuilder result = new StringBuilder();
+
+ if (address.isSchemeSet())
+ result.append(address.getScheme()).append(":");
+
+ if (address.isSchemeSpecificPartSet())
+ {
+ result.append(address.getSchemeSpecificPart());
+ }
+ else
+ {
+ if (address.isDomainSet())
+ result.append("//").append(address.getDomain());
+
+ if (address.isPortSet())
+ result.append(":").append(address.getPort());
+
+ if (address.isPathSet())
+ result.append(address.getPath());
+
+ if (address.isQuerySet())
+ {
+ if (address.isDomainSet() && !address.isPathSet())
+ result.append("/");
+ result.append('?').append(address.getQuery());
+ }
+
+ if (address.isAnchorSet())
+ result.append('#').append(address.getAnchor());
+ }
+ return result;
+ }
+
+ Map> getQueries()
+ {
+ Map> result = new LinkedHashMap>();
+ for (Entry entry : this.queries.entrySet()) {
+ CharSequence key = entry.getKey();
+ result.put(key == null ? null : key.toString(), entry.getValue().getValues());
+ }
+ return Collections.unmodifiableMap(result);
}
}
diff --git a/addressbuilder/src/main/java/org/ocpsoft/urlbuilder/AddressBuilderAnchor.java b/addressbuilder/src/main/java/org/ocpsoft/urlbuilder/AddressBuilderAnchor.java
index d39655d62..03d309822 100644
--- a/addressbuilder/src/main/java/org/ocpsoft/urlbuilder/AddressBuilderAnchor.java
+++ b/addressbuilder/src/main/java/org/ocpsoft/urlbuilder/AddressBuilderAnchor.java
@@ -20,7 +20,7 @@
*
* @author Lincoln Baxter, III
*/
-public class AddressBuilderAnchor
+public class AddressBuilderAnchor implements BuildableAddress
{
private AddressBuilder parent;
@@ -29,14 +29,18 @@ public class AddressBuilderAnchor
this.parent = parent;
}
- /**
- * Generate an {@link Address} representing the current state of this {@link AddressBuilder}.
- */
+ @Override
public Address build()
{
return parent.build();
}
+ @Override
+ public Address buildLiteral()
+ {
+ return parent.buildLiteral();
+ }
+
@Override
public String toString()
{
diff --git a/addressbuilder/src/main/java/org/ocpsoft/urlbuilder/AddressBuilderBase.java b/addressbuilder/src/main/java/org/ocpsoft/urlbuilder/AddressBuilderBase.java
index 35a2c1139..e8701ba3c 100644
--- a/addressbuilder/src/main/java/org/ocpsoft/urlbuilder/AddressBuilderBase.java
+++ b/addressbuilder/src/main/java/org/ocpsoft/urlbuilder/AddressBuilderBase.java
@@ -18,7 +18,7 @@
/**
* @author Lincoln Baxter, III
*/
-public class AddressBuilderBase
+public class AddressBuilderBase implements BuildableAddress
{
private AddressBuilder parent;
@@ -27,14 +27,18 @@ public class AddressBuilderBase
this.parent = parent;
}
- /**
- * Generate an {@link Address} representing the current state of this {@link AddressBuilder}.
- */
+ @Override
public Address build()
{
return parent.build();
}
+ @Override
+ public Address buildLiteral()
+ {
+ return parent.buildLiteral();
+ }
+
/**
* Set the scheme section of this {@link Address}.
*/
@@ -60,8 +64,8 @@ public AddressBuilderPort port(int port)
}
/**
- * Set the non-encoded path section of this {@link Address}. The given value will be stored without additional
- * encoding or decoding.
+ * Set the path section of this {@link Address}. The given value will be stored without additional encoding or
+ * decoding.
*/
public AddressBuilderPath path(CharSequence path)
{
@@ -69,7 +73,15 @@ public AddressBuilderPath path(CharSequence path)
}
/**
- * Set the encoded path section of this {@link Address}. The given value will be decoded before it is stored.
+ * Set the path section of this {@link Address}. The given value will be decoded before it is stored.
+ */
+ public AddressBuilderPath pathDecoded(CharSequence path)
+ {
+ return parent.pathDecoded(path);
+ }
+
+ /**
+ * Set the path section of this {@link Address}. The given value will be encoded before it is stored.
*/
public AddressBuilderPath pathEncoded(CharSequence path)
{
@@ -77,8 +89,8 @@ public AddressBuilderPath pathEncoded(CharSequence path)
}
/**
- * Set a query-parameter to a value or multiple values. The given name and values will be encoded before they are
- * stored.
+ * Set a query-parameter to a value or multiple values. The given name and values will be stored without additional
+ * encoding or decoding.
*/
public AddressBuilderQuery query(CharSequence name, Object... values)
{
@@ -86,8 +98,15 @@ public AddressBuilderQuery query(CharSequence name, Object... values)
}
/**
- * Set a pre-encoded query-parameter to a pre-encoded value or multiple values. The given name and values be stored
- * without additional encoding or decoding.
+ * Set a query-parameter value or multiple values. The given name and values be decoded before they are stored.
+ */
+ public AddressBuilderQuery queryDecoded(CharSequence name, Object... values)
+ {
+ return parent.queryDecoded(name, values);
+ }
+
+ /**
+ * Set a query-parameter to a value or multiple values. The given name and values be encoded before they are stored.
*/
public AddressBuilderQuery queryEncoded(CharSequence name, Object... values)
{
diff --git a/addressbuilder/src/main/java/org/ocpsoft/urlbuilder/AddressBuilderDomain.java b/addressbuilder/src/main/java/org/ocpsoft/urlbuilder/AddressBuilderDomain.java
index 52502c91d..dc10b524f 100644
--- a/addressbuilder/src/main/java/org/ocpsoft/urlbuilder/AddressBuilderDomain.java
+++ b/addressbuilder/src/main/java/org/ocpsoft/urlbuilder/AddressBuilderDomain.java
@@ -20,7 +20,7 @@
*
* @author Lincoln Baxter, III
*/
-public class AddressBuilderDomain
+public class AddressBuilderDomain implements BuildableAddress
{
private AddressBuilder parent;
@@ -29,14 +29,45 @@ public class AddressBuilderDomain
this.parent = parent;
}
- /**
- * Generate an {@link Address} representing the current state of this {@link AddressBuilder}.
- */
+ @Override
public Address build()
{
return parent.build();
}
+ @Override
+ public Address buildLiteral()
+ {
+ return parent.buildLiteral();
+ }
+
+ /**
+ * Set a parameter name and value or values. The supplied values will be stored without additional encoding.
+ */
+ public AddressBuilderDomain set(CharSequence name, Object... values)
+ {
+ parent.set(name, values);
+ return this;
+ }
+
+ /**
+ * Set a parameter name and value or values. The values will be decoded before they are stored.
+ */
+ public AddressBuilderDomain setDecoded(CharSequence name, Object... values)
+ {
+ parent.setDecoded(name, values);
+ return this;
+ }
+
+ /**
+ * Set a parameter name and value or values. The values will be encoded before they are stored.
+ */
+ public AddressBuilderDomain setEncoded(CharSequence name, Object... values)
+ {
+ parent.setEncoded(name, values);
+ return this;
+ }
+
/**
* Set the port section of this {@link Address}.
*/
@@ -46,8 +77,8 @@ public AddressBuilderPort port(int port)
}
/**
- * Set the non-encoded path section of this {@link Address}. The given value will be stored without additional
- * encoding or decoding.
+ * Set the path section of this {@link Address}. The given value will be stored without additional encoding or
+ * decoding.
*/
public AddressBuilderPath path(CharSequence path)
{
@@ -55,7 +86,15 @@ public AddressBuilderPath path(CharSequence path)
}
/**
- * Set the encoded path section of this {@link Address}. The given value will be decoded before it is stored.
+ * Set the path section of this {@link Address}. The given value will be decoded before it is stored.
+ */
+ public AddressBuilderPath pathDecoded(CharSequence path)
+ {
+ return parent.pathDecoded(path);
+ }
+
+ /**
+ * Set the path section of this {@link Address}. The given value will be encoded before it is stored.
*/
public AddressBuilderPath pathEncoded(CharSequence path)
{
@@ -63,8 +102,8 @@ public AddressBuilderPath pathEncoded(CharSequence path)
}
/**
- * Set a query-parameter to a value or multiple values. The given name and values will be encoded before they are
- * stored.
+ * Set a query-parameter to a value or multiple values. The given name and values will be stored without additional
+ * encoding or decoding.
*/
public AddressBuilderQuery query(CharSequence name, Object... values)
{
@@ -72,8 +111,15 @@ public AddressBuilderQuery query(CharSequence name, Object... values)
}
/**
- * Set a pre-encoded query-parameter to a pre-encoded value or multiple values. The given name and values be stored
- * without additional encoding or decoding.
+ * Set a query-parameter value or multiple values. The given name and values be decoded before they are stored.
+ */
+ public AddressBuilderQuery queryDecoded(CharSequence name, Object... values)
+ {
+ return parent.queryDecoded(name, values);
+ }
+
+ /**
+ * Set a query-parameter to a value or multiple values. The given name and values be encoded before they are stored.
*/
public AddressBuilderQuery queryEncoded(CharSequence name, Object... values)
{
diff --git a/addressbuilder/src/main/java/org/ocpsoft/urlbuilder/AddressBuilderPath.java b/addressbuilder/src/main/java/org/ocpsoft/urlbuilder/AddressBuilderPath.java
index 58fcc411f..a138ad47a 100644
--- a/addressbuilder/src/main/java/org/ocpsoft/urlbuilder/AddressBuilderPath.java
+++ b/addressbuilder/src/main/java/org/ocpsoft/urlbuilder/AddressBuilderPath.java
@@ -20,7 +20,7 @@
*
* @author Lincoln Baxter, III
*/
-public class AddressBuilderPath
+public class AddressBuilderPath implements BuildableAddress
{
private AddressBuilder parent;
@@ -29,17 +29,21 @@ public class AddressBuilderPath
this.parent = parent;
}
- /**
- * Generate an {@link Address} representing the current state of this {@link AddressBuilder}.
- */
+ @Override
public Address build()
{
return parent.build();
}
+ @Override
+ public Address buildLiteral()
+ {
+ return parent.buildLiteral();
+ }
+
/**
- * Set a query-parameter to a value or multiple values. The given name and values will be encoded before they are
- * stored.
+ * Set a query-parameter to a value or multiple values. The given name and values will be stored without additional
+ * encoding or decoding.
*/
public AddressBuilderQuery query(CharSequence name, Object... values)
{
@@ -47,8 +51,15 @@ public AddressBuilderQuery query(CharSequence name, Object... values)
}
/**
- * Set a pre-encoded query-parameter to a pre-encoded value or multiple values. The given name and values be stored
- * without additional encoding or decoding.
+ * Set a query-parameter value or multiple values. The given name and values be decoded before they are stored.
+ */
+ public AddressBuilderQuery queryDecoded(CharSequence name, Object... values)
+ {
+ return parent.queryDecoded(name, values);
+ }
+
+ /**
+ * Set a query-parameter to a value or multiple values. The given name and values be encoded before they are stored.
*/
public AddressBuilderQuery queryEncoded(CharSequence name, Object... values)
{
@@ -73,8 +84,7 @@ public AddressBuilderAnchor anchor(String anchor)
}
/**
- * Set a parameter name and value or values. Any supplied values will be encoded appropriately for their location in
- * the {@link Address}.
+ * Set a parameter name and value or values. The supplied values will be stored without additional encoding.
*/
public AddressBuilderPath set(CharSequence name, Object... values)
{
@@ -83,8 +93,16 @@ public AddressBuilderPath set(CharSequence name, Object... values)
}
/**
- * Set a pre-encoded parameter name and value or values. The values will be stored with no additional encoding or
- * decoding.
+ * Set a parameter name and value or values. The values will be decoded before they are stored.
+ */
+ public AddressBuilderPath setDecoded(CharSequence name, Object... values)
+ {
+ parent.setDecoded(name, values);
+ return this;
+ }
+
+ /**
+ * Set a parameter name and value or values. The values will be encoded before they are stored.
*/
public AddressBuilderPath setEncoded(CharSequence name, Object... values)
{
diff --git a/addressbuilder/src/main/java/org/ocpsoft/urlbuilder/AddressBuilderPort.java b/addressbuilder/src/main/java/org/ocpsoft/urlbuilder/AddressBuilderPort.java
index 344a7d909..9e2cd102b 100644
--- a/addressbuilder/src/main/java/org/ocpsoft/urlbuilder/AddressBuilderPort.java
+++ b/addressbuilder/src/main/java/org/ocpsoft/urlbuilder/AddressBuilderPort.java
@@ -20,7 +20,7 @@
*
* @author Lincoln Baxter, III
*/
-public class AddressBuilderPort
+public class AddressBuilderPort implements BuildableAddress
{
private AddressBuilder parent;
@@ -29,16 +29,20 @@ public class AddressBuilderPort
this.parent = parent;
}
- /**
- * Generate an {@link Address} representing the current state of this {@link AddressBuilder}.
- */
+ @Override
public Address build()
{
return parent.build();
}
+ @Override
+ public Address buildLiteral()
+ {
+ return parent.buildLiteral();
+ }
+
/**
- * Set the non-encoded path section of this {@link Address}. The given value will be stored without additional
+ * Set the path section of this {@link Address}. The given value will be stored without additional
* encoding or decoding.
*/
public AddressBuilderPath path(CharSequence path)
@@ -47,16 +51,24 @@ public AddressBuilderPath path(CharSequence path)
}
/**
- * Set the encoded path section of this {@link Address}. The given value will be decoded before it is stored.
+ * Set the path section of this {@link Address}. The given value will be decoded before it is stored.
+ */
+ public AddressBuilderPath pathDecoded(CharSequence path)
+ {
+ return parent.pathDecoded(path);
+ }
+
+ /**
+ * Set the path section of this {@link Address}. The given value will be encoded before it is stored.
*/
public AddressBuilderPath pathEncoded(CharSequence path)
{
- return parent.pathEncoded(path);
+ return parent.pathDecoded(path);
}
/**
- * Set a query-parameter to a value or multiple values. The given name and values will be encoded before they are
- * stored.
+ * Set a query-parameter to a value or multiple values. The given name and values will be stored without additional
+ * encoding or decoding.
*/
public AddressBuilderQuery query(CharSequence name, Object... values)
{
@@ -64,8 +76,15 @@ public AddressBuilderQuery query(CharSequence name, Object... values)
}
/**
- * Set a pre-encoded query-parameter to a pre-encoded value or multiple values. The given name and values be stored
- * without additional encoding or decoding.
+ * Set a query-parameter value or multiple values. The given name and values be decoded before they are stored.
+ */
+ public AddressBuilderQuery queryDecoded(CharSequence name, Object... values)
+ {
+ return parent.queryDecoded(name, values);
+ }
+
+ /**
+ * Set a query-parameter to a value or multiple values. The given name and values be encoded before they are stored.
*/
public AddressBuilderQuery queryEncoded(CharSequence name, Object... values)
{
diff --git a/addressbuilder/src/main/java/org/ocpsoft/urlbuilder/AddressBuilderQuery.java b/addressbuilder/src/main/java/org/ocpsoft/urlbuilder/AddressBuilderQuery.java
index 790cb9dc6..5833930ab 100644
--- a/addressbuilder/src/main/java/org/ocpsoft/urlbuilder/AddressBuilderQuery.java
+++ b/addressbuilder/src/main/java/org/ocpsoft/urlbuilder/AddressBuilderQuery.java
@@ -20,7 +20,7 @@
*
* @author Lincoln Baxter, III
*/
-public class AddressBuilderQuery
+public class AddressBuilderQuery implements BuildableAddress
{
private AddressBuilder parent;
@@ -29,17 +29,21 @@ public class AddressBuilderQuery
this.parent = parent;
}
- /**
- * Generate an {@link Address} representing the current state of this {@link AddressBuilder}.
- */
+ @Override
public Address build()
{
return parent.build();
}
+ @Override
+ public Address buildLiteral()
+ {
+ return parent.buildLiteral();
+ }
+
/**
- * Set a query-parameter to a value or multiple values. The given name and values will be encoded before they are
- * stored.
+ * Set a query-parameter to a value or multiple values. The given name and values will be stored without additional
+ * encoding or decoding.
*/
public AddressBuilderQuery query(CharSequence name, Object value)
{
@@ -47,8 +51,15 @@ public AddressBuilderQuery query(CharSequence name, Object value)
}
/**
- * Set a pre-encoded query-parameter to a pre-encoded value or multiple values. The given name and values be stored
- * without additional encoding or decoding.
+ * Set a query-parameter value or multiple values. The given name and values be decoded before they are stored.
+ */
+ public AddressBuilderQuery queryDecoded(CharSequence name, Object... values)
+ {
+ return parent.queryDecoded(name, values);
+ }
+
+ /**
+ * Set a query-parameter to a value or multiple values. The given name and values be encoded before they are stored.
*/
public AddressBuilderQuery queryEncoded(CharSequence name, Object value)
{
diff --git a/addressbuilder/src/main/java/org/ocpsoft/urlbuilder/AddressBuilderScheme.java b/addressbuilder/src/main/java/org/ocpsoft/urlbuilder/AddressBuilderScheme.java
index 9a030184d..45d971c86 100644
--- a/addressbuilder/src/main/java/org/ocpsoft/urlbuilder/AddressBuilderScheme.java
+++ b/addressbuilder/src/main/java/org/ocpsoft/urlbuilder/AddressBuilderScheme.java
@@ -20,7 +20,7 @@
*
* @author Lincoln Baxter, III
*/
-public class AddressBuilderScheme
+public class AddressBuilderScheme implements BuildableAddress
{
private AddressBuilder parent;
@@ -29,14 +29,18 @@ public class AddressBuilderScheme
this.parent = parent;
}
- /**
- * Generate an {@link Address} representing the current state of this {@link AddressBuilder}.
- */
+ @Override
public Address build()
{
return parent.build();
}
+ @Override
+ public Address buildLiteral()
+ {
+ return parent.buildLiteral();
+ }
+
/**
* Set the domain section of this {@link Address}.
*/
@@ -52,7 +56,34 @@ public AddressBuilderSchemeSpecificPart schemeSpecificPart(CharSequence schemeSp
{
return parent.schemeSpecificPart(schemeSpecificPart);
}
-
+
+ /**
+ * Set a parameter name and value or values. The supplied values will be stored without additional encoding.
+ */
+ public AddressBuilderScheme set(CharSequence name, Object... values)
+ {
+ parent.set(name, values);
+ return this;
+ }
+
+ /**
+ * Set a parameter name and value or values. The values will be decoded before they are stored.
+ */
+ public AddressBuilderScheme setDecoded(CharSequence name, Object... values)
+ {
+ parent.setDecoded(name, values);
+ return this;
+ }
+
+ /**
+ * Set a parameter name and value or values. The values will be encoded before they are stored.
+ */
+ public AddressBuilderScheme setEncoded(CharSequence name, Object... values)
+ {
+ parent.setEncoded(name, values);
+ return this;
+ }
+
/**
* Set the port section of this {@link Address}.
*/
@@ -71,16 +102,24 @@ public AddressBuilderPath path(CharSequence path)
}
/**
- * Set the encoded path section of this {@link Address}. The given value will be decoded before it is stored.
+ * Set the path section of this {@link Address}. The given value will be decoded before it is stored.
+ */
+ public AddressBuilderPath pathDecoded(CharSequence path)
+ {
+ return parent.pathDecoded(path);
+ }
+
+ /**
+ * Set the path section of this {@link Address}. The given value will be encoded before it is stored.
*/
public AddressBuilderPath pathEncoded(CharSequence path)
{
- return parent.pathEncoded(path);
+ return parent.pathDecoded(path);
}
/**
- * Set a query-parameter to a value or multiple values. The given name and values will be encoded before they are
- * stored.
+ * Set a query-parameter to a value or multiple values. The given name and values will be stored without additional
+ * encoding or decoding.
*/
public AddressBuilderQuery query(CharSequence name, Object... values)
{
@@ -88,8 +127,15 @@ public AddressBuilderQuery query(CharSequence name, Object... values)
}
/**
- * Set a pre-encoded query-parameter to a pre-encoded value or multiple values. The given name and values be stored
- * without additional encoding or decoding.
+ * Set a query-parameter value or multiple values. The given name and values be decoded before they are stored.
+ */
+ public AddressBuilderQuery queryDecoded(CharSequence name, Object... values)
+ {
+ return parent.queryDecoded(name, values);
+ }
+
+ /**
+ * Set a query-parameter to a value or multiple values. The given name and values be encoded before they are stored.
*/
public AddressBuilderQuery queryEncoded(CharSequence name, Object... values)
{
diff --git a/addressbuilder/src/main/java/org/ocpsoft/urlbuilder/AddressBuilderSchemeSpecificPart.java b/addressbuilder/src/main/java/org/ocpsoft/urlbuilder/AddressBuilderSchemeSpecificPart.java
index 5657a25d0..28440dc24 100644
--- a/addressbuilder/src/main/java/org/ocpsoft/urlbuilder/AddressBuilderSchemeSpecificPart.java
+++ b/addressbuilder/src/main/java/org/ocpsoft/urlbuilder/AddressBuilderSchemeSpecificPart.java
@@ -20,7 +20,7 @@
*
* @author Fabien Marsaud
*/
-public class AddressBuilderSchemeSpecificPart
+public class AddressBuilderSchemeSpecificPart implements BuildableAddress
{
private AddressBuilder parent;
@@ -30,13 +30,44 @@ public class AddressBuilderSchemeSpecificPart
}
/**
- * Generate an {@link Address} representing the current state of this {@link AddressBuilder}.
+ * Set a parameter name and value or values. The supplied values will be stored without additional encoding.
*/
+ public AddressBuilderSchemeSpecificPart set(CharSequence name, Object... values)
+ {
+ parent.set(name, values);
+ return this;
+ }
+
+ /**
+ * Set a parameter name and value or values. The values will be decoded before they are stored.
+ */
+ public AddressBuilderSchemeSpecificPart setDecoded(CharSequence name, Object... values)
+ {
+ parent.setDecoded(name, values);
+ return this;
+ }
+
+ /**
+ * Set a parameter name and value or values. The values will be encoded before they are stored.
+ */
+ public AddressBuilderSchemeSpecificPart setEncoded(CharSequence name, Object... values)
+ {
+ parent.setEncoded(name, values);
+ return this;
+ }
+
+ @Override
public Address build()
{
return parent.build();
}
+ @Override
+ public Address buildLiteral()
+ {
+ return parent.buildLiteral();
+ }
+
@Override
public String toString()
{
diff --git a/addressbuilder/src/main/java/org/ocpsoft/urlbuilder/AddressResult.java b/addressbuilder/src/main/java/org/ocpsoft/urlbuilder/AddressResult.java
index 60af7ff20..8b3ed30e7 100644
--- a/addressbuilder/src/main/java/org/ocpsoft/urlbuilder/AddressResult.java
+++ b/addressbuilder/src/main/java/org/ocpsoft/urlbuilder/AddressResult.java
@@ -15,13 +15,10 @@
*/
package org.ocpsoft.urlbuilder;
+import java.util.Collections;
+import java.util.List;
import java.util.Map;
-import org.ocpsoft.urlbuilder.util.CaptureType;
-import org.ocpsoft.urlbuilder.util.CapturingGroup;
-import org.ocpsoft.urlbuilder.util.Encoder;
-import org.ocpsoft.urlbuilder.util.ParseTools;
-
/**
* Implementation of {@link Address} created by {@link AddressBuilder}.
*
@@ -37,21 +34,22 @@ class AddressResult implements Address
private final String query;
private final String anchor;
private CharSequence result;
+ private Map> queries = Collections.emptyMap();
public AddressResult(AddressBuilder parent)
{
if (isSet(parent.scheme))
- protocol = parameterize(parent.parameters, parent.scheme).toString();
+ protocol = parent.scheme.toString();
else
protocol = null;
if (isSet(parent.schemeSpecificPart))
- schemeSpecificPart = parameterize(parent.parameters, parent.schemeSpecificPart, false).toString();
+ schemeSpecificPart = parent.schemeSpecificPart.toString();
else
schemeSpecificPart = null;
if (isSet(parent.domain))
- host = parameterize(parent.parameters, parent.domain).toString();
+ host = parent.domain.toString();
else
host = null;
@@ -62,7 +60,7 @@ public AddressResult(AddressBuilder parent)
if (isSet(parent.path))
{
- CharSequence path = parameterize(parent.parameters, parent.path);
+ CharSequence path = parent.path;
if (path.charAt(0) != '/')
path = new StringBuilder('/').append(path);
this.path = path.toString();
@@ -70,13 +68,15 @@ public AddressResult(AddressBuilder parent)
else
path = null;
- if (isSet(parent.queries))
+ if (isSet(parent.queries)) {
+ this.queries = Collections.unmodifiableMap(parent.getQueries());
query = toQuery(parent.queries).toString();
+ }
else
query = null;
if (isSetOrEmpty(parent.anchor))
- anchor = parameterize(parent.parameters, parent.anchor).toString();
+ anchor = parent.anchor.toString();
else
anchor = null;
}
@@ -98,7 +98,7 @@ private CharSequence toQuery(Map queries)
if (parameter.getValueCount() > 0)
{
for (int i = 0; i < parameter.getValueCount(); i++) {
- String value = parameter.getValueAsQueryParam(i);
+ String value = parameter.getValue(i);
if (value != null)
result.append('=').append(value);
@@ -118,95 +118,13 @@ public String toString()
{
if (this.result == null)
{
- StringBuilder result = new StringBuilder();
-
- if (isSchemeSet())
- result.append(getScheme()).append(":");
-
- if (isSchemeSpecificPartSet())
- {
- result.append(getSchemeSpecificPart());
- }
- else
- {
- if (isDomainSet())
- result.append("//").append(getDomain());
-
- if (isPortSet())
- result.append(":").append(getPort());
-
- if (isPathSet())
- result.append(getPath());
-
- if (isQuerySet())
- result.append('?').append(getQuery());
-
- if (isAnchorSet())
- result.append('#').append(getAnchor());
- }
-
+ StringBuilder result = AddressBuilder.toString(this);
this.result = result;
}
return this.result.toString();
}
- private CharSequence parameterize(Map parameters, CharSequence sequence)
- {
- return parameterize(parameters, sequence, true);
- }
-
- private CharSequence parameterize(Map parameters, CharSequence sequence, boolean encodeSequence)
- {
- StringBuilder result = new StringBuilder();
- int cursor = 0;
- int lastEnd = 0;
- while (cursor < sequence.length())
- {
- switch (sequence.charAt(cursor))
- {
- case '{':
- CharSequence subSequence = sequence.subSequence(lastEnd, cursor);
- if(encodeSequence)
- subSequence = Encoder.path(subSequence);
-
- result.append(subSequence);
-
- int startPos = cursor;
- CapturingGroup group = ParseTools.balancedCapture(sequence, startPos, sequence.length() - 1,
- CaptureType.BRACE);
- cursor = group.getEnd();
- lastEnd = group.getEnd() + 1;
-
- String name = group.getCaptured().toString();
-
- Parameter parameter = parameters.get(name);
- if (parameter == null || !parameter.hasValues())
- throw new IllegalStateException("No parameter [" + name + "] was set in the pattern [" + sequence
- + "]. Call address.set(\"" + name + "\", value); or remove the parameter from the pattern.");
-
- result.append(parameter.getValueAsPathParam(0));
-
- break;
-
- default:
- break;
- }
-
- cursor++;
- }
-
- if (cursor >= lastEnd)
- {
- CharSequence subSequence = sequence.subSequence(lastEnd, cursor);
- if(encodeSequence)
- subSequence = Encoder.path(subSequence);
-
- result.append(subSequence);
- }
- return result;
- }
-
private boolean isSet(Integer port)
{
return port != null;
@@ -307,19 +225,25 @@ public String getSchemeSpecificPart()
{
return schemeSpecificPart;
}
-
+
@Override
public boolean isSchemeSpecificPartSet()
{
return isSet(schemeSpecificPart);
}
-
+
@Override
public String getQuery()
{
return query;
}
+ @Override
+ public Map> getQueryParameters()
+ {
+ return queries;
+ }
+
@Override
public boolean isQuerySet()
{
diff --git a/addressbuilder/src/main/java/org/ocpsoft/urlbuilder/BuildableAddress.java b/addressbuilder/src/main/java/org/ocpsoft/urlbuilder/BuildableAddress.java
new file mode 100644
index 000000000..40acf0177
--- /dev/null
+++ b/addressbuilder/src/main/java/org/ocpsoft/urlbuilder/BuildableAddress.java
@@ -0,0 +1,28 @@
+/*
+ * Copyright 2016 Red Hat, Inc. and/or its affiliates.
+ *
+ * Licensed under the Eclipse Public License version 1.0, available at
+ * http://www.eclipse.org/legal/epl-v10.html
+ */
+package org.ocpsoft.urlbuilder;
+
+/**
+ * Represents an object that can build and return an {@link Address} as a result.
+ *
+ * @author Lincoln Baxter, III
+ */
+public interface BuildableAddress
+{
+ /**
+ * Generate an {@link Address} representing the current state of this {@link AddressBuilder}.
+ */
+ Address build();
+
+ /**
+ * Generate an {@link Address} representing the current literal state of this {@link AddressBuilder}.
+ *
+ * (Does not apply parameterization. E.g. The URL `/{foo}` will be treated as literal text, as opposed to calling
+ * {@link #build()}, which would result in `foo` being treated as a parameterized expression)
+ */
+ public Address buildLiteral();
+}
diff --git a/addressbuilder/src/main/java/org/ocpsoft/urlbuilder/Parameter.java b/addressbuilder/src/main/java/org/ocpsoft/urlbuilder/Parameter.java
index 57723e5f5..827280ed4 100644
--- a/addressbuilder/src/main/java/org/ocpsoft/urlbuilder/Parameter.java
+++ b/addressbuilder/src/main/java/org/ocpsoft/urlbuilder/Parameter.java
@@ -18,35 +18,31 @@
import java.util.Arrays;
import java.util.List;
-import org.ocpsoft.urlbuilder.util.Encoder;
-
/**
- * Internal state object used in {@link AddressBuilder} to perform parameterization of {@link String} based values.
+ * Immutable internal state object used in {@link AddressBuilder} to perform parameterization of {@link String} based
+ * values.
*
* @author Lincoln Baxter, III
*/
class Parameter
{
-
private final CharSequence name;
private final List values;
- private final boolean encode;
- private Parameter(CharSequence name, boolean encode, List values)
+ private Parameter(CharSequence name, List values)
{
this.name = name;
- this.encode = encode;
this.values = values;
}
- public static Parameter create(CharSequence name, Object... values)
+ public static Parameter create(CharSequence name, List values)
{
- return new Parameter(name, true, Arrays.asList(values));
+ return new Parameter(name, values);
}
- public static Parameter create(CharSequence name, boolean encode, Object... values)
+ public static Parameter create(CharSequence name, Object... values)
{
- return new Parameter(name, encode, Arrays.asList(values));
+ return new Parameter(name, Arrays.asList(values));
}
public CharSequence getName()
@@ -54,11 +50,6 @@ public CharSequence getName()
return name;
}
- public boolean isEncode()
- {
- return encode;
- }
-
public boolean hasValues()
{
return !values.isEmpty();
@@ -69,25 +60,15 @@ public int getValueCount()
return values.size();
}
- public String getValueAsPathParam(int index)
+ public String getValue(int index)
{
- if (encode) {
- return Encoder.path(values.get(index).toString());
- }
- else {
- return values.get(index).toString();
- }
+ Object value = values.get(index);
+ return value == null ? null : value.toString();
}
- public String getValueAsQueryParam(int index)
+ public List getValues()
{
- Object value = values.get(index);
- if (encode) {
- return Encoder.query(value == null ? null : value.toString());
- }
- else {
- return value == null ? null : value.toString();
- }
+ return values;
}
}
diff --git a/addressbuilder/src/main/java/org/ocpsoft/urlbuilder/ParameterizedAddressResult.java b/addressbuilder/src/main/java/org/ocpsoft/urlbuilder/ParameterizedAddressResult.java
new file mode 100644
index 000000000..b561a568b
--- /dev/null
+++ b/addressbuilder/src/main/java/org/ocpsoft/urlbuilder/ParameterizedAddressResult.java
@@ -0,0 +1,301 @@
+/*
+ * Copyright 2013 Lincoln Baxter, III
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package org.ocpsoft.urlbuilder;
+
+import java.util.Collections;
+import java.util.List;
+import java.util.Map;
+
+import org.ocpsoft.urlbuilder.util.CaptureType;
+import org.ocpsoft.urlbuilder.util.CapturingGroup;
+import org.ocpsoft.urlbuilder.util.ParseTools;
+
+/**
+ * Parameterized implementation of {@link Address} created by {@link AddressBuilder}. (Applies parameterization to all
+ * parts of the URL.)
+ *
+ * @author Lincoln Baxter, III
+ */
+class ParameterizedAddressResult implements Address
+{
+ private final String protocol;
+ private final String schemeSpecificPart;
+ private final String host;
+ private final Integer port;
+ private final String path;
+ private final String query;
+ private final String anchor;
+ private CharSequence result;
+ private Map> queries = Collections.emptyMap();
+
+ public ParameterizedAddressResult(AddressBuilder parent)
+ {
+ if (isSet(parent.scheme))
+ protocol = parameterize(parent.parameters, parent.scheme).toString();
+ else
+ protocol = null;
+
+ if (isSet(parent.schemeSpecificPart))
+ schemeSpecificPart = parameterize(parent.parameters, parent.schemeSpecificPart).toString();
+ else
+ schemeSpecificPart = null;
+
+ if (isSet(parent.domain))
+ host = parameterize(parent.parameters, parent.domain).toString();
+ else
+ host = null;
+
+ if (isSet(parent.port))
+ port = parent.port;
+ else
+ port = null;
+
+ if (isSet(parent.path))
+ {
+ CharSequence path = parameterize(parent.parameters, parent.path);
+ if (path.charAt(0) != '/')
+ path = new StringBuilder('/').append(path);
+ this.path = path.toString();
+ }
+ else
+ path = null;
+
+ if (isSet(parent.queries))
+ {
+ this.queries = Collections.unmodifiableMap(parent.getQueries());
+ query = toQuery(parent.queries).toString();
+ }
+ else
+ query = null;
+
+ if (isSetOrEmpty(parent.anchor))
+ anchor = parameterize(parent.parameters, parent.anchor).toString();
+ else
+ anchor = null;
+ }
+
+ private CharSequence toQuery(Map queries)
+ {
+ StringBuilder result = new StringBuilder();
+ boolean first = true;
+ for (CharSequence name : queries.keySet()) {
+ Parameter parameter = queries.get(name);
+
+ if (!first)
+ result.append('&');
+ else
+ first = false;
+
+ result.append(name);
+
+ if (parameter.getValueCount() > 0)
+ {
+ for (int i = 0; i < parameter.getValueCount(); i++) {
+ String value = parameter.getValue(i);
+
+ if (value != null)
+ result.append('=').append(value);
+
+ if (i < parameter.getValueCount() - 1)
+ {
+ result.append('&').append(name);
+ }
+ }
+ }
+ }
+ return result;
+ }
+
+ @Override
+ public String toString()
+ {
+ if (this.result == null)
+ {
+ StringBuilder result = AddressBuilder.toString(this);
+ this.result = result;
+ }
+
+ return this.result.toString();
+ }
+
+ private CharSequence parameterize(Map parameters, CharSequence sequence)
+ {
+ StringBuilder result = new StringBuilder();
+ int cursor = 0;
+ int lastEnd = 0;
+ while (cursor < sequence.length())
+ {
+ switch (sequence.charAt(cursor))
+ {
+ case '{':
+ result.append(sequence.subSequence(lastEnd, cursor));
+
+ int startPos = cursor;
+ CapturingGroup group = ParseTools.balancedCapture(sequence, startPos, sequence.length() - 1,
+ CaptureType.BRACE);
+ cursor = group.getEnd();
+ lastEnd = group.getEnd() + 1;
+
+ String name = group.getCaptured().toString();
+
+ Parameter parameter = parameters.get(name);
+ if (parameter == null || !parameter.hasValues())
+ throw new IllegalStateException("No parameter [" + name + "] was set in the pattern [" + sequence
+ + "]. Call address.set(\"" + name + "\", value); or remove the parameter from the pattern.");
+
+ result.append(parameter.getValue(0));
+
+ break;
+
+ default:
+ break;
+ }
+
+ cursor++;
+ }
+
+ if (cursor >= lastEnd)
+ {
+ result.append(sequence.subSequence(lastEnd, cursor));
+ }
+ return result;
+ }
+
+ private boolean isSet(Integer port)
+ {
+ return port != null;
+ }
+
+ private boolean isSet(Map, ?> map)
+ {
+ return map != null && !map.isEmpty();
+ }
+
+ private boolean isSet(CharSequence value)
+ {
+ return value != null && value.length() > 0;
+ }
+
+ private boolean isSetOrEmpty(CharSequence value)
+ {
+ return value != null;
+ }
+
+ /*
+ * Inspectors
+ */
+
+ @Override
+ public String getAnchor()
+ {
+ return anchor;
+ }
+
+ @Override
+ public boolean isAnchorSet()
+ {
+ return isSetOrEmpty(anchor);
+ }
+
+ @Override
+ public String getPath()
+ {
+ return path;
+ }
+
+ @Override
+ public String getPathAndQuery()
+ {
+ StringBuilder result = new StringBuilder();
+ if (isPathSet())
+ result.append(getPath());
+ if (isQuerySet())
+ result.append('?').append(getQuery());
+ return result.toString();
+ }
+
+ @Override
+ public boolean isPathSet()
+ {
+ return isSet(path);
+ }
+
+ @Override
+ public Integer getPort()
+ {
+ return port;
+ }
+
+ @Override
+ public boolean isPortSet()
+ {
+ return isSet(port);
+ }
+
+ @Override
+ public String getDomain()
+ {
+ return host;
+ }
+
+ @Override
+ public boolean isDomainSet()
+ {
+ return isSet(host);
+ }
+
+ @Override
+ public String getScheme()
+ {
+ return protocol;
+ }
+
+ @Override
+ public boolean isSchemeSet()
+ {
+ return isSet(protocol);
+ }
+
+ @Override
+ public String getSchemeSpecificPart()
+ {
+ return schemeSpecificPart;
+ }
+
+ @Override
+ public boolean isSchemeSpecificPartSet()
+ {
+ return isSet(schemeSpecificPart);
+ }
+
+ @Override
+ public String getQuery()
+ {
+ return query;
+ }
+
+ @Override
+ public Map> getQueryParameters()
+ {
+ return queries;
+ }
+
+ @Override
+ public boolean isQuerySet()
+ {
+ return isSet(query);
+ }
+}
diff --git a/addressbuilder/src/main/java/org/ocpsoft/urlbuilder/util/Encoder.java b/addressbuilder/src/main/java/org/ocpsoft/urlbuilder/util/Encoder.java
index 2411bee47..86c2f28dd 100644
--- a/addressbuilder/src/main/java/org/ocpsoft/urlbuilder/util/Encoder.java
+++ b/addressbuilder/src/main/java/org/ocpsoft/urlbuilder/util/Encoder.java
@@ -6,15 +6,22 @@
import java.net.URLEncoder;
import java.nio.charset.Charset;
+/**
+ * Utility class to encode URL path and query parts.
+ *
+ * @author Lincoln Baxter, III
+ */
public class Encoder
{
private static final Charset UTF8 = Charset.forName("UTF-8");
/**
- * Encodes the given string as described in RFC 2396
+ * Encodes the given string using HTML form encoding as described in RFC 2396.
+ *
+ * @throws IllegalArgumentException when illegal URI syntax is attempted.
*/
- public static String path(CharSequence s)
+ public static String path(CharSequence s) throws IllegalArgumentException
{
try
{
@@ -28,15 +35,17 @@ public static String path(CharSequence s)
}
/**
- * Encodes the given string using HTML form encoding
+ * Encodes the given string using HTML form encoding as described in RFC 2396.
+ *
+ * @throws IllegalArgumentException when illegal URI syntax is attempted.
*/
- public static String query(CharSequence s)
+ public static String query(CharSequence s) throws IllegalArgumentException
{
try {
return URLEncoder.encode(s.toString(), UTF8.name());
}
catch (UnsupportedEncodingException e) {
- throw new IllegalStateException(e);
+ throw new IllegalArgumentException(e);
}
}
diff --git a/addressbuilder/src/test/java/org/ocpsoft/urlbuilder/AddressBuilderEncodingTest.java b/addressbuilder/src/test/java/org/ocpsoft/urlbuilder/AddressBuilderEncodingTest.java
index 7d9a34dd8..1478bff63 100644
--- a/addressbuilder/src/test/java/org/ocpsoft/urlbuilder/AddressBuilderEncodingTest.java
+++ b/addressbuilder/src/test/java/org/ocpsoft/urlbuilder/AddressBuilderEncodingTest.java
@@ -25,7 +25,7 @@ public void testCreateImproperlyEncodedQuery()
@Test
public void testPathEncoded()
{
- Assert.assertEquals("foo%20bar", AddressBuilder.begin().pathEncoded("foo%20bar").build().toString());
+ Assert.assertEquals("foo%20bar", AddressBuilder.begin().path("foo%20bar").build().toString());
}
@Test
@@ -50,15 +50,29 @@ public void testCreateUnencodedAmpersandInQuery() throws Exception
}
@Test
- public void testParameterEncoding()
+ public void testParameterEncodingDomainWithQuery()
+ {
+ Assert.assertEquals("http://a%20b/?q=a+b",
+ AddressBuilder.begin()
+ .scheme("http")
+ .domain("{p}")
+ .setEncoded("p", "a b")
+ .queryEncoded("q", "a b")
+ .build()
+ .toString());
+ }
+
+ @Test
+ public void testParameterEncodingPathWithQuery()
{
Assert.assertEquals("http://localhost/a%20b?q=a+b",
AddressBuilder.begin()
.scheme("http")
.domain("localhost")
.path("/{p}")
- .set("p", "a b")
- .query("q", "a b")
+ .setEncoded("p", "a b")
+ .queryEncoded("q", "a b")
+ .build()
.toString());
}
@@ -70,8 +84,8 @@ public void testParameterEncodingResult()
.scheme("http")
.domain("localhost")
.path("/{p}")
- .set("p", "a b")
- .query("q", "a b")
+ .setEncoded("p", "a b")
+ .queryEncoded("q", "a b")
.build()
.toString());
}
@@ -84,21 +98,27 @@ public void testParametersWithoutEncoding()
.scheme("http")
.domain("localhost")
.path("/{p}")
- .setEncoded("p", "a%20b")
- .queryEncoded("q", "a+b")
+ .set("p", "a%20b")
+ .query("q", "a+b")
+ .build()
.toString());
}
@Test
public void testParametersWithoutEncodingResult()
{
- Assert.assertEquals("http://localhost/a%20b?q=a+b",
+ /*
+ * This is actually an erroneous resultant URL because the space ' ' character should be encoded,
+ * but since we are just testing behavior of the builder, this is fine.
+ * Just don't use this as a "good example".
+ */
+ Assert.assertEquals("http://localhost/a b?q=a b",
AddressBuilder.begin()
.scheme("http")
.domain("localhost")
.path("/{p}")
- .setEncoded("p", "a%20b")
- .queryEncoded("q", "a+b")
+ .set("p", "a b")
+ .query("q", "a b")
.build()
.toString());
}
@@ -107,27 +127,27 @@ public void testParametersWithoutEncodingResult()
public void testBuildQueryWithAmpersandInName()
{
Assert.assertEquals("?q%26q=200",
- AddressBuilder.begin().query("q&q", 200).toString());
+ AddressBuilder.begin().queryEncoded("q&q", 200).toString());
}
@Test
public void testBuildQueryWithAmpersandInValue()
{
Assert.assertEquals("?q=%26200",
- AddressBuilder.begin().query("q", "&200").toString());
+ AddressBuilder.begin().queryEncoded("q", "&200").toString());
}
@Test
public void testBuildQueryWithQuestionMarkInName()
{
Assert.assertEquals("??q=200",
- AddressBuilder.begin().queryEncoded("?q=200").toString());
+ AddressBuilder.begin().query("?q=200").toString());
}
@Test
public void testBuildQueryWithQuestionMarkInValue()
{
Assert.assertEquals("?q=?200",
- AddressBuilder.begin().queryEncoded("q", "?200").toString());
+ AddressBuilder.begin().query("q", "?200").toString());
}
}
diff --git a/addressbuilder/src/test/java/org/ocpsoft/urlbuilder/AddressBuilderTest.java b/addressbuilder/src/test/java/org/ocpsoft/urlbuilder/AddressBuilderTest.java
index 90885dbab..88360ea85 100644
--- a/addressbuilder/src/test/java/org/ocpsoft/urlbuilder/AddressBuilderTest.java
+++ b/addressbuilder/src/test/java/org/ocpsoft/urlbuilder/AddressBuilderTest.java
@@ -3,7 +3,6 @@
import static org.junit.Assert.assertEquals;
import org.junit.Assert;
-import org.junit.Ignore;
import org.junit.Test;
public class AddressBuilderTest
@@ -21,8 +20,9 @@ public void testBuildEverything()
.path("/{s}/{t}")
.set("s", "search")
.set("t", "table")
- .query("q", "query string")
+ .queryEncoded("q", "query string")
.anchor("foo")
+ .build()
.toString());
}
@@ -38,7 +38,7 @@ public void testBuildEverythingResult()
.path("/{s}/{t}")
.set("s", "search")
.set("t", "table")
- .query("q", "query string")
+ .queryEncoded("q", "query string")
.anchor("foo")
.build()
.toString());
@@ -146,7 +146,7 @@ public void testBuildPathSimpleResult()
public void testBuildPathWithOneParameter()
{
Assert.assertEquals("/store/23",
- AddressBuilder.begin().path("/store/{item}").set("item", 23).toString());
+ AddressBuilder.begin().path("/store/{item}").set("item", 23).build().toString());
}
@Test
@@ -160,7 +160,8 @@ public void testBuildPathWithOneParameterResult()
public void testBuildPathWithParameters()
{
Assert.assertEquals("/store/23/buy",
- AddressBuilder.begin().path("/store/{item}/{action}").set("item", 23).set("action", "buy").toString());
+ AddressBuilder.begin().path("/store/{item}/{action}").set("item", 23).set("action", "buy").build()
+ .toString());
}
@Test
@@ -177,7 +178,16 @@ public void testBuildHostAndPath()
Assert.assertEquals("//ocpsoft.org/store/23/buy",
AddressBuilder.begin()
.domain("ocpsoft.org")
- .path("/store/{item}/{action}").set("item", 23).set("action", "buy").toString());
+ .path("/store/{item}/{action}").set("item", 23).set("action", "buy").build().toString());
+ }
+
+ @Test
+ public void testBuildHostAndQuery()
+ {
+ Assert.assertEquals("//ocpsoft.org/?buy=23",
+ AddressBuilder.begin()
+ .domain("ocpsoft.org")
+ .query("buy", "23").build().toString());
}
@Test
@@ -238,6 +248,18 @@ public void testFromStringOnlyWithPathAndQuery()
assertEquals("/search?q=foobar", address.getPathAndQuery());
}
+ @Test
+ public void testFromStringOnlyWithPathAndQuery2()
+ {
+ Address address = AddressBuilder.create("search?q=foobar");
+ assertEquals(null, address.getScheme());
+ assertEquals(null, address.getDomain());
+ assertEquals(null, address.getPort());
+ assertEquals("search", address.getPath());
+ assertEquals("q=foobar", address.getQuery());
+ assertEquals("search?q=foobar", address.getPathAndQuery());
+ }
+
@Test
public void testCreateSchemalessUrl()
{
@@ -257,7 +279,7 @@ public void testBuildSchemeSpecificPart()
{
Assert.assertEquals("mailto:contact@ocpsoft.org?subject=Howdy Lincoln!",
AddressBuilder.begin()
- .scheme("mailto")
+ .scheme("mailto")
.schemeSpecificPart("contact@ocpsoft.org?subject=Howdy Lincoln!")
.toString());
}
@@ -267,9 +289,9 @@ public void testBuildSchemeSpecificPartResult()
{
Assert.assertEquals("mailto:contact@ocpsoft.org?subject=Howdy Lincoln!",
AddressBuilder.begin()
- .scheme("mailto")
- .schemeSpecificPart("contact@ocpsoft.org?subject=Howdy Lincoln!")
- .build().toString());
+ .scheme("mailto")
+ .schemeSpecificPart("contact@ocpsoft.org?subject=Howdy Lincoln!")
+ .build().toString());
}
@Test
@@ -285,11 +307,11 @@ public void testEmptyAnchorOnly()
}
@Test
- @Ignore // see: https://github.com/ocpsoft/rewrite/issues/195
public void shouldCreateAddressFromUrlWithCurlyBrace()
{
Address address = AddressBuilder.create("http://localhost/somepath/%7Bsomething%7D");
- assertEquals("/somepath/{something}", address.getPath());
+ assertEquals("/somepath/%7Bsomething%7D", address.getPath());
+ assertEquals("http://localhost/somepath/%7Bsomething%7D", address.toString());
}
}
diff --git a/api-servlet/src/main/java/org/ocpsoft/rewrite/servlet/http/event/HttpServletRewrite.java b/api-servlet/src/main/java/org/ocpsoft/rewrite/servlet/http/event/HttpServletRewrite.java
index 9b4d72207..aed545dfc 100644
--- a/api-servlet/src/main/java/org/ocpsoft/rewrite/servlet/http/event/HttpServletRewrite.java
+++ b/api-servlet/src/main/java/org/ocpsoft/rewrite/servlet/http/event/HttpServletRewrite.java
@@ -34,7 +34,8 @@ public interface HttpServletRewrite extends
public String getContextPath();
/**
- * Get the full {@link Address} of the current request.
+ * Get the full {@link Address} of the current request. This is the original URL of the request and has not been
+ * encoded or decoded.
*/
Address getInboundAddress();
diff --git a/api-servlet/src/main/java/org/ocpsoft/rewrite/servlet/util/URLBuilder.java b/api-servlet/src/main/java/org/ocpsoft/rewrite/servlet/util/URLBuilder.java
index fe2d63700..5db8a6a11 100644
--- a/api-servlet/src/main/java/org/ocpsoft/rewrite/servlet/util/URLBuilder.java
+++ b/api-servlet/src/main/java/org/ocpsoft/rewrite/servlet/util/URLBuilder.java
@@ -24,6 +24,8 @@
import org.ocpsoft.common.util.Strings;
import org.ocpsoft.urlbuilder.AddressBuilder;
+import org.ocpsoft.urlbuilder.util.Decoder;
+import org.ocpsoft.urlbuilder.util.Encoder;
/**
* Utility for building URL strings. Also manages the URL query string with the help of {@link QueryStringBuilder}.
@@ -170,26 +172,6 @@ public URLBuilder decode()
return new URLBuilder(getDecodedSegments(), metadata, query.decode());
}
- /**
- * Decodes a segment using the {@link URI} class.
- *
- * @param segment The segment to decode
- * @return the decoded segment
- */
- private String decodeSegment(final String segment)
- {
- try
- {
- String prepared = ("http://localhost/" + segment);
- final URI uri = new URI(prepared);
- return uri.getPath().substring(1);
- }
- catch (URISyntaxException e)
- {
- throw new IllegalArgumentException(e);
- }
- }
-
/**
* Return this {@link URLBuilder} after path segments and query parameters have been encoded.
*/
@@ -198,25 +180,6 @@ public URLBuilder encode()
return new URLBuilder(getEncodedSegments(), metadata, query.encode());
}
- /**
- * Encodes a segment using the {@link URI} class.
- *
- * @param segment The segment to encode
- * @return the encoded segment
- */
- private String encodeSegment(final String segment)
- {
- try
- {
- final URI uri = new URI("http", "localhost", "/" + segment, null);
- return uri.toASCIIString().substring(17);
- }
- catch (URISyntaxException e)
- {
- throw new IllegalArgumentException(e);
- }
- }
-
private List getDecodedSegments()
{
/*
@@ -224,7 +187,7 @@ private List getDecodedSegments()
*/
List result = new ArrayList();
for (int i = 0; i < segments.size(); i++) {
- result.add(decodeSegment(segments.get(i)));
+ result.add(Decoder.path(segments.get(i)));
}
return result;
}
@@ -236,7 +199,7 @@ private List getEncodedSegments()
*/
List result = new ArrayList();
for (int i = 0; i < segments.size(); i++) {
- result.add(encodeSegment(segments.get(i)));
+ result.add(Encoder.path(segments.get(i)));
}
return result;
}
diff --git a/config-prettyfaces-tests/src/test/java/org/ocpsoft/rewrite/prettyfaces/encoding/URLEncodingTest.java b/config-prettyfaces-tests/src/test/java/org/ocpsoft/rewrite/prettyfaces/encoding/URLEncodingTest.java
index a5eb9d17b..80eb85741 100644
--- a/config-prettyfaces-tests/src/test/java/org/ocpsoft/rewrite/prettyfaces/encoding/URLEncodingTest.java
+++ b/config-prettyfaces-tests/src/test/java/org/ocpsoft/rewrite/prettyfaces/encoding/URLEncodingTest.java
@@ -16,7 +16,6 @@
*/
package org.ocpsoft.rewrite.prettyfaces.encoding;
-
import org.apache.http.client.methods.HttpGet;
import org.jboss.arquillian.container.test.api.Deployment;
import org.jboss.arquillian.drone.api.annotation.Drone;
@@ -123,14 +122,35 @@ public void testURLDecoding() throws Exception
Assert.assertTrue(browser.getPageSource().contains("beanQueryText=Fooo Bar"));
}
+ @Test
+ public void testURLDecodingWithPoundSignEncoded() throws Exception
+ {
+ browser.get(getBaseURL() + getContextPath() + "/encoding/V%23r?dis=gt%23%232206");
+ String pageSource = browser.getPageSource();
+ Assert.assertTrue(pageSource.contains("/encoding/V%23r?dis=gt%23%232206"));
+ Assert.assertTrue(pageSource.contains("beanPathText=V#r"));
+ Assert.assertTrue(pageSource.contains("beanQueryText=gt##2206"));
+ }
+
+ @Test
+ public void testURLDecodingWithPoundSign() throws Exception
+ {
+ browser.get(getBaseURL() + getContextPath() + "/encoding/V%23r?dis=gt##2206");
+ String pageSource = browser.getPageSource();
+ Assert.assertTrue(pageSource.contains("/encoding/V%23r?dis=gt"));
+ Assert.assertTrue(pageSource.contains("beanPathText=V#r"));
+ Assert.assertTrue(pageSource.contains("beanQueryText=gt"));
+ }
+
@Test
public void testQueryDecoding() throws Exception
{
HttpAction action = get("/encoding/Vračar?dis=Fooo%20Bar");
Assert.assertTrue(action.getCurrentURL().endsWith("/encoding/Vračar?dis=Fooo%20Bar"));
- Assert.assertTrue(action.getResponseContent().contains("/encoding/Vra%C4%8Dar?dis=Fooo+Bar"));
- Assert.assertTrue(action.getResponseContent().contains("beanQueryText=Fooo Bar"));
+ String responseContent = action.getResponseContent();
+ Assert.assertTrue(responseContent.contains("/encoding/Vra%C4%8Dar?dis=Fooo+Bar"));
+ Assert.assertTrue(responseContent.contains("beanQueryText=Fooo Bar"));
}
@Test
@@ -141,7 +161,6 @@ public void testEncodedPathDecoding() throws Exception
Assert.assertTrue(action.getCurrentURL().endsWith("/encoding/Vračar?dis=Fooo%20Bar"));
Assert.assertTrue(action.getResponseContent().contains("/encoding/Vra%C4%8Dar?dis=Fooo+Bar"));
Assert.assertTrue(action.getResponseContent().contains("beanPathText=Vračar"));
- Assert.assertTrue(action.getResponseContent().contains("beanQueryText=Fooo Bar"));
}
@Test
@@ -178,4 +197,18 @@ public void testNoDecodeOnSubmitDoesNotCrash() throws Exception
browser.findElement(By.id("submit")).click();
Assert.assertTrue(browser.getPageSource().contains("viewId=/encoding.xhtml"));
}
+
+ @Test
+ public void testBracesAndBracketsInURL() throws Exception
+ {
+ browser.get(getBaseURL() + getContextPath() + "/basic/[]{}");
+ Assert.assertNotNull(browser.findElement(By.id("form")));
+ }
+
+ @Test
+ public void testBracesAndBracketsInURLEncoded() throws Exception
+ {
+ browser.get(getBaseURL() + getContextPath() + "/basic/%5B%5D%7B%7D");
+ Assert.assertNotNull(browser.findElement(By.id("form")));
+ }
}
diff --git a/config-prettyfaces-tests/src/test/resources/encoding/encoding-pretty-config.xml b/config-prettyfaces-tests/src/test/resources/encoding/encoding-pretty-config.xml
index f3368d599..f1c303b3b 100644
--- a/config-prettyfaces-tests/src/test/resources/encoding/encoding-pretty-config.xml
+++ b/config-prettyfaces-tests/src/test/resources/encoding/encoding-pretty-config.xml
@@ -41,5 +41,9 @@
+
+
+
+
\ No newline at end of file
diff --git a/config-prettyfaces/src/main/java/com/ocpsoft/pretty/faces/url/URL.java b/config-prettyfaces/src/main/java/com/ocpsoft/pretty/faces/url/URL.java
index 186763139..2f9210928 100644
--- a/config-prettyfaces/src/main/java/com/ocpsoft/pretty/faces/url/URL.java
+++ b/config-prettyfaces/src/main/java/com/ocpsoft/pretty/faces/url/URL.java
@@ -15,8 +15,6 @@
*/
package com.ocpsoft.pretty.faces.url;
-import java.net.URI;
-import java.net.URISyntaxException;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.Collections;
@@ -24,8 +22,16 @@
import java.util.List;
import java.util.Map;
+import org.ocpsoft.urlbuilder.util.Decoder;
+import org.ocpsoft.urlbuilder.util.Encoder;
+
import com.ocpsoft.pretty.faces.util.StringUtils;
+/**
+ * Utility class providing common functionality required when interacting with and asking questions of URLs.
+ *
+ * @author Lincoln Baxter, III
+ */
public class URL
{
private Metadata metadata = new Metadata();
@@ -96,7 +102,7 @@ public List getDecodedSegments()
List result = new ArrayList();
for (String segment : segments)
{
- result.add(decodeSegment(segment));
+ result.add(Decoder.path(segment));
}
decodedSegments.put(encoding, Collections.unmodifiableList(result));
}
@@ -111,65 +117,11 @@ public List getEncodedSegments()
List resultSegments = new ArrayList();
for (String segment : segments)
{
- resultSegments.add(encodeSegment(segment));
+ resultSegments.add(Encoder.path(segment));
}
return resultSegments;
}
- /**
- * Encodes a segment using the {@link URI} class.
- *
- * @param segment The segment to encode
- * @return the encoded segment
- */
- private static String encodeSegment(final String segment)
- {
- try
- {
- final URI uri = new URI("http", "localhost", "/" + segment, null);
- return uri.toASCIIString().substring(17);
- }
- catch (URISyntaxException e)
- {
- throw new IllegalArgumentException(e);
- }
- }
-
- /**
- * Decodes a segment using the {@link URI} class.
- *
- * @param segment The segment to decode
- * @return the decoded segment
- */
- private static String decodeSegment(final String segment)
- {
- try
- {
-
- /*
- * Note: The replacement allows to call decode() on an already decoded URL
- * and supports decoding of strings that contain not encoded characters.
- * IHMO this is only needed because there seem to be situation in PrettyFaces
- * where decoded URLs are decoded again.
- */
-
- final URI uri = new URI(("http://localhost/" + segment)
- .replace(" ", "%20")
- .replace("\"", "%22")
- .replace("[", "%5B")
- .replace("]", "%5D")
- .replace("<", "%3C")
- .replace(">", "%3E")
- .replace("|", "%7C")
- );
- return uri.getPath().substring(1);
- }
- catch (URISyntaxException e)
- {
- throw new IllegalArgumentException(e);
- }
- }
-
/**
* Return a decoded form of this URL.
*/
diff --git a/config-prettyfaces/src/main/java/org/ocpsoft/rewrite/prettyfaces/UrlMappingRuleAdaptor.java b/config-prettyfaces/src/main/java/org/ocpsoft/rewrite/prettyfaces/UrlMappingRuleAdaptor.java
index 161a57d34..b58a48cc4 100644
--- a/config-prettyfaces/src/main/java/org/ocpsoft/rewrite/prettyfaces/UrlMappingRuleAdaptor.java
+++ b/config-prettyfaces/src/main/java/org/ocpsoft/rewrite/prettyfaces/UrlMappingRuleAdaptor.java
@@ -121,7 +121,8 @@ private String rewritePrettyMappings(final PrettyConfig config, final String con
return result;
}
- private boolean evaluateOutbound(String outboundURL) {
+ private boolean evaluateOutbound(String outboundURL)
+ {
QueryString outboundQueryString = new QueryString();
if (outboundURL.contains("?")) {
outboundQueryString.addParameters(outboundURL);
@@ -169,7 +170,7 @@ private boolean evaluateOutbound(String outboundURL) {
for (String outboundParamValue : outboundParam.getValue())
{
if ((mappingViewParamValue == outboundParamValue)
- || (mappingViewParamValue != null && mappingViewParamValue.equals(outboundParamValue)))
+ || (mappingViewParamValue != null && mappingViewParamValue.equals(outboundParamValue)))
{
found = true;
break;
@@ -217,11 +218,12 @@ else if ((event instanceof HttpOutboundServletRewrite)
@Override
public void perform(final Rewrite event, final EvaluationContext ec)
{
- PrettyContext context = PrettyContext.getCurrentInstance(((HttpServletRewrite) event).getRequest());
+ HttpServletRewrite httpServletRewrite = (HttpServletRewrite) event;
+ PrettyContext context = PrettyContext.getCurrentInstance(httpServletRewrite.getRequest());
if (event instanceof HttpInboundServletRewrite)
{
- ((HttpServletRewrite) event).getRequest().setAttribute(REWRITE_MAPPING_ID_KEY,
+ httpServletRewrite.getRequest().setAttribute(REWRITE_MAPPING_ID_KEY,
REWRITE_MAPPING_ID_KEY + ":" + mapping.getId());
URL url = context.getRequestURL();
@@ -234,9 +236,9 @@ public void perform(final Rewrite event, final EvaluationContext ec)
{
String viewId = mapping.getViewId();
log.trace("Forwarding mapped request [" + url.toURL() + "] to resource [" + viewId + "]");
- if (url.decode().toURL().equals(viewId))
+ if (url.toURL().equals(viewId))
{
- ((HttpServletRewrite) event).proceed();
+ httpServletRewrite.proceed();
}
else
{
@@ -247,7 +249,7 @@ public void perform(final Rewrite event, final EvaluationContext ec)
else if ((event instanceof HttpOutboundServletRewrite) && mapping.isOutbound())
{
HttpOutboundServletRewrite outboundRewrite = (HttpOutboundServletRewrite) event;
- String newUrl = rewritePrettyMappings(context.getConfig(), ((HttpServletRewrite) event).getContextPath(),
+ String newUrl = rewritePrettyMappings(context.getConfig(), httpServletRewrite.getContextPath(),
outboundRewrite.getOutboundAddress().toString());
outboundRewrite.setOutboundAddress(AddressBuilder.create(newUrl));
}
diff --git a/config-servlet/src/main/java/org/ocpsoft/rewrite/servlet/config/Path.java b/config-servlet/src/main/java/org/ocpsoft/rewrite/servlet/config/Path.java
index e8a78beee..9929bedad 100644
--- a/config-servlet/src/main/java/org/ocpsoft/rewrite/servlet/config/Path.java
+++ b/config-servlet/src/main/java/org/ocpsoft/rewrite/servlet/config/Path.java
@@ -36,15 +36,14 @@
import org.ocpsoft.rewrite.servlet.http.event.HttpOutboundServletRewrite;
import org.ocpsoft.rewrite.servlet.http.event.HttpServletRewrite;
import org.ocpsoft.rewrite.servlet.spi.RequestParameterProvider;
-import org.ocpsoft.rewrite.servlet.util.URLBuilder;
import org.ocpsoft.urlbuilder.Address;
+import org.ocpsoft.urlbuilder.AddressBuilder;
/**
* A {@link Condition} that inspects the value of {@link HttpServletRewrite#getRequestPath()}
*
* @author Lincoln Baxter, III
*/
-@SuppressWarnings("deprecation")
public abstract class Path extends HttpCondition implements Parameterized
{
private final ParameterizedPatternParser expression;
@@ -129,7 +128,7 @@ public boolean evaluateHttp(final HttpServletRewrite event, final EvaluationCont
return false;
}
else
- url = URLBuilder.createFrom(event.getInboundAddress().getPath()).decode().toPath();
+ url = AddressBuilder.begin().pathDecoded(event.getInboundAddress().getPath()).buildLiteral().toString();
String contextPath = event.getContextPath();
if (!contextPath.equals("/") && url.startsWith(contextPath))
diff --git a/config-servlet/src/main/java/org/ocpsoft/rewrite/servlet/config/PathAndQuery.java b/config-servlet/src/main/java/org/ocpsoft/rewrite/servlet/config/PathAndQuery.java
index e4935ea98..3378f4fce 100644
--- a/config-servlet/src/main/java/org/ocpsoft/rewrite/servlet/config/PathAndQuery.java
+++ b/config-servlet/src/main/java/org/ocpsoft/rewrite/servlet/config/PathAndQuery.java
@@ -32,20 +32,18 @@
import org.ocpsoft.rewrite.param.ParameterizedPatternParser;
import org.ocpsoft.rewrite.param.RegexConstraint;
import org.ocpsoft.rewrite.param.RegexParameterizedPatternParser;
-import org.ocpsoft.rewrite.servlet.config.HttpCondition;
import org.ocpsoft.rewrite.servlet.config.bind.RequestBinding;
import org.ocpsoft.rewrite.servlet.http.event.HttpOutboundServletRewrite;
import org.ocpsoft.rewrite.servlet.http.event.HttpServletRewrite;
import org.ocpsoft.rewrite.servlet.spi.RequestParameterProvider;
-import org.ocpsoft.rewrite.servlet.util.URLBuilder;
import org.ocpsoft.urlbuilder.Address;
+import org.ocpsoft.urlbuilder.AddressBuilder;
/**
* A {@link Condition} that inspects the value of {@link HttpServletRewrite#getAddress()} path and query string.
*
* @author Lincoln Baxter, III
*/
-@SuppressWarnings("deprecation")
public abstract class PathAndQuery extends HttpCondition implements Parameterized
{
private final ParameterizedPatternParser expression;
@@ -132,7 +130,8 @@ public boolean evaluateHttp(final HttpServletRewrite event, final EvaluationCont
return false;
}
else
- url = URLBuilder.createFrom(event.getInboundAddress().getPathAndQuery()).decode().toURL();
+ url = AddressBuilder.begin().pathDecoded(event.getInboundAddress().getPath())
+ .queryDecoded(event.getInboundAddress().getQuery()).build().toString();
String contextPath = event.getContextPath();
if (!contextPath.equals("/") && url.startsWith(contextPath))
diff --git a/config-servlet/src/main/java/org/ocpsoft/rewrite/servlet/config/rule/Join.java b/config-servlet/src/main/java/org/ocpsoft/rewrite/servlet/config/rule/Join.java
index 3c12b4d14..ee4db4f9d 100644
--- a/config-servlet/src/main/java/org/ocpsoft/rewrite/servlet/config/rule/Join.java
+++ b/config-servlet/src/main/java/org/ocpsoft/rewrite/servlet/config/rule/Join.java
@@ -15,8 +15,11 @@
*/
package org.ocpsoft.rewrite.servlet.config.rule;
+import java.util.ArrayList;
import java.util.LinkedHashSet;
import java.util.List;
+import java.util.Map;
+import java.util.Map.Entry;
import java.util.Set;
import javax.servlet.http.HttpServletRequest;
@@ -46,8 +49,9 @@
import org.ocpsoft.rewrite.servlet.http.event.HttpOutboundServletRewrite;
import org.ocpsoft.rewrite.servlet.http.event.HttpServletRewrite;
import org.ocpsoft.rewrite.servlet.spi.RequestParameterProvider;
-import org.ocpsoft.rewrite.servlet.util.QueryStringBuilder;
import org.ocpsoft.urlbuilder.Address;
+import org.ocpsoft.urlbuilder.AddressBuilder;
+import org.ocpsoft.urlbuilder.AddressBuilderBase;
/**
* {@link Rule} that creates a bi-directional rewrite rule between an externally facing {@link Address} and an internal
@@ -56,7 +60,6 @@
*
* @author Lincoln Baxter, III
*/
-@SuppressWarnings("deprecation")
public class Join implements Rule, JoinPath, Parameterized
{
private static final String JOIN_DISABLED_KEY = Join.class.getName() + "_DISABLED";
@@ -268,25 +271,36 @@ public void perform(final Rewrite event, final EvaluationContext context)
else if (event instanceof HttpOutboundServletRewrite)
{
- Set parameters = getPathRequestParameters();
+ Address outboundAddress = ((HttpOutboundServletRewrite) event).getOutboundAddress();
- String outboundURL = ((HttpOutboundServletRewrite) event).getOutboundAddress().toString();
- QueryStringBuilder query = QueryStringBuilder.createNew();
- if (outboundURL.contains("?"))
+ /*
+ * Remove known path parameters from query parameter list to be included in new URL
+ */
+ Set pathParameters = getPathRequestParameters();
+ AddressBuilderBase queryBuilder = AddressBuilder.begin();
+ if (outboundAddress.isQuerySet())
{
- query.addParameters(outboundURL);
- for (String string : parameters) {
- List values = query.removeParameter(string);
- if (values.size() > 1)
+ // Create a new query string without the parameters that were used in building the path
+ Map> queryParameters = outboundAddress.getQueryParameters();
+ for (Entry> queryParameter : queryParameters.entrySet()) {
+ String parameterName = queryParameter.getKey();
+ List parameterValues = queryParameter.getValue();
+ if (pathParameters.contains(parameterName))
+ {
+ List newParameterValues = new ArrayList(parameterValues);
+ newParameterValues.remove(0);
+ if (!newParameterValues.isEmpty())
+ queryBuilder.query(parameterName, newParameterValues.toArray());
+ }
+ else
{
- query.addParameter(string, values.subList(1, values.size()).toArray(new String[] {}));
+ queryBuilder.query(parameterName, parameterValues.toArray());
}
}
}
+ Address queryResult = queryBuilder.buildLiteral();
- Address outboundAddress = ((HttpOutboundServletRewrite) event).getOutboundAddress();
-
- Substitute substitute = Substitute.with(requestPattern + query.toQueryString());
+ Substitute substitute = Substitute.with(requestPattern + queryResult.toString());
substitute.setParameterStore(store);
substitute.perform(event, context);
diff --git a/config-servlet/src/test/java/org/ocpsoft/rewrite/servlet/config/CommittedResponseTest.java b/config-servlet/src/test/java/org/ocpsoft/rewrite/servlet/config/CommittedResponseTest.java
index d91c5c673..259ae82b6 100644
--- a/config-servlet/src/test/java/org/ocpsoft/rewrite/servlet/config/CommittedResponseTest.java
+++ b/config-servlet/src/test/java/org/ocpsoft/rewrite/servlet/config/CommittedResponseTest.java
@@ -23,7 +23,6 @@
import org.jboss.arquillian.junit.Arquillian;
import org.jboss.shrinkwrap.api.asset.StringAsset;
import org.jboss.shrinkwrap.api.spec.WebArchive;
-import org.junit.Ignore;
import org.junit.Test;
import org.junit.experimental.categories.Category;
import org.junit.runner.RunWith;
diff --git a/config-servlet/src/test/java/org/ocpsoft/rewrite/servlet/config/ForwardEncodingTest.java b/config-servlet/src/test/java/org/ocpsoft/rewrite/servlet/config/ForwardEncodingTest.java
index e4d135cf7..9c5c0f828 100644
--- a/config-servlet/src/test/java/org/ocpsoft/rewrite/servlet/config/ForwardEncodingTest.java
+++ b/config-servlet/src/test/java/org/ocpsoft/rewrite/servlet/config/ForwardEncodingTest.java
@@ -105,7 +105,6 @@ public void requestUrlsDirect() throws Exception
Matchers.containsString("getRequestURI: [/rewrite-test/direct/debug/foo%20bar.dyn]"));
assertThat(action.getResponseContent(),
Matchers.containsString("inboundAddressPath: [/rewrite-test/direct/debug/foo%20bar.dyn]"));
-
}
@Test
@@ -116,13 +115,14 @@ public void requestUrlsForward() throws Exception
assertEquals(200, action.getResponse().getStatusLine().getStatusCode());
// Not really sure if this is the expected result
+ // Lincoln: This is the behavior of the underlying HttpServletRequest, so we've really not changed/modified any
+ // behavior here. Recommend leaving this alone.
assertThat(action.getResponseContent(),
Matchers.containsString("getRequestURI: [/rewrite-test/direct/debug/foo bar.dyn]"));
// IMHO this should be the result as it is consistent with the non-forwarded case
assertThat(action.getResponseContent(),
Matchers.containsString("inboundAddressPath: [/rewrite-test/direct/debug/foo%20bar.dyn]"));
-
}
}
\ No newline at end of file
diff --git a/config-servlet/src/test/java/org/ocpsoft/rewrite/servlet/config/JoinEncodingConfigurationTest.java b/config-servlet/src/test/java/org/ocpsoft/rewrite/servlet/config/JoinEncodingConfigurationTest.java
index 25ac3b41b..cf631b973 100644
--- a/config-servlet/src/test/java/org/ocpsoft/rewrite/servlet/config/JoinEncodingConfigurationTest.java
+++ b/config-servlet/src/test/java/org/ocpsoft/rewrite/servlet/config/JoinEncodingConfigurationTest.java
@@ -33,7 +33,6 @@
import org.jboss.arquillian.container.test.api.Deployment;
import org.jboss.arquillian.junit.Arquillian;
import org.jboss.shrinkwrap.api.spec.WebArchive;
-import org.junit.Ignore;
import org.junit.Test;
import org.junit.runner.RunWith;
import org.ocpsoft.common.util.Streams;
@@ -85,7 +84,6 @@ public void testJoinEncodingSpaceCharacter() throws Exception
}
@Test
- @Ignore // see: https://github.com/ocpsoft/rewrite/issues/195
public void testJoinSupportsSingleCurlyBrace() throws Exception
{
HttpAction action = get("/encoding/foo%7Bbar");
@@ -97,7 +95,17 @@ public void testJoinSupportsSingleCurlyBrace() throws Exception
}
@Test
- @Ignore // see: https://github.com/ocpsoft/rewrite/issues/195
+ public void testJoinSupportsCurlyBracketGroup() throws Exception
+ {
+ HttpAction action = get("/encoding/foo%5B%5D");
+ assertEquals(200, action.getResponse().getStatusLine().getStatusCode());
+
+ String responseContent = action.getResponseContent();
+ assertThat(responseContent, containsString("getRequestPath() = " + getContextPath() + "/encoding.html"));
+ assertThat(responseContent, containsString("getParameter('param') = foo[]"));
+ }
+
+ @Test
public void testJoinSupportsCurlyBraceGroup() throws Exception
{
HttpAction action = get("/encoding/foo%7Bbar%7D");
@@ -174,7 +182,8 @@ public void testOutboundRewritingSimpleString() throws Exception
/**
* Make sure that an URL containing a space in the query string (encoded as '+') is rewritten to a path containing
- * the space encoded as %20.
+ * the space encoded as %20. This effectively tests if proper encoding/decoding is occurring throughout the entire
+ * life-cycle of the parameter.
*/
@Test
public void testOutboundRewritingSpaceCharacter() throws Exception
diff --git a/impl-servlet/src/main/java/org/ocpsoft/rewrite/servlet/impl/BaseHttpRewrite.java b/impl-servlet/src/main/java/org/ocpsoft/rewrite/servlet/impl/BaseHttpRewrite.java
index 1a120c0b3..f95626132 100644
--- a/impl-servlet/src/main/java/org/ocpsoft/rewrite/servlet/impl/BaseHttpRewrite.java
+++ b/impl-servlet/src/main/java/org/ocpsoft/rewrite/servlet/impl/BaseHttpRewrite.java
@@ -89,8 +89,8 @@ public Address getInboundAddress()
.scheme(getRequest().getScheme())
.domain(getRequest().getServerName())
.port(getRequest().getServerPort())
- .pathEncoded(requestURI)
- .queryLiteral(getRequest().getQueryString()).build();
+ .path(requestURI)
+ .queryLiteral(getRequest().getQueryString()).buildLiteral();
}
return this.address;
}
diff --git a/impl-servlet/src/main/java/org/ocpsoft/rewrite/servlet/impl/DefaultHttpRewriteProvider.java b/impl-servlet/src/main/java/org/ocpsoft/rewrite/servlet/impl/DefaultHttpRewriteProvider.java
index 91b9ca337..d9ec680fc 100644
--- a/impl-servlet/src/main/java/org/ocpsoft/rewrite/servlet/impl/DefaultHttpRewriteProvider.java
+++ b/impl-servlet/src/main/java/org/ocpsoft/rewrite/servlet/impl/DefaultHttpRewriteProvider.java
@@ -246,7 +246,7 @@ private void rewriteInbound(final HttpServletRewrite event)
}
}
catch (Exception e) {
- throw new RewriteException("Error during [" + event + "] while executing rule [" + rule + "]");
+ throw new RewriteException("Error during [" + event + "] while executing rule [" + rule + "]", e);
}
}
diff --git a/impl-servlet/src/main/java/org/ocpsoft/rewrite/servlet/impl/HttpRewriteWrappedResponse.java b/impl-servlet/src/main/java/org/ocpsoft/rewrite/servlet/impl/HttpRewriteWrappedResponse.java
index 4ba4bfbab..d362e65a8 100644
--- a/impl-servlet/src/main/java/org/ocpsoft/rewrite/servlet/impl/HttpRewriteWrappedResponse.java
+++ b/impl-servlet/src/main/java/org/ocpsoft/rewrite/servlet/impl/HttpRewriteWrappedResponse.java
@@ -49,7 +49,6 @@
import org.ocpsoft.rewrite.servlet.http.event.HttpServletRewrite;
import org.ocpsoft.rewrite.servlet.spi.OutboundRewriteProducer;
import org.ocpsoft.rewrite.servlet.spi.RewriteLifecycleListener;
-import org.ocpsoft.rewrite.servlet.util.URLBuilder;
import org.ocpsoft.rewrite.spi.RewriteProvider;
import org.ocpsoft.urlbuilder.Address;
import org.ocpsoft.urlbuilder.AddressBuilder;
@@ -57,7 +56,6 @@
/**
* @author Lincoln Baxter, III
*/
-@SuppressWarnings("deprecation")
public class HttpRewriteWrappedResponse extends RewriteWrappedResponse
{
private final HttpServletRequest request;
@@ -378,7 +376,7 @@ public String encodeUrl(final String url)
@Override
public String encodeRedirectURL(final String url)
{
- Address address = AddressBuilder.create(URLBuilder.createFrom(url).toURL());
+ Address address = AddressBuilder.create(url);
OutboundServletRewrite event = rewrite(address);
if (event.getFlow().is(ServletRewriteFlow.ABORT_REQUEST))
@@ -391,7 +389,7 @@ public String encodeRedirectURL(final String url)
@Override
public String encodeURL(final String url)
{
- Address address = AddressBuilder.create(URLBuilder.createFrom(url).toURL());
+ Address address = AddressBuilder.create(url);
OutboundServletRewrite event = rewrite(address);
if (event.getFlow().is(ServletRewriteFlow.ABORT_REQUEST))
diff --git a/integration-faces/src/main/java/org/ocpsoft/rewrite/faces/navigate/Navigate.java b/integration-faces/src/main/java/org/ocpsoft/rewrite/faces/navigate/Navigate.java
index 1f929ee1c..fa4991ae1 100644
--- a/integration-faces/src/main/java/org/ocpsoft/rewrite/faces/navigate/Navigate.java
+++ b/integration-faces/src/main/java/org/ocpsoft/rewrite/faces/navigate/Navigate.java
@@ -126,10 +126,10 @@ public String build()
*/
private String buildRedirectOutcome()
{
- AddressBuilderPath builderPath = AddressBuilder.begin().path(viewId);
+ AddressBuilderPath builderPath = AddressBuilder.begin().pathEncoded(viewId);
for (Entry> param : parameters.entrySet()) {
String[] values = param.getValue().toArray(new String[param.getValue().size()]);
- builderPath.query(param.getKey(), (Object[]) values);
+ builderPath.queryEncoded(param.getKey(), (Object[]) values);
}
String url = builderPath.toString();
return RewriteNavigationHandler.REDIRECT_PREFIX + url;