001/*
002 *  Copyright 2010 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 */
016
017package org.ametys.site;
018
019import java.util.Map;
020import java.util.UUID;
021
022import org.apache.avalon.framework.parameters.Parameters;
023import org.apache.avalon.framework.service.ServiceException;
024import org.apache.avalon.framework.thread.ThreadSafe;
025import org.apache.cocoon.acting.ServiceableAction;
026import org.apache.cocoon.environment.ObjectModelHelper;
027import org.apache.cocoon.environment.Redirector;
028import org.apache.cocoon.environment.Request;
029import org.apache.cocoon.environment.SourceResolver;
030import org.apache.commons.lang.StringUtils;
031import org.apache.excalibur.source.Source;
032import org.apache.excalibur.source.SourceNotFoundException;
033import org.apache.excalibur.source.TraversableSource;
034import org.apache.excalibur.source.impl.FileSource;
035import org.slf4j.Logger;
036import org.slf4j.LoggerFactory;
037
038import org.ametys.plugins.site.cache.monitoring.Constants;
039import org.ametys.plugins.site.cache.monitoring.process.access.ResourceAccessComponent;
040import org.ametys.plugins.site.cache.monitoring.process.access.impl.FrontResourceAccess;
041
042/**
043 * The cocoon resource exists action but that returns false for folders
044 */
045public class ResourceExistsAction extends ServiceableAction implements ThreadSafe
046{
047    /** The resource access monitoring component */
048    protected ResourceAccessComponent _resourceAccessComponent;
049
050    // FIXME static final logger?
051    private final Logger _logger = LoggerFactory.getLogger("site.cache.log");
052
053    /**
054     * Get the resource access component
055     * @return the ResourceAccessComponent
056     */
057    protected ResourceAccessComponent _getResourceAccessComponent()
058    {
059        if (_resourceAccessComponent == null)
060        {
061            try
062            {
063                _resourceAccessComponent = (ResourceAccessComponent) manager.lookup(ResourceAccessComponent.ROLE);
064            }
065            catch (ServiceException e)
066            {
067                throw new IllegalStateException("Cannot get ResourceAccessComponent", e);
068            }
069        }
070        return _resourceAccessComponent;
071    }
072
073    @Override
074    public Map act(Redirector redirector, SourceResolver resolver, Map objectModel, String src, Parameters parameters) throws Exception
075    {
076        Request request = ObjectModelHelper.getRequest(objectModel);
077        
078        // First, only consider HEAD and GET methods
079        String method = request.getMethod();
080        
081        if (!method.equals("HEAD") && !method.equals("GET"))
082        {
083            return null;
084        }
085        
086        String resourceURI = parameters.getParameter("url", src);
087        Source source = null;
088
089        // Resource monitoring
090        // the Apache mod_unique_id set a request header "UNIQUE_ID"
091        // that we could use to track request in log files
092        String uniqueId = request.getHeader("UNIQUE_ID");
093
094        // Set the random uuid as a request attribute to be added later in the possible requests to the BO.
095        String uuid = UUID.randomUUID().toString();
096        request.setAttribute("Monitoring-UUID", uuid);
097        
098        String path = resourceURI;
099        if (StringUtils.startsWith(path, "ametys-home://cache"))
100        {
101            path = StringUtils.removeStart(path, "ametys-home://cache");
102        }
103        else
104        {
105            path = StringUtils.removeStart(resourceURI, SiteCacheHelper.getRootCache().getPath());
106        }
107        
108        FrontResourceAccess fra = new FrontResourceAccess(uniqueId, uuid, parameters.getParameter("site", null), path);
109        
110        try
111        {
112            source = resolver.resolveURI(resourceURI);
113
114            if (source instanceof FileSource && !SiteCacheHelper.isValid((FileSource) source))
115            {
116                // Release the old source and replace it by a hashed file source.
117                source = SiteCacheHelper.getHashedFileSource(resolver, (FileSource) source);
118            }
119
120            if (source.exists()
121                    && (!(source instanceof TraversableSource) || !((TraversableSource) source).isCollection()))
122            {
123                if (_logger.isDebugEnabled())
124                {
125                    _logger.debug("Find resource '" + resourceURI + " in cache");
126                }
127
128                fra.setCacheable(true);
129                fra.setCacheHit1(true);
130                _getResourceAccessComponent().addAccessRecord(fra);
131
132                return EMPTY_MAP;
133            }
134        }
135        catch (SourceNotFoundException e)
136        {
137            // Do not log
138        }
139        catch (Exception e)
140        {
141            getLogger().warn("Exception resolving resource " + resourceURI, e);
142        }
143        finally
144        {
145            if (source != null)
146            {
147                resolver.release(source);
148            }
149        }
150
151        fra.setCacheHit1(false);
152        request.setAttribute(Constants.REQUEST_ATTRIBUTE_PAGEACCESS, fra);
153
154        return null;
155    }
156
157}