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