001/*
002 *  Copyright 2010 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.web.site;
017
018import java.util.Collections;
019import java.util.LinkedHashMap;
020import java.util.Map;
021import java.util.Set;
022import java.util.regex.Pattern;
023
024import org.apache.avalon.framework.configuration.Configuration;
025import org.apache.avalon.framework.configuration.ConfigurationException;
026import org.apache.avalon.framework.service.ServiceException;
027import org.apache.avalon.framework.service.ServiceManager;
028
029import org.ametys.runtime.model.Enumerator;
030import org.ametys.runtime.parameter.Validator;
031import org.ametys.runtime.plugin.component.AbstractThreadSafeComponentExtensionPoint;
032import org.ametys.runtime.plugin.component.ThreadSafeComponentManager;
033
034/**
035 * Extension point holding all {@link SiteParameterWrapper} definitions.
036 */
037public class SiteConfigurationExtensionPoint extends AbstractThreadSafeComponentExtensionPoint<SiteParameterWrapper>
038{
039    /** Avalon Role */
040    public static final String ROLE = SiteConfigurationExtensionPoint.class.getName();
041    
042    private static final Pattern __PARAM_NAME_PATTERN = Pattern.compile("[a-z][a-z0-9-_]*", Pattern.CASE_INSENSITIVE);
043    
044    /** Parameter's wrappers map, indexed by parameter ID. */
045    private Map<String, SiteParameterWrapper> _parameterWrappers;
046    
047    /** ComponentManager for {@link Validator}s. */
048    private ThreadSafeComponentManager<Validator> _validatorManager;
049    
050    /** ComponentManager for {@link Enumerator}s. */
051    private ThreadSafeComponentManager<Enumerator> _enumeratorManager;
052    
053    /** Parser of parameter's wrappers */
054    private SiteParameterWrapperParser _parameterWrapperParser;
055    
056    /** Site parameter parser. */
057    private SiteParameterParser _parameterParser;
058    
059    private SiteParameterTypeExtensionPoint _siteParameterTypeEP;
060
061    
062    @Override
063    public void initialize() throws Exception
064    {
065        super.initialize();
066
067        _parameterWrappers = new LinkedHashMap<>();
068        
069        _validatorManager = new ThreadSafeComponentManager<>();
070        _validatorManager.setLogger(getLogger());
071        _validatorManager.contextualize(_context);
072        _validatorManager.service(_cocoonManager);
073        
074        _enumeratorManager = new ThreadSafeComponentManager<>();
075        _enumeratorManager.setLogger(getLogger());
076        _enumeratorManager.contextualize(_context);
077        _enumeratorManager.service(_cocoonManager);
078        
079        _parameterParser = new SiteParameterParser(_siteParameterTypeEP, _enumeratorManager, _validatorManager);
080        _parameterWrapperParser = new SiteParameterWrapperParser(_parameterParser);
081    }
082    
083    @Override
084    public void service(ServiceManager manager) throws ServiceException
085    {
086        super.service(manager);
087        _siteParameterTypeEP = (SiteParameterTypeExtensionPoint) manager.lookup(SiteParameterTypeExtensionPoint.ROLE);
088    }
089    
090    /**
091     * Dispose the manager before restarting it
092     */
093    @Override
094    public void dispose()
095    {
096        _parameterWrapperParser = null;
097        _parameterParser = null;
098        
099        _parameterWrappers = null;
100        _validatorManager.dispose();
101        _validatorManager = null;
102        _enumeratorManager.dispose();
103        _enumeratorManager = null;
104        
105        super.dispose();
106    }
107    
108    @Override
109    public boolean hasExtension(String id)
110    {
111        return _parameterWrappers.containsKey(id);
112    }
113    
114    @Override
115    public void addExtension(String id, String pluginName, String featureName, Configuration configuration) throws ConfigurationException
116    {
117        if (getLogger().isDebugEnabled())
118        {
119            getLogger().debug("Adding site parameters from feature " + pluginName + "/" + featureName);
120        }
121        
122        Configuration[] parameterConfigurations = configuration.getChildren("param");
123        for (Configuration parameterConfiguration : parameterConfigurations)
124        {
125            _addParameter(pluginName, featureName, parameterConfiguration);
126        }
127    }
128    
129    /**
130     * Declare a site parameter.
131     * @param pluginName The name of the plugin declaring the extension.
132     * @param featureName the name of the feature
133     * @param configuration The parameter configuration.
134     * @throws ConfigurationException if configuration is not complete.
135     */
136    protected void _addParameter(String pluginName, String featureName, Configuration configuration) throws ConfigurationException
137    {
138        SiteParameterWrapper parameter = _parameterWrapperParser.parse(_cocoonManager, pluginName, configuration);
139        
140        String name = parameter.getDefinition().getName();
141        
142        if (!__PARAM_NAME_PATTERN.matcher(name).matches())
143        {
144            throw new ConfigurationException("The feature " + pluginName + "/" + featureName + " declared an invalid site parameter name '" + name + "'. This value is not permited: only [a-zA-Z][a-zA-Z0-9-_]* are allowed.", configuration);
145        }
146        
147        if (_parameterWrappers.containsKey(name))
148        {
149            throw new ConfigurationException("In feature " + pluginName + "/" + featureName + " the parameter '" + name + "' is already declared. Parameter ids must be unique.", configuration);
150        }
151        
152        _parameterWrappers.put(name, parameter);
153        
154        if (getLogger().isDebugEnabled())
155        {
156            getLogger().debug("Site parameter added: " + name);
157        }
158    }
159    
160    @Override
161    public SiteParameterWrapper getExtension(String id)
162    {
163        if (hasExtension(id))
164        {
165            return _parameterWrappers.get(id);
166        }
167        else
168        {
169            throw new IllegalArgumentException("There is no site parameter named '" + id + "'.");
170        }
171    }
172    
173    @Override
174    public Set<String> getExtensionsIds()
175    {
176        return Collections.unmodifiableSet(_parameterWrappers.keySet());
177    }
178    
179    @Override
180    public void initializeExtensions() throws Exception
181    {
182        super.initializeExtensions();
183        _parameterParser.lookupComponents();
184    }
185}