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 */
016package org.ametys.web.inputdata;
017
018import org.apache.avalon.framework.service.ServiceException;
019import org.apache.avalon.framework.service.ServiceManager;
020import org.apache.cocoon.ProcessingException;
021import org.apache.cocoon.environment.ObjectModelHelper;
022import org.apache.cocoon.environment.Request;
023import org.apache.cocoon.generation.ServiceableGenerator;
024import org.apache.cocoon.xml.SaxBuffer;
025import org.apache.cocoon.xml.XMLUtils;
026import org.slf4j.Logger;
027import org.slf4j.LoggerFactory;
028import org.xml.sax.ContentHandler;
029import org.xml.sax.SAXException;
030
031import org.ametys.plugins.repository.provider.WorkspaceSelector;
032import org.ametys.web.cache.monitoring.Constants;
033import org.ametys.web.cache.monitoring.process.access.ResourceAccessComponent;
034import org.ametys.web.cache.monitoring.process.access.impl.PageElementResourceAccess;
035import org.ametys.web.cache.monitoring.process.access.impl.PageElementResourceAccess.PageElementType;
036import org.ametys.web.cache.monitoring.process.access.impl.PageResourceAccess;
037import org.ametys.web.cache.pageelement.PageElementCache;
038import org.ametys.web.renderingcontext.RenderingContext;
039import org.ametys.web.renderingcontext.RenderingContextHandler;
040import org.ametys.web.repository.page.Page;
041import org.ametys.web.repository.site.Site;
042import org.ametys.web.repository.site.SiteManager;
043
044/**
045 * Generates SAX events from activated input data.
046 */
047public class InputDataGenerator extends ServiceableGenerator
048{
049    private InputDataExtensionPoint _inputDataExtensionPoint;
050    private PageElementCache _inputDataCache;
051    private WorkspaceSelector _workspaceSelector;
052    private RenderingContextHandler _renderingContextHandler;
053    private SiteManager _sitesManager;
054    
055    /** The resource access monitoring component */
056    private ResourceAccessComponent _resourceAccessMonitor;
057    
058    private Logger _timeLogger = LoggerFactory.getLogger("org.ametys.web.rendering.time");
059    
060    @Override
061    public void service(ServiceManager sManager) throws ServiceException
062    {
063        super.service(sManager);
064        _inputDataExtensionPoint = (InputDataExtensionPoint) sManager.lookup(InputDataExtensionPoint.ROLE);
065        _inputDataCache = (PageElementCache) sManager.lookup(PageElementCache.ROLE + "/inputData");
066        _renderingContextHandler = (RenderingContextHandler) sManager.lookup(RenderingContextHandler.ROLE);
067        _workspaceSelector = (WorkspaceSelector) sManager.lookup(WorkspaceSelector.ROLE);
068        _sitesManager = (SiteManager) sManager.lookup(SiteManager.ROLE);
069        _resourceAccessMonitor = (ResourceAccessComponent) sManager.lookup(ResourceAccessComponent.ROLE);
070    }
071    
072    @Override
073    public void generate() throws SAXException, ProcessingException
074    {
075        long t0 = System.currentTimeMillis();
076        
077        Request request = ObjectModelHelper.getRequest(objectModel);
078        
079        String siteName;
080        Site site;
081        String pageId = null;
082        
083        Page page = (Page) request.getAttribute(Page.class.getName());
084        if (page != null)
085        {
086            pageId = page.getId();
087            site = page.getSite();
088            siteName = page.getSiteName();
089        }
090        else
091        {
092            siteName = (String) request.getAttribute("site");
093            site = _sitesManager.getSite(siteName);
094            // there's no current page, set the pageId to the current sitemap name, so that the cached element may depend on the language
095            pageId = (String) request.getAttribute("sitemapLanguage");
096        }
097        
098        String workspace = _workspaceSelector.getWorkspace();
099        RenderingContext renderingContext = _renderingContextHandler.getRenderingContext();
100        
101        // Access monitoring
102        PageResourceAccess pageAccess = (PageResourceAccess) request.getAttribute(Constants.REQUEST_ATTRIBUTE_PAGEACCESS);
103        
104        contentHandler.startDocument();
105        XMLUtils.startElement(contentHandler, "inputData");
106        
107        for (String id : _inputDataExtensionPoint.getExtensionsIds())
108        {
109            long t1 = System.currentTimeMillis();
110            
111            InputData inputData = _inputDataExtensionPoint.getExtension(id);
112            
113            PageElementResourceAccess inputDataAccess = pageAccess != null ? pageAccess.createPageElementAccess(id, PageElementType.INPUTDATA) : null;
114            
115
116            // Only lookup cached content if it should be cached, to avoid missed get on elements that wont be on the cache
117            boolean isCacheable = inputData.isCacheable(site, page);
118            boolean shouldBeCached = isCacheable && inputData.shouldBeCached(site, page);
119            SaxBuffer cachedContent = null;
120            if (shouldBeCached)
121            {
122                cachedContent = _inputDataCache.getPageElement(workspace, siteName, id, pageId, renderingContext);
123            }
124
125            if (cachedContent != null)
126            {
127                if (inputDataAccess != null)
128                {
129                    inputDataAccess.setCacheable(true);
130                    inputDataAccess.setCacheHit(true);
131                }
132                
133                if (getLogger().isDebugEnabled())
134                {
135                    getLogger().debug("Inputdata '" + id + "' retrieved from cache.");
136                }
137                
138                cachedContent.toSAX(contentHandler);
139            }
140            else
141            {
142                
143                if (inputDataAccess != null)
144                {
145                    inputDataAccess.setCacheable(isCacheable);
146                    inputDataAccess.setCacheHit(false);
147                }
148                
149                SaxBuffer buffer = null;
150                ContentHandler handler; // the actual ContentHandler, either the real one, or a buffer
151                if (shouldBeCached)
152                {
153                    buffer = new SaxBuffer();
154                    handler = buffer;
155                }
156                else
157                {
158                    handler = contentHandler;
159                }
160                
161                inputData.toSAX(handler);
162                
163                if (getLogger().isDebugEnabled())
164                {
165                    getLogger().debug("Inputdata '" + id + "' processed (" + (isCacheable ?  "" : "non ") + "cacheable).");
166                }
167                
168                // finally store the buffered data in the cache and SAX it to the pipeline
169                if (buffer != null)
170                {
171                    buffer.toSAX(contentHandler);
172                    _inputDataCache.storePageElement(workspace, siteName, id, pageId, renderingContext, buffer);
173                }
174            }
175            
176            // Monitor the access to this zone item.
177            if (inputDataAccess != null)
178            {
179                _resourceAccessMonitor.addAccessRecord(inputDataAccess);
180            }
181            
182            _timeLogger.debug("Inputdata '{}' processing time: {} ms", id, System.currentTimeMillis() - t1);
183        }
184        
185        XMLUtils.endElement(contentHandler, "inputData");
186        contentHandler.endDocument();
187        
188        _timeLogger.debug("Inputdata total processing time: {} ms", System.currentTimeMillis() - t0);
189    }
190}