View Javadoc
1   /*
2    * Copyright 2002-2015 the original author or authors.
3    *
4    * Licensed under the Apache License, Version 2.0 (the "License");
5    * you may not use this file except in compliance with the License.
6    * You may obtain a copy of the License at
7    *
8    *      http://www.apache.org/licenses/LICENSE-2.0
9    *
10   * Unless required by applicable law or agreed to in writing, software
11   * distributed under the License is distributed on an "AS IS" BASIS,
12   * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13   * See the License for the specific language governing permissions and
14   * limitations under the License.
15   */
16  
17  package org.springframework.expression.spel.ast;
18  
19  import java.util.concurrent.ConcurrentHashMap;
20  import java.util.concurrent.ConcurrentMap;
21  import java.util.regex.Matcher;
22  import java.util.regex.Pattern;
23  import java.util.regex.PatternSyntaxException;
24  
25  import org.springframework.expression.EvaluationException;
26  import org.springframework.expression.spel.ExpressionState;
27  import org.springframework.expression.spel.SpelEvaluationException;
28  import org.springframework.expression.spel.SpelMessage;
29  import org.springframework.expression.spel.support.BooleanTypedValue;
30  
31  /**
32   * Implements the matches operator. Matches takes two operands:
33   * The first is a String and the second is a Java regex.
34   * It will return {@code true} when {@link #getValue} is called
35   * if the first operand matches the regex.
36   *
37   * @author Andy Clement
38   * @author Juergen Hoeller
39   * @since 3.0
40   */
41  public class OperatorMatches extends Operator {
42  
43  	private final ConcurrentMap<String, Pattern> patternCache = new ConcurrentHashMap<String, Pattern>();
44  
45  
46  	public OperatorMatches(int pos, SpelNodeImpl... operands) {
47  		super("matches", pos, operands);
48  	}
49  
50  
51  	/**
52  	 * Check the first operand matches the regex specified as the second operand.
53  	 * @param state the expression state
54  	 * @return {@code true} if the first operand matches the regex specified as the
55  	 * second operand, otherwise {@code false}
56  	 * @throws EvaluationException if there is a problem evaluating the expression
57  	 * (e.g. the regex is invalid)
58  	 */
59  	@Override
60  	public BooleanTypedValue getValueInternal(ExpressionState state) throws EvaluationException {
61  		SpelNodeImpl leftOp = getLeftOperand();
62  		SpelNodeImpl rightOp = getRightOperand();
63  		Object left = leftOp.getValue(state, String.class);
64  		Object right = getRightOperand().getValueInternal(state).getValue();
65  
66  		if (!(left instanceof String)) {
67  			throw new SpelEvaluationException(leftOp.getStartPosition(),
68  					SpelMessage.INVALID_FIRST_OPERAND_FOR_MATCHES_OPERATOR, left);
69  		}
70  		if (!(right instanceof String)) {
71  			throw new SpelEvaluationException(rightOp.getStartPosition(),
72  					SpelMessage.INVALID_SECOND_OPERAND_FOR_MATCHES_OPERATOR, right);
73  		}
74  
75  		try {
76  			String leftString = (String) left;
77  			String rightString = (String) right;
78  			Pattern pattern = this.patternCache.get(rightString);
79  			if (pattern == null) {
80  				pattern = Pattern.compile(rightString);
81  				this.patternCache.putIfAbsent(rightString, pattern);
82  			}
83  			Matcher matcher = pattern.matcher(leftString);
84  			return BooleanTypedValue.forValue(matcher.matches());
85  		}
86  		catch (PatternSyntaxException ex) {
87  			throw new SpelEvaluationException(rightOp.getStartPosition(), ex, SpelMessage.INVALID_PATTERN, right);
88  		}
89  	}
90  
91  }