001/*
002 *  Copyright 2016 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.core.resources;
017
018import java.io.IOException;
019import java.io.Serializable;
020import java.util.Map;
021
022import org.apache.avalon.framework.context.Context;
023import org.apache.avalon.framework.context.ContextException;
024import org.apache.avalon.framework.context.Contextualizable;
025import org.apache.avalon.framework.parameters.Parameters;
026import org.apache.avalon.framework.service.ServiceException;
027import org.apache.avalon.framework.service.ServiceManager;
028import org.apache.avalon.framework.service.Serviceable;
029import org.apache.cocoon.Constants;
030import org.apache.cocoon.ProcessingException;
031import org.apache.cocoon.caching.CacheableProcessingComponent;
032import org.apache.cocoon.components.LifecycleHelper;
033import org.apache.cocoon.environment.ObjectModelHelper;
034import org.apache.cocoon.environment.Response;
035import org.apache.cocoon.reading.AbstractReader;
036import org.apache.excalibur.source.Source;
037import org.apache.excalibur.source.SourceResolver;
038import org.apache.excalibur.source.SourceValidity;
039import org.xml.sax.SAXException;
040
041import org.ametys.core.cocoon.source.NamedSource;
042import org.ametys.core.util.URIUtils;
043
044/**
045 * Default resource reader, that handle different resources type using the ResourcesExtensionPoint.
046 */
047public class ResourceReader extends AbstractReader implements CacheableProcessingComponent, Serviceable, Contextualizable
048{
049    /** last modified parameter name for resources parameters */
050    public static final String LAST_MODIFIED = "lastModified";
051    
052    private SourceResolver _resolver;
053    private org.apache.cocoon.environment.Context _cocoonContext;
054
055    private ResourceHandlerProviderExtensionPoint _resourcesHandlerEP;
056    private ResourceHandler _resourceHandler;
057
058    private Source _source;
059    private boolean _readForDownload;
060    
061    public void contextualize(Context context) throws ContextException
062    {
063        _cocoonContext = (org.apache.cocoon.environment.Context) context.get(Constants.CONTEXT_ENVIRONMENT_CONTEXT);
064    }
065    
066    public void service(ServiceManager sManager) throws ServiceException
067    {
068        _resourcesHandlerEP = (ResourceHandlerProviderExtensionPoint) sManager.lookup(ResourceHandlerProviderExtensionPoint.ROLE);
069        _resolver = (SourceResolver) sManager.lookup(SourceResolver.ROLE);
070    }
071    
072    @Override
073    public void setup(org.apache.cocoon.environment.SourceResolver res, Map objectModel, String source, Parameters parameters) throws ProcessingException, SAXException, IOException
074    {
075        try
076        {
077            _resourceHandler = _resourcesHandlerEP.getResourceHandler(source);
078        }
079        catch (Exception e)
080        {
081            throw new ProcessingException("Exception while retrieving resource handler for resource '" + source + "'", e);
082        }
083        
084        _readForDownload = parameters.getParameterAsBoolean("download", false);
085        _source = _resourceHandler.setup(source, objectModel, parameters, _readForDownload);
086        
087        // Minimizer does not receive the real lastModified through sitemap source 
088        @SuppressWarnings("unchecked")
089        Map<String, Object> params = (Map<String, Object>) objectModel.get(ObjectModelHelper.PARENT_CONTEXT);
090        if (params != null)
091        {
092            params.put(LAST_MODIFIED, getLastModified());
093        }
094        
095        if (_readForDownload)
096        {
097            String name = _source instanceof NamedSource ? URIUtils.encodeHeader(((NamedSource) _source).getName()) : null;
098            
099            Response response = ObjectModelHelper.getResponse(objectModel);
100            response.setHeader("Content-Disposition", "attachment" + (name != null ? ";filename=\"" + name + "\";filename*=UTF-8''" + name : ""));
101        }
102    }
103
104    @Override
105    public void generate() throws IOException, ProcessingException
106    {
107        _resourceHandler.generate(out);
108        out.flush();
109    }
110
111    @Override
112    public Serializable getKey()
113    {
114        return _resourceHandler.getKey();
115    }
116    
117    @Override
118    public SourceValidity getValidity()
119    {
120        return _resourceHandler.getValidity();
121    }
122
123    @Override
124    public void recycle()
125    {
126        super.recycle();
127        
128        _resolver.release(_source);
129        LifecycleHelper.dispose(_resourceHandler);
130    }
131    
132    @Override
133    public String getMimeType()
134    {
135        String sourceMimeType = _source.getMimeType();
136        
137        if (sourceMimeType != null)
138        {
139            return sourceMimeType;
140        }
141        
142        if (_cocoonContext != null) 
143        {
144            final String mimeType = _cocoonContext.getMimeType(_source.getURI());
145            
146            if (mimeType != null) 
147            {
148                return mimeType;
149            }
150        }
151        
152        return null;
153    }
154    
155    @Override
156    public long getLastModified()
157    {
158        return _resourceHandler.getLastModified();
159    }
160}