001/* 002 * Copyright 2010 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.text.DateFormat; 020import java.text.SimpleDateFormat; 021import java.util.Locale; 022 023import org.apache.avalon.framework.service.ServiceException; 024import org.apache.avalon.framework.service.ServiceManager; 025import org.apache.cocoon.ProcessingException; 026import org.apache.cocoon.environment.ObjectModelHelper; 027import org.apache.cocoon.environment.Request; 028import org.apache.cocoon.generation.Generator; 029import org.apache.cocoon.generation.ServiceableGenerator; 030import org.apache.cocoon.i18n.I18nUtils; 031import org.apache.cocoon.xml.XMLUtils; 032import org.apache.commons.lang.ArrayUtils; 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.contenttype.ContentTypesHelper; 039import org.ametys.cms.repository.Content; 040import org.ametys.runtime.model.View; 041import org.ametys.runtime.model.ViewHelper; 042 043/** 044 * {@link Generator} for rendering raw content data. 045 */ 046public class ContentGenerator extends ServiceableGenerator 047{ 048 /** The display date format. */ 049 protected static final DateFormat _DC_DATE_FORMAT = new SimpleDateFormat("yyyy-MM-dd"); 050 051 /** Content type extension point. */ 052 protected ContentTypeExtensionPoint _contentTypeExtensionPoint; 053 /** Helper for content types */ 054 protected ContentTypesHelper _cTypesHelper; 055 /** The content saxer */ 056 protected ContentSaxer _contentSaxer; 057 058 @Override 059 public void service(ServiceManager serviceManager) throws ServiceException 060 { 061 super.service(serviceManager); 062 _contentTypeExtensionPoint = (ContentTypeExtensionPoint) serviceManager.lookup(ContentTypeExtensionPoint.ROLE); 063 _cTypesHelper = (ContentTypesHelper) serviceManager.lookup(ContentTypesHelper.ROLE); 064 _contentSaxer = (ContentSaxer) serviceManager.lookup(ContentSaxer.CMS_CONTENT_SAXER_ROLE); 065 } 066 067 public void generate() throws IOException, SAXException, ProcessingException 068 { 069 contentHandler.startDocument(); 070 _generateContent(); 071 contentHandler.endDocument(); 072 } 073 074 /** 075 * Generate the content (with the start/end document) 076 * @throws SAXException if an error occurs while SAXing 077 * @throws IOException if an error occurs 078 * @throws ProcessingException if an error occurs 079 */ 080 protected void _generateContent() throws SAXException, IOException, ProcessingException 081 { 082 Request request = ObjectModelHelper.getRequest(objectModel); 083 Content content = (Content) request.getAttribute(Content.class.getName()); 084 085 // SAX the content 086 _saxContent(content, getDefaultLocale(request)); 087 } 088 089 /** 090 * Get the default locale to use to sax localized values 091 * @param request the request 092 * @return the default locale 093 */ 094 protected Locale getDefaultLocale(Request request) 095 { 096 String lang = parameters.getParameter("lang", request.getParameter("lang")); 097 return StringUtils.isNotEmpty(lang) ? new Locale(lang) : I18nUtils.findLocale(objectModel, "locale", null, Locale.getDefault(), true); 098 } 099 100 /** 101 * SAX the content 102 * @param content The content to SAX 103 * @param defaultLocale The default locale to use to sax localized values if the content's language is null. 104 * @throws SAXException if an error occurs while SAXing 105 * @throws IOException if an error occurs 106 * @throws ProcessingException if an error occurs 107 */ 108 protected void _saxContent (Content content, Locale defaultLocale) throws SAXException, IOException, ProcessingException 109 { 110 _contentSaxer.saxRootTag(content, contentHandler, defaultLocale, "content"); 111 112 boolean isEdition = parameters.getParameterAsBoolean("isEdition", false); 113 114 View view = _getView(content, isEdition); 115 Locale locale = content.getLanguage() != null ? new Locale(content.getLanguage()) : defaultLocale; 116 117 // FIXME CMS-3057 118 Request request = ObjectModelHelper.getRequest(objectModel); 119 boolean displayWorkflow = !"true".equals(request.getParameter("ignore-workflow")); 120 121 _contentSaxer.saxContent(content, contentHandler, locale, view, null, displayWorkflow, displayWorkflow, true, "metadata", isEdition); 122 123 if (isEdition) 124 { 125 XMLUtils.startElement(contentHandler, "comments"); 126 _saxAttributesComments(content, view); 127 XMLUtils.endElement(contentHandler, "comments"); 128 } 129 130 String[] cTypes = (String[]) ArrayUtils.addAll(content.getTypes(), content.getMixinTypes()); 131 for (String cTypeId : cTypes) 132 { 133 ContentType cType = _contentTypeExtensionPoint.getExtension(cTypeId); 134 cType.saxContentTypeAdditionalData(contentHandler, content); 135 } 136 137 _saxOtherData(content, defaultLocale); 138 139 XMLUtils.endElement(contentHandler, "content"); 140 } 141 142 /** 143 * SAX content attributes comments. 144 * @param content the content. 145 * @param view the view containing the attributes. 146 * @throws SAXException if an error occurs while SAXing. 147 */ 148 protected void _saxAttributesComments(Content content, View view) throws SAXException 149 { 150 content.commentsToSAX(contentHandler, view); 151 } 152 153 /** 154 * SAX any other data needed by the view.<p> 155 * Default implementation does nothing. 156 * @param content the content. 157 * @throws SAXException if an error occurs while SAXing. 158 * @throws ProcessingException if an error occurs. 159 * @deprecated Use and/or override {@link #_saxOtherData(Content, Locale)} instead 160 */ 161 @Deprecated 162 protected void _saxOtherData(Content content) throws SAXException, ProcessingException 163 { 164 // No other data to SAX 165 } 166 167 /** 168 * SAX any other data needed by the view.<p> 169 * Default implementation does nothing. 170 * @param content the content. 171 * @param defaultLocale The default locale 172 * @throws SAXException if an error occurs while SAXing. 173 * @throws ProcessingException if an error occurs. 174 * @throws IOException if an error occurs. 175 */ 176 protected void _saxOtherData(Content content, Locale defaultLocale) throws SAXException, ProcessingException, IOException 177 { 178 // For legacy purposes 179 _saxOtherData(content); 180 } 181 182 /** 183 * Retrieves the view to be used when SAX'ing attributes and attribute comments. 184 * @param content The content to consider. Cannot be null. 185 * @param isEdition <code>true</code> if the view is to use for edition, <code>false</code> otherwise 186 * @return The retrieved view 187 * @throws ProcessingException If the view could not be retrieved 188 */ 189 protected View _getView(Content content, boolean isEdition) throws ProcessingException 190 { 191 String fallbackViewName = parameters.getParameter("fallbackViewName", StringUtils.EMPTY); 192 String viewName = parameters.getParameter("viewName", StringUtils.EMPTY); 193 194 View view = _cTypesHelper.getViewWithFallback(viewName, fallbackViewName, content); 195 if (view == null) 196 { 197 String errorMsg = String.format("Unknown view '%s' nor fallback view '%s' for content '%s'", viewName, fallbackViewName, content.getId()); 198 getLogger().error(errorMsg); 199 throw new IllegalArgumentException(errorMsg); 200 } 201 202 return isEdition ? ViewHelper.getTruncatedView(view) : ViewHelper.mergeDuplicatedItems(view); 203 } 204}