View Javadoc
1   /* 
2    * Licensed under the Apache License, Version 2.0 (the "License");
3    * you may not use this file except in compliance with the License.
4    * You may obtain a copy of the License at
5    *
6    * http://www.apache.org/licenses/LICENSE-2.0
7    *
8    * Unless required by applicable law or agreed to in writing, software
9    * distributed under the License is distributed on an "AS IS" BASIS,
10   * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
11   * See the License for the specific language governing permissions and
12   * limitations under the License.
13   *
14   */
15  package org.esigate.impl;
16  
17  import java.util.regex.Matcher;
18  import java.util.regex.Pattern;
19  
20  import org.apache.commons.lang3.StringUtils;
21  import org.apache.commons.lang3.builder.ToStringBuilder;
22  import org.esigate.ConfigurationException;
23  
24  /**
25   * UriMapping holds provider mapping definition.
26   * 
27   * <p>
28   * Mappings are based on (all optional) :
29   * <ul>
30   * <li>A Scheme, host and port</li>
31   * <li>a starting path</li>
32   * <li>an extension</li>
33   * </ul>
34   * <p>
35   * Default (all values set to null) mappings are allowed.
36   * 
37   * @author Francois-Xavier Bonnet
38   * @author Nicolas Richeton
39   * 
40   */
41  public final class UriMapping {
42      private static final Pattern MAPPING_PATTERN = Pattern
43              .compile("((http://|https://)[^/:]*(:([0-9]*))?)?(/[^*]*)?(\\*?)([^*]*)");
44      private final String host;
45      private final String path;
46      private final String extension;
47      private final int weight;
48  
49      /**
50       * Creates UriMapping object and compute its weight.
51       * 
52       * @param host
53       * @param path
54       * @param extension
55       */
56      private UriMapping(String host, String path, String extension) {
57          this.host = host;
58          this.path = path;
59          this.extension = extension;
60          int targetWeight = 0;
61          if (this.host != null) {
62              targetWeight += 1000;
63          }
64          if (this.path != null) {
65              targetWeight += this.path.length() * 10;
66          }
67          if (this.extension != null) {
68              targetWeight += this.extension.length();
69          }
70          this.weight = targetWeight;
71      }
72  
73      /**
74       * Creates a UriMapping instance based on the mapping definition given as parameter.
75       * <p>
76       * Mapping is split in 3 parts :
77       * <ul>
78       * <li>Host, including the scheme and port : http://www.example:8080</li>;
79       * <li>path, left part before the wildcard caracter *</li>
80       * <li>extension, right part after the wildcard caracter *</li>
81       * </ul>
82       * 
83       * @param mapping
84       *            the mapping expression as string
85       * @return the uri mapping object
86       * @throws ConfigurationException
87       */
88      public static UriMapping create(String mapping) {
89          Matcher matcher = MAPPING_PATTERN.matcher(mapping);
90          if (!matcher.matches()) {
91              throw new ConfigurationException("Unrecognized URI pattern: " + mapping);
92          }
93          String host = StringUtils.trimToNull(matcher.group(1));
94          String path = StringUtils.trimToNull(matcher.group(5));
95  
96          if (path != null && !path.startsWith("/")) {
97              throw new ConfigurationException("Unrecognized URI pattern: " + mapping
98                      + " Mapping path should start with / was: " + path);
99          }
100         String extension = StringUtils.trimToNull(matcher.group(7));
101         if (extension != null && !extension.startsWith(".")) {
102             throw new ConfigurationException("Unrecognized URI pattern: " + mapping
103                     + " Mapping extension should start with . was: " + extension);
104         }
105         return new UriMapping(host, path, extension);
106     }
107 
108     /**
109      * Check this matching rule against a request.
110      * 
111      * @param schemeParam
112      * @param hostParam
113      * @param uriParam
114      * @return true if the rule matches the request
115      */
116     public boolean matches(String schemeParam, String hostParam, String uriParam) {
117         // If URI mapping enforce a host, ensure it is the one used.
118         if (this.host != null && !this.host.equalsIgnoreCase(schemeParam + "://" + hostParam)) {
119             return false;
120         }
121 
122         if (this.extension != null && !uriParam.endsWith(this.extension)) {
123             return false;
124         }
125 
126         if (this.path != null && !uriParam.startsWith(this.path)) {
127             return false;
128         }
129         return true;
130     }
131 
132     /**
133      * The weight of this URI matching. Larger weights must be evaluated first.
134      * 
135      * @return the weight
136      */
137     public int getWeight() {
138         return this.weight;
139     }
140 
141     /**
142      * Get the extension of this URI matching.
143      * 
144      * @return the extension
145      */
146     public String getExtension() {
147         return this.extension;
148     }
149 
150     /**
151      * Get the path of this URI matching.
152      * 
153      * @return the path
154      */
155     public String getPath() {
156         return this.path;
157     }
158 
159     /**
160      * Get the host of this URI matching.
161      * 
162      * @return the host
163      */
164     public String getHost() {
165         return this.host;
166     }
167 
168     @Override
169     public String toString() {
170         return ToStringBuilder.reflectionToString(this);
171     }
172 }