001/* 002 * Copyright 2012 Anyware Services 003 * 004 * Licensed under the Apache License, Version 2.0 (the "License"); 005 * you may not use this file except in compliance with the License. 006 * You may obtain a copy of the License at 007 * 008 * http://www.apache.org/licenses/LICENSE-2.0 009 * 010 * Unless required by applicable law or agreed to in writing, software 011 * distributed under the License is distributed on an "AS IS" BASIS, 012 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 013 * See the License for the specific language governing permissions and 014 * limitations under the License. 015 */ 016package org.ametys.runtime.parameter; 017 018import java.util.HashMap; 019import java.util.Map; 020import java.util.regex.Pattern; 021 022import org.apache.avalon.framework.configuration.Configurable; 023import org.apache.avalon.framework.configuration.Configuration; 024import org.apache.avalon.framework.configuration.ConfigurationException; 025import org.apache.avalon.framework.logger.AbstractLogEnabled; 026import org.apache.avalon.framework.service.ServiceException; 027import org.apache.avalon.framework.service.ServiceManager; 028import org.apache.avalon.framework.service.Serviceable; 029import org.apache.cocoon.util.log.SLF4JLoggerAdapter; 030import org.apache.cocoon.xml.XMLUtils; 031import org.slf4j.LoggerFactory; 032import org.xml.sax.ContentHandler; 033import org.xml.sax.SAXException; 034 035import org.ametys.core.util.JSONUtils; 036import org.ametys.runtime.i18n.I18nizableText; 037import org.ametys.runtime.plugin.component.PluginAware; 038 039 040/** 041 * This default implementation validates the following configurable stuff: 042 * <ul> 043 * <li>mandatory: check the parameter is set</li> 044 * <li>regexp: check the string parameter matches a regexp</li> 045 * </ul> 046 */ 047public class DefaultValidator extends AbstractLogEnabled implements Validator, Configurable, PluginAware, Serviceable 048{ 049 /** Is the value mandatory ? */ 050 protected boolean _isMandatory; 051 /** Does the value need to match a regexp */ 052 protected Pattern _regexp; 053 /** The error text to display if regexp fails */ 054 protected I18nizableText _invalidText; 055 /** The plugin name */ 056 protected String _pluginName; 057 058 /** The service manager */ 059 protected ServiceManager _smanager; 060 061 private JSONUtils _jsonUtils; 062 063 /** 064 * Default constructor for avalon 065 */ 066 public DefaultValidator() 067 { 068 // empty 069 } 070 071 /** 072 * Manual constructor 073 * @param regexp The regexp to check or null 074 * @param mandatory Is the value mandatory 075 */ 076 public DefaultValidator(String regexp, boolean mandatory) 077 { 078 _isMandatory = mandatory; 079 if (regexp != null) 080 { 081 _regexp = Pattern.compile(regexp); 082 } 083 enableLogging(new SLF4JLoggerAdapter(LoggerFactory.getLogger(this.getClass()))); 084 } 085 086 /** 087 * Manual constructor 088 * @param regexp The regexp to check or null 089 * @param invalidText The error text to display 090 * @param mandatory Is the value mandatory 091 */ 092 public DefaultValidator(String regexp, I18nizableText invalidText, boolean mandatory) 093 { 094 _isMandatory = mandatory; 095 if (regexp != null) 096 { 097 _regexp = Pattern.compile(regexp); 098 } 099 _invalidText = invalidText; 100 101 enableLogging(new SLF4JLoggerAdapter(LoggerFactory.getLogger(this.getClass()))); 102 } 103 104 @Override 105 public void service(ServiceManager smanager) throws ServiceException 106 { 107 _smanager = smanager; 108 } 109 110 @Override 111 public void setPluginInfo(String pluginName, String featureName, String id) 112 { 113 _pluginName = pluginName; 114 } 115 116 @Override 117 public void configure(Configuration configuration) throws ConfigurationException 118 { 119 Configuration validatorConfig = configuration.getChild("validation"); 120 121 _isMandatory = validatorConfig.getChild("mandatory", false) != null; 122 123 String regexp = validatorConfig.getChild("regexp").getValue(null); 124 if (regexp != null) 125 { 126 _regexp = Pattern.compile(regexp); 127 } 128 129 Configuration textConfig = validatorConfig.getChild("invalidText", false); 130 if (textConfig != null) 131 { 132 _invalidText = I18nizableText.parseI18nizableText(textConfig, "plugin." + _pluginName); 133 } 134 } 135 136 @Override 137 public Map<String, Object> toJson() 138 { 139 Map<String, Object> jsonObject = new HashMap<>(); 140 141 jsonObject.put("mandatory", _isMandatory); 142 143 if (_regexp != null) 144 { 145 jsonObject.put("regexp", _regexp.toString()); 146 } 147 148 if (_invalidText != null) 149 { 150 jsonObject.put("invalidText", _invalidText); 151 } 152 return jsonObject; 153 } 154 155 /** 156 * SAX the JSON configuration of this validator 157 * @param handler The content handlet to sax into 158 * @throws SAXException if an error occurred 159 */ 160 protected void saxJsonConfig (ContentHandler handler) throws SAXException 161 { 162 if (_jsonUtils == null) 163 { 164 try 165 { 166 // lazy lookup the json utils 167 _jsonUtils = (JSONUtils) _smanager.lookup(JSONUtils.ROLE); 168 XMLUtils.createElement(handler, "config", _jsonUtils.convertObjectToJson(toJson())); 169 } 170 catch (ServiceException e) 171 { 172 // FIXME RUNTIME-2013 Validators and enumerators can not use others components such as JSONUtils 173 getLogger().warn("Unable to retrieve the component JSONUtils", e); 174 } 175 } 176 } 177 178 @Override 179 public void saxConfiguration(ContentHandler handler) throws SAXException 180 { 181 XMLUtils.createElement(handler, "mandatory", Boolean.toString(_isMandatory)); 182 183 if (_regexp != null) 184 { 185 XMLUtils.createElement(handler, "regexp", _regexp.toString()); 186 } 187 188 if (_invalidText != null) 189 { 190 _invalidText.toSAX(handler, "invalidText"); 191 } 192 193 // FIXME RUNTIME-2015 The configuration of a validator as JSON object should be pass to the field configuration 194 // but FIXME RUNTIME-2013 Validators and enumerators can not use others components such as JSONUtils 195 // saxJsonConfig(handler); 196 } 197 198 @Override 199 public Map<String, Object> getConfiguration() 200 { 201 Map<String, Object> configuration = new HashMap<>(); 202 203 configuration.put("mandatory", Boolean.valueOf(_isMandatory)); 204 205 if (_regexp != null) 206 { 207 configuration.put("regexp", _regexp); 208 } 209 210 if (_invalidText != null) 211 { 212 configuration.put("invalidText", _invalidText); 213 } 214 215 return configuration; 216 } 217 218 @Override 219 public void validate(Object value, Errors errors) 220 { 221 boolean isArray = value != null && value.getClass().isArray(); 222 if (isArray) 223 { 224 validateArrayValues((Object[]) value, errors); 225 } 226 else 227 { 228 validateSingleValue (value, errors); 229 } 230 } 231 232 /** 233 * Validates a single value. 234 * @param value the value to validate (can be <code>null</code>). 235 * @param errors the structure to populate if the validation failed. 236 */ 237 protected void validateSingleValue (Object value, Errors errors) 238 { 239 if (_isMandatory && (value == null || value.toString().length() == 0)) 240 { 241 if (getLogger().isDebugEnabled()) 242 { 243 getLogger().debug("The validator refused a missing or empty value for a mandatory parameter"); 244 } 245 246 errors.addError(new I18nizableText("plugin.core-ui", "PLUGINS_CORE_UI_DEFAULT_VALIDATOR_MANDATORY")); 247 } 248 249 if (_regexp != null && value != null && value.toString().length() != 0 && !_regexp.matcher(value.toString()).matches()) 250 { 251 if (getLogger().isDebugEnabled()) 252 { 253 getLogger().debug("The validator refused a value for a parameter that should respect a regexep"); 254 } 255 256 errors.addError(new I18nizableText("plugin.core-ui", "PLUGINS_CORE_UI_DEFAULT_VALIDATOR_PATTERN_FAILED")); 257 } 258 } 259 260 /** 261 * Validates a array of values. 262 * @param values the values to validate 263 * @param errors the structure to populate if the validation failed. 264 */ 265 protected void validateArrayValues (Object[] values, Errors errors) 266 { 267 if (_isMandatory && (values == null || values.length == 0)) 268 { 269 if (getLogger().isDebugEnabled()) 270 { 271 getLogger().debug("The validator refused a missing or empty value for a mandatory parameter"); 272 } 273 274 errors.addError(new I18nizableText("kernel", "PLUGINS_CORE_UI_DEFAULT_VALIDATOR_MANDATORY")); 275 } 276 277 if (_regexp != null && values != null && !_matchRegexp(values)) 278 { 279 if (getLogger().isDebugEnabled()) 280 { 281 getLogger().debug("The validator refused a value for a parameter that should respect a regexep"); 282 } 283 284 errors.addError(new I18nizableText("kernel", "PLUGINS_CORE_UI_DEFAULT_VALIDATOR_PATTERN_FAILED")); 285 } 286 } 287 288 private boolean _matchRegexp (Object[] values) 289 { 290 for (Object value : values) 291 { 292 if (!_regexp.matcher(value.toString()).matches()) 293 { 294 return false; 295 } 296 } 297 return true; 298 } 299}