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