001/* 002 * Copyright 2022 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.plugins.calendar.search; 017 018import java.io.IOException; 019import java.util.Arrays; 020import java.util.Collection; 021import java.util.HashMap; 022import java.util.Locale; 023import java.util.Map; 024import java.util.Optional; 025import java.util.Set; 026 027import org.apache.cocoon.components.source.impl.SitemapSource; 028import org.apache.cocoon.environment.Request; 029import org.apache.cocoon.xml.AttributesImpl; 030import org.apache.cocoon.xml.XMLUtils; 031import org.apache.commons.lang3.StringUtils; 032import org.slf4j.Logger; 033import org.xml.sax.ContentHandler; 034import org.xml.sax.SAXException; 035 036import org.ametys.cms.contenttype.ContentTypesHelper; 037import org.ametys.cms.repository.Content; 038import org.ametys.cms.tag.Tag; 039import org.ametys.core.user.UserIdentity; 040import org.ametys.core.util.DateUtils; 041import org.ametys.core.util.IgnoreRootHandler; 042import org.ametys.core.util.LambdaUtils; 043import org.ametys.plugins.repository.AmetysObject; 044import org.ametys.plugins.repository.tag.TagAwareAmetysObject; 045import org.ametys.runtime.model.View; 046import org.ametys.runtime.model.type.DataContext; 047import org.ametys.web.WebConstants; 048import org.ametys.web.content.GetSiteAction; 049import org.ametys.web.frontoffice.search.metamodel.ReturnableSaxer; 050import org.ametys.web.frontoffice.search.metamodel.impl.AbstractContentBasedReturnable; 051import org.ametys.web.frontoffice.search.metamodel.impl.ContentSaxer; 052import org.ametys.web.frontoffice.search.requesttime.SearchComponentArguments; 053import org.ametys.web.repository.content.WebContent; 054import org.ametys.web.repository.site.Site; 055 056/** 057 * {@link ReturnableSaxer} for {@link CalendarContentReturnable} 058 */ 059public class CalendarContentSaxer extends ContentSaxer 060{ 061 /** 062 * Constructor 063 * @param contentReturnable The associated returnable on contents 064 * @param view The view for SAXing contents 065 * @param cTypesHelper the {@link ContentTypesHelper} 066 * @param contentTypes the allowed content types 067 */ 068 public CalendarContentSaxer(AbstractContentBasedReturnable contentReturnable, String view, ContentTypesHelper cTypesHelper, Collection<String> contentTypes) 069 { 070 super(contentReturnable, view, cTypesHelper, contentTypes); 071 } 072 073 @Override 074 public void sax(ContentHandler contentHandler, AmetysObject hit, Logger logger, SearchComponentArguments args) throws SAXException 075 { 076 Content content = (Content) hit; 077 078 View view = _cTypesHelper.getView(_view, content); 079 080 AttributesImpl attrs = new AttributesImpl(); 081 attrs.addCDATAAttribute("id", content.getId()); 082 attrs.addCDATAAttribute("name", content.getName()); 083 attrs.addCDATAAttribute("title", content.getTitle(null)); 084 attrs.addCDATAAttribute("createdAt", DateUtils.zonedDateTimeToString(content.getCreationDate())); 085 attrs.addCDATAAttribute("creator", UserIdentity.userIdentityToString(content.getCreator())); 086 attrs.addCDATAAttribute("lastModifiedAt", DateUtils.zonedDateTimeToString(content.getLastModified())); 087 088 Optional.ofNullable(content.getLanguage()).ifPresent(lang -> attrs.addCDATAAttribute("language", lang)); 089 090 XMLUtils.startElement(contentHandler, "content", attrs); 091 092 String[] contentTypes = content.getTypes(); 093 XMLUtils.startElement(contentHandler, "contentTypes"); 094 Arrays.asList(contentTypes).forEach(LambdaUtils.wrapConsumer(cType -> XMLUtils.createElement(contentHandler, "contentType", cType))); 095 XMLUtils.endElement(contentHandler, "contentTypes"); 096 097 XMLUtils.startElement(contentHandler, "attributes"); 098 Locale defaultLocale = getDefaultLocale(args.request(), args); 099 content.dataToSAX(contentHandler, view, DataContext.newInstance().withLocale(defaultLocale).withEmptyValues(false)); 100 XMLUtils.endElement(contentHandler, "attributes"); 101 102 saxHtmlView(contentHandler, content, args, logger); 103 104 saxTags(content, contentHandler); 105 106 XMLUtils.endElement(contentHandler, "content"); 107 } 108 109 /** 110 * Get the default locale 111 * @param request the request 112 * @param args the search arguments 113 * @return the default locale 114 */ 115 protected Locale getDefaultLocale(Request request, SearchComponentArguments args) 116 { 117 String lang = args.generatorParameters().getParameter("lang", request.getParameter("lang")); 118 return StringUtils.isNotEmpty(lang) ? new Locale(lang) : Locale.getDefault(); 119 } 120 121 /** 122 * SAX content html view 123 * @param contentHandler the content handler 124 * @param content the content 125 * @param args the search arguments 126 * @param logger the logger 127 * @throws SAXException if an error occurred while saxing 128 */ 129 protected void saxHtmlView(ContentHandler contentHandler, Content content, SearchComponentArguments args, Logger logger) throws SAXException 130 { 131 132 Request request = args.request(); 133 String currentSiteName = (String) request.getAttribute(WebConstants.REQUEST_ATTR_SITE_NAME); 134 Site currentSite = (Site) request.getAttribute(WebConstants.REQUEST_ATTR_SITE); 135 String currentSkinName = (String) request.getAttribute(WebConstants.REQUEST_ATTR_SKIN_ID); 136 137 try 138 { 139 // Content of other sites should be rendered with the current skin 140 request.setAttribute(GetSiteAction.OVERRIDE_SITE_REQUEST_ATTR, currentSiteName); 141 request.setAttribute(GetSiteAction.OVERRIDE_SKIN_REQUEST_ATTR, currentSkinName); 142 143 XMLUtils.startElement(contentHandler, "view"); 144 145 if (_contentReturnable instanceof CalendarContentReturnable) 146 { 147 148 149 String uri = _contentReturnable.getContentHelper().getContentHtmlViewUrl(content, _view); 150 151 SitemapSource src = null; 152 153 try 154 { 155 src = (SitemapSource) ((CalendarContentReturnable) _contentReturnable)._srcResolver.resolveURI(uri); 156 src.toSAX(new IgnoreRootHandler(contentHandler)); 157 } 158 finally 159 { 160 ((CalendarContentReturnable) _contentReturnable)._srcResolver.release(src); 161 } 162 } 163 164 XMLUtils.endElement(contentHandler, "view"); 165 } 166 catch (IOException e) 167 { 168 logger.error("Unable to sax HTML view for content '{}'", content.getId(), e); 169 } 170 finally 171 { 172 // Need to do this as contentFilterHelper redirects to a Cocoon URL that gets through 'GetSiteAction' which changes some request attributes 173 request.removeAttribute(GetSiteAction.OVERRIDE_SITE_REQUEST_ATTR); 174 request.removeAttribute(GetSiteAction.OVERRIDE_SKIN_REQUEST_ATTR); 175 request.setAttribute(WebConstants.REQUEST_ATTR_SITE_NAME, currentSiteName); 176 request.setAttribute(WebConstants.REQUEST_ATTR_SITE, currentSite); 177 request.setAttribute("siteName", currentSiteName); 178 request.setAttribute(WebConstants.REQUEST_ATTR_SKIN_ID, currentSkinName); 179 } 180 } 181 182 /** 183 * Generates SAX events for tags. 184 * @param content the {@link WebContent}. 185 * @param contentHandler the ContentHandler receving SAX events. 186 * @throws SAXException if an error occurs during the SAX events generation. 187 */ 188 protected void saxTags(Content content, ContentHandler contentHandler) throws SAXException 189 { 190 if (_contentReturnable instanceof CalendarContentReturnable) 191 { 192 XMLUtils.startElement(contentHandler, "tags"); 193 194 Set<String> tags = ((TagAwareAmetysObject) content).getTags(); 195 for (String tagName : tags) 196 { 197 Map<String, Object> contextParameters = new HashMap<>(); 198 if (content instanceof WebContent) 199 { 200 contextParameters.put("siteName", ((WebContent) content).getSiteName()); 201 } 202 203 Tag tag = ((CalendarContentReturnable) _contentReturnable).getTagProviderExtensionPoint().getTag(tagName, contextParameters); 204 205 if (tag != null) 206 { 207 AttributesImpl attrs = new AttributesImpl(); 208 if (tag.getParentName() != null) 209 { 210 attrs.addCDATAAttribute("parent", tag.getParentName()); 211 } 212 213 XMLUtils.startElement(contentHandler, tagName, attrs); 214 tag.getTitle().toSAX(contentHandler); 215 XMLUtils.endElement(contentHandler, tagName); 216 } 217 } 218 219 XMLUtils.endElement(contentHandler, "tags"); 220 } 221 222 } 223}