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.plugins.odfweb.repository; 017 018import java.util.ArrayList; 019import java.util.Arrays; 020import java.util.Collections; 021import java.util.List; 022import java.util.NoSuchElementException; 023import java.util.Optional; 024import java.util.Set; 025import java.util.stream.Collectors; 026 027import org.apache.commons.lang3.StringUtils; 028 029import org.ametys.cms.FilterNameHelper; 030import org.ametys.odf.program.Program; 031import org.ametys.plugins.explorer.resources.ResourceCollection; 032import org.ametys.plugins.repository.AmetysObject; 033import org.ametys.plugins.repository.AmetysObjectIterable; 034import org.ametys.plugins.repository.AmetysObjectIterator; 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.web.repository.page.Page; 041import org.ametys.web.repository.page.UnknownZoneException; 042import org.ametys.web.repository.page.Zone; 043import org.ametys.web.repository.site.Site; 044import org.ametys.web.repository.sitemap.Sitemap; 045 046import com.google.common.collect.Iterables; 047 048/** 049 * Page representing a second-level page. 050 */ 051public class SecondLevelPage implements Page 052{ 053 private AmetysObjectResolver _resolver; 054 private ODFPageCache _odfPageCache; 055 private Page _root; 056 private String _name; 057 private String _title; 058 private String _level1; 059 private OdfPageHandler _odfPageHandler; 060 private FirstLevelPage _level1Page; 061 062 /** 063 * Constructor. 064 * @param resolver the {@link AmetysObjectResolver}. 065 * @param odfPageCache the {@link ODFPageCache}. 066 * @param root the odf root page. 067 * @param level1Key the parent first level code (name) 068 * @param name the page's name. 069 * @param title the page's title. 070 * @param odfPageHandler the ODF page handler. 071 */ 072 public SecondLevelPage(AmetysObjectResolver resolver, ODFPageCache odfPageCache, Page root, String level1Key, String name, String title, OdfPageHandler odfPageHandler) 073 { 074 this(resolver, odfPageCache, root, level1Key, name, title, odfPageHandler, null); 075 } 076 077 /** 078 * Constructor. 079 * @param resolver the {@link AmetysObjectResolver}. 080 * @param odfPageCache the {@link ODFPageCache}. 081 * @param root the odf root page. 082 * @param level1Key the parent first level code (name) 083 * @param name the page's name. 084 * @param title the page's title. 085 * @param odfPageHandler the ODF page handler. 086 * @param firstLevelPage The parent first level page. 087 */ 088 public SecondLevelPage(AmetysObjectResolver resolver, ODFPageCache odfPageCache, Page root, String level1Key, String name, String title, OdfPageHandler odfPageHandler, FirstLevelPage firstLevelPage) 089 { 090 _resolver = resolver; 091 _odfPageCache = odfPageCache; 092 _root = root; 093 _name = name; 094 _title = title; 095 _level1 = level1Key; 096 _odfPageHandler = odfPageHandler; 097 _level1Page = firstLevelPage; 098 } 099 100 @Override 101 public int getDepth() throws AmetysRepositoryException 102 { 103 return _root.getDepth() + 2; 104 } 105 106 @Override 107 public Set<String> getReferers() throws AmetysRepositoryException 108 { 109 return null; 110 } 111 112 @Override 113 public ResourceCollection getRootAttachments() throws AmetysRepositoryException 114 { 115 return null; 116 } 117 118 @Override 119 public String getTemplate() throws AmetysRepositoryException 120 { 121 // TODO 122 return "program-list"; 123 } 124 125 @Override 126 public String getTitle() throws AmetysRepositoryException 127 { 128 return _title; 129 } 130 131 @Override 132 public String getLongTitle() throws AmetysRepositoryException 133 { 134 return getParent().getTitle() + " - " + _title; 135 } 136 137 @Override 138 public PageType getType() throws AmetysRepositoryException 139 { 140 return PageType.CONTAINER; 141 } 142 143 @Override 144 public String getURL() throws AmetysRepositoryException 145 { 146 throw new UnsupportedOperationException("getURL not supported on virtual odf pages"); 147 } 148 149 @Override 150 public LinkType getURLType() throws AmetysRepositoryException 151 { 152 throw new UnsupportedOperationException("getURLType not supported on virtual odf pages"); 153 } 154 155 @Override 156 public Zone getZone(String name) throws UnknownZoneException, AmetysRepositoryException 157 { 158 if (!"default".equals(name)) 159 { 160 throw new IllegalArgumentException("Only the zone named 'default' is actually supported on virtual program pages."); 161 } 162 163 return new SecondLevelZone(this); 164 } 165 166 @Override 167 public AmetysObjectIterable<? extends Zone> getZones() throws AmetysRepositoryException 168 { 169 ArrayList<Zone> zones = new ArrayList<>(); 170 zones.add(new SecondLevelZone(this)); 171 return new CollectionIterable<>(zones); 172 } 173 174 @Override 175 public boolean hasZone(String name) throws AmetysRepositoryException 176 { 177 return "default".equals(name); 178 } 179 180 @Override 181 public AmetysObjectIterable<? extends Page> getChildrenPages() throws AmetysRepositoryException 182 { 183 List<ProgramPage> pages = _getChildrenFromCache() 184 .orElseGet(() -> _odfPageHandler.getProgramsWithRestrictions(_root, _level1, _name, null)) 185 .stream() 186 .map(this::_toProgramPage) 187 .collect(Collectors.toList()); 188 189 return new CollectionIterable<>(pages); 190 } 191 192 private Optional<AmetysObjectIterable<Program>> _getChildrenFromCache() 193 { 194 return Optional.ofNullable(_odfPageCache.getProgramCache(_root, false)) 195 .map(firstLevelCache -> firstLevelCache.get(_level1)) 196 .map(secondLevelCache -> secondLevelCache.get(_name)) 197 .map(CollectionIterable<Program>::new); 198 } 199 200 private ProgramPage _toProgramPage(Program program) 201 { 202 return new ProgramPage(_resolver, _odfPageHandler, _root, program, null, null, this); 203 } 204 205 @Override 206 public String getPathInSitemap() throws AmetysRepositoryException 207 { 208 return _root.getPathInSitemap() + "/" + getParent().getName() + "/" + getName(); 209 } 210 211 @Override 212 public Site getSite() throws AmetysRepositoryException 213 { 214 return _root.getSite(); 215 } 216 217 @Override 218 public String getSiteName() throws AmetysRepositoryException 219 { 220 return _root.getSiteName(); 221 } 222 223 @Override 224 public Sitemap getSitemap() throws AmetysRepositoryException 225 { 226 return _root.getSitemap(); 227 } 228 229 @Override 230 public String getSitemapName() throws AmetysRepositoryException 231 { 232 return _root.getSitemapName(); 233 } 234 235 @SuppressWarnings("unchecked") 236 @Override 237 public <A extends AmetysObject> A getChild(String path) throws AmetysRepositoryException, UnknownAmetysObjectException 238 { 239 List<String> headQueuePath = Arrays.asList(StringUtils.split(path, "/", 2)); 240 String queuePath = Iterables.get(headQueuePath, 1, null); 241 242 String pageName = headQueuePath.get(0); 243 244 int j = pageName.lastIndexOf("program-"); 245 String programName = j == -1 ? pageName : pageName.substring(j); 246 247 return (A) _getChildFromCache(programName) 248 .<Page>map(this::_toProgramPage) 249 .map(page -> StringUtils.isEmpty(queuePath) ? page : page.getChild(queuePath)) 250 .orElseThrow(() -> 251 new UnknownAmetysObjectException("There's no content named " + programName)); 252 } 253 254 private Optional<Program> _getChildFromCache(String programName) 255 { 256 return Optional.ofNullable(_odfPageCache.getProgram(_root, _level1, _name, programName)); 257 } 258 259 @SuppressWarnings("unchecked") 260 @Override 261 public AmetysObjectIterable<? extends AmetysObject> getChildren() throws AmetysRepositoryException 262 { 263 return getChildrenPages(); 264 } 265 266 @Override 267 public boolean hasChild(String name) throws AmetysRepositoryException 268 { 269 return _getChildFromCache(name).isPresent(); 270 } 271 272 @Override 273 public String getId() throws AmetysRepositoryException 274 { 275 // E.g: odfLevel2://XA/ALL?rootId=... 276 return "odfLevel2://" + _odfPageHandler.encodeLevelValue(_level1) + "/" + _odfPageHandler.encodeLevelValue(_name) + "?rootId=" + _root.getId(); 277 } 278 279 @Override 280 public String getName() throws AmetysRepositoryException 281 { 282 // E.g: arts-lettres-langues-ALL 283 return FilterNameHelper.filterName(_title) + "-" + _odfPageHandler.encodeLevelValue(_name); 284 } 285 286 @SuppressWarnings("unchecked") 287 @Override 288 public Page getParent() throws AmetysRepositoryException 289 { 290 return _level1Page != null ? _level1Page : (Page) _root.getChild(_odfPageHandler.encodeLevelValue(_level1)); 291 } 292 293 @Override 294 public String getParentPath() throws AmetysRepositoryException 295 { 296 return _root.getPath() + "/" + getParent().getName(); 297 } 298 299 @Override 300 public String getPath() throws AmetysRepositoryException 301 { 302 return getParentPath() + "/" + getName(); 303 } 304 305 @Override 306 public CompositeMetadata getMetadataHolder() 307 { 308 return new StaticCompositeMetadata(); 309 } 310 311 @Override 312 public Set<String> getTags() throws AmetysRepositoryException 313 { 314 return Collections.emptySet(); 315 } 316 317 @Override 318 public boolean isVisible() throws AmetysRepositoryException 319 { 320 return true; 321 } 322 323 @Override 324 public AmetysObjectIterable< ? extends Page> getChildrenPages(boolean includeInvisiblePages) throws AmetysRepositoryException 325 { 326 return getChildrenPages(); 327 } 328 329 @Override 330 public Page getChildPageAt(int index) throws UnknownAmetysObjectException, AmetysRepositoryException 331 { 332 if (index < 0) 333 { 334 throw new AmetysRepositoryException("Child page index cannot be negative"); 335 } 336 337 AmetysObjectIterator<? extends Page> childPages = getChildrenPages().iterator(); 338 339 try 340 { 341 childPages.skip(index); 342 return childPages.next(); 343 } 344 catch (NoSuchElementException e) 345 { 346 throw new UnknownAmetysObjectException("There's no child page at index " + index + " for page " + this.getId()); 347 } 348 } 349}