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.site; 017 018import java.util.Map; 019 020import org.apache.avalon.framework.parameters.Parameters; 021import org.apache.avalon.framework.service.ServiceException; 022import org.apache.avalon.framework.service.ServiceManager; 023import org.apache.avalon.framework.thread.ThreadSafe; 024import org.apache.cocoon.acting.ServiceableAction; 025import org.apache.cocoon.environment.ObjectModelHelper; 026import org.apache.cocoon.environment.Redirector; 027import org.apache.cocoon.environment.Request; 028import org.apache.cocoon.environment.SourceResolver; 029import org.apache.excalibur.source.Source; 030import org.apache.excalibur.source.SourceNotFoundException; 031import org.apache.excalibur.source.TraversableSource; 032import org.apache.excalibur.source.impl.FileSource; 033import org.slf4j.Logger; 034import org.slf4j.LoggerFactory; 035 036import org.ametys.plugins.site.cache.monitoring.Constants; 037import org.ametys.plugins.site.cache.monitoring.process.access.ResourceAccessComponent; 038import org.ametys.plugins.site.cache.monitoring.process.access.impl.FrontResourceAccess; 039 040/** 041 * Blocks until the cacheable status is known. 042 */ 043public class IsPageCacheableAction extends ServiceableAction implements ThreadSafe 044{ 045 /** The cache access component. */ 046 protected CacheAccessManager _cacheAccess; 047 048 /** The resource access monitoring component */ 049 protected ResourceAccessComponent _resourceAccessComponent; 050 051 /** The source resolver. */ 052 protected SourceResolver _resolver; 053 054 private final Logger _logger = LoggerFactory.getLogger("site.cache.log"); 055 056 @Override 057 public void service(ServiceManager serviceManager) throws ServiceException 058 { 059 super.service(serviceManager); 060 _cacheAccess = (CacheAccessManager) serviceManager.lookup(CacheAccessManager.ROLE); 061 _resourceAccessComponent = (ResourceAccessComponent) serviceManager.lookup(ResourceAccessComponent.ROLE); 062 } 063 064 @Override 065 public Map act(Redirector redirector, SourceResolver resolver, Map objectModel, String source, Parameters parameters) throws Exception 066 { 067 try 068 { 069 // Block until known if the page is cacheable. 070 boolean cacheable = _cacheAccess.isCacheable(source); 071 072 Request request = ObjectModelHelper.getRequest(objectModel); 073 074 if (_logger.isDebugEnabled()) 075 { 076 String uniqueId = request.getHeader("UNIQUE_ID"); 077 if (uniqueId != null) 078 { 079 _logger.debug(uniqueId + " - cacheable : " + cacheable); 080 } 081 } 082 083 // Resource monitoring 084 FrontResourceAccess fra = (FrontResourceAccess) request.getAttribute(Constants.REQUEST_ATTRIBUTE_PAGEACCESS); 085 fra.setCacheable(cacheable); 086 087 // If the page isn't cacheable, unlock and generate (return null). 088 String resourceURI = parameters.getParameter("uri", ""); 089 if (!cacheable) 090 { 091 _resourceAccessComponent.addAccessRecord(fra); 092 093 _cacheAccess.unlock(source); 094 return null; 095 } 096 // If cacheable and the resource exists, we don't have to generate it. 097 else if (cacheable && _resourceExists(resolver, resourceURI)) 098 { 099 fra.setCacheHit2(true); 100 _resourceAccessComponent.addAccessRecord(fra); 101 102 _cacheAccess.unlock(source); 103 return EMPTY_MAP; 104 } 105 106 // Else, return null: the page will be generated into the cache and unlocked when it's done. 107 fra.setCacheHit2(false); 108 _resourceAccessComponent.addAccessRecord(fra); 109 110 return null; 111 } 112 catch (Exception e) 113 { 114 _cacheAccess.unlock(source); 115 throw e; 116 } 117 } 118 119 /** 120 * Tests if the resource exists. 121 * @param resolver the resolver. 122 * @param resourceURI the resource uri. 123 * @return true if the resource exists, false otherwise. 124 */ 125 protected boolean _resourceExists(SourceResolver resolver, String resourceURI) 126 { 127 boolean exists = false; 128 129 Source source = null; 130 try 131 { 132 source = resolver.resolveURI(resourceURI); 133 134 if (source instanceof FileSource && !SiteCacheHelper.isValid((FileSource) source)) 135 { 136 // Release the old source and replace it by a hashed file source. 137 source = SiteCacheHelper.getHashedFileSource(resolver, (FileSource) source); 138 } 139 140 if (source.exists() && (!(source instanceof TraversableSource) || !((TraversableSource) source).isCollection())) 141 { 142 exists = true; 143 } 144 } 145 catch (SourceNotFoundException e) 146 { 147 // Do not log 148 } 149 catch (Exception e) 150 { 151 getLogger().warn("Exception resolving resource " + resourceURI, e); 152 } 153 finally 154 { 155 if (source != null) 156 { 157 resolver.release(source); 158 } 159 } 160 161 return exists; 162 } 163}