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