001/* 002 * Copyright 2019 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.content; 017 018import java.io.IOException; 019import java.util.List; 020import java.util.Locale; 021import java.util.Optional; 022 023import org.apache.avalon.framework.service.ServiceException; 024import org.apache.avalon.framework.service.ServiceManager; 025import org.apache.cocoon.ProcessingException; 026import org.apache.cocoon.environment.ObjectModelHelper; 027import org.apache.cocoon.environment.Request; 028import org.apache.cocoon.generation.ServiceableGenerator; 029import org.apache.cocoon.xml.AttributesImpl; 030import org.apache.cocoon.xml.XMLUtils; 031import org.apache.commons.lang.StringUtils; 032import org.xml.sax.SAXException; 033 034import org.ametys.cms.contenttype.ContentTypesHelper; 035import org.ametys.cms.repository.Content; 036import org.ametys.odf.NoLiveVersionException; 037import org.ametys.odf.ODFHelper; 038import org.ametys.odf.ProgramItem; 039import org.ametys.odf.course.Course; 040import org.ametys.odf.courselist.CourseList; 041import org.ametys.odf.coursepart.CoursePart; 042import org.ametys.odf.enumeration.OdfReferenceTableEntry; 043import org.ametys.odf.enumeration.OdfReferenceTableHelper; 044import org.ametys.odf.program.AbstractProgram; 045import org.ametys.odf.program.Container; 046import org.ametys.odf.program.Program; 047import org.ametys.odf.program.SubProgram; 048import org.ametys.plugins.repository.AmetysRepositoryException; 049import org.ametys.plugins.repository.jcr.DefaultAmetysObject; 050import org.ametys.runtime.model.View; 051import org.ametys.runtime.model.exception.BadItemTypeException; 052import org.ametys.runtime.model.type.DataContext; 053 054/** 055 * SAX the structure (ie. the child program items) of a {@link ProgramItem} 056 * 057 */ 058public class ProgramItemStructureGenerator extends ServiceableGenerator 059{ 060 /** The ODF helper */ 061 protected ODFHelper _odfHelper; 062 /** Helper for ODF reference table */ 063 protected OdfReferenceTableHelper _odfReferenceTableHelper; 064 /** The content types helper */ 065 protected ContentTypesHelper _cTypesHelper; 066 067 @Override 068 public void service(ServiceManager smanager) throws ServiceException 069 { 070 _odfHelper = (ODFHelper) smanager.lookup(ODFHelper.ROLE); 071 _odfReferenceTableHelper = (OdfReferenceTableHelper) smanager.lookup(OdfReferenceTableHelper.ROLE); 072 _cTypesHelper = (ContentTypesHelper) smanager.lookup(ContentTypesHelper.ROLE); 073 } 074 075 public void generate() throws IOException, SAXException, ProcessingException 076 { 077 Request request = ObjectModelHelper.getRequest(objectModel); 078 Content content = (Content) request.getAttribute(Content.class.getName()); 079 080 String viewName = request.getParameter("viewName"); 081 082 contentHandler.startDocument(); 083 084 if ("main".equals(viewName) || StringUtils.isEmpty(viewName)) 085 { 086 if (content instanceof ProgramItem) 087 { 088 XMLUtils.startElement(contentHandler, "structure"); 089 saxProgramItem((ProgramItem) content); 090 XMLUtils.endElement(contentHandler, "structure"); 091 } 092 else 093 { 094 getLogger().warn("Cannot get the structure of a non program item '" + content.getId() + "'"); 095 } 096 } 097 098 contentHandler.endDocument(); 099 } 100 101 /** 102 * SAX a program item with its child program items 103 * @param programItem the program item 104 * @throws SAXException if an error occurs while saxing 105 */ 106 protected void saxProgramItem(ProgramItem programItem) throws SAXException 107 { 108 if (programItem instanceof Program) 109 { 110 saxProgram((Program) programItem); 111 } 112 else if (programItem instanceof SubProgram) 113 { 114 saxSubProgram((SubProgram) programItem); 115 } 116 else if (programItem instanceof Container) 117 { 118 saxContainer((Container) programItem); 119 } 120 else if (programItem instanceof CourseList) 121 { 122 saxCourseList((CourseList) programItem); 123 } 124 else if (programItem instanceof Course) 125 { 126 saxCourse((Course) programItem); 127 } 128 } 129 130 /** 131 * SAX the child program items 132 * @param programItem the program item 133 * @throws SAXException if an error occurs while saxing 134 */ 135 protected void saxChildProgramItems(ProgramItem programItem) throws SAXException 136 { 137 List<ProgramItem> childProgramItems = _odfHelper.getChildProgramItems(programItem); 138 for (ProgramItem childProgramItem : childProgramItems) 139 { 140 try 141 { 142 _odfHelper.switchToLiveVersionIfNeeded((DefaultAmetysObject) childProgramItem); 143 saxProgramItem(childProgramItem); 144 } 145 catch (NoLiveVersionException e) 146 { 147 // Just ignore the program item 148 } 149 } 150 } 151 152 /** 153 * SAX a program 154 * @param program the subprogram to SAX 155 * @throws SAXException if an error occurs 156 */ 157 protected void saxProgram(Program program) throws SAXException 158 { 159 AttributesImpl attrs = new AttributesImpl(); 160 _saxCommonAttributes(program, attrs); 161 162 XMLUtils.startElement(contentHandler, "program", attrs); 163 164 XMLUtils.startElement(contentHandler, "attributes"); 165 _saxStructureViewIfExists(program); 166 XMLUtils.endElement(contentHandler, "attributes"); 167 168 saxChildProgramItems(program); 169 XMLUtils.endElement(contentHandler, "program"); 170 } 171 172 /** 173 * SAX a subprogram 174 * @param subProgram the subprogram to SAX 175 * @throws SAXException if an error occurs 176 */ 177 protected void saxSubProgram(SubProgram subProgram) throws SAXException 178 { 179 AttributesImpl attrs = new AttributesImpl(); 180 _saxCommonAttributes(subProgram, attrs); 181 182 XMLUtils.startElement(contentHandler, "subprogram", attrs); 183 184 XMLUtils.startElement(contentHandler, "attributes"); 185 _saxReferenceTableItem(subProgram.getEcts(), AbstractProgram.ECTS, subProgram.getLanguage()); 186 _saxStructureViewIfExists(subProgram); 187 XMLUtils.endElement(contentHandler, "attributes"); 188 189 saxChildProgramItems(subProgram); 190 191 XMLUtils.endElement(contentHandler, "subprogram"); 192 } 193 194 /** 195 * SAX a container 196 * @param container the container to SAX 197 * @throws SAXException if an error occurs while saxing 198 */ 199 protected void saxContainer(Container container) throws SAXException 200 { 201 AttributesImpl attrs = new AttributesImpl(); 202 _saxCommonAttributes(container, attrs); 203 204 XMLUtils.startElement(contentHandler, "container", attrs); 205 206 XMLUtils.startElement(contentHandler, "attributes"); 207 _saxReferenceTableItem(container.getNature(), Container.NATURE, container.getLanguage()); 208 _saxReferenceTableItem(container.getPeriod(), Container.PERIOD, container.getLanguage()); 209 210 _saxStructureViewIfExists(container); 211 212 XMLUtils.endElement(contentHandler, "attributes"); 213 214 saxChildProgramItems(container); 215 216 XMLUtils.endElement(contentHandler, "container"); 217 } 218 219 /** 220 * SAX a course list 221 * @param cl the course list to SAX 222 * @throws SAXException if an error occurs while saxing 223 */ 224 protected void saxCourseList(CourseList cl) throws SAXException 225 { 226 AttributesImpl attrs = new AttributesImpl(); 227 _saxCommonAttributes(cl, attrs); 228 229 XMLUtils.startElement(contentHandler, "courselist", attrs); 230 231 XMLUtils.startElement(contentHandler, "attributes"); 232 _saxStructureViewIfExists(cl); 233 XMLUtils.endElement(contentHandler, "attributes"); 234 235 saxChildProgramItems(cl); 236 237 XMLUtils.endElement(contentHandler, "courselist"); 238 } 239 240 /** 241 * SAX a course 242 * @param course the container to SAX 243 * @throws SAXException if an error occurs while saxing 244 */ 245 protected void saxCourse(Course course) throws SAXException 246 { 247 AttributesImpl attrs = new AttributesImpl(); 248 _saxCommonAttributes(course, attrs); 249 250 XMLUtils.startElement(contentHandler, "course", attrs); 251 252 XMLUtils.startElement(contentHandler, "attributes"); 253 _saxReferenceTableItem(course.getCourseType(), Course.COURSE_TYPE, course.getLanguage()); 254 _saxStructureViewIfExists(course); 255 XMLUtils.endElement(contentHandler, "attributes"); 256 257 saxChildProgramItems(course); 258 259 saxCourseParts(course); 260 261 XMLUtils.endElement(contentHandler, "course"); 262 } 263 264 /** 265 * SAX a course part 266 * @param course The course 267 * @throws SAXException if an error occurs 268 */ 269 protected void saxCourseParts(Course course) throws SAXException 270 { 271 List<CoursePart> courseParts = course.getCourseParts(); 272 273 double totalHours = 0; 274 for (CoursePart coursePart : course.getCourseParts()) 275 { 276 totalHours += coursePart.getNumberOfHours(); 277 } 278 279 AttributesImpl attrs = new AttributesImpl(); 280 attrs.addCDATAAttribute("totalHours", String.valueOf(totalHours)); 281 XMLUtils.startElement(contentHandler, "courseparts", attrs); 282 283 for (CoursePart coursePart : courseParts) 284 { 285 saxCoursePart(coursePart); 286 } 287 288 XMLUtils.endElement(contentHandler, "courseparts"); 289 } 290 291 /** 292 * SAX a course part 293 * @param coursePart The course part to SAX 294 * @throws SAXException if an error occurs 295 */ 296 protected void saxCoursePart(CoursePart coursePart) throws SAXException 297 { 298 AttributesImpl attrs = new AttributesImpl(); 299 attrs.addCDATAAttribute("id", coursePart.getId()); 300 attrs.addCDATAAttribute("title", coursePart.getTitle()); 301 _addAttrIfNotEmpty(attrs, "code", coursePart.getCode()); 302 303 XMLUtils.startElement(contentHandler, "coursepart", attrs); 304 305 XMLUtils.startElement(contentHandler, "attributes"); 306 _saxReferenceTableItem(coursePart.getNature(), CoursePart.NATURE, coursePart.getLanguage()); 307 308 _saxStructureViewIfExists(coursePart); 309 310 XMLUtils.endElement(contentHandler, "attributes"); 311 312 XMLUtils.endElement(contentHandler, "coursepart"); 313 } 314 315 /** 316 * SAX the 'structure' view if exists 317 * @param content the content 318 * @throws SAXException if an error occurs 319 */ 320 protected void _saxStructureViewIfExists(Content content) throws SAXException 321 { 322 View view = _cTypesHelper.getView("structure", content.getTypes(), content.getMixinTypes()); 323 if (view != null) 324 { 325 try 326 { 327 content.dataToSAX(contentHandler, view, DataContext.newInstance().withLocale(new Locale(content.getLanguage())).withEmptyValues(false)); 328 } 329 catch (BadItemTypeException | AmetysRepositoryException | IOException e) 330 { 331 throw new SAXException("Fail to sax the 'structure' view for content " + content.getId(), e); 332 } 333 } 334 } 335 336 /** 337 * SAX the common attributes for program item 338 * @param programItem the program item 339 * @param attrs the attributes 340 */ 341 protected void _saxCommonAttributes(ProgramItem programItem, AttributesImpl attrs) 342 { 343 attrs.addCDATAAttribute("title", ((Content) programItem).getTitle()); 344 attrs.addCDATAAttribute("id", programItem.getId()); 345 attrs.addCDATAAttribute("code", programItem.getCode()); 346 attrs.addCDATAAttribute("name", programItem.getName()); 347 } 348 349 /** 350 * SAX the item of a reference table 351 * @param itemId the item id 352 * @param tagName the tag name 353 * @param lang the language to use 354 * @throws SAXException if an error occurs while saxing 355 */ 356 protected void _saxReferenceTableItem(String itemId, String tagName, String lang) throws SAXException 357 { 358 OdfReferenceTableEntry item = Optional.ofNullable(itemId) 359 .filter(StringUtils::isNotEmpty) 360 .map(_odfReferenceTableHelper::getItem) 361 .orElse(null); 362 363 if (item != null) 364 { 365 AttributesImpl attrs = new AttributesImpl(); 366 attrs.addCDATAAttribute("id", item.getId()); 367 _addAttrIfNotEmpty(attrs, "code", item.getCode()); 368 369 XMLUtils.createElement(contentHandler, tagName, attrs, item.getLabel(lang)); 370 } 371 } 372 373 /** 374 * Add an attribute if its not null or empty. 375 * @param attrs The attributes 376 * @param attrName The attribute name 377 * @param attrValue The attribute value 378 */ 379 protected void _addAttrIfNotEmpty(AttributesImpl attrs, String attrName, String attrValue) 380 { 381 if (StringUtils.isNotEmpty(attrValue)) 382 { 383 attrs.addCDATAAttribute(attrName, attrValue); 384 } 385 } 386 387}