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