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 015 package org.apache.tapestry.form.validator; 016 017 import org.apache.hivemind.ApplicationRuntimeException; 018 import org.apache.hivemind.HiveMind; 019 import org.apache.hivemind.util.Defense; 020 import org.apache.hivemind.util.PropertyUtils; 021 import org.apache.tapestry.IComponent; 022 import org.apache.tapestry.util.RegexpMatch; 023 import org.apache.tapestry.util.RegexpMatcher; 024 025 import java.util.ArrayList; 026 import java.util.Collections; 027 import java.util.List; 028 import java.util.Map; 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 */ 037 public 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.badSpecification(specification)); 077 078 RegexpMatch match = matches[0]; 079 080 String name = match.getGroup(1); 081 String value = match.getGroup(3); 082 String message = null; 083 084 int length = match.getMatchLength(); 085 086 if (chopped.length() > length) 087 { 088 char lastChar = chopped.charAt(length); 089 if (lastChar == ',') 090 length--; 091 else if (lastChar == '[') 092 { 093 int messageClose = chopped.indexOf(']', length); 094 message = chopped.substring(length + 1, messageClose); 095 length = messageClose; 096 } 097 } 098 099 Validator validator = buildValidator(component, name, value, message); 100 101 result.add(validator); 102 103 if (length >= chopped.length()) 104 break; 105 106 chopped = chopped.substring(length + 1); 107 108 } 109 110 return Collections.unmodifiableList(result); 111 } 112 113 private Validator buildValidator(IComponent component, String name, String value, String message) 114 { 115 if (name.startsWith("$")) 116 return extractValidatorBean(component, name, value, message); 117 118 ValidatorContribution vc = (ValidatorContribution) _validators.get(name); 119 120 if (vc == null) 121 throw new ApplicationRuntimeException(ValidatorMessages.unknownValidator(name)); 122 123 if (value == null && vc.isConfigurable()) 124 throw new ApplicationRuntimeException(ValidatorMessages.needsConfiguration("name")); 125 126 if (value != null && !vc.isConfigurable()) 127 throw new ApplicationRuntimeException(ValidatorMessages.notConfigurable(name, value)); 128 129 try 130 { 131 Object result = vc.getValidatorClass().newInstance(); 132 133 if (vc.isConfigurable()) 134 PropertyUtils.smartWrite(result, name, value); 135 136 if (message != null) 137 PropertyUtils.write(result, "message", message); 138 139 return (Validator) result; 140 } 141 catch (Exception ex) 142 { 143 throw new ApplicationRuntimeException(ValidatorMessages.errorInitializingValidator( 144 name, 145 vc.getValidatorClass(), 146 ex), ex); 147 } 148 } 149 150 private Validator extractValidatorBean(IComponent component, String validatorName, 151 String value, String message) 152 { 153 String beanName = validatorName.substring(1); 154 155 if (HiveMind.isNonBlank(value) || HiveMind.isNonBlank(message)) 156 throw new ApplicationRuntimeException(ValidatorMessages 157 .noValueOrMessageForBean(beanName)); 158 159 return new BeanValidatorWrapper(component, beanName); 160 } 161 162 public void setValidators(Map validators) 163 { 164 _validators = validators; 165 } 166 }