001/* 002 * Copyright 2011 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.enumeration; 017 018import java.util.Arrays; 019import java.util.Collections; 020import java.util.HashMap; 021import java.util.HashSet; 022import java.util.LinkedHashMap; 023import java.util.List; 024import java.util.Map; 025import java.util.Optional; 026import java.util.Set; 027import java.util.stream.Collectors; 028 029import org.apache.avalon.framework.component.Component; 030import org.apache.avalon.framework.service.ServiceException; 031import org.apache.avalon.framework.service.ServiceManager; 032import org.apache.avalon.framework.service.Serviceable; 033import org.apache.cocoon.xml.AttributesImpl; 034import org.apache.cocoon.xml.XMLUtils; 035import org.apache.commons.lang3.StringUtils; 036import org.xml.sax.ContentHandler; 037import org.xml.sax.SAXException; 038 039import org.ametys.cms.contenttype.ContentAttributeDefinition; 040import org.ametys.cms.contenttype.ContentType; 041import org.ametys.cms.contenttype.ContentTypeExtensionPoint; 042import org.ametys.cms.contenttype.ContentTypesHelper; 043import org.ametys.cms.data.ContentValue; 044import org.ametys.cms.repository.Content; 045import org.ametys.cms.repository.ContentQueryHelper; 046import org.ametys.cms.repository.ContentTypeExpression; 047import org.ametys.core.ui.Callable; 048import org.ametys.odf.ODFHelper; 049import org.ametys.odf.ProgramItem; 050import org.ametys.odf.program.AbstractProgram; 051import org.ametys.odf.program.Program; 052import org.ametys.plugins.repository.AmetysObjectIterable; 053import org.ametys.plugins.repository.AmetysObjectIterator; 054import org.ametys.plugins.repository.AmetysObjectResolver; 055import org.ametys.plugins.repository.UnknownAmetysObjectException; 056import org.ametys.plugins.repository.model.RepeaterDefinition; 057import org.ametys.plugins.repository.query.SortCriteria; 058import org.ametys.plugins.repository.query.expression.AndExpression; 059import org.ametys.plugins.repository.query.expression.Expression.Operator; 060import org.ametys.plugins.repository.query.expression.StringExpression; 061import org.ametys.runtime.config.Config; 062import org.ametys.runtime.model.ElementDefinition; 063import org.ametys.runtime.model.ModelItem; 064import org.ametys.runtime.model.ModelItemContainer; 065import org.ametys.runtime.model.View; 066import org.ametys.runtime.model.ViewElement; 067import org.ametys.runtime.model.ViewItem; 068import org.ametys.runtime.model.ViewItemContainer; 069import org.ametys.runtime.plugin.component.AbstractLogEnabled; 070 071/** 072 * This component handles ODF reference tables 073 * 074 */ 075public class OdfReferenceTableHelper extends AbstractLogEnabled implements Component, Serviceable 076{ 077 /** Avalon Role */ 078 public static final String ROLE = OdfReferenceTableHelper.class.getName(); 079 080 /** Abstract table ref */ 081 public static final String ABSTRACT_TABLE_REF = "odf-enumeration.AbstractTableRef"; 082 /** Domain */ 083 public static final String DOMAIN = "odf-enumeration.Domain"; 084 /** Degree */ 085 public static final String DEGREE = "odf-enumeration.Degree"; 086 /** Level */ 087 public static final String LEVEL = "odf-enumeration.Level"; 088 /** Program type. */ 089 public static final String PROGRAM_TYPE = "odf-enumeration.ProgramType"; 090 /** Form of teaching */ 091 public static final String FORMOFTEACHING_METHOD = "odf-enumeration.FormofteachingMethod"; 092 /** Orgnization of teaching */ 093 public static final String FORMOFTEACHING_ORG = "odf-enumeration.FormofteachingOrg"; 094 /** Teaching method */ 095 public static final String TEACHING_ACTIVITY = "odf-enumeration.TeachingActivity"; 096 /** Type of training course */ 097 public static final String INTERNSHIP = "odf-enumeration.Internship"; 098 /** Distance learning modalities */ 099 public static final String DISTANCE_LEARNING_MODALITIES = "odf-enumeration.DistanceLearningModalities"; 100 /** Place */ 101 public static final String PLACE = "odf-enumeration.Place"; 102 /** Teaching term. */ 103 public static final String TEACHING_TERM = "odf-enumeration.TeachingTerm"; 104 /** Time slot */ 105 public static final String TIME_SLOT = "odf-enumeration.TimeSlot"; 106 /** Code ROME */ 107 public static final String CODE_ROME = "odf-enumeration.CodeRome"; 108 /** Code ERASMUS */ 109 public static final String CODE_ERASMUS = "odf-enumeration.CodeErasmus"; 110 /** Code DGESIP */ 111 public static final String CODE_DGESIP = "odf-enumeration.CodeDgesip"; 112 /** Code SISE */ 113 public static final String CODE_SISE = "odf-enumeration.CodeSise"; 114 /** Code Cite97 */ 115 public static final String CODE_CITE97 = "odf-enumeration.CodeCite97"; 116 /** Code FAP */ 117 public static final String CODE_FAP = "odf-enumeration.CodeFap"; 118 /** Code NSF */ 119 public static final String CODE_NSF = "odf-enumeration.CodeNsf"; 120 /** RNCP level */ 121 public static final String RNCP_LEVEL = "odf-enumeration.RncpLevel"; 122 /** Join orgunit*/ 123 public static final String JOIN_ORGUNIT = "odf-enumeration.JoinOrgunit"; 124 /** Mention licence */ 125 public static final String ABSTRACT_MENTION = "odf-enumeration.Mention"; 126 /** Mention BUT */ 127 public static final String MENTION_BUT = "odf-enumeration.MentionBUT"; 128 /** Mention BUT */ 129 public static final String MENTION_BUT_ATTRIBUTE_PARCOURS = "parcours"; 130 /** Mention licence */ 131 public static final String MENTION_LICENCE = "odf-enumeration.MentionLicence"; 132 /** Mention licence pro */ 133 public static final String MENTION_LICENCEPRO = "odf-enumeration.MentionLicencepro"; 134 /** Mention master */ 135 public static final String MENTION_MASTER = "odf-enumeration.MentionMaster"; 136 /** Abstract table ref for category */ 137 public static final String ABSTRACT_TABLE_REF_CATEGORY = "odf-enumeration.AbstractTableRefCategory"; 138 /** Apprenticeship contract */ 139 public static final String APPRENTICESHIP_CONTRACT = "odf-enumeration.ApprenticeshipContract"; 140 /** Available certification */ 141 public static final String AVAILABLE_CERTIFICATION = "odf-enumeration.AvailableCertification"; 142 /** Campus */ 143 public static final String CAMPUS = "odf-enumeration.Campus"; 144 /** Category for code Erasmus */ 145 public static final String CODE_ERASMUS_CATEGORY = "odf-enumeration.CodeErasmusCategory"; 146 /** Category for code FAP */ 147 public static final String CODE_FAP_CATEGORY = "odf-enumeration.CodeFapCategory"; 148 /** Nature of container */ 149 public static final String CONTAINER_NATURE = "odf-enumeration.ContainerNature"; 150 /** Nature of course */ 151 public static final String COURSE_NATURE = "odf-enumeration.CourseNature"; 152 /** Discipline */ 153 public static final String DISCIPLINE = "odf-enumeration.Discipline"; 154 /** Duration */ 155 public static final String DURATION = "odf-enumeration.Duration"; 156 /** ECTS */ 157 public static final String ECTS = "odf-enumeration.Ects"; 158 /** Foreign place */ 159 public static final String FOREIGN_PLACE = "odf-enumeration.ForeignPlace"; 160 /** International education */ 161 public static final String INTERNATIONAL_EDUCATION = "odf-enumeration.InternationalEducation"; 162 /** Language */ 163 public static final String LANGUAGE = "odf-enumeration.Language"; 164 /** OrgUnit type */ 165 public static final String ORGUNIT_TYPE = "odf-enumeration.OrgUnitType"; 166 /** Period */ 167 public static final String PERIOD = "odf-enumeration.Period"; 168 /** Period type */ 169 public static final String PERIOD_TYPE = "odf-enumeration.PeriodType"; 170 /** Person role */ 171 public static final String PERSON_ROLE = "odf-enumeration.PersonRole"; 172 /** Program field */ 173 public static final String PROGRAM_FIELD = "odf-enumeration.ProgramField"; 174 /** Sectors */ 175 public static final String SECTORS = "odf-enumeration.Sectors"; 176 /** Nature of course part */ 177 public static final String ENSEIGNEMENT_NATURE = "odf-enumeration.EnseignementNature"; 178 /** Category of nature of course part */ 179 public static final String ENSEIGNEMENT_NATURE_CATEGORY = "odf-enumeration.EnseignementNatureCategory"; 180 /** Skill */ 181 public static final String SKILL = "odf-enumeration.Skill"; 182 /** Skill set */ 183 public static final String SKILL_SET = "odf-enumeration.SkillSet"; 184 /** Attribute name for mention type in table refe degree */ 185 public static final String DEGREE_MENTION_TYPE = "mentionType"; 186 187 private AmetysObjectResolver _resolver; 188 189 private ContentTypeExtensionPoint _cTypeEP; 190 191 private ContentTypesHelper _cTypeHelper; 192 193 private ODFHelper _odfHelper; 194 195 @Override 196 public void service(ServiceManager manager) throws ServiceException 197 { 198 _resolver = (AmetysObjectResolver) manager.lookup(AmetysObjectResolver.ROLE); 199 _cTypeEP = (ContentTypeExtensionPoint) manager.lookup(ContentTypeExtensionPoint.ROLE); 200 _cTypeHelper = (ContentTypesHelper) manager.lookup(ContentTypesHelper.ROLE); 201 _odfHelper = (ODFHelper) manager.lookup(ODFHelper.ROLE); 202 } 203 204 /** 205 * Determines if the content type is a ODF table reference 206 * @param cTypeId The id of content type 207 * @return true if the content type is a ODF table reference 208 */ 209 public boolean isTableReference(String cTypeId) 210 { 211 return _cTypeHelper.getAncestors(cTypeId).contains(ABSTRACT_TABLE_REF); 212 } 213 214 /** 215 * Determines if the content is an entry of a ODF table reference 216 * @param content The content 217 * @return <code>true</code> if the content is an entry of a ODF table reference 218 */ 219 public boolean isTableReferenceEntry(Content content) 220 { 221 String[] cTypeIds = content.getTypes(); 222 for (String cTypeId : cTypeIds) 223 { 224 if (isTableReference(cTypeId)) 225 { 226 return true; 227 } 228 } 229 return false; 230 } 231 232 /** 233 * Get the id of table references 234 * @return The content type's id 235 */ 236 public Set<String> getTableReferenceIds() 237 { 238 Set<String> tableRefIds = new HashSet<>(); 239 240 for (String cTypeId : _cTypeEP.getExtensionsIds()) 241 { 242 if (_cTypeHelper.getAncestors(cTypeId).contains(ABSTRACT_TABLE_REF)) 243 { 244 tableRefIds.add(cTypeId); 245 } 246 } 247 return tableRefIds; 248 } 249 250 /** 251 * Get the attribute definitions for table references for a given content type 252 * @param cTypeId The id of content type 253 * @return The attribute definitions for table references 254 */ 255 public Map<String, ContentAttributeDefinition> getTableRefAttributeDefinitions(String cTypeId) 256 { 257 ContentType cType = _cTypeEP.getExtension(cTypeId); 258 return _getTableRefAttributes(cType); 259 } 260 261 private Map<String, ContentAttributeDefinition> _getTableRefAttributes(ModelItemContainer modelItemContainer) 262 { 263 Map<String, ContentAttributeDefinition> tableRefAttributes = new LinkedHashMap<>(); 264 265 for (ModelItem modelItem : modelItemContainer.getModelItems()) 266 { 267 if (modelItem instanceof ContentAttributeDefinition) 268 { 269 ContentAttributeDefinition attributeDefinition = (ContentAttributeDefinition) modelItem; 270 if (isTableReference(attributeDefinition.getContentTypeId())) 271 { 272 tableRefAttributes.put(attributeDefinition.getPath(), attributeDefinition); 273 } 274 } 275 else if (modelItem instanceof ModelItemContainer && !(modelItem instanceof RepeaterDefinition)) 276 { 277 // enumerated attributes in repeaters are not supported 278 tableRefAttributes.putAll(_getTableRefAttributes((ModelItemContainer) modelItem)); 279 } 280 } 281 282 return tableRefAttributes; 283 } 284 285 /** 286 * Get the attribute definitions for table references for a given content type and a view 287 * @param cTypeId The id of content type 288 * @param viewName the name of the view. Cannot be null. 289 * @return The attributes definitions for table references 290 */ 291 public Map<String, ContentAttributeDefinition> getTableRefAttributeDefinitions(String cTypeId, String viewName) 292 { 293 ContentType cType = _cTypeEP.getExtension(cTypeId); 294 295 View view = cType.getView(viewName); 296 return _getTableRefAttributes(view); 297 } 298 299 private Map<String, ContentAttributeDefinition> _getTableRefAttributes(ViewItemContainer viewItemContainer) 300 { 301 Map<String, ContentAttributeDefinition> tableRefAttributes = new LinkedHashMap<>(); 302 303 for (ViewItem viewItem : viewItemContainer.getViewItems()) 304 { 305 if (viewItem instanceof ViewElement) 306 { 307 ElementDefinition definition = ((ViewElement) viewItem).getDefinition(); 308 if (definition instanceof ContentAttributeDefinition) 309 { 310 tableRefAttributes.put(definition.getPath(), (ContentAttributeDefinition) definition); 311 } 312 } 313 else if (viewItem instanceof ViewItemContainer) 314 { 315 tableRefAttributes.putAll(_getTableRefAttributes((ViewItemContainer) viewItem)); 316 } 317 } 318 319 return tableRefAttributes; 320 } 321 322 /** 323 * Get the content type for mention for this degree 324 * @param degreeIds The ids of degrees 325 * @return A map with the id of content type or null if there is no mention for this degree 326 */ 327 @Callable 328 public Map<String, String> getMentionContentTypes(List<String> degreeIds) 329 { 330 Map<String, String> mentionTypes = new HashMap<>(); 331 for (String degreeId : degreeIds) 332 { 333 mentionTypes.put(degreeId, getMentionForDegree(degreeId)); 334 } 335 return mentionTypes; 336 } 337 338 /** 339 * Get the available BUT training paths for a BUT mention 340 * @param mentionId the id of BUT mention 341 * @return the BUT training paths 342 */ 343 public ContentValue[] getBUTParcoursForMention(String mentionId) 344 { 345 Content content = _resolver.resolveById(mentionId); 346 if (_cTypeHelper.isInstanceOf(content, MENTION_BUT)) 347 { 348 return content.getValue(MENTION_BUT_ATTRIBUTE_PARCOURS, false, new ContentValue[0]); 349 } 350 return new ContentValue[0]; 351 } 352 353 /** 354 * Get the available BUT training paths for a content 355 * @param contentId the content's id 356 * @param mentionId the id of mention. Can be null or empty 357 * @return the available BUT training paths 358 */ 359 @Callable 360 public List<Map<String, String>> getBUTParcoursItems(String contentId, String mentionId) 361 { 362 ContentValue[] values = null; 363 if (StringUtils.isNotEmpty(mentionId)) 364 { 365 // Get items from mention 366 values = getBUTParcoursForMention(mentionId); 367 } 368 else 369 { 370 // Get items from parent program 371 values = getBUTParcoursItems(contentId); 372 } 373 374 if (values != null) 375 { 376 return Arrays.stream(values) 377 .map(ContentValue::getContent) 378 .map(c -> Map.of("id", c.getId(), "title", c.getTitle())) 379 .collect(Collectors.toList()); 380 } 381 else 382 { 383 return List.of(); 384 } 385 } 386 /** 387 * Get the available BUT training paths for a {@link ProgramItem} 388 * @param programItemId the id of program item 389 * @return the BUT training paths 390 */ 391 public ContentValue[] getBUTParcoursItems(String programItemId) 392 { 393 Content content = _resolver.resolveById(programItemId); 394 395 // Get first parent program 396 Set<Program> parentPrograms = _odfHelper.getParentPrograms((AbstractProgram) content); 397 if (!parentPrograms.isEmpty()) 398 { 399 Program program = parentPrograms.iterator().next(); 400 401 if (isBUTDiploma(program)) 402 { 403 return Optional.ofNullable(program.<ContentValue>getValue(AbstractProgram.MENTION)) 404 .map(ContentValue::getContentIfExists) 405 .filter(Optional::isPresent) 406 .map(Optional::get) 407 .map(c -> c.<ContentValue[]>getValue(MENTION_BUT_ATTRIBUTE_PARCOURS)) 408 .orElse(new ContentValue[0]); 409 410 } 411 } 412 413 // No BUT training paths 414 return new ContentValue[0]; 415 } 416 417 /** 418 * Determines if the program is a BUT diploma 419 * @param program the program 420 * @return true if the program has a BUT 421 */ 422 public boolean isBUTDiploma(Program program) 423 { 424 String mentionType = getMentionType(program); 425 return mentionType != null && MENTION_BUT.equals(mentionType); 426 } 427 428 /** 429 * Get the type of mention for a program 430 * @param program the program 431 * @return the type of mention or null if there is no mention for this program 432 */ 433 public String getMentionType(Program program) 434 { 435 return Optional.ofNullable(program.<ContentValue>getValue(AbstractProgram.DEGREE)) 436 .map(ContentValue::getContentIfExists) 437 .filter(Optional::isPresent) 438 .map(Optional::get) 439 .map(c -> c.<String>getValue(DEGREE_MENTION_TYPE)) 440 .orElse(null); 441 } 442 443 /** 444 * Get the mention for a given degree. 445 * @param degreeId The degree ID 446 * @return The associated mention reference table, null if there isn't 447 */ 448 public String getMentionForDegree(String degreeId) 449 { 450 try 451 { 452 Content content = _resolver.resolveById(degreeId); 453 return content.getValue(DEGREE_MENTION_TYPE); 454 } 455 catch (UnknownAmetysObjectException e) 456 { 457 // Nothing to do 458 } 459 return null; 460 } 461 462 /** 463 * Get the CDM-fr value associated with the given code 464 * @param tableRefId The id of content type 465 * @param code The code 466 * @return The CDM-fr value or empty string if not found 467 */ 468 public String getCDMfrValue (String tableRefId, String code) 469 { 470 ContentTypeExpression cTypeExpr = new ContentTypeExpression(Operator.EQ, tableRefId); 471 StringExpression codeExpr = new StringExpression(OdfReferenceTableEntry.CODE, Operator.EQ, code); 472 473 String xpathQuery = ContentQueryHelper.getContentXPathQuery(new AndExpression(cTypeExpr, codeExpr)); 474 AmetysObjectIterable<Content> contents = _resolver.query(xpathQuery); 475 AmetysObjectIterator<Content> it = contents.iterator(); 476 477 if (it.hasNext()) 478 { 479 OdfReferenceTableEntry entry = new OdfReferenceTableEntry(it.next()); 480 return entry.getCdmValue(); 481 } 482 483 return ""; 484 } 485 486 /** 487 * Get all items of an enumeration and their label 488 * @param tableRefId The id of content type 489 * @return items of enumeration 490 */ 491 public List<OdfReferenceTableEntry> getItems (String tableRefId) 492 { 493 return getItems(tableRefId, new SortField[0]); 494 } 495 496 /** 497 * Get all items of an enumeration and their label, sorted by given fields 498 * @param tableRefId The id of content type 499 * @param sortFields The sort fields to order results 500 * @return items of enumeration 501 */ 502 public List<OdfReferenceTableEntry> getItems (String tableRefId, SortField... sortFields) 503 { 504 ContentTypeExpression cTypeExpr = new ContentTypeExpression(Operator.EQ, tableRefId); 505 506 SortCriteria sortCriteria = new SortCriteria(); 507 for (SortField sortField : sortFields) 508 { 509 sortCriteria.addCriterion(sortField.getName(), sortField.getAscending(), sortField.getNormalize()); 510 } 511 512 String xpathQuery = ContentQueryHelper.getContentXPathQuery(cTypeExpr, sortCriteria); 513 AmetysObjectIterable<Content> contents = _resolver.query(xpathQuery); 514 515 return contents.stream().map(c -> new OdfReferenceTableEntry(c)).collect(Collectors.toList()); 516 } 517 518 /** 519 * Returns the label of an reference table entry 520 * @param contentId The content id 521 * @param lang The requested language of label 522 * @return the item label or <code>null</code> if not found 523 */ 524 public String getItemLabel(String contentId, String lang) 525 { 526 try 527 { 528 Content content = _resolver.resolveById(contentId); 529 OdfReferenceTableEntry entry = new OdfReferenceTableEntry(content); 530 return entry.getLabel(lang); 531 } 532 catch (UnknownAmetysObjectException e) 533 { 534 return null; 535 } 536 } 537 538 /** 539 * Returns the label of an reference table entry 540 * @param tableRefId The id of content type (useless) 541 * @param contentId The content id 542 * @param lang The requested language of label 543 * @return the item label or <code>null</code> if not found 544 * @deprecated Use {@link #getItemLabel(String, String)} instead 545 */ 546 @Deprecated 547 public String getItemLabel (String tableRefId, String contentId, String lang) 548 { 549 return getItemLabel(contentId, lang); 550 } 551 552 /** 553 * Returns the CMD value of an reference table entry 554 * @param contentId The content id 555 * @param returnCodeIfEmpty <code>true</code> to return the code if CDM-fr value is empty 556 * @return the CDM-fr value or empty value if not found 557 */ 558 public String getItemCDMfrValue(String contentId, boolean returnCodeIfEmpty) 559 { 560 if (StringUtils.isEmpty(contentId)) 561 { 562 return ""; 563 } 564 565 Content content = _resolver.resolveById(contentId); 566 OdfReferenceTableEntry entry = new OdfReferenceTableEntry(content); 567 568 String cdmValue = entry.getCdmValue(); 569 570 if (StringUtils.isEmpty(cdmValue) && returnCodeIfEmpty) 571 { 572 return entry.getCode(); 573 } 574 return cdmValue; 575 } 576 577 /** 578 * Returns the CMD value of an reference table entry 579 * @param tableRefId The id of content type (useless) 580 * @param contentId The content id 581 * @param returnCodeIfEmpty <code>true</code> to return the code if CDM-fr value is empty 582 * @return the CDM-fr value or empty value if not found 583 * @deprecated Use {@link #getItemCDMfrValue(String, boolean)} instead 584 */ 585 @Deprecated 586 public String getItemCDMfrValue (String tableRefId, String contentId, boolean returnCodeIfEmpty) 587 { 588 return getItemCDMfrValue(contentId, returnCodeIfEmpty); 589 } 590 591 /** 592 * Returns the code of an reference table entry from its CDM value 593 * @param contentId The id of content 594 * @return the code or empty value if not found 595 */ 596 public String getItemCode(String contentId) 597 { 598 if (StringUtils.isEmpty(contentId)) 599 { 600 return ""; 601 } 602 603 try 604 { 605 Content content = _resolver.resolveById(contentId); 606 OdfReferenceTableEntry entry = new OdfReferenceTableEntry(content); 607 return entry.getCode(); 608 } 609 catch (UnknownAmetysObjectException e) 610 { 611 return ""; 612 } 613 } 614 615 /** 616 * Returns the code of an reference table entry from its CDM value 617 * @param tableRefId The id of content type (useless) 618 * @param contentId The id of content 619 * @return the code or empty value if not found 620 * @deprecated Use {@link #getItemCode(String)} instead 621 */ 622 @Deprecated 623 public String getItemCode (String tableRefId, String contentId) 624 { 625 return getItemCode(contentId); 626 } 627 628 /** 629 * Returns the code of an reference table entry from its CDM value 630 * @param tableRefId The id of content type 631 * @param cdmValue The CDM-fr value 632 * @return the code or <code>null</code> if not found 633 */ 634 public String getItemCodeFromCDM (String tableRefId, String cdmValue) 635 { 636 ContentTypeExpression cTypeExpr = _getContentTypeExpression(tableRefId); 637 StringExpression codeExpr = new StringExpression(OdfReferenceTableEntry.CDM_VALUE, Operator.EQ, cdmValue); 638 639 String xpathQuery = ContentQueryHelper.getContentXPathQuery(new AndExpression(cTypeExpr, codeExpr)); 640 AmetysObjectIterable<Content> contents = _resolver.query(xpathQuery); 641 AmetysObjectIterator<Content> it = contents.iterator(); 642 643 if (it.hasNext()) 644 { 645 OdfReferenceTableEntry entry = new OdfReferenceTableEntry(it.next()); 646 return entry.getCode(); 647 } 648 return null; 649 } 650 651 /** 652 * Returns the entry of an reference table entry from its cdmValue 653 * @param tableRefId The id of content type 654 * @param cdmValue The CDM-fr value 655 * @return the entry or <code>null</code> if not found 656 */ 657 public OdfReferenceTableEntry getItemFromCDM(String tableRefId, String cdmValue) 658 { 659 ContentTypeExpression cTypeExpr = _getContentTypeExpression(tableRefId); 660 StringExpression cdmExpr = new StringExpression(OdfReferenceTableEntry.CDM_VALUE, Operator.EQ, cdmValue); 661 662 String xpathQuery = ContentQueryHelper.getContentXPathQuery(new AndExpression(cTypeExpr, cdmExpr)); 663 664 return _resolver.<Content>query(xpathQuery).stream() 665 .findFirst() 666 .map(OdfReferenceTableEntry::new) 667 .orElse(null); 668 } 669 670 /** 671 * Returns the entry of an reference table entry from its code 672 * @param tableRefId The id of content type 673 * @param code The code 674 * @return the entry or <code>null</code> if not found 675 */ 676 public OdfReferenceTableEntry getItemFromCode(String tableRefId, String code) 677 { 678 ContentTypeExpression cTypeExpr = _getContentTypeExpression(tableRefId); 679 StringExpression codeExpr = new StringExpression(OdfReferenceTableEntry.CODE, Operator.EQ, code); 680 681 String xpathQuery = ContentQueryHelper.getContentXPathQuery(new AndExpression(cTypeExpr, codeExpr)); 682 683 return _resolver.<Content>query(xpathQuery).stream() 684 .findFirst() 685 .map(OdfReferenceTableEntry::new) 686 .orElse(null); 687 } 688 689 /** 690 * Returns the entry of a reference table entry from its code for the connector (Apogée, Pégase...) 691 * @param tableRefId The id of content type 692 * @param connectorCode The code 693 * @param codeFieldName The field name containing the connector code 694 * @return the entry or <code>null</code> if not found 695 */ 696 public OdfReferenceTableEntry getItemFromConnector(String tableRefId, String connectorCode, String codeFieldName) 697 { 698 ContentTypeExpression cTypeExpr = _getContentTypeExpression(tableRefId); 699 StringExpression cdmExpr = new StringExpression(codeFieldName, Operator.EQ, connectorCode); 700 701 String xpathQuery = ContentQueryHelper.getContentXPathQuery(new AndExpression(cTypeExpr, cdmExpr)); 702 703 return _resolver.<Content>query(xpathQuery).stream() 704 .findFirst() 705 .map(OdfReferenceTableEntry::new) 706 .orElse(null); 707 } 708 709 private ContentTypeExpression _getContentTypeExpression(String tableRefId) 710 { 711 Set<String> tableRefids; 712 if (tableRefId.equals(OdfReferenceTableHelper.ABSTRACT_MENTION)) 713 { 714 tableRefids = _cTypeEP.getSubTypes(tableRefId); 715 } 716 else 717 { 718 tableRefids = Collections.singleton(tableRefId); 719 } 720 721 return new ContentTypeExpression(Operator.EQ, tableRefids.toArray(new String[tableRefids.size()])); 722 } 723 724 /** 725 * Returns the reference table entry from its CDM value 726 * @param contentId The id of content 727 * @return the item as an {@link OdfReferenceTableEntry} or null if not found 728 */ 729 public OdfReferenceTableEntry getItem(String contentId) 730 { 731 try 732 { 733 Content content = _resolver.resolveById(contentId); 734 return new OdfReferenceTableEntry(content); 735 } 736 catch (UnknownAmetysObjectException e) 737 { 738 // Can be an empty ID or an invalid ID (workspace or simply deleted element) 739 return null; 740 } 741 } 742 743 /** 744 * SAX items of a reference table 745 * @param contentHandler The content handler to sax into 746 * @param tableRefId The id of reference table 747 * @throws SAXException if an error occurred while saxing 748 */ 749 public void saxItems (ContentHandler contentHandler, String tableRefId) throws SAXException 750 { 751 saxItems(contentHandler, tableRefId, null); 752 } 753 754 /** 755 * SAX items of a reference table 756 * @param contentHandler the content handler to sax into 757 * @param attributeDefinition the metadata definition 758 * @throws SAXException if an error occurs while saxing 759 */ 760 public void saxItems (ContentHandler contentHandler, ContentAttributeDefinition attributeDefinition) throws SAXException 761 { 762 saxItems(contentHandler, attributeDefinition, null); 763 } 764 765 /** 766 * SAX items of a reference table 767 * @param contentHandler The content handler to sax into 768 * @param tableRefId The id of reference table 769 * @param lang the language to use to display items, can be <code>null</code> then odf language is used 770 * @throws SAXException if an error occurred while saxing 771 */ 772 public void saxItems (ContentHandler contentHandler, String tableRefId, String lang) throws SAXException 773 { 774 _saxItems(contentHandler, new AttributesImpl(), tableRefId, lang); 775 } 776 777 /** 778 * SAX items of a reference table 779 * @param contentHandler the content handler to sax into 780 * @param attributeDefinition the metadata definition 781 * @param lang the language to use to display items, can be <code>null</code> then odf language is used 782 * @throws SAXException if an error occurs while saxing 783 */ 784 public void saxItems(ContentHandler contentHandler, ContentAttributeDefinition attributeDefinition, String lang) throws SAXException 785 { 786 String cTypeId = attributeDefinition.getContentTypeId(); 787 if (cTypeId.startsWith("odf-enumeration.")) 788 { 789 AttributesImpl attrs = new AttributesImpl(); 790 attrs.addCDATAAttribute("metadataName", attributeDefinition.getName()); 791 attrs.addCDATAAttribute("metadataPath", attributeDefinition.getPath()); 792 793 _saxItems(contentHandler, attrs, cTypeId, lang); 794 } 795 } 796 797 private void _saxItems(ContentHandler contentHandler, AttributesImpl rootAttrs, String tableRefId, String lang) throws SAXException 798 { 799 String langToUse = lang != null ? lang : Config.getInstance().getValue("odf.programs.lang"); 800 boolean hasShortLabel = _cTypeEP.getExtension(tableRefId).hasModelItem("shortLabel"); 801 802 rootAttrs.addCDATAAttribute("contentTypeId", tableRefId); 803 XMLUtils.startElement(contentHandler, "items", rootAttrs); 804 805 List<OdfReferenceTableEntry> entries = getItems(tableRefId); 806 for (OdfReferenceTableEntry entry : entries) 807 { 808 AttributesImpl valueAttrs = new AttributesImpl(); 809 valueAttrs.addCDATAAttribute("id", entry.getId()); 810 valueAttrs.addCDATAAttribute("order", entry.getOrder().toString()); 811 valueAttrs.addCDATAAttribute("code", entry.getCode()); 812 valueAttrs.addCDATAAttribute("cdmValue", entry.getCdmValue()); 813 valueAttrs.addCDATAAttribute("archived", entry.isArchived().toString()); 814 if (hasShortLabel) 815 { 816 valueAttrs.addCDATAAttribute("shortLabel", entry.getContent().getValue("shortLabel", false, StringUtils.EMPTY)); 817 } 818 819 XMLUtils.createElement(contentHandler, "item", valueAttrs, entry.getLabel(langToUse)); 820 } 821 822 XMLUtils.endElement(contentHandler, "items"); 823 } 824 825 /** 826 * This class represents a sort field for reference table. 827 * 828 */ 829 public static final class SortField 830 { 831 private String _name; 832 private boolean _ascending; 833 private boolean _normalize; 834 835 /** 836 * Create a sort field 837 * @param name the name of field to sort on 838 * @param ascending <code>true</code> to sort in ascending order, <code>false</code> otherwise 839 */ 840 public SortField(String name, boolean ascending) 841 { 842 this(name, ascending, false); 843 } 844 845 /** 846 * Create a sort field 847 * @param name the name of field to sort on 848 * @param ascending <code>true</code> to sort in ascending order, <code>false</code> otherwise 849 * @param normalize <code>true</code> to normalize string properties (remove accents and lower case) 850 */ 851 public SortField(String name, boolean ascending, boolean normalize) 852 { 853 _name = name; 854 _ascending = ascending; 855 _normalize = normalize; 856 } 857 858 /** 859 * Get the name of the sort field 860 * @return the name of the sort field 861 */ 862 public String getName() 863 { 864 return _name; 865 } 866 867 /** 868 * Get the order for sorting results 869 * @return <code>true</code> to sort results in ascending order, <code>false</code> otherwise 870 */ 871 public boolean getAscending() 872 { 873 return _ascending; 874 } 875 876 /** 877 * Return the normalize status for this sort field 878 * @return <code>true</code> if string properties should be normalized (remove accents and lower case) 879 */ 880 public boolean getNormalize() 881 { 882 return _normalize; 883 } 884 885 } 886}