All Downloads are FREE. Search and download functionalities are using the official Maven repository.

com.damnhandy.uri.template.Expression Maven / Gradle / Ivy

Go to download

Handy URI Templates is a RFC6570 compliant URI template processor. The library allows clients to utilize templatized URIs and inject replacement variables to expand the template into a URI. The library sports a fluent API, ability to plugin custom object renderers, and supports all levels of URI templates.

The newest version!
/*
 * Copyright 2012, Ryan J. McDonough
 *
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 *     http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */
package com.damnhandy.uri.template;


import com.damnhandy.uri.template.impl.Modifier;
import com.damnhandy.uri.template.impl.Operator;
import com.damnhandy.uri.template.impl.VarSpec;

import java.util.ArrayList;
import java.util.List;
import java.util.regex.Matcher;
import java.util.regex.Pattern;

/**
 * 

* An Expression represents the text between '{' and '}', including the enclosing * braces, as defined in Section 2 of RFC6570. *

*
 * http://www.example.com/foo{?query,number}
 *                            \___________/
 *                                  ^
 *                                  |
 *                                  |
 *                            The expression
 * 
*

* This class models this representation and adds helper functions for replacement and reverse matching. *

* * @author Ryan J. McDonough * @version $Revision: 1.1 $ * @since 2.0 */ public class Expression extends UriTemplateComponent { /** * The serialVersionUID */ private static final long serialVersionUID = -5305648325957481840L; /** * A regex quoted string that matches the expression for replacement in the * expansion process. For example: *
     *          \Q{?query,number}\E
     * 
*/ private String replacementPattern; /** * That {@link Operator} value that is associated with this Expression */ private Operator op; /** * The character position where this expression occurs in the URI template */ private final int location; /** * The the parsed {@link VarSpec} instances found in the expression. */ private List varSpecs; /** * The Patter that would be used to reverse match this expression */ private Pattern matchPattern; /** * Creates a new {@link Builder} to create a simple expression according * to section 3.2.2. * Calling: *
     * String exp = Expression.simple(var("var")).build().toString();
     * 
*

* Will return the following expression: *

*
     * {var}
     * 
* * @return */ public static Builder simple(VarSpec... varSpec) { return Builder.create(Operator.NUL, varSpec); } /** * Creates a new {@link Builder} to create an expression that will use reserved expansion * according to section 3.2.3. * Calling: *
     * String exp = Expression.reserved().var("var").build().toString();
     * 
*

* Will return the following expression: *

*
     * {+var}
     * 
* * @return */ public static Builder reserved(VarSpec... varSpec) { return Builder.create(Operator.RESERVED, varSpec); } /** * Creates a new {@link Builder} to create an expression with a fragment operator * according to section 3.2.4. * Calling: *
     * String exp = Expression.fragment().var("var").build().toString();
     * 
*

* Will return the following expression: *

*
     * {#var}
     * 
* * @return */ public static Builder fragment(VarSpec... varSpec) { return Builder.create(Operator.FRAGMENT, varSpec); } /** * Creates a new {@link Builder} to create an expression using label expansion * according to section 3.2.5. * Calling: *
     * String exp = Expression.label(var("var")).build().toString();
     * 
*

* Will return the following expression: *

*
     * {.var}
     * 
* * @return */ public static Builder label(VarSpec... varSpec) { return Builder.create(Operator.NAME_LABEL, varSpec); } /** * Creates a new {@link Builder} to create an expression using path expansion * according to section 3.2.6. * Calling: *
     * String exp = Expression.path().var("var").build().toString();
     * 
*

* Will return the following expression: *

*
     * {/var}
     * 
* * @return */ public static Builder path(VarSpec... varSpec) { return Builder.create(Operator.PATH, varSpec); } /** * Creates a new {@link Builder} to create an expression using path-style parameter * (a.k.a. matrix parameter) expansion according to * section 3.2.7. * Calling: *
     * String exp = Expression.matrix().var("var").build().toString();
     * 
*

* Will return the following expression: *

*
     * {;var}
     * 
* * @return the builder */ public static Builder matrix(VarSpec... varSpec) { return Builder.create(Operator.MATRIX, varSpec); } /** * Creates a new {@link Builder} to create an expression using form-style query string expansion * according to section 3.2.8. * Calling: *
     * String exp = Expression.query().var("var").build().toString();
     * 
*

* Will return the following expression: *

*
     * {?var}
     * 
* * @return */ public static Builder query(VarSpec... varSpec) { return Builder.create(Operator.QUERY, varSpec); } /** * Creates a new {@link Builder} to create an expression using form-style query continuation expansion * according to section 3.2.9. * Calling: *
     * String exp = Expression.continuation().var("var").build().toString();
     * 
*

* Will return the following expression: *

*
     * {&var}
     * 
* * @return */ public static Builder continuation(VarSpec... varSpec) { return Builder.create(Operator.CONTINUATION, varSpec); } /** * Create a new Expression. * * @param rawExpression * @param startPosition * @throws MalformedUriTemplateException */ public Expression(final String rawExpression, final int startPosition) throws MalformedUriTemplateException { super(startPosition); this.location = startPosition; this.parseRawExpression(rawExpression); } /** * Create a new Expression * * @param op * @param varSpecs * @throws MalformedUriTemplateException */ public Expression(final Operator op, final List varSpecs) { super(0); this.op = op; this.varSpecs = varSpecs; this.replacementPattern = Pattern.quote(toString()); this.location = 0; } /** * @param rawExpression * @throws MalformedUriTemplateException */ private void parseRawExpression(String rawExpression) throws MalformedUriTemplateException { final String expressionReplacement = Pattern.quote(rawExpression); String token = rawExpression.substring(1, rawExpression.length() - 1); // Check for URI operators Operator operator = Operator.NUL; String firstChar = token.substring(0, 1); if (UriTemplate.containsOperator(firstChar)) { try { operator = Operator.fromOpCode(firstChar); } catch (IllegalArgumentException e) { throw new MalformedUriTemplateException("Invalid operator", this.location, e); } token = token.substring(1, token.length()); } String[] varspecStrings = token.split(","); List varspecs = new ArrayList(); for (String varname : varspecStrings) { int subStrPos = varname.indexOf(Modifier.PREFIX.getValue()); /* * Prefix variable */ if (subStrPos > 0) { String[] pair = varname.split(Modifier.PREFIX.getValue()); try { Integer pos = Integer.valueOf(varname.substring(subStrPos + 1)); varspecs.add(new VarSpec(pair[0], Modifier.PREFIX, pos)); } catch (NumberFormatException e) { throw new MalformedUriTemplateException("The prefix value for " + pair[0] + " was not a number", this.location, e); } } /* * Variable will be exploded */ else if (varname.lastIndexOf(Modifier.EXPLODE.getValue()) > 0) { varspecs.add(new VarSpec(varname, Modifier.EXPLODE)); } /* * Standard Value */ else { varspecs.add(new VarSpec(varname, Modifier.NONE)); } } this.replacementPattern = expressionReplacement; this.op = operator; this.varSpecs = varspecs; } private Pattern buildMatchingPattern() { StringBuilder b = new StringBuilder(); for (VarSpec v : getVarSpecs()) { b.append("(?<").append(v.getVariableName()).append(">[^\\/]+)"); } return Pattern.compile(b.toString()); } /** * Returns a string that contains a regular expression that matches the * URI template expression. * * @return the match pattern */ @Override public Pattern getMatchPattern() { if (this.matchPattern == null) { this.matchPattern = buildMatchingPattern(); } return this.matchPattern; } /** * Get the replacementToken. * * @return the replacementToken. */ public String getReplacementPattern() { return replacementPattern; } /** * Get the {@link Operator} value for this expression. * * @return the operator value. */ public Operator getOperator() { return op; } /** * Get the varSpecs. * * @return the varSpecs. */ public List getVarSpecs() { return varSpecs; } /** * Returns the string representation of the expression. * * @see Object#toString() */ public String toString() { StringBuilder b = new StringBuilder(); b.append("{").append(this.getOperator().getOperator()); for (int i = 0; i < varSpecs.size(); i++) { VarSpec v = varSpecs.get(i); b.append(v.getValue()); // Double check that the value doesn't already contain the modifier int r = v.getValue().lastIndexOf(v.getModifier().getValue()); if(v.getModifier() != null && v.getValue().lastIndexOf(v.getModifier().getValue()) == -1) { b.append(v.getModifier().getValue()); } if (v.getModifier() == Modifier.PREFIX) { b.append(v.getPosition()); } if (i != (varSpecs.size() - 1)) { b.append(","); } } return b.append("}").toString(); } /** * Returns the value of this component * * @return the string value of this component. */ @Override public String getValue() { return toString(); } @Override public int hashCode() { final int prime = 31; int result = 1; result = prime * result + ((op == null) ? 0 : op.hashCode()); result = prime * result + ((varSpecs == null) ? 0 : varSpecs.hashCode()); return result; } @Override public boolean equals(Object obj) { if (this == obj) { return true; } if (obj == null) { return false; } if (getClass() != obj.getClass()) { return false; } Expression other = (Expression) obj; if (op != other.op) { return false; } if (varSpecs == null) { if (other.varSpecs != null) { return false; } } else if (!varSpecs.equals(other.varSpecs)) { return false; } return true; } /** * Builder class for creating an {@link Expression}. * * @author Ryan J. McDonough * @version $Revision: 1.1 $ */ public static class Builder { /** * */ private Operator operator; /** * */ private List varSpecs; /** * Create a new ExpressionBuilder. * * @param operator */ private Builder(Operator operator, VarSpec... varSpec) { this.operator = operator; this.varSpecs = new ArrayList(); for (VarSpec v : varSpec) { varSpecs.add(v); } } /** * @param operator * @return the builder */ static Builder create(Operator operator, VarSpec... varSpec) { return new Builder(operator, varSpec); } public Expression build() { return new Expression(operator, varSpecs); } } }




© 2015 - 2024 Weber Informatics LLC | Privacy Policy