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