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.Collections; 021import java.util.List; 022import java.util.Map; 023import java.util.Map.Entry; 024import java.util.stream.Collectors; 025import java.util.Set; 026import java.util.SortedSet; 027 028import org.apache.commons.lang.StringUtils; 029 030import org.ametys.cms.repository.Content; 031import org.ametys.plugins.contentio.synchronize.SynchronizableContentsCollectionDAO; 032import org.ametys.plugins.explorer.resources.ResourceCollection; 033import org.ametys.plugins.repository.AmetysObject; 034import org.ametys.plugins.repository.AmetysObjectIterable; 035import org.ametys.plugins.repository.AmetysObjectResolver; 036import org.ametys.plugins.repository.AmetysRepositoryException; 037import org.ametys.plugins.repository.CollectionIterable; 038import org.ametys.plugins.repository.UnknownAmetysObjectException; 039import org.ametys.plugins.repository.metadata.CompositeMetadata; 040import org.ametys.plugins.userdirectory.UserDirectoryPageHandler; 041import org.ametys.web.repository.page.Page; 042import org.ametys.web.repository.page.UnknownZoneException; 043import org.ametys.web.repository.page.Zone; 044import org.ametys.web.repository.site.Site; 045import org.ametys.web.repository.sitemap.Sitemap; 046import org.ametys.web.skin.SkinsManager; 047 048 049/** 050 * Page representing a second-level page. 051 */ 052public class TransitionalPage implements Page 053{ 054 private Page _root; 055 private String _path; 056 private int _initialDepth; 057 private String _prefix; 058 private AmetysObjectResolver _resolver; 059 private UserDirectoryPageHandler _userDirectoryPageHandler; 060 private SynchronizableContentsCollectionDAO _syncContentsCollectionDAO; 061 private SkinsManager _skinsManager; 062 063 /** 064 * Constructor. 065 * @param root the user directory root page. 066 * @param prefix the page's title. 067 * @param resolver the {@link AmetysObjectResolver}. 068 * @param path the path 069 * @param userDirectoryPageHandler the user directory page handler component 070 * @param syncContentsCollectionDAO The DAO for synchronizable collections 071 * @param skinsManager the skins manager 072 */ 073 public TransitionalPage(Page root, String prefix, String path, AmetysObjectResolver resolver, UserDirectoryPageHandler userDirectoryPageHandler, SynchronizableContentsCollectionDAO syncContentsCollectionDAO, SkinsManager skinsManager) 074 { 075 _root = root; 076 _prefix = prefix; 077 _path = path; 078 _resolver = resolver; 079 _userDirectoryPageHandler = userDirectoryPageHandler; 080 _syncContentsCollectionDAO = syncContentsCollectionDAO; 081 _skinsManager = skinsManager; 082 083 _initialDepth = _userDirectoryPageHandler.getDepth(_root); 084 } 085 086 @Override 087 public int getDepth() throws AmetysRepositoryException 088 { 089 return _root.getDepth() + _path.split("/").length; 090 } 091 092 @Override 093 public Set<String> getReferers() throws AmetysRepositoryException 094 { 095 return null; 096 } 097 098 @Override 099 public ResourceCollection getRootAttachments() throws AmetysRepositoryException 100 { 101 return null; 102 } 103 104 @Override 105 public String getTemplate() throws AmetysRepositoryException 106 { 107 return "page"; 108 } 109 110 @Override 111 public String getTitle() throws AmetysRepositoryException 112 { 113 return StringUtils.upperCase(_prefix); 114 } 115 116 @Override 117 public String getLongTitle() throws AmetysRepositoryException 118 { 119 return StringUtils.upperCase(_prefix); 120 } 121 122 @Override 123 public PageType getType() throws AmetysRepositoryException 124 { 125 return PageType.CONTAINER; 126 } 127 128 @Override 129 public String getURL() throws AmetysRepositoryException 130 { 131 throw new UnsupportedOperationException("getURL not supported on virtual user directory pages"); 132 } 133 134 @Override 135 public LinkType getURLType() throws AmetysRepositoryException 136 { 137 throw new UnsupportedOperationException("getURLType not supported on virtual user directory pages"); 138 } 139 140 @Override 141 public Zone getZone(String name) throws UnknownZoneException, AmetysRepositoryException 142 { 143 if (!"default".equals(name)) 144 { 145 throw new IllegalArgumentException("Only the zone named 'default' is actually supported on virtual transitional pages."); 146 } 147 148 return new TransitionalZone(this); 149 } 150 151 @Override 152 public AmetysObjectIterable< ? extends Zone> getZones() throws AmetysRepositoryException 153 { 154 List<Zone> zones = new ArrayList<>(); 155 zones.add(new TransitionalZone(this)); 156 return new CollectionIterable<>(zones); 157 } 158 159 @Override 160 public boolean hasZone(String name) throws AmetysRepositoryException 161 { 162 return "default".equals(name); 163 } 164 165 @Override 166 public AmetysObjectIterable<? extends Page> getChildrenPages() throws AmetysRepositoryException 167 { 168 ArrayList<Page> children = new ArrayList<>(); 169 170 int depth = _initialDepth - _path.split("/").length; 171 if (depth > 0) 172 { 173 SortedSet<String> transitionalPagesName = _userDirectoryPageHandler.getTransitionalPagesName(_root, _userDirectoryPageHandler.getName(_path)); 174 for (String name : transitionalPagesName) 175 { 176 String pathName = _userDirectoryPageHandler.getPathName(name); 177 children.add(new TransitionalPage(_root, name, _path + "/" + pathName, _resolver, _userDirectoryPageHandler, _syncContentsCollectionDAO, _skinsManager)); 178 } 179 180 Map<String, String> userPagesContent = _userDirectoryPageHandler.getUserPagesContent(_root, _userDirectoryPageHandler.getName(_path)); 181 for (Entry<String, String> entry : userPagesContent.entrySet()) 182 { 183 String contentTypeId = _userDirectoryPageHandler.getContentTypeId(_root); 184 String classificationMetadata = _userDirectoryPageHandler.getClassificationMetadata(_root); 185 Content content; 186 try 187 { 188 content = _resolver.resolveById(entry.getValue()); 189 } 190 catch (AmetysRepositoryException e) 191 { 192 // content does not exist, skip to next iteration 193 break; 194 } 195 if (content == null || !Arrays.asList(content.getTypes()).contains(contentTypeId) || !content.getMetadataHolder().hasMetadata(classificationMetadata)) 196 { 197 break; 198 } 199 200 String metadataValue = _userDirectoryPageHandler.getTransformedClassificationMetadataValue(_root, content); 201 if (metadataValue != null && metadataValue.length() == _path.split("/").length) 202 { 203 children.add(new UserPage(_root, content, _path, _resolver, _userDirectoryPageHandler, _syncContentsCollectionDAO, _skinsManager)); 204 } 205 } 206 } 207 else 208 { 209 Map<String, String> userPagesContent = _userDirectoryPageHandler.getUserPagesContent(_root, _path); 210 for (String contentId : userPagesContent.values()) 211 { 212 try 213 { 214 Content content = _resolver.resolveById(contentId); 215 children.add(new UserPage(_root, content, _path, _resolver, _userDirectoryPageHandler, _syncContentsCollectionDAO, _skinsManager)); 216 } 217 catch (UnknownAmetysObjectException e) 218 { 219 System.out.println("Content does not exist anymore"); 220 } 221 } 222 } 223 224 return new CollectionIterable<>(children); 225 } 226 227 @Override 228 public AmetysObjectIterable< ? extends Page> getChildrenPages(boolean includeInvisiblePage) throws AmetysRepositoryException 229 { 230 if (includeInvisiblePage) 231 { 232 return getChildrenPages(); 233 } 234 else 235 { 236 ArrayList<Page> children = new ArrayList<>(); 237 return new CollectionIterable<>(children); 238 } 239 } 240 241 @Override 242 public String getPathInSitemap() throws AmetysRepositoryException 243 { 244 String path = StringUtils.lowerCase(_path); 245 return _root.getPathInSitemap() + "/" + path; 246 } 247 248 @Override 249 public Site getSite() throws AmetysRepositoryException 250 { 251 return _root.getSite(); 252 } 253 254 @Override 255 public String getSiteName() throws AmetysRepositoryException 256 { 257 return _root.getSiteName(); 258 } 259 260 @Override 261 public Sitemap getSitemap() throws AmetysRepositoryException 262 { 263 return _root.getSitemap(); 264 } 265 266 @Override 267 public String getSitemapName() throws AmetysRepositoryException 268 { 269 return _root.getSitemapName(); 270 } 271 272 @SuppressWarnings("unchecked") 273 @Override 274 public <A extends AmetysObject> A getChild(String path) throws AmetysRepositoryException, UnknownAmetysObjectException 275 { 276 if (path.isEmpty()) 277 { 278 throw new AmetysRepositoryException("path must be non empty"); 279 } 280 281 String completePath = _path + "/" + path; 282 int depth = _initialDepth - completePath.split("/").length + 1; 283 if (depth > 0) 284 { 285 String namePath = StringUtils.substringAfterLast(completePath, "/"); 286 String parentPath = StringUtils.substringBeforeLast(completePath, "/"); 287 288 SortedSet<String> transitionalPagesName = _userDirectoryPageHandler.getTransitionalPagesName(_root, parentPath); 289 Map<String, String> userPagesContent = _userDirectoryPageHandler.getUserPagesContent(_root, parentPath); 290 String name = _userDirectoryPageHandler.getName(namePath); 291 if (transitionalPagesName.contains(name)) 292 { 293 TransitionalPage page = new TransitionalPage(_root, name, completePath, _resolver, _userDirectoryPageHandler, _syncContentsCollectionDAO, _skinsManager); 294 return (A) page; 295 } 296 else if (userPagesContent.containsKey(name)) 297 { 298 String contentId = userPagesContent.get(name); 299 Content syncContent = _resolver.resolveById(contentId); 300 UserPage page = new UserPage(_root, syncContent, parentPath, _resolver, _userDirectoryPageHandler, _syncContentsCollectionDAO, _skinsManager); 301 return (A) page; 302 } 303 else 304 { 305 throw new UnknownAmetysObjectException("No transitional page named " + name + " (full page path " + path + ")."); 306 } 307 } 308 else 309 { 310 String userPath = StringUtils.substringBeforeLast(completePath, "/"); 311 String contentName = StringUtils.substringAfterLast(completePath, "/"); 312 313 Map<String, String> userPagesContent = _userDirectoryPageHandler.getUserPagesContent(_root, userPath); 314 if (userPagesContent.containsKey(contentName)) 315 { 316 Content content = _resolver.resolveById(userPagesContent.get(contentName)); 317 UserPage page = new UserPage(_root, content, userPath, _resolver, _userDirectoryPageHandler, _syncContentsCollectionDAO, _skinsManager); 318 return (A) page; 319 } 320 else 321 { 322 throw new UnknownAmetysObjectException("No user content named " + contentName + " (full page path " + path + ")."); 323 } 324 } 325 } 326 327 @SuppressWarnings("unchecked") 328 @Override 329 public AmetysObjectIterable<? extends AmetysObject> getChildren() throws AmetysRepositoryException 330 { 331 return getChildrenPages(); 332 } 333 334 @Override 335 public boolean hasChild(String name) throws AmetysRepositoryException 336 { 337 int depth = _initialDepth - _path.split("/").length; 338 if (depth > 0) 339 { 340 SortedSet<String> transitionalPagesName = _userDirectoryPageHandler.getTransitionalPagesName(_root, _path); 341 Map<String, String> userPagesContent = _userDirectoryPageHandler.getUserPagesContent(_root, _path); 342 return transitionalPagesName.contains(name) || userPagesContent.containsKey(name); 343 } 344 else 345 { 346 Map<String, String> userPagesContent = _userDirectoryPageHandler.getUserPagesContent(_root, _path); 347 return userPagesContent.containsKey(name); 348 } 349 } 350 351 @Override 352 public String getId() throws AmetysRepositoryException 353 { 354 // E.g: udtransitional://path?rootId=... 355 return "udtransitional://" + _path + "?rootId=" + _root.getId(); 356 } 357 358 @Override 359 public String getName() throws AmetysRepositoryException 360 { 361 return StringUtils.lowerCase(_prefix); 362 } 363 364 @SuppressWarnings("unchecked") 365 @Override 366 public Page getParent() throws AmetysRepositoryException 367 { 368 if (_path.split("/").length > 1) 369 { 370 String parentPath = StringUtils.substringBeforeLast(_path, "/"); 371 String pathName = parentPath; 372 if (StringUtils.contains(pathName, "/")) 373 { 374 pathName = StringUtils.substringAfterLast(pathName, "/"); 375 } 376 377 String name = _userDirectoryPageHandler.getName(pathName); 378 return new TransitionalPage(_root, name, parentPath, _resolver, _userDirectoryPageHandler, _syncContentsCollectionDAO, _skinsManager); 379 } 380 else 381 { 382 return _root; 383 } 384 } 385 386 @Override 387 public String getParentPath() throws AmetysRepositoryException 388 { 389 if (_path.split("/").length > 1) 390 { 391 String path = StringUtils.lowerCase(_path); 392 return _root.getPath() + "/" + StringUtils.substringBeforeLast(path, "/"); 393 } 394 else 395 { 396 return _root.getPath(); 397 } 398 } 399 400 @Override 401 public String getPath() throws AmetysRepositoryException 402 { 403 return getParentPath() + "/" + getName(); 404 } 405 406 @Override 407 public CompositeMetadata getMetadataHolder() 408 { 409 return new StaticCompositeMetadata(); 410 } 411 412 @Override 413 public Set<String> getTags() throws AmetysRepositoryException 414 { 415 return Collections.emptySet(); 416 } 417 418 @Override 419 public boolean isVisible() throws AmetysRepositoryException 420 { 421 return false; 422 } 423 424 @Override 425 public Page getChildPageAt(int index) throws UnknownAmetysObjectException, AmetysRepositoryException 426 { 427 return getChildrenPages().stream().collect(Collectors.toList()).get(index); 428 } 429}