001/* 002 * Copyright 2022 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.util.ArrayList; 019import java.util.Collection; 020import java.util.Collections; 021import java.util.List; 022import java.util.NoSuchElementException; 023import java.util.Optional; 024 025import javax.jcr.Node; 026 027import org.apache.commons.collections4.MapUtils; 028import org.slf4j.Logger; 029import org.slf4j.LoggerFactory; 030import org.xml.sax.ContentHandler; 031import org.xml.sax.SAXException; 032 033import org.ametys.plugins.repository.AmetysObject; 034import org.ametys.plugins.repository.AmetysObjectIterable; 035import org.ametys.plugins.repository.AmetysObjectIterator; 036import org.ametys.plugins.repository.AmetysRepositoryException; 037import org.ametys.plugins.repository.CollectionIterable; 038import org.ametys.plugins.repository.ModifiableTraversableAmetysObject; 039import org.ametys.plugins.repository.RepositoryConstants; 040import org.ametys.plugins.repository.TraversableAmetysObject; 041import org.ametys.plugins.repository.UnknownAmetysObjectException; 042import org.ametys.plugins.repository.data.holder.ModifiableModelAwareDataHolder; 043import org.ametys.plugins.repository.data.repositorydata.impl.JCRRepositoryData; 044import org.ametys.plugins.repository.jcr.DefaultTraversableAmetysObject; 045import org.ametys.plugins.repository.metadata.ModifiableCompositeMetadata; 046import org.ametys.runtime.model.View; 047import org.ametys.runtime.model.exception.BadItemTypeException; 048import org.ametys.runtime.model.exception.NotUniqueTypeException; 049import org.ametys.runtime.model.exception.UnknownTypeException; 050import org.ametys.runtime.model.type.DataContext; 051import org.ametys.web.parameters.view.ViewParametersManager; 052import org.ametys.web.parameters.view.ViewParametersModel; 053import org.ametys.web.repository.page.ModifiableSitemapElement; 054import org.ametys.web.repository.page.ModifiableZone; 055import org.ametys.web.repository.page.Page; 056import org.ametys.web.repository.page.SitemapElement; 057import org.ametys.web.repository.page.UnknownZoneException; 058 059/** 060 * {@link SitemapElement} implementation stored into a JCR node. 061 * 062 * @param <F> the actual type of factory. 063 */ 064public abstract class AbstractSitemapElement<F extends AbstractSitemapElementFactory> extends DefaultTraversableAmetysObject<F> implements ModifiableSitemapElement 065{ 066 /** Constant for the zones node name. */ 067 public static final String ZONES_NODE_NAME = RepositoryConstants.NAMESPACE_PREFIX_INTERNAL + ":zones"; 068 069 /** Constant for the zones node type. */ 070 public static final String ZONES_NODE_TYPE = RepositoryConstants.NAMESPACE_PREFIX + ":zones"; 071 072 /** Constant for the zone node type. */ 073 public static final String ZONE_NODE_TYPE = RepositoryConstants.NAMESPACE_PREFIX + ":zone"; 074 075 private static final Logger __LOGGER = LoggerFactory.getLogger(AbstractSitemapElement.class); 076 077 /** 078 * Creates an {@link AbstractSitemapElement}. 079 * 080 * @param node the node backing this {@link AmetysObject}. 081 * @param parentPath the parent path in the Ametys hierarchy. 082 * @param factory the {@link DefaultPageFactory} which creates the 083 * AmetysObject. 084 */ 085 public AbstractSitemapElement(Node node, String parentPath, F factory) 086 { 087 super(node, parentPath, factory); 088 } 089 090 091 @Override 092 public AmetysObjectIterable< ? extends Page> getChildrenPages() throws AmetysRepositoryException 093 { 094 return getChildrenPages(true); 095 } 096 097 @Override 098 public AmetysObjectIterable< ? extends Page> getChildrenPages(boolean includeInvisiblePage) throws AmetysRepositoryException 099 { 100 List<Page> childrenPages = new ArrayList<>(); 101 for (AmetysObject childObject : getChildren()) 102 { 103 if (childObject instanceof Page) 104 { 105 Page page = (Page) childObject; 106 if (includeInvisiblePage || page.isVisible()) 107 { 108 childrenPages.add(page); 109 } 110 } 111 } 112 return new CollectionIterable<>(childrenPages); 113 } 114 115 @Override 116 public Page getChildPageAt(int index) throws UnknownAmetysObjectException, AmetysRepositoryException 117 { 118 if (index < 0) 119 { 120 throw new AmetysRepositoryException("Child page index cannot be negative"); 121 } 122 123 AmetysObjectIterable< ? extends Page> childPages = getChildrenPages(); 124 AmetysObjectIterator< ? extends Page> it = childPages.iterator(); 125 126 try 127 { 128 it.skip(index); 129 return it.next(); 130 } 131 catch (NoSuchElementException e) 132 { 133 throw new UnknownAmetysObjectException("There's no child page at index " + index + " for sitemap " + this.getId()); 134 } 135 } 136 137 @Override 138 public AmetysObjectIterable<ModifiableZone> getZones() throws AmetysRepositoryException 139 { 140 try 141 { 142 return ((TraversableAmetysObject) getChild(ZONES_NODE_NAME)).getChildren(); 143 } 144 catch (UnknownAmetysObjectException e) 145 { 146 Collection<ModifiableZone> emptyCollection = Collections.emptyList(); 147 return new CollectionIterable<>(emptyCollection); 148 } 149 } 150 151 @Override 152 public boolean hasZone(String name) throws AmetysRepositoryException 153 { 154 if (hasChild(ZONES_NODE_NAME)) 155 { 156 return ((TraversableAmetysObject) getChild(ZONES_NODE_NAME)).hasChild(name); 157 } 158 else 159 { 160 return false; 161 } 162 } 163 164 @Override 165 public ModifiableZone getZone(String name) throws UnknownZoneException, AmetysRepositoryException 166 { 167 return ((TraversableAmetysObject) getChild(ZONES_NODE_NAME)).getChild(name); 168 } 169 170 @Override 171 public ModifiableZone createZone(String name) throws AmetysRepositoryException 172 { 173 ModifiableTraversableAmetysObject zones; 174 if (hasChild(ZONES_NODE_NAME)) 175 { 176 zones = getChild(ZONES_NODE_NAME); 177 } 178 else 179 { 180 zones = createChild(ZONES_NODE_NAME, ZONES_NODE_TYPE); 181 } 182 183 return zones.createChild(name, ZONE_NODE_TYPE); 184 } 185 186 @Override 187 public ModifiableCompositeMetadata getMetadataHolder() 188 { 189 __LOGGER.warn("The getMetadataHolder method of AbstractSitemapElement is deprecated. Use the getDataHolder instead. StackTrace: ", new Exception()); 190 return super.getMetadataHolder(); 191 } 192 193 public ModifiableModelAwareDataHolder getTemplateParametersHolder() throws AmetysRepositoryException 194 { 195 JCRRepositoryData zoneItemRepositoryData = new JCRRepositoryData(getNode()); 196 197 // Get the template Id 198 String templateId = getTemplate(); 199 200 // Get the skin Id 201 String skinId = getSite().getSkinId(); 202 203 ViewParametersManager viewParametersManager = _getFactory().getViewParametersManager(); 204 Optional<ViewParametersModel> templateViewParameters = viewParametersManager.getTemplateViewParametersModel(skinId, templateId); 205 if (templateViewParameters.isEmpty()) 206 { 207 templateViewParameters = Optional.of(new ViewParametersModel("template-no-param", new View(), MapUtils.EMPTY_SORTED_MAP)); 208 } 209 210 return viewParametersManager.getParametersHolder(zoneItemRepositoryData, templateViewParameters.get()); 211 } 212 213 /* 214 * The default implementation is overridden here to not use the getDataHolder()#dataToSAX implementation 215 * Each #dataToSAX method calls the next one and the implementation that has to change is the last one. 216 * If the getDataHolder() is used for one, the next ones will be called with the default implementation 217 */ 218 @Override 219 public void dataToSAX(ContentHandler contentHandler, DataContext context) throws SAXException, UnknownTypeException, NotUniqueTypeException, BadItemTypeException 220 { 221 for (String name : getDataNames()) 222 { 223 dataToSAX(contentHandler, name, context); 224 } 225 } 226 227 @Override 228 public void dataToSAX(ContentHandler contentHandler, String dataPath, DataContext context) throws SAXException, UnknownTypeException, NotUniqueTypeException, BadItemTypeException 229 { 230 if (!ViewParametersManager.VIEW_PARAMETERS_COMPOSITE_NAME.equals(dataPath)) 231 { 232 super.dataToSAX(contentHandler, dataPath, context); 233 } 234 } 235}