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.odf.export.pdf; 017 018import java.io.IOException; 019import java.net.MalformedURLException; 020import java.util.HashMap; 021import java.util.LinkedHashSet; 022import java.util.Map; 023import java.util.Set; 024import java.util.stream.Collectors; 025 026import org.apache.avalon.framework.service.ServiceException; 027import org.apache.avalon.framework.service.ServiceManager; 028import org.apache.cocoon.ProcessingException; 029import org.apache.cocoon.components.source.impl.SitemapSource; 030import org.apache.cocoon.environment.ObjectModelHelper; 031import org.apache.cocoon.environment.Request; 032import org.apache.cocoon.generation.ServiceableGenerator; 033import org.apache.cocoon.xml.AttributesImpl; 034import org.apache.cocoon.xml.XMLUtils; 035import org.apache.commons.lang.StringUtils; 036import org.xml.sax.SAXException; 037 038import org.ametys.cms.CmsConstants; 039import org.ametys.cms.repository.Content; 040import org.ametys.cms.repository.DefaultContent; 041import org.ametys.core.util.IgnoreRootHandler; 042import org.ametys.odf.NoLiveVersionException; 043import org.ametys.odf.ODFHelper; 044import org.ametys.odf.ProgramItem; 045import org.ametys.odf.catalog.Catalog; 046import org.ametys.odf.catalog.CatalogsManager; 047import org.ametys.odf.course.Course; 048import org.ametys.odf.program.SubProgram; 049import org.ametys.odf.schedulable.ArchiveEducationalBookletSchedulable; 050import org.ametys.odf.schedulable.EducationalBookletSchedulable; 051import org.ametys.plugins.repository.AmetysObjectResolver; 052import org.ametys.plugins.repository.UnknownAmetysObjectException; 053import org.ametys.plugins.repository.jcr.DefaultAmetysObject; 054 055 056/** 057 * Generator producing the SAX of subprogram and its courses for the educational booklet 058 */ 059public class EducationalBookletGenerator extends ServiceableGenerator 060{ 061 private static final String __EXPORT_MODE = "educational-booklet"; 062 063 /** The Ametys object resolver */ 064 protected AmetysObjectResolver _resolver; 065 066 /** The ODF helper */ 067 protected ODFHelper _odfHelper; 068 069 /** The catalog manager */ 070 protected CatalogsManager _catalogManager; 071 072 @Override 073 public void service(ServiceManager sManager) throws ServiceException 074 { 075 super.service(sManager); 076 _resolver = (AmetysObjectResolver) sManager.lookup(AmetysObjectResolver.ROLE); 077 _odfHelper = (ODFHelper) sManager.lookup(ODFHelper.ROLE); 078 _catalogManager = (CatalogsManager) sManager.lookup(CatalogsManager.ROLE); 079 } 080 081 public void generate() throws IOException, SAXException, ProcessingException 082 { 083 Request request = ObjectModelHelper.getRequest(objectModel); 084 request.setAttribute(ODFHelper.REQUEST_ATTRIBUTE_VALID_LABEL, true); 085 086 contentHandler.startDocument(); 087 088 AttributesImpl attrs = new AttributesImpl(); 089 090 String archiveDateAsString = (String) request.getAttribute(ArchiveEducationalBookletSchedulable.PARAM_ARCHIVE_DATE); 091 if (StringUtils.isNotBlank(archiveDateAsString)) 092 { 093 attrs.addCDATAAttribute("isValidated", "true"); 094 attrs.addCDATAAttribute("archiveDate", archiveDateAsString); 095 } 096 else 097 { 098 attrs.addCDATAAttribute("isValidated", "false"); 099 } 100 101 XMLUtils.startElement(contentHandler, "booklet", attrs); 102 103 String programItemId = (String) request.getAttribute(EducationalBookletSchedulable.PARAM_PROGRAM_ITEM_ID); 104 ProgramItem programItem = _resolver.resolveById(programItemId); 105 106 _saxCatalog(programItem); 107 108 try 109 { 110 Content content = (Content) programItem; 111 _odfHelper.switchToLiveVersion((DefaultContent) content); 112 _saxProgramItem(programItem, "programItem"); 113 114 boolean includeSubPrograms = (boolean) request.getAttribute(EducationalBookletSchedulable.PARAM_INCLUDE_SUBPROGRAMS); 115 116 if (includeSubPrograms) 117 { 118 for (SubProgram subProgram : _getChildSubPrograms(programItem)) 119 { 120 _saxProgramItem(subProgram, "subprogram"); 121 } 122 } 123 124 for (Course course : _getChildCourses(programItem)) 125 { 126 _saxProgramItem(course, "course"); 127 } 128 } 129 catch (NoLiveVersionException e) 130 { 131 throw new IllegalArgumentException("The program item with id " + programItemId + " has no live version."); 132 } 133 134 XMLUtils.endElement(contentHandler, "booklet"); 135 contentHandler.endDocument(); 136 } 137 138 /** 139 * Sax the catalog of program item 140 * @param programItem the program item 141 * @throws SAXException if an error occurred 142 */ 143 protected void _saxCatalog(ProgramItem programItem) throws SAXException 144 { 145 String catalogName = programItem.getCatalog(); 146 Catalog catalog = _catalogManager.getCatalog(catalogName); 147 148 if (catalog != null) 149 { 150 AttributesImpl attrs = new AttributesImpl(); 151 attrs.addCDATAAttribute("name", catalogName); 152 XMLUtils.createElement(contentHandler, "catalog", attrs, catalog.getTitle()); 153 } 154 } 155 156 /** 157 * Get all child courses from the program item 158 * @param programItem the program item 159 * @return the set of child courses 160 * @throws MalformedURLException if an error occurred 161 * @throws IOException if an error occurred 162 * @throws SAXException if an error occurred 163 */ 164 protected Set<Course> _getChildCourses(ProgramItem programItem) throws MalformedURLException, IOException, SAXException 165 { 166 Set<Course> courses = new LinkedHashSet<>(); 167 for (ProgramItem childProgramItem : _odfHelper.getChildProgramItems(programItem)) 168 { 169 try 170 { 171 _odfHelper.switchToLiveVersion((DefaultAmetysObject) childProgramItem); 172 if (childProgramItem instanceof Course) 173 { 174 courses.add((Course) childProgramItem); 175 } 176 courses.addAll(_getChildCourses(childProgramItem)); 177 } 178 catch (NoLiveVersionException e) 179 { 180 getLogger().warn("Cannot add the course to the educational booklet : Live label is required but there is no Live version for content " + childProgramItem.getId()); 181 } 182 } 183 184 return courses; 185 } 186 187 /** 188 * Get the direct child {@link SubProgram}s of a {@link ProgramItem} 189 * @param programItem the program item 190 * @return the subprograms 191 */ 192 protected Set<SubProgram> _getChildSubPrograms(ProgramItem programItem) 193 { 194 return _odfHelper.getChildProgramItems(programItem) 195 .stream() 196 .filter(SubProgram.class::isInstance) 197 .map(SubProgram.class::cast) 198 .collect(Collectors.toSet()); 199 } 200 201 /** 202 * Sax a {@link ProgramItem} as fo 203 * @param programItem the program item 204 * @param tagName the xml tag name 205 * @throws MalformedURLException if an error occurred 206 * @throws IOException if an error occurred 207 * @throws SAXException if an error occurred 208 */ 209 protected void _saxProgramItem(ProgramItem programItem, String tagName) throws MalformedURLException, IOException, SAXException 210 { 211 AttributesImpl attrs = new AttributesImpl(); 212 attrs.addCDATAAttribute("id", programItem.getId()); 213 attrs.addCDATAAttribute("name", programItem.getName()); 214 attrs.addCDATAAttribute("title", ((Content) programItem).getTitle()); 215 attrs.addCDATAAttribute("code", programItem.getCode()); 216 217 XMLUtils.startElement(contentHandler, tagName, attrs); 218 _saxContentAsFo((Content) programItem); 219 XMLUtils.endElement(contentHandler, tagName); 220 } 221 222 /** 223 * Sax content as fo 224 * @param content the content 225 * @throws MalformedURLException if an error occurred 226 * @throws IOException if an error occurred 227 * @throws SAXException if an error occurred 228 */ 229 protected void _saxContentAsFo(Content content) throws MalformedURLException, IOException, SAXException 230 { 231 XMLUtils.startElement(contentHandler, "fo"); 232 SitemapSource src = null; 233 234 try 235 { 236 Map<String, Object> pdfParameters = new HashMap<>(); 237 pdfParameters.put("versionLabel", CmsConstants.LIVE_LABEL); 238 pdfParameters.put("exportMode", __EXPORT_MODE); 239 240 String uri = "cocoon://_plugins/odf/_content/" + content.getName() + ".fo"; 241 src = (SitemapSource) resolver.resolveURI(uri, null, pdfParameters); 242 src.toSAX(new IgnoreRootHandler(contentHandler)); 243 } 244 catch (UnknownAmetysObjectException e) 245 { 246 // The content may be archived 247 } 248 finally 249 { 250 resolver.release(src); 251 } 252 253 XMLUtils.endElement(contentHandler, "fo"); 254 } 255}