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 023 import java.util.ArrayList; 024 import java.util.Collections; 025 import java.util.List; 026 import java.util.Map; 027 import java.util.regex.Matcher; 028 029 /** 030 * Implementation of the tapestry.form.validator.ValidatorFactory service, which builds and caches 031 * validators and lists of validators from a "magic" string specification. 032 * 033 * @author Howard Lewis Ship 034 * @since 4.0 035 */ 036 public class ValidatorFactoryImpl implements ValidatorFactory 037 { 038 private static final String PATTERN = "^\\s*(\\$?\\w+)\\s*(=\\s*(((?!,|\\[).)*))?"; 039 private static final java.util.regex.Pattern PATTERN_COMPILED = java.util.regex.Pattern.compile(PATTERN); 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 while (true) 058 { 059 if (chopped.length() == 0) 060 break; 061 062 if (!result.isEmpty()) 063 { 064 if (chopped.charAt(0) != ',') 065 failBadSpec(specification); 066 067 chopped = chopped.substring(1); 068 } 069 070 Matcher matcher = PATTERN_COMPILED.matcher(chopped); 071 072 if (!matcher.find()) failBadSpec(specification); 073 074 String name = matcher.group(1); 075 String value = matcher.group(3); 076 String message = null; 077 078 int length = matcher.group().length(); 079 080 if (matcher.find()) failBadSpec(specification); 081 082 if (chopped.length() > length) 083 { 084 char lastChar = chopped.charAt(length); 085 if (lastChar == ',') 086 length--; 087 else if (lastChar == '[') 088 { 089 int messageClose = chopped.indexOf(']', length); 090 message = chopped.substring(length + 1, messageClose); 091 length = messageClose; 092 } 093 } 094 095 Validator validator = buildValidator(component, name, value, message); 096 097 result.add(validator); 098 099 if (length >= chopped.length()) 100 break; 101 102 chopped = chopped.substring(length + 1); 103 104 } 105 106 return Collections.unmodifiableList(result); 107 } 108 109 private void failBadSpec(String specification) { 110 throw new ApplicationRuntimeException(ValidatorMessages.badSpecification(specification)); 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 }