001/* 002 * Copyright 2012 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; 017 018import java.util.HashMap; 019import java.util.Iterator; 020import java.util.LinkedHashSet; 021import java.util.Map; 022import java.util.Set; 023 024import javax.jcr.Node; 025import javax.jcr.RepositoryException; 026import javax.jcr.Value; 027 028import org.apache.avalon.framework.activity.Initializable; 029import org.apache.avalon.framework.component.Component; 030import org.apache.avalon.framework.logger.AbstractLogEnabled; 031import org.apache.avalon.framework.service.ServiceException; 032import org.apache.avalon.framework.service.ServiceManager; 033import org.apache.avalon.framework.service.Serviceable; 034 035import org.ametys.plugins.blog.repository.BlogRootPageFactory; 036import org.ametys.plugins.blog.repository.VirtualPostsPage; 037import org.ametys.plugins.blog.repository.VirtualTagsPage; 038import org.ametys.plugins.repository.AmetysObjectIterable; 039import org.ametys.plugins.repository.AmetysObjectResolver; 040import org.ametys.plugins.repository.AmetysRepositoryException; 041import org.ametys.plugins.repository.UnknownAmetysObjectException; 042import org.ametys.plugins.repository.jcr.JCRAmetysObject; 043import org.ametys.plugins.repository.query.expression.Expression; 044import org.ametys.plugins.repository.query.expression.VirtualFactoryExpression; 045import org.ametys.web.repository.content.WebContent; 046import org.ametys.web.repository.page.Page; 047import org.ametys.web.repository.page.PageQueryHelper; 048import org.ametys.web.repository.page.PagesContainer; 049import org.ametys.web.repository.site.Site; 050import org.ametys.web.repository.site.SiteManager; 051import org.ametys.web.repository.sitemap.Sitemap; 052 053/** 054 * Retrieves blog pages. 055 */ 056public class BlogPageHandler extends AbstractLogEnabled implements Component, Initializable, Serviceable 057{ 058 059 /** The avalon role. */ 060 public static final String ROLE = BlogPageHandler.class.getName(); 061 062 /** The ametys object resolver. */ 063 protected AmetysObjectResolver _resolver; 064 065 /** The site manager. */ 066 protected SiteManager _siteManager; 067 068 /** The blog root page IDs, indexed by site and sitemap name. */ 069 protected Map<String, Map<String, String>> _blogRootPages; 070 071 /** For each site, indicate if a blog root is present. */ 072 protected Map<String, Boolean> _hasBlogRoot; 073 074 @Override 075 public void service(ServiceManager serviceManager) throws ServiceException 076 { 077 _resolver = (AmetysObjectResolver) serviceManager.lookup(AmetysObjectResolver.ROLE); 078 _siteManager = (SiteManager) serviceManager.lookup(SiteManager.ROLE); 079 } 080 081 @Override 082 public void initialize() throws Exception 083 { 084 _blogRootPages = new HashMap<>(); 085 _hasBlogRoot = new HashMap<>(); 086 } 087 088 /** 089 * Get the blog root page. 090 * @param siteName the current site. 091 * @param sitemapName the current sitemap/language. 092 * @return the blog root page or null if not found. 093 * @throws AmetysRepositoryException if an error occurs. 094 */ 095 public PagesContainer getBlogRootPage(String siteName, String sitemapName) throws AmetysRepositoryException 096 { 097 PagesContainer rootPage = null; 098 099 Map<String, String> siteBlogRootPages = null; 100 101 if (_blogRootPages.containsKey(siteName)) 102 { 103 siteBlogRootPages = _blogRootPages.get(siteName); 104 } 105 else 106 { 107 siteBlogRootPages = new HashMap<>(); 108 _blogRootPages.put(siteName, siteBlogRootPages); 109 } 110 111 if (siteBlogRootPages.containsKey(sitemapName)) 112 { 113 String rootId = siteBlogRootPages.get(sitemapName); 114 if (rootId != null) 115 { 116 rootPage = _resolver.resolveById(rootId); 117 } 118 } 119 else 120 { 121 rootPage = _getBlogRootPage(siteName, sitemapName); 122 siteBlogRootPages.put(sitemapName, rootPage == null ? null : rootPage.getId()); 123 } 124 125 return rootPage; 126 } 127 128 /** 129 * Test if the given site has at least one sitemap with a blog root page. 130 * @param site the site to test. 131 * @return true if the site has at least one sitemap with a blog root page, false otherwise. 132 */ 133 public boolean hasBlogRootPage(Site site) 134 { 135 boolean hasOneRoot = false; 136 137 String siteName = site.getName(); 138 139 if (_hasBlogRoot.containsKey(siteName)) 140 { 141 hasOneRoot = _hasBlogRoot.get(siteName); 142 } 143 else 144 { 145 Iterator<Sitemap> sitemaps = site.getSitemaps().iterator(); 146 147 while (sitemaps.hasNext() && !hasOneRoot) 148 { 149 String sitemapName = sitemaps.next().getName(); 150 151 if (getBlogRootPage(site.getName(), sitemapName) != null) 152 { 153 hasOneRoot = true; 154 } 155 } 156 157 _hasBlogRoot.put(siteName, hasOneRoot); 158 } 159 160 return hasOneRoot; 161 } 162 163 /** 164 * Test if the given page is the blog root page. 165 * @param ametysObject the container ametysObject. 166 * @return true/false. 167 */ 168 public boolean isBlogRootPage(JCRAmetysObject ametysObject) 169 { 170 try 171 { 172 Node node = ametysObject.getNode(); 173 174 if (node.hasProperty(AmetysObjectResolver.VIRTUAL_PROPERTY)) 175 { 176 Value[] values = node.getProperty(AmetysObjectResolver.VIRTUAL_PROPERTY).getValues(); 177 178 boolean hasValue = false; 179 for (int i = 0; i < values.length && !hasValue; i++) 180 { 181 hasValue = BlogRootPageFactory.class.getName().equals(values[i].getString()); 182 } 183 184 return hasValue; 185 } 186 else 187 { 188 return false; 189 } 190 } 191 catch (RepositoryException e) 192 { 193 return false; 194 } 195 } 196 197 /** 198 * Get a page under the blog root. 199 * @param site the current site. 200 * @param language the current language/sitemap. 201 * @param pagePath the wanted page path. 202 * @return the blog page or null if not found. 203 * @throws AmetysRepositoryException if an error occurs 204 */ 205 public Page getBlogPage(String site, String language, String pagePath) throws AmetysRepositoryException 206 { 207 Page page = null; 208 209 PagesContainer rootPage = getBlogRootPage(site, language); 210 if (rootPage != null) 211 { 212 if (rootPage.hasChild(pagePath)) 213 { 214 page = rootPage.getChild(pagePath); 215 } 216 } 217 218 return page; 219 } 220 221 /** 222 * Get the Page holding the given post content. 223 * @param postContent the post content. 224 * @return the Page holding the post content. 225 */ 226 public Page getPostPage(WebContent postContent) 227 { 228 String siteName = postContent.getSiteName(); 229 String language = postContent.getLanguage(); 230 String postName = postContent.getName(); 231 232 PagesContainer rootPage = getBlogRootPage(siteName, language); 233 Page postsPage = rootPage.getChild(VirtualPostsPage.NAME); 234 235 Page postPage = null; 236 if (postsPage.hasChild(postName)) 237 { 238 postPage = postsPage.getChild(postName); 239 } 240 241 return postPage; 242 } 243 244 /** 245 * Get the page holding the given tag 246 * @param siteName The site's name 247 * @param lang The language 248 * @param tagPath The tag's path 249 * @return The page holding this tag or null if not exists 250 */ 251 public Page getTagPage (String siteName, String lang, String tagPath) 252 { 253 try 254 { 255 PagesContainer rootPage = getBlogRootPage(siteName, lang); 256 Page tagsPage = rootPage.getChild(VirtualTagsPage.NAME); 257 258 return tagsPage.getChild(tagPath); 259 } 260 catch (UnknownAmetysObjectException e) 261 { 262 return null; 263 } 264 } 265 266 /** 267 * Get the pages corresponding to the post Content. 268 * @param postContent the post Content. 269 * @return the post pages. 270 */ 271 @Deprecated 272 public Set<Page> getPostPages(WebContent postContent) 273 { 274 Set<Page> postPages = new LinkedHashSet<>(); 275 276 Page postPage = getPostPage(postContent); 277 if (postPage != null) 278 { 279 postPages.add(postPage); 280 } 281 282 return postPages; 283 } 284 285 /** 286 * Clear the blog root page cache. 287 */ 288 public void clearCache() 289 { 290 _blogRootPages = new HashMap<>(); 291 _hasBlogRoot = new HashMap<>(); 292 } 293 294 /** 295 * Clear the blog root page cache for a given site and language. 296 * @param siteName the current site. 297 * @param sitemapName the current sitemap/language. 298 */ 299 public void clearCache(String siteName, String sitemapName) 300 { 301 if (_blogRootPages.containsKey(siteName)) 302 { 303 _blogRootPages.get(siteName).remove(sitemapName); 304 } 305 306 _hasBlogRoot.remove(siteName); 307 } 308 309 /** 310 * Get the blog root page. 311 * @param siteName the current site. 312 * @param sitemapName the current sitemap/language. 313 * @return the blog root page or null if not found. 314 * @throws AmetysRepositoryException if an error occurs. 315 */ 316 protected PagesContainer _getBlogRootPage(String siteName, String sitemapName) throws AmetysRepositoryException 317 { 318 PagesContainer page = null; 319 320 // First, test if the sitemap is the blog root. 321 Sitemap sitemap = _siteManager.getSite(siteName).getSitemap(sitemapName); 322 if (isBlogRootPage(sitemap)) 323 { 324 page = sitemap; 325 } 326 else 327 { 328 Expression expression = new VirtualFactoryExpression(BlogRootPageFactory.class.getName()); 329 330 String query = PageQueryHelper.getPageXPathQuery(siteName, sitemapName, null, expression, null); 331 332 AmetysObjectIterable<PagesContainer> pages = _resolver.query(query); 333 Iterator<PagesContainer> it = pages.iterator(); 334 if (it.hasNext()) 335 { 336 page = it.next(); 337 } 338 } 339 340 return page; 341 } 342}