001/* 002 * Copyright 2010 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.web.repository.page.jcr; 017 018import java.io.IOException; 019import java.util.ArrayList; 020import java.util.Collection; 021import java.util.Collections; 022import java.util.HashSet; 023import java.util.List; 024import java.util.Locale; 025import java.util.NoSuchElementException; 026import java.util.Optional; 027import java.util.Set; 028 029import javax.jcr.ItemExistsException; 030import javax.jcr.Node; 031import javax.jcr.RepositoryException; 032import javax.jcr.Value; 033 034import org.apache.commons.collections4.MapUtils; 035import org.apache.commons.lang.StringUtils; 036import org.slf4j.Logger; 037import org.slf4j.LoggerFactory; 038import org.xml.sax.ContentHandler; 039import org.xml.sax.SAXException; 040 041import org.ametys.cms.tag.jcr.TaggableAmetysObjectHelper; 042import org.ametys.plugins.explorer.resources.ResourceCollection; 043import org.ametys.plugins.explorer.resources.jcr.JCRResourcesCollectionFactory; 044import org.ametys.plugins.repository.AmetysObject; 045import org.ametys.plugins.repository.AmetysObjectIterable; 046import org.ametys.plugins.repository.AmetysObjectIterator; 047import org.ametys.plugins.repository.AmetysRepositoryException; 048import org.ametys.plugins.repository.CollectionIterable; 049import org.ametys.plugins.repository.CopiableAmetysObject; 050import org.ametys.plugins.repository.ModifiableTraversableAmetysObject; 051import org.ametys.plugins.repository.RepositoryConstants; 052import org.ametys.plugins.repository.RepositoryIntegrityViolationException; 053import org.ametys.plugins.repository.TraversableAmetysObject; 054import org.ametys.plugins.repository.UnknownAmetysObjectException; 055import org.ametys.plugins.repository.data.holder.ModifiableDataHolder; 056import org.ametys.plugins.repository.data.holder.ModifiableModelAwareDataHolder; 057import org.ametys.plugins.repository.data.holder.ModifiableModelLessDataHolder; 058import org.ametys.plugins.repository.data.holder.impl.DataHolderHelper; 059import org.ametys.plugins.repository.data.holder.impl.DefaultModifiableModelLessDataHolder; 060import org.ametys.plugins.repository.data.repositorydata.ModifiableRepositoryData; 061import org.ametys.plugins.repository.data.repositorydata.impl.JCRRepositoryData; 062import org.ametys.plugins.repository.jcr.DefaultTraversableAmetysObject; 063import org.ametys.plugins.repository.jcr.SimpleAmetysObject; 064import org.ametys.plugins.repository.metadata.ModifiableCompositeMetadata; 065import org.ametys.runtime.model.View; 066import org.ametys.runtime.model.exception.BadItemTypeException; 067import org.ametys.runtime.model.exception.NotUniqueTypeException; 068import org.ametys.runtime.model.exception.UndefinedItemPathException; 069import org.ametys.runtime.model.exception.UnknownTypeException; 070import org.ametys.runtime.model.type.ModelItemTypeConstants; 071import org.ametys.web.parameters.view.ViewParametersModel; 072import org.ametys.web.parameters.view.ViewParametersManager; 073import org.ametys.web.repository.page.ModifiablePage; 074import org.ametys.web.repository.page.ModifiableZone; 075import org.ametys.web.repository.page.MoveablePage; 076import org.ametys.web.repository.page.Page; 077import org.ametys.web.repository.page.PagesContainer; 078import org.ametys.web.repository.page.UnknownZoneException; 079import org.ametys.web.repository.site.Site; 080import org.ametys.web.repository.sitemap.Sitemap; 081 082/** 083 * {@link Page} implementation stored into a JCR node using 084 * <code>ametys:defaultPage</code> node type. 085 * 086 * @param <F> the actual type of factory. 087 */ 088public class DefaultPage<F extends DefaultPageFactory> extends DefaultTraversableAmetysObject<F> implements ModifiablePage, CopiableAmetysObject, MoveablePage 089{ 090 /** Constant for title metadata. */ 091 public static final String METADATA_TITLE = RepositoryConstants.NAMESPACE_PREFIX_INTERNAL + ":title"; 092 093 /** Constant for long title metadata. */ 094 public static final String METADATA_LONG_TITLE = "long-title"; 095 096 /** Constant for title metadata. */ 097 public static final String METADATA_TYPE = RepositoryConstants.NAMESPACE_PREFIX_INTERNAL + ":type"; 098 099 /** Constant for title metadata. */ 100 public static final String METADATA_URL = RepositoryConstants.NAMESPACE_PREFIX_INTERNAL + ":url"; 101 102 /** Constant for title metadata. */ 103 public static final String METADATA_URLTYPE = RepositoryConstants.NAMESPACE_PREFIX_INTERNAL + ":url-type"; 104 105 /** Constant for template metadata. */ 106 public static final String METADATA_TEMPLATE = RepositoryConstants.NAMESPACE_PREFIX_INTERNAL + ":template"; 107 108 /** Constant for referers metadata. */ 109 public static final String METADATA_REFERERS = RepositoryConstants.NAMESPACE_PREFIX_INTERNAL + ":referers"; 110 111 /** Constant for the visible attribute. */ 112 public static final String METADATA_VISIBLE = RepositoryConstants.NAMESPACE_PREFIX_INTERNAL + ":visible"; 113 114 /** Constant for robots metadata. */ 115 public static final String METADATA_ROBOTS_DISALLOW = "robots-disallow"; 116 117 /** Constant for the zones node name. */ 118 public static final String ZONES_NODE_NAME = RepositoryConstants.NAMESPACE_PREFIX_INTERNAL + ":zones"; 119 120 /** Constant for the zones node type. */ 121 public static final String ZONES_NODE_TYPE = RepositoryConstants.NAMESPACE_PREFIX + ":zones"; 122 123 /** Constant for the zone node type. */ 124 public static final String ZONE_NODE_TYPE = RepositoryConstants.NAMESPACE_PREFIX + ":zone"; 125 126 /** Constant for the attachment node name. */ 127 public static final String ATTACHMENTS_NODE_NAME = RepositoryConstants.NAMESPACE_PREFIX_INTERNAL + ":attachments"; 128 129 /** Constants for site Metadata* */ 130 public static final String METADATA_SITE = "site"; 131 132 /** Constants for sitemap Metadata* */ 133 public static final String METADATA_SITEMAP = "sitemap"; 134 135 /** Constant for publication start date metadata. */ 136 public static final String METADATA_PUBLICATION_START_DATE = "publicationStartDate"; 137 138 /** Constant for publication end date metadata. */ 139 public static final String METADATA_PUBLICATION_END_DATE = "publicationEndDate"; 140 141 private static final Logger __LOGGER = LoggerFactory.getLogger(DefaultPage.class); 142 143 /** 144 * Creates a {@link DefaultPage}. 145 * 146 * @param node the node backing this {@link AmetysObject}. 147 * @param parentPath the parent path in the Ametys hierarchy. 148 * @param factory the {@link DefaultPageFactory} which creates the 149 * AmetysObject. 150 */ 151 public DefaultPage(Node node, String parentPath, F factory) 152 { 153 super(node, parentPath, factory); 154 } 155 156 @Override 157 public Set<String> getTags() throws AmetysRepositoryException 158 { 159 return TaggableAmetysObjectHelper.getTags(this); 160 } 161 162 @Override 163 public void tag(String tag) throws AmetysRepositoryException 164 { 165 TaggableAmetysObjectHelper.tag(this, tag); 166 } 167 168 @Override 169 public void untag(String tag) throws AmetysRepositoryException 170 { 171 TaggableAmetysObjectHelper.untag(this, tag); 172 } 173 174 @Override 175 public String getTitle() throws AmetysRepositoryException 176 { 177 try 178 { 179 return getNode().getProperty(METADATA_TITLE).getString(); 180 } 181 catch (RepositoryException e) 182 { 183 throw new AmetysRepositoryException("Unable to get title property", e); 184 } 185 } 186 187 @Override 188 public void setTitle(String title) throws AmetysRepositoryException 189 { 190 try 191 { 192 getNode().setProperty(METADATA_TITLE, title); 193 } 194 catch (RepositoryException e) 195 { 196 throw new AmetysRepositoryException("Unable to set title property", e); 197 } 198 } 199 200 @Override 201 public String getLongTitle() throws AmetysRepositoryException 202 { 203 String longTitle = getValue(METADATA_LONG_TITLE); 204 if (StringUtils.isNotBlank(longTitle)) 205 { 206 return longTitle; 207 } 208 else 209 { 210 return this.getTitle(); 211 } 212 } 213 214 @Override 215 public void setLongTitle(String title) throws AmetysRepositoryException 216 { 217 String newTitle = StringUtils.trimToNull(title); 218 setValue(METADATA_LONG_TITLE, newTitle, ModelItemTypeConstants.STRING_TYPE_ID); 219 } 220 221 @Override 222 public Sitemap getSitemap() throws AmetysRepositoryException 223 { 224 try 225 { 226 Node node = getNode(); 227 228 do 229 { 230 node = node.getParent(); 231 } 232 while (!node.getPrimaryNodeType().getName().equals(Sitemap.NODE_TYPE)); 233 234 return _getFactory().resolveAmetysObject(node); 235 } 236 catch (RepositoryException e) 237 { 238 throw new AmetysRepositoryException("Unable to get sitemap", e); 239 } 240 } 241 242 @Override 243 public int getDepth() throws AmetysRepositoryException 244 { 245 try 246 { 247 int depth = 1; 248 Node node = getNode().getParent(); 249 while (!node.getPrimaryNodeType().getName().equals(Sitemap.NODE_TYPE)) 250 { 251 depth++; 252 node = node.getParent(); 253 } 254 255 return depth; 256 } 257 catch (RepositoryException e) 258 { 259 throw new AmetysRepositoryException("Unable to get depth", e); 260 } 261 } 262 263 @Override 264 public Site getSite() throws AmetysRepositoryException 265 { 266 return getSitemap().getSite(); 267 } 268 269 @Override 270 public String getSiteName() 271 { 272 return getValue(METADATA_SITE); 273 } 274 275 @Override 276 public void setSiteName(String siteName) 277 { 278 setValue(METADATA_SITE, siteName); 279 } 280 281 @Override 282 public String getSitemapName() throws AmetysRepositoryException 283 { 284 return getValue(METADATA_SITEMAP); 285 } 286 287 @Override 288 public void setSitemapName(String sitemapName) throws AmetysRepositoryException 289 { 290 setValue(METADATA_SITEMAP, sitemapName); 291 } 292 293 @Override 294 public String getPathInSitemap() throws AmetysRepositoryException 295 { 296 String nodePath = getPath(); 297 String sitemapPath = getSitemap().getPath(); 298 return nodePath.substring(sitemapPath.length() + 1); 299 } 300 301 @Override 302 public PageType getType() throws AmetysRepositoryException 303 { 304 try 305 { 306 return PageType.valueOf(getNode().getProperty(METADATA_TYPE).getString()); 307 } 308 catch (RepositoryException e) 309 { 310 throw new AmetysRepositoryException("Unable to get type property", e); 311 } 312 } 313 314 @Override 315 public void setType(PageType type) throws AmetysRepositoryException 316 { 317 try 318 { 319 getNode().setProperty(METADATA_TYPE, type.name()); 320 } 321 catch (RepositoryException e) 322 { 323 throw new AmetysRepositoryException("Unable to set type property", e); 324 } 325 } 326 327 @Override 328 public String getURL() throws AmetysRepositoryException 329 { 330 try 331 { 332 return getNode().getProperty(METADATA_URL).getString(); 333 } 334 catch (RepositoryException e) 335 { 336 throw new AmetysRepositoryException("Unable to get url property", e); 337 } 338 } 339 340 @Override 341 public LinkType getURLType() throws AmetysRepositoryException 342 { 343 try 344 { 345 return LinkType.valueOf(getNode().getProperty(METADATA_URLTYPE).getString()); 346 } 347 catch (RepositoryException e) 348 { 349 throw new AmetysRepositoryException("Unable to get url type property", e); 350 } 351 } 352 353 @Override 354 public void setURL(LinkType type, String url) throws AmetysRepositoryException 355 { 356 try 357 { 358 getNode().setProperty(METADATA_URLTYPE, type.toString()); 359 getNode().setProperty(METADATA_URL, url); 360 } 361 catch (RepositoryException e) 362 { 363 throw new AmetysRepositoryException("Unable to set url property", e); 364 } 365 } 366 367 @Override 368 public String getTemplate() throws AmetysRepositoryException 369 { 370 try 371 { 372 Node node = getNode(); 373 374 if (node.hasProperty(METADATA_TEMPLATE)) 375 { 376 return node.getProperty(METADATA_TEMPLATE).getString(); 377 } 378 else 379 { 380 return null; 381 } 382 } 383 catch (RepositoryException e) 384 { 385 throw new AmetysRepositoryException("Unable to get template property", e); 386 } 387 } 388 389 @Override 390 public void setTemplate(String template) throws AmetysRepositoryException 391 { 392 try 393 { 394 getNode().setProperty(METADATA_TEMPLATE, template); 395 } 396 catch (RepositoryException e) 397 { 398 throw new AmetysRepositoryException("Unable to set template property", e); 399 } 400 } 401 402 @Override 403 public AmetysObjectIterable<ModifiableZone> getZones() throws AmetysRepositoryException 404 { 405 try 406 { 407 return ((TraversableAmetysObject) getChild(ZONES_NODE_NAME)).getChildren(); 408 } 409 catch (UnknownAmetysObjectException e) 410 { 411 Collection<ModifiableZone> emptyCollection = Collections.emptyList(); 412 return new CollectionIterable<>(emptyCollection); 413 } 414 } 415 416 @Override 417 public boolean hasZone(String name) throws AmetysRepositoryException 418 { 419 if (hasChild(ZONES_NODE_NAME)) 420 { 421 return ((TraversableAmetysObject) getChild(ZONES_NODE_NAME)).hasChild(name); 422 } 423 else 424 { 425 return false; 426 } 427 } 428 429 @Override 430 public ModifiableZone getZone(String name) throws UnknownZoneException, AmetysRepositoryException 431 { 432 return ((TraversableAmetysObject) getChild(ZONES_NODE_NAME)).getChild(name); 433 } 434 435 @Override 436 public ModifiableZone createZone(String name) throws AmetysRepositoryException 437 { 438 ModifiableTraversableAmetysObject zones; 439 if (hasChild(ZONES_NODE_NAME)) 440 { 441 zones = getChild(ZONES_NODE_NAME); 442 } 443 else 444 { 445 zones = createChild(ZONES_NODE_NAME, ZONES_NODE_TYPE); 446 } 447 448 return zones.createChild(name, ZONE_NODE_TYPE); 449 } 450 451 @Override 452 public ResourceCollection getRootAttachments() throws AmetysRepositoryException 453 { 454 ResourceCollection attachments; 455 if (hasChild(ATTACHMENTS_NODE_NAME)) 456 { 457 attachments = getChild(ATTACHMENTS_NODE_NAME); 458 } 459 else 460 { 461 attachments = createChild(ATTACHMENTS_NODE_NAME, JCRResourcesCollectionFactory.RESOURCESCOLLECTION_NODETYPE); 462 463 try 464 { 465 getNode().getSession().save(); 466 } 467 catch (RepositoryException e) 468 { 469 throw new AmetysRepositoryException("Unable to save session", e); 470 } 471 } 472 473 return attachments; 474 } 475 476 @Override 477 public Set<String> getReferers() throws AmetysRepositoryException 478 { 479 try 480 { 481 Node node = getNode(); 482 483 if (!node.hasProperty(METADATA_REFERERS)) 484 { 485 return Collections.emptySet(); 486 } 487 488 Value[] values = getNode().getProperty(METADATA_REFERERS).getValues(); 489 Set<String> ids = new HashSet<>(values.length); 490 491 for (Value value : values) 492 { 493 ids.add(value.getString()); 494 } 495 496 return ids; 497 } 498 catch (RepositoryException e) 499 { 500 throw new AmetysRepositoryException("Unable to get referers property", e); 501 } 502 } 503 504 @Override 505 public void addReferer(String ametysObjectId) throws AmetysRepositoryException 506 { 507 try 508 { 509 Set<String> ids = null; 510 Node node = getNode(); 511 512 if (!node.hasProperty(METADATA_REFERERS)) 513 { 514 ids = Collections.singleton(ametysObjectId); 515 } 516 else 517 { 518 Value[] values = getNode().getProperty(METADATA_REFERERS).getValues(); 519 ids = new HashSet<>(values.length + 1); 520 521 for (Value value : values) 522 { 523 ids.add(value.getString()); 524 } 525 526 ids.add(ametysObjectId); 527 } 528 529 node.setProperty(METADATA_REFERERS, ids.toArray(new String[ids.size()])); 530 } 531 catch (RepositoryException e) 532 { 533 throw new AmetysRepositoryException("Unable to add an id into referers property", e); 534 } 535 } 536 537 @Override 538 public void removeReferer(String ametysObjectId) throws AmetysRepositoryException 539 { 540 try 541 { 542 Node node = getNode(); 543 544 if (node.hasProperty(METADATA_REFERERS)) 545 { 546 Value[] values = getNode().getProperty(METADATA_REFERERS).getValues(); 547 Set<String> ids = new HashSet<>(values.length + 1); 548 549 for (Value value : values) 550 { 551 ids.add(value.getString()); 552 } 553 554 ids.remove(ametysObjectId); 555 node.setProperty(METADATA_REFERERS, ids.toArray(new String[ids.size()])); 556 } 557 } 558 catch (RepositoryException e) 559 { 560 throw new AmetysRepositoryException("Unable to remove an id from referers property", e); 561 } 562 } 563 564 @Override 565 public AmetysObjectIterable< ? extends Page> getChildrenPages() throws AmetysRepositoryException 566 { 567 return getChildrenPages(true); 568 } 569 570 @Override 571 public AmetysObjectIterable< ? extends Page> getChildrenPages(boolean includeInvisiblePage) throws AmetysRepositoryException 572 { 573 List<Page> childrenPages = new ArrayList<>(); 574 for (AmetysObject childObject : getChildren()) 575 { 576 if (childObject instanceof Page) 577 { 578 Page page = (Page) childObject; 579 if (includeInvisiblePage || page.isVisible()) 580 { 581 childrenPages.add(page); 582 } 583 } 584 } 585 return new CollectionIterable<>(childrenPages); 586 } 587 588 @Override 589 public Page getChildPageAt(int index) throws UnknownAmetysObjectException, AmetysRepositoryException 590 { 591 if (index < 0) 592 { 593 throw new AmetysRepositoryException("Child page index cannot be negative"); 594 } 595 596 AmetysObjectIterable< ? extends Page> childPages = getChildrenPages(); 597 AmetysObjectIterator< ? extends Page> it = childPages.iterator(); 598 599 try 600 { 601 it.skip(index); 602 return it.next(); 603 } 604 catch (NoSuchElementException e) 605 { 606 throw new UnknownAmetysObjectException("There's no child page at index " + index + " for page " + this.getId()); 607 } 608 } 609 610 @Override 611 public DefaultPage copyTo(ModifiableTraversableAmetysObject parent, String name, List<String> restrictTo) throws AmetysRepositoryException 612 { 613 try 614 { 615 int index = 1; 616 String originalName = name == null ? getName() : name; 617 String pageName = originalName; 618 while (parent.hasChild(pageName)) 619 { 620 // Find unused name on new parent node 621 pageName = originalName + "-" + index++; 622 } 623 624 DefaultPage cPage = parent.createChild(pageName, "ametys:defaultPage"); 625 cPage.setType(getType()); 626 cPage.setTitle(getTitle()); 627 628 if (PageType.CONTAINER.equals(getType())) 629 { 630 cPage.setTemplate(getTemplate()); 631 } 632 else if (PageType.LINK.equals(getType())) 633 { 634 cPage.setURL(getURLType(), getURL()); 635 } 636 637 // Copy metadata 638 copyTo(cPage); 639 640 // Copy view parameters 641 getTemplateParametersHolder().copyTo(cPage.getTemplateParametersHolder()); 642 643 // Copy zones 644 for (ModifiableZone zone : getZones()) 645 { 646 if (zone instanceof CopiableAmetysObject) 647 { 648 ((CopiableAmetysObject) zone).copyTo(cPage, null); 649 } 650 } 651 652 // Copy tags 653 Set<String> tags = getTags(); 654 for (String tag : tags) 655 { 656 cPage.tag(tag); 657 } 658 659 // Update sitemap name 660 if (parent instanceof PagesContainer) 661 { 662 cPage.setSitemapName(((PagesContainer) parent).getSitemapName()); 663 } 664 665 parent.saveChanges(); 666 667 // Copy attachments 668 ResourceCollection rootAttachments = getRootAttachments(); 669 if (rootAttachments instanceof SimpleAmetysObject) 670 { 671 Node resourcesNode = ((SimpleAmetysObject) rootAttachments).getNode(); 672 getNode().getSession().getWorkspace().copy(resourcesNode.getPath(), cPage.getNode().getPath() + "/" + resourcesNode.getName()); 673 } 674 675 // Copy sub-pages 676 AmetysObjectIterable< ? extends Page> childrenPages = getChildrenPages(); 677 for (Page page : childrenPages) 678 { 679 // Avoid infinite loop : do not copy the page itself 680 if (page instanceof CopiableAmetysObject && restrictTo.contains(page.getId())) 681 { 682 ((CopiableAmetysObject) page).copyTo(cPage, null, restrictTo); 683 } 684 } 685 686 return cPage; 687 } 688 catch (RepositoryException e) 689 { 690 throw new AmetysRepositoryException(e); 691 } 692 } 693 694 @Override 695 public DefaultPage copyTo(ModifiableTraversableAmetysObject parent, String name) throws AmetysRepositoryException 696 { 697 return copyTo (parent, name, new ArrayList<String>()); 698 } 699 700 public void copyTo(ModifiableDataHolder dataHolder) throws UndefinedItemPathException, BadItemTypeException, UnknownTypeException, NotUniqueTypeException 701 { 702 for (String name : getDataNames()) 703 { 704 if (!ViewParametersManager.VIEW_PARAMETERS_COMPOSITE_NAME.equals(name)) 705 { 706 DataHolderHelper.copyTo(getDataHolder(), dataHolder, name); 707 } 708 } 709 } 710 711 @Override 712 public void moveTo(AmetysObject newParent, boolean renameIfExist) throws AmetysRepositoryException, RepositoryIntegrityViolationException 713 { 714 Node node = getNode(); 715 716 try 717 { 718 if (getParent().equals(newParent)) 719 { 720 // Just order current node to the end 721 node.getParent().orderBefore(node.getName(), null); 722 } 723 else 724 { 725 if (!canMoveTo(newParent)) 726 { 727 throw new AmetysRepositoryException("DefaultPage " + toString() + " can only be moved to a CompositePages and "); 728 } 729 PagesContainer newParentPage = (PagesContainer) newParent; 730 731 String sitemapNodePath = getSitemap().getNode().getPath(); 732 String newPath = sitemapNodePath + (newParentPage instanceof Sitemap ? "" : '/' + newParentPage.getPathInSitemap()); 733 734 String name = node.getName(); 735 736 if (renameIfExist) 737 { 738 // Find unused name on new parent node 739 int index = 1; 740 while (node.getSession().getRootNode().hasNode(newPath.substring(1) + "/" + name)) 741 { 742 name = name + "-" + index++; 743 } 744 } 745 746 try 747 { 748 // Move node 749 node.getSession().move(node.getPath(), newPath + "/" + name); 750 } 751 catch (ItemExistsException e) 752 { 753 throw new AmetysRepositoryException(String.format("A page already exists for in parent path '%s'", newPath), e); 754 } 755 756 // recompute name in case it has changed 757 _invalidateName(); 758 759 // Invalidate parent path as the parent path has changed 760 _invalidateParentPath(); 761 } 762 } 763 catch (RepositoryException e) 764 { 765 throw new AmetysRepositoryException(String.format("Unable to move page '%s' to node '%s'", this, newParent.getId()), e); 766 } 767 } 768 769 @Override 770 public boolean canMoveTo(AmetysObject newParent) throws AmetysRepositoryException 771 { 772 return newParent instanceof PagesContainer && ((PagesContainer) newParent).getSitemap().equals(getSitemap()); 773 } 774 775 @Override 776 public void orderBefore(AmetysObject siblingNode) throws AmetysRepositoryException 777 { 778 Node node = getNode(); 779 try 780 { 781 node.getParent().orderBefore(node.getName(), siblingNode != null ? siblingNode.getName() : null); 782 } 783 catch (RepositoryException e) 784 { 785 throw new AmetysRepositoryException(String.format("Unable to order page '%s' before sibling '%s'", this, siblingNode != null ? siblingNode.getName() : ""), e); 786 } 787 } 788 789 @Override 790 public boolean isVisible() throws AmetysRepositoryException 791 { 792 try 793 { 794 if (getNode().hasProperty(METADATA_VISIBLE)) 795 { 796 return getNode().getProperty(METADATA_VISIBLE).getBoolean(); 797 } 798 else 799 { 800 return true; 801 } 802 } 803 catch (RepositoryException e) 804 { 805 throw new AmetysRepositoryException("Unable to get visible property", e); 806 } 807 } 808 809 @Override 810 public void setVisible(boolean isVisible) throws AmetysRepositoryException 811 { 812 try 813 { 814 getNode().setProperty(METADATA_VISIBLE, isVisible); 815 } 816 catch (RepositoryException e) 817 { 818 throw new AmetysRepositoryException("Unable to set visible property", e); 819 } 820 } 821 822 public ModifiableModelLessDataHolder getDataHolder() 823 { 824 ModifiableRepositoryData repositoryData = new JCRRepositoryData(getNode()); 825 return new DefaultModifiableModelLessDataHolder(_getFactory().getPageDataTypeExtensionPoint(), repositoryData); 826 } 827 828 @Override 829 public ModifiableCompositeMetadata getMetadataHolder() 830 { 831 __LOGGER.warn("The getMetadataHolder method of DefaultPage is deprecated. Use the getDataHolder instead. StackTrace: ", new Exception()); 832 return super.getMetadataHolder(); 833 } 834 835 public ModifiableModelAwareDataHolder getTemplateParametersHolder() throws AmetysRepositoryException 836 { 837 JCRRepositoryData zoneItemRepositoryData = new JCRRepositoryData(getNode()); 838 839 // Get the template Id 840 String templateId = getTemplate(); 841 842 // Get the skin Id 843 String skinId = getSite().getSkinId(); 844 845 ViewParametersManager viewParametersManager = _getFactory().getViewParametersManager(); 846 Optional<ViewParametersModel> templateViewParameters = viewParametersManager.getTemplateViewParametersModel(skinId, templateId); 847 if (templateViewParameters.isEmpty()) 848 { 849 templateViewParameters = Optional.of(new ViewParametersModel("template-no-param", new View(), MapUtils.EMPTY_SORTED_MAP)); 850 } 851 852 return viewParametersManager.getParametersHolder(zoneItemRepositoryData, templateViewParameters.get()); 853 } 854 855 /* 856 * The default implementation is overridden here to not use the getDataHolder()#dataToSAX implementation 857 * Each #dataToSAX method calls the next one and the implementation that has to change is the last one. 858 * If the getDataHolder() is used for one, the next ones will be called with the default implementation 859 */ 860 public void dataToSAX(ContentHandler contentHandler, Locale locale) throws SAXException, IOException, UnknownTypeException, NotUniqueTypeException 861 { 862 for (String name : getDataNames()) 863 { 864 dataToSAX(contentHandler, name, locale); 865 } 866 } 867 868 public void dataToSAX(ContentHandler contentHandler, String dataPath, Locale locale) throws SAXException, IOException 869 { 870 if (!ViewParametersManager.VIEW_PARAMETERS_COMPOSITE_NAME.equals(dataPath)) 871 { 872 ModifiablePage.super.dataToSAX(contentHandler, dataPath, locale); 873 } 874 } 875}