001/* 002 * Copyright 2010 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.skin; 017 018import java.io.File; 019import java.io.FileInputStream; 020import java.io.InputStream; 021import java.util.Date; 022import java.util.HashMap; 023import java.util.HashSet; 024import java.util.Map; 025import java.util.Set; 026 027import org.apache.avalon.framework.configuration.Configuration; 028import org.apache.avalon.framework.configuration.ConfigurationException; 029import org.apache.avalon.framework.configuration.DefaultConfigurationBuilder; 030import org.slf4j.Logger; 031import org.slf4j.LoggerFactory; 032 033import org.ametys.runtime.i18n.I18nizableText; 034 035/** 036 * A skin 037 */ 038public class Skin 039{ 040 private static Logger _logger = LoggerFactory.getLogger(Skin.class); 041 042 /** The skin id (e.g. the directory name) */ 043 protected String _id; 044 /** The skin directory */ 045 protected File _file; 046 /** The skin name */ 047 protected I18nizableText _label; 048 /** The skin description */ 049 protected I18nizableText _description; 050 /** The skin thumbnail 16x16 */ 051 protected String _smallImage; 052 /** The skin thumbnail 32x32 */ 053 protected String _mediumImage; 054 /** The skin thumbnail 48x48 */ 055 protected String _largeImage; 056 /** The map of templates id and associated templates */ 057 protected Map<String, SkinTemplate> _templates = new HashMap<>(); 058 059 /** The last time the file was loaded */ 060 protected long _lastConfUpdate; 061 062 /** 063 * Creates a skin 064 * @param id The id of the skin (e.g. the directory name) 065 * @param file The skin file 066 */ 067 public Skin(String id, File file) 068 { 069 this._id = id; 070 this._file = file; 071 } 072 073 /** 074 * Get the list of existing templates 075 * @return A set of skin names. Can be null if there is an error. 076 */ 077 public Set<String> getTemplates() 078 { 079 try 080 { 081 Set<String> template = new HashSet<>(); 082 083 File tplDir = new File (_file, "/templates"); 084 085 for (File child : tplDir.listFiles()) 086 { 087 if (_templateExists(child.getName())) 088 { 089 template.add(child.getName()); 090 } 091 } 092 093 return template; 094 } 095 catch (Exception e) 096 { 097 _logger.error("Can not determine the list of skins available", e); 098 return null; 099 } 100 } 101 102 /** 103 * Get a template 104 * @param id The id of the template 105 * @return The template or null if the template doest not exists 106 */ 107 @SuppressWarnings("null") 108 public SkinTemplate getTemplate(String id) 109 { 110 try 111 { 112 boolean templateDirExists = _templateExists(id); 113 SkinTemplate template = _templates.get(id); 114 if (template == null && templateDirExists) 115 { 116 template = new SkinTemplate(this._id, id, new File (_file, "/templates/" + id)); 117 _templates.put(id, template); 118 } 119 else if (!templateDirExists) 120 { 121 _templates.put(id, null); 122 return null; 123 } 124 125 template.refreshValues(); 126 return template; 127 } 128 catch (Exception e) 129 { 130 throw new IllegalStateException("Can not create the template DAO for skin '" + this._id + "' and the template '" + id + "'", e); 131 } 132 } 133 134 private boolean _templateExists(String id) 135 { 136 File tplFile = new File (_file, "/templates/" + id + "/stylesheets/template.xsl"); 137 return tplFile.exists(); 138 } 139 140 /** 141 * The configuration default values (if configuration file does not exist or is unreadable) 142 */ 143 protected void _defaultValues() 144 { 145 _lastConfUpdate = new Date().getTime(); 146 147 this._label = new I18nizableText(this._id); 148 this._description = new I18nizableText(""); 149 this._smallImage = "/plugins/web/resources/img/skin/skin_16.png"; 150 this._mediumImage = "/plugins/web/resources/img/skin/skin_32.png"; 151 this._largeImage = "/plugins/web/resources/img/skin/skin_48.png"; 152 } 153 154 /** 155 * Refresh the conf values 156 */ 157 public void refreshValues() 158 { 159 File configurationFile = null; 160 161 try 162 { 163 configurationFile = new File (_file, "/conf/skin.xml"); 164 if (configurationFile.exists()) 165 { 166 167 if (_lastConfUpdate < configurationFile.lastModified()) 168 { 169 _lastConfUpdate = configurationFile.lastModified(); 170 try (InputStream is = new FileInputStream(configurationFile)) 171 { 172 Configuration configuration = new DefaultConfigurationBuilder().build(is); 173 174 this._label = _configureI18n(configuration.getChild("label", false), new I18nizableText(this._id)); 175 this._description = _configureI18n(configuration.getChild("description", false), new I18nizableText("")); 176 this._smallImage = _configureThumbnail(configuration.getChild("thumbnail").getChild("small").getValue(null), "/plugins/web/resources/img/skin/skin_16.png"); 177 this._mediumImage = _configureThumbnail(configuration.getChild("thumbnail").getChild("medium").getValue(null), "/plugins/web/resources/img/skin/skin_32.png"); 178 this._largeImage = _configureThumbnail(configuration.getChild("thumbnail").getChild("large").getValue(null), "/plugins/web/resources/img/skin/skin_48.png"); 179 } 180 } 181 } 182 else 183 { 184 _defaultValues(); 185 } 186 } 187 catch (Exception e) 188 { 189 _defaultValues(); 190 if (_logger.isWarnEnabled()) 191 { 192 _logger.warn("Cannot read the configuration file conf/skin.xml for the skin '" + this._id + "'. Continue as if file was not existing", e); 193 } 194 } 195 } 196 197 private String _configureThumbnail(String value, String defaultImage) 198 { 199 if (value == null) 200 { 201 return defaultImage; 202 } 203 else 204 { 205 return "/skins/" + this._id + "/resources/" + value; 206 } 207 } 208 209 private I18nizableText _configureI18n(Configuration child, I18nizableText defaultValue) throws ConfigurationException 210 { 211 if (child != null) 212 { 213 String value = child.getValue(); 214 if (child.getAttributeAsBoolean("i18n", false)) 215 { 216 return new I18nizableText("skin." + this._id, value); 217 } 218 else 219 { 220 return new I18nizableText(value); 221 } 222 } 223 else 224 { 225 return defaultValue; 226 } 227 } 228 229 /** 230 * The skin id 231 * @return the id 232 */ 233 public String getId() 234 { 235 return _id; 236 } 237 238 /** 239 * The skin label 240 * @return The label 241 */ 242 public I18nizableText getLabel() 243 { 244 return _label; 245 } 246 /** 247 * The skin description 248 * @return The description. Can not be null but can be empty 249 */ 250 public I18nizableText getDescription() 251 { 252 return _description; 253 } 254 255 /** 256 * The small image file uri 257 * @return The small image file uri 258 */ 259 public String getSmallImage() 260 { 261 return _smallImage; 262 } 263 264 /** 265 * The medium image file uri 266 * @return The medium image file uri 267 */ 268 public String getMediumImage() 269 { 270 return _mediumImage; 271 } 272 273 /** 274 * The large image file uri 275 * @return The large image file uri 276 */ 277 public String getLargeImage() 278 { 279 return _largeImage; 280 } 281 282 /** 283 * Get the skin's file directory 284 * @return the skin's file directory 285 */ 286 public File getFile () 287 { 288 return _file; 289 } 290 291 /** 292 * Get the absolute path of the skin's file directory 293 * @return the absolute path of the skin's file directory 294 */ 295 public String getLocation () 296 { 297 return _file.getAbsolutePath(); 298 } 299}