You are viewing a plain text version of this content. The canonical link for it is here.
Posted to dev@shindig.apache.org by et...@apache.org on 2008/08/15 21:24:02 UTC

svn commit: r686334 - in /incubator/shindig/trunk/java/common/src: main/java/org/apache/shindig/common/uri/ test/java/org/apache/shindig/common/uri/

Author: etnu
Date: Fri Aug 15 12:24:01 2008
New Revision: 686334

URL: http://svn.apache.org/viewvc?rev=686334&view=rev
Log:
Created more useful Uri abstractions than the built in java.net.URI. This facilitates disassembling and reconstructing uris in a more flexible manner than the ad-hoc parsing being done currently.

One missing piece of functionality at the moment is the ability to set raw, unencoded query strings. This will be a temporary barrier to using this code in signed fetch and oauth due to the encoding requirements that differ from java.net.URLEncoder.


Added:
    incubator/shindig/trunk/java/common/src/main/java/org/apache/shindig/common/uri/
    incubator/shindig/trunk/java/common/src/main/java/org/apache/shindig/common/uri/Uri.java
    incubator/shindig/trunk/java/common/src/main/java/org/apache/shindig/common/uri/UriBuilder.java
    incubator/shindig/trunk/java/common/src/test/java/org/apache/shindig/common/uri/
    incubator/shindig/trunk/java/common/src/test/java/org/apache/shindig/common/uri/UriBuilderTest.java
    incubator/shindig/trunk/java/common/src/test/java/org/apache/shindig/common/uri/UriTest.java

Added: incubator/shindig/trunk/java/common/src/main/java/org/apache/shindig/common/uri/Uri.java
URL: http://svn.apache.org/viewvc/incubator/shindig/trunk/java/common/src/main/java/org/apache/shindig/common/uri/Uri.java?rev=686334&view=auto
==============================================================================
--- incubator/shindig/trunk/java/common/src/main/java/org/apache/shindig/common/uri/Uri.java (added)
+++ incubator/shindig/trunk/java/common/src/main/java/org/apache/shindig/common/uri/Uri.java Fri Aug 15 12:24:01 2008
@@ -0,0 +1,175 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements.  See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership.  The ASF licenses this file
+ * to you 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.apache.shindig.common.uri;
+
+import com.google.common.collect.Multimap;
+import com.google.common.collect.Multimaps;
+
+import java.net.URI;
+import java.net.URISyntaxException;
+import java.util.Collection;
+
+/**
+* Represents a Uniform Resource Identifier (URI) reference as defined by <a
+* href="http://tools.ietf.org/html/rfc3986">RFC 3986</a>.
+*
+* Assumes that all url components are UTF-8 encoded.
+*/
+public final class Uri {
+  private final String text;
+  private final String scheme;
+  private final String authority;
+  private final String path;
+  private final String queryString;
+  private final Multimap<String, String> query;
+  private final String fragment;
+
+  /**
+   * Produces a new Uri from a text representation.
+   *
+   * @param text The text uri.
+   * @return A new Uri, parsed into components.
+   */
+  public static Uri parse(String text) {
+    try {
+      URI uri = new URI(text);
+      return new Uri(uri.getScheme(),
+                     uri.getAuthority(),
+                     uri.getPath(),
+                     UriBuilder.splitParameters(uri.getRawQuery()),
+                     uri.getFragment());
+    } catch (URISyntaxException e) {
+      throw new IllegalArgumentException(e);
+    }
+  }
+
+  Uri(String scheme, String authority, String path, Multimap<String, String> query,
+      String fragment) {
+    this.scheme = scheme;
+    this.authority = authority;
+    this.path = path;
+    this.query = Multimaps.unmodifiableMultimap(query);
+    this.queryString = UriBuilder.joinParameters(query);
+    this.fragment = fragment;
+
+    StringBuilder out = new StringBuilder();
+
+    if (scheme != null) {
+      out.append(scheme).append(':');
+    }
+    if (authority != null) {
+      out.append("//").append(authority);
+    }
+    if (path != null) {
+      out.append(path);
+    }
+    if (queryString != null) {
+      out.append('?').append(queryString);
+    }
+    if (fragment != null) {
+      out.append('#').append(fragment);
+    }
+    this.text = out.toString();
+  }
+
+  /**
+   * Converts the Uri to a java.net.URI.
+   */
+  public URI toJavaUri() throws URISyntaxException {
+    return new URI(scheme, authority, path, queryString, fragment);
+  }
+
+  /**
+   * @return The scheme part of the uri, or null if none was specified.
+   */
+  public String getScheme() {
+    return scheme;
+  }
+
+  /**
+   * @return The authority part of the uri, or null if none was specified.
+   */
+  public String getAuthority() {
+    return authority;
+  }
+
+  /**
+   * @return The path part of the uri, or null if none was specified.
+   */
+  public String getPath() {
+    return path;
+  }
+
+  /**
+   * @return The query part of the uri, or null if none was specified.
+   */
+  public String getQuery() {
+    return queryString;
+  }
+
+  /**
+   * @return The query part of the uri, separated into component parts.
+   */
+  public Multimap<String, String> getQueryParameters() {
+    return query;
+  }
+
+  /**
+   * @return All query parameters with the given name.
+   */
+  public Collection<String> getQueryParameters(String name) {
+    return query.get(name);
+  }
+
+  /**
+   * @return The first query parameter value with the given name.
+   */
+  public String getQueryParameter(String name) {
+    Collection<String> values = query.get(name);
+    if (values == null || values.isEmpty()) {
+      return null;
+    }
+    return values.iterator().next();
+  }
+
+  /**
+   * @return The query fragment.
+   */
+  public String getFragment() {
+    return fragment;
+  }
+
+  @Override
+  public String toString() {
+    return text;
+  }
+
+  @Override
+  public int hashCode() {
+    return text.hashCode();
+  }
+
+  @Override
+  public boolean equals(Object rhs) {
+    if (rhs == this) {return true;}
+    if (!(rhs instanceof Uri)) {return false;}
+
+    return text.equals(((Uri)rhs).text);
+  }
+}

Added: incubator/shindig/trunk/java/common/src/main/java/org/apache/shindig/common/uri/UriBuilder.java
URL: http://svn.apache.org/viewvc/incubator/shindig/trunk/java/common/src/main/java/org/apache/shindig/common/uri/UriBuilder.java?rev=686334&view=auto
==============================================================================
--- incubator/shindig/trunk/java/common/src/main/java/org/apache/shindig/common/uri/UriBuilder.java (added)
+++ incubator/shindig/trunk/java/common/src/main/java/org/apache/shindig/common/uri/UriBuilder.java Fri Aug 15 12:24:01 2008
@@ -0,0 +1,224 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements.  See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership.  The ASF licenses this file
+ * to you 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.apache.shindig.common.uri;
+
+import org.apache.shindig.common.util.Utf8UrlCoder;
+
+import com.google.common.collect.Multimap;
+import com.google.common.collect.Multimaps;
+
+import java.util.Collection;
+import java.util.Map;
+import java.util.regex.Matcher;
+import java.util.regex.Pattern;
+
+/**
+ * Constructs Uris from inputs.
+ */
+public class UriBuilder {
+  private static final Pattern QUERY_PATTERN = Pattern.compile("([^&=]+)=([^&=]*)");
+
+  private String scheme;
+  private String authority;
+  private String path;
+  private Multimap<String, String> query;
+  private String fragment;
+
+  /**
+   * Construct a new builder from an existing uri.
+   */
+  public UriBuilder(Uri uri) {
+    scheme = uri.getScheme();
+    authority = uri.getAuthority();
+    path = uri.getPath();
+    query = Multimaps.newLinkedListMultimap(uri.getQueryParameters());
+    fragment = uri.getFragment();
+  }
+
+  /**
+   * Create an empty builder.
+   */
+  public UriBuilder() {
+    query = Multimaps.newLinkedListMultimap();
+  }
+
+  /**
+   * Construct a builder by parsing a string.
+   */
+  public static UriBuilder parse(String text) {
+    return new UriBuilder(Uri.parse(text));
+  }
+
+  /**
+   * Convert the builder to a Uri.
+   */
+  public Uri toUri() {
+    return new Uri(scheme, authority, path, query, fragment);
+  }
+
+  /**
+   * @return The scheme part of the uri, or null if none was specified.
+   */
+  public String getScheme() {
+    return scheme;
+  }
+
+  public UriBuilder setScheme(String scheme) {
+    this.scheme = scheme;
+    return this;
+  }
+
+  /**
+   * @return The authority part of the uri, or null if none was specified.
+   */
+  public String getAuthority() {
+    return authority;
+  }
+
+  public UriBuilder setAuthority(String authority) {
+    this.authority = authority;
+    return this;
+  }
+
+  /**
+   * @return The path part of the uri, or null if none was specified.
+   */
+  public String getPath() {
+    return path;
+  }
+
+  public UriBuilder setPath(String path) {
+    this.path = path;
+    return this;
+  }
+
+  /**
+   * @return The query part of the uri, or null if none was specified.
+   */
+  public String getQuery() {
+    return joinParameters(query);
+  }
+
+  public UriBuilder setQuery(String query) {
+    this.query.clear();
+    this.query.putAll(splitParameters(query));
+    return this;
+  }
+
+  public UriBuilder addQueryParameter(String name, String value) {
+    query.put(name, value);
+    return this;
+  }
+
+  public UriBuilder addQueryParameters(Map<String, String> parameters) {
+    for (Map.Entry<String, String> entry : parameters.entrySet()) {
+      query.put(entry.getKey(), entry.getValue());
+    }
+    return this;
+  }
+
+  /**
+   * @return The query part of the uri, separated into component parts.
+   */
+  public Multimap<String, String> getQueryParameters() {
+    return query;
+  }
+
+  /**
+   * @return All query parameters with the given name.
+   */
+  public Collection<String> getQueryParameters(String name) {
+    return query.get(name);
+  }
+
+  /**
+   * @return The first query parameter value with the given name.
+   */
+  public String getQueryParameter(String name) {
+    Collection<String> values = query.get(name);
+    if (values == null || values.isEmpty()) {
+      return null;
+    }
+    return values.iterator().next();
+  }
+
+  /**
+   * @return The query fragment.
+   */
+  public String getFragment() {
+    return fragment;
+  }
+
+  public UriBuilder setFragment(String fragment) {
+    this.fragment = fragment;
+    return this;
+  }
+
+  /**
+   * Utility method for joining key / value pair parameters into a string.
+   */
+  static String joinParameters(Multimap<String, String> query) {
+    if (query.size() == 0) {
+      return null;
+    }
+    StringBuilder buf = new StringBuilder();
+    boolean firstDone = false;
+    for (Map.Entry<String, String> entry : query.entries()) {
+      if (firstDone) {
+        buf.append("&");
+      }
+      firstDone = true;
+      buf.append(Utf8UrlCoder.encode(entry.getKey()))
+         .append("=")
+         .append(Utf8UrlCoder.encode(entry.getValue()));
+    }
+    return buf.toString();
+  }
+
+  static Multimap<String, String> splitParameters(String query) {
+    if (query == null) {
+      return Multimaps.immutableMultimap();
+    }
+    Multimap<String, String> params = Multimaps.newLinkedListMultimap();
+    Matcher paramMatcher = QUERY_PATTERN.matcher(query);
+    while (paramMatcher.find()) {
+      params.put(Utf8UrlCoder.decode(paramMatcher.group(1)),
+                 Utf8UrlCoder.decode(paramMatcher.group(2)));
+    }
+    return Multimaps.unmodifiableMultimap(params);
+  }
+
+  @Override
+  public String toString() {
+    return toUri().toString();
+  }
+
+  @Override
+  public int hashCode() {
+    return toUri().hashCode();
+  }
+
+  @Override
+  public boolean equals(Object rhs) {
+    if (rhs == this) {return true;}
+    if (!(rhs instanceof UriBuilder)) {return false;}
+
+    return toString().equals(rhs.toString());
+  }
+}

Added: incubator/shindig/trunk/java/common/src/test/java/org/apache/shindig/common/uri/UriBuilderTest.java
URL: http://svn.apache.org/viewvc/incubator/shindig/trunk/java/common/src/test/java/org/apache/shindig/common/uri/UriBuilderTest.java?rev=686334&view=auto
==============================================================================
--- incubator/shindig/trunk/java/common/src/test/java/org/apache/shindig/common/uri/UriBuilderTest.java (added)
+++ incubator/shindig/trunk/java/common/src/test/java/org/apache/shindig/common/uri/UriBuilderTest.java Fri Aug 15 12:24:01 2008
@@ -0,0 +1,283 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements.  See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership.  The ASF licenses this file
+ * to you 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://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.apache.shindig.common.uri;
+
+import static org.junit.Assert.assertEquals;
+import static org.junit.Assert.assertFalse;
+import static org.junit.Assert.assertTrue;
+
+import com.google.common.collect.Maps;
+import com.google.common.collect.Multimap;
+
+import org.junit.Test;
+
+import java.util.Arrays;
+import java.util.Collection;
+
+/**
+ * Tests for UriBuilder
+ */
+public class UriBuilderTest {
+
+  @Test
+  public void allPartsUsed() {
+    UriBuilder builder = new UriBuilder()
+        .setScheme("http")
+        .setAuthority("apache.org")
+        .setPath("/shindig")
+        .setQuery("hello=world")
+        .setFragment("foo");
+    assertEquals("http://apache.org/shindig?hello=world#foo", builder.toString());
+  }
+
+  @Test
+  public void noSchemeUsed() {
+    UriBuilder builder = new UriBuilder()
+        .setAuthority("apache.org")
+        .setPath("/shindig")
+        .setQuery("hello=world")
+        .setFragment("foo");
+    assertEquals("//apache.org/shindig?hello=world#foo", builder.toString());
+  }
+
+  @Test
+  public void noAuthorityUsed() {
+    UriBuilder builder = new UriBuilder()
+        .setScheme("http")
+        .setPath("/shindig")
+        .setQuery("hello=world")
+        .setFragment("foo");
+    assertEquals("http:/shindig?hello=world#foo", builder.toString());
+  }
+
+  @Test
+  public void noPathUsed() {
+    UriBuilder builder = new UriBuilder()
+        .setScheme("http")
+        .setAuthority("apache.org")
+        .setQuery("hello=world")
+        .setFragment("foo");
+    assertEquals("http://apache.org?hello=world#foo", builder.toString());
+  }
+
+  @Test
+  public void noQueryUsed() {
+    UriBuilder builder = new UriBuilder()
+        .setScheme("http")
+        .setAuthority("apache.org")
+        .setPath("/shindig")
+        .setFragment("foo");
+    assertEquals("http://apache.org/shindig#foo", builder.toString());
+  }
+
+  @Test
+  public void noFragmentUsed() {
+    UriBuilder builder = new UriBuilder()
+        .setScheme("http")
+        .setAuthority("apache.org")
+        .setPath("/shindig")
+        .setQuery("hello=world");
+    assertEquals("http://apache.org/shindig?hello=world", builder.toString());
+  }
+
+  @Test
+  public void hostRelativePaths() {
+    UriBuilder builder = new UriBuilder()
+        .setPath("/shindig")
+        .setQuery("hello=world")
+        .setFragment("foo");
+    assertEquals("/shindig?hello=world#foo", builder.toString());
+  }
+
+  @Test
+  public void relativePaths() {
+    UriBuilder builder = new UriBuilder()
+        .setPath("foo")
+        .setQuery("hello=world")
+        .setFragment("foo");
+    assertEquals("foo?hello=world#foo", builder.toString());
+  }
+
+  @Test
+  public void noPathNoHostNoAuthority() {
+    UriBuilder builder = new UriBuilder()
+        .setQuery("hello=world")
+        .setFragment("foo");
+    assertEquals("?hello=world#foo", builder.toString());
+  }
+
+  @Test
+  public void justSchemeAndAuthority() {
+    UriBuilder builder = new UriBuilder()
+        .setScheme("http")
+        .setAuthority("apache.org");
+    assertEquals("http://apache.org", builder.toString());
+  }
+
+  @Test
+  public void justPath() {
+    UriBuilder builder = new UriBuilder()
+        .setPath("/shindig");
+    assertEquals("/shindig", builder.toString());
+  }
+
+  @Test
+  public void justAuthorityAndPath() {
+    UriBuilder builder = new UriBuilder()
+        .setAuthority("apache.org")
+        .setPath("/shindig");
+    assertEquals("//apache.org/shindig", builder.toString());
+  }
+
+  @Test
+  public void justQuery() {
+    UriBuilder builder = new UriBuilder()
+        .setQuery("hello=world");
+    assertEquals("?hello=world", builder.toString());
+  }
+
+  @Test
+  public void justFragment() {
+    UriBuilder builder = new UriBuilder()
+        .setFragment("foo");
+    assertEquals("#foo", builder.toString());
+  }
+
+  @Test
+  public void addSingleQueryParameter() {
+    UriBuilder builder = new UriBuilder()
+        .setScheme("http")
+        .setAuthority("apache.org")
+        .setPath("/shindig")
+        .addQueryParameter("hello", "world")
+        .setFragment("foo");
+    assertEquals("http://apache.org/shindig?hello=world#foo", builder.toString());
+  }
+
+  @Test
+  public void addTwoQueryParameters() {
+    UriBuilder builder = new UriBuilder()
+        .setScheme("http")
+        .setAuthority("apache.org")
+        .setPath("/shindig")
+        .addQueryParameter("hello", "world")
+        .addQueryParameter("foo", "bar")
+        .setFragment("foo");
+    assertEquals("http://apache.org/shindig?hello=world&foo=bar#foo", builder.toString());
+  }
+
+  @Test
+  public void addIdenticalParameters() {
+    UriBuilder builder = new UriBuilder()
+        .setScheme("http")
+        .setAuthority("apache.org")
+        .setPath("/shindig")
+        .addQueryParameter("hello", "world")
+        .addQueryParameter("hello", "goodbye")
+        .setFragment("foo");
+    assertEquals("http://apache.org/shindig?hello=world&hello=goodbye#foo", builder.toString());
+  }
+
+  @Test
+  public void addBatchParameters() {
+    UriBuilder builder = new UriBuilder()
+        .setScheme("http")
+        .setAuthority("apache.org")
+        .setPath("/shindig")
+        .addQueryParameters(Maps.immutableMap("foo", "bar", "hello", "world"))
+        .setFragment("foo");
+    assertEquals("http://apache.org/shindig?foo=bar&hello=world#foo", builder.toString());
+  }
+
+  @Test
+  public void queryStringIsUnescaped() {
+    UriBuilder builder = new UriBuilder()
+        .setScheme("http")
+        .setAuthority("apache.org")
+        .setPath("/shindig")
+        .setQuery("hello+world=world%26bar");
+    assertEquals("world&bar", builder.getQueryParameter("hello world"));
+  }
+
+  @Test
+  public void queryParamsAreEscaped() {
+    UriBuilder builder = new UriBuilder()
+        .setScheme("http")
+        .setAuthority("apache.org")
+        .setPath("/shindig")
+        .addQueryParameter("hello world", "foo&bar")
+        .setFragment("foo");
+    assertEquals("http://apache.org/shindig?hello+world=foo%26bar#foo", builder.toString());
+  }
+
+  @Test
+  public void parse() {
+    UriBuilder builder = UriBuilder.parse("http://apache.org/shindig?foo=bar%26baz&foo=three#blah");
+
+    assertEquals("http", builder.getScheme());
+    assertEquals("apache.org", builder.getAuthority());
+    assertEquals("/shindig", builder.getPath());
+    assertEquals("foo=bar%26baz&foo=three", builder.getQuery());
+    assertEquals("blah", builder.getFragment());
+
+    assertEquals("bar&baz", builder.getQueryParameter("foo"));
+
+    Collection<String> values = Arrays.asList("bar&baz", "three");
+    assertEquals(values, builder.getQueryParameters("foo"));
+
+    assertEquals(2, builder.getQueryParameters().size());
+  }
+
+  @Test
+  public void constructFromUriAndBack() {
+    Uri uri = Uri.parse("http://apache.org/foo/bar?foo=bar#foo");
+    UriBuilder builder = new UriBuilder(uri);
+
+    assertEquals(uri, builder.toUri());
+  }
+
+  @Test
+  public void constructFromUriAndModify() {
+    Uri uri = Uri.parse("http://apache.org/foo/bar?foo=bar#foo");
+    UriBuilder builder = new UriBuilder(uri);
+
+    builder.setAuthority("example.org");
+    builder.addQueryParameter("bar", "foo");
+
+    assertEquals("http://example.org/foo/bar?foo=bar&bar=foo#foo", builder.toString());
+  }
+
+  @Test
+  public void equalsAndHashCodeOk() {
+    UriBuilder uri = UriBuilder.parse("http://example.org/foo/bar/baz?blah=blah#boo");
+    Multimap<String, String> params = UriBuilder.splitParameters("blah=blah");
+    UriBuilder uri2 = new UriBuilder(Uri.parse("http://example.org/foo/bar/baz?blah=blah#boo"));
+
+    assertTrue(uri.equals(uri2));
+    assertTrue(uri2.equals(uri));
+
+    assertTrue(uri.equals(uri));
+
+    assertFalse(uri.equals(null));
+    assertFalse(uri.equals("http://example.org/foo/bar/baz?blah=blah#boo"));
+    assertFalse(uri.equals(Uri.parse("http://example.org/foo/bar/baz?blah=blah#boo")));
+
+    assertTrue(uri.hashCode() == uri2.hashCode());
+  }
+}

Added: incubator/shindig/trunk/java/common/src/test/java/org/apache/shindig/common/uri/UriTest.java
URL: http://svn.apache.org/viewvc/incubator/shindig/trunk/java/common/src/test/java/org/apache/shindig/common/uri/UriTest.java?rev=686334&view=auto
==============================================================================
--- incubator/shindig/trunk/java/common/src/test/java/org/apache/shindig/common/uri/UriTest.java (added)
+++ incubator/shindig/trunk/java/common/src/test/java/org/apache/shindig/common/uri/UriTest.java Fri Aug 15 12:24:01 2008
@@ -0,0 +1,164 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements.  See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership.  The ASF licenses this file
+ * to you 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://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.apache.shindig.common.uri;
+
+import static org.junit.Assert.assertEquals;
+import static org.junit.Assert.assertFalse;
+import static org.junit.Assert.assertTrue;
+
+import com.google.common.collect.Multimap;
+
+import org.junit.Test;
+
+import java.net.URI;
+import java.net.URISyntaxException;
+import java.util.Arrays;
+import java.util.Collection;
+
+/**
+ * Tests for Uri.
+ */
+public class UriTest {
+  @Test
+  public void parseFull() {
+    Uri uri = Uri.parse("http://apache.org/foo?a=b&a=c&b=d+e#blah");
+
+    assertEquals("http", uri.getScheme());
+    assertEquals("apache.org", uri.getAuthority());
+    assertEquals("/foo", uri.getPath());
+    assertEquals("a=b&a=c&b=d+e", uri.getQuery());
+    Collection<String> params = Arrays.asList("b", "c");
+    assertEquals(params, uri.getQueryParameters("a"));
+    assertEquals("b", uri.getQueryParameter("a"));
+    assertEquals("d e", uri.getQueryParameter("b"));
+    assertEquals("blah", uri.getFragment());
+
+    assertEquals("http://apache.org/foo?a=b&a=c&b=d+e#blah", uri.toString());
+  }
+
+  @Test
+  public void parseNoScheme() {
+    Uri uri = Uri.parse("//apache.org/foo?a=b&a=c&b=d+e#blah");
+
+    assertEquals(null, uri.getScheme());
+    assertEquals("apache.org", uri.getAuthority());
+    assertEquals("/foo", uri.getPath());
+    assertEquals("a=b&a=c&b=d+e", uri.getQuery());
+    Collection<String> params = Arrays.asList("b", "c");
+    assertEquals(params, uri.getQueryParameters("a"));
+    assertEquals("b", uri.getQueryParameter("a"));
+    assertEquals("d e", uri.getQueryParameter("b"));
+    assertEquals("blah", uri.getFragment());
+  }
+
+  @Test
+  public void parseNoAuthority() {
+    Uri uri = Uri.parse("http:/foo?a=b&a=c&b=d+e#blah");
+
+    assertEquals("http", uri.getScheme());
+    assertEquals(null, uri.getAuthority());
+    assertEquals("/foo", uri.getPath());
+    assertEquals("a=b&a=c&b=d+e", uri.getQuery());
+    Collection<String> params = Arrays.asList("b", "c");
+    assertEquals(params, uri.getQueryParameters("a"));
+    assertEquals("b", uri.getQueryParameter("a"));
+    assertEquals("d e", uri.getQueryParameter("b"));
+    assertEquals("blah", uri.getFragment());
+  }
+
+  @Test
+  public void parseNoPath() {
+    Uri uri = Uri.parse("http://apache.org?a=b&a=c&b=d+e#blah");
+
+    assertEquals("http", uri.getScheme());
+    assertEquals("apache.org", uri.getAuthority());
+    // Path is never null.
+    assertEquals("", uri.getPath());
+    assertEquals("a=b&a=c&b=d+e", uri.getQuery());
+    Collection<String> params = Arrays.asList("b", "c");
+    assertEquals(params, uri.getQueryParameters("a"));
+    assertEquals("b", uri.getQueryParameter("a"));
+    assertEquals("d e", uri.getQueryParameter("b"));
+    assertEquals("blah", uri.getFragment());
+  }
+
+  @Test
+  public void parseNoQuery() {
+    Uri uri = Uri.parse("http://apache.org/foo#blah");
+
+    assertEquals("http", uri.getScheme());
+    assertEquals("apache.org", uri.getAuthority());
+    assertEquals("/foo", uri.getPath());
+    assertEquals(null, uri.getQuery());
+    assertEquals(0, uri.getQueryParameters().size());
+    assertEquals(null, uri.getQueryParameter("foo"));
+    assertEquals("blah", uri.getFragment());
+  }
+
+  @Test
+  public void parseNoFragment() {
+    Uri uri = Uri.parse("http://apache.org/foo?a=b&a=c&b=d+e");
+
+    assertEquals("http", uri.getScheme());
+    assertEquals("apache.org", uri.getAuthority());
+    assertEquals("/foo", uri.getPath());
+    assertEquals("a=b&a=c&b=d+e", uri.getQuery());
+    assertEquals(null, uri.getFragment());
+  }
+
+  @Test(expected = IllegalArgumentException.class)
+  public void parseInvalidHost() {
+    Uri.parse("http://A&E%#%#%/foo?a=b#blah");
+  }
+
+  @Test(expected = IllegalArgumentException.class)
+  public void parseInvalidScheme() {
+    Uri.parse("----://apache.org/foo?a=b#blah");
+  }
+
+  @Test(expected = IllegalArgumentException.class)
+  public void parseInvalidPath() {
+    Uri.parse("http://apache.org/foo\\---(&%?a=b#blah");
+  }
+
+  @Test
+  public void toJavaUri() throws URISyntaxException {
+    URI javaUri = URI.create("http://example.org/foo/bar/baz?blah=blah#boo");
+    Uri uri = Uri.parse("http://example.org/foo/bar/baz?blah=blah#boo");
+
+    assertEquals(javaUri, uri.toJavaUri());
+  }
+
+  @Test
+  public void equalsAndHashCodeOk() {
+    Uri uri = Uri.parse("http://example.org/foo/bar/baz?blah=blah#boo");
+    Multimap<String, String> params = UriBuilder.splitParameters("blah=blah");
+    Uri uri2 = new Uri("http", "example.org", "/foo/bar/baz", params, "boo");
+
+    assertTrue(uri.equals(uri2));
+    assertTrue(uri2.equals(uri));
+
+    assertTrue(uri.equals(uri));
+
+    assertFalse(uri.equals(null));
+    assertFalse(uri.equals("http://example.org/foo/bar/baz?blah=blah#boo"));
+
+    assertTrue(uri.hashCode() == uri2.hashCode());
+  }
+}