View Javadoc
1   /*
2    * ====================================================================
3    * Licensed to the Apache Software Foundation (ASF) under one
4    * or more contributor license agreements.  See the NOTICE file
5    * distributed with this work for additional information
6    * regarding copyright ownership.  The ASF licenses this file
7    * to you under the Apache License, Version 2.0 (the
8    * "License"); you may not use this file except in compliance
9    * with the License.  You may obtain a copy of the License at
10   *
11   *   http://www.apache.org/licenses/LICENSE-2.0
12   *
13   * Unless required by applicable law or agreed to in writing,
14   * software distributed under the License is distributed on an
15   * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
16   * KIND, either express or implied.  See the License for the
17   * specific language governing permissions and limitations
18   * under the License.
19   * ====================================================================
20   *
21   * This software consists of voluntary contributions made by many
22   * individuals on behalf of the Apache Software Foundation.  For more
23   * information on the Apache Software Foundation, please see
24   * <http://www.apache.org/>.
25   *
26   */
27  
28  package org.apache.hc.core5.http.protocol;
29  
30  import java.util.HashSet;
31  import java.util.LinkedHashMap;
32  import java.util.Map;
33  import java.util.Map.Entry;
34  import java.util.Set;
35  import java.util.concurrent.locks.ReentrantLock;
36  
37  import org.apache.hc.core5.annotation.Contract;
38  import org.apache.hc.core5.annotation.ThreadingBehavior;
39  import org.apache.hc.core5.http.impl.routing.PathPatternMatcher;
40  import org.apache.hc.core5.util.Args;
41  
42  /**
43   * Maintains a map of objects keyed by a request URI pattern.
44   * <p>
45   * Patterns may have three formats:
46   * </p>
47   * <ul>
48   * <li>{@code *}</li>
49   * <li>{@code *<uri>}</li>
50   * <li>{@code <uri>*}</li>
51   * </ul>
52   * <p>
53   * This class can be used to resolve an object matching a particular request
54   * URI.
55   * </p>
56   *
57   * @param <T> The type of registered objects.
58   * @since 4.0
59   *
60   * @deprecated Use {@link org.apache.hc.core5.http.impl.routing.RequestRouter} for
61   * request routing.
62   */
63  @Contract(threading = ThreadingBehavior.SAFE)
64  @Deprecated
65  public class UriPatternMatcher<T> implements LookupRegistry<T> {
66  
67      private final Map<String, T> map;
68  
69      private final ReentrantLock lock;
70  
71      public UriPatternMatcher() {
72          super();
73          this.map = new LinkedHashMap<>();
74          this.lock = new ReentrantLock();
75      }
76  
77      /**
78       * Returns a {@link Set} view of the mappings contained in this matcher.
79       *
80       * @return  a set view of the mappings contained in this matcher.
81       *
82       * @see Map#entrySet()
83       * @since 4.4.9
84       */
85      public Set<Entry<String, T>> entrySet() {
86          lock.lock();
87          try {
88              return new HashSet<>(map.entrySet());
89          } finally {
90              lock.unlock();
91          }
92      }
93  
94      /**
95       * Registers the given object for URIs matching the given pattern.
96       *
97       * @param pattern
98       *            the pattern to register the handler for.
99       * @param obj
100      *            the object.
101      */
102     @Override
103     public void register(final String pattern, final T obj) {
104         lock.lock();
105         try {
106             Args.notNull(pattern, "URI request pattern");
107             this.map.put(pattern, obj);
108         } finally {
109             lock.unlock();
110         }
111     }
112 
113     /**
114      * Removes registered object, if exists, for the given pattern.
115      *
116      * @param pattern
117      *            the pattern to unregister.
118      */
119     @Override
120     public void unregister(final String pattern) {
121         lock.lock();
122         try {
123             if (pattern == null) {
124                 return;
125             }
126             this.map.remove(pattern);
127         } finally {
128             lock.unlock();
129         }
130     }
131 
132     /**
133      * Looks up an object matching the given request path.
134      *
135      * @param path
136      *            the request path
137      * @return object or {@code null} if no match is found.
138      */
139     @Override
140     public T lookup(final String path) {
141         lock.lock();
142         try {
143             Args.notNull(path, "Request path");
144             // direct match?
145             T obj = this.map.get(path);
146             if (obj == null) {
147                 // pattern match?
148                 String bestMatch = null;
149                 for (final String pattern : this.map.keySet()) {
150                     if (matchUriRequestPattern(pattern, path)) {
151                         // we have a match. is it any better?
152                         if (bestMatch == null || (bestMatch.length() < pattern.length())
153                                 || (bestMatch.length() == pattern.length() && pattern.endsWith("*"))) {
154                             obj = this.map.get(pattern);
155                             bestMatch = pattern;
156                         }
157                     }
158                 }
159             }
160             return obj;
161         } finally {
162             lock.unlock();
163         }
164     }
165 
166     /**
167      * Tests if the given request path matches the given pattern.
168      *
169      * @param pattern
170      *            the pattern
171      * @param path
172      *            the request path
173      * @return {@code true} if the request URI matches the pattern, {@code false} otherwise.
174      */
175     protected boolean matchUriRequestPattern(final String pattern, final String path) {
176         return PathPatternMatcher.INSTANCE.match(pattern, path);
177     }
178 
179     @Override
180     public String toString() {
181         return this.map.toString();
182     }
183 
184 }