001/* 002 * Copyright 2015 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.web.cache; 017 018import java.util.ArrayList; 019import java.util.Collection; 020import java.util.Iterator; 021import java.util.List; 022 023import org.apache.avalon.framework.component.Component; 024import org.apache.avalon.framework.logger.AbstractLogEnabled; 025import org.apache.avalon.framework.service.ServiceException; 026import org.apache.avalon.framework.service.ServiceManager; 027import org.apache.avalon.framework.service.Serviceable; 028 029import org.ametys.cms.repository.Content; 030import org.ametys.core.right.RightManager; 031import org.ametys.plugins.repository.AmetysObjectIterable; 032import org.ametys.web.inputdata.InputData; 033import org.ametys.web.inputdata.InputDataExtensionPoint; 034import org.ametys.web.repository.page.Page; 035import org.ametys.web.repository.page.Page.PageType; 036import org.ametys.web.repository.page.SitemapElement; 037import org.ametys.web.repository.page.Zone; 038import org.ametys.web.repository.page.ZoneItem; 039import org.ametys.web.repository.page.ZoneItem.ZoneType; 040import org.ametys.web.repository.site.Site; 041import org.ametys.web.service.Service; 042import org.ametys.web.service.ServiceExtensionPoint; 043 044/** 045 * Helper component providing status of pages. 046 */ 047public class PageHelper extends AbstractLogEnabled implements Component, Serviceable 048{ 049 /** The component role. */ 050 public static final String ROLE = PageHelper.class.getName(); 051 052 private ServiceExtensionPoint _serviceExtPt; 053 private RightManager _rightManager; 054 private InputDataExtensionPoint _inputDataExtensionPoint; 055 056 @Override 057 public void service(ServiceManager serviceManager) throws ServiceException 058 { 059 _serviceExtPt = (ServiceExtensionPoint) serviceManager.lookup(ServiceExtensionPoint.ROLE); 060 _rightManager = (RightManager) serviceManager.lookup(RightManager.ROLE); 061 _inputDataExtensionPoint = (InputDataExtensionPoint) serviceManager.lookup(InputDataExtensionPoint.ROLE); 062 } 063 064 /** 065 * Tests if a page is cacheable, i.e:<ul> 066 * <li>its access is not restricted</li> 067 * <li>all its page elements are cacheable</li> 068 * </ul> 069 * @param page The page to test. 070 * @return true if the page is cacheable, false otherwise. 071 */ 072 public boolean isCacheable(Page page) 073 { 074 String debugStringPrefix = ""; 075 if (getLogger().isDebugEnabled()) 076 { 077 debugStringPrefix = "Page " + page.getSiteName() + "/" + page.getSitemapName() + "/" + page .getTitle() + " (" + page.getId() + ") is "; 078 } 079 080 if (!_rightManager.hasAnonymousReadAccess(page)) 081 { 082 // never cache a private page 083 getLogger().debug(debugStringPrefix + "not cacheable: access is limited"); 084 return false; 085 } 086 087 if (page.getType() != PageType.CONTAINER) 088 { 089 // makes no sense to cache a Node or link page 090 getLogger().debug(debugStringPrefix + "not cacheable: not a container page"); 091 return false; 092 } 093 094 AmetysObjectIterable<? extends Zone> zones = page.getZones(); 095 Iterator<? extends Zone> itZ = zones.iterator(); 096 097 // test each service of the page 098 while (itZ.hasNext()) 099 { 100 Zone zone = itZ.next(); 101 AmetysObjectIterable<? extends ZoneItem> zoneItems = zone.getZoneItems(); 102 Iterator<? extends ZoneItem> itZI = zoneItems.iterator(); 103 104 while (itZI.hasNext()) 105 { 106 ZoneItem zoneItem = itZI.next(); 107 if (zoneItem.getType() == ZoneType.SERVICE) 108 { 109 Service service = _serviceExtPt.getExtension(zoneItem.getServiceId()); 110 try 111 { 112 // null service is cacheable 113 if (service != null && !service.isCacheable(page, zoneItem)) 114 { 115 getLogger().debug(debugStringPrefix + "not cacheable: due to service " + zoneItem.getServiceId() + " (" + zoneItem.getId() + ")"); 116 return false; 117 } 118 } 119 catch (Exception e) 120 { 121 // Ignore 122 } 123 } 124 } 125 } 126 127 // Test each inputdata 128 Collection<String> ids = _inputDataExtensionPoint.getExtensionsIds(); 129 Iterator<String> it = ids.iterator(); 130 while (it.hasNext()) 131 { 132 String id = it.next(); 133 InputData inputData = _inputDataExtensionPoint.getExtension(id); 134 if (!inputData.isCacheable(page.getSite(), page)) 135 { 136 getLogger().debug(debugStringPrefix + "not cacheable: due to inputdata " + id); 137 return false; 138 } 139 } 140 141 getLogger().debug(debugStringPrefix + "cacheable"); 142 return true; 143 } 144 145 /** 146 * Determines if a captcha is required on forms of the page 147 * @param page The page to test 148 * @return true if a captcha is required 149 */ 150 public boolean isCaptchaRequired (SitemapElement page) 151 { 152 Site site = page.getSite(); 153 154 String captchaPolicy = site.getValue("display-captcha-policy"); 155 156 if (captchaPolicy == null || "restricted".equals(captchaPolicy)) 157 { 158 // Display captcha on public page only 159 return _rightManager.hasAnonymousReadAccess(page); 160 } 161 162 return "always".equals(captchaPolicy); 163 } 164 165 /** 166 * Get all the contents inside a page 167 * @param page page to search 168 * @return list of contents in this page 169 */ 170 public List<Content> getAllContents (Page page) 171 { 172 List<Content> result = new ArrayList<>(); 173 AmetysObjectIterable< ? extends Zone> zones = page.getZones(); 174 for (Zone zone : zones) 175 { 176 AmetysObjectIterable< ? extends ZoneItem> zoneItems = zone.getZoneItems(); 177 for (ZoneItem zoneItem : zoneItems) 178 { 179 if (ZoneType.CONTENT.equals(zoneItem.getType())) 180 { 181 Content content = zoneItem.getContent(); 182 result.add(content); 183 } 184 } 185 } 186 return result; 187 } 188 189}