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.io.IOException; 019import java.util.ArrayList; 020import java.util.HashMap; 021import java.util.HashSet; 022import java.util.List; 023import java.util.Map; 024import java.util.Set; 025 026import javax.jcr.RepositoryException; 027 028import org.apache.avalon.framework.parameters.Parameters; 029import org.apache.avalon.framework.service.ServiceException; 030import org.apache.avalon.framework.service.ServiceManager; 031import org.apache.cocoon.ProcessingException; 032import org.apache.cocoon.acting.ServiceableAction; 033import org.apache.cocoon.environment.ObjectModelHelper; 034import org.apache.cocoon.environment.Redirector; 035import org.apache.cocoon.environment.Request; 036import org.apache.cocoon.environment.SourceResolver; 037import org.apache.commons.lang.StringUtils; 038import org.xml.sax.SAXException; 039 040import org.ametys.cms.tag.jcr.AbstractJCRTagProvider; 041import org.ametys.core.cocoon.JSonReader; 042import org.ametys.plugins.repository.AmetysObjectResolver; 043import org.ametys.plugins.repository.AmetysRepositoryException; 044 045/** 046 * SAX events for tags 047 * 048 */ 049public abstract class AbstractGetTagsAction extends ServiceableAction 050{ 051 /** The tag provider extension point */ 052 protected AbstractTagProviderExtensionPoint<? extends Tag> _tagProviderExtPt; 053 054 /** The Ametys object resolver */ 055 protected AmetysObjectResolver _resolver; 056 057 @SuppressWarnings("unchecked") 058 @Override 059 public void service(ServiceManager serviceManager) throws ServiceException 060 { 061 super.service(serviceManager); 062 _resolver = (AmetysObjectResolver) serviceManager.lookup(AmetysObjectResolver.ROLE); 063 _tagProviderExtPt = (AbstractTagProviderExtensionPoint< ? extends Tag>) serviceManager.lookup(getTagProviderEPRole()); 064 } 065 066 /** 067 * Get the tag provider extension point role 068 * @return the tag provider extension point role 069 */ 070 public abstract String getTagProviderEPRole(); 071 072 @SuppressWarnings("unchecked") 073 @Override 074 public Map act(Redirector redirector, SourceResolver resolver, Map objectModel, String source, Parameters parameters) throws IOException, SAXException, ProcessingException 075 { 076 Map<String, Object> jsParameters = (Map<String, Object>) objectModel.get(ObjectModelHelper.PARENT_CONTEXT); 077 078 String parentId = (String) jsParameters.get("node"); 079 String nodeName = (String) jsParameters.get("nodeName"); 080 boolean onlyCustomTags = (Boolean) jsParameters.get("onlyCustomTags"); 081 082 List<String> objectTargetIds = (List<String>) jsParameters.get("objectTargetIds"); 083 084 Map<String, Object> contextualParameters = (Map<String, Object>) jsParameters.get("contextualParameters"); 085 086 List<Map<String, Object>> tags = new ArrayList<>(); 087 088 if (StringUtils.isEmpty(parentId) || parentId.equals("tag-root")) 089 { 090 Set<String> extensionsIds = getProvidersIds(onlyCustomTags); 091 092 for (String id : extensionsIds) 093 { 094 TagProvider<? extends Tag> tagProvider = _tagProviderExtPt.getExtension(id); 095 tags.add(providerToJSON(tagProvider, contextualParameters, jsParameters)); 096 } 097 } 098 else if (nodeName.startsWith("provider_")) 099 { 100 String providerId = nodeName.substring("provider_".length()); 101 TagProvider<? extends Tag> tagProvider = _tagProviderExtPt.getExtension(providerId); 102 103 if (tagProvider != null) 104 { 105 for (Tag tag : _getFilteredTags(tagProvider.getTags(contextualParameters), jsParameters).values()) 106 { 107 tags.add(tagToJSON(tag, tagProvider, objectTargetIds, jsParameters)); 108 } 109 } 110 } 111 else 112 { 113 Set<String> extensionsIds = getProvidersIds(onlyCustomTags); 114 for (String id : extensionsIds) 115 { 116 TagProvider<? extends Tag> tagProvider = _tagProviderExtPt.getExtension(id); 117 if (tagProvider.hasTag(nodeName, contextualParameters)) 118 { 119 Tag parent = tagProvider.getTag(nodeName, contextualParameters); 120 for (Tag tag : _getFilteredTags(parent.getTags(), jsParameters).values()) 121 { 122 tags.add(tagToJSON(tag, tagProvider, objectTargetIds, jsParameters)); 123 } 124 } 125 } 126 } 127 128 Map<String, Object> result = new HashMap<>(); 129 result.put("children", tags); 130 131 Request request = ObjectModelHelper.getRequest(objectModel); 132 request.setAttribute(JSonReader.OBJECT_TO_READ, result); 133 134 return EMPTY_MAP; 135 } 136 137 /** 138 * Get filtered tags 139 * @param tags the tags to filter 140 * @param jsParameters the js parameters 141 * @return the map of tags 142 */ 143 protected Map<String, ? extends Tag> _getFilteredTags(Map<String, ? extends Tag> tags, Map<String, Object> jsParameters) 144 { 145 return tags; 146 } 147 148 /** 149 * Get all providers IDs 150 * @param onlyCustomTags If true, return only JCR providers IDs. 151 * @return a set of providers IDs 152 */ 153 protected Set<String> getProvidersIds(boolean onlyCustomTags) 154 { 155 if (!onlyCustomTags) 156 { 157 return _tagProviderExtPt.getExtensionsIds(); 158 } 159 160 return new HashSet<>(); 161 } 162 163 /** 164 * Returns the tag providers' id 165 * @return The id of tag providers 166 */ 167 protected Set<String> getProvidersId() 168 { 169 return getProvidersIds(false); 170 } 171 172 /** 173 * Get tag's properties to JSON format 174 * @param tag The tag 175 * @param tagProvider the tag provider 176 * @param objectTargetIds the list of Ametys object ids. Can be empty 177 * @param jsParameters the js parameters 178 * @return The tag properties 179 */ 180 protected Map<String, Object> tagToJSON(Tag tag, TagProvider<? extends Tag> tagProvider, List<String> objectTargetIds, Map<String, Object> jsParameters) 181 { 182 Map<String, Object> infos = new HashMap<>(); 183 184 infos.put("id", tag.getId()); 185 infos.put("name", tag.getName()); 186 infos.put("title", tag.getTitle()); 187 infos.put("description", tag.getDescription()); 188 189 if (tag instanceof ColorableTag colorableTag) 190 { 191 infos.put("isColorable", true); 192 infos.put("color", colorableTag.getColor(true)); 193 infos.put("class", colorableTag.getColorCSSClassPrefix()); 194 } 195 196 boolean authorized = isUserAuthorized(tag, objectTargetIds, jsParameters); 197 infos.put("authorized", authorized); 198 infos.put("creationAllowed", isCreationAllowed(tagProvider, tag)); 199 200 if (tag.getTags().size() == 0) 201 { 202 infos.put("leaf", true); 203 } 204 205 return infos; 206 } 207 208 /** 209 * Get tag provider's properties to JSON format 210 * @param tagProvider the tag provider 211 * @param contextualParameters The contextual parameters 212 * @param jsParameters The js parameters 213 * @return The tag providers properties 214 * @throws AmetysRepositoryException If an error occurred 215 */ 216 protected Map<String, Object> providerToJSON(TagProvider<? extends Tag> tagProvider, Map<String, Object> contextualParameters, Map<String, Object> jsParameters) 217 { 218 Map<String, Object> infos = new HashMap<>(); 219 220 if (tagProvider instanceof AbstractJCRTagProvider) 221 { 222 AbstractJCRTagProvider<? extends Tag> provider = (AbstractJCRTagProvider<? extends Tag>) tagProvider; 223 try 224 { 225 infos.put("id", provider.getRootNode(contextualParameters).getId()); 226 } 227 catch (AmetysRepositoryException e) 228 { 229 getLogger().error("Unable to get JCR tag provider root node", e); 230 } 231 catch (RepositoryException e) 232 { 233 getLogger().error("Unable to get JCR tag provider root node", e); 234 } 235 } 236 else 237 { 238 infos.put("id", tagProvider.getId()); 239 } 240 241 infos.put("type", "provider"); 242 infos.put("name", "provider_" + tagProvider.getId()); 243 infos.put("title", tagProvider.getLabel()); 244 infos.put("description", tagProvider.getDescription()); 245 infos.put("authorized", true); 246 infos.put("creationAllowed", isCreationAllowed(tagProvider, null)); 247 infos.put("iconSmall", "/plugins/cms/resources/img/tag/tags_16.png"); 248 infos.put("iconMedium", "/plugins/cms/resources/img/tag/tags_32.png"); 249 infos.put("iconLarge", "/plugins/cms/resources/img/tag/tags_50.png"); 250 251 if (_getFilteredTags(tagProvider.getTags(contextualParameters), jsParameters).size() == 0) 252 { 253 infos.put("leaf", true); 254 } 255 return infos; 256 } 257 258 /** 259 * Test if a tag is visible to the current user. 260 * @param tag the Tag object. 261 * @param objectTargetIds the ids of current Ametys objects 262 * @param jsParameters The js parameters 263 * @return true if the user has access to the tag, false otherwise. 264 */ 265 protected boolean isUserAuthorized(Tag tag, List<String> objectTargetIds, Map<String, Object> jsParameters) 266 { 267 return true; 268 } 269 270 /** 271 * Determines if the current user can created tag 272 * @param tagProvider The tag provider 273 * @param tag The tag. Can be null. 274 * @return true if creation is allowed 275 */ 276 protected boolean isCreationAllowed(TagProvider<? extends Tag> tagProvider, Tag tag) 277 { 278 return true; 279 } 280}