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