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.tags; 017 018import java.io.InputStream; 019import java.util.ArrayList; 020import java.util.HashMap; 021import java.util.List; 022import java.util.Map; 023 024import org.apache.avalon.framework.configuration.Configuration; 025import org.apache.avalon.framework.configuration.ConfigurationException; 026import org.apache.avalon.framework.service.ServiceException; 027import org.apache.avalon.framework.service.ServiceManager; 028import org.apache.excalibur.source.Source; 029import org.apache.excalibur.source.SourceResolver; 030 031import org.ametys.cms.tag.CMSTag; 032import org.ametys.cms.tag.CMSTag.TagVisibility; 033import org.ametys.cms.tag.StaticTagProvider; 034import org.ametys.cms.tag.Tag; 035import org.ametys.cms.tag.TagTargetType; 036import org.ametys.runtime.i18n.I18nizableText; 037import org.ametys.web.repository.site.Site; 038import org.ametys.web.repository.site.SiteManager; 039import org.ametys.web.skin.Skin; 040import org.ametys.web.skin.SkinConfigurationHelper; 041import org.ametys.web.skin.SkinsManager; 042 043/** 044 * This class represents the tags provide by the skin 045 */ 046public class SkinTagProvider extends StaticTagProvider 047{ 048 /** The source resolver */ 049 protected SourceResolver _resolver; 050 051 /** The tags */ 052 protected Map<String, List<String>> _skinLocalIds; 053 /** The tags */ 054 protected Map<String, Map<String, CMSTag>> _skinTags; 055 056 private SiteManager _siteManager; 057 private SkinsManager _skinsManager; 058 059 private SkinConfigurationHelper _skinConfigurationHelper; 060 061 @Override 062 public void service(ServiceManager smanager) throws ServiceException 063 { 064 super.service(smanager); 065 _resolver = (SourceResolver) smanager.lookup(SourceResolver.ROLE); 066 _siteManager = (SiteManager) smanager.lookup(SiteManager.ROLE); 067 _skinsManager = (SkinsManager) smanager.lookup(SkinsManager.ROLE); 068 _skinConfigurationHelper = (SkinConfigurationHelper) smanager.lookup(SkinConfigurationHelper.ROLE); 069 } 070 071 @Override 072 public void configure(Configuration configuration) throws ConfigurationException 073 { 074 _skinLocalIds = new HashMap<>(); 075 076 _id = configuration.getAttribute("id"); 077 _label = configureLabel(configuration, "plugin." + _pluginName); 078 _description = configureDescription(configuration, "plugin." + _pluginName); 079 080 if (_skinTags == null) 081 { 082 _skinTags = new HashMap<>(); 083 } 084 085 for (String skinName : _skinsManager.getSkins()) 086 { 087 try 088 { 089 initializeTags(skinName); 090 } 091 catch (Exception e) 092 { 093 throw new ConfigurationException("Unable to load tags configuration values for skin " + skinName, e); 094 } 095 } 096 } 097 098 @Override 099 public Map<String, CMSTag> getTags(Map<String, Object> contextualParameters) 100 { 101 if (contextualParameters.get("siteName") == null) 102 { 103 // contextualParameters#containsKey not sufficient here because the in some case the siteName key can be set to null 104 return null; 105 } 106 107 Site site = _siteManager.getSite((String) contextualParameters.get("siteName")); 108 109 if (site == null) 110 { 111 String errorMessage = "Unable to load tags configuration values for site " + (String) contextualParameters.get("siteName"); 112 getLogger().error(errorMessage); 113 return null; 114 } 115 116 String skin = site.getSkinId(); 117 118 if (!_skinTags.containsKey(skin)) 119 { 120 try 121 { 122 initializeTags(skin); 123 } 124 catch (Exception e) 125 { 126 String errorMessage = "Unable to load tags configuration values for skin " + skin; 127 getLogger().error(errorMessage, e); 128 } 129 } 130 131 return _skinTags.get(skin); 132 } 133 134 /** 135 * Initialize a skin's tags from the tags file. 136 * @param skinName the name of the skin to initialize tags. 137 * @throws Exception if an error occurs. 138 */ 139 protected void initializeTags(String skinName) throws Exception 140 { 141 // Obsolete location 142 Source otherSrc = null; 143 try 144 { 145 otherSrc = _resolver.resolveURI("skin:" + skinName + "://tags/tags.xml"); 146 if (otherSrc.exists()) 147 { 148 getLogger().error("In skin '" + skinName + "' (or one of its parent skin) the 'tags.xml' file location is obsolete AND NOT SUPPORTED ANYMORE. Move the file tags/tags.xml to conf/tags.xml"); 149 } 150 } 151 finally 152 { 153 _resolver.release(otherSrc); 154 } 155 156 157 // Right inheritable location 158 Skin skin = _skinsManager.getSkin(skinName); 159 try (InputStream xslIs = getClass().getResourceAsStream("skin-tag-merge.xsl")) 160 { 161 Configuration configuration = _skinConfigurationHelper.getInheritanceMergedConfiguration(skin, "conf/tags.xml", xslIs); 162 163 if (!_skinLocalIds.containsKey(skinName)) 164 { 165 _skinLocalIds.put(skinName, new ArrayList<String>()); 166 } 167 168 Map<String, CMSTag> tags = configureTags(configuration, skinName, null, "skin." + skinName); 169 _skinTags.put(skinName, tags); 170 } 171 } 172 173 /** 174 * Configure tag from the passed configuration 175 * @param configuration The configuration 176 * @param skinName the skin name 177 * @param parent The parent tag if any 178 * @param defaultCatalogue The default catalog for i18n 179 * @return a Set of {@link CMSTag} 180 * @throws ConfigurationException if configuration is invalid 181 */ 182 protected Map<String, CMSTag> configureTags (Configuration configuration, String skinName, CMSTag parent, String defaultCatalogue) throws ConfigurationException 183 { 184 Map<String, CMSTag> tags = new HashMap<>(); 185 186 Configuration[] tagsConfiguration = configuration.getChildren("tag"); 187 for (Configuration tagConfiguration : tagsConfiguration) 188 { 189 String id = tagConfiguration.getAttribute("id", null); 190 if (id == null) 191 { 192 getLogger().error("Missing attributed named \"id\" for tag configuration at " + tagConfiguration.getLocation() + ". Tag is ignored."); 193 } 194 else if (!Tag.NAME_PATTERN.matcher(id).matches()) 195 { 196 getLogger().error("Invalid tag ID \"" + id + "\" for tag configuration at " + tagConfiguration.getLocation() + ". It must match the pattern " + Tag.NAME_PATTERN.toString() + ". Tag is ignored."); 197 } 198 else if (_skinLocalIds.get(skinName).contains(id)) 199 { 200 getLogger().error("A tag with the ID \"" + id + "\" for tag configuration at " + tagConfiguration.getLocation() + " already exists. Tag is ignored."); 201 } 202 else 203 { 204 _skinLocalIds.get(skinName).add(id); 205 206 String typeName = tagConfiguration.getAttribute("target", null); 207 if (typeName != null) 208 { 209 TagTargetType targetType = _targetTypeEP.getTagTargetType(typeName); 210 211 TagVisibility visibility = TagVisibility.PUBLIC; 212 if (tagConfiguration.getAttribute("private", "").equals("true")) 213 { 214 visibility = TagVisibility.PRIVATE; 215 } 216 I18nizableText label = configureLabel (tagConfiguration, defaultCatalogue); 217 I18nizableText description = configureDescription (tagConfiguration, defaultCatalogue); 218 CMSTag tag = new CMSTag(id, id, parent, label, description, visibility, targetType); 219 tags.put(id, tag); 220 221 // Recursive configuration 222 Map<String, CMSTag> childTags = configureTags(tagConfiguration, skinName, tag, defaultCatalogue); 223 tag.setTags(childTags); 224 } 225 else 226 { 227 getLogger().error("Missing attributed named \"target\" for tag configuration of id \"" + id + "\" at " + tagConfiguration.getLocation() + ". Tag is ignored."); 228 } 229 } 230 231 } 232 233 return tags; 234 } 235}