001/* 002 * Copyright 2011 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.blog.repository; 017 018import java.util.ArrayList; 019import java.util.Collections; 020import java.util.HashMap; 021import java.util.Map; 022import java.util.NoSuchElementException; 023import java.util.Set; 024 025import javax.jcr.RepositoryException; 026 027import org.ametys.cms.tag.Tag; 028import org.ametys.cms.tag.TagHelper; 029import org.ametys.cms.tag.TagProviderExtensionPoint; 030import org.ametys.cms.tag.jcr.JCRTag; 031import org.ametys.core.util.I18nUtils; 032import org.ametys.plugins.blog.BlogCacheManager; 033import org.ametys.plugins.explorer.resources.ResourceCollection; 034import org.ametys.plugins.repository.AmetysObject; 035import org.ametys.plugins.repository.AmetysObjectIterable; 036import org.ametys.plugins.repository.AmetysObjectIterator; 037import org.ametys.plugins.repository.AmetysObjectResolver; 038import org.ametys.plugins.repository.AmetysRepositoryException; 039import org.ametys.plugins.repository.CollectionIterable; 040import org.ametys.plugins.repository.EmptyIterable; 041import org.ametys.plugins.repository.TraversableAmetysObject; 042import org.ametys.plugins.repository.UnknownAmetysObjectException; 043import org.ametys.plugins.repository.data.holder.ModelAwareDataHolder; 044import org.ametys.plugins.repository.data.holder.ModelLessDataHolder; 045import org.ametys.plugins.repository.data.holder.impl.DefaultModelLessDataHolder; 046import org.ametys.plugins.repository.data.repositorydata.RepositoryData; 047import org.ametys.plugins.repository.data.repositorydata.impl.MemoryRepositoryData; 048import org.ametys.web.data.type.ModelItemTypeExtensionPoint; 049import org.ametys.web.repository.page.Page; 050import org.ametys.web.repository.page.SitemapElement; 051import org.ametys.web.repository.page.UnknownZoneException; 052import org.ametys.web.repository.page.Zone; 053import org.ametys.web.repository.site.Site; 054import org.ametys.web.repository.sitemap.Sitemap; 055import org.ametys.web.repository.tag.WEBJCRTagProvider; 056import org.ametys.web.service.ServiceExtensionPoint; 057import org.ametys.web.skin.SkinsManager; 058 059/** 060 * Virtual page representing the Post list page. 061 */ 062public class VirtualTagsPage implements Page 063{ 064 065 /** The page name. */ 066 public static final String NAME = "tags"; 067 068 private AmetysObjectResolver _resolver; 069 private BlogCacheManager _cacheManager; 070 private I18nUtils _i18nUtils; 071 private TagProviderExtensionPoint _tagProviderEP; 072 private SitemapElement _root; 073 private SkinsManager _skinsManager; 074 private String _title; 075 076 private ModelItemTypeExtensionPoint _pageDataTypeExtensionPoint; 077 private ModelItemTypeExtensionPoint _zoneDataTypeExtensionPoint; 078 private ServiceExtensionPoint _serviceExtensionPoint; 079 private ModelItemTypeExtensionPoint _zoneItemDataTypeExtensionPoint; 080 081 /** 082 * Constructor. 083 * @param resolver the {@link AmetysObjectResolver}. 084 * @param cacheManager the {@link AmetysObjectResolver}. 085 * @param skinsManager the {@link SkinsManager}. 086 * @param i18nCache the i18n utils 087 * @param tagProviderEP the tags provider 088 * @param root the blog root page. 089 * @param title the page's title. 090 * @param pageDataTypeExtensionPoint the extension point with available data types for pages 091 * @param zoneDataTypeExtensionPoint the extension point with available data types for zones 092 * @param serviceExtensionPoint The service extension point 093 * @param zoneItemDataTypeExtensionPoint the extension point with available data types for zone items 094 */ 095 public VirtualTagsPage(AmetysObjectResolver resolver, BlogCacheManager cacheManager, SkinsManager skinsManager, I18nUtils i18nCache, TagProviderExtensionPoint tagProviderEP, String title, SitemapElement root, ModelItemTypeExtensionPoint pageDataTypeExtensionPoint, ModelItemTypeExtensionPoint zoneDataTypeExtensionPoint, ServiceExtensionPoint serviceExtensionPoint, ModelItemTypeExtensionPoint zoneItemDataTypeExtensionPoint) 096 { 097 _resolver = resolver; 098 _cacheManager = cacheManager; 099 _skinsManager = skinsManager; 100 _i18nUtils = i18nCache; 101 _tagProviderEP = tagProviderEP; 102 _root = root; 103 _title = title; 104 105 _pageDataTypeExtensionPoint = pageDataTypeExtensionPoint; 106 _zoneDataTypeExtensionPoint = zoneDataTypeExtensionPoint; 107 _serviceExtensionPoint = serviceExtensionPoint; 108 _zoneItemDataTypeExtensionPoint = zoneItemDataTypeExtensionPoint; 109 } 110 111 @Override 112 public int getDepth() throws AmetysRepositoryException 113 { 114 int depth = 0; 115 if (_root instanceof Page) 116 { 117 depth = ((Page) _root).getDepth(); 118 } 119 120 return depth + 1; 121 } 122 123 @Override 124 public Set<String> getReferers() throws AmetysRepositoryException 125 { 126 return null; 127 } 128 129 @Override 130 public ResourceCollection getRootAttachments() throws AmetysRepositoryException 131 { 132 return null; 133 } 134 135 @Override 136 public String getTemplate() throws AmetysRepositoryException 137 { 138 return null; 139 } 140 141 @Override 142 public String getTitle() throws AmetysRepositoryException 143 { 144 return _title; 145 } 146 147 @Override 148 public String getLongTitle() throws AmetysRepositoryException 149 { 150 return _title; 151 } 152 153 @Override 154 public PageType getType() throws AmetysRepositoryException 155 { 156 return PageType.NODE; 157 } 158 159 @Override 160 public String getURL() throws AmetysRepositoryException 161 { 162 throw new UnsupportedOperationException("getURL not supported on virtual blog pages"); 163 } 164 165 @Override 166 public LinkType getURLType() throws AmetysRepositoryException 167 { 168 throw new UnsupportedOperationException("getURLType not supported on virtual blog pages"); 169 } 170 171 @Override 172 public Zone getZone(String name) throws UnknownZoneException, AmetysRepositoryException 173 { 174 throw new UnknownZoneException("There is no zone on the blog tags page."); 175 } 176 177 @Override 178 public AmetysObjectIterable< ? extends Zone> getZones() throws AmetysRepositoryException 179 { 180 return new EmptyIterable<>(); 181 } 182 183 @Override 184 public boolean hasZone(String name) throws AmetysRepositoryException 185 { 186 return false; 187 } 188 189 @Override 190 public AmetysObjectIterable<? extends Page> getChildrenPages() throws AmetysRepositoryException 191 { 192 ArrayList<Page> children = new ArrayList<>(); 193 194 Set<String> tagNames = _cacheManager.getTags(getSiteName(), getSitemapName()); 195 196 WEBJCRTagProvider provider = (WEBJCRTagProvider) _tagProviderEP.getExtension(WEBJCRTagProvider.class.getName()); 197 try 198 { 199 Map<String, Object> contextualParams = new HashMap<>(); 200 contextualParams.put("siteName", getSiteName()); 201 202 TraversableAmetysObject rootNode = provider.getRootNode(contextualParams); 203 AmetysObjectIterable<AmetysObject> it = rootNode.getChildren(); 204 for (AmetysObject object : it) 205 { 206 if (object instanceof JCRTag) 207 { 208 String tagName = object.getName(); 209 210 Tag tag = _tagProviderEP.getTag(object.getName(), contextualParams); 211 212 Set<String> descendantAndItSelfNames = TagHelper.getDescendantNames(tag, true); 213 214 if (!Collections.disjoint(tagNames, descendantAndItSelfNames)) 215 { 216 String title = _i18nUtils.translate(tag.getTitle(), getSitemapName()); 217 218 VirtualTagPage page = new VirtualTagPage(_resolver, _cacheManager, _skinsManager, _tagProviderEP, _i18nUtils, tagName, title, _root, _pageDataTypeExtensionPoint, _zoneDataTypeExtensionPoint, _serviceExtensionPoint, _zoneItemDataTypeExtensionPoint); 219 220 children.add(page); 221 } 222 } 223 } 224 } 225 catch (RepositoryException e) 226 { 227 throw new AmetysRepositoryException("Unable to get tags pages", e); 228 } 229 230 return new CollectionIterable<>(children); 231 } 232 233 @Override 234 public AmetysObjectIterable< ? extends Page> getChildrenPages(boolean includeInvisiblePages) throws AmetysRepositoryException 235 { 236 return getChildrenPages(); 237 } 238 239 @Override 240 public Page getChildPageAt(int index) throws UnknownAmetysObjectException, AmetysRepositoryException 241 { 242 if (index < 0) 243 { 244 throw new AmetysRepositoryException("Child page index cannot be negative"); 245 } 246 247 AmetysObjectIterable< ? extends Page> childPages = getChildrenPages(); 248 AmetysObjectIterator< ? extends Page> it = childPages.iterator(); 249 250 try 251 { 252 it.skip(index); 253 return it.next(); 254 } 255 catch (NoSuchElementException e) 256 { 257 throw new UnknownAmetysObjectException("There's no child page at index " + index + " for page " + this.getId()); 258 } 259 } 260 261 @Override 262 public String getPathInSitemap() throws AmetysRepositoryException 263 { 264 StringBuilder path = new StringBuilder(_root.getPathInSitemap()); 265 if (path.length() > 0) 266 { 267 path.append('/'); 268 } 269 path.append(NAME); 270 271 return path.toString(); 272 } 273 274 @Override 275 public Site getSite() throws AmetysRepositoryException 276 { 277 return _root.getSite(); 278 } 279 280 @Override 281 public String getSiteName() throws AmetysRepositoryException 282 { 283 return _root.getSiteName(); 284 } 285 286 @Override 287 public Sitemap getSitemap() throws AmetysRepositoryException 288 { 289 return _root.getSitemap(); 290 } 291 292 @Override 293 public String getSitemapName() throws AmetysRepositoryException 294 { 295 return _root.getSitemapName(); 296 } 297 298 @SuppressWarnings("unchecked") 299 @Override 300 public <A extends AmetysObject> A getChild(String path) throws AmetysRepositoryException, UnknownAmetysObjectException 301 { 302 if (path.isEmpty()) 303 { 304 throw new AmetysRepositoryException("Path must be non empty"); 305 } 306 307 int slashPos = path.indexOf('/'); 308 309 String childName = slashPos == -1 ? path : path.substring(0, slashPos); 310 311 Set<String> tagNames = _cacheManager.getTags(getSiteName(), getSitemapName()); 312 313 Map<String, Object> contextualParams = new HashMap<>(); 314 contextualParams.put("siteName", getSiteName()); 315 316 Tag tag = _tagProviderEP.getTag(childName, contextualParams); 317 if (tag == null) 318 { 319 throw new UnknownAmetysObjectException("No child named " + childName + " exists in parent " + getId()); 320 } 321 322 Set<String> descendantAndItSelfNames = TagHelper.getDescendantNames(tag, true); 323 if (Collections.disjoint(tagNames, descendantAndItSelfNames)) 324 { 325 throw new UnknownAmetysObjectException("No child named " + childName + " exists in parent " + getId()); 326 } 327 328 String title = _i18nUtils.translate(tag.getTitle(), getSitemapName()); 329 330 VirtualTagPage page = new VirtualTagPage(_resolver, _cacheManager, _skinsManager, _tagProviderEP, _i18nUtils, childName, title, _root, _pageDataTypeExtensionPoint, _zoneDataTypeExtensionPoint, _serviceExtensionPoint, _zoneItemDataTypeExtensionPoint); 331 332 if (slashPos == -1) 333 { 334 return (A) page; 335 } 336 else 337 { 338 return (A) page.getChild(path.substring(slashPos + 1)); 339 } 340 } 341 342 @SuppressWarnings("unchecked") 343 @Override 344 public AmetysObjectIterable<? extends AmetysObject> getChildren() throws AmetysRepositoryException 345 { 346 return getChildrenPages(); 347 } 348 349 @Override 350 public boolean hasChild(String name) throws AmetysRepositoryException 351 { 352 return _cacheManager.hasTag(getSiteName(), getSitemapName(), name); 353 } 354 355 @Override 356 public String getId() throws AmetysRepositoryException 357 { 358 return "blog-category://" + NAME + "?rootId=" + _root.getId(); 359 } 360 361 @Override 362 public String getName() throws AmetysRepositoryException 363 { 364 return NAME; 365 } 366 367 @SuppressWarnings("unchecked") 368 @Override 369 public SitemapElement getParent() throws AmetysRepositoryException 370 { 371 return _root; 372 } 373 374 @Override 375 public String getParentPath() throws AmetysRepositoryException 376 { 377 return _root.getPath(); 378 } 379 380 @Override 381 public String getPath() throws AmetysRepositoryException 382 { 383 StringBuilder buff = new StringBuilder(getParentPath()); 384 if (!getParentPath().isEmpty()) 385 { 386 buff.append('/'); 387 } 388 buff.append(NAME); 389 390 return buff.toString(); 391 } 392 393 public ModelLessDataHolder getDataHolder() 394 { 395 RepositoryData repositoryData = new MemoryRepositoryData(getName()); 396 return new DefaultModelLessDataHolder(_pageDataTypeExtensionPoint, repositoryData); 397 } 398 399 @Override 400 public Set<String> getTags() throws AmetysRepositoryException 401 { 402 return Collections.emptySet(); 403 } 404 405 @Override 406 public boolean isVisible() throws AmetysRepositoryException 407 { 408 return true; 409 } 410 411 public ModelAwareDataHolder getTemplateParametersHolder() throws AmetysRepositoryException 412 { 413 return null; 414 } 415}