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; 024 025import org.apache.avalon.framework.service.ServiceException; 026import org.apache.avalon.framework.service.ServiceManager; 027import org.apache.cocoon.ProcessingException; 028import org.apache.cocoon.components.source.impl.SitemapSource; 029import org.apache.cocoon.environment.ObjectModelHelper; 030import org.apache.cocoon.environment.Request; 031import org.apache.cocoon.generation.ServiceableGenerator; 032import org.apache.cocoon.xml.AttributesImpl; 033import org.apache.cocoon.xml.XMLUtils; 034import org.apache.commons.lang.StringUtils; 035import org.xml.sax.SAXException; 036 037import org.ametys.cms.CmsConstants; 038import org.ametys.cms.repository.Content; 039import org.ametys.core.util.IgnoreRootHandler; 040import org.ametys.odf.NoLiveVersionException; 041import org.ametys.odf.ODFHelper; 042import org.ametys.odf.ProgramItem; 043import org.ametys.odf.course.Course; 044import org.ametys.odf.program.SubProgram; 045import org.ametys.plugins.repository.AmetysObjectResolver; 046import org.ametys.plugins.repository.UnknownAmetysObjectException; 047import org.ametys.plugins.repository.jcr.DefaultAmetysObject; 048 049 050/** 051 * Generator producing the SAX of subprogram and its courses for the educational booklet 052 */ 053public class EducationalBookletGenerator extends ServiceableGenerator 054{ 055 /** The Ametys object resolver */ 056 protected AmetysObjectResolver _resolver; 057 058 /** The ODF helper */ 059 protected ODFHelper _odfHelper; 060 061 @Override 062 public void service(ServiceManager sManager) throws ServiceException 063 { 064 super.service(sManager); 065 _resolver = (AmetysObjectResolver) sManager.lookup(AmetysObjectResolver.ROLE); 066 _odfHelper = (ODFHelper) sManager.lookup(ODFHelper.ROLE); 067 } 068 069 public void generate() throws IOException, SAXException, ProcessingException 070 { 071 Request request = ObjectModelHelper.getRequest(objectModel); 072 request.setAttribute(ODFHelper.REQUEST_ATTRIBUTE_VALID_LABEL, true); 073 074 contentHandler.startDocument(); 075 076 Map parentContextParameters = (Map) objectModel.get(ObjectModelHelper.PARENT_CONTEXT); 077 if (parentContextParameters == null) 078 { 079 throw new ProcessingException("Missing parent context"); 080 } 081 082 AttributesImpl attrs = new AttributesImpl(); 083 String archiveDateAsString = (String) parentContextParameters.get("archiveDate"); 084 if (StringUtils.isNotBlank(archiveDateAsString)) 085 { 086 attrs.addCDATAAttribute("isValidated", "true"); 087 attrs.addCDATAAttribute("archiveDate", archiveDateAsString); 088 } 089 else 090 { 091 attrs.addCDATAAttribute("isValidated", "false"); 092 } 093 094 XMLUtils.startElement(contentHandler, "booklet", attrs); 095 096 String subProgramId = (String) parentContextParameters.get("subProgramId"); 097 Content content = _resolver.resolveById(subProgramId); 098 if (content instanceof SubProgram) 099 { 100 try 101 { 102 SubProgram subProgram = (SubProgram) content; 103 _odfHelper.switchToLiveVersion(subProgram); 104 _saxSubProgram(subProgram); 105 106 for (Course course : _getChildCourses(subProgram)) 107 { 108 _saxCourse(course); 109 } 110 } 111 catch (NoLiveVersionException e) 112 { 113 throw new IllegalArgumentException("The subprogram with id " + subProgramId + " has no live version."); 114 } 115 } 116 117 XMLUtils.endElement(contentHandler, "booklet"); 118 contentHandler.endDocument(); 119 } 120 121 /** 122 * Get all child courses from the program item 123 * @param programItem the program item 124 * @return the set of child courses 125 * @throws MalformedURLException if an error occurred 126 * @throws IOException if an error occurred 127 * @throws SAXException if an error occurred 128 */ 129 protected Set<Course> _getChildCourses(ProgramItem programItem) throws MalformedURLException, IOException, SAXException 130 { 131 Set<Course> courses = new LinkedHashSet<>(); 132 for (ProgramItem subProgramItem : _odfHelper.getChildProgramItems(programItem)) 133 { 134 try 135 { 136 _odfHelper.switchToLiveVersion((DefaultAmetysObject) subProgramItem); 137 if (subProgramItem instanceof Course) 138 { 139 courses.add((Course) subProgramItem); 140 } 141 courses.addAll(_getChildCourses(subProgramItem)); 142 } 143 catch (NoLiveVersionException e) 144 { 145 getLogger().warn("Cannot add the course to the educational booklet : Live label is required but there is no Live version for content " + subProgramItem.getId()); 146 } 147 } 148 149 return courses; 150 } 151 152 /** 153 * Sax course as fo 154 * @param course the course 155 * @throws MalformedURLException if an error occurred 156 * @throws IOException if an error occurred 157 * @throws SAXException if an error occurred 158 */ 159 protected void _saxCourse(Course course) throws MalformedURLException, IOException, SAXException 160 { 161 AttributesImpl attrs = new AttributesImpl(); 162 attrs.addCDATAAttribute("id", course.getId()); 163 attrs.addCDATAAttribute("name", course.getName()); 164 attrs.addCDATAAttribute("title", course.getTitle()); 165 166 XMLUtils.startElement(contentHandler, "course", attrs); 167 _saxContentAsFo(course); 168 XMLUtils.endElement(contentHandler, "course"); 169 } 170 171 /** 172 * Sax sub program as fo 173 * @param subProgram the sub program 174 * @throws MalformedURLException if an error occurred 175 * @throws IOException if an error occurred 176 * @throws SAXException if an error occurred 177 */ 178 protected void _saxSubProgram(SubProgram subProgram) throws MalformedURLException, IOException, SAXException 179 { 180 AttributesImpl attrs = new AttributesImpl(); 181 attrs.addCDATAAttribute("id", subProgram.getId()); 182 attrs.addCDATAAttribute("name", subProgram.getName()); 183 attrs.addCDATAAttribute("title", subProgram.getTitle()); 184 185 XMLUtils.startElement(contentHandler, "subProgram", attrs); 186 _saxContentAsFo(subProgram); 187 XMLUtils.endElement(contentHandler, "subProgram"); 188 } 189 190 /** 191 * Sax content as fo 192 * @param content the content 193 * @throws MalformedURLException if an error occurred 194 * @throws IOException if an error occurred 195 * @throws SAXException if an error occurred 196 */ 197 protected void _saxContentAsFo(Content content) throws MalformedURLException, IOException, SAXException 198 { 199 XMLUtils.startElement(contentHandler, "fo"); 200 SitemapSource src = null; 201 202 try 203 { 204 Map<String, Object> pdfParameters = new HashMap<>(); 205 pdfParameters.put("versionLabel", CmsConstants.LIVE_LABEL); 206 207 String uri = "cocoon://_plugins/odf/_content/" + content.getName() + ".fo"; 208 src = (SitemapSource) resolver.resolveURI(uri, null, pdfParameters); 209 src.toSAX(new IgnoreRootHandler(contentHandler)); 210 } 211 catch (UnknownAmetysObjectException e) 212 { 213 // The content may be archived 214 } 215 finally 216 { 217 resolver.release(src); 218 } 219 220 XMLUtils.endElement(contentHandler, "fo"); 221 } 222}