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