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