001/* 002 * Copyright 2019 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.odfweb.service.search; 017 018import java.time.ZonedDateTime; 019import java.util.Collections; 020import java.util.List; 021import java.util.Locale; 022import java.util.Optional; 023import java.util.stream.Collectors; 024 025import org.apache.cocoon.xml.AttributesImpl; 026import org.apache.cocoon.xml.XMLUtils; 027import org.slf4j.Logger; 028import org.xml.sax.ContentHandler; 029import org.xml.sax.SAXException; 030 031import org.ametys.cms.repository.Content; 032import org.ametys.core.util.DateUtils; 033import org.ametys.odf.ProgramItem; 034import org.ametys.odf.course.Course; 035import org.ametys.odf.program.AbstractProgram; 036import org.ametys.odf.program.Program; 037import org.ametys.plugins.odfweb.repository.CoursePage; 038import org.ametys.plugins.repository.AmetysObject; 039import org.ametys.web.frontoffice.search.metamodel.ReturnableSaxer; 040import org.ametys.web.frontoffice.search.metamodel.impl.PageReturnable; 041import org.ametys.web.frontoffice.search.metamodel.impl.PageSaxer; 042import org.ametys.web.frontoffice.search.requesttime.SearchComponentArguments; 043import org.ametys.web.repository.page.Page; 044import org.ametys.web.repository.site.Site; 045 046/** 047 * {@link ReturnableSaxer} for {@link CourseReturnable} 048 * <br> 049 * <br>Note for developpers: This Saxer extends PageSaxer to have access to its protected method #saxContent() 050 */ 051public class CourseSaxer extends PageSaxer 052{ 053 private CourseReturnable _courseReturnable; 054 055 /** 056 * Constructor 057 * @param pageReturnable The course returnable (needed for superclass) 058 * @param courseReturnable The associated returnable on courses 059 */ 060 public CourseSaxer(PageReturnable pageReturnable, CourseReturnable courseReturnable) 061 { 062 super(pageReturnable); 063 _courseReturnable = courseReturnable; 064 } 065 066 @Override 067 public boolean canSax(AmetysObject hit, Logger logger, SearchComponentArguments args) 068 { 069 return hit instanceof Course; 070 } 071 072 @Override 073 public void sax(ContentHandler contentHandler, AmetysObject hit, Logger logger, SearchComponentArguments args) throws SAXException 074 { 075 Course course = (Course) hit; 076 _saxCourseContent(contentHandler, course, logger, args); 077 078 // Get the first course page found 079 Optional<CoursePage> coursePage = _resolveCoursePage(course, args.currentSite()); 080 if (coursePage.isPresent()) 081 { 082 Page page = coursePage.get(); 083 XMLUtils.createElement(contentHandler, "uri", page.getSitemap().getName() + "/" + page.getPathInSitemap()); 084 } 085 086 _saxCoursePages(contentHandler, course); 087 } 088 089 private Optional<CoursePage> _resolveCoursePage(Course course, Site currentSite) 090 { 091 return Optional.of(_courseReturnable._odfPageResolver) 092 .map(res -> res.getCoursePage(course, (AbstractProgram) null, currentSite.getName())); 093 } 094 095 private void _saxCourseContent(ContentHandler contentHandler, Course course, Logger logger, SearchComponentArguments args) throws SAXException 096 { 097 XMLUtils.createElement(contentHandler, "title", course.getTitle()); 098 ZonedDateTime lastValidationDate = course.getLastValidationDate(); 099 if (lastValidationDate != null) 100 { 101 XMLUtils.createElement(contentHandler, "lastValidation", DateUtils.zonedDateTimeToString(lastValidationDate)); 102 } 103 Locale locale = new Locale(args.currentPage().getSitemapName()); 104 saxContent(course, "index", locale, contentHandler, logger); 105 } 106 107 private void _saxCoursePages(ContentHandler contentHandler, Course course) throws SAXException 108 { 109 List<List<ProgramItem>> ancestorPaths = _courseReturnable._odfHelper.getPathOfAncestors(course); 110 for (List<ProgramItem> ancestorPath : ancestorPaths) 111 { 112 if (ancestorPath.get(0) instanceof Program) // ignore paths that is not part of a Program 113 { 114 // Filter on program items that is part of ODF pages 115 List<ProgramItem> filteredAncestor = ancestorPath.stream() 116 .filter(p -> p instanceof AbstractProgram || p instanceof Course) 117 .collect(Collectors.toList()); 118 119 List<String> courseUri = filteredAncestor.stream() 120 .map(p -> p.getId()) 121 .collect(Collectors.toList()); 122 Collections.reverse(courseUri); 123 String uri = String.join(";", courseUri); 124 125 XMLUtils.startElement(contentHandler, "coursePage"); 126 XMLUtils.createElement(contentHandler, "uri", uri); 127 128 String resolvedUri = _courseReturnable._odfURIResolver.resolve(uri, false, false, false); 129 XMLUtils.createElement(contentHandler, "resolvedUri", resolvedUri); 130 131 // Sax course path with title 132 _saxCoursePath(contentHandler, filteredAncestor); 133 134 XMLUtils.endElement(contentHandler, "coursePage"); 135 } 136 } 137 } 138 139 private void _saxCoursePath(ContentHandler contentHandler, List<ProgramItem> coursePath) throws SAXException 140 { 141 XMLUtils.startElement(contentHandler, "path"); 142 for (ProgramItem item : coursePath) 143 { 144 AttributesImpl attrs = new AttributesImpl(); 145 attrs.addCDATAAttribute("id", ((Content) item).getId()); 146 XMLUtils.createElement(contentHandler, "element", attrs, ((Content) item).getTitle()); 147 } 148 XMLUtils.endElement(contentHandler, "path"); 149 } 150} 151