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.cdmfr; 017 018import java.time.LocalDate; 019import java.util.Optional; 020import java.util.Set; 021 022import org.apache.avalon.framework.service.ServiceException; 023import org.apache.avalon.framework.service.ServiceManager; 024import org.apache.avalon.framework.service.Serviceable; 025import org.apache.cocoon.xml.AttributesImpl; 026import org.apache.cocoon.xml.XMLUtils; 027import org.apache.commons.lang3.ArrayUtils; 028import org.apache.commons.lang3.StringUtils; 029import org.apache.excalibur.source.SourceResolver; 030import org.xml.sax.ContentHandler; 031import org.xml.sax.SAXException; 032 033import org.ametys.cms.data.ContentValue; 034import org.ametys.cms.data.File; 035import org.ametys.cms.data.Geocode; 036import org.ametys.cms.data.RichText; 037import org.ametys.cms.data.type.ModelItemTypeConstants; 038import org.ametys.cms.repository.Content; 039import org.ametys.cms.repository.ModifiableContent; 040import org.ametys.odf.catalog.Catalog; 041import org.ametys.odf.catalog.CatalogsManager; 042import org.ametys.odf.course.Course; 043import org.ametys.odf.coursepart.CoursePart; 044import org.ametys.odf.enumeration.MonthEnumerator; 045import org.ametys.odf.enumeration.OdfReferenceTableHelper; 046import org.ametys.odf.orgunit.OrgUnit; 047import org.ametys.odf.person.Person; 048import org.ametys.odf.program.AbstractProgram; 049import org.ametys.odf.program.Container; 050import org.ametys.odf.program.Program; 051import org.ametys.odf.program.ProgramFactory; 052import org.ametys.odf.program.SubProgram; 053import org.ametys.odf.skill.ODFSkillsHelper; 054import org.ametys.plugins.repository.AmetysObjectResolver; 055import org.ametys.plugins.repository.data.holder.group.ModelAwareRepeater; 056import org.ametys.plugins.repository.data.holder.group.ModelAwareRepeaterEntry; 057import org.ametys.plugins.repository.model.RepositoryDataContext; 058import org.ametys.runtime.model.ModelItem; 059import org.ametys.runtime.model.type.DataContext; 060 061/** 062 * base CDMfr extension for Ametys 063 */ 064public class AmetysCDMfrExtension extends AbstractCDMfrExtension implements Serviceable 065{ 066 private OdfReferenceTableHelper _refTableHelper; 067 private CatalogsManager _catalogsManager; 068 private SourceResolver _sourceResolver; 069 private AmetysObjectResolver _resolver; 070 private MonthEnumerator _monthEnumerator; 071 072 @Override 073 public void service(ServiceManager manager) throws ServiceException 074 { 075 _refTableHelper = (OdfReferenceTableHelper) manager.lookup(OdfReferenceTableHelper.ROLE); 076 _catalogsManager = (CatalogsManager) manager.lookup(CatalogsManager.ROLE); 077 _sourceResolver = (SourceResolver) manager.lookup(SourceResolver.ROLE); 078 _resolver = (AmetysObjectResolver) manager.lookup(AmetysObjectResolver.ROLE); 079 _monthEnumerator = (MonthEnumerator) manager.lookup(MonthEnumerator.ROLE); 080 } 081 082 @Override 083 public void abstractProgram2CDM(ContentHandler contentHandler, AbstractProgram<? extends ProgramFactory> program, Set<String> persons, Set<String> orgUnits) throws SAXException 084 { 085 AttributesImpl attrs = new AttributesImpl(); 086 087 // Certified 088 // <ametys-cdm:certified/> 089 if (program.isCertified()) 090 { 091 XMLUtils.createElement(contentHandler, CDMFRTagsConstants.NAMESPACE_AMETYS_CDM + AbstractProgram.CERTIFIED); 092 } 093 094 // Passerelle et réorientation 095 // <ametys-cdm:reorientation>...</ametys-cdm:reorientation> 096 DataContext reorientationContext = RepositoryDataContext.newInstance() 097 .withObject(program) 098 .withDataPath(AbstractProgram.REORIENTATION); 099 CDMHelper.richText2CDM(contentHandler, CDMFRTagsConstants.NAMESPACE_AMETYS_CDM + AbstractProgram.REORIENTATION, program.getReorientation(), reorientationContext, _sourceResolver, attrs); 100 101 102 // Date de fin de la formation 103 // <ametys-cdm:teachingEnd>...</ametys-cdm:teachingEnd> 104 LocalDate teachingEnd = program.getTeachingEnd(); 105 if (teachingEnd != null) 106 { 107 CDMHelper.date2CDM(contentHandler, CDMFRTagsConstants.NAMESPACE_AMETYS_CDM + CDMFRTagsConstants.TAG_TEACHING_END, teachingEnd); 108 } 109 110 // Ouvert en stage 111 // <ametys-cdm:internshipOpen/> 112 if (program.isInternshipOpen()) 113 { 114 XMLUtils.createElement(contentHandler, CDMFRTagsConstants.NAMESPACE_AMETYS_CDM + AbstractProgram.INTERNSHIP_OPEN); 115 } 116 117 // Stages 118 // <ametys-cdm:training> 119 // <ametys-cdm:trainingInfo value="internship_mandatory">Obligatoire</ametys-cdm:trainingInfo> 120 // <ametys-cdm:trainingDuration>6 mois</ametys-cdm:trainingInfo> 121 // <ametys-cdm:trainingAbroadInfo value="internship_mandatory">Obligatoire</ametys-cdm:trainingAbroadInfo> 122 // <ametys-cdm:trainingAbroadDuration>6 mois</ametys-cdm:trainingAbroadDuration> 123 // <ametys-cdm:trainingDetails> 124 // <ametys-cdm:trainingDetail> 125 // <ametys-cdm:title>...</ametys-cmd:title> 126 // <ametys-cdm:duration>...</ametys-cmd:duration> 127 // <ametys-cdm:period>...</ametys-cmd:period> 128 // <ametys-cdm:kind>...</ametys-cmd:kind> 129 // </ametys-cdm:trainingDetail> 130 // </ametys-cdm:trainingDetails> 131 // </ametys-cdm:training> 132 saxTraining(contentHandler, program); 133 134 // Etablissement partenaires 135 // <ametys-cdm:partnerSchools/> 136 saxPartnerSchools(contentHandler, program); 137 138 // Laboratoires partenaires 139 // <ametys-cdm:partnerLaboratories/> 140 saxPartnerLaboratories(contentHandler, program); 141 142 // Fichier attachés 143 // <ametys-cdm:attachments/> 144 saxAttachments(contentHandler, program); 145 146 // Niveau RNCP 147 // <ametys-cdm:rncpLevel/> 148 if (program instanceof Program) 149 { 150 String[] rncpLevels = program.getRncpLevel(); 151 152 if (rncpLevels.length > 0) 153 { 154 for (String rncpLevel : rncpLevels) 155 { 156 String rncpValue = _refTableHelper.getItemCDMfrValue(rncpLevel, true); 157 String rncpLabel = _refTableHelper.getItemLabel(rncpLevel, program.getLanguage()); 158 159 attrs = new AttributesImpl(); 160 attrs.addCDATAAttribute("value", rncpValue); 161 XMLUtils.createElement(contentHandler, CDMFRTagsConstants.NAMESPACE_AMETYS_CDM + AbstractProgram.RNCP_LEVEL, attrs, rncpLabel); 162 } 163 } 164 else 165 { 166 XMLUtils.createElement(contentHandler, CDMFRTagsConstants.NAMESPACE_AMETYS_CDM + AbstractProgram.RNCP_LEVEL); 167 } 168 } 169 170 // RNCP code 171 // <ametys-cdm:rncpCode>Code RNCP</ametys-cdm:rncpCode> 172 for (String rncpCode : program.getRncpCode()) 173 { 174 if (StringUtils.isNotEmpty(rncpCode)) 175 { 176 XMLUtils.createElement(contentHandler, CDMFRTagsConstants.NAMESPACE_AMETYS_CDM + "rncpCode", rncpCode); 177 } 178 } 179 180 // Niveau(x) d'entrée 181 // <ametys-cdm:educationEntryLevel code="code">Label</ametys-cdm:educationEntryLevel> 182 _saxMultipleEnumeration(contentHandler, program.getEducationLevelEntry(), AbstractProgram.EDUCATION_ENTRY_LEVEL, program.getLanguage()); 183 184 // Campus 185 // <ametys-cdm:campus code="code">Label</ametys-cdm:campus> 186 _saxMultipleEnumeration(contentHandler, program.getCampus(), AbstractProgram.CAMPUS, program.getLanguage()); 187 188 // Lieu(x) à l'étranger 189 // <ametys-cdm:foreignPlace code="code">Label</ametys-cdm:foreignPlace> 190 _saxMultipleEnumeration(contentHandler, program.getForeignPlace(), AbstractProgram.FOREIGN_PLACE, program.getLanguage()); 191 192 // Champ(s) de formation 193 // <ametys-cdm:programField code="code">Label</ametys-cdm:programField> 194 _saxMultipleEnumeration(contentHandler, program.getProgramField(), AbstractProgram.PROGRAM_FIELD, program.getLanguage()); 195 196 // Disciplines 197 // <ametys-cdm:disciplines code="code">Label</ametys-cdm:disciplines> 198 _saxMultipleEnumeration(contentHandler, program.getDisciplines(), AbstractProgram.DISCIPLINES, program.getLanguage()); 199 200 // Poursuite d'études dans l'établissement 201 // <ametys-cdm:furtherStudyPrograms code="cdm-code">Label</ametys-cdm:furtherStudyPrograms> 202 for (String furtherStudyProgramId : program.getFurtherStudyPrograms()) 203 { 204 AbstractProgram furtherStudyProgram = _resolver.resolveById(furtherStudyProgramId); 205 attrs = new AttributesImpl(); 206 attrs.addCDATAAttribute("code", furtherStudyProgram.getCdmCode()); 207 XMLUtils.createElement(contentHandler, CDMFRTagsConstants.NAMESPACE_AMETYS_CDM + AbstractProgram.FURTHER_STUDY_PROGRAMS, attrs, furtherStudyProgram.getTitle()); 208 } 209 210 // Secteurs d'activité 211 // <ametys-cdm:sectors code="code">Label</ametys-cdm:sectors> 212 _saxMultipleEnumeration(contentHandler, program.getSectors(), AbstractProgram.SECTORS, program.getLanguage()); 213 214 // Ouvert en alternance 215 // <ametys-cdm:apprenticeshipOpen /> 216 if (program.isApprenticeshipOpen()) 217 { 218 XMLUtils.createElement(contentHandler, AbstractProgram.APPRENTICESHIP_OPEN); 219 } 220 221 // Rythme d'alternance 222 // <ametys-cdm:apprenticeshipPeriod>...</ametys-cdm:apprenticeshipPeriod> 223 DataContext apprenticeshipPeriodContext = RepositoryDataContext.newInstance() 224 .withObject(program) 225 .withDataPath(AbstractProgram.APPRENTICESHIP_PERIOD); 226 CDMHelper.richText2CDM(contentHandler, CDMFRTagsConstants.NAMESPACE_AMETYS_CDM + AbstractProgram.APPRENTICESHIP_PERIOD, program.getApprenticeshipPeriod(), apprenticeshipPeriodContext, _sourceResolver); 227 228 // Modalitités d'alternance 229 // <ametys-cdm:apprenticeshipModalities>...</ametys-cdm:apprenticeshipModalities> 230 DataContext apprenticeshipModalitiesContext = RepositoryDataContext.newInstance() 231 .withObject(program) 232 .withDataPath(AbstractProgram.APPRENTICESHIP_MODALITIES); 233 CDMHelper.richText2CDM(contentHandler, CDMFRTagsConstants.NAMESPACE_AMETYS_CDM + AbstractProgram.APPRENTICESHIP_MODALITIES, program.getApprenticeshipModalities(), apprenticeshipModalitiesContext, _sourceResolver); 234 235 // Type(s) de contrat 236 // <ametys-cdm:apprenticeshipContract code="code">Label</ametys-cdm:apprenticeshipContract> 237 _saxMultipleEnumeration(contentHandler, program.getApprenticeshipContract(), AbstractProgram.APPRENTICESHIP_CONTRACT, program.getLanguage()); 238 239 // Formation internationale 240 // <ametys-cdm:internationalEducation code="code">Label</ametys-cdm:internationalEducation> 241 _saxMultipleEnumeration(contentHandler, program.getInternationalEducation(), AbstractProgram.INTERNATIONAL_EDUCATION, program.getLanguage()); 242 243 // Dimension internationale 244 // <ametys-cdm:internationalDimension>...</ametys-cdm:internationalDimension> 245 DataContext internationalDimensionContext = RepositoryDataContext.newInstance() 246 .withObject(program) 247 .withDataPath(AbstractProgram.INTERNATIONAL_DIMENSION); 248 CDMHelper.richText2CDM(contentHandler, CDMFRTagsConstants.NAMESPACE_AMETYS_CDM + AbstractProgram.INTERNATIONAL_DIMENSION, program.getInternationalDimension(), internationalDimensionContext, _sourceResolver); 249 250 // Géolocalisation 251 // <ametys-cdm:disciplines code="code">Label</ametys-cdm:disciplines> 252 Geocode geocode = program.getGeocode(); 253 if (geocode != null) 254 { 255 Double latitude = geocode.getLatitude(); 256 Double longitude = geocode.getLongitude(); 257 if (latitude != null && longitude != null) 258 { 259 attrs = new AttributesImpl(); 260 attrs.addCDATAAttribute("latitude", String.valueOf(latitude)); 261 attrs.addCDATAAttribute("longitude", String.valueOf(longitude)); 262 XMLUtils.createElement(contentHandler, CDMFRTagsConstants.NAMESPACE_AMETYS_CDM + AbstractProgram.GEOCODE, attrs); 263 } 264 } 265 266 // Autres structures partenaires 267 DataContext otherPartnersContext = RepositoryDataContext.newInstance() 268 .withObject(program) 269 .withDataPath(AbstractProgram.OTHER_PARTNERS); 270 CDMHelper.richText2CDM(contentHandler, CDMFRTagsConstants.NAMESPACE_AMETYS_CDM + AbstractProgram.OTHER_PARTNERS, program.getOtherPartners(), otherPartnersContext, _sourceResolver); 271 272 // Certifications possibles 273 // <ametys-cdm:disciplines code="code">Label</ametys-cdm:disciplines> 274 _saxMultipleEnumeration(contentHandler, program.getAvailableCertification(), AbstractProgram.AVAILABLE_CERTIFICATION, program.getLanguage()); 275 276 // Autre contact 277 // <ametys-cdm:otherContact>...</ametys-cdm:otherContact> 278 RichText otherContact = program.getValue(AbstractProgram.OTHER_CONTACT, false, null); 279 if (otherContact != null) 280 { 281 DataContext otherContactContext = RepositoryDataContext.newInstance() 282 .withObject(program) 283 .withDataPath(AbstractProgram.OTHER_CONTACT); 284 CDMHelper.richText2CDM(contentHandler, CDMFRTagsConstants.NAMESPACE_AMETYS_CDM + AbstractProgram.OTHER_CONTACT, otherContact, otherContactContext, _sourceResolver); 285 } 286 } 287 288 /** 289 * SAX a multiple metadata based on an reference table. 290 * <ametys-cdm:tagName code="code">Label</ametys-cdm:tagName> 291 * @param contentHandler The handler 292 * @param values Values to SAX 293 * @param tagName The tag name 294 * @param lang The language to translate the label 295 * @throws SAXException if an error occurs 296 */ 297 private void _saxMultipleEnumeration(ContentHandler contentHandler, String[] values, String tagName, String lang) throws SAXException 298 { 299 for (String value : values) 300 { 301 _saxSingleEnumeration(contentHandler, value, tagName, lang); 302 } 303 } 304 305 private void _saxSingleEnumeration(ContentHandler contentHandler, String value, String tagName, String lang) throws SAXException 306 { 307 String code = _refTableHelper.getItemCDMfrValue(value, true); 308 String label = _refTableHelper.getItemLabel(value, lang); 309 310 AttributesImpl attrs = new AttributesImpl(); 311 attrs.addCDATAAttribute("code", code); 312 XMLUtils.createElement(contentHandler, CDMFRTagsConstants.NAMESPACE_AMETYS_CDM + tagName, attrs, label); 313 } 314 315 /** 316 * Sax training and internship informations. 317 * @param contentHandler the receiving contentHandler. 318 * @param program the abstract program (common for program and subprogram) 319 * @throws SAXException if an error occurs during CDM processing. 320 */ 321 protected void saxTraining(ContentHandler contentHandler, AbstractProgram<? extends ProgramFactory> program) throws SAXException 322 { 323 XMLUtils.startElement(contentHandler, CDMFRTagsConstants.NAMESPACE_AMETYS_CDM + "training"); 324 325 String internship = program.getInternship(); 326 if (!internship.isEmpty()) 327 { 328 AttributesImpl attrs = new AttributesImpl(); 329 attrs.addCDATAAttribute("value", _refTableHelper.getItemCDMfrValue(internship, true)); 330 String internshipLabel = _refTableHelper.getItemLabel(internship, program.getLanguage()); 331 XMLUtils.createElement(contentHandler, CDMFRTagsConstants.NAMESPACE_AMETYS_CDM + "trainingInfo", attrs, internshipLabel); 332 } 333 else 334 { 335 XMLUtils.createElement(contentHandler, CDMFRTagsConstants.NAMESPACE_AMETYS_CDM + "trainingInfo"); 336 } 337 338 XMLUtils.createElement(contentHandler, CDMFRTagsConstants.NAMESPACE_AMETYS_CDM + "trainingDuration", program.getInternshipDuration()); 339 340 String internshipAbroad = program.getInternshipAbroad(); 341 if (!internshipAbroad.isEmpty()) 342 { 343 AttributesImpl attrs = new AttributesImpl(); 344 attrs.addCDATAAttribute("value", _refTableHelper.getItemCDMfrValue(internshipAbroad, true)); 345 String internshipLabel = _refTableHelper.getItemLabel(internshipAbroad, program.getLanguage()); 346 XMLUtils.createElement(contentHandler, CDMFRTagsConstants.NAMESPACE_AMETYS_CDM + "trainingAbroadInfo", attrs, internshipLabel); 347 } 348 else 349 { 350 XMLUtils.createElement(contentHandler, CDMFRTagsConstants.NAMESPACE_AMETYS_CDM + "trainingAbroadInfo"); 351 } 352 XMLUtils.createElement(contentHandler, CDMFRTagsConstants.NAMESPACE_AMETYS_CDM + "trainingAbroadDuration", program.getAbroadInternshipDuration()); 353 354 if (program.hasValue(AbstractProgram.INTERNSHIP_DESCRIPTION)) 355 { 356 ModelAwareRepeater internshipDescriptions = program.getRepeater(AbstractProgram.INTERNSHIP_DESCRIPTION); 357 if (internshipDescriptions.getSize() > 0) 358 { 359 XMLUtils.startElement(contentHandler, CDMFRTagsConstants.NAMESPACE_AMETYS_CDM + "trainingDetails"); 360 for (ModelAwareRepeaterEntry internshipDescription : internshipDescriptions.getEntries()) 361 { 362 XMLUtils.startElement(contentHandler, CDMFRTagsConstants.NAMESPACE_AMETYS_CDM + "trainingDetail"); 363 XMLUtils.createElement(contentHandler, CDMFRTagsConstants.NAMESPACE_AMETYS_CDM + "title", internshipDescription.getValue(AbstractProgram.INTERNSHIP_DESCRIPTION_TITLE, false, StringUtils.EMPTY)); 364 XMLUtils.createElement(contentHandler, CDMFRTagsConstants.NAMESPACE_AMETYS_CDM + "duration", internshipDescription.getValue(AbstractProgram.INTERNSHIP_DESCRIPTION_DURATION, false, StringUtils.EMPTY)); 365 366 for (String value : internshipDescription.getValue(AbstractProgram.INTERNSHIP_DESCRIPTION_PERIOD, false, ArrayUtils.EMPTY_STRING_ARRAY)) 367 { 368 AttributesImpl attrs = new AttributesImpl(); 369 attrs.addCDATAAttribute("code", value); 370 XMLUtils.createElement(contentHandler, CDMFRTagsConstants.NAMESPACE_AMETYS_CDM + "period", attrs, _monthEnumerator.getLabel(value, program.getLanguage())); 371 } 372 373 StringBuilder dataPath = new StringBuilder(AbstractProgram.INTERNSHIP_DESCRIPTION) 374 .append("[") 375 .append(internshipDescription.getPosition()) 376 .append("]") 377 .append(ModelItem.ITEM_PATH_SEPARATOR) 378 .append(AbstractProgram.INTERNSHIP_DESCRIPTION_KIND); 379 DataContext internshipDescriptionKindContext = RepositoryDataContext.newInstance() 380 .withObject(program) 381 .withDataPath(dataPath.toString()); 382 CDMHelper.richText2CDM(contentHandler, CDMFRTagsConstants.NAMESPACE_AMETYS_CDM + AbstractProgram.INTERNSHIP_DESCRIPTION_KIND, internshipDescription.getValue(AbstractProgram.INTERNSHIP_DESCRIPTION_KIND), internshipDescriptionKindContext, _sourceResolver); 383 384 XMLUtils.endElement(contentHandler, CDMFRTagsConstants.NAMESPACE_AMETYS_CDM + "trainingDetail"); 385 } 386 XMLUtils.endElement(contentHandler, CDMFRTagsConstants.NAMESPACE_AMETYS_CDM + "trainingDetails"); 387 } 388 } 389 390 XMLUtils.endElement(contentHandler, CDMFRTagsConstants.NAMESPACE_AMETYS_CDM + "training"); 391 } 392 393 /** 394 * Sax partner schools (<ametys-cdm:partnerSchools/>). 395 * @param contentHandler the receiving contentHandler. 396 * @param program the abstract program (common for program and subprogram) 397 * @throws SAXException if an error occurs during CDM processing. 398 */ 399 protected void saxPartnerSchools(ContentHandler contentHandler, AbstractProgram<? extends ProgramFactory> program) throws SAXException 400 { 401 if (program.hasValue(AbstractProgram.PARTNER_SCHOOLS)) 402 { 403 XMLUtils.startElement(contentHandler, CDMFRTagsConstants.NAMESPACE_AMETYS_CDM + AbstractProgram.PARTNER_SCHOOLS); 404 405 ModelAwareRepeater partnerSchools = program.getRepeater(AbstractProgram.PARTNER_SCHOOLS); 406 for (ModelAwareRepeaterEntry partnerSchool : partnerSchools.getEntries()) 407 { 408 String linkUrl = partnerSchool.getValue(AbstractProgram.PARTNER_SCHOOLS_LINK_URL, false, StringUtils.EMPTY); 409 String linkLabel = partnerSchool.getValue(AbstractProgram.PARTNER_SCHOOLS_LINK_LABEL, false, StringUtils.EMPTY); 410 411 if (!linkUrl.isEmpty() || !linkLabel.isEmpty()) 412 { 413 XMLUtils.startElement(contentHandler, CDMFRTagsConstants.NAMESPACE_AMETYS_CDM + "partnerSchool"); 414 XMLUtils.createElement(contentHandler, CDMFRTagsConstants.NAMESPACE_AMETYS_CDM + "linkUrl", linkUrl); 415 XMLUtils.createElement(contentHandler, CDMFRTagsConstants.NAMESPACE_AMETYS_CDM + "linkLabel", linkLabel); 416 XMLUtils.endElement(contentHandler, CDMFRTagsConstants.NAMESPACE_AMETYS_CDM + "partnerSchool"); 417 } 418 } 419 420 XMLUtils.endElement(contentHandler, CDMFRTagsConstants.NAMESPACE_AMETYS_CDM + AbstractProgram.PARTNER_SCHOOLS); 421 } 422 } 423 424 /** 425 * Sax partner laboratories (<ametys-cdm:partnerLaboratories/>). 426 * @param contentHandler the receiving contentHandler. 427 * @param program the abstract program (common for program and subprogram) 428 * @throws SAXException if an error occurs during CDM processing. 429 */ 430 protected void saxPartnerLaboratories(ContentHandler contentHandler, AbstractProgram<? extends ProgramFactory> program) throws SAXException 431 { 432 if (program.hasValue(AbstractProgram.PARTNER_LABORATORIES)) 433 { 434 XMLUtils.startElement(contentHandler, CDMFRTagsConstants.NAMESPACE_AMETYS_CDM + AbstractProgram.PARTNER_LABORATORIES); 435 436 ModelAwareRepeater partnerLaboratories = program.getRepeater(AbstractProgram.PARTNER_LABORATORIES); 437 for (ModelAwareRepeaterEntry partnerLaboratory : partnerLaboratories.getEntries()) 438 { 439 String linkUrl = partnerLaboratory.getValue(AbstractProgram.PARTNER_LABORATORIES_LINK_URL, false, StringUtils.EMPTY); 440 String linkLabel = partnerLaboratory.getValue(AbstractProgram.PARTNER_LABORATORIES_LINK_LABEL, false, StringUtils.EMPTY); 441 442 if (!linkUrl.isEmpty() || !linkLabel.isEmpty()) 443 { 444 XMLUtils.startElement(contentHandler, CDMFRTagsConstants.NAMESPACE_AMETYS_CDM + "partnerLaboratory"); 445 XMLUtils.createElement(contentHandler, CDMFRTagsConstants.NAMESPACE_AMETYS_CDM + "linkUrl", linkUrl); 446 XMLUtils.createElement(contentHandler, CDMFRTagsConstants.NAMESPACE_AMETYS_CDM + "linkLabel", linkLabel); 447 XMLUtils.endElement(contentHandler, CDMFRTagsConstants.NAMESPACE_AMETYS_CDM + "partnerLaboratory"); 448 } 449 } 450 451 XMLUtils.endElement(contentHandler, CDMFRTagsConstants.NAMESPACE_AMETYS_CDM + AbstractProgram.PARTNER_LABORATORIES); 452 } 453 } 454 455 /** 456 * Sax attachments (<ametys-cdm:attachments/>). 457 * @param contentHandler the receiving contentHandler. 458 * @param program the abstract program (common for program and subprogram) 459 * @throws SAXException if an error occurs during CDM processing. 460 */ 461 protected void saxAttachments(ContentHandler contentHandler, AbstractProgram<? extends ProgramFactory> program) throws SAXException 462 { 463 if (program.hasValue(AbstractProgram.ATTACHMENTS)) 464 { 465 XMLUtils.startElement(contentHandler, CDMFRTagsConstants.NAMESPACE_AMETYS_CDM + AbstractProgram.ATTACHMENTS); 466 467 ModelAwareRepeater attachments = program.getRepeater(AbstractProgram.ATTACHMENTS); 468 for (ModelAwareRepeaterEntry entry: attachments.getEntries()) 469 { 470 if (entry.hasValue(AbstractProgram.ATTACHMENTS_ATTACHMENT)) 471 { 472 String url = null; 473 if (ModelItemTypeConstants.FILE_ELEMENT_TYPE_ID.equals(entry.getType(AbstractProgram.ATTACHMENTS_ATTACHMENT).getId())) 474 { 475 File file = entry.getValue(AbstractProgram.ATTACHMENTS_ATTACHMENT); 476 url = _getFileAbsoluteUrl(program, file, "attachments[" + entry.getPosition() + "]/attachment"); 477 } 478 479 String text = entry.getValue(AbstractProgram.ATTACHMENTS_ATTACHMENT_TEXT, false, StringUtils.EMPTY); 480 481 XMLUtils.startElement(contentHandler, CDMFRTagsConstants.NAMESPACE_AMETYS_CDM + "attachment"); 482 XMLUtils.createElement(contentHandler, CDMFRTagsConstants.NAMESPACE_AMETYS_CDM + "text", text); 483 if (url != null) 484 { 485 XMLUtils.createElement(contentHandler, CDMFRTagsConstants.NAMESPACE_AMETYS_CDM + "href", url); 486 } 487 XMLUtils.endElement(contentHandler, CDMFRTagsConstants.NAMESPACE_AMETYS_CDM + "attachment"); 488 } 489 } 490 491 XMLUtils.endElement(contentHandler, CDMFRTagsConstants.NAMESPACE_AMETYS_CDM + AbstractProgram.ATTACHMENTS); 492 } 493 } 494 495 /** 496 * Sax the acquired skills 497 * @param contentHandler the receiving contentHandler. 498 * @param course the course 499 * @throws SAXException if an error occurs during CDM processing. 500 */ 501 protected void saxAcquiredSkills(ContentHandler contentHandler, Course course) throws SAXException 502 { 503 if (course.hasValue(Course.ACQUIRED_MICRO_SKILLS)) 504 { 505 XMLUtils.startElement(contentHandler, CDMFRTagsConstants.NAMESPACE_AMETYS_CDM + Course.ACQUIRED_MICRO_SKILLS); 506 507 ModelAwareRepeater repeater = course.getRepeater(Course.ACQUIRED_MICRO_SKILLS); 508 for (ModelAwareRepeaterEntry entry : repeater.getEntries()) 509 { 510 ContentValue programValue = entry.getValue(Course.ACQUIRED_MICRO_SKILLS_PROGRAM, false, null); 511 if (programValue != null) 512 { 513 XMLUtils.startElement(contentHandler, CDMFRTagsConstants.NAMESPACE_AMETYS_CDM + "acquiredMicroSkillByProgram"); 514 515 Optional<ModifiableContent> programIfExists = programValue.getContentIfExists(); 516 if (programIfExists.isPresent()) 517 { 518 Program program = (Program) programIfExists.get(); 519 AttributesImpl attrs = new AttributesImpl(); 520 attrs.addCDATAAttribute("id", program.getId()); 521 attrs.addCDATAAttribute("code", program.getCode()); 522 String label = program.getTitle(); 523 attrs.addCDATAAttribute("title", label); 524 525 attrs.addCDATAAttribute(CDMFRTagsConstants.ATTRIBUTE_ID_REF, program.getCDMId()); 526 527 XMLUtils.createElement(contentHandler, CDMFRTagsConstants.NAMESPACE_AMETYS_CDM + "program", attrs, label); 528 } 529 530 ContentValue[] skills = entry.getValue(Course.ACQUIRED_MICRO_SKILLS_SKILLS, false, null); 531 if (skills != null) 532 { 533 for (ContentValue skill : skills) 534 { 535 Optional<ModifiableContent> skillContent = skill.getContentIfExists(); 536 if (skillContent.isPresent()) 537 { 538 saxAcquiredSkill(contentHandler, skillContent.get()); 539 } 540 } 541 } 542 543 XMLUtils.endElement(contentHandler, CDMFRTagsConstants.NAMESPACE_AMETYS_CDM + "acquiredMicroSkillByProgram"); 544 545 } 546 } 547 548 XMLUtils.endElement(contentHandler, CDMFRTagsConstants.NAMESPACE_AMETYS_CDM + Course.ACQUIRED_MICRO_SKILLS); 549 } 550 } 551 552 /** 553 * Sax the acquired skill 554 * @param contentHandler the receiving contentHandler. 555 * @param skill The skill 556 * @throws SAXException if an error occurs during CDM processing. 557 */ 558 protected void saxAcquiredSkill(ContentHandler contentHandler, Content skill) throws SAXException 559 { 560 AttributesImpl attrs = new AttributesImpl(); 561 attrs.addCDATAAttribute("id", skill.getId()); 562 attrs.addCDATAAttribute("code", skill.getValue("code")); 563 attrs.addCDATAAttribute("skillCode", skill.getValue("skillCode")); 564 String label = skill.getTitle(); 565 attrs.addCDATAAttribute("title", label); 566 XMLUtils.createElement(contentHandler, CDMFRTagsConstants.NAMESPACE_AMETYS_CDM + "skill", attrs, label); 567 } 568 569 @Override 570 public void program2CDM(ContentHandler contentHandler, Program program, Set<String> persons, Set<String> orgUnits) throws SAXException 571 { 572 // Catalogue de formation 573 String catalogCode = program.getCatalog(); 574 if (StringUtils.isNotEmpty(catalogCode)) 575 { 576 AttributesImpl attrs = new AttributesImpl(); 577 attrs.addCDATAAttribute("value", catalogCode); 578 579 Catalog catalog = _catalogsManager.getCatalog(catalogCode); 580 String catalogLabel = catalog != null ? catalog.getTitle() : catalogCode; 581 XMLUtils.createElement(contentHandler, CDMFRTagsConstants.NAMESPACE_AMETYS_CDM + "catalog", attrs, catalogLabel); 582 } 583 } 584 585 public void subProgram2CDM(ContentHandler contentHandler, SubProgram subProgram, Set<String> persons, Set<String> orgUnits) throws SAXException 586 { 587 // nothing specific to subprograms in the default Ametys model 588 } 589 590 @Override 591 public void course2CDM(ContentHandler contentHandler, Course course, Set<String> persons, Set<String> orgUnits) throws SAXException 592 { 593 // Catalogue de formation 594 String catalogCode = course.getCatalog(); 595 if (StringUtils.isNotEmpty(catalogCode)) 596 { 597 AttributesImpl attrs = new AttributesImpl(); 598 attrs.addCDATAAttribute("value", catalogCode); 599 600 Catalog catalog = _catalogsManager.getCatalog(catalogCode); 601 String catalogLabel = catalog != null ? catalog.getTitle() : catalogCode; 602 XMLUtils.createElement(contentHandler, CDMFRTagsConstants.NAMESPACE_AMETYS_CDM + "catalog", attrs, catalogLabel); 603 } 604 605 // Ouvert aux étudiants en échange 606 // <ametys-cdm:openToExchangeStudents /> 607 if (course.isOpenToExchangeStudents()) 608 { 609 XMLUtils.createElement(contentHandler, CDMFRTagsConstants.NAMESPACE_AMETYS_CDM + Course.OPEN_TO_EXCHANGE_STUDENTS); 610 } 611 612 if (ODFSkillsHelper.isSkillsEnabled()) 613 { 614 // Compétence acquises 615 saxAcquiredSkills(contentHandler, course); 616 } 617 618 // Course parts 619 for (CoursePart coursePart : course.getCourseParts()) 620 { 621 _coursePart2CDM(contentHandler, coursePart); 622 } 623 } 624 625 /** 626 * Sax a {@link CoursePart} with the following structure : 627 * <ametys-cdm:coursePart @ametys-cdm:code="code"> 628 * <ametys-cdm:title>Title</ametys-cdm:title> 629 * <ametys-cdm:nature>Nature CDM-fr value or code</ametys-cdm:nature> 630 * <ametys-cdm:nbHours>Number of hours</ametys-cdm:nbHours> 631 * <ametys-cdm:courseHolder>CDM ID of the course holder</ametys-cdm:courseHolder> 632 * </ametys-cdm:coursePart> 633 * @param contentHandler The content handler 634 * @param coursePart The {@link CoursePart} to sax 635 * @throws SAXException if an error occurs 636 */ 637 protected void _coursePart2CDM(ContentHandler contentHandler, CoursePart coursePart) throws SAXException 638 { 639 AttributesImpl attrs = new AttributesImpl(); 640 attrs.addCDATAAttribute("code", coursePart.getCode()); 641 642 XMLUtils.startElement(contentHandler, CDMFRTagsConstants.NAMESPACE_AMETYS_CDM + "coursePart", attrs); 643 XMLUtils.createElement(contentHandler, CDMFRTagsConstants.NAMESPACE_AMETYS_CDM + Content.ATTRIBUTE_TITLE, coursePart.getTitle()); 644 String nature = _refTableHelper.getItemCDMfrValue(coursePart.getNature(), true); 645 XMLUtils.createElement(contentHandler, CDMFRTagsConstants.NAMESPACE_AMETYS_CDM + CoursePart.NATURE, nature); 646 XMLUtils.createElement(contentHandler, CDMFRTagsConstants.NAMESPACE_AMETYS_CDM + CoursePart.NB_HOURS, String.valueOf(coursePart.getNumberOfHours())); 647 648 Course courseHolder = coursePart.getCourseHolder(); 649 if (courseHolder != null) 650 { 651 // it is not a normal case, but sometimes, the courseHolder references a not existing course, and we don't want to fail here 652 XMLUtils.createElement(contentHandler, CDMFRTagsConstants.NAMESPACE_AMETYS_CDM + CoursePart.COURSE_HOLDER, courseHolder.getCDMId()); 653 } 654 655 XMLUtils.endElement(contentHandler, CDMFRTagsConstants.NAMESPACE_AMETYS_CDM + "coursePart"); 656 } 657 658 @Override 659 public void orgunit2CDM(ContentHandler contentHandler, OrgUnit orgunit) throws SAXException 660 { 661 // nothing 662 } 663 664 @Override 665 public void person2CDM(ContentHandler contentHandler, Person person) throws SAXException 666 { 667 // Titre du contenu (à ne pas confondre avec personTitle) 668 String title = person.getTitle(); 669 if (StringUtils.isNotEmpty(title)) 670 { 671 XMLUtils.createElement(contentHandler, CDMFRTagsConstants.NAMESPACE_AMETYS_CDM + "title", title); 672 } 673 } 674 675 @Override 676 public void container2CDM(ContentHandler contentHandler, Container container, Set<String> persons, Set<String> orgUnits) throws SAXException 677 { 678 // Période 679 // <ametys-cdm:period code="code">Label</ametys-cdm:period> 680 String period = container.getPeriod(); 681 if (StringUtils.isNotEmpty(period)) 682 { 683 String code = _refTableHelper.getItemCDMfrValue(period, true); 684 String label = _refTableHelper.getItemLabel(period, container.getLanguage()); 685 686 AttributesImpl attrs = new AttributesImpl(); 687 attrs.addCDATAAttribute("code", code); 688 XMLUtils.createElement(contentHandler, CDMFRTagsConstants.NAMESPACE_AMETYS_CDM + Container.PERIOD, attrs, label); 689 } 690 } 691}