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