001/* 002 * Copyright 2012 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.plugins.odfweb.repository; 017 018import java.util.Arrays; 019import java.util.HashMap; 020import java.util.HashSet; 021import java.util.Iterator; 022import java.util.List; 023import java.util.Map; 024import java.util.Set; 025import java.util.stream.Collectors; 026 027import javax.jcr.Node; 028import javax.jcr.RepositoryException; 029import javax.jcr.Value; 030 031import org.apache.avalon.framework.activity.Initializable; 032import org.apache.avalon.framework.component.Component; 033import org.apache.avalon.framework.service.ServiceException; 034import org.apache.avalon.framework.service.ServiceManager; 035import org.apache.avalon.framework.service.Serviceable; 036import org.apache.commons.lang3.StringUtils; 037 038import org.ametys.cms.FilterNameHelper; 039import org.ametys.cms.content.ContentHelper; 040import org.ametys.cms.contenttype.ContentTypeExtensionPoint; 041import org.ametys.cms.contenttype.ContentTypesHelper; 042import org.ametys.cms.contenttype.MetadataDefinition; 043import org.ametys.core.ui.Callable; 044import org.ametys.core.util.I18nUtils; 045import org.ametys.odf.ProgramItem; 046import org.ametys.odf.catalog.CatalogsManager; 047import org.ametys.odf.course.Course; 048import org.ametys.odf.enumeration.OdfReferenceTableHelper; 049import org.ametys.odf.orgunit.RootOrgUnitProvider; 050import org.ametys.odf.program.AbstractProgram; 051import org.ametys.odf.program.Program; 052import org.ametys.odf.tree.OdfClassificationHandler; 053import org.ametys.plugins.odfweb.restrictions.OdfProgramRestriction; 054import org.ametys.plugins.odfweb.restrictions.OdfProgramRestrictionManager; 055import org.ametys.plugins.repository.AmetysObjectIterable; 056import org.ametys.plugins.repository.AmetysObjectResolver; 057import org.ametys.plugins.repository.AmetysRepositoryException; 058import org.ametys.plugins.repository.jcr.JCRAmetysObject; 059import org.ametys.plugins.repository.provider.WorkspaceSelector; 060import org.ametys.plugins.repository.query.expression.Expression; 061import org.ametys.plugins.repository.query.expression.VirtualFactoryExpression; 062import org.ametys.runtime.i18n.I18nizableText; 063import org.ametys.runtime.plugin.component.AbstractLogEnabled; 064import org.ametys.web.repository.page.Page; 065import org.ametys.web.repository.page.PageQueryHelper; 066import org.ametys.web.repository.site.Site; 067import org.ametys.web.repository.sitemap.Sitemap; 068 069import com.google.common.collect.ImmutableList; 070 071/** 072 * Component providing methods to retrieve ODF virtual pages, such as the ODF root, 073 * level 1 and 2 metadata names, and so on. 074 */ 075public class OdfPageHandler extends AbstractLogEnabled implements Component, Initializable, Serviceable 076{ 077 /** The avalon role. */ 078 public static final String ROLE = OdfPageHandler.class.getName(); 079 080 /** First level metadata name. */ 081 public static final String LEVEL1_METADATA_NAME = "firstLevel"; 082 083 /** Second level metadata name. */ 084 public static final String LEVEL2_METADATA_NAME = "secondLevel"; 085 086 /** Catalog metadata name. */ 087 public static final String CATALOG_METADATA_NAME = "odf-root-catalog"; 088 089 /** Content types that are not eligible for first and second level */ 090 // See ODF-1115 Exclude the mentions enumerator from the list : 091 protected static final List<String> NON_ELIGIBLE_CTYPES_FOR_LEVEL = Arrays.asList("org.ametys.plugins.odf.Content.programItem", "odf-enumeration.Mention"); 092 093 /** The ametys object resolver. */ 094 protected AmetysObjectResolver _resolver; 095 096 /** The i18n utils. */ 097 protected I18nUtils _i18nUtils; 098 099 /** The content type extension point. */ 100 protected ContentTypeExtensionPoint _cTypeEP; 101 102 /** The ODF Catalog enumeration */ 103 protected CatalogsManager _catalogsManager; 104 105 /** The workspace selector. */ 106 protected WorkspaceSelector _workspaceSelector; 107 108 /** The ODF root pages, indexed by workspace, site and sitemap name. */ 109 protected Map<String, Map<String, Map<String, Set<String>>>> _odfRootPages; 110 111 /** For each site, indicate if an ODF root is present. */ 112 protected Map<String, Map<String, Boolean>> _hasOdfRoot; 113 114 /** Avalon service manager */ 115 protected ServiceManager _manager; 116 117 /** Restriction manager */ 118 protected OdfProgramRestrictionManager _odfRestrictionsManager; 119 120 /** Content types helper */ 121 protected ContentTypesHelper _contentTypesHelper; 122 123 /** Content helper */ 124 protected ContentHelper _contentHelper; 125 126 /** Odf reference table helper */ 127 protected OdfReferenceTableHelper _odfReferenceTableHelper; 128 129 /** Root orgunit provider */ 130 protected RootOrgUnitProvider _orgUnitProvider; 131 132 /** Root orgunit provider */ 133 protected OdfClassificationHandler _odfClassificationHandler; 134 135 @Override 136 public void service(ServiceManager serviceManager) throws ServiceException 137 { 138 _manager = serviceManager; 139 _resolver = (AmetysObjectResolver) serviceManager.lookup(AmetysObjectResolver.ROLE); 140 _i18nUtils = (I18nUtils) serviceManager.lookup(I18nUtils.ROLE); 141 _cTypeEP = (ContentTypeExtensionPoint) serviceManager.lookup(ContentTypeExtensionPoint.ROLE); 142 _workspaceSelector = (WorkspaceSelector) serviceManager.lookup(WorkspaceSelector.ROLE); 143 _catalogsManager = (CatalogsManager) serviceManager.lookup(CatalogsManager.ROLE); 144 _odfRestrictionsManager = (OdfProgramRestrictionManager) serviceManager.lookup(OdfProgramRestrictionManager.ROLE); 145 _contentTypesHelper = (ContentTypesHelper) serviceManager.lookup(ContentTypesHelper.ROLE); 146 _contentHelper = (ContentHelper) serviceManager.lookup(ContentHelper.ROLE); 147 _odfReferenceTableHelper = (OdfReferenceTableHelper) serviceManager.lookup(OdfReferenceTableHelper.ROLE); 148 _orgUnitProvider = (RootOrgUnitProvider) serviceManager.lookup(RootOrgUnitProvider.ROLE); 149 _odfClassificationHandler = (OdfClassificationHandler) serviceManager.lookup(OdfClassificationHandler.ROLE); 150 } 151 152 @Override 153 public void initialize() throws Exception 154 { 155 _odfRootPages = new HashMap<>(); 156 _hasOdfRoot = new HashMap<>(); 157 } 158 159 /** 160 * Get the first ODF root page. 161 * @param siteName The site name 162 * @param sitemapName The sitemap's name 163 * @return a ODF root page or null if not found. 164 * @throws AmetysRepositoryException if an error occurs 165 */ 166 public Page getOdfRootPage(String siteName, String sitemapName) throws AmetysRepositoryException 167 { 168 Set<Page> rootPages = getOdfRootPages(siteName, sitemapName); 169 return rootPages.isEmpty() ? null : rootPages.iterator().next(); 170 } 171 172 /** 173 * Get ODF root page of a specific catalog. 174 * @param siteName The site name 175 * @param sitemapName The sitemap name 176 * @param catalogName The catalog name 177 * @return the ODF root page or null if not found. 178 * @throws AmetysRepositoryException if an error occurs 179 */ 180 public Page getOdfRootPage(String siteName, String sitemapName, String catalogName) throws AmetysRepositoryException 181 { 182 String catalogToCompare = catalogName != null ? catalogName : ""; 183 184 for (Page odfRootPage : getOdfRootPages(siteName, sitemapName)) 185 { 186 if (catalogToCompare.equals(getCatalog(odfRootPage))) 187 { 188 return odfRootPage; 189 } 190 } 191 192 return null; 193 } 194 195 /** 196 * Get the id of ODF root pages 197 * @param siteName The site name 198 * @param sitemapName The sitemap name 199 * @return The ids of ODF root pages 200 * @throws AmetysRepositoryException if an error occurs. 201 */ 202 @Callable 203 public List<String> getOdfRootPageIds(String siteName, String sitemapName) throws AmetysRepositoryException 204 { 205 Set<Page> pages = getOdfRootPages(siteName, sitemapName); 206 return pages.stream().map(p -> p.getId()).collect(Collectors.toList()); 207 } 208 209 /** 210 * Get the ODF root pages. 211 * @param siteName the current site. 212 * @param sitemapName the current sitemap/language. 213 * @return the ODF root pages 214 * @throws AmetysRepositoryException if an error occurs. 215 */ 216 public Set<Page> getOdfRootPages(String siteName, String sitemapName) throws AmetysRepositoryException 217 { 218 Set<Page> rootPages = new HashSet<>(); 219 220 String workspace = _workspaceSelector.getWorkspace(); 221 222 Map<String, Map<String, Set<String>>> wspOdfRootPages = null; 223 if (_odfRootPages.containsKey(workspace)) 224 { 225 wspOdfRootPages = _odfRootPages.get(workspace); 226 } 227 else 228 { 229 wspOdfRootPages = new HashMap<>(); 230 _odfRootPages.put(workspace, wspOdfRootPages); 231 } 232 233 Map<String, Set<String>> siteOdfRootPages = null; 234 235 if (wspOdfRootPages.containsKey(siteName)) 236 { 237 siteOdfRootPages = wspOdfRootPages.get(siteName); 238 } 239 else 240 { 241 siteOdfRootPages = new HashMap<>(); 242 wspOdfRootPages.put(siteName, siteOdfRootPages); 243 } 244 245 if (siteOdfRootPages.containsKey(sitemapName)) 246 { 247 Set<String> odfRootPageIds = siteOdfRootPages.get(sitemapName); 248 if (odfRootPageIds != null) 249 { 250 for (String pageId : odfRootPageIds) 251 { 252 rootPages.add((Page) _resolver.resolveById(pageId)); 253 } 254 } 255 } 256 else 257 { 258 rootPages = _getOdfRootPages(siteName, sitemapName); 259 Set<String> odfRootPageIds = new HashSet<>(); 260 for (Page rootPage : rootPages) 261 { 262 odfRootPageIds.add(rootPage.getId()); 263 } 264 siteOdfRootPages.put(sitemapName, odfRootPageIds); 265 } 266 267 return rootPages; 268 } 269 270 /** 271 * Test if the given site has at least one sitemap with an odf root page. 272 * @param site the site to test. 273 * @return true if the site has at least one sitemap with an odf root page, false otherwise. 274 */ 275 public boolean hasOdfRootPage(Site site) 276 { 277 boolean hasOneRoot = false; 278 279 String workspace = _workspaceSelector.getWorkspace(); 280 String siteName = site.getName(); 281 282 Map<String, Boolean> wspHasOneRoot = null; 283 if (_hasOdfRoot.containsKey(workspace)) 284 { 285 wspHasOneRoot = _hasOdfRoot.get(workspace); 286 } 287 else 288 { 289 wspHasOneRoot = new HashMap<>(); 290 _hasOdfRoot.put(workspace, wspHasOneRoot); 291 } 292 293 294 if (wspHasOneRoot.containsKey(siteName)) 295 { 296 hasOneRoot = wspHasOneRoot.get(siteName); 297 } 298 else 299 { 300 Iterator<Sitemap> sitemaps = site.getSitemaps().iterator(); 301 302 while (sitemaps.hasNext() && !hasOneRoot) 303 { 304 String sitemapName = sitemaps.next().getName(); 305 306 if (!getOdfRootPages(site.getName(), sitemapName).isEmpty()) 307 { 308 hasOneRoot = true; 309 } 310 } 311 312 wspHasOneRoot.put(siteName, hasOneRoot); 313 } 314 315 return hasOneRoot; 316 } 317 318 /** 319 * Determines if the program is part of the site restrictions 320 * @param rootPage The ODF root page 321 * @param program The program 322 * @return <code>true</code> the program is part of the site restrictions 323 */ 324 public boolean isValidRestriction(Page rootPage, Program program) 325 { 326 // Check catalog 327 if (!program.getCatalog().equals(getCatalog(rootPage))) 328 { 329 return false; 330 } 331 332 // Check language 333 if (!program.getLanguage().equals(rootPage.getSitemapName())) 334 { 335 return false; 336 } 337 338 // Check site restrictions 339 OdfProgramRestriction restriction = _odfRestrictionsManager.getRestriction(rootPage); 340 if (restriction != null) 341 { 342 return restriction.contains(program); 343 } 344 345 return true; 346 } 347 348 /** 349 * Clear the ODF root page cache. 350 */ 351 public void clearRootCache() 352 { 353 _odfRootPages = new HashMap<>(); 354 _hasOdfRoot = new HashMap<>(); 355 } 356 357 /** 358 * Clear the ODF root page cache for a given site and language. 359 * @param siteName the current site. 360 * @param sitemapName the current sitemap/language. 361 */ 362 public void clearRootCache(String siteName, String sitemapName) 363 { 364 if (_odfRootPages.containsKey(siteName)) 365 { 366 _odfRootPages.get(siteName).remove(sitemapName); 367 } 368 369 _hasOdfRoot.remove(siteName); 370 } 371 372 /** 373 * Determines if the page is a ODF root page 374 * @param page The page to test 375 * @return true if the page is a ODF root page 376 */ 377 public boolean isODFRootPage (Page page) 378 { 379 if (page instanceof JCRAmetysObject) 380 { 381 try 382 { 383 JCRAmetysObject jcrPage = (JCRAmetysObject) page; 384 Node node = jcrPage.getNode(); 385 386 if (node.hasProperty(AmetysObjectResolver.VIRTUAL_PROPERTY)) 387 { 388 Value[] values = node.getProperty(AmetysObjectResolver.VIRTUAL_PROPERTY).getValues(); 389 390 boolean hasValue = false; 391 for (int i = 0; i < values.length && !hasValue; i++) 392 { 393 hasValue = FirstLevelPageFactory.class.getName().equals(values[i].getString()); 394 } 395 396 return hasValue; 397 } 398 else 399 { 400 return false; 401 } 402 } 403 catch (RepositoryException e) 404 { 405 return false; 406 } 407 } 408 409 return false; 410 411 } 412 413 /** 414 * Get the ODF root page. 415 * @param siteName the current site. 416 * @param sitemapName the current sitemap/language. 417 * @return the ODF root page or null if not found. 418 * @throws AmetysRepositoryException if an error occurs. 419 */ 420 protected Page _getOdfRootPage(String siteName, String sitemapName) throws AmetysRepositoryException 421 { 422 Expression expression = new VirtualFactoryExpression(FirstLevelPageFactory.class.getName()); 423 String query = PageQueryHelper.getPageXPathQuery(siteName, sitemapName, null, expression, null); 424 425 AmetysObjectIterable<Page> pages = _resolver.query(query); 426 Page page = pages.stream().findFirst().orElse(null); 427 428 return page; 429 } 430 431 /** 432 * Get the ODF root page. 433 * @param siteName the current site. 434 * @param sitemapName the current sitemap/language. 435 * @return the ODF root page or null if not found. 436 * @throws AmetysRepositoryException if an error occurs. 437 */ 438 protected Set<Page> _getOdfRootPages(String siteName, String sitemapName) throws AmetysRepositoryException 439 { 440 Expression expression = new VirtualFactoryExpression(FirstLevelPageFactory.class.getName()); 441 String query = PageQueryHelper.getPageXPathQuery(siteName, sitemapName, null, expression, null); 442 443 return _resolver.<Page>query(query).stream().collect(Collectors.toSet()); 444 } 445 446 /** 447 * Get the catalog value of the ODF root page 448 * @param rootPage The ODF root page 449 * @return the catalog value 450 */ 451 public String getCatalog (Page rootPage) 452 { 453 return rootPage.getValue(CATALOG_METADATA_NAME, StringUtils.EMPTY); 454 } 455 456 /** 457 * Get the first level metadata name. 458 * @param siteName the site name. 459 * @param sitemapName the sitemap name. 460 * @param catalog the current selected catalog. 461 * @return the first level metadata name. 462 */ 463 public String getLevel1Metadata(String siteName, String sitemapName, String catalog) 464 { 465 Page rootPage = getOdfRootPage(siteName, sitemapName, catalog); 466 467 return getLevel1Metadata(rootPage); 468 } 469 470 /** 471 * Get the first level metadata name. 472 * @param rootPage the ODF root page. 473 * @return the first level metadata name. 474 */ 475 public String getLevel1Metadata(Page rootPage) 476 { 477 return rootPage.getValue(LEVEL1_METADATA_NAME); 478 } 479 480 /** 481 * Get the second level metadata name. 482 * @param siteName the site name. 483 * @param sitemapName the sitemap name. 484 * @param catalog the current selected catalog. 485 * @return the second level metadata name. 486 */ 487 public String getLevel2Metadata(String siteName, String sitemapName, String catalog) 488 { 489 Page rootPage = getOdfRootPage(siteName, sitemapName, catalog); 490 491 return getLevel2Metadata(rootPage); 492 } 493 494 /** 495 * Get the second level metadata name. 496 * @param rootPage the ODF root page. 497 * @return the second level metadata name. 498 */ 499 public String getLevel2Metadata(Page rootPage) 500 { 501 return rootPage.getValue(LEVEL2_METADATA_NAME); 502 } 503 504 /** 505 * Get the first level metadata values (with translated label). 506 * @param siteName the site name. 507 * @param sitemapName the sitemap name. 508 * @param catalog the current selected catalog. 509 * @return the first level metadata values. 510 */ 511 public Map<String, String> getLevel1Values(String siteName, String sitemapName, String catalog) 512 { 513 Page rootPage = getOdfRootPage(siteName, sitemapName, catalog); 514 515 return getLevel1Values(rootPage); 516 } 517 518 /** 519 * Get the level value of a program by extracting and transforming the raw program value at the desired metadata path 520 * @param program The program 521 * @param levelMetaPath The desired metadata path that represent a level 522 * @return The final level value 523 */ 524 public String getProgramLevelValue(Program program, String levelMetaPath) 525 { 526 List<String> programLevelValue = _odfClassificationHandler.getProgramLevelValues(program, levelMetaPath); 527 return programLevelValue.isEmpty() ? null : programLevelValue.get(0); 528 } 529 530 /** 531 * Get the first level value of a program by extracting and transforming the raw program value 532 * @param rootPage The root page 533 * @param program The program 534 * @return The final level value or <code>null</code> if not found 535 */ 536 public String getProgramLevel1Value(Page rootPage, Program program) 537 { 538 String level1Metadata = getLevel1Metadata(rootPage); 539 if (StringUtils.isNotBlank(level1Metadata)) 540 { 541 List<String> programLevelValue = _odfClassificationHandler.getProgramLevelValues(program, level1Metadata); 542 return programLevelValue.isEmpty() ? null : programLevelValue.get(0); 543 } 544 else 545 { 546 return null; 547 } 548 } 549 550 /** 551 * Get the second level value of a program by extracting and transforming the raw program value 552 * @param rootPage The root page 553 * @param program The program 554 * @return The final level value or <code>null</code> if not found 555 */ 556 public String getProgramLevel2Value(Page rootPage, Program program) 557 { 558 String level2Metadata = getLevel2Metadata(rootPage); 559 if (StringUtils.isNotBlank(level2Metadata)) 560 { 561 List<String> programLevelValue = _odfClassificationHandler.getProgramLevelValues(program, level2Metadata); 562 return programLevelValue.isEmpty() ? null : programLevelValue.get(0); 563 } 564 else 565 { 566 return null; 567 } 568 } 569 570 /** 571 * Get the name of the page of first level for a given program 572 * @param rootPage The ODF root page 573 * @param program The program 574 * @return The page's name 575 */ 576 public String getLevel1PageName(Page rootPage, Program program) 577 { 578 String value = getProgramLevel1Value(rootPage, program); 579 return value != null ? FilterNameHelper.filterName(value) + "-" + encodeLevelValue(value) : ""; 580 } 581 582 /** 583 * Get the name of the page of second level for a given program 584 * @param rootPage The ODF root page 585 * @param program The program 586 * @return The page's name 587 */ 588 public String getLevel2PageName(Page rootPage, Program program) 589 { 590 String value = getProgramLevel2Value(rootPage, program); 591 return value != null ? FilterNameHelper.filterName(value) + "-" + encodeLevelValue(value) : ""; 592 } 593 594 /** 595 * Get the orgunit identifier given an uai code 596 * @param rootPage Odf root page 597 * @param uaiCode The uai code 598 * @return The orgunit id or null if not found 599 */ 600 public String getOrgunitIdFromUaiCode(Page rootPage, String uaiCode) 601 { 602 return _odfClassificationHandler.getOrgunitIdFromUaiCode(rootPage.getSitemapName(), uaiCode); 603 } 604 605 /** 606 * Get the programs available for a ODF root page, taking account the site's restrictions 607 * @param rootPage The ODF root page 608 * @param level1 filters results with a level1 value. Can be null. 609 * @param level2 filters results with a level2 value. Can be null. 610 * @param programCode expected program code. Can be null. 611 * @param programName expected program name. Can be null. 612 * @return an iterator over resulting programs 613 */ 614 public AmetysObjectIterable<Program> getProgramsWithRestrictions(Page rootPage, String level1, String level2, String programCode, String programName) 615 { 616 return getProgramsWithRestrictions(rootPage, getLevel1Metadata(rootPage), level1, getLevel2Metadata(rootPage), level2, programCode, programName); 617 } 618 619 /** 620 * Get the programs available for a ODF root page, taking account the site's restrictions 621 * @param rootPage The ODF root page 622 * @param level1Metadata metadata name for first level 623 * @param level1 filters results with a level1 value. Can be null. 624 * @param level2Metadata metadata name for second level 625 * @param level2 filters results with a level2 value. Can be null. 626 * @param programCode expected program code. Can be null. 627 * @param programName expected program name. Can be null. 628 * @return an iterator over resulting programs 629 */ 630 public AmetysObjectIterable<Program> getProgramsWithRestrictions(Page rootPage, String level1Metadata, String level1, String level2Metadata, String level2, String programCode, String programName) 631 { 632 OdfProgramRestriction restriction = _odfRestrictionsManager.getRestriction(rootPage); 633 return _odfClassificationHandler.getPrograms(getCatalog(rootPage), rootPage.getSitemapName(), level1Metadata, level1, level2Metadata, level2, programCode, programName, restriction == null ? null : ImmutableList.of(restriction.getExpression())); 634 } 635 636 /** 637 * Get the first level metadata values (with translated label). 638 * @param rootPage the ODF root page. 639 * @return the first level metadata values. 640 */ 641 public Map<String, String> getLevel1Values(Page rootPage) 642 { 643 return _odfClassificationHandler.getLevelValues(getLevel1Metadata(rootPage), rootPage.getSitemapName()); 644 } 645 646 /** 647 * Get the second level metadata values (with translated label). 648 * @param siteName the site name. 649 * @param sitemapName the sitemap name. 650 * @param catalog the current selected catalog. 651 * @return the second level metadata values. 652 */ 653 public Map<String, String> getLevel2Values(String siteName, String sitemapName, String catalog) 654 { 655 Page rootPage = getOdfRootPage(siteName, sitemapName, catalog); 656 657 return getLevel2Values(rootPage); 658 } 659 660 /** 661 * Get the second level metadata values (with translated label). 662 * @param rootPage the ODF root page. 663 * @return the second level metadata values. 664 */ 665 public Map<String, String> getLevel2Values(Page rootPage) 666 { 667 return _odfClassificationHandler.getLevelValues(getLevel2Metadata(rootPage), rootPage.getSitemapName()); 668 } 669 670 /** 671 * Encode level value to be use into a URI. 672 * Double-encode characters ':', '-' and '/'. 673 * @param value The raw value 674 * @return the encoded value 675 */ 676 public String encodeLevelValue (String value) 677 { 678 return _odfClassificationHandler.encodeLevelValue(value); 679 } 680 681 /** 682 * Decode level value used in a URI 683 * @param value The encoded value 684 * @return the decoded value 685 */ 686 public String decodeLevelValue (String value) 687 { 688 return _odfClassificationHandler.decodeLevelValue(value); 689 } 690 691 /** 692 * Returns the page's name of a {@link ProgramItem}. 693 * Only {@link AbstractProgram} and {@link Course} can have a page. 694 * @param item The program item 695 * @return The page's name 696 * @throws IllegalArgumentException if the program item is not a {@link AbstractProgram} nor a {@link Course}. 697 */ 698 public String getPageName (ProgramItem item) 699 { 700 if (item instanceof AbstractProgram) 701 { 702 // E.g: licence-lea-anglais-allemand-H7AIIUYW 703 return FilterNameHelper.filterName(((AbstractProgram) item).getTitle()) + "-" + item.getCode(); 704 } 705 else if (item instanceof Course) 706 { 707 // E.g: langue-anglaise-1-h6yp1p98 708 return FilterNameHelper.filterName(((Course) item).getTitle()) + "-" + item.getCode(); 709 } 710 else 711 { 712 throw new IllegalArgumentException("Illegal program item : no page can be associated for a program item of type " + item.getClass().getName()); 713 } 714 } 715 716 /** 717 * Get the eligible enumerated metadata for ODF page level 718 * @return the eligible metadata definition 719 */ 720 public Map<String, MetadataDefinition> getEligibleMetadataForLevel() 721 { 722 return _odfClassificationHandler.getEligibleMetadataForLevel(); 723 } 724 725 /** 726 * Get the ODF catalogs 727 * @return the ODF catalogs 728 */ 729 public Map<String, I18nizableText> getCatalogs() 730 { 731 return _odfClassificationHandler.getCatalogs(); 732 } 733 734 /** 735 * Get the enumerated metadata definition for the given content type. 736 * Metadata with enumerator or content metadata are considered as enumrated 737 * @param programContentTypeId The content type's id 738 * @param allowMultiple <code>true</code> true to allow multiple metadata 739 * @return The definition of enumerated metadata 740 */ 741 public Map<String, MetadataDefinition> getEnumeratedMetadata(String programContentTypeId, boolean allowMultiple) 742 { 743 return _odfClassificationHandler.getEnumeratedMetadata(programContentTypeId, allowMultiple); 744 } 745 746 /** 747 * Compute the path from the root odf page, representing the first and second level pages. 748 * @param rootPage The odf root page 749 * @param parentProgram The program to compute 750 * @return the path 751 */ 752 public String computeLevelsPath(Page rootPage, Program parentProgram) 753 { 754 755 String level1 = getProgramLevel1Value(rootPage, parentProgram); 756 String level2 = getProgramLevel2Value(rootPage, parentProgram); 757 758 if (StringUtils.isNotBlank(level2)) 759 { 760 // The path is no more valid, re-calculate the real path 761 String secondLevelPageId = "odfLevel2://" + level1 + "/" + level2 + "?rootId=" + rootPage.getId(); 762 Page secondLevelPage = _resolver.resolveById(secondLevelPageId); 763 764 return secondLevelPage.getParent().getName() + "/" + secondLevelPage.getName(); 765 } 766 else if (StringUtils.isNotBlank(level1)) 767 { 768 // The path is no more valid, re-calculate the real path 769 String firstLevelPageId = "odfLevel1://" + level1 + "?rootId=" + rootPage.getId(); 770 Page firstLevelPage = _resolver.resolveById(firstLevelPageId); 771 772 return firstLevelPage.getName(); 773 } 774 else 775 { 776 return StringUtils.EMPTY; 777 } 778 779 } 780}