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 .map(ContentValue::getContentIfExists) 408 .filter(Optional::isPresent) 409 .map(Optional::get) 410 .map(c -> c.<ContentValue[]>getValue(MENTION_BUT_ATTRIBUTE_PARCOURS)) 411 .orElse(new ContentValue[0]); 412 413 } 414 } 415 416 // No BUT training paths 417 return new ContentValue[0]; 418 } 419 420 /** 421 * Determines if the program is a BUT diploma 422 * @param program the program 423 * @return true if the program has a BUT 424 */ 425 public boolean isBUTDiploma(Program program) 426 { 427 String mentionType = getMentionType(program); 428 return mentionType != null && MENTION_BUT.equals(mentionType); 429 } 430 431 /** 432 * Get the type of mention for a program 433 * @param program the program 434 * @return the type of mention or null if there is no mention for this program 435 */ 436 public String getMentionType(Program program) 437 { 438 return Optional.ofNullable(program.<ContentValue>getValue(AbstractProgram.DEGREE)) 439 .map(ContentValue::getContentIfExists) 440 .filter(Optional::isPresent) 441 .map(Optional::get) 442 .map(c -> c.<String>getValue(DEGREE_MENTION_TYPE)) 443 .orElse(null); 444 } 445 446 /** 447 * Get the mention for a given degree. 448 * @param degreeId The degree ID 449 * @return The associated mention reference table, null if there isn't 450 */ 451 public String getMentionForDegree(String degreeId) 452 { 453 try 454 { 455 Content content = _resolver.resolveById(degreeId); 456 return content.getValue(DEGREE_MENTION_TYPE); 457 } 458 catch (UnknownAmetysObjectException e) 459 { 460 // Nothing to do 461 } 462 return null; 463 } 464 465 /** 466 * Get the CDM-fr value associated with the given code 467 * @param tableRefId The id of content type 468 * @param code The code 469 * @return The CDM-fr value or empty string if not found 470 */ 471 public String getCDMfrValue (String tableRefId, String code) 472 { 473 ContentTypeExpression cTypeExpr = new ContentTypeExpression(Operator.EQ, tableRefId); 474 StringExpression codeExpr = new StringExpression(OdfReferenceTableEntry.CODE, Operator.EQ, code); 475 476 String xpathQuery = ContentQueryHelper.getContentXPathQuery(new AndExpression(cTypeExpr, codeExpr)); 477 AmetysObjectIterable<Content> contents = _resolver.query(xpathQuery); 478 AmetysObjectIterator<Content> it = contents.iterator(); 479 480 if (it.hasNext()) 481 { 482 OdfReferenceTableEntry entry = new OdfReferenceTableEntry(it.next()); 483 return entry.getCdmValue(); 484 } 485 486 return ""; 487 } 488 489 /** 490 * Get all items of an enumeration and their label 491 * @param tableRefId The id of content type 492 * @return items of enumeration 493 */ 494 public List<OdfReferenceTableEntry> getItems (String tableRefId) 495 { 496 return getItems(tableRefId, new SortField[0]); 497 } 498 499 /** 500 * Get all items of an enumeration and their label, sorted by given fields 501 * @param tableRefId The id of content type 502 * @param sortFields The sort fields to order results 503 * @return items of enumeration 504 */ 505 public List<OdfReferenceTableEntry> getItems (String tableRefId, SortField... sortFields) 506 { 507 return getItems(tableRefId, true, sortFields); 508 } 509 510 /** 511 * Get all items of an enumeration and their label, sorted by given fields 512 * @param tableRefId The id of content type 513 * @param includeArchived <code>true</code> to include archived entries 514 * @param sortFields The sort fields to order results 515 * @return items of enumeration 516 */ 517 public List<OdfReferenceTableEntry> getItems (String tableRefId, boolean includeArchived, SortField... sortFields) 518 { 519 Expression expr = new ContentTypeExpression(Operator.EQ, tableRefId); 520 if (!includeArchived) 521 { 522 Expression notArchivedExpr = new NotExpression(new BooleanExpression(OdfReferenceTableEntry.ARCHIVED, true)); 523 expr = new AndExpression(expr, notArchivedExpr); 524 } 525 526 SortCriteria sortCriteria = new SortCriteria(); 527 for (SortField sortField : sortFields) 528 { 529 sortCriteria.addCriterion(sortField.getName(), sortField.getAscending(), sortField.getNormalize()); 530 } 531 532 String xpathQuery = ContentQueryHelper.getContentXPathQuery(expr, sortCriteria); 533 AmetysObjectIterable<Content> contents = _resolver.query(xpathQuery); 534 535 return contents.stream().map(c -> new OdfReferenceTableEntry(c)).collect(Collectors.toList()); 536 } 537 538 /** 539 * Returns the label of an reference table entry 540 * @param contentId The content id 541 * @param lang The requested language of label 542 * @return the item label or <code>null</code> if not found 543 */ 544 public String getItemLabel(String contentId, String lang) 545 { 546 try 547 { 548 Content content = _resolver.resolveById(contentId); 549 OdfReferenceTableEntry entry = new OdfReferenceTableEntry(content); 550 return entry.getLabel(lang); 551 } 552 catch (UnknownAmetysObjectException e) 553 { 554 return null; 555 } 556 } 557 558 /** 559 * Returns the label of an reference table entry 560 * @param tableRefId The id of content type (useless) 561 * @param contentId The content id 562 * @param lang The requested language of label 563 * @return the item label or <code>null</code> if not found 564 * @deprecated Use {@link #getItemLabel(String, String)} instead 565 */ 566 @Deprecated 567 public String getItemLabel (String tableRefId, String contentId, String lang) 568 { 569 return getItemLabel(contentId, lang); 570 } 571 572 /** 573 * Returns the CMD value of an reference table entry 574 * @param contentId The content id 575 * @param returnCodeIfEmpty <code>true</code> to return the code if CDM-fr value is empty 576 * @return the CDM-fr value or empty value if not found 577 */ 578 public String getItemCDMfrValue(String contentId, boolean returnCodeIfEmpty) 579 { 580 if (StringUtils.isEmpty(contentId)) 581 { 582 return ""; 583 } 584 585 Content content = _resolver.resolveById(contentId); 586 OdfReferenceTableEntry entry = new OdfReferenceTableEntry(content); 587 588 String cdmValue = entry.getCdmValue(); 589 590 if (StringUtils.isEmpty(cdmValue) && returnCodeIfEmpty) 591 { 592 return entry.getCode(); 593 } 594 return cdmValue; 595 } 596 597 /** 598 * Returns the CMD value of an reference table entry 599 * @param tableRefId The id of content type (useless) 600 * @param contentId The content id 601 * @param returnCodeIfEmpty <code>true</code> to return the code if CDM-fr value is empty 602 * @return the CDM-fr value or empty value if not found 603 * @deprecated Use {@link #getItemCDMfrValue(String, boolean)} instead 604 */ 605 @Deprecated 606 public String getItemCDMfrValue (String tableRefId, String contentId, boolean returnCodeIfEmpty) 607 { 608 return getItemCDMfrValue(contentId, returnCodeIfEmpty); 609 } 610 611 /** 612 * Returns the code of an reference table entry from its CDM value 613 * @param contentId The id of content 614 * @return the code or empty value if not found 615 */ 616 public String getItemCode(String contentId) 617 { 618 if (StringUtils.isEmpty(contentId)) 619 { 620 return ""; 621 } 622 623 try 624 { 625 Content content = _resolver.resolveById(contentId); 626 OdfReferenceTableEntry entry = new OdfReferenceTableEntry(content); 627 return entry.getCode(); 628 } 629 catch (UnknownAmetysObjectException e) 630 { 631 return ""; 632 } 633 } 634 635 /** 636 * Returns the code of an reference table entry from its CDM value 637 * @param tableRefId The id of content type (useless) 638 * @param contentId The id of content 639 * @return the code or empty value if not found 640 * @deprecated Use {@link #getItemCode(String)} instead 641 */ 642 @Deprecated 643 public String getItemCode (String tableRefId, String contentId) 644 { 645 return getItemCode(contentId); 646 } 647 648 /** 649 * Returns the code of an reference table entry from its CDM value 650 * @param tableRefId The id of content type 651 * @param cdmValue The CDM-fr value 652 * @return the code or <code>null</code> if not found 653 */ 654 public String getItemCodeFromCDM (String tableRefId, String cdmValue) 655 { 656 ContentTypeExpression cTypeExpr = _getContentTypeExpression(tableRefId); 657 StringExpression codeExpr = new StringExpression(OdfReferenceTableEntry.CDM_VALUE, Operator.EQ, cdmValue); 658 659 String xpathQuery = ContentQueryHelper.getContentXPathQuery(new AndExpression(cTypeExpr, codeExpr)); 660 AmetysObjectIterable<Content> contents = _resolver.query(xpathQuery); 661 AmetysObjectIterator<Content> it = contents.iterator(); 662 663 if (it.hasNext()) 664 { 665 OdfReferenceTableEntry entry = new OdfReferenceTableEntry(it.next()); 666 return entry.getCode(); 667 } 668 return null; 669 } 670 671 /** 672 * Returns the entry of an reference table entry from its cdmValue 673 * @param tableRefId The id of content type 674 * @param cdmValue The CDM-fr value 675 * @return the entry or <code>null</code> if not found 676 */ 677 public OdfReferenceTableEntry getItemFromCDM(String tableRefId, String cdmValue) 678 { 679 ContentTypeExpression cTypeExpr = _getContentTypeExpression(tableRefId); 680 StringExpression cdmExpr = new StringExpression(OdfReferenceTableEntry.CDM_VALUE, Operator.EQ, cdmValue); 681 682 String xpathQuery = ContentQueryHelper.getContentXPathQuery(new AndExpression(cTypeExpr, cdmExpr)); 683 684 return _resolver.<Content>query(xpathQuery).stream() 685 .findFirst() 686 .map(OdfReferenceTableEntry::new) 687 .orElse(null); 688 } 689 690 /** 691 * Returns the entry of an reference table entry from its code 692 * @param tableRefId The id of content type 693 * @param code The code 694 * @return the entry or <code>null</code> if not found 695 */ 696 public OdfReferenceTableEntry getItemFromCode(String tableRefId, String code) 697 { 698 ContentTypeExpression cTypeExpr = _getContentTypeExpression(tableRefId); 699 StringExpression codeExpr = new StringExpression(OdfReferenceTableEntry.CODE, Operator.EQ, code); 700 701 String xpathQuery = ContentQueryHelper.getContentXPathQuery(new AndExpression(cTypeExpr, codeExpr)); 702 703 return _resolver.<Content>query(xpathQuery).stream() 704 .findFirst() 705 .map(OdfReferenceTableEntry::new) 706 .orElse(null); 707 } 708 709 /** 710 * Returns the entry of a reference table entry from its code for the connector (Apogée, Pégase...) 711 * @param tableRefId The id of content type 712 * @param connectorCode The code 713 * @param codeFieldName The field name containing the connector code 714 * @return the entry or <code>null</code> if not found 715 */ 716 public OdfReferenceTableEntry getItemFromConnector(String tableRefId, String connectorCode, String codeFieldName) 717 { 718 ContentTypeExpression cTypeExpr = _getContentTypeExpression(tableRefId); 719 StringExpression cdmExpr = new StringExpression(codeFieldName, Operator.EQ, connectorCode); 720 721 String xpathQuery = ContentQueryHelper.getContentXPathQuery(new AndExpression(cTypeExpr, cdmExpr)); 722 723 return _resolver.<Content>query(xpathQuery).stream() 724 .findFirst() 725 .map(OdfReferenceTableEntry::new) 726 .orElse(null); 727 } 728 729 private ContentTypeExpression _getContentTypeExpression(String tableRefId) 730 { 731 Set<String> tableRefids; 732 if (tableRefId.equals(OdfReferenceTableHelper.ABSTRACT_MENTION)) 733 { 734 tableRefids = _cTypeEP.getSubTypes(tableRefId); 735 } 736 else 737 { 738 tableRefids = Collections.singleton(tableRefId); 739 } 740 741 return new ContentTypeExpression(Operator.EQ, tableRefids.toArray(new String[tableRefids.size()])); 742 } 743 744 /** 745 * Returns the reference table entry from its CDM value 746 * @param contentId The id of content 747 * @return the item as an {@link OdfReferenceTableEntry} or null if not found 748 */ 749 public OdfReferenceTableEntry getItem(String contentId) 750 { 751 try 752 { 753 Content content = _resolver.resolveById(contentId); 754 return new OdfReferenceTableEntry(content); 755 } 756 catch (UnknownAmetysObjectException e) 757 { 758 // Can be an empty ID or an invalid ID (workspace or simply deleted element) 759 return null; 760 } 761 } 762 763 /** 764 * SAX items of a reference table 765 * @param contentHandler The content handler to sax into 766 * @param tableRefId The id of reference table 767 * @throws SAXException if an error occurred while saxing 768 */ 769 public void saxItems (ContentHandler contentHandler, String tableRefId) throws SAXException 770 { 771 saxItems(contentHandler, tableRefId, null); 772 } 773 774 /** 775 * SAX items of a reference table 776 * @param contentHandler the content handler to sax into 777 * @param attributeDefinition the metadata definition 778 * @throws SAXException if an error occurs while saxing 779 */ 780 public void saxItems (ContentHandler contentHandler, ContentAttributeDefinition attributeDefinition) throws SAXException 781 { 782 saxItems(contentHandler, attributeDefinition, null); 783 } 784 785 /** 786 * SAX items of a reference table 787 * @param contentHandler The content handler to sax into 788 * @param tableRefId The id of reference table 789 * @param lang the language to use to display items, can be <code>null</code> then odf language is used 790 * @throws SAXException if an error occurred while saxing 791 */ 792 public void saxItems (ContentHandler contentHandler, String tableRefId, String lang) throws SAXException 793 { 794 _saxItems(contentHandler, new AttributesImpl(), tableRefId, lang); 795 } 796 797 /** 798 * SAX items of a reference table 799 * @param contentHandler the content handler to sax into 800 * @param attributeDefinition the metadata definition 801 * @param lang the language to use to display items, can be <code>null</code> then odf language is used 802 * @throws SAXException if an error occurs while saxing 803 */ 804 public void saxItems(ContentHandler contentHandler, ContentAttributeDefinition attributeDefinition, String lang) throws SAXException 805 { 806 String cTypeId = attributeDefinition.getContentTypeId(); 807 if (cTypeId.startsWith("odf-enumeration.")) 808 { 809 AttributesImpl attrs = new AttributesImpl(); 810 attrs.addCDATAAttribute("metadataName", attributeDefinition.getName()); 811 attrs.addCDATAAttribute("metadataPath", attributeDefinition.getPath()); 812 813 _saxItems(contentHandler, attrs, cTypeId, lang); 814 } 815 } 816 817 private void _saxItems(ContentHandler contentHandler, AttributesImpl rootAttrs, String tableRefId, String lang) throws SAXException 818 { 819 String langToUse = lang != null ? lang : Config.getInstance().getValue("odf.programs.lang"); 820 boolean hasShortLabel = _cTypeEP.getExtension(tableRefId).hasModelItem("shortLabel"); 821 822 rootAttrs.addCDATAAttribute("contentTypeId", tableRefId); 823 XMLUtils.startElement(contentHandler, "items", rootAttrs); 824 825 List<OdfReferenceTableEntry> entries = getItems(tableRefId); 826 for (OdfReferenceTableEntry entry : entries) 827 { 828 AttributesImpl valueAttrs = new AttributesImpl(); 829 valueAttrs.addCDATAAttribute("id", entry.getId()); 830 valueAttrs.addCDATAAttribute("order", entry.getOrder().toString()); 831 valueAttrs.addCDATAAttribute("code", entry.getCode()); 832 valueAttrs.addCDATAAttribute("cdmValue", entry.getCdmValue()); 833 valueAttrs.addCDATAAttribute("archived", entry.isArchived().toString()); 834 if (hasShortLabel) 835 { 836 valueAttrs.addCDATAAttribute("shortLabel", entry.getContent().getValue("shortLabel", false, StringUtils.EMPTY)); 837 } 838 839 XMLUtils.createElement(contentHandler, "item", valueAttrs, entry.getLabel(langToUse)); 840 } 841 842 XMLUtils.endElement(contentHandler, "items"); 843 } 844 845 /** 846 * This class represents a sort field for reference table. 847 * 848 */ 849 public static final class SortField 850 { 851 private String _name; 852 private boolean _ascending; 853 private boolean _normalize; 854 855 /** 856 * Create a sort field 857 * @param name the name of field to sort on 858 * @param ascending <code>true</code> to sort in ascending order, <code>false</code> otherwise 859 */ 860 public SortField(String name, boolean ascending) 861 { 862 this(name, ascending, false); 863 } 864 865 /** 866 * Create a sort field 867 * @param name the name of field to sort on 868 * @param ascending <code>true</code> to sort in ascending order, <code>false</code> otherwise 869 * @param normalize <code>true</code> to normalize string properties (remove accents and lower case) 870 */ 871 public SortField(String name, boolean ascending, boolean normalize) 872 { 873 _name = name; 874 _ascending = ascending; 875 _normalize = normalize; 876 } 877 878 /** 879 * Get the name of the sort field 880 * @return the name of the sort field 881 */ 882 public String getName() 883 { 884 return _name; 885 } 886 887 /** 888 * Get the order for sorting results 889 * @return <code>true</code> to sort results in ascending order, <code>false</code> otherwise 890 */ 891 public boolean getAscending() 892 { 893 return _ascending; 894 } 895 896 /** 897 * Return the normalize status for this sort field 898 * @return <code>true</code> if string properties should be normalized (remove accents and lower case) 899 */ 900 public boolean getNormalize() 901 { 902 return _normalize; 903 } 904 905 } 906}