/* * This file is part of the URI Template library. * * For licensing information please see the file license.txt included in the release. * A copy of this licence can also be found at * http://www.opensource.org/licenses/artistic-license-2.0.php */ package org.weborganic.furi; import java.util.List; import java.util.regex.Pattern; /** * A URI Pattern for matching URI following the same regular structure. * * <p> * Instances of this class implement the PageSeeder URL pattern as defined by the "PageSeeder URI * Templates" document. * * <p> * A PageSeeder URI Pattern follows the URI syntax defined for URI templates but must only contain * matchable tokens. * * @author Christophe Lauret * @version 27 October 2009 */ public class URIPattern extends URITemplate implements Matchable { /** * The regular expression pattern for matching URIs to this URI Pattern. */ private Pattern _pattern; /** * The score for this pattern, the length of the literal text. */ private int _score = -1; /** * Creates a new URI Pattern instance from the specified URI template string. * * @param template The string following the URI template syntax. * * @throws URITemplateSyntaxException If the string provided does not follow the proper syntax. */ public URIPattern(String template) throws IllegalArgumentException { super(template); if (!isMatchable(this)) { throw new IllegalArgumentException("Cannot create a URL pattern containing non-matchable tokens."); } this._pattern = computePattern(tokens()); } /** * Creates a new URI Pattern instance from an existing URI Template. * * @param template The URI template to generate the pattern from. * * @throws URITemplateSyntaxException If the string provided does not follow the proper syntax. */ public URIPattern(URITemplate template) throws IllegalArgumentException { super(template != null ? template.toString() : ""); if (template == null) { throw new NullPointerException("Cannot create a URL pattern with a null template"); } if (!isMatchable(template)) { throw new IllegalArgumentException("Cannot create a URL pattern from template containing non-matchable tokens."); } this._pattern = computePattern(tokens()); } /** * Indicates whether the given URI template can be used to construct a new URI Pattern instance. * * <p> * A template is matchable only if all its components are matchable tokens, that is the token * implements the {@link Matchable} interface. * * @param template The template to test. * * @return <code>true</code> if the template is matchable; <code>false</code> otherwise. */ public static boolean isMatchable(URITemplate template) { // return false if any non-matchable token is found. for (Token t : template.tokens()) { if (!(t instanceof Matchable)) { return false; } } // all tokens are matchable at this point. return true; } /** * Indicates whether this URI Pattern matches the specified URL. * * @param uri The URI to test. * * @return <code>true</code> if this URI Pattern matches this */ public boolean match(String uri) { return this._pattern.matcher(uri).matches(); } /** * Returns the regular expression pattern corresponding to this URI pattern. * * @return The regular expression pattern corresponding to this URI pattern. */ public Pattern pattern() { return this._pattern; } @Override public boolean equals(Object o) { return super.equals(o); } @Override public int hashCode() { // use the original regex pattern string because the Pattern object's hashCode return 7 * this._pattern.pattern().hashCode() + 3 * this.toString().hashCode() + 31; } /** * Returns the score for this URI pattern. * * The score corresponds to the length of literal content. * * @return the score for this URI pattern. */ protected int score() { if (this._score < 0) { this._score = computeScore(this.tokens()); } return this._score; } // private helpers ---------------------------------------------------------- /** * Compute the Regular Expression pattern for this URI Pattern. * * Important note: the regular expression contain the same number of capturing groups as the * number of token to facilitate the resolve process. * * @return The regex Pattern instance corresponding to this URI pattern. */ private Pattern computePattern(List<Token> tokens) { StringBuffer p = new StringBuffer(); for (Token t : tokens) { Matchable mt = (Matchable) t; // wrap each token in a capturing group to facilitate the resolve process. p.append('('); p.append(mt.pattern()); p.append(')'); } return Pattern.compile(p.toString()); } /** * Compute the score from the specified tokens. * * The score is the sum of the length of each literal token. * * @return The score from the specified tokens. */ private int computeScore(List<Token> tokens) { int score = 0; for (Token t : tokens) { if (t instanceof TokenLiteral) { score += t.expression().length(); } } return score; } }