You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@hc.apache.org by gg...@apache.org on 2017/04/18 05:45:40 UTC
svn commit: r1791744 - in /httpcomponents/httpcore/trunk/httpcore5/src:
main/java/org/apache/hc/core5/http/protocol/
test/java/org/apache/hc/core5/http/protocol/
Author: ggregory
Date: Tue Apr 18 05:45:40 2017
New Revision: 1791744
URL: http://svn.apache.org/viewvc?rev=1791744&view=rev
Log:
[HTTPCORE-452] Add a UriRegexMatcher. Add the new class. Make the current UriPatternMatcher implement the new interface LookupRegistry (whose methods where pulled up from UriPatternMatcher.)
Added:
httpcomponents/httpcore/trunk/httpcore5/src/main/java/org/apache/hc/core5/http/protocol/LookupRegistry.java
httpcomponents/httpcore/trunk/httpcore5/src/main/java/org/apache/hc/core5/http/protocol/UriRegexMatcher.java
httpcomponents/httpcore/trunk/httpcore5/src/test/java/org/apache/hc/core5/http/protocol/TestUriRegexMatcher.java
Modified:
httpcomponents/httpcore/trunk/httpcore5/src/main/java/org/apache/hc/core5/http/protocol/UriPatternMatcher.java
httpcomponents/httpcore/trunk/httpcore5/src/test/java/org/apache/hc/core5/http/protocol/TestUriPatternMatcher.java
Added: httpcomponents/httpcore/trunk/httpcore5/src/main/java/org/apache/hc/core5/http/protocol/LookupRegistry.java
URL: http://svn.apache.org/viewvc/httpcomponents/httpcore/trunk/httpcore5/src/main/java/org/apache/hc/core5/http/protocol/LookupRegistry.java?rev=1791744&view=auto
==============================================================================
--- httpcomponents/httpcore/trunk/httpcore5/src/main/java/org/apache/hc/core5/http/protocol/LookupRegistry.java (added)
+++ httpcomponents/httpcore/trunk/httpcore5/src/main/java/org/apache/hc/core5/http/protocol/LookupRegistry.java Tue Apr 18 05:45:40 2017
@@ -0,0 +1,59 @@
+/*
+ * ====================================================================
+ * 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.
+ * ====================================================================
+ *
+ * This software consists of voluntary contributions made by many
+ * individuals on behalf of the Apache Software Foundation. For more
+ * information on the Apache Software Foundation, please see
+ * <http://www.apache.org/>.
+ *
+ */
+package org.apache.hc.core5.http.protocol;
+
+/**
+ * A lookup registry.
+ *
+ * @param <T> The type of objects to register and lookup.
+ */
+public interface LookupRegistry<T> {
+
+ /**
+ * Registers the given object for URIs matching the given pattern.
+ *
+ * @param pattern the pattern to register the handler for.
+ * @param obj the object.
+ */
+ void register(String pattern, T obj);
+
+ /**
+ * Looks up an object matching the given request path.
+ *
+ * @param path the request path
+ * @return object or {@code null} if no match is found.
+ */
+ T lookup(String string);
+
+ /**
+ * Removes registered object, if exists, for the given pattern.
+ *
+ * @param pattern the pattern to unregister.
+ */
+ void unregister(String pattern);
+
+}
Modified: httpcomponents/httpcore/trunk/httpcore5/src/main/java/org/apache/hc/core5/http/protocol/UriPatternMatcher.java
URL: http://svn.apache.org/viewvc/httpcomponents/httpcore/trunk/httpcore5/src/main/java/org/apache/hc/core5/http/protocol/UriPatternMatcher.java?rev=1791744&r1=1791743&r2=1791744&view=diff
==============================================================================
--- httpcomponents/httpcore/trunk/httpcore5/src/main/java/org/apache/hc/core5/http/protocol/UriPatternMatcher.java (original)
+++ httpcomponents/httpcore/trunk/httpcore5/src/main/java/org/apache/hc/core5/http/protocol/UriPatternMatcher.java Tue Apr 18 05:45:40 2017
@@ -35,22 +35,20 @@ import org.apache.hc.core5.annotation.Th
import org.apache.hc.core5.util.Args;
/**
- * Maintains a map of objects keyed by a request URI pattern.
- * <br>
+ * Maintains a map of objects keyed by a request URI pattern. <br>
* Patterns may have three formats:
* <ul>
- * <li>{@code *}</li>
- * <li>{@code *<uri>}</li>
- * <li>{@code <uri>*}</li>
+ * <li>{@code *}</li>
+ * <li>{@code *<uri>}</li>
+ * <li>{@code <uri>*}</li>
* </ul>
* <br>
- * This class can be used to resolve an object matching a particular request
- * URI.
+ * This class can be used to resolve an object matching a particular request URI.
*
* @since 4.0
*/
@Contract(threading = ThreadingBehavior.SAFE)
-public class UriPatternMatcher<T> {
+public class UriPatternMatcher<T> implements LookupRegistry<T> {
private final Map<String, T> map;
@@ -62,9 +60,12 @@ public class UriPatternMatcher<T> {
/**
* Registers the given object for URIs matching the given pattern.
*
- * @param pattern the pattern to register the handler for.
- * @param obj the object.
+ * @param pattern
+ * the pattern to register the handler for.
+ * @param obj
+ * the object.
*/
+ @Override
public synchronized void register(final String pattern, final T obj) {
Args.notNull(pattern, "URI request pattern");
this.map.put(pattern, obj);
@@ -73,8 +74,10 @@ public class UriPatternMatcher<T> {
/**
* Removes registered object, if exists, for the given pattern.
*
- * @param pattern the pattern to unregister.
+ * @param pattern
+ * the pattern to unregister.
*/
+ @Override
public synchronized void unregister(final String pattern) {
if (pattern == null) {
return;
@@ -85,9 +88,11 @@ public class UriPatternMatcher<T> {
/**
* Looks up an object matching the given request path.
*
- * @param path the request path
+ * @param path
+ * the request path
* @return object or {@code null} if no match is found.
*/
+ @Override
public synchronized T lookup(final String path) {
Args.notNull(path, "Request path");
// direct match?
@@ -98,8 +103,7 @@ public class UriPatternMatcher<T> {
for (final String pattern : this.map.keySet()) {
if (matchUriRequestPattern(pattern, path)) {
// we have a match. is it any better?
- if (bestMatch == null
- || (bestMatch.length() < pattern.length())
+ if (bestMatch == null || (bestMatch.length() < pattern.length())
|| (bestMatch.length() == pattern.length() && pattern.endsWith("*"))) {
obj = this.map.get(pattern);
bestMatch = pattern;
@@ -113,18 +117,18 @@ public class UriPatternMatcher<T> {
/**
* Tests if the given request path matches the given pattern.
*
- * @param pattern the pattern
- * @param path the request path
- * @return {@code true} if the request URI matches the pattern,
- * {@code false} otherwise.
+ * @param pattern
+ * the pattern
+ * @param path
+ * the request path
+ * @return {@code true} if the request URI matches the pattern, {@code false} otherwise.
*/
protected boolean matchUriRequestPattern(final String pattern, final String path) {
if (pattern.equals("*")) {
return true;
}
- return
- (pattern.endsWith("*") && path.startsWith(pattern.substring(0, pattern.length() - 1))) ||
- (pattern.startsWith("*") && path.endsWith(pattern.substring(1, pattern.length())));
+ return (pattern.endsWith("*") && path.startsWith(pattern.substring(0, pattern.length() - 1)))
+ || (pattern.startsWith("*") && path.endsWith(pattern.substring(1, pattern.length())));
}
@Override
Added: httpcomponents/httpcore/trunk/httpcore5/src/main/java/org/apache/hc/core5/http/protocol/UriRegexMatcher.java
URL: http://svn.apache.org/viewvc/httpcomponents/httpcore/trunk/httpcore5/src/main/java/org/apache/hc/core5/http/protocol/UriRegexMatcher.java?rev=1791744&view=auto
==============================================================================
--- httpcomponents/httpcore/trunk/httpcore5/src/main/java/org/apache/hc/core5/http/protocol/UriRegexMatcher.java (added)
+++ httpcomponents/httpcore/trunk/httpcore5/src/main/java/org/apache/hc/core5/http/protocol/UriRegexMatcher.java Tue Apr 18 05:45:40 2017
@@ -0,0 +1,119 @@
+/*
+ * ====================================================================
+ * 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.
+ * ====================================================================
+ *
+ * This software consists of voluntary contributions made by many
+ * individuals on behalf of the Apache Software Foundation. For more
+ * information on the Apache Software Foundation, please see
+ * <http://www.apache.org/>.
+ *
+ */
+
+package org.apache.hc.core5.http.protocol;
+
+import java.util.LinkedHashMap;
+import java.util.Map;
+import java.util.Map.Entry;
+import java.util.regex.Pattern;
+
+import org.apache.hc.core5.annotation.Contract;
+import org.apache.hc.core5.annotation.ThreadingBehavior;
+import org.apache.hc.core5.util.Args;
+
+/**
+ * Maintains a map of objects keyed by a request URI regular expression.
+ *
+ * <p>
+ * The insertion order is in maintained in that map such that the lookup tests each regex until there is a match. This
+ * class can be used to resolve an object matching a particular request URI.
+ * </p>
+ *
+ * @since 5.0
+ */
+@Contract(threading = ThreadingBehavior.SAFE)
+public class UriRegexMatcher<T> implements LookupRegistry<T> {
+
+ private final Map<String, T> objectMap;
+ private final Map<String, Pattern> patternMap;
+
+ public UriRegexMatcher() {
+ super();
+ this.objectMap = new LinkedHashMap<>();
+ this.patternMap = new LinkedHashMap<>();
+ }
+
+ /**
+ * Registers the given object for URIs matching the given regex.
+ *
+ * @param regex
+ * the regex to register the handler for.
+ * @param obj
+ * the object.
+ */
+ @Override
+ public synchronized void register(final String regex, final T obj) {
+ Args.notNull(regex, "URI request regex");
+ this.objectMap.put(regex, obj);
+ this.patternMap.put(regex, Pattern.compile(regex));
+ }
+
+ /**
+ * Removes registered object, if exists, for the given regex.
+ *
+ * @param regex
+ * the regex to unregister.
+ */
+ @Override
+ public synchronized void unregister(final String regex) {
+ if (regex == null) {
+ return;
+ }
+ this.objectMap.remove(regex);
+ this.patternMap.remove(regex);
+ }
+
+ /**
+ * Looks up an object matching the given request path.
+ *
+ * @param path
+ * the request path
+ * @return object or {@code null} if no match is found.
+ */
+ @Override
+ public synchronized T lookup(final String path) {
+ Args.notNull(path, "Request path");
+ // direct match?
+ final T obj = this.objectMap.get(path);
+ if (obj == null) {
+ // regex match?
+ for (final Entry<String, Pattern> entry : this.patternMap.entrySet()) {
+ if (entry.getValue().matcher(path).matches()) {
+ return objectMap.get(entry.getKey());
+ }
+ }
+ }
+ return obj;
+ }
+
+ @Override
+ public String toString() {
+ return this.objectMap.toString();
+ }
+
+}
Modified: httpcomponents/httpcore/trunk/httpcore5/src/test/java/org/apache/hc/core5/http/protocol/TestUriPatternMatcher.java
URL: http://svn.apache.org/viewvc/httpcomponents/httpcore/trunk/httpcore5/src/test/java/org/apache/hc/core5/http/protocol/TestUriPatternMatcher.java?rev=1791744&r1=1791743&r2=1791744&view=diff
==============================================================================
--- httpcomponents/httpcore/trunk/httpcore5/src/test/java/org/apache/hc/core5/http/protocol/TestUriPatternMatcher.java (original)
+++ httpcomponents/httpcore/trunk/httpcore5/src/test/java/org/apache/hc/core5/http/protocol/TestUriPatternMatcher.java Tue Apr 18 05:45:40 2017
@@ -38,7 +38,7 @@ public class TestUriPatternMatcher {
final Object h2 = new Object();
final Object h3 = new Object();
- final UriPatternMatcher<Object> matcher = new UriPatternMatcher<>();
+ final LookupRegistry<Object> matcher = new UriPatternMatcher<>();
matcher.register("/h1", h1);
matcher.register("/h2", h2);
matcher.register("/h3", h3);
@@ -62,7 +62,7 @@ public class TestUriPatternMatcher {
@Test(expected=IllegalArgumentException.class)
public void testRegisterNull() throws Exception {
- final UriPatternMatcher<Object> matcher = new UriPatternMatcher<>();
+ final LookupRegistry<Object> matcher = new UriPatternMatcher<>();
matcher.register(null, null);
}
@@ -73,7 +73,7 @@ public class TestUriPatternMatcher {
final Object h3 = new Object();
final Object def = new Object();
- final UriPatternMatcher<Object> matcher = new UriPatternMatcher<>();
+ final LookupRegistry<Object> matcher = new UriPatternMatcher<>();
matcher.register("*", def);
matcher.register("/one/*", h1);
matcher.register("/one/two/*", h2);
@@ -104,7 +104,7 @@ public class TestUriPatternMatcher {
final Object h2 = new Object();
final Object def = new Object();
- final UriPatternMatcher<Object> matcher = new UriPatternMatcher<>();
+ final LookupRegistry<Object> matcher = new UriPatternMatcher<>();
matcher.register("*", def);
matcher.register("*.view", h1);
matcher.register("*.form", h2);
@@ -129,7 +129,7 @@ public class TestUriPatternMatcher {
final Object h1 = new Object();
final Object h2 = new Object();
- final UriPatternMatcher<Object> matcher = new UriPatternMatcher<>();
+ final LookupRegistry<Object> matcher = new UriPatternMatcher<>();
matcher.register("/ma*", h1);
matcher.register("*tch", h2);
@@ -140,13 +140,13 @@ public class TestUriPatternMatcher {
@Test(expected=IllegalArgumentException.class)
public void testRegisterInvalidInput() throws Exception {
- final UriPatternMatcher<Object> matcher = new UriPatternMatcher<>();
+ final LookupRegistry<Object> matcher = new UriPatternMatcher<>();
matcher.register(null, null);
}
@Test(expected=IllegalArgumentException.class)
public void testLookupInvalidInput() throws Exception {
- final UriPatternMatcher<Object> matcher = new UriPatternMatcher<>();
+ final LookupRegistry<Object> matcher = new UriPatternMatcher<>();
matcher.lookup(null);
}
Added: httpcomponents/httpcore/trunk/httpcore5/src/test/java/org/apache/hc/core5/http/protocol/TestUriRegexMatcher.java
URL: http://svn.apache.org/viewvc/httpcomponents/httpcore/trunk/httpcore5/src/test/java/org/apache/hc/core5/http/protocol/TestUriRegexMatcher.java?rev=1791744&view=auto
==============================================================================
--- httpcomponents/httpcore/trunk/httpcore5/src/test/java/org/apache/hc/core5/http/protocol/TestUriRegexMatcher.java (added)
+++ httpcomponents/httpcore/trunk/httpcore5/src/test/java/org/apache/hc/core5/http/protocol/TestUriRegexMatcher.java Tue Apr 18 05:45:40 2017
@@ -0,0 +1,211 @@
+/*
+ * ====================================================================
+ * 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.
+ * ====================================================================
+ *
+ * This software consists of voluntary contributions made by many
+ * individuals on behalf of the Apache Software Foundation. For more
+ * information on the Apache Software Foundation, please see
+ * <http://www.apache.org/>.
+ *
+ */
+
+package org.apache.hc.core5.http.protocol;
+
+import org.junit.Assert;
+import org.junit.Test;
+
+public class TestUriRegexMatcher {
+
+ @Test
+ public void testRegisterUnregister() throws Exception {
+ final Object h1 = new Object();
+ final Object h2 = new Object();
+ final Object h3 = new Object();
+
+ final LookupRegistry<Object> matcher = new UriRegexMatcher<>();
+ matcher.register("/h1", h1);
+ matcher.register("/h2", h2);
+ matcher.register("/h3", h3);
+
+ Object h;
+
+ h = matcher.lookup("/h1");
+ Assert.assertNotNull(h);
+ Assert.assertTrue(h1 == h);
+ h = matcher.lookup("/h2");
+ Assert.assertNotNull(h);
+ Assert.assertTrue(h2 == h);
+ h = matcher.lookup("/h3");
+ Assert.assertNotNull(h);
+ Assert.assertTrue(h3 == h);
+
+ matcher.unregister("/h1");
+ h = matcher.lookup("/h1");
+ Assert.assertNull(h);
+ }
+
+ @Test(expected = IllegalArgumentException.class)
+ public void testRegisterNull() throws Exception {
+ final LookupRegistry<Object> matcher = new UriRegexMatcher<>();
+ matcher.register(null, null);
+ }
+
+ @Test
+ public void testWildCardMatching1a() throws Exception {
+ final Object h1 = new Object();
+ final Object h2 = new Object();
+ final Object h3 = new Object();
+ final Object def = new Object();
+
+ final LookupRegistry<Object> matcher = new UriRegexMatcher<>();
+ matcher.register(".*", def);
+ matcher.register("/one/.*", h1);
+ matcher.register("/one/two/.*", h2);
+ matcher.register("/one/two/three/.*", h3);
+
+ Object h;
+
+ h = matcher.lookup("/one/request");
+ Assert.assertNotNull(h);
+ Assert.assertTrue(def == h);
+
+ h = matcher.lookup("/one/two/request");
+ Assert.assertNotNull(h);
+ Assert.assertTrue(def == h);
+
+ h = matcher.lookup("/one/two/three/request");
+ Assert.assertNotNull(h);
+ Assert.assertTrue(def == h);
+
+ h = matcher.lookup("default/request");
+ Assert.assertNotNull(h);
+ Assert.assertTrue(def == h);
+ }
+
+ @Test
+ public void testWildCardMatching1b() throws Exception {
+ final Object h1 = new Object();
+ final Object h2 = new Object();
+ final Object h3 = new Object();
+ final Object def = new Object();
+
+ final LookupRegistry<Object> matcher = new UriRegexMatcher<>();
+ matcher.register("/one/two/three/.*", h3);
+ matcher.register("/one/two/.*", h2);
+ matcher.register("/one/.*", h1);
+ matcher.register(".*", def);
+
+ Object h;
+
+ h = matcher.lookup("/one/request");
+ Assert.assertNotNull(h);
+ Assert.assertTrue(h1 == h);
+
+ h = matcher.lookup("/one/two/request");
+ Assert.assertNotNull(h);
+ Assert.assertTrue(h2 == h);
+
+ h = matcher.lookup("/one/two/three/request");
+ Assert.assertNotNull(h);
+ Assert.assertTrue(h3 == h);
+
+ h = matcher.lookup("default/request");
+ Assert.assertNotNull(h);
+ Assert.assertTrue(def == h);
+ }
+
+ @Test
+ public void testWildCardMatching2a() throws Exception {
+ final Object h1 = new Object();
+ final Object h2 = new Object();
+ final Object def = new Object();
+
+ final LookupRegistry<Object> matcher = new UriRegexMatcher<>();
+ matcher.register(".*", def);
+ matcher.register(".*\\.view", h1);
+ matcher.register(".*\\.form", h2);
+
+ Object h;
+
+ h = matcher.lookup("/that.view");
+ Assert.assertNotNull(h);
+ Assert.assertTrue(def == h);
+
+ h = matcher.lookup("/that.form");
+ Assert.assertNotNull(h);
+ Assert.assertTrue(def == h);
+
+ h = matcher.lookup("/whatever");
+ Assert.assertNotNull(h);
+ Assert.assertTrue(def == h);
+ }
+
+ @Test
+ public void testWildCardMatching2b() throws Exception {
+ final Object h1 = new Object();
+ final Object h2 = new Object();
+ final Object def = new Object();
+
+ final LookupRegistry<Object> matcher = new UriRegexMatcher<>();
+ matcher.register(".*\\.form", h2);
+ matcher.register(".*\\.view", h1);
+ matcher.register(".*", def);
+
+ Object h;
+
+ h = matcher.lookup("/that.view");
+ Assert.assertNotNull(h);
+ Assert.assertTrue(h1 == h);
+
+ h = matcher.lookup("/that.form");
+ Assert.assertNotNull(h);
+ Assert.assertTrue(h2 == h);
+
+ h = matcher.lookup("/whatever");
+ Assert.assertNotNull(h);
+ Assert.assertTrue(def == h);
+ }
+
+ @Test
+ public void testSuffixPatternOverPrefixPatternMatch() throws Exception {
+ final Object h1 = new Object();
+ final Object h2 = new Object();
+
+ final LookupRegistry<Object> matcher = new UriRegexMatcher<>();
+ matcher.register("/ma.*", h1);
+ matcher.register(".*tch", h2);
+
+ final Object h = matcher.lookup("/match");
+ Assert.assertNotNull(h);
+ Assert.assertTrue(h1 == h);
+ }
+
+ @Test(expected = IllegalArgumentException.class)
+ public void testRegisterInvalidInput() throws Exception {
+ final LookupRegistry<Object> matcher = new UriRegexMatcher<>();
+ matcher.register(null, null);
+ }
+
+ @Test(expected = IllegalArgumentException.class)
+ public void testLookupInvalidInput() throws Exception {
+ final LookupRegistry<Object> matcher = new UriRegexMatcher<>();
+ matcher.lookup(null);
+ }
+
+}