001// Copyright 2005 The Apache Software Foundation 002// 003// Licensed under the Apache License, Version 2.0 (the "License"); 004// you may not use this file except in compliance with the License. 005// You may obtain a copy of the License at 006// 007// http://www.apache.org/licenses/LICENSE-2.0 008// 009// Unless required by applicable law or agreed to in writing, software 010// distributed under the License is distributed on an "AS IS" BASIS, 011// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 012// See the License for the specific language governing permissions and 013// limitations under the License. 014 015package org.apache.tapestry.form.validator; 016 017import java.util.ArrayList; 018import java.util.Collections; 019import java.util.List; 020import java.util.Map; 021 022import org.apache.hivemind.ApplicationRuntimeException; 023import org.apache.hivemind.HiveMind; 024import org.apache.hivemind.util.Defense; 025import org.apache.hivemind.util.PropertyUtils; 026import org.apache.tapestry.IComponent; 027import org.apache.tapestry.util.RegexpMatch; 028import org.apache.tapestry.util.RegexpMatcher; 029 030/** 031 * Implementation of the tapestry.form.validator.ValidatorFactory service, which builds and caches 032 * validators and lists of validators from a "magic" string specification. 033 * 034 * @author Howard Lewis Ship 035 * @since 4.0 036 */ 037public class ValidatorFactoryImpl implements ValidatorFactory 038{ 039 private static final String PATTERN = "^\\s*(\\$?\\w+)\\s*(=\\s*(((?!,|\\[).)*))?"; 040 041 /** 042 * Injected map of validator names to ValidatorContribution. 043 */ 044 045 private Map _validators; 046 047 public List constructValidatorList(IComponent component, String specification) 048 { 049 Defense.notNull(component, "component"); 050 051 if (HiveMind.isBlank(specification)) 052 return Collections.EMPTY_LIST; 053 054 List result = new ArrayList(); 055 String chopped = specification; 056 057 RegexpMatcher matcher = new RegexpMatcher(); 058 059 while (true) 060 { 061 if (chopped.length() == 0) 062 break; 063 064 if (!result.isEmpty()) 065 { 066 if (chopped.charAt(0) != ',') 067 throw new ApplicationRuntimeException(ValidatorMessages 068 .badSpecification(specification)); 069 070 chopped = chopped.substring(1); 071 } 072 073 RegexpMatch[] matches = matcher.getMatches(PATTERN, chopped); 074 075 if (matches.length != 1) 076 throw new ApplicationRuntimeException(ValidatorMessages 077 .badSpecification(specification)); 078 079 RegexpMatch match = matches[0]; 080 081 String name = match.getGroup(1); 082 String value = match.getGroup(3); 083 String message = null; 084 085 int length = match.getMatchLength(); 086 087 if (chopped.length() > length) 088 { 089 char lastChar = chopped.charAt(length); 090 if (lastChar == ',') 091 length--; 092 else if (lastChar == '[') 093 { 094 int messageClose = chopped.indexOf(']', length); 095 message = chopped.substring(length + 1, messageClose); 096 length = messageClose; 097 } 098 } 099 100 Validator validator = buildValidator(component, name, value, message); 101 102 result.add(validator); 103 104 if (length >= chopped.length()) 105 break; 106 107 chopped = chopped.substring(length + 1); 108 109 } 110 111 return Collections.unmodifiableList(result); 112 } 113 114 private Validator buildValidator(IComponent component, String name, String value, String message) 115 { 116 if (name.startsWith("$")) 117 return extractValidatorBean(component, name, value, message); 118 119 ValidatorContribution vc = (ValidatorContribution) _validators.get(name); 120 121 if (vc == null) 122 throw new ApplicationRuntimeException(ValidatorMessages.unknownValidator(name)); 123 124 if (value == null && vc.isConfigurable()) 125 throw new ApplicationRuntimeException(ValidatorMessages.needsConfiguration("name")); 126 127 if (value != null && !vc.isConfigurable()) 128 throw new ApplicationRuntimeException(ValidatorMessages.notConfigurable(name, value)); 129 130 try 131 { 132 Object result = vc.getValidatorClass().newInstance(); 133 134 if (vc.isConfigurable()) 135 PropertyUtils.smartWrite(result, name, value); 136 137 if (message != null) 138 PropertyUtils.write(result, "message", message); 139 140 return (Validator) result; 141 } 142 catch (Exception ex) 143 { 144 throw new ApplicationRuntimeException(ValidatorMessages.errorInitializingValidator( 145 name, 146 vc.getValidatorClass(), 147 ex), ex); 148 } 149 } 150 151 private Validator extractValidatorBean(IComponent component, String validatorName, 152 String value, String message) 153 { 154 String beanName = validatorName.substring(1); 155 156 if (HiveMind.isNonBlank(value) || HiveMind.isNonBlank(message)) 157 throw new ApplicationRuntimeException(ValidatorMessages 158 .noValueOrMessageForBean(beanName)); 159 160 return new BeanValidatorWrapper(component, beanName); 161 } 162 163 public void setValidators(Map validators) 164 { 165 _validators = validators; 166 } 167}