001/* 002 * Copyright 2014 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.cms.tag; 017 018import java.text.Normalizer; 019import java.util.ArrayList; 020import java.util.HashMap; 021import java.util.List; 022import java.util.Map; 023import java.util.Set; 024 025import org.apache.avalon.framework.component.Component; 026import org.apache.avalon.framework.logger.AbstractLogEnabled; 027import org.apache.avalon.framework.service.ServiceException; 028import org.apache.avalon.framework.service.ServiceManager; 029import org.apache.avalon.framework.service.Serviceable; 030import org.apache.commons.lang3.StringUtils; 031 032import org.ametys.core.ui.Callable; 033import org.ametys.core.util.I18nUtils; 034import org.ametys.runtime.i18n.I18nizableText; 035 036/** 037 * DAO for manipulating tags 038 */ 039public abstract class AbstractTagsDAO extends AbstractLogEnabled implements Serviceable, Component 040{ 041 /** The tag provider extension point */ 042 protected AbstractTagProviderExtensionPoint<? extends Tag> _tagProviderExtPt; 043 /** The I18n utils */ 044 protected I18nUtils _i18nUtils; 045 046 @SuppressWarnings("unchecked") 047 @Override 048 public void service(ServiceManager manager) throws ServiceException 049 { 050 _i18nUtils = (I18nUtils) manager.lookup(I18nUtils.ROLE); 051 _tagProviderExtPt = (AbstractTagProviderExtensionPoint< ? extends Tag>) manager.lookup(getTagProviderEPRole()); 052 } 053 054 /** 055 * Get the tag provider extension point role 056 * @return the tag provider extension point role 057 */ 058 public abstract String getTagProviderEPRole(); 059 060 /** 061 * Get the paths of given tags 062 * @param tagNames The name of tags 063 * @param contextualParameters Contextual parameters 064 * @return {String} path 065 */ 066 @Callable 067 public List<String> getTagPaths(List<String> tagNames, Map<String, Object> contextualParameters) 068 { 069 List<String> paths = new ArrayList<>(); 070 if (tagNames != null) 071 { 072 for (String tagName : tagNames) 073 { 074 if (tagName.startsWith("provider_")) 075 { 076 paths.add(tagName); 077 } 078 else 079 { 080 String tagPath = getFullPath(tagName, contextualParameters); 081 if (tagPath != null) 082 { 083 paths.add(tagPath); 084 } 085 086 } 087 } 088 } 089 090 return paths; 091 } 092 093 /** 094 * Get the full path of a tag, with its provider 095 * @param tagName The tag name 096 * @param contextualParameters Contextual parameters 097 * @return the full path of tag or null if not found 098 */ 099 protected String getFullPath (String tagName, Map<String, Object> contextualParameters) 100 { 101 Set<String> tagProviders = _tagProviderExtPt.getExtensionsIds(); 102 103 for (String id : tagProviders) 104 { 105 TagProvider<? extends Tag> tagProvider = _tagProviderExtPt.getExtension(id); 106 if (tagProvider.hasTag(tagName, contextualParameters)) 107 { 108 Tag tag = tagProvider.getTag(tagName, contextualParameters); 109 return "provider_" + tagProvider.getId() + getPath(tag); 110 } 111 } 112 113 // Not found 114 return null; 115 } 116 117 /** 118 * Get a tag by its name 119 * @param tagName The tag name 120 * @param contextualParameters Contextual parameters 121 * @return The tag or null if not found 122 */ 123 public Tag getTag (String tagName, Map<String, Object> contextualParameters) 124 { 125 Set<String> tagProviders = _tagProviderExtPt.getExtensionsIds(); 126 127 for (String id : tagProviders) 128 { 129 TagProvider<? extends Tag> tagProvider = _tagProviderExtPt.getExtension(id); 130 if (tagProvider.hasTag(tagName, contextualParameters)) 131 { 132 return tagProvider.getTag(tagName, contextualParameters); 133 } 134 } 135 return null; 136 } 137 138 /** 139 * Get the path of a tag inside its provider. 140 * The path is composed of tags name and '/' as a separator 141 * @param tag The tag 142 * @return The path 143 */ 144 protected String getPath (Tag tag) 145 { 146 return tag == null ? "" : getPath(tag.getParent()) + "/" + tag.getName(); 147 } 148 149 /** 150 * Get the title of given tags 151 * @param tagNames The name of tags 152 * @param contextualParameters Contextual parameters 153 * @return the labels 154 */ 155 @Callable 156 public Map<String, Object> getTagsTitle(List<String> tagNames, Map<String, Object> contextualParameters) 157 { 158 Map<String, Object> result = new HashMap<>(); 159 160 Set<String> tagProviders = _tagProviderExtPt.getExtensionsIds(); 161 162 List<I18nizableText> labels = new ArrayList<>(); 163 164 for (String tagName : tagNames) 165 { 166 if (tagName.startsWith("provider_")) 167 { 168 TagProvider<? extends Tag> tagProvider = _tagProviderExtPt.getExtension(tagName.substring("provider_".length())); 169 labels.add(tagProvider.getLabel()); 170 } 171 else 172 { 173 for (String id : tagProviders) 174 { 175 TagProvider<? extends Tag> tagProvider = _tagProviderExtPt.getExtension(id); 176 if (tagProvider.hasTag(tagName, contextualParameters)) 177 { 178 Tag tag = tagProvider.getTag(tagName, contextualParameters); 179 labels.add(tag.getTitle()); 180 } 181 } 182 } 183 } 184 185 result.put("titles", labels); 186 return result; 187 } 188 189 /** 190 * Get the path of node which match filter regexp 191 * @param value the value to match 192 * @param contextualParameters Contextual parameters 193 * @return the matching paths 194 */ 195 @Callable 196 public List<String> filterTagsByRegExp(String value, Map<String, Object> contextualParameters) 197 { 198 List<String> matchingPaths = new ArrayList<>(); 199 200 String toMatch = Normalizer.normalize(value.toLowerCase(), Normalizer.Form.NFD).replaceAll("[\\p{InCombiningDiacriticalMarks}]", "").trim(); 201 202 Set<String> extensionsIds = _tagProviderExtPt.getExtensionsIds(); 203 for (String id : extensionsIds) 204 { 205 TagProvider<? extends Tag> tagProvider = _tagProviderExtPt.getExtension(id); 206 for (Tag tag : tagProvider.getTags(contextualParameters).values()) 207 { 208 _getMatchingTag(toMatch, tagProvider, tag, matchingPaths); 209 } 210 } 211 212 return matchingPaths; 213 } 214 215 /** 216 * Get the path of node which match filter regexp 217 * @param filter the value to match 218 * @param tagNames the list of tag's name to search inside 219 * @param contextualParameters Contextual parameters 220 * @return the matching paths 221 */ 222 @Callable 223 public List<String> filterTagsFromListByRegExp(String filter, List<String> tagNames, Map<String, Object> contextualParameters) 224 { 225 if (StringUtils.isEmpty(filter)) 226 { 227 return getTagPaths(tagNames, contextualParameters); 228 } 229 230 if (tagNames != null && tagNames.size() > 0) 231 { 232 List<String> matchingPaths = new ArrayList<>(); 233 234 String toMatch = Normalizer.normalize(filter.toLowerCase(), Normalizer.Form.NFD).replaceAll("[\\p{InCombiningDiacriticalMarks}]", "").trim(); 235 236 for (String tagName : tagNames) 237 { 238 Tag tag = getTag(tagName, contextualParameters); 239 if (tag != null) 240 { 241 String title = _i18nUtils.translate(tag.getTitle()); 242 String normalizedName = Normalizer.normalize(title.toLowerCase(), Normalizer.Form.NFD).replaceAll("[\\p{InCombiningDiacriticalMarks}]", ""); 243 if (normalizedName.contains(toMatch)) 244 { 245 matchingPaths.add(getFullPath(tagName, contextualParameters)); 246 } 247 } 248 } 249 250 return matchingPaths; 251 } 252 else 253 { 254 return filterTagsByRegExp(filter, contextualParameters); 255 } 256 } 257 258 /** 259 * Get paths of tag which match filter regexp 260 * @param value the value to match 261 * @param tagProvider the tag provider 262 * @param tag the current tag 263 * @param matchingPaths the matching paths 264 */ 265 private void _getMatchingTag(String value, TagProvider<? extends Tag> tagProvider, Tag tag, List<String> matchingPaths) 266 { 267 String title = _i18nUtils.translate(tag.getTitle()); 268 269 if (title != null) 270 { 271 String normalizedName = Normalizer.normalize(title.toLowerCase(), Normalizer.Form.NFD).replaceAll("[\\p{InCombiningDiacriticalMarks}]", ""); 272 273 if (normalizedName.contains(value)) 274 { 275 matchingPaths.add("provider_" + tagProvider.getId() + getPath(tag)); 276 } 277 } 278 279 for (Tag child : tag.getTags().values()) 280 { 281 _getMatchingTag(value, tagProvider, child, matchingPaths); 282 } 283 } 284 285 /** 286 * Test if tags exists 287 * @param tagNames The tag names to test 288 * @param onlyCustomTags If true, return only custom tags 289 * @param otherParameters the other parameters 290 * @param contextualParameters Contextual parameters 291 * @return The list of tag names without the invalid values. 292 */ 293 @Callable 294 public List<String> checkTags(List<String> tagNames, boolean onlyCustomTags, Map<String, Object> otherParameters, Map<String, Object> contextualParameters) 295 { 296 List<String> existingTagNames = new ArrayList<>(); 297 List<TagProvider<? extends Tag>> tagProviders = new ArrayList<>(); 298 299 if (onlyCustomTags) 300 { 301 tagProviders.addAll(getCustomTagProvider()); 302 } 303 else 304 { 305 Set<String> extensionsIds = _tagProviderExtPt.getExtensionsIds(); 306 for (String id : extensionsIds) 307 { 308 tagProviders.add(_tagProviderExtPt.getExtension(id)); 309 } 310 } 311 312 for (String tagName : tagNames) 313 { 314 if (tagName.startsWith("provider_")) 315 { 316 String providerId = tagName.substring("provider_".length()); 317 TagProvider<? extends Tag> tagProvider = _tagProviderExtPt.getExtension(providerId); 318 319 if (tagProvider != null) 320 { 321 existingTagNames.add(tagName); 322 } 323 } 324 else 325 { 326 for (TagProvider<? extends Tag> tagProvider : tagProviders) 327 { 328 if (tagProvider.hasTag(tagName, contextualParameters)) 329 { 330 String filteredTagName = _getFilteredTagName(tagProvider, tagName, otherParameters, contextualParameters); 331 if (StringUtils.isNotBlank(filteredTagName)) 332 { 333 existingTagNames.add(filteredTagName); 334 break; 335 } 336 } 337 } 338 } 339 } 340 341 return existingTagNames; 342 } 343 344 /** 345 * Get filtered tag name 346 * @param tagProvider the tag provider 347 * @param tagName the tag name 348 * @param otherParameters the other parameters 349 * @param contextualParameters the contextual parameters 350 * @return the tag name if it match 351 */ 352 protected String _getFilteredTagName(TagProvider<? extends Tag> tagProvider, String tagName, Map<String, Object> otherParameters, Map<String, Object> contextualParameters) 353 { 354 return tagName; 355 } 356 357 /** 358 * Get the list of custom tag provider 359 * @return the list of custom tag provider 360 */ 361 protected abstract List<TagProvider<? extends Tag>> getCustomTagProvider(); 362}