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