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