1 29 30 package com.caucho.server.dispatch; 31 32 import com.caucho.server.util.CauchoSystem; 33 import com.caucho.util.CharBuffer; 34 35 import javax.servlet.ServletException ; 36 import java.util.ArrayList ; 37 import java.util.regex.Matcher ; 38 import java.util.regex.Pattern ; 39 import java.util.regex.PatternSyntaxException ; 40 41 49 public class UrlMap<E> { 50 private ArrayList <RegexpEntry<E>> _regexps; 52 private boolean _bestShort; 54 55 58 public UrlMap() 59 { 60 _regexps = new ArrayList <RegexpEntry<E>>(); 61 } 62 63 68 public UrlMap(boolean bestShort) 69 { 70 _regexps = new ArrayList <RegexpEntry<E>>(); 71 _bestShort = bestShort; 72 } 73 74 80 void setBestShort(boolean bestShort) 81 { 82 _bestShort = bestShort; 83 } 84 85 int size() 86 { 87 return _regexps.size(); 88 } 89 90 public void addMap(String pattern, E value) 91 throws PatternSyntaxException 92 { 93 addMap(pattern, null, value); 94 } 95 96 102 public void addMap(String pattern, String flags, E value) 103 throws PatternSyntaxException 104 { 105 if (pattern.length() == 0 || 106 pattern.length() == 1 && pattern.charAt(0) == '/') { 107 addRegexp(-1, "", flags, value, true); 108 return; 109 } 110 111 else if (pattern.equals("/*")) { 112 addRegexp(1, "/*", "", flags, value, true); 113 return; 114 } 115 116 int length = pattern.length(); 117 boolean isExact = true; 118 119 if (pattern.charAt(0) != '/' && pattern.charAt(0) != '*') { 120 pattern = "/" + pattern; 121 length++; 122 } 123 124 int prefixLength = -1; 125 boolean isShort = false; 126 CharBuffer cb = new CharBuffer(); 127 cb.append("^"); 128 for (int i = 0; i < length; i++) { 129 char ch = pattern.charAt(i); 130 131 if (ch == '*' && i + 1 == length && i > 0) { 132 isExact = false; 133 134 if (pattern.charAt(i - 1) == '/') { 135 cb.setLength(cb.length() - 1); 136 137 if (prefixLength < 0) 138 prefixLength = i - 1; 139 140 } 141 else if (prefixLength < 0) 142 prefixLength = i; 143 144 if (prefixLength == 0) 145 prefixLength = 1; 146 } 147 else if (ch == '*') { 148 isExact = false; 149 cb.append(".*"); 150 if (prefixLength < 0) 151 prefixLength = i; 152 153 if (i == 0) 154 isShort = true; 155 } 156 else if (ch == '.' || ch == '[' || ch == '^' || ch == '$' || 157 ch == '{' || ch == '}' || ch == '|' || 158 ch == '(' || ch == ')' || ch == '?') { 159 cb.append('\\'); 160 cb.append(ch); 161 } 162 else 163 cb.append(ch); 164 } 165 166 if (isExact) 167 cb.append("$"); 168 else { 169 cb.append("(?=/)|" + cb.toString() + "\\z"); 170 } 171 172 if (prefixLength < 0) 173 prefixLength = pattern.length(); 174 else if (prefixLength < pattern.length() && 175 pattern.charAt(prefixLength) == '/') 176 prefixLength--; 177 178 if (cb.length() > 0 && cb.charAt(0) == '/') 179 cb.insert(0, '^'); 180 181 addRegexp(prefixLength, pattern, cb.close(), flags, value, isShort); 182 } 183 184 public static String urlPatternToRegexpPattern(String pattern) 185 { 186 if (pattern.length() == 0 || 187 pattern.length() == 1 && pattern.charAt(0) == '/') { 188 return "^.*$"; 189 } 190 191 else if (pattern.equals("/*")) 192 return "^.*$"; 193 194 int length = pattern.length(); 195 196 if (pattern.charAt(0) != '/' && pattern.charAt(0) != '*') { 197 pattern = "/" + pattern; 198 length++; 199 } 200 201 boolean isExact = true; 202 CharBuffer cb = new CharBuffer(); 203 cb.append("^"); 204 for (int i = 0; i < length; i++) { 205 char ch = pattern.charAt(i); 206 207 if (ch == '*' && i + 1 == length && i > 0) { 208 isExact = false; 209 210 if (pattern.charAt(i - 1) == '/') { 211 cb.setLength(cb.length() - 1); 212 } 213 } 214 else if (ch == '*') { 215 isExact = false; 216 cb.append(".*"); 217 } 218 else if (ch == '.' || ch == '[' || ch == '^' || ch == '$' || 219 ch == '{' || ch == '}' || ch == '|' || 220 ch == '(' || ch == ')' || ch == '?') { 221 cb.append('\\'); 222 cb.append(ch); 223 } 224 else 225 cb.append(ch); 226 } 227 228 if (isExact) 229 cb.append("\\z"); 230 else 231 cb.append("(?=/)|" + cb.toString() + "\\z"); 232 233 if (cb.length() > 0 && cb.charAt(0) == '/') 234 cb.insert(0, '^'); 235 236 return cb.close(); 237 } 238 239 245 public void addStrictMap(String pattern, String flags, 246 E value) 247 throws PatternSyntaxException , ServletException 248 { 249 if (pattern.length() == 0 || 250 pattern.length() == 1 && pattern.charAt(0) == '/') { 251 addRegexp(-1, "^.*$", flags, value, true); 252 return; 253 } 254 255 int length = pattern.length(); 256 boolean isExact = true; 257 258 if (pattern.charAt(0) != '/' && pattern.charAt(0) != '*') { 259 pattern = "/" + pattern; 260 length++; 261 } 262 263 if (pattern.indexOf('*') < pattern.lastIndexOf('*')) 264 throw new ServletException ("at most one '*' is allowed"); 265 266 int prefixLength = -1; 267 boolean isShort = false; 268 CharBuffer cb = new CharBuffer(); 269 cb.append('^'); 270 271 for (int i = 0; i < length; i++) { 272 char ch = pattern.charAt(i); 273 274 switch (ch) { 275 case '*': 276 if (i > 0 && i + 1 == length && pattern.charAt(i - 1) == '/') { 277 cb.append(".*"); 278 } 279 else if (i == 0 && length > 1 && pattern.charAt(1) == '.' && 280 pattern.lastIndexOf('/') < 0) { 281 cb.append(".*"); 282 } 283 else 284 throw new ServletException ("illegal url-pattern `" + pattern + "'"); 285 break; 286 287 case '.': case '[': case '^': case '$': 288 case '{': case '}': case '|': case '(': case '?': 289 cb.append('\\'); 290 cb.append(ch); 291 break; 292 293 default: 294 cb.append(ch); 295 } 296 } 297 298 cb.append("$"); 299 300 addRegexp(prefixLength, pattern, cb.close(), flags, value, isShort); 301 } 302 303 public void addRegexp(String regexp, String flags, E value) 304 throws PatternSyntaxException 305 { 306 addRegexp(0, regexp, flags, value, false); 307 } 308 309 public void addRegexp(String regexp, E value) 310 throws PatternSyntaxException 311 { 312 addRegexp(0, regexp, null, value, false); 313 } 314 315 324 public void addRegexp(int prefixLength, String regexp, 325 String flags, E value, boolean isShort) 326 throws PatternSyntaxException 327 { 328 RegexpEntry<E> entry 329 = new RegexpEntry<E>(prefixLength, regexp, flags, value); 330 331 for (int i = 0; i < _regexps.size(); i++) { 332 RegexpEntry<E> re = _regexps.get(i); 333 334 if (re.equals(entry)) { 335 _regexps.remove(i); 336 break; 337 } 338 } 339 340 if (isShort) 341 entry.setShortMatch(); 342 343 _regexps.add(entry); 344 } 345 346 356 public void addRegexp(int prefixLength, String pattern, 357 String regexp, String flags, 358 E value, boolean isShort) 359 throws PatternSyntaxException 360 { 361 RegexpEntry<E> entry 362 = new RegexpEntry<E>(prefixLength, pattern, regexp, flags, value); 363 364 for (int i = _regexps.size() - 1; i >= 0; i--) { 365 RegexpEntry<E> re = _regexps.get(i); 366 367 if (re.equals(entry)) { 368 _regexps.remove(i); 369 } 370 } 371 372 if (isShort) 373 entry.setShortMatch(); 374 375 _regexps.add(entry); 376 } 377 378 386 public E map(String uri) 387 { 388 return map(uri, null); 389 } 390 391 400 public E map(String uri, ArrayList <String > vars) 401 { 402 E best = null; 403 404 if (vars != null) 405 vars.add(uri); 406 407 int bestPrefixLength = -2; 408 int bestMinLength = -2; 409 int bestMaxLength = Integer.MAX_VALUE; 410 411 for (int i = 0; i < _regexps.size(); i++) { 412 RegexpEntry<E> entry = _regexps.get(i); 413 414 if ("plugin_match".equals(entry._value) || 415 "plugin-match".equals(entry._value)) 416 continue; 417 if ("plugin_ignore".equals(entry._value) || 418 "plugin-ignore".equals(entry._value)) 419 continue; 420 if (entry._prefixLength < bestPrefixLength) 421 continue; 422 423 Matcher matcher = entry._regexp.matcher(uri); 424 425 if (! matcher.find()) 426 continue; 427 428 int begin = matcher.start(); 429 int end = matcher.end(); 430 431 int length = end - begin; 432 433 boolean bestShort = entry.isShortMatch(); 434 435 if (bestPrefixLength < entry._prefixLength || bestMinLength < length) { 437 if (vars != null) { 438 vars.clear(); 439 440 vars.add(uri.substring(0, end)); 441 for (int j = 1; j <= matcher.groupCount(); j++) 442 vars.add(matcher.group(j)); 443 } 444 445 best = entry._value; 446 bestPrefixLength = entry._prefixLength; 447 bestMaxLength = length; 448 if (! entry.isShortMatch()) 449 bestMinLength = length; 450 if (entry._prefixLength > bestMinLength) 451 bestMinLength = entry._prefixLength; 452 } 453 } 454 455 return best; 456 } 457 458 461 public ArrayList <String > getURLPatterns() 462 { 463 ArrayList <String > patterns = new ArrayList <String >(); 464 465 for (int i = 0; i < _regexps.size(); i++) { 466 RegexpEntry<E> entry = _regexps.get(i); 467 468 String urlPattern = entry.getURLPattern(); 469 470 if (urlPattern != null) 471 patterns.add(urlPattern); 472 } 473 474 return patterns; 475 } 476 477 static class RegexpEntry<E> { 478 String _urlPattern; 479 String _pattern; 480 int _flags; 481 Pattern _regexp; 482 E _value; 483 int _prefixLength; 484 boolean _shortMatch; 485 486 RegexpEntry(int prefixLength, String pattern, String flags, E value) 487 throws PatternSyntaxException 488 { 489 this(prefixLength, pattern, pattern, flags, value); 490 } 491 492 RegexpEntry(int prefixLength, String urlPattern, 493 String pattern, String flags, E value) 494 throws PatternSyntaxException 495 { 496 _urlPattern = urlPattern; 497 _prefixLength = prefixLength; 498 _pattern = pattern; 499 500 if (flags == null && CauchoSystem.isCaseInsensitive()) 501 _flags = Pattern.CASE_INSENSITIVE; 502 else if (flags != null && flags.equals("i")) 503 _flags = Pattern.CASE_INSENSITIVE; 504 505 _regexp = Pattern.compile(pattern, _flags); 506 _value = value; 507 } 508 509 void setShortMatch() 510 { 511 _shortMatch = true; 512 } 513 514 boolean isShortMatch() 515 { 516 return _shortMatch; 517 } 518 519 String getURLPattern() 520 { 521 return _urlPattern; 522 } 523 524 String getPattern() 525 { 526 return _pattern; 527 } 528 529 public int hashCode() 530 { 531 if (_urlPattern != null) 532 return _urlPattern.hashCode(); 533 else if (_pattern != null) 534 return _pattern.hashCode(); 535 else 536 return 17; 537 } 538 539 public boolean equals(Object o) 540 { 541 if (! (o instanceof RegexpEntry)) 542 return false; 543 544 RegexpEntry re = (RegexpEntry) o; 545 546 if (_urlPattern != null) 547 return _urlPattern.equals(re._urlPattern); 548 else if (_pattern != null) 549 return _pattern.equals(re._pattern); 550 else 551 return false; 552 } 553 554 public String toString() 555 { 556 if (_urlPattern != null) 557 return "RegexpEntry[" + _urlPattern + "]"; 558 else if (_pattern != null) 559 return "RegexpEntry[" + _pattern + "]"; 560 else 561 return super.toString(); 562 } 563 } 564 } 565 | Popular Tags |