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.Locale; 020 021import org.apache.wicket.Component; 022import org.apache.wicket.markup.ComponentTag; 023import org.apache.wicket.validation.IValidatable; 024import org.apache.wicket.validation.IValidationError; 025import org.apache.wicket.validation.ValidationError; 026 027/** 028 * Validator for checking if length of a string falls within [min,max] range. 029 * 030 * If either min or max are {@code null} they are not checked. 031 * 032 * <p> 033 * If the component is attached to an {@code input} tag, a {@code maxlen} attribute will be added if 034 * the maximum is set. 035 * 036 * * 037 * <p> 038 * Resource keys: 039 * <ul> 040 * <li>{@code StringValidator.exact} if min==max ({@link #exactLength(int)})</li> 041 * <li>{@code StringValidator.range} if both min and max are not {@code null}</li> 042 * <li>{@code StringValidator.minimum} if max is {@code null} ({@link #minimumLength(int)})</li> 043 * <li>{@code StringValidator.maximum} if min is {@code null} ({@link #maximumLength(int)})</li> 044 * </ul> 045 * </p> 046 * 047 * <p> 048 * Error Message Variables: 049 * <ul> 050 * <li>{@code name}: the id of {@code Component} that failed</li> 051 * <li>{@code label}: the label of the {@code Component} (either comes from 052 * {@code FormComponent.labelModel} or resource key {@code <form-id>.<form-component-id>}</li> 053 * <li>{@code input}: the input value</li> 054 * <li>{@code length}: the length of the entered</li> 055 * <li>{@code minimum}: the minimum allowed length</li> 056 * <li>{@code maximum}: the maximum allowed length</li> 057 * </ul> 058 * </p> 059 * 060 * @author igor 061 */ 062public class StringValidator extends AbstractRangeValidator<Integer, String> 063{ 064 private static final long serialVersionUID = 1L; 065 066 /** 067 * Constructor that sets the minimum and maximum length values. 068 * 069 * @param minimum 070 * the minimum length 071 * @param maximum 072 * the maximum length 073 */ 074 public StringValidator(Integer minimum, Integer maximum) 075 { 076 setRange(minimum, maximum); 077 } 078 079 /** 080 * Constructor used for subclasses who want to set the range using 081 * {@link #setRange(Comparable, Comparable)} 082 */ 083 protected StringValidator() 084 { 085 } 086 087 @Override 088 protected Integer getValue(IValidatable<String> validatable) 089 { 090 return validatable.getValue().length(); 091 } 092 093 @Override 094 protected IValidationError decorate(IValidationError error, IValidatable<String> validatable) 095 { 096 error = super.decorate(error, validatable); 097 if (error instanceof ValidationError) 098 { 099 ((ValidationError)error).setVariable("length", validatable.getValue().length()); 100 } 101 return error; 102 } 103 104 @Override 105 public void onComponentTag(Component component, ComponentTag tag) 106 { 107 super.onComponentTag(component, tag); 108 109 String tagName = tag.getName().toLowerCase(Locale.ROOT); 110 boolean hasLengthAttribute = hasLengthAttribute(tagName); 111 112 Integer maximum = getMaximum(); 113 if (maximum != null && hasLengthAttribute) 114 { 115 tag.put("maxlength", maximum); 116 } 117 118 Integer minimum = getMinimum(); 119 if (minimum != null && hasLengthAttribute) 120 { 121 tag.put("minlength", minimum); 122 } 123 } 124 125 protected boolean hasLengthAttribute(String tagName) 126 { 127 return "input".equalsIgnoreCase(tagName) || "textarea".equalsIgnoreCase(tagName); 128 } 129 130 /** 131 * @param length 132 * @return a {@link StringValidator} that generates an error if a string is not of an exact 133 * length 134 */ 135 public static StringValidator exactLength(int length) 136 { 137 return new StringValidator(length, length); 138 } 139 140 /** 141 * @param length 142 * @return a {@link StringValidator} that generates an error if a string exceeds a maximum 143 * length 144 */ 145 public static StringValidator maximumLength(int length) 146 { 147 return new StringValidator(null, length); 148 } 149 150 /** 151 * @param length 152 * @return a {@link StringValidator} that generates an error if a string is not of a minimum 153 * length 154 */ 155 public static StringValidator minimumLength(int length) 156 { 157 return new StringValidator(length, null); 158 } 159 160 /** 161 * @param minimum 162 * @param maximum 163 * @return a {@link StringValidator} that generates an error if the length of a string is not 164 * between (inclusive) minimum and maximum 165 */ 166 public static StringValidator lengthBetween(int minimum, int maximum) 167 { 168 return new StringValidator(minimum, maximum); 169 } 170 171}