001/*
002 * Licensed to the Apache Software Foundation (ASF) under one or more
003 * contributor license agreements.  See the NOTICE file distributed with
004 * this work for additional information regarding copyright ownership.
005 * The ASF licenses this file to You under the Apache License, Version 2.0
006 * (the "License"); you may not use this file except in compliance with
007 * the License.  You may obtain a copy of the License at
008 *
009 *      http://www.apache.org/licenses/LICENSE-2.0
010 *
011 * Unless required by applicable law or agreed to in writing, software
012 * distributed under the License is distributed on an "AS IS" BASIS,
013 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
014 * See the License for the specific language governing permissions and
015 * limitations under the License.
016 */
017package org.apache.wicket.validation.validator;
018
019import java.util.regex.Pattern;
020
021import org.apache.wicket.markup.html.form.FormComponent;
022import org.apache.wicket.util.parse.metapattern.MetaPattern;
023import org.apache.wicket.validation.IValidatable;
024import org.apache.wicket.validation.IValidationError;
025import org.apache.wicket.validation.IValidator;
026import org.apache.wicket.validation.ValidationError;
027
028/**
029 * Validates an {@link IValidatable} by matching the value against a regular expression pattern. A
030 * <code>PatternValidator</code> can be constructed with either a Java regular expression (compiled
031 * or not) or a {@link MetaPattern}. If the pattern matches against the value then it is considered
032 * valid. If the pattern does not match, the an {@link IValidationError} will be reported on the
033 * {@link IValidatable}.
034 * <p>
035 * For example, to restrict a field to only digits, you might add a <code>PatternValidator</code>
036 * constructed with the pattern "\d+". Another way to do the same thing would be to construct the
037 * <code>PatternValidator</code> passing in {@link MetaPattern#DIGITS}. The advantages of using
038 * {@link MetaPattern} over straight Java regular expressions are that the patterns are easier to
039 * construct and easier to combine into complex patterns. They are also more readable and more
040 * reusable. See {@link MetaPattern} for details.
041 * <p>
042 * The error message will be generated with the key "PatternValidator" and one additional message
043 * key ${pattern} for the pattern which failed to match. See {@link FormComponent} for a list of
044 * further messages keys.
045 * 
046 * @see java.util.regex.Pattern
047 * 
048 * @author Jonathan Locke
049 * @author Igor Vaynberg (ivaynberg)
050 * @since 1.2.6
051 */
052public class PatternValidator implements IValidator<String>
053{
054        private static final long serialVersionUID = 1L;
055
056        /** the pattern to match */
057        private final Pattern pattern;
058
059        /** whether to exclude matching input **/
060        private boolean reverse = false;
061
062        /**
063         * Constructor that accepts a <code>String</code> regular expression pattern.
064         * 
065         * @param pattern
066         *            a regular expression pattern
067         */
068        public PatternValidator(final String pattern)
069        {
070                this(Pattern.compile(pattern));
071        }
072
073        /**
074         * Constructor that accepts a <code>String</code> pattern and Java <code>regex</code> compile
075         * flags as arguments.
076         * 
077         * @param pattern
078         *            a regular expression pattern
079         * @param flags
080         *            compile flags for <code>java.util.regex.Pattern</code>
081         */
082        public PatternValidator(final String pattern, final int flags)
083        {
084                this(Pattern.compile(pattern, flags));
085        }
086
087        /**
088         * Constructor that accepts a compiled pattern.
089         * 
090         * @param pattern
091         *            a compiled pattern
092         */
093        public PatternValidator(final Pattern pattern)
094        {
095                this.pattern = pattern;
096        }
097
098        /**
099         * Constructor that accepts a <code>MetaPattern</code> argument.
100         * 
101         * @param pattern
102         *            a <code>MetaPattern</code>
103         */
104        public PatternValidator(final MetaPattern pattern)
105        {
106                this(pattern.pattern());
107        }
108
109        /**
110         * Gets the regexp pattern.
111         * 
112         * @return the regexp pattern
113         */
114        public final Pattern getPattern()
115        {
116                return pattern;
117        }
118
119        /**
120         * If set to true then input that matches the pattern is considered invalid.
121         * 
122         * @param reverse
123         * @return itself
124         */
125        public PatternValidator setReverse(boolean reverse)
126        {
127                this.reverse = reverse;
128                return this;
129        }
130
131        /**
132         * @see java.lang.Object#toString()
133         */
134        @Override
135        public String toString()
136        {
137                return "[PatternValidator pattern = " + pattern + "]";
138        }
139
140        /**
141         * Checks a value against this <code>PatternValidator</code>'s {@link Pattern}.
142         * 
143         * @param validatable
144         *            the <code>IValidatable</code> to check
145         */
146        @Override
147        public void validate(IValidatable<String> validatable)
148        {
149                // Check value against pattern
150                if (pattern.matcher(validatable.getValue()).matches() == reverse)
151                {
152                        ValidationError error = new ValidationError(this);
153                        error.setVariable("pattern", pattern.pattern());
154                        validatable.error(decorate(error, validatable));
155                }
156        }
157
158        /**
159         * Allows subclasses to decorate reported errors
160         * 
161         * @param error
162         * @param validatable
163         * @return decorated error
164         */
165        protected IValidationError decorate(IValidationError error, IValidatable<String> validatable)
166        {
167                return error;
168        }
169}