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.plugins.linkdirectory; 018 019import java.io.InputStream; 020import java.util.HashMap; 021import java.util.LinkedHashMap; 022import java.util.Map; 023 024import org.apache.avalon.framework.component.Component; 025import org.apache.avalon.framework.configuration.Configurable; 026import org.apache.avalon.framework.configuration.Configuration; 027import org.apache.avalon.framework.configuration.ConfigurationException; 028import org.apache.avalon.framework.configuration.DefaultConfigurationBuilder; 029import org.apache.avalon.framework.service.ServiceException; 030import org.apache.avalon.framework.service.ServiceManager; 031import org.apache.avalon.framework.service.Serviceable; 032import org.apache.commons.lang3.StringUtils; 033import org.apache.excalibur.source.Source; 034 035import org.ametys.core.ui.Callable; 036import org.ametys.core.util.filereloader.FileReloader; 037import org.ametys.core.util.filereloader.FileReloaderUtils; 038import org.ametys.runtime.plugin.component.AbstractLogEnabled; 039import org.ametys.web.repository.site.Site; 040import org.ametys.web.repository.site.SiteManager; 041 042/** 043 * Component listing the available colors for a link 044 */ 045public class LinkDirectoryColorsComponent extends AbstractLogEnabled implements Component, Serviceable, Configurable 046{ 047 /** The component role */ 048 public static final String ROLE = LinkDirectoryColorsComponent.class.getName(); 049 050 /** The site manager */ 051 protected SiteManager _siteManager; 052 053 /** The file reloader utils */ 054 protected FileReloaderUtils _fileReloaderUtils; 055 056 /** The colors configuration */ 057 protected ColorsConfiguration _colorsConfiguration; 058 059 /** The cache of colors for each skins */ 060 protected Map<String, ColorsConfiguration> _colorsSkinCache; 061 062 063 public void service(ServiceManager manager) throws ServiceException 064 { 065 _siteManager = (SiteManager) manager.lookup(SiteManager.ROLE); 066 _fileReloaderUtils = (FileReloaderUtils) manager.lookup(FileReloaderUtils.ROLE); 067 } 068 069 @Override 070 public void configure(Configuration configuration) throws ConfigurationException 071 { 072 _colorsSkinCache = new HashMap<>(); 073 if ("colors".equals(configuration.getName())) 074 { 075 _colorsConfiguration = _parseColors(configuration); 076 } 077 else 078 { 079 _colorsConfiguration = _parseColors(configuration.getChild("colors")); 080 } 081 } 082 083 /** 084 * Get colors from site name 085 * @param siteName the site name 086 * @return the map of colors 087 */ 088 @Callable 089 public Map<String, Map<String, String>> getColors(String siteName) 090 { 091 // First get colors from skins if linkdirectory-colors.xml file exist in the skin configuration 092 ColorsConfiguration colorsConfFromSkin = _getColorsFromSkin(siteName); 093 if (colorsConfFromSkin != null) 094 { 095 return colorsConfFromSkin.getColorsMap(); 096 } 097 098 // Then get colors from WEB-INF/param/linkdirectory-colors.xml or in the plugin itself 099 return _colorsConfiguration.getColorsMap(); 100 } 101 102 /** 103 * Get the default color key 104 * @param siteName the site name 105 * @return the default key 106 */ 107 public String getDefaultKey(String siteName) 108 { 109 // First get colors from skins if linkdirectory-colors.xml file exist in the skin configuration 110 ColorsConfiguration colorsConfFromSkin = _getColorsFromSkin(siteName); 111 if (colorsConfFromSkin != null) 112 { 113 return colorsConfFromSkin.getDefaultKey(); 114 } 115 116 // Then get colors from WEB-INF/param/linkdirectory-colors.xml or in the plugin itself 117 return _colorsConfiguration.getDefaultKey(); 118 } 119 120 /** 121 * Parse colors from configuration 122 * @param configuration the configuration 123 * @return the colors configuration 124 * @throws ConfigurationException if a configuration error occurred 125 */ 126 protected ColorsConfiguration _parseColors(Configuration configuration) throws ConfigurationException 127 { 128 Map<String, Map<String, String>> colors = new LinkedHashMap<>(); 129 String defaultKey = configuration.getAttribute("default", ""); 130 for (Configuration colorConfiguration : configuration.getChildren("color")) 131 { 132 Map<String, String> color = new HashMap<>(); 133 134 for (Configuration child : colorConfiguration.getChildren()) 135 { 136 String name = child.getName(); 137 String value = child.getValue(); 138 139 color.put(name, value); 140 } 141 142 String id = colorConfiguration.getAttribute("id"); 143 colors.put(id, color); 144 145 if (StringUtils.isEmpty(defaultKey)) 146 { 147 defaultKey = id; 148 } 149 } 150 151 return new ColorsConfiguration(defaultKey, colors); 152 } 153 154 /** 155 * Get colors configuration from skin 156 * @param siteName the site name 157 * @return the colors configuration 158 */ 159 protected ColorsConfiguration _getColorsFromSkin(String siteName) 160 { 161 try 162 { 163 Site site = _siteManager.getSite(siteName); 164 String skinId = site.getSkinId(); 165 166 String file = "skin:" + skinId + "://conf/linkdirectory-colors.xml"; 167 _fileReloaderUtils.updateFile(file, new LinkDirectoryReloader(skinId, this)); 168 169 return _colorsSkinCache.containsKey(skinId) ? _colorsSkinCache.get(skinId) : null; 170 } 171 catch (Exception e) 172 { 173 getLogger().error("An error occurred reading the configuration file", e); 174 return null; 175 } 176 } 177 178 /** 179 * Class representing a link directory reloader 180 */ 181 public static class LinkDirectoryReloader implements FileReloader 182 { 183 private String _skin; 184 private LinkDirectoryColorsComponent _component; 185 186 /** 187 * Constructor 188 * @param skin the skin 189 * @param component the link directory colors component 190 */ 191 public LinkDirectoryReloader (String skin, LinkDirectoryColorsComponent component) 192 { 193 _skin = skin; 194 _component = component; 195 } 196 197 /** 198 * Get the skin 199 * @return the skin 200 */ 201 public String getSkin() 202 { 203 return _skin; 204 } 205 206 /** 207 * Get the link directory colors component 208 * @return the link directory colors component 209 */ 210 public LinkDirectoryColorsComponent getComponent() 211 { 212 return _component; 213 } 214 215 216 public void updateFile(String sourceUrl, Source source, InputStream is) throws Exception 217 { 218 if (is != null) 219 { 220 LinkDirectoryColorsComponent component = getComponent(); 221 // We pass in this method only if the file has been modified since the last time we parse colors 222 Configuration configuration = new DefaultConfigurationBuilder().build(is); 223 component._colorsSkinCache.put(getSkin(), component._parseColors (configuration)); 224 } 225 } 226 227 public String getId(String sourceUrl) 228 { 229 return LinkDirectoryReloader.class.getName() + "#" + getSkin(); 230 } 231 } 232 233 /** 234 * Class representing a colors configuration 235 */ 236 public static class ColorsConfiguration 237 { 238 private String _defaultKey; 239 private Map<String, Map<String, String>> _colors; 240 241 /** 242 * Constructor 243 * @param defaultKey the default color key 244 * @param colors the map of colors 245 */ 246 public ColorsConfiguration (String defaultKey, Map<String, Map<String, String>> colors) 247 { 248 _defaultKey = defaultKey; 249 _colors = colors; 250 } 251 252 /** 253 * Get the default key 254 * @return the default key 255 */ 256 public String getDefaultKey() 257 { 258 return _defaultKey; 259 } 260 261 /** 262 * Get colors map 263 * @return the colors map 264 */ 265 public Map<String, Map<String, String>> getColorsMap() 266 { 267 return _colors; 268 } 269 } 270}