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.slf4j.LoggerFactory;
031
032import org.ametys.runtime.i18n.I18nizableText;
033import org.ametys.runtime.plugin.component.PluginAware;
034
035
036/**
037 * This default implementation validates the following configurable stuff:
038 * <ul>
039 *  <li>mandatory: check the parameter is set</li>
040 *  <li>regexp: check the string parameter matches a regexp</li>
041 * </ul> 
042 */
043public class DefaultValidator extends AbstractLogEnabled implements Validator, Configurable, PluginAware, Serviceable
044{
045    /** Is the value mandatory ? */
046    protected boolean _isMandatory;
047    /** Does the value need to match a regexp */
048    protected Pattern _regexp;
049    /** The error text to display if regexp fails */
050    protected I18nizableText _invalidText;
051    /** The plugin name */
052    protected String _pluginName;
053    
054    /** The service manager */
055    protected ServiceManager _smanager;
056    
057    /**
058     * Default constructor for avalon
059     */
060    public DefaultValidator()
061    {
062        // empty
063    }
064    
065    /**
066     * Manual constructor
067     * @param regexp The regexp to check or null
068     * @param mandatory Is the value mandatory 
069     */
070    public DefaultValidator(String regexp, boolean mandatory)
071    {
072        _isMandatory = mandatory;
073        if (regexp != null)
074        {
075            _regexp = Pattern.compile(regexp);
076        }
077        enableLogging(new SLF4JLoggerAdapter(LoggerFactory.getLogger(this.getClass())));
078    }
079    
080    /**
081     * Manual constructor
082     * @param regexp The regexp to check or null
083     * @param invalidText The error text to display
084     * @param mandatory Is the value mandatory 
085     */
086    public DefaultValidator(String regexp, I18nizableText invalidText, boolean mandatory)
087    {
088        _isMandatory = mandatory;
089        if (regexp != null)
090        {
091            _regexp = Pattern.compile(regexp);
092        }
093        _invalidText = invalidText;
094        
095        enableLogging(new SLF4JLoggerAdapter(LoggerFactory.getLogger(this.getClass())));
096    }
097    
098    @Override
099    public void service(ServiceManager smanager) throws ServiceException
100    {
101        _smanager = smanager;
102    }
103    
104    @Override
105    public void setPluginInfo(String pluginName, String featureName, String id)
106    {
107        _pluginName = pluginName;
108    }
109    
110    @Override
111    public void configure(Configuration configuration) throws ConfigurationException
112    {
113        Configuration validatorConfig = configuration.getChild("validation");
114        
115        _isMandatory = validatorConfig.getChild("mandatory", false) != null;
116
117        String regexp = validatorConfig.getChild("regexp").getValue(null);
118        if (regexp != null)
119        {
120            _regexp = Pattern.compile(regexp);
121        }
122        
123        Configuration textConfig = validatorConfig.getChild("invalidText", false);
124        if (textConfig != null)
125        {
126            _invalidText = I18nizableText.parseI18nizableText(textConfig, "plugin." + _pluginName);
127        }
128    }
129    
130    @Override
131    public Map<String, Object> getConfiguration()
132    {
133        Map<String, Object> configuration = new HashMap<>();
134        
135        configuration.put("mandatory", Boolean.valueOf(_isMandatory));
136        
137        if (_regexp != null)
138        {
139            configuration.put("regexp", _regexp);
140        }
141    
142        if (_invalidText != null)
143        {
144            configuration.put("invalidText", _invalidText);
145        }
146        
147        return configuration;
148    }
149    
150    @Override
151    public ValidationResult validate(Object value)
152    {
153        return value != null && value.getClass().isArray()
154                ? validateArrayValues((Object[]) value)
155                : validateSingleValue (value);
156    }
157    
158    /**
159     * Validates a single value.
160     * @param value the value to validate (can be <code>null</code>).
161     * @return the validation result
162     */
163    protected ValidationResult validateSingleValue (Object value)
164    {
165        ValidationResult result = new ValidationResult();
166        
167        if (_isMandatory && (value == null || value.toString().length() == 0))
168        {
169            if (getLogger().isDebugEnabled())
170            {
171                getLogger().debug("The validator refused a missing or empty value for a mandatory parameter");
172            }
173            
174            result.addError(new I18nizableText("plugin.core-ui", "PLUGINS_CORE_UI_DEFAULT_VALIDATOR_MANDATORY"));
175        }
176        
177        if (_regexp != null && value != null && value.toString().length() != 0 && !_regexp.matcher(value.toString()).matches())
178        {
179            if (getLogger().isDebugEnabled())
180            {
181                getLogger().debug("The validator refused a value for a parameter that should respect a regexep");
182            }
183
184            result.addError(new I18nizableText("plugin.core-ui", "PLUGINS_CORE_UI_DEFAULT_VALIDATOR_PATTERN_FAILED"));
185        }
186        
187        return result;
188    }
189    
190    /**
191     * Validates a array of values.
192     * @param values the values to validate
193     * @return the validation result
194     */
195    protected ValidationResult validateArrayValues (Object[] values)
196    {
197        ValidationResult result = new ValidationResult();
198        
199        if (_isMandatory && (values == null || values.length == 0))
200        {
201            if (getLogger().isDebugEnabled())
202            {
203                getLogger().debug("The validator refused a missing or empty value for a mandatory parameter");
204            }
205            
206            result.addError(new I18nizableText("plugin.core-ui", "PLUGINS_CORE_UI_DEFAULT_VALIDATOR_MANDATORY"));
207        }
208        
209        if (_regexp != null && values != null && !_matchRegexp(values))
210        {
211            if (getLogger().isDebugEnabled())
212            {
213                getLogger().debug("The validator refused a value for a parameter that should respect a regexep");
214            }
215
216            result.addError(new I18nizableText("plugin.core-ui", "PLUGINS_CORE_UI_DEFAULT_VALIDATOR_PATTERN_FAILED"));
217        }
218        
219        return result;
220    }
221    
222    private boolean _matchRegexp (Object[] values)
223    {
224        for (Object value : values)
225        {
226            if (!_regexp.matcher(value.toString()).matches())
227            {
228                return false;
229            }
230        }
231        return true;
232    }
233
234    @Override
235    public int hashCode()
236    {
237        final int prime = 31;
238        int result = 1;
239        result = prime * result + ((_invalidText == null) ? 0 : _invalidText.hashCode());
240        result = prime * result + (_isMandatory ? 1231 : 1237);
241        result = prime * result + ((_pluginName == null) ? 0 : _pluginName.hashCode());
242        result = prime * result + ((_regexp == null) ? 0 : _regexp.hashCode());
243        result = prime * result + ((_smanager == null) ? 0 : _smanager.hashCode());
244        return result;
245    }
246    
247    @Override
248    public boolean equals(Object obj)
249    {
250        // Generated method but modified to correctly compare patterns
251        if (this == obj)
252        {
253            return true;
254        }
255        if (obj == null)
256        {
257            return false;
258        }
259        if (getClass() != obj.getClass())
260        {
261            return false;
262        }
263        DefaultValidator other = (DefaultValidator) obj;
264        if (_invalidText == null)
265        {
266            if (other._invalidText != null)
267            {
268                return false;
269            }
270        }
271        else if (!_invalidText.equals(other._invalidText))
272        {
273            return false;
274        }
275        if (_isMandatory != other._isMandatory)
276        {
277            return false;
278        }
279        if (_regexp == null)
280        {
281            if (other._regexp != null)
282            {
283                return false;
284            }
285        }
286        // Beginning of the modification
287        else if (other._regexp == null)
288        {
289            return false;
290        }
291        else if (!_regexp.pattern().equals(other._regexp.pattern()))
292        {
293            return false;
294        }
295        // End of the modification
296        return true;
297    }
298}