001/* 002 * Copyright 2016 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.userdirectory.page; 017 018import java.util.ArrayList; 019import java.util.Arrays; 020import java.util.List; 021import java.util.Map; 022import java.util.Map.Entry; 023import java.util.Set; 024import java.util.SortedSet; 025import java.util.stream.Collectors; 026 027import org.apache.commons.lang3.StringUtils; 028import org.apache.commons.lang3.Strings; 029import org.slf4j.Logger; 030import org.slf4j.LoggerFactory; 031 032import org.ametys.cms.repository.Content; 033import org.ametys.plugins.repository.AmetysObject; 034import org.ametys.plugins.repository.AmetysObjectIterable; 035import org.ametys.plugins.repository.AmetysRepositoryException; 036import org.ametys.plugins.repository.CollectionIterable; 037import org.ametys.plugins.repository.UnknownAmetysObjectException; 038import org.ametys.web.repository.page.Page; 039import org.ametys.web.repository.page.virtual.AbstractConfigurableVirtualPage; 040import org.ametys.web.repository.page.virtual.VirtualPageConfiguration; 041 042 043/** 044 * Page representing a second-level page. 045 */ 046public class TransitionalPage extends AbstractConfigurableVirtualPage<TransitionalPageFactory> 047{ 048 private static Logger _logger = LoggerFactory.getLogger(TransitionalPage.class); 049 private String _path; 050 private int _initialDepth; 051 private String _prefix; 052 053 /** 054 * Constructor. 055 * @param root the user directory root page. 056 * @param prefix the page's title. 057 * @param path the path 058 * @param configuration The abstract virtual page configuration 059 * @param scheme The scheme 060 * @param factory The transitional page factory 061 */ 062 public TransitionalPage(Page root, VirtualPageConfiguration configuration, String scheme, TransitionalPageFactory factory, String prefix, String path) 063 { 064 super(root, configuration, scheme, factory); 065 066 _prefix = prefix; 067 _path = path; 068 069 _initialDepth = _factory.getUserDirectoryPageHandler().getDepth(_root); 070 } 071 072 @Override 073 public int getDepth() throws AmetysRepositoryException 074 { 075 return _root.getDepth() + _path.split("/").length; 076 } 077 078 @Override 079 public Set<String> getReferers() throws AmetysRepositoryException 080 { 081 return null; 082 } 083 084 @Override 085 public String getTitle() throws AmetysRepositoryException 086 { 087 return StringUtils.upperCase(_prefix); 088 } 089 090 @Override 091 public String getLongTitle() throws AmetysRepositoryException 092 { 093 return StringUtils.upperCase(_prefix); 094 } 095 096 @Override 097 public AmetysObjectIterable<? extends Page> getChildrenPages() throws AmetysRepositoryException 098 { 099 List<Page> children = new ArrayList<>(); 100 101 int depth = _initialDepth - _path.split("/").length; 102 if (depth > 0) 103 { 104 SortedSet<String> transitionalPagesName = _factory.getUserDirectoryPageHandler().getTransitionalPagesName(_root, _factory.getUserDirectoryPageHandler().getName(_path)); 105 for (String name : transitionalPagesName) 106 { 107 String pathName = _factory.getUserDirectoryPageHandler().getPathName(name); 108 children.add(_factory.createTransitionalPage(_root, name, _path + "/" + pathName)); 109 } 110 111 Map<String, String> userPagesContent = _factory.getUserDirectoryPageHandler().getUserPagesContent(_root, _factory.getUserDirectoryPageHandler().getName(_path)); 112 for (Entry<String, String> entry : userPagesContent.entrySet()) 113 { 114 String contentTypeId = _factory.getUserDirectoryPageHandler().getContentTypeId(_root); 115 String classificationAttribute = _factory.getUserDirectoryPageHandler().getClassificationAttribute(_root); 116 Content content; 117 try 118 { 119 content = _factory.getResolver().resolveById(entry.getValue()); 120 } 121 catch (AmetysRepositoryException e) 122 { 123 // content does not exist, skip to next iteration 124 break; 125 } 126 if (content == null || !Arrays.asList(content.getTypes()).contains(contentTypeId) || !content.hasValue(classificationAttribute)) 127 { 128 break; 129 } 130 131 String classificationAttributeValue = _factory.getUserDirectoryPageHandler().getTransformedClassificationValue(_root, content); 132 if (classificationAttributeValue != null && classificationAttributeValue.length() == _path.split("/").length) 133 { 134 children.add(_factory.getUserPageFactory().createUserPage(_root, content, _path)); 135 } 136 } 137 } 138 else 139 { 140 Map<String, String> userPagesContent = _factory.getUserDirectoryPageHandler().getUserPagesContent(_root, _path); 141 for (String contentId : userPagesContent.values()) 142 { 143 try 144 { 145 Content content = _factory.getResolver().resolveById(contentId); 146 children.add(_factory.getUserPageFactory().createUserPage(_root, content, _path)); 147 } 148 catch (UnknownAmetysObjectException e) 149 { 150 _logger.warn("Content {} does not exist anymore", contentId, e); 151 } 152 } 153 } 154 155 return new CollectionIterable<>(children); 156 } 157 158 @Override 159 public AmetysObjectIterable< ? extends Page> getChildrenPages(boolean includeInvisiblePage) throws AmetysRepositoryException 160 { 161 if (includeInvisiblePage) 162 { 163 return getChildrenPages(); 164 } 165 else 166 { 167 List<Page> children = new ArrayList<>(); 168 return new CollectionIterable<>(children); 169 } 170 } 171 172 @Override 173 public String getPathInSitemap() throws AmetysRepositoryException 174 { 175 String path = StringUtils.lowerCase(_path); 176 return _root.getPathInSitemap() + "/" + path; 177 } 178 179 @SuppressWarnings("unchecked") 180 @Override 181 public <A extends AmetysObject> A getChild(String path) throws AmetysRepositoryException, UnknownAmetysObjectException 182 { 183 if (path.isEmpty()) 184 { 185 throw new AmetysRepositoryException("path must be non empty"); 186 } 187 188 String completePath = _path + "/" + path; 189 int depth = _initialDepth - completePath.split("/").length + 1; 190 if (depth > 0) 191 { 192 String namePath = StringUtils.substringAfterLast(completePath, "/"); 193 String parentPath = StringUtils.substringBeforeLast(completePath, "/"); 194 195 SortedSet<String> transitionalPagesName = _factory.getUserDirectoryPageHandler().getTransitionalPagesName(_root, parentPath); 196 Map<String, String> userPagesContent = _factory.getUserDirectoryPageHandler().getUserPagesContent(_root, parentPath); 197 String name = _factory.getUserDirectoryPageHandler().getName(namePath); 198 if (transitionalPagesName.contains(name)) 199 { 200 TransitionalPage page = _factory.createTransitionalPage(_root, name, completePath); 201 return (A) page; 202 } 203 else if (userPagesContent.containsKey(name)) 204 { 205 String contentId = userPagesContent.get(name); 206 Content syncContent = _factory.getResolver().resolveById(contentId); 207 UserPage page = _factory.getUserPageFactory().createUserPage(_root, syncContent, parentPath); 208 return (A) page; 209 } 210 else 211 { 212 throw new UnknownAmetysObjectException("No transitional page named " + name + " (full page path " + path + ")."); 213 } 214 } 215 else 216 { 217 String userPath = StringUtils.substringBeforeLast(completePath, "/"); 218 String contentName = StringUtils.substringAfterLast(completePath, "/"); 219 220 Map<String, String> userPagesContent = _factory.getUserDirectoryPageHandler().getUserPagesContent(_root, userPath); 221 if (userPagesContent.containsKey(contentName)) 222 { 223 Content content = _factory.getResolver().resolveById(userPagesContent.get(contentName)); 224 225 UserPage page = _factory.getUserPageFactory().createUserPage(_root, content, userPath); 226 return (A) page; 227 } 228 else 229 { 230 throw new UnknownAmetysObjectException("No user content named " + contentName + " (full page path " + path + ")."); 231 } 232 } 233 } 234 235 @SuppressWarnings("unchecked") 236 @Override 237 public AmetysObjectIterable<? extends AmetysObject> getChildren() throws AmetysRepositoryException 238 { 239 return getChildrenPages(); 240 } 241 242 @Override 243 public boolean hasChild(String name) throws AmetysRepositoryException 244 { 245 int depth = _initialDepth - _path.split("/").length; 246 if (depth > 0) 247 { 248 SortedSet<String> transitionalPagesName = _factory.getUserDirectoryPageHandler().getTransitionalPagesName(_root, _path); 249 Map<String, String> userPagesContent = _factory.getUserDirectoryPageHandler().getUserPagesContent(_root, _path); 250 return transitionalPagesName.contains(name) || userPagesContent.containsKey(name); 251 } 252 else 253 { 254 Map<String, String> userPagesContent = _factory.getUserDirectoryPageHandler().getUserPagesContent(_root, _path); 255 return userPagesContent.containsKey(name); 256 } 257 } 258 259 @Override 260 public String getId() throws AmetysRepositoryException 261 { 262 // E.g: udtransitional://path?rootId=... 263 return "udtransitional://" + _path + "?rootId=" + _root.getId(); 264 } 265 266 @Override 267 public String getName() throws AmetysRepositoryException 268 { 269 return StringUtils.lowerCase(_prefix); 270 } 271 272 @SuppressWarnings("unchecked") 273 @Override 274 public Page getParent() throws AmetysRepositoryException 275 { 276 if (_path.split("/").length > 1) 277 { 278 String parentPath = StringUtils.substringBeforeLast(_path, "/"); 279 String pathName = parentPath; 280 if (Strings.CS.contains(pathName, "/")) 281 { 282 pathName = StringUtils.substringAfterLast(pathName, "/"); 283 } 284 285 String name = _factory.getUserDirectoryPageHandler().getName(pathName); 286 return _factory.createTransitionalPage(_root, name, parentPath); 287 } 288 else 289 { 290 return _root; 291 } 292 } 293 294 @Override 295 public String getParentPath() throws AmetysRepositoryException 296 { 297 if (_path.split("/").length > 1) 298 { 299 String path = StringUtils.lowerCase(_path); 300 return _root.getPath() + "/" + StringUtils.substringBeforeLast(path, "/"); 301 } 302 else 303 { 304 return _root.getPath(); 305 } 306 } 307 308 @Override 309 public boolean isVisible() throws AmetysRepositoryException 310 { 311 return false; 312 } 313 314 @Override 315 public Page getChildPageAt(int index) throws UnknownAmetysObjectException, AmetysRepositoryException 316 { 317 return getChildrenPages().stream().collect(Collectors.toList()).get(index); 318 } 319}