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