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.InputStream; 019import java.util.HashMap; 020import java.util.HashSet; 021import java.util.Map; 022import java.util.Set; 023import java.util.regex.Pattern; 024 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.excalibur.source.Source; 033import org.apache.excalibur.source.SourceResolver; 034 035import org.ametys.web.repository.page.Page; 036import org.ametys.web.repository.site.Site; 037 038/** 039 * This implementation of the templates handler is based uppon a configuration. 040 */ 041public class StaticTemplatesAssignmentHandler extends AbstractLogEnabled implements TemplatesAssignmentHandler, Serviceable 042{ 043 /** The skins manager */ 044 protected SkinsManager _skinsManager; 045 /** The source resolver */ 046 protected SourceResolver _srcResolver; 047 048 private Map<String, Map<String, AssignmentCondition>> _tplCache = new HashMap<>(); 049 private Map<String, Long> _lastConfUpdate = new HashMap<>(); 050 051 @Override 052 public void service(ServiceManager smanager) throws ServiceException 053 { 054 _skinsManager = (SkinsManager) smanager.lookup(SkinsManager.ROLE); 055 _srcResolver = (SourceResolver) smanager.lookup(SourceResolver.ROLE); 056 } 057 058 @Override 059 public Set<String> getAvailablesTemplates(String skinName) 060 { 061 Skin skin = _skinsManager.getSkin(skinName); 062 _refreshValues (skin); 063 064 return _tplCache.get(skinName).keySet(); 065 } 066 067 @Override 068 public Set<String> getAvailablesTemplates(Page page) 069 { 070 Set<String> availableTemplates = new HashSet<>(); 071 072 Site site = page.getSite(); 073 074 Skin skin = _skinsManager.getSkin(site.getSkinId()); 075 String skinName = skin.getId(); 076 077 _refreshValues (skin); 078 079 Map<String, AssignmentCondition> templates = _tplCache.get(skinName); 080 for (String templateName : templates.keySet()) 081 { 082 if (templates.get(templateName).matchCondition(page)) 083 { 084 availableTemplates.add(templateName); 085 } 086 } 087 088 return availableTemplates; 089 } 090 091 /** 092 * Get the available templates for assignment 093 * @param skin The skin 094 */ 095 protected void _refreshValues (Skin skin) 096 { 097 Source source = null; 098 try 099 { 100 source = _srcResolver.resolveURI("context://skins/" + skin.getId() + "/conf/template_assignment.xml"); 101 if (source.exists()) 102 { 103 if (!_lastConfUpdate.containsKey(skin.getId()) || _lastConfUpdate.get(skin.getId()) < source.getLastModified()) 104 { 105 _lastConfUpdate.put(skin.getId(), source.getLastModified()); 106 107 try (InputStream is = source.getInputStream()) 108 { 109 Configuration configuration = new DefaultConfigurationBuilder().build(is); 110 _parseAvailableTemplates (skin, configuration); 111 } 112 } 113 } 114 else 115 { 116 _getAllTemplatesWithoutCondition (skin); 117 } 118 } 119 catch (Exception e) 120 { 121 getLogger().error("Unable to read the available templates configuration file", e); 122 } 123 } 124 125 private void _parseAvailableTemplates (Skin skin, Configuration configuration) throws ConfigurationException 126 { 127 boolean exclude = configuration.getChild("list", false) == null || "exclude".equals(configuration.getChild("list").getAttribute("mode", "include")); 128 129 if (exclude) 130 { 131 _getAllTemplatesWithoutCondition (skin); 132 } 133 134 Configuration[] tplList = configuration.getChild("list").getChildren("template"); 135 for (Configuration tplConf : tplList) 136 { 137 String reName = tplConf.getAttribute("name"); 138 Pattern namePattern = _getPattern (reName); 139 140 for (String templateName : skin.getTemplates()) 141 { 142 if (namePattern.matcher(templateName).matches()) 143 { 144 if (!exclude) 145 { 146 if (!_tplCache.containsKey(skin.getId())) 147 { 148 _tplCache.put(skin.getId(), new HashMap<String, AssignmentCondition>()); 149 } 150 Map<String, AssignmentCondition> m = _tplCache.get(skin.getId()); 151 m.put(templateName, new AssignmentCondition(skin.getId(), templateName)); 152 } 153 else 154 { 155 Map<String, AssignmentCondition> m = _tplCache.get(skin.getId()); 156 m.remove(templateName); 157 } 158 } 159 } 160 } 161 162 Set<String> findCondition = new HashSet<>(); 163 164 // Conditions 165 Configuration[] conditions = configuration.getChild("conditions").getChildren("condition"); 166 for (Configuration conditionConf : conditions) 167 { 168 String reName = conditionConf.getAttribute("template"); 169 Pattern namePattern = _getPattern (reName); 170 171 Set<String> skinTemplates = _tplCache.get(skin.getId()).keySet(); 172 for (String templateName : skinTemplates) 173 { 174 if (!findCondition.contains(templateName) && namePattern.matcher(templateName).matches()) 175 { 176 findCondition.add(templateName); 177 178 AssignmentCondition condition = _tplCache.get(skin.getId()).get(templateName); 179 180 String regexp = conditionConf.getChild("page").getAttribute("regexp_path", null); 181 if (regexp != null) 182 { 183 condition.setRegExpPath(regexp, false); 184 } 185 else 186 { 187 String reverseRegexp = conditionConf.getChild("page").getAttribute("reverse_regexp_path", null); 188 if (reverseRegexp != null) 189 { 190 condition.setRegExpPath(reverseRegexp, true); 191 } 192 } 193 } 194 } 195 } 196 } 197 198 private void _getAllTemplatesWithoutCondition (Skin skin) 199 { 200 Map<String, AssignmentCondition> m = new HashMap<>(); 201 _tplCache.put(skin.getId(), m); 202 203 for (String templateName : skin.getTemplates()) 204 { 205 m.put(templateName, new AssignmentCondition(skin.getId(), templateName)); 206 } 207 } 208 209 private Pattern _getPattern (String pattern) 210 { 211 String regexp = "^" + pattern.replaceAll("\\*", "([^/]*)") + "$"; 212 return Pattern.compile(regexp); 213 } 214 215 /** 216 * Class representing the condition for a template assignment 217 */ 218 public class AssignmentCondition 219 { 220 private String _skinName; 221 private String _templateName; 222 private String _rePath; 223 private boolean _reverse; 224 225 /** 226 * Constructor 227 * @param skinName the skin name 228 * @param templateName the template name 229 */ 230 public AssignmentCondition (String skinName, String templateName) 231 { 232 _skinName = skinName; 233 _templateName = templateName; 234 } 235 236 /** 237 * Set the RegExp for path 238 * @param rePath the RegExp for path 239 * @param reverse true to reverse mode 240 */ 241 public void setRegExpPath (String rePath, boolean reverse) 242 { 243 _rePath = (rePath.startsWith("^") ? "" : "^") + rePath + (rePath.startsWith("$") ? "" : "$"); 244 _reverse = reverse; 245 } 246 247 /** 248 * Test if page matches condition 249 * @param page the page to test 250 * @return true if page matches condition 251 */ 252 public boolean matchCondition (Page page) 253 { 254 if (_rePath == null) 255 { 256 return true; 257 } 258 259 if (!_reverse) 260 { 261 return Pattern.compile(_rePath).matcher(page.getPathInSitemap()).matches(); 262 } 263 else 264 { 265 return !Pattern.compile(_rePath).matcher(page.getPathInSitemap()).matches(); 266 } 267 } 268 269 /** 270 * Get the skin name 271 * @return the skin name 272 */ 273 public String getSkinName () 274 { 275 return _skinName; 276 } 277 278 /** 279 * Get the template name 280 * @return the template name 281 */ 282 public String getTemplateName () 283 { 284 return _templateName; 285 } 286 } 287 288}