001/* 002 * Copyright 2018 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 */ 016 017package org.ametys.web.skin; 018 019import java.io.IOException; 020import java.io.InputStream; 021import java.nio.file.Files; 022import java.nio.file.Path; 023import java.util.ArrayList; 024import java.util.Collection; 025import java.util.Comparator; 026import java.util.List; 027import java.util.stream.Collectors; 028 029import org.apache.avalon.framework.configuration.Configuration; 030import org.apache.avalon.framework.configuration.ConfigurationException; 031import org.apache.avalon.framework.configuration.DefaultConfigurationBuilder; 032import org.apache.avalon.framework.context.Context; 033import org.apache.avalon.framework.service.ServiceManager; 034import org.apache.cocoon.ProcessingException; 035import org.slf4j.LoggerFactory; 036import org.xml.sax.SAXException; 037 038import org.ametys.core.util.I18nizableTextKeyComparator; 039import org.ametys.runtime.i18n.I18nizableText; 040import org.ametys.runtime.model.CategorizedElementDefinitionHelper; 041import org.ametys.runtime.model.CategorizedElementDefinitionParser; 042import org.ametys.runtime.model.CategorizedElementDefinitionWrapper; 043import org.ametys.runtime.model.CategorizedElementDefinitionWrapperComparator; 044import org.ametys.runtime.model.ElementDefinition; 045import org.ametys.runtime.model.Enumerator; 046import org.ametys.runtime.model.Model; 047import org.ametys.runtime.model.View; 048import org.ametys.runtime.model.disableconditions.DisableConditions; 049import org.ametys.runtime.model.exception.UndefinedItemPathException; 050import org.ametys.runtime.parameter.Validator; 051import org.ametys.runtime.plugin.component.ThreadSafeComponentManager; 052import org.ametys.web.data.type.ModelItemTypeExtensionPoint; 053 054/** 055 * Model for Skin (do not mistake this with {@link SkinModel} ) 056 */ 057public class SkinParametersModel implements Model 058{ 059 private String _skinName; 060 private Path _skinDir; 061 private ModelItemTypeExtensionPoint _skinParameterTypeEP; 062 private Context _context; 063 private ServiceManager _manager; 064 065 private List<CategorizedElementDefinitionWrapper> _parameterWrappers; 066 private List<ElementDefinition> _parameters; 067 068 /** 069 * Create an instance of a model, based on the skin directory 070 * @param skinName name of the skin (must be unique) 071 * @param skinDir the skin directory where the configuration will be read 072 * @param skinParameterTypeEP the skin parameter type extension point 073 * @param context the current context 074 * @param manager the service manager 075 * @throws ProcessingException something went wrong while parsing the file 076 */ 077 public SkinParametersModel(String skinName, Path skinDir, ModelItemTypeExtensionPoint skinParameterTypeEP, Context context, ServiceManager manager) throws ProcessingException 078 { 079 _skinName = skinName; 080 _skinDir = skinDir; 081 _skinParameterTypeEP = skinParameterTypeEP; 082 _context = context; 083 _manager = manager; 084 _initialize(); 085 } 086 087 public Collection<ElementDefinition> getModelItems() 088 { 089 return _parameters; 090 } 091 092 @Override 093 public ElementDefinition getModelItem(String itemPath) throws UndefinedItemPathException 094 { 095 // Skin parameter can only be element definitions 096 return (ElementDefinition) Model.super.getModelItem(itemPath); 097 } 098 099 /** 100 * Retrieves the view of skin parameters 101 * @return the skin parameters' view 102 */ 103 public View getView() 104 { 105 Comparator<I18nizableText> groupsComparator = new I18nizableTextKeyComparator(); 106 Comparator<CategorizedElementDefinitionWrapper> elementsComparator = new CategorizedElementDefinitionWrapperComparator<>(); 107 108 return CategorizedElementDefinitionHelper.buildViewFromCategories(_parameterWrappers, null, groupsComparator, elementsComparator); 109 } 110 111 public String getId() 112 { 113 return _skinName; 114 } 115 116 public String getFamilyId() 117 { 118 return this.getClass().getName(); 119 } 120 121 private void _initialize() throws ProcessingException 122 { 123 if (_parameterWrappers == null) 124 { 125 _parameterWrappers = _readSkinParameters(); 126 } 127 128 _parameters = _parameterWrappers.stream() 129 .map(CategorizedElementDefinitionWrapper::getDefinition) 130 .collect(Collectors.toList()); 131 } 132 133 /** 134 * Read the {@link CategorizedElementDefinitionWrapper} from the skin directory 135 * @return a list of {@link CategorizedElementDefinitionWrapper} 136 * @throws ProcessingException error while reading the XML 137 */ 138 private List<CategorizedElementDefinitionWrapper> _readSkinParameters() throws ProcessingException 139 { 140 List<CategorizedElementDefinitionWrapper> skinParameterWrappers = new ArrayList<>(); 141 142 ThreadSafeComponentManager<DisableConditions> disableConditionsManager = new ThreadSafeComponentManager<>(); 143 ThreadSafeComponentManager<Validator> validatorManager = new ThreadSafeComponentManager<>(); 144 ThreadSafeComponentManager<Enumerator> enumeratorManager = new ThreadSafeComponentManager<>(); 145 146 try 147 { 148 disableConditionsManager.setLogger(LoggerFactory.getLogger(getClass())); 149 disableConditionsManager.contextualize(_context); 150 disableConditionsManager.service(_manager); 151 152 validatorManager.setLogger(LoggerFactory.getLogger(getClass())); 153 validatorManager.contextualize(_context); 154 validatorManager.service(_manager); 155 156 enumeratorManager.setLogger(LoggerFactory.getLogger(getClass())); 157 enumeratorManager.contextualize(_context); 158 enumeratorManager.service(_manager); 159 160 SkinParameterParser definitionParser = new SkinParameterParser(_skinParameterTypeEP, disableConditionsManager, enumeratorManager, validatorManager, _skinDir.resolve("i18n").toUri().toString()); 161 CategorizedElementDefinitionParser parser = new CategorizedElementDefinitionParser(definitionParser); 162 Configuration configuration = _getConfigurationModel(_skinDir); 163 164 if (configuration != null) 165 { 166 Configuration[] parameterConfigs = configuration.getChild("parameters").getChildren("parameter"); 167 for (Configuration parameterConfig : parameterConfigs) 168 { 169 CategorizedElementDefinitionWrapper parameter = parser.parse(_manager, "tempskin", parameterConfig, this, null); 170 skinParameterWrappers.add(parameter); 171 } 172 173 try 174 { 175 definitionParser.lookupComponents(); 176 } 177 catch (Exception e) 178 { 179 throw new ConfigurationException("Unable to lookup parameter local components", configuration, e); 180 } 181 } 182 183 return skinParameterWrappers; 184 } 185 catch (ConfigurationException | SAXException | IOException e) 186 { 187 throw new ProcessingException(e); 188 } 189 } 190 191 private Configuration _getConfigurationModel(Path skinDir) throws ConfigurationException, SAXException, IOException 192 { 193 Path configFile = skinDir.resolve("stylesheets/config/config-model.xml"); 194 195 if (Files.exists(configFile)) 196 { 197 try (InputStream is = Files.newInputStream(configFile)) 198 { 199 DefaultConfigurationBuilder builder = new DefaultConfigurationBuilder(); 200 return builder.build(is); 201 } 202 } 203 204 // There is no parameter 205 return null; 206 } 207}