001/*
002 *  Copyright 2016 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.core.datasource;
017
018import java.util.HashSet;
019import java.util.Map;
020import java.util.Set;
021import java.util.regex.Pattern;
022
023import org.apache.avalon.framework.configuration.Configuration;
024import org.apache.avalon.framework.configuration.ConfigurationException;
025import org.apache.commons.collections.CollectionUtils;
026import org.apache.commons.lang3.StringUtils;
027
028import org.ametys.core.datasource.AbstractDataSourceManager.DataSourceDefinition;
029import org.ametys.runtime.i18n.I18nizableText;
030import org.ametys.runtime.parameter.DefaultValidator;
031import org.ametys.runtime.parameter.Errors;
032
033/**
034 * This validator validates that a type of SQL data sources is an authorized database type  
035 *
036 */
037public class SQLDatabaseTypeValidator extends DefaultValidator
038{
039    private Set<String> _allowedDbTypes;
040    
041    @Override
042    public void configure(Configuration configuration) throws ConfigurationException
043    {
044        _allowedDbTypes = new HashSet<>();
045        
046        Configuration validatorConfig = configuration.getChild("validation").getChild("custom-validator");
047        
048        _isMandatory = validatorConfig.getChild("mandatory", false) != null;
049
050        String regexp = validatorConfig.getChild("regexp").getValue(null);
051        if (regexp != null)
052        {
053            _regexp = Pattern.compile(regexp);
054        }
055        
056        Configuration textConfig = validatorConfig.getChild("invalidText", false);
057        if (textConfig != null)
058        {
059            _invalidText = I18nizableText.parseI18nizableText(textConfig, "plugin." + _pluginName);
060        }
061        
062        
063        Configuration dbtypesConfig = validatorConfig.getChild("allowed-dbtypes", false);
064        if (dbtypesConfig != null)
065        {
066            String[] dbtypes = dbtypesConfig.getValue().split(",");
067            for (String dbtype : dbtypes)
068            {
069                CollectionUtils.addIgnoreNull(_allowedDbTypes, StringUtils.trimToNull(dbtype));
070            }
071        }
072    }
073    
074    /**
075     * Validates a single value.
076     * @param value the value to validate (can be <code>null</code>).
077     * @param errors the structure to populate if the validation failed.
078     */
079    @Override
080    protected void validateSingleValue (Object value, Errors errors)
081    {
082        super.validateSingleValue(value, errors);
083        
084        if (_allowedDbTypes.size() > 0 && value != null && value.toString().length() > 0)
085        {
086            String dataSourceId = value.toString();
087            _validateDataSource(dataSourceId, errors);
088        }
089    }
090    
091    @Override
092    protected void validateArrayValues (Object[] values, Errors errors)
093    {
094        if (_allowedDbTypes.size() > 0 && values != null && values.length > 0)
095        {
096            for (Object value : values)
097            {
098                String dataSourceId = value.toString();
099                _validateDataSource(dataSourceId, errors);
100            }
101        }
102    }
103    
104    private void _validateDataSource (String dataSourceId, Errors errors)
105    {
106        if (!_isValidDatasource(dataSourceId))
107        {
108            if (getLogger().isDebugEnabled())
109            {
110                getLogger().debug("The type of datasource of id '" + dataSourceId + "' is not an authorized database type.");
111            }
112            
113            errors.addError(new I18nizableText("plugin.core", "PLUGINS_CORE_SQL_DATASOURCETYPE_VALIDATOR_FAILED"));
114        }
115    }
116    
117    private boolean _isValidDatasource (String dataSourceId)
118    {
119        // FIXME Add a static method to get all data source definition in safe-mode ?
120        
121        // Use static method because the SQLDataSourceManager may be not initialized yet
122        Map<String, DataSourceDefinition> dsDefinitions = SQLDataSourceManager.readDataSourceDefinition(SQLDataSourceManager.getStaticFileConfiguration());
123        
124        // Add the default datasource
125        boolean findDefault = false;
126        for (DataSourceDefinition dsDefinition : dsDefinitions.values())
127        {
128            if (dsDefinition.isDefault())
129            {
130                dsDefinitions.put(SQLDataSourceManager.SQL_DATASOURCE_PREFIX + AbstractDataSourceManager.DEFAULT_DATASOURCE_SUFFIX, dsDefinition.duplicate());
131                findDefault = true;
132                break;
133            }
134        }
135        
136        // Add the internal data source
137        DataSourceDefinition internalDsDefinition = SQLDataSourceManager.getInternalDataSourceDefinition();
138        dsDefinitions.put(internalDsDefinition.getId(), internalDsDefinition);
139        
140        if (!findDefault)
141        {
142            // The internal db is the default data source
143            dsDefinitions.put(SQLDataSourceManager.SQL_DATASOURCE_PREFIX + AbstractDataSourceManager.DEFAULT_DATASOURCE_SUFFIX, internalDsDefinition.duplicate());
144        }
145        
146        if (dsDefinitions.containsKey(dataSourceId))
147        {
148            String dbtype = (String) dsDefinitions.get(dataSourceId).getParameters().get(SQLDataSourceManager.PARAM_DATABASE_TYPE);
149            return _allowedDbTypes.contains(dbtype);
150        }
151        
152        return false;
153    }
154    
155    @Override
156    public Map<String, Object> getConfiguration()
157    {
158        Map<String, Object> configuration = super.getConfiguration();
159        configuration.put("allowedDbTypes", _allowedDbTypes);
160        return configuration;
161    }
162
163    @Override
164    public int hashCode()
165    {
166        final int prime = 31;
167        int result = super.hashCode();
168        result = prime * result + ((_allowedDbTypes == null) ? 0 : _allowedDbTypes.hashCode());
169        return result;
170    }
171
172    @Override
173    public boolean equals(Object obj)
174    {
175        if (this == obj)
176        {
177            return true;
178        }
179        if (!super.equals(obj))
180        {
181            return false;
182        }
183        if (getClass() != obj.getClass())
184        {
185            return false;
186        }
187        SQLDatabaseTypeValidator other = (SQLDatabaseTypeValidator) obj;
188        if (_allowedDbTypes == null)
189        {
190            if (other._allowedDbTypes != null)
191            {
192                return false;
193            }
194        }
195        else if (!_allowedDbTypes.equals(other._allowedDbTypes))
196        {
197            return false;
198        }
199        return true;
200    }
201
202    
203}