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.http.protocol;
29  
30  import java.util.HashMap;
31  import java.util.Iterator;
32  import java.util.Map;
33  
34  import org.apache.http.annotation.GuardedBy;
35  import org.apache.http.annotation.ThreadSafe;
36  
37  /**
38   * Maintains a map of objects keyed by a request URI pattern.
39   * <br>
40   * Patterns may have three formats:
41   * <ul>
42   *   <li><code>*</code></li>
43   *   <li><code>*&lt;uri&gt;</code></li>
44   *   <li><code>&lt;uri&gt;*</code></li>
45   * </ul>
46   * <br>
47   * This class can be used to resolve an object matching a particular request
48   * URI.
49   *
50   * @since 4.0
51   */
52  @ThreadSafe
53  public class UriPatternMatcher<T> {
54  
55      @GuardedBy("this")
56      private final Map<String, T> map;
57  
58      public UriPatternMatcher() {
59          super();
60          this.map = new HashMap<String, T>();
61      }
62  
63      /**
64       * Registers the given object for URIs matching the given pattern.
65       *
66       * @param pattern the pattern to register the handler for.
67       * @param obj the object.
68       */
69      public synchronized void register(final String pattern, final T obj) {
70          if (pattern == null) {
71              throw new IllegalArgumentException("URI request pattern may not be null");
72          }
73          this.map.put(pattern, obj);
74      }
75  
76      /**
77       * Removes registered object, if exists, for the given pattern.
78       *
79       * @param pattern the pattern to unregister.
80       */
81      public synchronized void unregister(final String pattern) {
82          if (pattern == null) {
83              return;
84          }
85          this.map.remove(pattern);
86      }
87  
88      /**
89       * @deprecated (4.1) use {@link #setObjects(Map)}
90       */
91      @Deprecated
92      public synchronized void setHandlers(final Map<String, T> map) {
93          if (map == null) {
94              throw new IllegalArgumentException("Map of handlers may not be null");
95          }
96          this.map.clear();
97          this.map.putAll(map);
98      }
99  
100     /**
101      * Sets objects from the given map.
102      * @param map the map containing objects keyed by their URI patterns.
103      */
104     public synchronized void setObjects(final Map<String, T> map) {
105         if (map == null) {
106             throw new IllegalArgumentException("Map of handlers may not be null");
107         }
108         this.map.clear();
109         this.map.putAll(map);
110     }
111 
112     /**
113      * Returns the objects map.
114      * @return The map of objects.
115      *
116      * @since 4.2
117      */
118     public synchronized Map<String, T> getObjects() {
119         return this.map;
120     }
121 
122     /**
123      * Looks up an object matching the given request URI.
124      *
125      * @param requestURI the request URI
126      * @return object or <code>null</code> if no match is found.
127      */
128     public synchronized T lookup(String requestURI) {
129         if (requestURI == null) {
130             throw new IllegalArgumentException("Request URI may not be null");
131         }
132         //Strip away the query part part if found
133         int index = requestURI.indexOf("?");
134         if (index != -1) {
135             requestURI = requestURI.substring(0, index);
136         }
137 
138         // direct match?
139         T obj = this.map.get(requestURI);
140         if (obj == null) {
141             // pattern match?
142             String bestMatch = null;
143             for (Iterator<String> it = this.map.keySet().iterator(); it.hasNext();) {
144                 String pattern = it.next();
145                 if (matchUriRequestPattern(pattern, requestURI)) {
146                     // we have a match. is it any better?
147                     if (bestMatch == null
148                             || (bestMatch.length() < pattern.length())
149                             || (bestMatch.length() == pattern.length() && pattern.endsWith("*"))) {
150                         obj = this.map.get(pattern);
151                         bestMatch = pattern;
152                     }
153                 }
154             }
155         }
156         return obj;
157     }
158 
159     /**
160      * Tests if the given request URI matches the given pattern.
161      *
162      * @param pattern the pattern
163      * @param requestUri the request URI
164      * @return <code>true</code> if the request URI matches the pattern,
165      *   <code>false</code> otherwise.
166      */
167     protected boolean matchUriRequestPattern(final String pattern, final String requestUri) {
168         if (pattern.equals("*")) {
169             return true;
170         } else {
171             return
172             (pattern.endsWith("*") && requestUri.startsWith(pattern.substring(0, pattern.length() - 1))) ||
173             (pattern.startsWith("*") && requestUri.endsWith(pattern.substring(1, pattern.length())));
174         }
175     }
176 
177 }