001/*
002 *  Copyright 2019 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.Collection;
019import java.util.HashMap;
020import java.util.Iterator;
021import java.util.List;
022import java.util.Map;
023
024import org.apache.avalon.framework.activity.Disposable;
025import org.apache.avalon.framework.activity.Initializable;
026import org.apache.avalon.framework.component.Component;
027import org.apache.avalon.framework.service.ServiceException;
028import org.apache.avalon.framework.service.ServiceManager;
029import org.apache.avalon.framework.service.Serviceable;
030
031import org.ametys.plugins.repository.UnknownAmetysObjectException;
032import org.ametys.runtime.i18n.I18nizableText;
033import org.ametys.runtime.model.ElementDefinition;
034import org.ametys.runtime.model.ModelHelper;
035import org.ametys.runtime.model.View;
036import org.ametys.runtime.model.exception.UndefinedItemPathException;
037import org.ametys.runtime.plugin.component.AbstractLogEnabled;
038import org.ametys.web.repository.site.Site;
039import org.ametys.web.repository.site.SiteManager;
040import org.ametys.web.repository.site.SiteType;
041import org.ametys.web.repository.site.SiteTypesExtensionPoint;
042
043/**
044 * Helper component for managing sites configuration.
045 */
046public class SiteConfigurationManager extends AbstractLogEnabled implements Component, Serviceable, Initializable, Disposable
047{
048    /** Avalon Role */
049    public static final String ROLE = SiteConfigurationManager.class.getName();
050    
051    /** The site manager. */
052    protected SiteManager _siteManager;
053    /** The site type extension point. */
054    protected SiteTypesExtensionPoint _siteTypesExtensionPoint;
055    
056    /** Determines if all parameters are valued, by site. */
057    protected Map<String, Boolean> _areSiteComplete;
058    
059    public void service(ServiceManager manager) throws ServiceException
060    {
061        _siteManager = (SiteManager) manager.lookup(SiteManager.ROLE);
062        _siteTypesExtensionPoint = (SiteTypesExtensionPoint) manager.lookup(SiteTypesExtensionPoint.ROLE);
063    }
064
065    public void initialize() throws Exception
066    {
067        _areSiteComplete = new HashMap<>();
068    }
069    
070    public void dispose()
071    {
072        _areSiteComplete = new HashMap<>();
073    }
074    
075    /**
076     * Reload a site's configuration.
077     * @param siteName the site name.
078     * @throws UnknownAmetysObjectException if the site doesn't exist.
079     */
080    public void reloadSiteConfiguration(String siteName) throws UnknownAmetysObjectException
081    {
082        // Check if the site exists.
083        Site site = _siteManager.getSite(siteName);
084        
085        // Reload the site configuration.
086        reloadSiteConfiguration(site);
087    }
088    
089    /**
090     * Reload a site's configuration.
091     * @param site the site.
092     * @throws UnknownAmetysObjectException if the site doesn't exist.
093     */
094    public void reloadSiteConfiguration(Site site) throws UnknownAmetysObjectException
095    {
096        // Reload the site configuration.
097        _areSiteComplete.put(site.getName(), _isSiteConfigurationValid(site));
098    }
099
100    /**
101     * Remove a site's configuration.
102     * @param site the site.
103     */
104    public void removeSiteConfiguration(Site site)
105    {
106        removeSiteConfiguration(site.getName());
107    }
108
109    /**
110     * Remove a site's configuration.
111     * @param siteName the site name.
112     */
113    public void removeSiteConfiguration(String siteName)
114    {
115        if (_areSiteComplete.containsKey(siteName))
116        {
117            _areSiteComplete.remove(siteName);
118        }
119    }
120    
121    /**
122     * Validate the configuration of the given site.
123     * @param siteName the name of the site to check.
124     * @return <code>true</code> if the site is correctly configured, <code>false</code> otherwise.
125     * @throws UnknownAmetysObjectException if the site doesn't exist.
126     */
127    public boolean isSiteConfigurationValid(String siteName) throws UnknownAmetysObjectException
128    {
129        if (siteName == null)
130        {
131            throw new IllegalArgumentException("Cannot determine if a null siteName is valid or not");
132        }
133
134        // Check if the site exists.
135        if (!_siteManager.hasSite(siteName))
136        {
137            throw new UnknownAmetysObjectException ("Unknown site '" + siteName + "'. Can not check configuration.");
138        }
139
140        // Validate the site configuration now if it's not already done.
141        Site site = _siteManager.getSite(siteName);
142        return isSiteConfigurationValid(site);
143    }
144    
145    /**
146     * Validate the configuration of the given site.
147     * @param site the site to check.
148     * @return <code>true</code> if the site is correctly configured, <code>false</code> otherwise.
149     * @throws UnknownAmetysObjectException if the site doesn't exist.
150     */
151    public boolean isSiteConfigurationValid(Site site) throws UnknownAmetysObjectException
152    {
153        if (site == null)
154        {
155            throw new IllegalArgumentException("Cannot determine if a null site is valid or not");
156        }
157
158        // Validate the site configuration now if it's not already done.
159        if (!_areSiteComplete.containsKey(site.getName()))
160        {
161            _areSiteComplete.put(site.getName(), _isSiteConfigurationValid(site));
162        }
163
164        return _areSiteComplete.get(site.getName());
165    }
166
167    /**
168     * Validate the configuration of the given site.
169     * @param site the site to check.
170     * @return <code>true</code> if the site is correctly configured, <code>false</code> otherwise.
171     */
172    protected boolean _isSiteConfigurationValid(Site site)
173    {
174        if (getLogger().isDebugEnabled())
175        {
176            getLogger().debug("Validating the configuration of site '" + site + "'");
177        }
178
179        SiteType siteType = _siteTypesExtensionPoint.getExtension(site.getType());
180        if (siteType == null)
181        {
182            getLogger().error("Site " + site.getName() + " has the unknown type '" + site.getType() + "'" );
183            return false;
184        }
185        
186        boolean areParametersValid = true;
187
188        Iterator<ElementDefinition> definitionsIterator = siteType.getModelItems().iterator();
189        while (definitionsIterator.hasNext() && areParametersValid)
190        {
191            ElementDefinition item = definitionsIterator.next();
192            areParametersValid = _isValidSiteParameter(item, site);
193        }
194        
195        return areParametersValid;
196    }
197    
198    /**
199     * Validate the the given site parameter
200     * @param parameter the site parameter to validate.
201     * @param site the site
202     * @return true if the parameter's value is valid, false otherwise.
203     */
204    protected boolean _isValidSiteParameter(ElementDefinition parameter, Site site)
205    {
206        // TODO RUNTIME-2897: call the validateValue without boolean when multiple values are managed in enumerators
207        Object value = site.getValue(parameter.getName(), true, null);
208        List<I18nizableText> errors = ModelHelper.validateValue(parameter, value, false);
209        if (!errors.isEmpty())
210        {
211            if (getLogger().isWarnEnabled())
212            {
213                StringBuffer sb = new StringBuffer();
214
215                sb.append("The parameter '")
216                    .append(parameter.getPath())
217                    .append("' of site '")
218                    .append(site.getName())
219                    .append("' is not valid with value '")
220                    .append(parameter.getType().toString(value))
221                    .append("':");
222                
223                for (I18nizableText error : errors)
224                {
225                    sb.append("\n* " + error.toString());
226                }
227                
228                sb.append("\nConfiguration is not initialized");
229
230                getLogger().warn(sb.toString());
231            }
232
233            return false;
234        }
235
236        return true;
237    }
238    
239    /**
240     * Retrieves the parameters of the given site
241     * @param siteName the name of the site
242     * @return the site's parameters
243     */
244    public Collection<ElementDefinition> getSiteParameters(String siteName)
245    {
246        Site site = _siteManager.getSite(siteName);
247        return getSiteParameters(site);
248    }
249    
250    /**
251     * Retrieves the parameters of the given site
252     * @param site the site
253     * @return the site's parameters
254     */
255    public Collection<ElementDefinition> getSiteParameters(Site site)
256    {
257        SiteType siteType = _siteTypesExtensionPoint.getExtension(site.getType());
258        return siteType.getModelItems();
259    }
260    
261    /**
262     * Retrieves the parameter of the given site with the given name
263     * @param siteName the name of the site
264     * @param parameterName the name of the parameter to retrieve
265     * @return the site's parameter
266     * @throws UndefinedItemPathException if there is no site parameter defined with the given name
267     */
268    public ElementDefinition getSiteParameter(String siteName, String parameterName) throws UndefinedItemPathException
269    {
270        Site site = _siteManager.getSite(siteName);
271        return getSiteParameter(site, parameterName);
272    }
273    
274    /**
275     * Retrieves the parameter of the given site with the given name
276     * @param site the site
277     * @param parameterName the name of the parameter to retrieve
278     * @return the site's parameter
279     * @throws UndefinedItemPathException if there is no site parameter defined with the given name
280     */
281    public ElementDefinition getSiteParameter(Site site, String parameterName) throws UndefinedItemPathException
282    {
283        SiteType siteType = _siteTypesExtensionPoint.getExtension(site.getType());
284        return siteType.getModelItem(parameterName);
285    }
286
287    /**
288     * Retrieves the view of the site with the given name
289     * @param siteName the name of the site
290     * @return the site's view
291     */
292    public View getSiteView(String siteName)
293    {
294        Site site = _siteManager.getSite(siteName);
295        return getSiteView(site);
296    }
297
298    /**
299     * Retrieves the view of the site with the given name
300     * @param site the site
301     * @return the site's view
302     */
303    public View getSiteView(Site site)
304    {
305        SiteType siteType = _siteTypesExtensionPoint.getExtension(site.getType());
306        return siteType.getView();
307    }
308}