001/* 002 * Copyright 2020 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.parameters.view; 017 018import java.io.InputStream; 019import java.util.ArrayList; 020import java.util.HashMap; 021import java.util.List; 022import java.util.Map; 023import java.util.Optional; 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.configuration.Configuration; 029import org.apache.avalon.framework.configuration.ConfigurationException; 030import org.apache.avalon.framework.configuration.DefaultConfigurationBuilder; 031import org.apache.avalon.framework.context.Context; 032import org.apache.avalon.framework.context.ContextException; 033import org.apache.avalon.framework.context.Contextualizable; 034import org.apache.avalon.framework.service.ServiceException; 035import org.apache.avalon.framework.service.ServiceManager; 036import org.apache.avalon.framework.service.Serviceable; 037import org.apache.commons.lang.StringUtils; 038import org.apache.excalibur.source.Source; 039import org.apache.excalibur.source.SourceNotFoundException; 040 041import org.ametys.cms.data.holder.group.DataHolderRepeaterDefinitionParser; 042import org.ametys.core.util.filereloader.FileReloader; 043import org.ametys.core.util.filereloader.FileReloaderUtils; 044import org.ametys.runtime.model.Enumerator; 045import org.ametys.runtime.model.View; 046import org.ametys.runtime.model.disableconditions.DisableConditions; 047import org.ametys.runtime.parameter.Validator; 048import org.ametys.runtime.plugin.component.AbstractLogEnabled; 049import org.ametys.runtime.plugin.component.ThreadSafeComponentManager; 050import org.ametys.web.data.type.ModelItemTypeExtensionPoint; 051import org.ametys.web.parameters.ViewAndParametersParser; 052import org.ametys.web.parameters.ViewAndParametersParser.ViewAndParameters; 053 054/** 055 * Manager for global view parameters 056 */ 057public class GlobalViewParametersManager extends AbstractLogEnabled implements Component, Serviceable, Contextualizable, Initializable, Disposable 058{ 059 /** Avalon Role */ 060 public static final String ROLE = GlobalViewParametersManager.class.getName(); 061 062 /** The file reloader utils */ 063 protected FileReloaderUtils _fileReloaderUtils; 064 065 /** The view parameter type extension point */ 066 protected ModelItemTypeExtensionPoint _viewParametersEP; 067 068 /** The view and parameters parser */ 069 protected ViewAndParametersParser _viewAndParametersParser; 070 071 /** The avalon context */ 072 protected Context _context; 073 074 /** The service manager */ 075 protected ServiceManager _manager; 076 077 /** The object representing the global view parameters by skin */ 078 protected SkinsGlobalViewParameters _skinsGlobalViewParameters; 079 080 private List<ThreadSafeComponentManager> _components; 081 082 public void service(ServiceManager manager) throws ServiceException 083 { 084 _manager = manager; 085 _fileReloaderUtils = (FileReloaderUtils) manager.lookup(FileReloaderUtils.ROLE); 086 _viewParametersEP = (ModelItemTypeExtensionPoint) manager.lookup(ModelItemTypeExtensionPoint.ROLE_VIEW_PARAM); 087 _viewAndParametersParser = (ViewAndParametersParser) manager.lookup(ViewAndParametersParser.ROLE); 088 } 089 090 public void contextualize(Context context) throws ContextException 091 { 092 _context = context; 093 } 094 095 public void initialize() throws Exception 096 { 097 _skinsGlobalViewParameters = new SkinsGlobalViewParameters(); 098 _components = new ArrayList<>(); 099 } 100 101 /** 102 * The view parameters type 103 */ 104 public enum ViewParametersType 105 { 106 /** View parameters for template */ 107 TEMPLATES, 108 /** View parameters for zone */ 109 ZONES, 110 /** View parameters for zone item */ 111 ZONEITEMS, 112 /** View parameters for service */ 113 SERVICES, 114 /** View parameters for content */ 115 CONTENTS 116 } 117 118 /** 119 * Get global view parameters for one type (template, zone, zone item, service or content) 120 * @param skinId the skin id 121 * @param type the type 122 * @return the view parameters 123 */ 124 public Optional<ViewParametersModel> getViewParameters(String skinId, ViewParametersType type) 125 { 126 String sourceUrl = "skin:" + skinId + "://conf/parameters.xml"; 127 try 128 { 129 _fileReloaderUtils.updateFile(sourceUrl, new GlobalViewParametersReloader(skinId, this)); 130 } 131 catch (SourceNotFoundException e) 132 { 133 // Do nothing, the parameter xml file doesn't exist 134 } 135 catch (Exception e) 136 { 137 getLogger().error("Failed to read the global parameters file '{}'. It will be ignored", sourceUrl, e); 138 } 139 140 return _skinsGlobalViewParameters.getGlobalViewParameters(skinId, type); 141 } 142 143 /** 144 * Class representing a global view parameters reloader 145 */ 146 public static class GlobalViewParametersReloader implements FileReloader 147 { 148 private String _skinId; 149 private GlobalViewParametersManager _globalViewParameterManager; 150 151 /** 152 * Constructor for the reloader 153 * @param skinId the skin id 154 * @param manager the global view parameters manager 155 */ 156 public GlobalViewParametersReloader (String skinId, GlobalViewParametersManager manager) 157 { 158 _skinId = skinId; 159 _globalViewParameterManager = manager; 160 } 161 162 /** 163 * Get the skin id 164 * @return the skin id 165 */ 166 public String getSkinId() 167 { 168 return _skinId; 169 } 170 171 /** 172 * Get the global view parameters manager 173 * @return the global view parameters manager 174 */ 175 public GlobalViewParametersManager getGlobalViewParameterManager() 176 { 177 return _globalViewParameterManager; 178 } 179 180 public void updateFile(String sourceUrl, Source source, InputStream is) throws Exception 181 { 182 if (is != null) 183 { 184 GlobalViewParametersManager manager = getGlobalViewParameterManager(); 185 186 manager._disposeComponents(); 187 188 String skinId = getSkinId(); 189 String plugin = "web"; // default plugin for enumerator and validator component 190 String catalog = "skin." + getSkinId(); 191 192 Configuration conf = new DefaultConfigurationBuilder().build(is); 193 194 manager._addViewParameters(conf, skinId, ViewParametersType.TEMPLATES, plugin, catalog); 195 manager._addViewParameters(conf, skinId, ViewParametersType.ZONES, plugin, catalog); 196 manager._addViewParameters(conf, skinId, ViewParametersType.ZONEITEMS, plugin, catalog); 197 manager._addViewParameters(conf, skinId, ViewParametersType.SERVICES, plugin, catalog); 198 manager._addViewParameters(conf, skinId, ViewParametersType.CONTENTS, plugin, catalog); 199 200 } 201 } 202 203 public String getId(String sourceUrl) 204 { 205 return GlobalViewParametersManager.class.getName() + "#" + getSkinId(); 206 } 207 } 208 209 /** 210 * Add view parameters from the configuration of a given type 211 * @param paramConfiguration the configuration 212 * @param skinId the skin Id 213 * @param type the type 214 * @param plugin the plugin 215 * @param catalog the catalog 216 * @throws ConfigurationException if a configuration error occurred 217 */ 218 protected void _addViewParameters(Configuration paramConfiguration, String skinId, ViewParametersType type, String plugin, String catalog) throws ConfigurationException 219 { 220 String viewParametersId = skinId + "_" + StringUtils.lowerCase(type.name()) + "_global_view_parameters"; 221 222 Configuration typeParamConfiguration = paramConfiguration.getChild(StringUtils.lowerCase(type.name())); 223 Optional<ViewParametersModel> viewParameters = _configureViewParameters(typeParamConfiguration, viewParametersId, plugin, catalog); 224 225 _skinsGlobalViewParameters.addGlobalViewParameters(skinId, type, viewParameters); 226 } 227 228 /** 229 * Parse global view parameters from the configuration 230 * @param paramConfiguration the configuration 231 * @param viewParametersId the view parameters id 232 * @param plugin the plugin 233 * @param catalog the catalog 234 * @return the view parameters 235 * @throws ConfigurationException if a configuration error occurred 236 */ 237 protected Optional<ViewParametersModel> _configureViewParameters(Configuration paramConfiguration, String viewParametersId, String plugin, String catalog) throws ConfigurationException 238 { 239 ThreadSafeComponentManager<DisableConditions> parametersDisableConditionsManager = new ThreadSafeComponentManager<>(); 240 parametersDisableConditionsManager.setLogger(getLogger()); 241 parametersDisableConditionsManager.contextualize(_context); 242 parametersDisableConditionsManager.service(_manager); 243 _components.add(parametersDisableConditionsManager); 244 245 ThreadSafeComponentManager<DisableConditions> repeaterDisableConditionsManager = new ThreadSafeComponentManager<>(); 246 repeaterDisableConditionsManager.setLogger(getLogger()); 247 repeaterDisableConditionsManager.contextualize(_context); 248 repeaterDisableConditionsManager.service(_manager); 249 _components.add(repeaterDisableConditionsManager); 250 251 ThreadSafeComponentManager<Validator> validatorManager = new ThreadSafeComponentManager<>(); 252 validatorManager.setLogger(getLogger()); 253 validatorManager.contextualize(_context); 254 validatorManager.service(_manager); 255 _components.add(validatorManager); 256 257 ThreadSafeComponentManager<Enumerator> enumeratorManager = new ThreadSafeComponentManager<>(); 258 enumeratorManager.setLogger(getLogger()); 259 enumeratorManager.contextualize(_context); 260 enumeratorManager.service(_manager); 261 _components.add(enumeratorManager); 262 263 ViewParametersModel viewParameters = new ViewParametersModel(viewParametersId, new View(), new HashMap<>()); 264 265 ViewParameterDefinitionParser elementDefinitionParser = new ViewParameterDefinitionParser(_viewParametersEP, parametersDisableConditionsManager, enumeratorManager, validatorManager); 266 DataHolderRepeaterDefinitionParser repeaterDefinitionParser = new DataHolderRepeaterDefinitionParser(_viewParametersEP, repeaterDisableConditionsManager); 267 268 ViewAndParameters viewAndParameters = _viewAndParametersParser.parseParameters(paramConfiguration, plugin, catalog, viewParameters, elementDefinitionParser, repeaterDefinitionParser); 269 viewParameters.setView(viewAndParameters.getView()); 270 viewParameters.setModelItems(viewAndParameters.getParameters()); 271 272 try 273 { 274 elementDefinitionParser.lookupComponents(); 275 repeaterDefinitionParser.lookupComponents(); 276 } 277 catch (Exception e) 278 { 279 throw new ConfigurationException("Unable to lookup parameter local components", paramConfiguration, e); 280 } 281 282 return Optional.ofNullable(viewParameters); 283 } 284 285 public void dispose() 286 { 287 _disposeComponents(); 288 } 289 290 private void _disposeComponents() 291 { 292 for (ThreadSafeComponentManager component : _components) 293 { 294 component.dispose(); 295 } 296 } 297 298 static class SkinsGlobalViewParameters 299 { 300 Map<String, SkinWrapper> _globalViewParametersBySkin; 301 302 SkinsGlobalViewParameters() 303 { 304 this._globalViewParametersBySkin = new HashMap<>(); 305 } 306 307 Optional<ViewParametersModel> getGlobalViewParameters(String skinId, ViewParametersType type) 308 { 309 SkinWrapper skin = _globalViewParametersBySkin.getOrDefault(skinId, new SkinWrapper()); 310 return skin.getGlobalViewParameters(type); 311 } 312 313 void addGlobalViewParameters(String skinId, ViewParametersType type, Optional<ViewParametersModel> viewParameters) 314 { 315 if (!_globalViewParametersBySkin.containsKey(skinId)) 316 { 317 _globalViewParametersBySkin.put(skinId, new SkinWrapper()); 318 } 319 320 SkinWrapper skin = _globalViewParametersBySkin.get(skinId); 321 skin.addGlobalViewParameters(type, viewParameters); 322 } 323 } 324 325 static class SkinWrapper 326 { 327 Map<ViewParametersType, Optional<ViewParametersModel>> _parametersByType; 328 329 SkinWrapper() 330 { 331 this._parametersByType = new HashMap<>(); 332 } 333 334 Optional<ViewParametersModel> getGlobalViewParameters(ViewParametersType type) 335 { 336 return _parametersByType.getOrDefault(type, Optional.empty()); 337 } 338 339 void addGlobalViewParameters(ViewParametersType type, Optional<ViewParametersModel> viewParameters) 340 { 341 _parametersByType.put(type, viewParameters); 342 } 343 } 344}