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