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 */ 016package org.ametys.cms.content.referencetable.search; 017 018import java.util.ArrayList; 019import java.util.Collection; 020import java.util.HashMap; 021import java.util.LinkedHashMap; 022import java.util.LinkedHashSet; 023import java.util.List; 024import java.util.Locale; 025import java.util.Map; 026import java.util.Set; 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.acting.ServiceableAction; 032import org.apache.cocoon.environment.ObjectModelHelper; 033import org.apache.cocoon.environment.Redirector; 034import org.apache.cocoon.environment.Request; 035import org.apache.cocoon.environment.SourceResolver; 036import org.apache.commons.lang3.ArrayUtils; 037import org.apache.commons.lang3.StringUtils; 038 039import org.ametys.cms.content.ContentHelper; 040import org.ametys.cms.contenttype.ContentType; 041import org.ametys.cms.contenttype.ContentTypeExtensionPoint; 042import org.ametys.cms.contenttype.ContentTypesHelper; 043import org.ametys.cms.contenttype.MetadataType; 044import org.ametys.cms.languages.Language; 045import org.ametys.cms.languages.LanguagesManager; 046import org.ametys.cms.repository.Content; 047import org.ametys.cms.repository.WorkflowAwareContent; 048import org.ametys.core.cocoon.JSonReader; 049import org.ametys.core.util.DateUtils; 050import org.ametys.core.util.ServerCommHelper; 051import org.ametys.plugins.core.user.UserHelper; 052import org.ametys.plugins.repository.AmetysObjectResolver; 053import org.ametys.plugins.workflow.support.WorkflowProvider; 054import org.ametys.plugins.workflow.support.WorkflowProvider.AmetysObjectWorkflow; 055import org.ametys.runtime.i18n.I18nizableText; 056 057import com.opensymphony.workflow.loader.StepDescriptor; 058import com.opensymphony.workflow.loader.WorkflowDescriptor; 059 060/** 061 * Action for getting information about the referencing contents of a content 062 * 063 */ 064public class GetReferencingContentsAction extends ServiceableAction 065{ 066 /** The extension point for content types */ 067 protected ContentTypeExtensionPoint _contentTypeExtensionPoint; 068 /** Content types helper */ 069 protected ContentTypesHelper _contentTypesHelper; 070 /** The content helper */ 071 protected ContentHelper _contentHelper; 072 /** Server comm helper */ 073 protected ServerCommHelper _serverCommHelper; 074 /** Language Manager */ 075 protected LanguagesManager _languagesManager; 076 /** Workflow provider */ 077 protected WorkflowProvider _workflowProvider; 078 /** User helper */ 079 protected UserHelper _userHelper; 080 /** The ametys object resolver */ 081 protected AmetysObjectResolver _resolver; 082 083 @Override 084 public void service(ServiceManager smanager) throws ServiceException 085 { 086 super.service(smanager); 087 _resolver = (AmetysObjectResolver) smanager.lookup(AmetysObjectResolver.ROLE); 088 _contentTypeExtensionPoint = (ContentTypeExtensionPoint) smanager.lookup(ContentTypeExtensionPoint.ROLE); 089 _contentTypesHelper = (ContentTypesHelper) smanager.lookup(ContentTypesHelper.ROLE); 090 _serverCommHelper = (ServerCommHelper) smanager.lookup(ServerCommHelper.ROLE); 091 _contentHelper = (ContentHelper) smanager.lookup(ContentHelper.ROLE); 092 _languagesManager = (LanguagesManager) smanager.lookup(LanguagesManager.ROLE); 093 _workflowProvider = (WorkflowProvider) smanager.lookup(WorkflowProvider.ROLE); 094 _userHelper = (UserHelper) smanager.lookup(UserHelper.ROLE); 095 } 096 097 @Override 098 public Map act(Redirector redirector, SourceResolver resolver, Map objectModel, String source, Parameters parameters) throws Exception 099 { 100 Map<String, Object> result = new HashMap<>(); 101 Request request = ObjectModelHelper.getRequest(objectModel); 102 103 Map<String, Object> jsParameters = _serverCommHelper.getJsParameters(); 104 105 String contentId = (String) jsParameters.get("contentId"); 106 107 int begin = jsParameters.containsKey("start") ? (Integer) jsParameters.get("start") : 0; // Index of search 108 int offset = jsParameters.containsKey("limit") ? (Integer) jsParameters.get("limit") : Integer.MAX_VALUE; // Number of results to SAX 109 110 String lang = (String) jsParameters.get("lang"); 111 Locale defaultLocale = StringUtils.isNotEmpty(lang) ? new Locale(lang) : null; 112 113 Set<Content> referencingContents = new LinkedHashSet<>(); 114 List<Map<String, Object>> referencingContentsJson = new ArrayList<>(); 115 116 int index = 0; 117 referencingContents.addAll(getReferencingContents(contentId, true)); 118 119 for (Content content : referencingContents) 120 { 121 if (index >= begin && index < begin + offset) 122 { 123 referencingContentsJson.add(getContentData(content, defaultLocale)); 124 } 125 126 index++; 127 } 128 129 result.put("contents", referencingContentsJson); 130 request.setAttribute(JSonReader.OBJECT_TO_READ, result); 131 return EMPTY_MAP; 132 } 133 134 /** 135 * Get the contents referencing the entry of a reference table 136 * @param contentId The id of the entry 137 * @param excludeContentOfSameType true to exclude the contents of the same reference table 138 * @return The referencing contents 139 */ 140 protected Collection<Content> getReferencingContents (String contentId, boolean excludeContentOfSameType) 141 { 142 Content content = _resolver.resolveById(contentId); 143 144 Collection<Content> referencingContents = content.getReferencingContents(); 145 146 if (excludeContentOfSameType) 147 { 148 Set<Content> filteredContents = new LinkedHashSet<>(); 149 150 for (Content referencingContent : referencingContents) 151 { 152 if (_filter(content, referencingContent)) 153 { 154 filteredContents.add(referencingContent); 155 } 156 } 157 158 return filteredContents; 159 } 160 else 161 { 162 return referencingContents; 163 } 164 } 165 166 private boolean _filter(Content content, Content refContent) 167 { 168 String[] ctypes = content.getTypes(); 169 String[] refCTypes = refContent.getTypes(); 170 171 for (String ctype : ctypes) 172 { 173 if (ArrayUtils.contains(refCTypes, ctype)) 174 { 175 return false; 176 } 177 } 178 179 return true; 180 } 181 182 /** 183 * Get the JSON representation of content 184 * @param content The content 185 * @param defaultLocale The default locale 186 * @return The content data 187 */ 188 protected Map<String, Object> getContentData(Content content, Locale defaultLocale) 189 { 190 Map<String, Object> contentData = new HashMap<>(); 191 192 contentData.put("id", content.getId()); 193 contentData.put("name", content.getName()); 194 195 if (_contentHelper.isMultilingual(content) && _contentTypesHelper.getMetadataDefinition("title", content).getType() == MetadataType.MULTILINGUAL_STRING) 196 { 197 contentData.put("title", _contentHelper.getTitleVariants(content)); 198 } 199 else 200 { 201 contentData.put("title", _contentHelper.getTitle(content)); 202 } 203 204 contentData.put("language", _language2json(content)); 205 contentData.put("contentTypes", _contentTypes2json(content)); 206 contentData.put("iconGlyph", _contentTypesHelper.getIconGlyph(content)); 207 contentData.put("iconDecorator", _contentTypesHelper.getIconDecorator(content)); 208 contentData.put("smallIcon", _contentTypesHelper.getSmallIcon(content)); 209 contentData.put("mediumIcon", _contentTypesHelper.getMediumIcon(content)); 210 contentData.put("largeIcon", _contentTypesHelper.getLargeIcon(content)); 211 contentData.put("isSimple", _contentHelper.isSimple(content)); 212 contentData.put("lastModified", DateUtils.dateToString(content.getLastModified())); 213 contentData.put("creationDate", DateUtils.dateToString(content.getCreationDate())); 214 contentData.put("creator", _userHelper.user2json(content.getCreator(), true)); 215 contentData.put("contributor", _userHelper.user2json(content.getLastContributor(), true)); 216 contentData.put("workflowStep", _workflowStep2json(content)); 217 218 return contentData; 219 } 220 221 private List<I18nizableText> _contentTypes2json(Content content) 222 { 223 List<I18nizableText> cTypes = new ArrayList<>(); 224 for (String cTypeId : content.getTypes()) 225 { 226 ContentType cType = _contentTypeExtensionPoint.getExtension(cTypeId); 227 if (cType != null) 228 { 229 cTypes.add(cType.getLabel()); 230 } 231 else if (getLogger().isWarnEnabled()) 232 { 233 getLogger().warn(String.format("Trying to get the label for an unknown content type : '%s'.", cTypeId)); 234 } 235 } 236 237 return cTypes; 238 } 239 240 private Map<String, Object> _language2json(Content content) 241 { 242 Map<String, Object> infos = new LinkedHashMap<>(); 243 244 String languageCode = content.getLanguage(); 245 infos.put("code", languageCode); 246 247 if (languageCode != null) 248 { 249 Language language = _languagesManager.getLanguage(languageCode); 250 if (language != null) 251 { 252 infos.put("icon", language.getSmallIcon()); 253 infos.put("label", language.getLabel()); 254 } 255 } 256 257 return infos; 258 } 259 260 private Map<String, Object> _workflowStep2json(Content content) 261 { 262 Map<String, Object> workflowInfos = new LinkedHashMap<>(); 263 264 if (content instanceof WorkflowAwareContent) 265 { 266 WorkflowAwareContent waContent = (WorkflowAwareContent) content; 267 int currentStepId = Math.toIntExact(waContent.getCurrentStepId()); 268 269 StepDescriptor stepDescriptor = _getStepDescriptor(waContent, currentStepId); 270 271 if (stepDescriptor != null) 272 { 273 I18nizableText workflowStepName = new I18nizableText("application", stepDescriptor.getName()); 274 275 workflowInfos.put("stepId", currentStepId); 276 workflowInfos.put("name", workflowStepName); 277 278 String[] icons = new String[] {"small", "medium", "large"}; 279 for (String icon : icons) 280 { 281 if ("application".equals(workflowStepName.getCatalogue())) 282 { 283 workflowInfos.put(icon + "Icon", "/plugins/cms/resources_workflow/" + workflowStepName.getKey() + "-" + icon + ".png"); 284 } 285 else 286 { 287 String pluginName = workflowStepName.getCatalogue().substring("plugin.".length()); 288 workflowInfos.put(icon + "Icon", "/plugins/" + pluginName + "/resources/img/workflow/" + workflowStepName.getKey() + "-" + icon + ".png"); 289 } 290 } 291 } 292 } 293 294 return workflowInfos; 295 } 296 297 private StepDescriptor _getStepDescriptor(WorkflowAwareContent content, int stepId) 298 { 299 long workflowId = content.getWorkflowId(); 300 301 AmetysObjectWorkflow workflow = _workflowProvider.getAmetysObjectWorkflow(content); 302 303 String workflowName = workflow.getWorkflowName(workflowId); 304 WorkflowDescriptor workflowDescriptor = workflow.getWorkflowDescriptor(workflowName); 305 306 if (workflowDescriptor != null) 307 { 308 StepDescriptor stepDescriptor = workflowDescriptor.getStep(stepId); 309 if (stepDescriptor != null) 310 { 311 return stepDescriptor; 312 } 313 else if (getLogger().isWarnEnabled()) 314 { 315 getLogger().warn("Unknown step id '" + stepId + "' for workflow for name : " + workflowName); 316 } 317 } 318 else if (getLogger().isWarnEnabled()) 319 { 320 getLogger().warn("Unknown workflow for name : " + workflowName); 321 } 322 323 return null; 324 } 325}