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 085 contentHandler.startDocument(); 086 087 AttributesImpl attrs = new AttributesImpl(); 088 089 String archiveDateAsString = (String) request.getAttribute(ArchiveEducationalBookletSchedulable.PARAM_ARCHIVE_DATE); 090 if (StringUtils.isNotBlank(archiveDateAsString)) 091 { 092 attrs.addCDATAAttribute("isValidated", "true"); 093 attrs.addCDATAAttribute("archiveDate", archiveDateAsString); 094 } 095 else 096 { 097 attrs.addCDATAAttribute("isValidated", "false"); 098 } 099 100 XMLUtils.startElement(contentHandler, "booklet", attrs); 101 102 String programItemId = (String) request.getAttribute(EducationalBookletSchedulable.PARAM_PROGRAM_ITEM_ID); 103 ProgramItem programItem = _resolver.resolveById(programItemId); 104 105 _saxCatalog(programItem); 106 107 try 108 { 109 Content content = (Content) programItem; 110 _odfHelper.switchToLiveVersion((DefaultContent) content); 111 _saxProgramItem(programItem, "programItem"); 112 113 boolean includeSubPrograms = (boolean) request.getAttribute(EducationalBookletSchedulable.PARAM_INCLUDE_SUBPROGRAMS); 114 115 if (includeSubPrograms) 116 { 117 for (SubProgram subProgram : _getChildSubPrograms(programItem)) 118 { 119 _saxProgramItem(subProgram, "subprogram"); 120 } 121 } 122 123 for (Course course : _getChildCourses(programItem)) 124 { 125 _saxProgramItem(course, "course"); 126 } 127 } 128 catch (NoLiveVersionException e) 129 { 130 throw new IllegalArgumentException("The program item with id " + programItemId + " has no live version."); 131 } 132 133 XMLUtils.endElement(contentHandler, "booklet"); 134 contentHandler.endDocument(); 135 } 136 137 /** 138 * Sax the catalog of program item 139 * @param programItem the program item 140 * @throws SAXException if an error occurred 141 */ 142 protected void _saxCatalog(ProgramItem programItem) throws SAXException 143 { 144 String catalogName = programItem.getCatalog(); 145 Catalog catalog = _catalogManager.getCatalog(catalogName); 146 147 if (catalog != null) 148 { 149 AttributesImpl attrs = new AttributesImpl(); 150 attrs.addCDATAAttribute("name", catalogName); 151 XMLUtils.createElement(contentHandler, "catalog", attrs, catalog.getTitle()); 152 } 153 } 154 155 /** 156 * Get all child courses from the program item 157 * @param programItem the program item 158 * @return the set of child courses 159 * @throws MalformedURLException if an error occurred 160 * @throws IOException if an error occurred 161 * @throws SAXException if an error occurred 162 */ 163 protected Set<Course> _getChildCourses(ProgramItem programItem) throws MalformedURLException, IOException, SAXException 164 { 165 Set<Course> courses = new LinkedHashSet<>(); 166 for (ProgramItem childProgramItem : _odfHelper.getChildProgramItems(programItem)) 167 { 168 try 169 { 170 _odfHelper.switchToLiveVersion((DefaultAmetysObject) childProgramItem); 171 if (childProgramItem instanceof Course) 172 { 173 courses.add((Course) childProgramItem); 174 } 175 courses.addAll(_getChildCourses(childProgramItem)); 176 } 177 catch (NoLiveVersionException e) 178 { 179 getLogger().warn("Cannot add the course to the educational booklet : Live label is required but there is no Live version for content " + childProgramItem.getId()); 180 } 181 } 182 183 return courses; 184 } 185 186 /** 187 * Get the direct child {@link SubProgram}s of a {@link ProgramItem} 188 * @param programItem the program item 189 * @return the subprograms 190 */ 191 protected Set<SubProgram> _getChildSubPrograms(ProgramItem programItem) 192 { 193 return _odfHelper.getChildProgramItems(programItem) 194 .stream() 195 .filter(SubProgram.class::isInstance) 196 .map(SubProgram.class::cast) 197 .collect(Collectors.toSet()); 198 } 199 200 /** 201 * Sax a {@link ProgramItem} as fo 202 * @param programItem the program item 203 * @param tagName the xml tag name 204 * @throws MalformedURLException if an error occurred 205 * @throws IOException if an error occurred 206 * @throws SAXException if an error occurred 207 */ 208 protected void _saxProgramItem(ProgramItem programItem, String tagName) throws MalformedURLException, IOException, SAXException 209 { 210 AttributesImpl attrs = new AttributesImpl(); 211 attrs.addCDATAAttribute("id", programItem.getId()); 212 attrs.addCDATAAttribute("name", programItem.getName()); 213 attrs.addCDATAAttribute("title", ((Content) programItem).getTitle()); 214 attrs.addCDATAAttribute("code", programItem.getCode()); 215 216 XMLUtils.startElement(contentHandler, tagName, attrs); 217 _saxContentAsFo((Content) programItem); 218 XMLUtils.endElement(contentHandler, tagName); 219 } 220 221 /** 222 * Sax content as fo 223 * @param content the content 224 * @throws MalformedURLException if an error occurred 225 * @throws IOException if an error occurred 226 * @throws SAXException if an error occurred 227 */ 228 protected void _saxContentAsFo(Content content) throws MalformedURLException, IOException, SAXException 229 { 230 XMLUtils.startElement(contentHandler, "fo"); 231 SitemapSource src = null; 232 233 try 234 { 235 Map<String, Object> pdfParameters = new HashMap<>(); 236 pdfParameters.put("versionLabel", CmsConstants.LIVE_LABEL); 237 pdfParameters.put("exportMode", __EXPORT_MODE); 238 239 String uri = "cocoon://_plugins/odf/_content/" + content.getName() + ".fo"; 240 src = (SitemapSource) resolver.resolveURI(uri, null, pdfParameters); 241 src.toSAX(new IgnoreRootHandler(contentHandler)); 242 } 243 catch (UnknownAmetysObjectException e) 244 { 245 // The content may be archived 246 } 247 finally 248 { 249 resolver.release(src); 250 } 251 252 XMLUtils.endElement(contentHandler, "fo"); 253 } 254}