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