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 java.util.ArrayList;
018 import java.util.Collections;
019 import java.util.List;
020 import java.util.Map;
021
022 import org.apache.hivemind.ApplicationRuntimeException;
023 import org.apache.hivemind.HiveMind;
024 import org.apache.hivemind.util.Defense;
025 import org.apache.hivemind.util.PropertyUtils;
026 import org.apache.tapestry.IComponent;
027 import org.apache.tapestry.util.RegexpMatch;
028 import 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 */
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
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 }