001/* 002 * Copyright 2020 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.workspaces.search.module; 017 018import java.util.Collection; 019import java.util.Date; 020import java.util.HashMap; 021import java.util.Locale; 022import java.util.Map; 023import java.util.Set; 024 025import org.apache.avalon.framework.service.ServiceException; 026import org.apache.avalon.framework.service.ServiceManager; 027import org.apache.cocoon.environment.Request; 028import org.apache.cocoon.xml.AttributesImpl; 029import org.apache.cocoon.xml.XMLUtils; 030import org.xml.sax.SAXException; 031 032import org.ametys.cms.contenttype.ContentTypesHelper; 033import org.ametys.cms.repository.Content; 034import org.ametys.cms.search.SearchResults; 035import org.ametys.cms.search.Sort.Order; 036import org.ametys.cms.search.content.ContentSearcherFactory; 037import org.ametys.cms.search.content.ContentSearcherFactory.SimpleContentSearcher; 038import org.ametys.cms.search.query.Query; 039import org.ametys.cms.tag.Tag; 040import org.ametys.cms.tag.TagProviderExtensionPoint; 041import org.ametys.core.user.UserIdentity; 042import org.ametys.core.util.DateUtils; 043import org.ametys.plugins.repository.AmetysObject; 044import org.ametys.runtime.model.View; 045import org.ametys.runtime.model.type.DataContext; 046import org.ametys.web.repository.content.WebContent; 047import org.ametys.web.repository.page.Page; 048 049/** 050 * Abstract generator for search module of type content 051 * 052 */ 053public abstract class AbstractContentSolrSearchModuleGenerator extends AbstractSolrSearchModuleGenerator 054{ 055 /** The content searcher factory */ 056 protected ContentSearcherFactory _contentSearcherFactory; 057 /** The content types helper */ 058 protected ContentTypesHelper _cTypesHelper; 059 /** The tag provider */ 060 protected TagProviderExtensionPoint _tagProviderEP; 061 062 @Override 063 public void service(ServiceManager smanager) throws ServiceException 064 { 065 super.service(smanager); 066 _contentSearcherFactory = (ContentSearcherFactory) manager.lookup(ContentSearcherFactory.ROLE); 067 _cTypesHelper = (ContentTypesHelper) smanager.lookup(ContentTypesHelper.ROLE); 068 _tagProviderEP = (TagProviderExtensionPoint) smanager.lookup(TagProviderExtensionPoint.ROLE); 069 } 070 071 @Override 072 protected void saxHit(AmetysObject object, String lang) throws Exception 073 { 074 if (object instanceof Content) 075 { 076 Content content = (Content) object; 077 View view = _cTypesHelper.getView("search", content.getTypes(), content.getMixinTypes()); 078 if (view == null) 079 { 080 // fallback to main view 081 view = _cTypesHelper.getView("main", content.getTypes(), content.getMixinTypes()); 082 } 083 084 AttributesImpl attrs = new AttributesImpl(); 085 attrs.addCDATAAttribute("id", content.getId()); 086 attrs.addCDATAAttribute("title", content.getTitle()); 087 088 attrs.addCDATAAttribute("createdAt", DateUtils.dateToString(content.getCreationDate())); 089 attrs.addCDATAAttribute("creator", UserIdentity.userIdentityToString(content.getCreator())); 090 attrs.addCDATAAttribute("lastModifiedAt", DateUtils.dateToString(content.getLastModified())); 091 Date lastValidatedAt = content.getLastValidationDate(); 092 if (lastValidatedAt != null) 093 { 094 attrs.addCDATAAttribute("lastValidatedAt", DateUtils.dateToString(lastValidatedAt)); 095 } 096 097 attrs.addCDATAAttribute("lastContributor", UserIdentity.userIdentityToString(content.getLastContributor())); 098 099 XMLUtils.startElement(contentHandler, "hit", attrs); 100 101 XMLUtils.startElement(contentHandler, "attributes"); 102 content.dataToSAX(contentHandler, view, DataContext.newInstance().withLocale(new Locale(lang)).withEmptyValues(false)); 103 XMLUtils.endElement(contentHandler, "attributes"); 104 105 saxAdditionalInformation(content); 106 107 XMLUtils.endElement(contentHandler, "hit"); 108 } 109 else 110 { 111 getLogger().error("Object '" + object.getId() + "' is not a Content."); 112 } 113 } 114 115 /** 116 * SAX additional information on content 117 * @param content the content 118 * @throws SAXException if an error occurs while saxing 119 */ 120 protected void saxAdditionalInformation(Content content) throws SAXException 121 { 122 saxPage(content); 123 saxTags(content); 124 } 125 126 /** 127 * SAX page content 128 * @param content the content 129 * @throws SAXException if an error occured while saxing 130 */ 131 protected void saxPage(Content content) throws SAXException 132 { 133 if (content instanceof WebContent) 134 { 135 Collection<Page> referencingPages = ((WebContent) content).getReferencingPages(); 136 if (!referencingPages.isEmpty()) 137 { 138 XMLUtils.createElement(contentHandler, "page", referencingPages.iterator().next().getId()); 139 } 140 } 141 } 142 143 /** 144 * SAX content's tags 145 * @param content the content 146 * @throws SAXException if an error occured while saxing 147 */ 148 protected void saxTags(Content content) throws SAXException 149 { 150 Set<String> tags = content.getTags(); 151 if (!tags.isEmpty()) 152 { 153 XMLUtils.startElement(contentHandler, "tags"); 154 155 for (String tagName : tags) 156 { 157 Map<String, Object> contextParameters = new HashMap<>(); 158 if (content instanceof WebContent) 159 { 160 contextParameters.put("siteName", ((WebContent) content).getSiteName()); 161 } 162 Tag tag = _tagProviderEP.getTag(tagName, contextParameters); 163 164 if (tag != null) 165 { 166 AttributesImpl attrs = new AttributesImpl(); 167 if (tag.getParentName() != null) 168 { 169 attrs.addCDATAAttribute("parent", tag.getParentName()); 170 } 171 172 XMLUtils.startElement(contentHandler, tagName, attrs); 173 tag.getTitle().toSAX(contentHandler); 174 XMLUtils.endElement(contentHandler, tagName); 175 } 176 } 177 178 XMLUtils.endElement(contentHandler, "tags"); 179 } 180 } 181 182 @Override 183 protected SearchResults<Content> getSearchResults(String siteName, String lang, String textfield, Request request, int offset, int limit) throws Exception 184 { 185 SimpleContentSearcher searcher = getSearcher(); 186 187 Query query = getQuery(siteName, lang, textfield, request); 188 189 return searcher 190 .withLimits(offset, limit) 191 .addSort(getSortFieldName(), getSortOrder()) 192 .searchWithFacets(query); 193 } 194 195 /** 196 * Get the searcher 197 * @return the searcher 198 */ 199 protected abstract SimpleContentSearcher getSearcher(); 200 201 /** 202 * The sort field name 203 * @return the sort field name 204 */ 205 protected abstract String getSortFieldName(); 206 207 /** 208 * The sort order 209 * @return the sort order 210 */ 211 protected abstract Order getSortOrder(); 212 213 /** 214 * Get the search query 215 * @param siteName the current site name 216 * @param lang the current language 217 * @param textfield the search input 218 * @param request the request 219 * @return the search query 220 */ 221 protected abstract Query getQuery(String siteName, String lang, String textfield, Request request); 222}