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.io.Serializable; 020import java.util.Locale; 021 022import org.apache.wicket.behavior.Behavior; 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 * Base class for validators that check if a given value falls within [min,max] range. 030 * 031 * If either min or max are {@code null} they are not checked. 032 * 033 * <p> 034 * Resource keys: 035 * <ul> 036 * <li>{@code <class.simpleName>.exact} if min==max</li> 037 * <li>{@code <class.simpleName>.range} if both min and max are not {@code null}</li> 038 * <li>{@code <class.simpleName>.minimum} if max is {@code null}</li> 039 * <li>{@code <class.simpleName>.maximum} if min is {@code null}</li> 040 * </ul> 041 * </p> 042 * 043 * <p> 044 * Error Message Variables: 045 * <ul> 046 * <li>{@code name}: the id of {@code Component} that failed</li> 047 * <li>{@code label}: the label of the {@code Component} (either comes from 048 * {@code FormComponent.labelModel} or resource key {@code <form-id>.<form-component-id>}</li> 049 * <li>{@code input}: the input value</li> 050 * <li>{@code minimum}: the minimum allowed value</li> 051 * <li>{@code maximum}: the maximum allowed value</li> 052 * </ul> 053 * </p> 054 * 055 * @param <R> 056 * type of range value 057 * @param <V> 058 * type of validatable 059 * 060 * @author igor 061 */ 062public abstract class AbstractRangeValidator<R extends Comparable<? super R> & Serializable, V extends Serializable> 063 extends Behavior implements IValidator<V> 064{ 065 private static final long serialVersionUID = 1L; 066 private R minimum; 067 private R maximum; 068 069 /** 070 * Constructor that sets the minimum and maximum values. 071 * 072 * @param minimum 073 * the minimum value 074 * @param maximum 075 * the maximum value 076 */ 077 public AbstractRangeValidator(R minimum, R maximum) 078 { 079 setRange(minimum, maximum); 080 } 081 082 /** 083 * Constructor used for subclasses who want to set the range using 084 * {@link #setRange(Comparable, Comparable)} 085 */ 086 protected AbstractRangeValidator() 087 { 088 } 089 090 /** 091 * Sets validator range 092 * 093 * @param minimum 094 * @param maximum 095 */ 096 protected final void setRange(R minimum, R maximum) 097 { 098 if (minimum == null && maximum == null) 099 { 100 throw new IllegalArgumentException("Both minimum and maximum values cannot be null"); 101 } 102 this.minimum = minimum; 103 this.maximum = maximum; 104 } 105 106 @Override 107 public void validate(IValidatable<V> validatable) 108 { 109 R value = getValue(validatable); 110 final R min = getMinimum(); 111 final R max = getMaximum(); 112 if ((min != null && value.compareTo(min) < 0) || (max != null && value.compareTo(max) > 0)) 113 { 114 Mode mode = getMode(); 115 ValidationError error = new ValidationError(this, mode.getVariation()); 116 if (min != null) 117 { 118 error.setVariable("minimum", min); 119 } 120 if (max != null) 121 { 122 error.setVariable("maximum", max); 123 } 124 if (mode == Mode.EXACT) 125 { 126 error.setVariable("exact", max); 127 } 128 validatable.error(decorate(error, validatable)); 129 } 130 } 131 132 /** 133 * Gets the value that should be validated against the range 134 * 135 * @param validatable 136 * @return value to validate 137 */ 138 protected abstract R getValue(IValidatable<V> validatable); 139 140 /** 141 * Gets the minimum value. 142 * 143 * @return minimum value 144 */ 145 public R getMinimum() 146 { 147 return minimum; 148 } 149 150 /** 151 * Gets the maximum value. 152 * 153 * @return maximum value 154 */ 155 public R getMaximum() 156 { 157 return maximum; 158 } 159 160 /** 161 * Allows subclasses to decorate reported errors 162 * 163 * @param error 164 * @param validatable 165 * @return decorated error 166 */ 167 protected IValidationError decorate(IValidationError error, IValidatable<V> validatable) 168 { 169 return error; 170 } 171 172 /** 173 * Gets validation mode which is determined by whether min, max, or both values are provided 174 * 175 * @return validation mode 176 */ 177 public final Mode getMode() 178 { 179 final R min = getMinimum(); 180 final R max = getMaximum(); 181 182 if (min == null && max != null) 183 { 184 return Mode.MAXIMUM; 185 } 186 else if (max == null && min != null) 187 { 188 return Mode.MINIMUM; 189 } 190 else if ((min == null && max == null) || max.equals(min)) 191 { 192 return Mode.EXACT; 193 } 194 else 195 { 196 return Mode.RANGE; 197 } 198 } 199 200 /** 201 * Validator mode 202 * 203 * @author igor 204 */ 205 public static enum Mode { 206 MINIMUM, MAXIMUM, RANGE, EXACT; 207 208 public String getVariation() 209 { 210 return name().toLowerCase(Locale.ROOT); 211 } 212 } 213 214}