001/* 002 * Copyright 2014 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.ArrayList; 021import java.util.List; 022import java.util.Map; 023import java.util.Optional; 024import java.util.stream.Stream; 025 026import org.apache.avalon.framework.parameters.ParameterException; 027import org.apache.avalon.framework.service.ServiceException; 028import org.apache.avalon.framework.service.ServiceManager; 029import org.apache.cocoon.ProcessingException; 030import org.apache.cocoon.components.source.impl.SitemapSource; 031import org.apache.cocoon.environment.ObjectModelHelper; 032import org.apache.cocoon.generation.ServiceableGenerator; 033import org.apache.cocoon.xml.AttributesImpl; 034import org.apache.cocoon.xml.XMLUtils; 035import org.apache.commons.lang3.StringUtils; 036import org.xml.sax.SAXException; 037 038import org.ametys.cms.contenttype.ContentAttributeDefinition; 039import org.ametys.cms.contenttype.ContentTypeExtensionPoint; 040import org.ametys.cms.repository.Content; 041import org.ametys.cms.repository.ContentTypeExpression; 042import org.ametys.cms.repository.LanguageExpression; 043import org.ametys.core.util.IgnoreRootHandler; 044import org.ametys.core.util.LambdaUtils; 045import org.ametys.odf.NoLiveVersionException; 046import org.ametys.odf.ODFHelper; 047import org.ametys.odf.ProgramItem; 048import org.ametys.odf.catalog.Catalog; 049import org.ametys.odf.catalog.CatalogsManager; 050import org.ametys.odf.enumeration.OdfReferenceTableEntry; 051import org.ametys.odf.enumeration.OdfReferenceTableHelper; 052import org.ametys.odf.orgunit.OrgUnit; 053import org.ametys.odf.program.AbstractProgram; 054import org.ametys.odf.program.Program; 055import org.ametys.odf.program.ProgramFactory; 056import org.ametys.plugins.repository.AmetysObjectIterable; 057import org.ametys.plugins.repository.AmetysObjectResolver; 058import org.ametys.plugins.repository.AmetysRepositoryException; 059import org.ametys.plugins.repository.UnknownAmetysObjectException; 060import org.ametys.plugins.repository.query.QueryHelper; 061import org.ametys.plugins.repository.query.SortCriteria; 062import org.ametys.plugins.repository.query.expression.AndExpression; 063import org.ametys.plugins.repository.query.expression.Expression; 064import org.ametys.plugins.repository.query.expression.Expression.Operator; 065import org.ametys.plugins.repository.query.expression.OrExpression; 066import org.ametys.plugins.repository.query.expression.StringExpression; 067import org.ametys.runtime.model.View; 068 069/** 070 * Generator producing the SAX events for the catalogue summary 071 */ 072public class FOProgramsGenerator extends ServiceableGenerator 073{ 074 /** The Ametys object resolver */ 075 protected AmetysObjectResolver _resolver; 076 /** The content type extension point */ 077 protected ContentTypeExtensionPoint _ctypeEP; 078 /** The ODf helper */ 079 protected ODFHelper _odfHelper; 080 /** The ODf enumeration helper */ 081 protected OdfReferenceTableHelper _odfTableRefHelper; 082 /** The catalog manager */ 083 protected CatalogsManager _catalogManager; 084 085 @Override 086 public void service(ServiceManager sManager) throws ServiceException 087 { 088 super.service(sManager); 089 _resolver = (AmetysObjectResolver) sManager.lookup(AmetysObjectResolver.ROLE); 090 _ctypeEP = (ContentTypeExtensionPoint) sManager.lookup(ContentTypeExtensionPoint.ROLE); 091 _odfHelper = (ODFHelper) sManager.lookup(ODFHelper.ROLE); 092 _odfTableRefHelper = (OdfReferenceTableHelper) sManager.lookup(OdfReferenceTableHelper.ROLE); 093 _catalogManager = (CatalogsManager) sManager.lookup(CatalogsManager.ROLE); 094 } 095 096 public void generate() throws IOException, SAXException, ProcessingException 097 { 098 contentHandler.startDocument(); 099 XMLUtils.startElement(contentHandler, "programs"); 100 101 Catalog catalog = null; 102 if ("_default".equals(source)) 103 { 104 catalog = _catalogManager.getDefaultCatalog(); 105 } 106 else 107 { 108 catalog = _catalogManager.getCatalog(source); 109 } 110 111 if (catalog == null) 112 { 113 throw new IllegalArgumentException ("Failed to generated PDF of unknown catalog '" + source + "'"); 114 } 115 116 String lang; 117 try 118 { 119 lang = parameters.getParameter("lang"); 120 } 121 catch (ParameterException e) 122 { 123 throw new IllegalArgumentException ("Missing lang parameter", e); 124 } 125 126 // Catalog 127 AttributesImpl attrs = new AttributesImpl(); 128 attrs.addCDATAAttribute("name", source); 129 XMLUtils.createElement(contentHandler, "catalog", attrs, catalog.getTitle()); 130 131 Map parentContext = (Map) objectModel.get(ObjectModelHelper.PARENT_CONTEXT); 132 133 // OrgUnit 134 OrgUnit orgUnit = Optional.ofNullable(parentContext) 135 .map(pc -> pc.get("orgunit")) 136 .map(Object::toString) 137 .map(LambdaUtils.wrap(_resolver::<OrgUnit>resolveById)) 138 .orElse(null); 139 if (orgUnit != null) 140 { 141 attrs.clear(); 142 attrs.addCDATAAttribute("id", orgUnit.getId()); 143 attrs.addCDATAAttribute("uaiCode", orgUnit.getUAICode()); 144 XMLUtils.createElement(contentHandler, "orgunit", attrs, orgUnit.getTitle()); 145 } 146 147 // Degree 148 OdfReferenceTableEntry degree = Optional.ofNullable(parentContext) 149 .map(pc -> pc.get("degree")) 150 .map(Object::toString) 151 .filter(StringUtils::isNotEmpty) 152 .map(_odfTableRefHelper::getItem) 153 .orElse(null); 154 if (degree != null) 155 { 156 attrs.clear(); 157 attrs.addCDATAAttribute("id", degree.getId()); 158 attrs.addCDATAAttribute("code", degree.getCode()); 159 attrs.addCDATAAttribute("order", String.valueOf(degree.getOrder())); 160 XMLUtils.createElement(contentHandler, "degree", attrs, degree.getLabel(lang)); 161 } 162 163 Map<String, ContentAttributeDefinition> tableRefAttributeDefs = _odfTableRefHelper.getTableRefAttributeDefinitions(ProgramFactory.PROGRAM_CONTENT_TYPE); 164 165 _saxPrograms(_getPrograms(catalog.getName(), lang, orgUnit, degree), tableRefAttributeDefs); 166 167 // SAX entries of table references 168 XMLUtils.startElement(contentHandler, "enumerated-metadata"); 169 for (ContentAttributeDefinition attributeDef : tableRefAttributeDefs.values()) 170 { 171 _odfTableRefHelper.saxItems(contentHandler, attributeDef, lang); 172 } 173 XMLUtils.endElement(contentHandler, "enumerated-metadata"); 174 175 XMLUtils.endElement(contentHandler, "programs"); 176 contentHandler.endDocument(); 177 } 178 179 /** 180 * Get programs from catalog, lang, orgunit and degree. Orgunit and degree can be null. 181 * @param catalog The catalog 182 * @param lang The content language 183 * @param orgUnit The root orgunit to display 184 * @param degree The degree 185 * @return An iterable of programs corresponding to the query with catalog, lang, orgunit and degree. 186 */ 187 protected AmetysObjectIterable<Program> _getPrograms(String catalog, String lang, OrgUnit orgUnit, OdfReferenceTableEntry degree) 188 { 189 List<Expression> exprs = new ArrayList<>(); 190 exprs.add(new ContentTypeExpression(Operator.EQ, ProgramFactory.PROGRAM_CONTENT_TYPE)); 191 exprs.add(new StringExpression(ProgramItem.CATALOG, Operator.EQ, catalog)); 192 exprs.add(new LanguageExpression(Operator.EQ, lang)); 193 194 if (degree != null) 195 { 196 exprs.add(new StringExpression(AbstractProgram.DEGREE, Operator.EQ, degree.getId())); 197 } 198 199 Expression[] orgUnitExpressions = Optional.ofNullable(orgUnit) 200 .map(_odfHelper::getSubOrgUnitIds) 201 .map(List::stream) 202 .orElseGet(Stream::empty) 203 .map(orgunitId -> new StringExpression(AbstractProgram.ORG_UNITS_REFERENCES, Operator.EQ, orgunitId)) 204 .toArray(Expression[]::new); 205 if (orgUnitExpressions.length > 0) 206 { 207 exprs.add(new OrExpression(orgUnitExpressions)); 208 } 209 210 Expression programsExpression = new AndExpression(exprs.toArray(Expression[]::new)); 211 212 SortCriteria sortCriteria = new SortCriteria(); 213 sortCriteria.addCriterion(Content.ATTRIBUTE_TITLE, true, true); 214 215 String programsQuery = QueryHelper.getXPathQuery(null, ProgramFactory.PROGRAM_NODETYPE, programsExpression, sortCriteria); 216 AmetysObjectIterable<Program> programs = _resolver.query(programsQuery); 217 218 return programs; 219 } 220 221 /** 222 * SAX programs 223 * @param programs The programs to sax 224 * @param tableRefAttributeDefs The table reference attribute definitions 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 _saxPrograms(AmetysObjectIterable<Program> programs, Map<String, ContentAttributeDefinition> tableRefAttributeDefs) throws MalformedURLException, IOException, SAXException 230 { 231 for (Program program : programs) 232 { 233 try 234 { 235 _odfHelper.switchToLiveVersionIfNeeded(program); 236 AttributesImpl attrs = new AttributesImpl(); 237 attrs.addCDATAAttribute("id", program.getId()); 238 attrs.addCDATAAttribute("name", program.getName()); 239 attrs.addCDATAAttribute("title", program.getTitle()); 240 241 XMLUtils.startElement(contentHandler, "program", attrs); 242 243 _saxTableRefAttributeValues(program, tableRefAttributeDefs); 244 245 XMLUtils.startElement(contentHandler, "fo"); 246 SitemapSource src = null; 247 248 try 249 { 250 String uri = "cocoon://_plugins/odf/_content/" + program.getName() + ".fo"; 251 src = (SitemapSource) resolver.resolveURI(uri); 252 src.toSAX(new IgnoreRootHandler(contentHandler)); 253 } 254 catch (UnknownAmetysObjectException e) 255 { 256 // The content may be archived 257 } 258 finally 259 { 260 resolver.release(src); 261 } 262 263 XMLUtils.endElement(contentHandler, "fo"); 264 XMLUtils.endElement(contentHandler, "program"); 265 } 266 catch (NoLiveVersionException e) 267 { 268 getLogger().info("No live version found for program " + program.getTitle() + " (" + program.getCode() + "). The program will not appear in the PDF export.", e); 269 } 270 } 271 } 272 273 /** 274 * SAX enumerated values of an attribute 275 * @param program The program 276 * @param tableRefAttributeDefs The table reference attribute definitions 277 * @throws AmetysRepositoryException if an error occurred 278 * @throws SAXException if an error occurred 279 * @throws IOException if an error occurred 280 */ 281 protected void _saxTableRefAttributeValues(Program program, Map<String, ContentAttributeDefinition> tableRefAttributeDefs) throws AmetysRepositoryException, SAXException, IOException 282 { 283 // Build a view containing all the reference tables attributes 284 View view = View.of(program.getModel(), tableRefAttributeDefs.keySet().toArray(new String[tableRefAttributeDefs.size()])); 285 286 // Generate SAX events for the built view 287 XMLUtils.startElement(contentHandler, "metadata"); 288 program.dataToSAX(contentHandler, view); 289 XMLUtils.endElement(contentHandler, "metadata"); 290 } 291}