001/* 002 * Copyright 2013 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.skinfactory.model; 017 018import java.io.File; 019import java.io.FileInputStream; 020import java.io.InputStream; 021import java.util.HashMap; 022import java.util.Map; 023 024import org.apache.avalon.framework.component.Component; 025import org.apache.avalon.framework.configuration.Configuration; 026import org.apache.avalon.framework.configuration.ConfigurationException; 027import org.apache.avalon.framework.configuration.DefaultConfigurationBuilder; 028import org.apache.avalon.framework.logger.AbstractLogEnabled; 029import org.apache.avalon.framework.service.ServiceException; 030import org.apache.avalon.framework.service.ServiceManager; 031import org.apache.avalon.framework.service.Serviceable; 032import org.apache.avalon.framework.thread.ThreadSafe; 033import org.apache.excalibur.source.Source; 034import org.apache.excalibur.source.SourceResolver; 035import org.apache.excalibur.source.impl.FileSource; 036 037import org.ametys.runtime.i18n.I18nizableText; 038import org.ametys.skinfactory.SkinFactoryComponent; 039import org.ametys.skinfactory.parameters.I18nizableTextParameter; 040import org.ametys.skinfactory.parameters.ImageParameter; 041import org.ametys.skinfactory.parameters.AbstractSkinParameter; 042import org.ametys.web.skin.SkinModel; 043import org.ametys.web.skin.SkinModelsManager; 044 045/** 046 * Manages the design conceptions of a model 047 */ 048public class ModelDesignsManager extends AbstractLogEnabled implements ThreadSafe, Serviceable, Component 049{ 050 /** The avalon role name */ 051 public static final String ROLE = ModelDesignsManager.class.getName(); 052 053 private SkinModelsManager _modelsManager; 054 private SkinFactoryComponent _skinFactoryManager; 055 private SourceResolver _resolver; 056 057 private Map<String, Map<String, Design>> _designsCache = new HashMap<>(); 058 059 @Override 060 public void service(ServiceManager smanager) throws ServiceException 061 { 062 _modelsManager = (SkinModelsManager) smanager.lookup(SkinModelsManager.ROLE); 063 _skinFactoryManager = (SkinFactoryComponent) smanager.lookup(SkinFactoryComponent.ROLE); 064 _resolver = (SourceResolver) smanager.lookup(SourceResolver.ROLE); 065 } 066 067 /** 068 * Get all design instances for given model 069 * @param modelName The model name 070 * @return all design instances for given model 071 */ 072 public Map<String, Design> getDesigns (String modelName) 073 { 074 if (!_designsCache.containsKey(modelName)) 075 { 076 _configureDesigns (modelName); 077 } 078 return _designsCache.get(modelName); 079 } 080 081 /** 082 * Get design instance of given id and model name 083 * @param modelName The model name 084 * @param id The id 085 * @return design instance 086 */ 087 public Design getDesign (String modelName, String id) 088 { 089 if (!_designsCache.containsKey(modelName)) 090 { 091 _configureDesigns (modelName); 092 } 093 return _designsCache.get(modelName).get(id); 094 } 095 096 /** 097 * Apply a design 098 * @param modelName The model name 099 * @param id Id of design 100 * @param skinDir The skin directory (could be temp, work or skins) 101 */ 102 public void applyDesign (String modelName, String id, File skinDir) 103 { 104 SkinModel model = _modelsManager.getModel(modelName); 105 106 File file = new File(model.getFile(), "model/designs/" + id + ".xml"); 107 if (file.exists()) 108 { 109 // Apply color theme 110 String themeId = _getColorTheme (file); 111 if (themeId != null) 112 { 113 _skinFactoryManager.saveColorTheme(skinDir, themeId); 114 } 115 116 // Apply values 117 Map<String, Object> values = _getParameterValues (modelName, file); 118 _skinFactoryManager.applyModelParameters(modelName, skinDir, values); 119 } 120 } 121 122 123 private void _configureDesigns (String modelName) 124 { 125 SkinModel model = _modelsManager.getModel(modelName); 126 127 _designsCache.put(modelName, new HashMap<String, Design>()); 128 Map<String, Design> designs = _designsCache.get(modelName); 129 130 File designDir = new File(model.getFile(), "model/designs"); 131 if (designDir.exists()) 132 { 133 for (File child : designDir.listFiles()) 134 { 135 if (child.getName().endsWith(".xml")) 136 { 137 Design design = _configureDesign (modelName, child); 138 if (design != null) 139 { 140 designs.put(design.getId(), design); 141 } 142 } 143 } 144 } 145 } 146 147 148 private Design _configureDesign (String modelName, File configurationFile) 149 { 150 try (InputStream is = new FileInputStream(configurationFile)) 151 { 152 String fileName = configurationFile.getName(); 153 String id = fileName.substring(0, fileName.lastIndexOf(".")); 154 155 Configuration configuration = new DefaultConfigurationBuilder().build(is); 156 I18nizableText label = _configureI18nizableText(configuration.getChild("label", false), new I18nizableText(id), modelName); 157 I18nizableText description = _configureI18nizableText(configuration.getChild("description", false), new I18nizableText(id), modelName); 158 159 String iconName = id + ".png"; 160 String icon = "/plugins/skinfactory/resources/img/actions/designs_32.png"; 161 File iconFile = new File(configurationFile.getParentFile(), iconName); 162 if (iconFile.exists()) 163 { 164 icon = "/plugins/skinfactory/" + modelName + "/_thumbnail/32/32/model/designs/" + iconName; 165 } 166 167 return new Design(id, label, description, icon); 168 } 169 catch (Exception e) 170 { 171 if (getLogger().isWarnEnabled()) 172 { 173 getLogger().warn("Cannot read the configuration file model/designs/" + configurationFile.getName() + " for the model '" + modelName + "'. Continue as if file was not existing", e); 174 } 175 return null; 176 } 177 178 } 179 180 private String _getColorTheme (File file) 181 { 182 Source src = null; 183 try 184 { 185 186 src = new FileSource("file", file); 187 188 Configuration configuration = new DefaultConfigurationBuilder(true).build(src.getInputStream()); 189 return configuration.getChild("color-theme").getValue(null); 190 } 191 catch (Exception e) 192 { 193 getLogger().error("Unable to get color theme", e); 194 return null; 195 } 196 finally 197 { 198 if (src != null) 199 { 200 _resolver.release(src); 201 } 202 } 203 } 204 205 private Map<String, Object> _getParameterValues (String modelName, File file) 206 { 207 Map<String, Object> values = new HashMap<>(); 208 209 Source src = null; 210 try 211 { 212 213 src = new FileSource("file", file); 214 215 Configuration configuration = new DefaultConfigurationBuilder(true).build(src.getInputStream()); 216 Configuration[] parametersConf = configuration.getChild("parameters").getChildren("parameter"); 217 218 Map<String, AbstractSkinParameter> modelParameters = _skinFactoryManager.getModelParameters(modelName); 219 220 for (Configuration paramConf : parametersConf) 221 { 222 String id = paramConf.getAttribute("id"); 223 AbstractSkinParameter modelParam = modelParameters.get(id); 224 if (modelParam != null) 225 { 226 if (modelParam instanceof I18nizableTextParameter) 227 { 228 Configuration[] children = paramConf.getChildren(); 229 Map<String, String> langValues = new HashMap<>(); 230 for (Configuration langConfig : children) 231 { 232 langValues.put(langConfig.getName(), langConfig.getValue("")); 233 } 234 values.put(id, langValues); 235 } 236 else if (modelParam instanceof ImageParameter) 237 { 238 values.put(id, new ImageParameter.FileValue(paramConf.getValue(""), false)); 239 } 240 else 241 { 242 values.put(id, paramConf.getValue("")); 243 } 244 } 245 } 246 247 return values; 248 } 249 catch (Exception e) 250 { 251 getLogger().error("Unable to get values of all parameters", e); 252 return new HashMap<>(); 253 } 254 finally 255 { 256 if (src != null) 257 { 258 _resolver.release(src); 259 } 260 } 261 } 262 263 264 private I18nizableText _configureI18nizableText(Configuration configuration, I18nizableText defaultValue, String modelName) throws ConfigurationException 265 { 266 if (configuration != null) 267 { 268 boolean i18nSupported = configuration.getAttributeAsBoolean("i18n", false); 269 if (i18nSupported) 270 { 271 String catalogue = configuration.getAttribute("catalogue", null); 272 if (catalogue == null) 273 { 274 catalogue = "model." + modelName; 275 } 276 277 return new I18nizableText(catalogue, configuration.getValue()); 278 } 279 else 280 { 281 return new I18nizableText(configuration.getValue("")); 282 } 283 } 284 else 285 { 286 return defaultValue; 287 } 288 289 } 290 291 /** 292 * Bean representing a model design 293 * 294 */ 295 public class Design 296 { 297 private String _id; 298 private I18nizableText _label; 299 private I18nizableText _description; 300 private String _icon; 301 302 /** 303 * Constructor 304 * @param id the theme id 305 * @param label the theme's label 306 * @param description the theme's description 307 * @param icon the icon 308 */ 309 public Design (String id, I18nizableText label, I18nizableText description, String icon) 310 { 311 _id = id; 312 _label = label; 313 _description = description; 314 _icon = icon; 315 } 316 317 /** 318 * Get the id 319 * @return the id 320 */ 321 public String getId () 322 { 323 return _id; 324 } 325 326 /** 327 * Get the label 328 * @return the label 329 */ 330 public I18nizableText getLabel () 331 { 332 return _label; 333 } 334 335 /** 336 * Get the description 337 * @return the description 338 */ 339 public I18nizableText getDescription () 340 { 341 return _description; 342 } 343 344 /** 345 * Get the icon 346 * @return the icon 347 */ 348 public String getIcon () 349 { 350 return _icon; 351 } 352 } 353 354}