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.plugins.contentio.synchronize.impl;
017
018import java.util.Collection;
019import java.util.LinkedHashMap;
020import java.util.Map;
021
022import org.apache.avalon.framework.activity.Disposable;
023import org.apache.avalon.framework.configuration.Configurable;
024import org.apache.avalon.framework.configuration.Configuration;
025import org.apache.avalon.framework.configuration.ConfigurationException;
026import org.apache.avalon.framework.context.Context;
027import org.apache.avalon.framework.context.ContextException;
028import org.apache.avalon.framework.context.Contextualizable;
029import org.apache.avalon.framework.service.ServiceException;
030import org.apache.avalon.framework.service.ServiceManager;
031import org.apache.avalon.framework.service.Serviceable;
032
033import org.ametys.plugins.contentio.synchronize.SynchronizableContentsCollection;
034import org.ametys.plugins.contentio.synchronize.SynchronizableContentsCollectionModel;
035import org.ametys.plugins.contentio.synchronize.SynchronizableContentsCollectionModelParameterParser;
036import org.ametys.runtime.config.ConfigParameterTypeExtensionPoint;
037import org.ametys.runtime.i18n.I18nizableText;
038import org.ametys.runtime.model.Enumerator;
039import org.ametys.runtime.model.ModelItem;
040import org.ametys.runtime.parameter.Validator;
041import org.ametys.runtime.plugin.component.AbstractLogEnabled;
042import org.ametys.runtime.plugin.component.PluginAware;
043import org.ametys.runtime.plugin.component.ThreadSafeComponentManager;
044
045/**
046 * Implementation of {@link SynchronizableContentsCollectionModel} able to populate contents from a LDAP source
047 *
048 */
049public class DefaultSynchronizableContentsCollectionModel extends AbstractLogEnabled implements SynchronizableContentsCollectionModel, Serviceable, Contextualizable, PluginAware, Configurable, Disposable
050{
051    private ConfigParameterTypeExtensionPoint _sccParameterTypeExtensionPoint;
052    private ServiceManager _manager;
053    private Context _context;
054    
055    // ComponentManager for validators
056    private ThreadSafeComponentManager<Validator> _validatorManager;
057    
058    // ComponentManager for enumerators
059    private ThreadSafeComponentManager<Enumerator> _enumeratorManager;
060    
061    private String _id;
062    private Class<SynchronizableContentsCollection> _syncCollectionClass;
063    private I18nizableText _label;
064    private I18nizableText _description;
065    private Map<String, ModelItem> _parameters = new LinkedHashMap<>();
066    private String _pluginName;
067    
068    public void service(ServiceManager manager) throws ServiceException
069    {
070        _manager = manager;
071        _sccParameterTypeExtensionPoint = (ConfigParameterTypeExtensionPoint) manager.lookup(ConfigParameterTypeExtensionPoint.ROLE);
072    }
073    
074    public void contextualize(Context context) throws ContextException
075    {
076        _context = context;
077    }
078    
079    @Override
080    public void setPluginInfo(String pluginName, String featureName, String id)
081    {
082        _pluginName = pluginName;
083        _id = id;
084    }
085    
086    @SuppressWarnings("unchecked")
087    public void configure(Configuration configuration) throws ConfigurationException
088    {
089        _label = I18nizableText.parseI18nizableText(configuration.getChild("label"), "plugin." + _pluginName);
090        _description = I18nizableText.parseI18nizableText(configuration.getChild("description"), "plugin." + _pluginName);
091        
092        String className = null;
093        try
094        {
095            className = configuration.getChild("class").getAttribute("name");
096            _syncCollectionClass = (Class<SynchronizableContentsCollection>) Class.forName(className);
097        }
098        catch (ClassNotFoundException | ConfigurationException e)
099        {
100            throw new ConfigurationException("SynchronizableContentsCollection model with id '" + _id + "' has an invalid configuration for class name " + (className != null ? className + " <class not found>" : "<missing tag <class>") + "'", e);
101        }
102        
103        if (!SynchronizableContentsCollection.class.isAssignableFrom(_syncCollectionClass))
104        {
105            throw new ConfigurationException("SynchronizableContentsCollection model with id '" + _id + "' has an invalid configuration: '" + className + "' is not an instance of SynchronizableContentsCollection");
106        }
107        
108        configureParameters(configuration);
109    }
110    
111    /**
112     * Configure the SCC parameters
113     * @param configuration the model configuration
114     * @throws ConfigurationException if a configuration exception occurred
115     */
116    protected void configureParameters(Configuration configuration) throws ConfigurationException
117    {
118        _validatorManager = new ThreadSafeComponentManager<>();
119        _validatorManager.setLogger(getLogger());
120        _validatorManager.contextualize(_context);
121        _validatorManager.service(_manager);
122        
123        _enumeratorManager = new ThreadSafeComponentManager<>();
124        _enumeratorManager.setLogger(getLogger());
125        _enumeratorManager.contextualize(_context);
126        _enumeratorManager.service(_manager);
127        
128        SynchronizableContentsCollectionModelParameterParser sccParametersParser = new SynchronizableContentsCollectionModelParameterParser(_sccParameterTypeExtensionPoint, _enumeratorManager, _validatorManager);
129        
130        Configuration parametersConfiguration = configuration.getChild("parameters");
131        Configuration[] paramsConfiguration = parametersConfiguration.getChildren("param");
132        for (Configuration paramConfiguration : paramsConfiguration)
133        {
134            ModelItem parameter = sccParametersParser.parse(_manager, _pluginName, "plugin." + _pluginName, paramConfiguration, this, null);
135            String parameterPath = parameter.getPath();
136            
137            if (_parameters.containsKey(parameterPath))
138            {
139                throw new ConfigurationException("The parameter '" + parameterPath + "' is already declared. IDs must be unique.", paramConfiguration);
140            }
141            
142            _parameters.put(parameterPath, parameter);
143        }
144        
145        try
146        {
147            sccParametersParser.lookupComponents();
148        }
149        catch (Exception e)
150        {
151            throw new ConfigurationException("Unable to lookup parameter local components", configuration, e);
152        }
153    }
154    
155    @Override
156    public void dispose()
157    {
158        _validatorManager.dispose();
159        _validatorManager = null;
160        
161        _enumeratorManager.dispose();
162        _enumeratorManager = null;
163    }
164    
165    @Override
166    public String getId()
167    {
168        return _id;
169    }
170
171    @Override
172    public I18nizableText getLabel()
173    {
174        return _label;
175    }
176
177    @Override
178    public I18nizableText getDescription()
179    {
180        return _description;
181    }
182
183    @Override
184    public Collection<ModelItem> getModelItems()
185    {
186        return _parameters.values();
187    }
188    
189    @Override
190    public String getPluginName()
191    {
192        return _pluginName;
193    }
194
195    @Override
196    public Class<SynchronizableContentsCollection> getSynchronizableCollectionClass()
197    {
198        return _syncCollectionClass;
199    }
200}