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