001/* 002 * Copyright 2013 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; 017 018import java.io.IOException; 019import java.util.Comparator; 020import java.util.HashMap; 021import java.util.Locale; 022import java.util.Map; 023import java.util.Set; 024import java.util.TreeSet; 025 026import org.apache.avalon.framework.service.ServiceException; 027import org.apache.avalon.framework.service.ServiceManager; 028import org.apache.cocoon.ProcessingException; 029import org.apache.cocoon.environment.ObjectModelHelper; 030import org.apache.cocoon.environment.Request; 031import org.apache.cocoon.generation.ServiceableGenerator; 032import org.apache.cocoon.xml.AttributesImpl; 033import org.apache.cocoon.xml.XMLUtils; 034import org.apache.commons.lang3.StringUtils; 035import org.xml.sax.SAXException; 036 037import org.ametys.cms.contenttype.ContentType; 038import org.ametys.cms.contenttype.ContentTypeExtensionPoint; 039import org.ametys.cms.repository.Content; 040import org.ametys.cms.repository.DefaultContent; 041import org.ametys.cms.tag.Tag; 042import org.ametys.cms.tag.TagProviderExtensionPoint; 043import org.ametys.core.right.RightManager; 044import org.ametys.core.right.RightManager.RightResult; 045import org.ametys.plugins.repository.AmetysObject; 046import org.ametys.plugins.repository.AmetysObjectResolver; 047import org.ametys.plugins.repository.version.VersionableAmetysObject; 048import org.ametys.runtime.i18n.I18nizableText; 049 050/** 051 * Generates addition information on content 052 */ 053public class AdditionalContentPropertiesGenerator extends ServiceableGenerator 054{ 055 /** The AmetysObject resolver. */ 056 protected AmetysObjectResolver _resolver; 057 /** the Ametys rights manager */ 058 protected RightManager _rightManager; 059 /** the tag provider extension point */ 060 protected TagProviderExtensionPoint _tagProviderEP; 061 private ContentTypeExtensionPoint _contentTypeEP; 062 063 @Override 064 public void service(ServiceManager serviceManager) throws ServiceException 065 { 066 super.service(serviceManager); 067 _resolver = (AmetysObjectResolver) serviceManager.lookup(AmetysObjectResolver.ROLE); 068 _contentTypeEP = (ContentTypeExtensionPoint) serviceManager.lookup(ContentTypeExtensionPoint.ROLE); 069 _tagProviderEP = (TagProviderExtensionPoint) serviceManager.lookup(TagProviderExtensionPoint.ROLE); 070 _rightManager = (RightManager) serviceManager.lookup(RightManager.ROLE); 071 } 072 073 @Override 074 public void generate() throws IOException, SAXException, ProcessingException 075 { 076 Request request = ObjectModelHelper.getRequest(objectModel); 077 078 String contentId = parameters.getParameter("contentId", request.getParameter("contentId")); 079 080 Content content = null; 081 if (StringUtils.isNotEmpty(contentId)) 082 { 083 content = _resolver.resolveById(contentId); 084 } 085 else 086 { 087 content = (Content) request.getAttribute(Content.class.getName()); 088 } 089 090 contentHandler.startDocument(); 091 092 AttributesImpl attrs = new AttributesImpl(); 093 attrs.addCDATAAttribute("id", content.getId()); 094 if (content instanceof DefaultContent) 095 { 096 try 097 { 098 DefaultContent dc = (DefaultContent) content; 099 attrs.addCDATAAttribute("path", dc.getNode().getPath()); 100 } 101 catch (Exception e) 102 { 103 getLogger().error("Cannot determine JCR path for content " + content.getId(), e); 104 } 105 } 106 XMLUtils.startElement(contentHandler, "content", attrs); 107 108 // Take the HEAD revision 109 String revision = null; 110 if (content instanceof VersionableAmetysObject) 111 { 112 revision = ((VersionableAmetysObject) content).getRevision(); 113 ((VersionableAmetysObject) content).switchToRevision(null); 114 } 115 116 _saxContentTypesHierarchy (content); 117 _saxMixinsHierarchy(content); 118 _saxReferencingContents(content); 119 _saxTags(content); 120 _saxOtherProperties(content); 121 _saxRepositoryRights(); 122 123 if (content instanceof VersionableAmetysObject && revision != null) 124 { 125 ((VersionableAmetysObject) content).switchToRevision(revision); 126 } 127 128 XMLUtils.endElement(contentHandler, "content"); 129 contentHandler.endDocument(); 130 } 131 132 private void _saxRepositoryRights() throws SAXException 133 { 134 XMLUtils.startElement(contentHandler, "repository"); 135 XMLUtils.startElement(contentHandler, "rights"); 136 XMLUtils.createElement(contentHandler, "access", Boolean.toString(_rightManager.currentUserHasRight("REPOSITORY_Rights_Access", "/repository") == RightResult.RIGHT_ALLOW)); 137 XMLUtils.endElement(contentHandler, "rights"); 138 XMLUtils.endElement(contentHandler, "repository"); 139 140 } 141 142 /** 143 * SAX other additional properties 144 * @param content the content 145 * @throws SAXException if an error occurred while saxing 146 */ 147 protected void _saxOtherProperties (Content content) throws SAXException 148 { 149 // Nothing to do 150 } 151 152 /** 153 * SAX content's tags 154 * @param content The content 155 * @throws SAXException if an error occurred 156 */ 157 protected void _saxTags (Content content) throws SAXException 158 { 159 Set<String> tags = content.getTags(); 160 161 XMLUtils.startElement(contentHandler, "tags"); 162 163 for (String tagName : tags) 164 { 165 Tag tag = _tagProviderEP.getTag(tagName, getContextualParameters(content)); 166 if (tag != null) 167 { 168 AttributesImpl attrs = new AttributesImpl(); 169 attrs.addCDATAAttribute("name", tag.getName()); 170 XMLUtils.startElement(contentHandler, "tag", attrs); 171 tag.getTitle().toSAX(contentHandler); 172 XMLUtils.endElement(contentHandler, "tag"); 173 } 174 } 175 176 XMLUtils.endElement(contentHandler, "tags"); 177 } 178 179 /** 180 * Get the contextual parameters for the given object 181 * @param object the object 182 * @return the object's contextual parameters 183 */ 184 protected Map<String, Object> getContextualParameters (AmetysObject object) 185 { 186 return new HashMap<>(); 187 } 188 189 /** 190 * Sax the referencing contents 191 * @param content The content 192 * @throws SAXException if an error occurred while saxing 193 */ 194 protected void _saxReferencingContents (Content content) throws SAXException 195 { 196 XMLUtils.startElement(contentHandler, "referencing-contents"); 197 198 Locale locale = content.getLanguage() != null ? new Locale(content.getLanguage()) : null; 199 for (Content referrerContent : content.getReferencingContents()) 200 { 201 AttributesImpl refererAttrs = new AttributesImpl(); 202 refererAttrs.addCDATAAttribute("id", referrerContent.getId()); 203 refererAttrs.addCDATAAttribute("name", referrerContent.getName()); 204 refererAttrs.addCDATAAttribute("title", referrerContent.getTitle(locale)); 205 206 XMLUtils.createElement(contentHandler, "referencing-content", refererAttrs); 207 } 208 209 XMLUtils.endElement(contentHandler, "referencing-contents"); 210 } 211 212 /** 213 * SAX the content types hierarchy 214 * @param content The content type 215 * @throws SAXException if an error occurred while saxing 216 */ 217 protected void _saxContentTypesHierarchy (Content content) throws SAXException 218 { 219 // Sort content types 220 TreeSet<ContentType> treeSet = new TreeSet<>(new ContentTypeComparator()); 221 for (String id : content.getTypes()) 222 { 223 ContentType contentType = _contentTypeEP.getExtension(id); 224 treeSet.add(contentType); 225 } 226 227 XMLUtils.startElement(contentHandler, "content-types"); 228 for (ContentType cType : treeSet) 229 { 230 _saxContentType (cType); 231 } 232 XMLUtils.endElement(contentHandler, "content-types"); 233 } 234 235 /** 236 * SAX the content types hierarchy 237 * @param content The content type 238 * @throws SAXException if an error occurred while saxing 239 */ 240 protected void _saxMixinsHierarchy (Content content) throws SAXException 241 { 242 XMLUtils.startElement(contentHandler, "mixins"); 243 244 String[] contentTypes = content.getMixinTypes(); 245 for (String id : contentTypes) 246 { 247 ContentType cType = _contentTypeEP.getExtension(id); 248 _saxMixin(cType); 249 } 250 251 XMLUtils.endElement(contentHandler, "mixins"); 252 } 253 254 /** 255 * SAX the content type hierarchy 256 * @param cType The content type 257 * @throws SAXException if an error occurred while saxing 258 */ 259 protected void _saxContentType (ContentType cType) throws SAXException 260 { 261 AttributesImpl attrs = new AttributesImpl(); 262 263 attrs.addCDATAAttribute("id", cType.getId()); 264 265 if (cType.getSmallIcon() != null) 266 { 267 attrs.addCDATAAttribute("icon", cType.getSmallIcon()); 268 } 269 if (cType.getIconGlyph() != null) 270 { 271 attrs.addCDATAAttribute("icon-glyph", cType.getIconGlyph()); 272 } 273 if (cType.getIconDecorator() != null) 274 { 275 attrs.addCDATAAttribute("icon-decorator", cType.getIconDecorator()); 276 } 277 278 XMLUtils.startElement(contentHandler, "content-type", attrs); 279 cType.getLabel().toSAX(contentHandler, "label"); 280 281 for (String id : cType.getSupertypeIds()) 282 { 283 ContentType superType = _contentTypeEP.getExtension(id); 284 _saxContentType(superType); 285 } 286 XMLUtils.endElement(contentHandler, "content-type"); 287 } 288 289 /** 290 * SAX the mixin hierarchy 291 * @param mixin The mixin type 292 * @throws SAXException if an error occurred while saxing 293 */ 294 protected void _saxMixin (ContentType mixin) throws SAXException 295 { 296 AttributesImpl attrs = new AttributesImpl(); 297 298 attrs.addCDATAAttribute("id", mixin.getId()); 299 if (mixin.getSmallIcon() != null) 300 { 301 attrs.addCDATAAttribute("icon", mixin.getSmallIcon()); 302 } 303 if (mixin.getIconGlyph() != null) 304 { 305 attrs.addCDATAAttribute("icon-glyph", mixin.getIconGlyph()); 306 } 307 if (mixin.getIconDecorator() != null) 308 { 309 attrs.addCDATAAttribute("icon-decorator", mixin.getIconDecorator()); 310 } 311 312 XMLUtils.startElement(contentHandler, "mixin", attrs); 313 mixin.getLabel().toSAX(contentHandler, "label"); 314 for (String id : mixin.getSupertypeIds()) 315 { 316 ContentType superType = _contentTypeEP.getExtension(id); 317 _saxMixin(superType); 318 } 319 XMLUtils.endElement(contentHandler, "mixin"); 320 } 321 322 class ContentTypeComparator implements Comparator<ContentType> 323 { 324 @Override 325 public int compare(ContentType c1, ContentType c2) 326 { 327 I18nizableText t1 = c1.getLabel(); 328 I18nizableText t2 = c2.getLabel(); 329 330 String str1 = t1.isI18n() ? t1.getKey() : t1.getLabel(); 331 String str2 = t2.isI18n() ? t2.getKey() : t2.getLabel(); 332 333 int compareTo = str1.toString().compareTo(str2.toString()); 334 if (compareTo == 0) 335 { 336 // Content types have same keys but there are not equals, so do not return 0 to add it in TreeSet 337 // Indeed, in a TreeSet implementation two elements that are equal by the method compareTo are, from the standpoint of the set, equal 338 return 1; 339 } 340 return compareTo; 341 } 342 } 343}