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 /** Attribute name for mention type in table refe degree */ 184 public static final String DEGREE_MENTION_TYPE = "mentionType"; 185 186 private AmetysObjectResolver _resolver; 187 188 private ContentTypeExtensionPoint _cTypeEP; 189 190 private ContentTypesHelper _cTypeHelper; 191 192 private ODFHelper _odfHelper; 193 194 @Override 195 public void service(ServiceManager manager) throws ServiceException 196 { 197 _resolver = (AmetysObjectResolver) manager.lookup(AmetysObjectResolver.ROLE); 198 _cTypeEP = (ContentTypeExtensionPoint) manager.lookup(ContentTypeExtensionPoint.ROLE); 199 _cTypeHelper = (ContentTypesHelper) manager.lookup(ContentTypesHelper.ROLE); 200 _odfHelper = (ODFHelper) manager.lookup(ODFHelper.ROLE); 201 } 202 203 /** 204 * Determines if the content type is a ODF table reference 205 * @param cTypeId The id of content type 206 * @return true if the content type is a ODF table reference 207 */ 208 public boolean isTableReference(String cTypeId) 209 { 210 return _cTypeHelper.getAncestors(cTypeId).contains(ABSTRACT_TABLE_REF); 211 } 212 213 /** 214 * Determines if the content is an entry of a ODF table reference 215 * @param content The content 216 * @return <code>true</code> if the content is an entry of a ODF table reference 217 */ 218 public boolean isTableReferenceEntry(Content content) 219 { 220 String[] cTypeIds = content.getTypes(); 221 for (String cTypeId : cTypeIds) 222 { 223 if (isTableReference(cTypeId)) 224 { 225 return true; 226 } 227 } 228 return false; 229 } 230 231 /** 232 * Get the id of table references 233 * @return The content type's id 234 */ 235 public Set<String> getTableReferenceIds() 236 { 237 Set<String> tableRefIds = new HashSet<>(); 238 239 for (String cTypeId : _cTypeEP.getExtensionsIds()) 240 { 241 if (_cTypeHelper.getAncestors(cTypeId).contains(ABSTRACT_TABLE_REF)) 242 { 243 tableRefIds.add(cTypeId); 244 } 245 } 246 return tableRefIds; 247 } 248 249 /** 250 * Get the attribute definitions for table references for a given content type 251 * @param cTypeId The id of content type 252 * @return The attribute definitions for table references 253 */ 254 public Map<String, ContentAttributeDefinition> getTableRefAttributeDefinitions(String cTypeId) 255 { 256 ContentType cType = _cTypeEP.getExtension(cTypeId); 257 return _getTableRefAttributes(cType); 258 } 259 260 private Map<String, ContentAttributeDefinition> _getTableRefAttributes(ModelItemContainer modelItemContainer) 261 { 262 Map<String, ContentAttributeDefinition> tableRefAttributes = new LinkedHashMap<>(); 263 264 for (ModelItem modelItem : modelItemContainer.getModelItems()) 265 { 266 if (modelItem instanceof ContentAttributeDefinition) 267 { 268 ContentAttributeDefinition attributeDefinition = (ContentAttributeDefinition) modelItem; 269 if (isTableReference(attributeDefinition.getContentTypeId())) 270 { 271 tableRefAttributes.put(attributeDefinition.getPath(), attributeDefinition); 272 } 273 } 274 else if (modelItem instanceof ModelItemContainer && !(modelItem instanceof RepeaterDefinition)) 275 { 276 // enumerated attributes in repeaters are not supported 277 tableRefAttributes.putAll(_getTableRefAttributes((ModelItemContainer) modelItem)); 278 } 279 } 280 281 return tableRefAttributes; 282 } 283 284 /** 285 * Get the attribute definitions for table references for a given content type and a view 286 * @param cTypeId The id of content type 287 * @param viewName the name of the view. Cannot be null. 288 * @return The attributes definitions for table references 289 */ 290 public Map<String, ContentAttributeDefinition> getTableRefAttributeDefinitions(String cTypeId, String viewName) 291 { 292 ContentType cType = _cTypeEP.getExtension(cTypeId); 293 294 View view = cType.getView(viewName); 295 return _getTableRefAttributes(view); 296 } 297 298 private Map<String, ContentAttributeDefinition> _getTableRefAttributes(ViewItemContainer viewItemContainer) 299 { 300 Map<String, ContentAttributeDefinition> tableRefAttributes = new LinkedHashMap<>(); 301 302 for (ViewItem viewItem : viewItemContainer.getViewItems()) 303 { 304 if (viewItem instanceof ViewElement) 305 { 306 ElementDefinition definition = ((ViewElement) viewItem).getDefinition(); 307 if (definition instanceof ContentAttributeDefinition) 308 { 309 tableRefAttributes.put(definition.getPath(), (ContentAttributeDefinition) definition); 310 } 311 } 312 else if (viewItem instanceof ViewItemContainer) 313 { 314 tableRefAttributes.putAll(_getTableRefAttributes((ViewItemContainer) viewItem)); 315 } 316 } 317 318 return tableRefAttributes; 319 } 320 321 /** 322 * Get the content type for mention for this degree 323 * @param degreeIds The ids of degrees 324 * @return A map with the id of content type or null if there is no mention for this degree 325 */ 326 @Callable 327 public Map<String, String> getMentionContentTypes(List<String> degreeIds) 328 { 329 Map<String, String> mentionTypes = new HashMap<>(); 330 for (String degreeId : degreeIds) 331 { 332 mentionTypes.put(degreeId, getMentionForDegree(degreeId)); 333 } 334 return mentionTypes; 335 } 336 337 /** 338 * Get the available BUT training paths for a BUT mention 339 * @param mentionId the id of BUT mention 340 * @return the BUT training paths 341 */ 342 public ContentValue[] getBUTParcoursForMention(String mentionId) 343 { 344 Content content = _resolver.resolveById(mentionId); 345 if (_cTypeHelper.isInstanceOf(content, MENTION_BUT)) 346 { 347 return content.getValue(MENTION_BUT_ATTRIBUTE_PARCOURS, false, new ContentValue[0]); 348 } 349 return new ContentValue[0]; 350 } 351 352 /** 353 * Get the available BUT training paths for a content 354 * @param contentId the content's id 355 * @param mentionId the id of mention. Can be null or empty 356 * @return the available BUT training paths 357 */ 358 @Callable 359 public List<Map<String, String>> getBUTParcoursItems(String contentId, String mentionId) 360 { 361 ContentValue[] values = null; 362 if (StringUtils.isNotEmpty(mentionId)) 363 { 364 // Get items from mention 365 values = getBUTParcoursForMention(mentionId); 366 } 367 else 368 { 369 // Get items from parent program 370 values = getBUTParcoursItems(contentId); 371 } 372 373 if (values != null) 374 { 375 return Arrays.stream(values) 376 .map(ContentValue::getContent) 377 .map(c -> Map.of("id", c.getId(), "title", c.getTitle())) 378 .collect(Collectors.toList()); 379 } 380 else 381 { 382 return List.of(); 383 } 384 } 385 /** 386 * Get the available BUT training paths for a {@link ProgramItem} 387 * @param programItemId the id of program item 388 * @return the BUT training paths 389 */ 390 public ContentValue[] getBUTParcoursItems(String programItemId) 391 { 392 Content content = _resolver.resolveById(programItemId); 393 394 // Get first parent program 395 Set<Program> parentPrograms = _odfHelper.getParentPrograms((AbstractProgram) content); 396 if (!parentPrograms.isEmpty()) 397 { 398 Program program = parentPrograms.iterator().next(); 399 400 if (isBUTDiploma(program)) 401 { 402 return Optional.ofNullable(program.<ContentValue>getValue(AbstractProgram.MENTION)) 403 .flatMap(ContentValue::getContentIfExists) 404 .map(c -> c.<ContentValue[]>getValue(MENTION_BUT_ATTRIBUTE_PARCOURS)) 405 .orElse(new ContentValue[0]); 406 407 } 408 } 409 410 // No BUT training paths 411 return new ContentValue[0]; 412 } 413 414 /** 415 * Determines if the program is a BUT diploma 416 * @param program the program 417 * @return true if the program has a BUT 418 */ 419 public boolean isBUTDiploma(Program program) 420 { 421 String mentionType = getMentionType(program); 422 return mentionType != null && MENTION_BUT.equals(mentionType); 423 } 424 425 /** 426 * Get the type of mention for a program 427 * @param program the program 428 * @return the type of mention or null if there is no mention for this program 429 */ 430 public String getMentionType(Program program) 431 { 432 return Optional.ofNullable(program.<ContentValue>getValue(AbstractProgram.DEGREE)) 433 .flatMap(ContentValue::getContentIfExists) 434 .map(c -> c.<String>getValue(DEGREE_MENTION_TYPE)) 435 .orElse(null); 436 } 437 438 /** 439 * Get the mention for a given degree. 440 * @param degreeId The degree ID 441 * @return The associated mention reference table, null if there isn't 442 */ 443 public String getMentionForDegree(String degreeId) 444 { 445 try 446 { 447 Content content = _resolver.resolveById(degreeId); 448 return content.getValue(DEGREE_MENTION_TYPE); 449 } 450 catch (UnknownAmetysObjectException e) 451 { 452 // Nothing to do 453 } 454 return null; 455 } 456 457 /** 458 * Get the CDM-fr value associated with the given code 459 * @param tableRefId The id of content type 460 * @param code The code 461 * @return The CDM-fr value or empty string if not found 462 */ 463 public String getCDMfrValue (String tableRefId, String code) 464 { 465 ContentTypeExpression cTypeExpr = new ContentTypeExpression(Operator.EQ, tableRefId); 466 StringExpression codeExpr = new StringExpression(OdfReferenceTableEntry.CODE, Operator.EQ, code); 467 468 String xpathQuery = ContentQueryHelper.getContentXPathQuery(new AndExpression(cTypeExpr, codeExpr)); 469 AmetysObjectIterable<Content> contents = _resolver.query(xpathQuery); 470 AmetysObjectIterator<Content> it = contents.iterator(); 471 472 if (it.hasNext()) 473 { 474 OdfReferenceTableEntry entry = new OdfReferenceTableEntry(it.next()); 475 return entry.getCdmValue(); 476 } 477 478 return ""; 479 } 480 481 /** 482 * Get all items of an enumeration and their label 483 * @param tableRefId The id of content type 484 * @return items of enumeration 485 */ 486 public List<OdfReferenceTableEntry> getItems (String tableRefId) 487 { 488 return getItems(tableRefId, new SortField[0]); 489 } 490 491 /** 492 * Get all items of an enumeration and their label, sorted by given fields 493 * @param tableRefId The id of content type 494 * @param sortFields The sort fields to order results 495 * @return items of enumeration 496 */ 497 public List<OdfReferenceTableEntry> getItems (String tableRefId, SortField... sortFields) 498 { 499 return getItems(tableRefId, true, sortFields); 500 } 501 502 /** 503 * Get all items of an enumeration and their label, sorted by given fields 504 * @param tableRefId The id of content type 505 * @param includeArchived <code>true</code> to include archived entries 506 * @param sortFields The sort fields to order results 507 * @return items of enumeration 508 */ 509 public List<OdfReferenceTableEntry> getItems (String tableRefId, boolean includeArchived, SortField... sortFields) 510 { 511 Expression expr = new ContentTypeExpression(Operator.EQ, tableRefId); 512 if (!includeArchived) 513 { 514 Expression notArchivedExpr = new NotExpression(new BooleanExpression(OdfReferenceTableEntry.ARCHIVED, true)); 515 expr = new AndExpression(expr, notArchivedExpr); 516 } 517 518 SortCriteria sortCriteria = new SortCriteria(); 519 for (SortField sortField : sortFields) 520 { 521 sortCriteria.addCriterion(sortField.getName(), sortField.getAscending(), sortField.getNormalize()); 522 } 523 524 String xpathQuery = ContentQueryHelper.getContentXPathQuery(expr, sortCriteria); 525 AmetysObjectIterable<Content> contents = _resolver.query(xpathQuery); 526 527 return contents.stream().map(OdfReferenceTableEntry::new).collect(Collectors.toList()); 528 } 529 530 /** 531 * Returns the label of an reference table entry 532 * @param contentId The content id 533 * @param lang The requested language of label 534 * @return the item label or <code>null</code> if not found 535 */ 536 public String getItemLabel(String contentId, String lang) 537 { 538 try 539 { 540 Content content = _resolver.resolveById(contentId); 541 OdfReferenceTableEntry entry = new OdfReferenceTableEntry(content); 542 return entry.getLabel(lang); 543 } 544 catch (UnknownAmetysObjectException e) 545 { 546 return null; 547 } 548 } 549 550 /** 551 * Returns the label of an reference table entry 552 * @param tableRefId The id of content type (useless) 553 * @param contentId The content id 554 * @param lang The requested language of label 555 * @return the item label or <code>null</code> if not found 556 * @deprecated Use {@link #getItemLabel(String, String)} instead 557 */ 558 @Deprecated 559 public String getItemLabel (String tableRefId, String contentId, String lang) 560 { 561 return getItemLabel(contentId, lang); 562 } 563 564 /** 565 * Returns the CMD value of an reference table entry 566 * @param contentId The content id 567 * @param returnCodeIfEmpty <code>true</code> to return the code if CDM-fr value is empty 568 * @return the CDM-fr value or empty value if not found 569 */ 570 public String getItemCDMfrValue(String contentId, boolean returnCodeIfEmpty) 571 { 572 if (StringUtils.isEmpty(contentId)) 573 { 574 return ""; 575 } 576 577 Content content = _resolver.resolveById(contentId); 578 OdfReferenceTableEntry entry = new OdfReferenceTableEntry(content); 579 580 String cdmValue = entry.getCdmValue(); 581 582 if (StringUtils.isEmpty(cdmValue) && returnCodeIfEmpty) 583 { 584 return entry.getCode(); 585 } 586 return cdmValue; 587 } 588 589 /** 590 * Returns the CMD value of an reference table entry 591 * @param tableRefId The id of content type (useless) 592 * @param contentId The content id 593 * @param returnCodeIfEmpty <code>true</code> to return the code if CDM-fr value is empty 594 * @return the CDM-fr value or empty value if not found 595 * @deprecated Use {@link #getItemCDMfrValue(String, boolean)} instead 596 */ 597 @Deprecated 598 public String getItemCDMfrValue (String tableRefId, String contentId, boolean returnCodeIfEmpty) 599 { 600 return getItemCDMfrValue(contentId, returnCodeIfEmpty); 601 } 602 603 /** 604 * Returns the code of an reference table entry from its CDM value 605 * @param contentId The id of content 606 * @return the code or empty value if not found 607 */ 608 public String getItemCode(String contentId) 609 { 610 if (StringUtils.isEmpty(contentId)) 611 { 612 return ""; 613 } 614 615 try 616 { 617 Content content = _resolver.resolveById(contentId); 618 OdfReferenceTableEntry entry = new OdfReferenceTableEntry(content); 619 return entry.getCode(); 620 } 621 catch (UnknownAmetysObjectException e) 622 { 623 return ""; 624 } 625 } 626 627 /** 628 * Returns the code of an reference table entry from its CDM value 629 * @param tableRefId The id of content type (useless) 630 * @param contentId The id of content 631 * @return the code or empty value if not found 632 * @deprecated Use {@link #getItemCode(String)} instead 633 */ 634 @Deprecated 635 public String getItemCode (String tableRefId, String contentId) 636 { 637 return getItemCode(contentId); 638 } 639 640 /** 641 * Returns the code of an reference table entry from its CDM value 642 * @param tableRefId The id of content type 643 * @param cdmValue The CDM-fr value 644 * @return the code or <code>null</code> if not found 645 */ 646 public String getItemCodeFromCDM (String tableRefId, String cdmValue) 647 { 648 ContentTypeExpression cTypeExpr = _getContentTypeExpression(tableRefId); 649 StringExpression codeExpr = new StringExpression(OdfReferenceTableEntry.CDM_VALUE, Operator.EQ, cdmValue); 650 651 String xpathQuery = ContentQueryHelper.getContentXPathQuery(new AndExpression(cTypeExpr, codeExpr)); 652 AmetysObjectIterable<Content> contents = _resolver.query(xpathQuery); 653 AmetysObjectIterator<Content> it = contents.iterator(); 654 655 if (it.hasNext()) 656 { 657 OdfReferenceTableEntry entry = new OdfReferenceTableEntry(it.next()); 658 return entry.getCode(); 659 } 660 return null; 661 } 662 663 /** 664 * Returns the entry of an reference table entry from its cdmValue 665 * @param tableRefId The id of content type 666 * @param cdmValue The CDM-fr value 667 * @return the entry or <code>null</code> if not found 668 */ 669 public OdfReferenceTableEntry getItemFromCDM(String tableRefId, String cdmValue) 670 { 671 ContentTypeExpression cTypeExpr = _getContentTypeExpression(tableRefId); 672 StringExpression cdmExpr = new StringExpression(OdfReferenceTableEntry.CDM_VALUE, Operator.EQ, cdmValue); 673 674 String xpathQuery = ContentQueryHelper.getContentXPathQuery(new AndExpression(cTypeExpr, cdmExpr)); 675 676 return _resolver.<Content>query(xpathQuery).stream() 677 .findFirst() 678 .map(OdfReferenceTableEntry::new) 679 .orElse(null); 680 } 681 682 /** 683 * Returns the entry of an reference table entry from its code 684 * @param tableRefId The id of content type 685 * @param code The code 686 * @return the entry or <code>null</code> if not found 687 */ 688 public OdfReferenceTableEntry getItemFromCode(String tableRefId, String code) 689 { 690 ContentTypeExpression cTypeExpr = _getContentTypeExpression(tableRefId); 691 StringExpression codeExpr = new StringExpression(OdfReferenceTableEntry.CODE, Operator.EQ, code); 692 693 String xpathQuery = ContentQueryHelper.getContentXPathQuery(new AndExpression(cTypeExpr, codeExpr)); 694 695 return _resolver.<Content>query(xpathQuery).stream() 696 .findFirst() 697 .map(OdfReferenceTableEntry::new) 698 .orElse(null); 699 } 700 701 /** 702 * Returns the entry of a reference table entry from its code for the connector (Apogée, Pégase...) 703 * @param tableRefId The id of content type 704 * @param connectorCode The code 705 * @param codeFieldName The field name containing the connector code 706 * @return the entry or <code>null</code> if not found 707 */ 708 public OdfReferenceTableEntry getItemFromConnector(String tableRefId, String connectorCode, String codeFieldName) 709 { 710 ContentTypeExpression cTypeExpr = _getContentTypeExpression(tableRefId); 711 StringExpression cdmExpr = new StringExpression(codeFieldName, Operator.EQ, connectorCode); 712 713 String xpathQuery = ContentQueryHelper.getContentXPathQuery(new AndExpression(cTypeExpr, cdmExpr)); 714 715 return _resolver.<Content>query(xpathQuery).stream() 716 .findFirst() 717 .map(OdfReferenceTableEntry::new) 718 .orElse(null); 719 } 720 721 private ContentTypeExpression _getContentTypeExpression(String tableRefId) 722 { 723 Set<String> tableRefids; 724 if (tableRefId.equals(OdfReferenceTableHelper.ABSTRACT_MENTION)) 725 { 726 tableRefids = _cTypeEP.getSubTypes(tableRefId); 727 } 728 else 729 { 730 tableRefids = Collections.singleton(tableRefId); 731 } 732 733 return new ContentTypeExpression(Operator.EQ, tableRefids.toArray(new String[tableRefids.size()])); 734 } 735 736 /** 737 * Returns the reference table entry from its CDM value 738 * @param contentId The id of content 739 * @return the item as an {@link OdfReferenceTableEntry} or null if not found 740 */ 741 public OdfReferenceTableEntry getItem(String contentId) 742 { 743 try 744 { 745 Content content = _resolver.resolveById(contentId); 746 return new OdfReferenceTableEntry(content); 747 } 748 catch (UnknownAmetysObjectException e) 749 { 750 // Can be an empty ID or an invalid ID (workspace or simply deleted element) 751 return null; 752 } 753 } 754 755 /** 756 * SAX items of a reference table 757 * @param contentHandler The content handler to sax into 758 * @param tableRefId The id of reference table 759 * @throws SAXException if an error occurred while saxing 760 */ 761 public void saxItems (ContentHandler contentHandler, String tableRefId) throws SAXException 762 { 763 saxItems(contentHandler, tableRefId, null); 764 } 765 766 /** 767 * SAX items of a reference table 768 * @param contentHandler the content handler to sax into 769 * @param attributeDefinition the metadata definition 770 * @throws SAXException if an error occurs while saxing 771 */ 772 public void saxItems (ContentHandler contentHandler, ContentAttributeDefinition attributeDefinition) throws SAXException 773 { 774 saxItems(contentHandler, attributeDefinition, null); 775 } 776 777 /** 778 * SAX items of a reference table 779 * @param contentHandler The content handler to sax into 780 * @param tableRefId The id of reference table 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 occurred while saxing 783 */ 784 public void saxItems (ContentHandler contentHandler, String tableRefId, String lang) throws SAXException 785 { 786 _saxItems(contentHandler, new AttributesImpl(), tableRefId, lang); 787 } 788 789 /** 790 * SAX items of a reference table 791 * @param contentHandler the content handler to sax into 792 * @param attributeDefinition the metadata definition 793 * @param lang the language to use to display items, can be <code>null</code> then odf language is used 794 * @throws SAXException if an error occurs while saxing 795 */ 796 public void saxItems(ContentHandler contentHandler, ContentAttributeDefinition attributeDefinition, String lang) throws SAXException 797 { 798 String cTypeId = attributeDefinition.getContentTypeId(); 799 if (cTypeId.startsWith("odf-enumeration.")) 800 { 801 AttributesImpl attrs = new AttributesImpl(); 802 attrs.addCDATAAttribute("metadataName", attributeDefinition.getName()); 803 attrs.addCDATAAttribute("metadataPath", attributeDefinition.getPath()); 804 805 _saxItems(contentHandler, attrs, cTypeId, lang); 806 } 807 } 808 809 private void _saxItems(ContentHandler contentHandler, AttributesImpl rootAttrs, String tableRefId, String lang) throws SAXException 810 { 811 String langToUse = lang != null ? lang : Config.getInstance().getValue("odf.programs.lang"); 812 boolean hasShortLabel = _cTypeEP.getExtension(tableRefId).hasModelItem("shortLabel"); 813 814 rootAttrs.addCDATAAttribute("contentTypeId", tableRefId); 815 XMLUtils.startElement(contentHandler, "items", rootAttrs); 816 817 List<OdfReferenceTableEntry> entries = getItems(tableRefId); 818 for (OdfReferenceTableEntry entry : entries) 819 { 820 AttributesImpl valueAttrs = new AttributesImpl(); 821 valueAttrs.addCDATAAttribute("id", entry.getId()); 822 valueAttrs.addCDATAAttribute("order", entry.getOrder().toString()); 823 valueAttrs.addCDATAAttribute("code", entry.getCode()); 824 valueAttrs.addCDATAAttribute("cdmValue", entry.getCdmValue()); 825 valueAttrs.addCDATAAttribute("archived", entry.isArchived().toString()); 826 if (hasShortLabel) 827 { 828 valueAttrs.addCDATAAttribute("shortLabel", entry.getContent().getValue("shortLabel", false, StringUtils.EMPTY)); 829 } 830 831 XMLUtils.createElement(contentHandler, "item", valueAttrs, entry.getLabel(langToUse)); 832 } 833 834 XMLUtils.endElement(contentHandler, "items"); 835 } 836 837 /** 838 * This class represents a sort field for reference table. 839 * 840 */ 841 public static final class SortField 842 { 843 private String _name; 844 private boolean _ascending; 845 private boolean _normalize; 846 847 /** 848 * Create a sort field 849 * @param name the name of field to sort on 850 * @param ascending <code>true</code> to sort in ascending order, <code>false</code> otherwise 851 */ 852 public SortField(String name, boolean ascending) 853 { 854 this(name, ascending, false); 855 } 856 857 /** 858 * Create a sort field 859 * @param name the name of field to sort on 860 * @param ascending <code>true</code> to sort in ascending order, <code>false</code> otherwise 861 * @param normalize <code>true</code> to normalize string properties (remove accents and lower case) 862 */ 863 public SortField(String name, boolean ascending, boolean normalize) 864 { 865 _name = name; 866 _ascending = ascending; 867 _normalize = normalize; 868 } 869 870 /** 871 * Get the name of the sort field 872 * @return the name of the sort field 873 */ 874 public String getName() 875 { 876 return _name; 877 } 878 879 /** 880 * Get the order for sorting results 881 * @return <code>true</code> to sort results in ascending order, <code>false</code> otherwise 882 */ 883 public boolean getAscending() 884 { 885 return _ascending; 886 } 887 888 /** 889 * Return the normalize status for this sort field 890 * @return <code>true</code> if string properties should be normalized (remove accents and lower case) 891 */ 892 public boolean getNormalize() 893 { 894 return _normalize; 895 } 896 897 } 898}