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.util.List; 019 020import org.apache.avalon.framework.service.ServiceException; 021import org.apache.avalon.framework.service.ServiceManager; 022import org.apache.avalon.framework.service.Serviceable; 023import org.apache.cocoon.xml.AttributesImpl; 024import org.apache.cocoon.xml.XMLUtils; 025import org.apache.commons.lang3.tuple.Pair; 026import org.xml.sax.ContentHandler; 027import org.xml.sax.SAXException; 028 029import org.ametys.cms.search.SearchResults; 030import org.ametys.core.util.DateUtils; 031import org.ametys.plugins.calendar.events.EventsFilterHelper.DateTimeRange; 032import org.ametys.plugins.calendar.icsreader.IcsEventHelper; 033import org.ametys.plugins.calendar.icsreader.IcsReader.IcsEvents; 034import org.ametys.plugins.calendar.icsreader.LocalVEvent; 035import org.ametys.plugins.repository.AmetysObject; 036import org.ametys.plugins.repository.AmetysObjectResolver; 037import org.ametys.web.frontoffice.search.instance.SearchServiceInstance; 038import org.ametys.web.frontoffice.search.requesttime.SearchComponent; 039import org.ametys.web.frontoffice.search.requesttime.SearchComponentArguments; 040import org.ametys.web.frontoffice.search.requesttime.impl.SaxResultsSearchComponent; 041import org.ametys.web.repository.page.ZoneItem; 042 043/** 044 * {@link SearchComponent} to sax calendar events results resulting of contents' search and/or external ICS 045 * 046 */ 047public class CalendarSearchComponent extends SaxResultsSearchComponent implements Serviceable 048{ 049 private IcsEventHelper _icsEventHelper; 050 private AmetysObjectResolver _resolver; 051 052 public void service(ServiceManager smanager) throws ServiceException 053 { 054 _resolver = (AmetysObjectResolver) smanager.lookup(AmetysObjectResolver.ROLE); 055 _icsEventHelper = (IcsEventHelper) smanager.lookup(IcsEventHelper.ROLE); 056 } 057 058 @Override 059 public boolean supports(SearchComponentArguments args) 060 { 061 return CalendarSearchService.isFormSubmit(args) && CalendarSearchService.isActive(args); 062 } 063 064 @Override 065 public void execute(SearchComponentArguments args) throws Exception 066 { 067 SearchResults<AmetysObject> aoResults = getResults(args); 068 069 String zoneItemId = args.serviceInstance().getId(); 070 ZoneItem zoneItem = (ZoneItem) _resolver.resolveById(zoneItemId); 071 072 DateTimeRange dateRange = CalendarSearchService.getDateRange(args); 073 List<IcsEvents> icsResults; 074 075 if (args.generatorParameters().getParameterAsBoolean("export", false)) 076 { 077 // If we are exporting the ICS, we do not want to use maximum events or ICS file size limitation 078 icsResults = _icsEventHelper.getICSEvents(zoneItem, args.currentSite().getName(), dateRange, Long.MAX_VALUE, Long.MAX_VALUE); 079 } 080 else 081 { 082 icsResults = _icsEventHelper.getICSEvents(zoneItem, args.currentSite().getName(), dateRange); 083 } 084 085 ContentHandler handler = args.contentHandler(); 086 087 int aoTotal = total(aoResults, args.serviceInstance()); 088 int total = aoTotal + icsResults.size(); 089 090 AttributesImpl atts = new AttributesImpl(); 091 atts.addCDATAAttribute("total", String.valueOf(total)); 092 XMLUtils.startElement(handler, "hits", atts); 093 094 SearchServiceInstance service = args.serviceInstance(); 095 096 // Content's hits 097 saxHits(aoResults, 0, args, service.getReturnables(), service.getAdditionalParameterValues()); 098 099 // ICS hits 100 List<String> selectedTags = CalendarSearchService.getSelectedTags(args); 101 saxICSHits(handler, icsResults, dateRange, selectedTags, aoTotal); 102 103 XMLUtils.endElement(handler, "hits"); 104 105 saxDangeRange(handler, dateRange, total); 106 107 _icsEventHelper.saxICSErrors(icsResults, handler); 108 109 } 110 111 /** 112 * SAX results resulting of external ICS 113 * @param handler the content handler 114 * @param icsResults the ICS events 115 * @param dateRange the date range 116 * @param filteredTags A list of tag's name to filter ICS events. If empty no filter is applied. 117 * @param start the start index 118 * @throws SAXException if an error occured 119 */ 120 protected void saxICSHits(ContentHandler handler, List<IcsEvents> icsResults, DateTimeRange dateRange, List<String> filteredTags, int start) throws SAXException 121 { 122 Pair<List<LocalVEvent>, String> localIcsEvents = _icsEventHelper.toLocalIcsEvent(icsResults, dateRange, filteredTags); 123 124 List<LocalVEvent> icsHits = localIcsEvents.getLeft(); 125 _icsEventHelper.saxIcsEventHits(handler, icsHits, start); 126 127 String fullICSDistantEvents = localIcsEvents.getRight(); 128 XMLUtils.createElement(handler, "rawICS", fullICSDistantEvents); 129 130 // Generate VTimeZones for distant events 131 String timezones = _icsEventHelper.toVTimeZone(icsResults, dateRange, List.of()); 132 133 XMLUtils.createElement(handler, "timezones", timezones); 134 } 135 136 /** 137 * SAx date range 138 * @param handler the content handler 139 * @param dateRange the date range 140 * @param total the total hits in date range 141 * @throws SAXException if an error occured 142 */ 143 protected void saxDangeRange(ContentHandler handler, DateTimeRange dateRange, int total) throws SAXException 144 { 145 if (dateRange != null) 146 { 147 AttributesImpl atts = new AttributesImpl(); 148 atts.addCDATAAttribute("total", String.valueOf(total)); 149 atts.addCDATAAttribute("start", DateUtils.zonedDateTimeToString(dateRange.fromDate())); 150 atts.addCDATAAttribute("end", DateUtils.zonedDateTimeToString(dateRange.untilDate())); 151 152 XMLUtils.createElement(handler, "date-range", atts); 153 } 154 } 155}