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");
220                if (site.hasValue(parameter.getName()))
221                {
222                    sb.append(" with value '");
223                    try
224                    {
225                        sb.append(parameter.getType().toString(value));
226                    }
227                    catch (Exception e)
228                    {
229                        sb.append(value.toString());
230                    }
231                    sb.append("'");
232                }
233                else
234                {
235                    sb.append(" with empty value");
236                }
237                sb.append(":");
238                
239                for (I18nizableText error : errors)
240                {
241                    sb.append("\n* " + error.toString());
242                }
243                
244                sb.append("\nConfiguration is not initialized");
245
246                getLogger().warn(sb.toString());
247            }
248
249            return false;
250        }
251
252        return true;
253    }
254    
255    /**
256     * Retrieves the parameters of the given site
257     * @param siteName the name of the site
258     * @return the site's parameters
259     */
260    public Collection<ElementDefinition> getSiteParameters(String siteName)
261    {
262        Site site = _siteManager.getSite(siteName);
263        return getSiteParameters(site);
264    }
265    
266    /**
267     * Retrieves the parameters of the given site
268     * @param site the site
269     * @return the site's parameters
270     */
271    public Collection<ElementDefinition> getSiteParameters(Site site)
272    {
273        SiteType siteType = _siteTypesExtensionPoint.getExtension(site.getType());
274        return siteType.getModelItems();
275    }
276    
277    /**
278     * Retrieves the parameter of the given site with the given name
279     * @param siteName the name of the site
280     * @param parameterName the name of the parameter to retrieve
281     * @return the site's parameter
282     * @throws UndefinedItemPathException if there is no site parameter defined with the given name
283     */
284    public ElementDefinition getSiteParameter(String siteName, String parameterName) throws UndefinedItemPathException
285    {
286        Site site = _siteManager.getSite(siteName);
287        return getSiteParameter(site, parameterName);
288    }
289    
290    /**
291     * Retrieves the parameter of the given site with the given name
292     * @param site the site
293     * @param parameterName the name of the parameter to retrieve
294     * @return the site's parameter
295     * @throws UndefinedItemPathException if there is no site parameter defined with the given name
296     */
297    public ElementDefinition getSiteParameter(Site site, String parameterName) throws UndefinedItemPathException
298    {
299        SiteType siteType = _siteTypesExtensionPoint.getExtension(site.getType());
300        return siteType.getModelItem(parameterName);
301    }
302
303    /**
304     * Retrieves the view of the site with the given name
305     * @param siteName the name of the site
306     * @return the site's view
307     */
308    public View getSiteView(String siteName)
309    {
310        Site site = _siteManager.getSite(siteName);
311        return getSiteView(site);
312    }
313
314    /**
315     * Retrieves the view of the site with the given name
316     * @param site the site
317     * @return the site's view
318     */
319    public View getSiteView(Site site)
320    {
321        SiteType siteType = _siteTypesExtensionPoint.getExtension(site.getType());
322        return siteType.getView();
323    }
324}