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