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.tags.inputdata;
017
018import java.io.IOException;
019import java.io.InputStream;
020import java.util.ArrayList;
021import java.util.List;
022
023import org.apache.avalon.framework.configuration.Configuration;
024import org.apache.avalon.framework.configuration.DefaultConfigurationBuilder;
025import org.apache.avalon.framework.context.Context;
026import org.apache.avalon.framework.context.ContextException;
027import org.apache.avalon.framework.context.Contextualizable;
028import org.apache.avalon.framework.logger.AbstractLogEnabled;
029import org.apache.avalon.framework.service.ServiceException;
030import org.apache.avalon.framework.service.ServiceManager;
031import org.apache.avalon.framework.service.Serviceable;
032import org.apache.avalon.framework.thread.ThreadSafe;
033import org.apache.cocoon.ProcessingException;
034import org.apache.cocoon.components.ContextHelper;
035import org.apache.cocoon.environment.Request;
036import org.apache.cocoon.xml.XMLUtils;
037import org.apache.excalibur.source.Source;
038import org.apache.excalibur.source.SourceNotFoundException;
039import org.apache.excalibur.source.SourceResolver;
040import org.xml.sax.ContentHandler;
041import org.xml.sax.SAXException;
042
043import org.ametys.cms.contenttype.ContentTypeExtensionPoint;
044import org.ametys.cms.tag.TagProviderExtensionPoint;
045import org.ametys.plugins.repository.AmetysObjectResolver;
046import org.ametys.runtime.plugin.component.PluginAware;
047import org.ametys.web.content.GetSiteAction;
048import org.ametys.web.filter.ContentFilterHelper;
049import org.ametys.web.filter.StaticWebContentFilter;
050import org.ametys.web.filter.WebContentFilter;
051import org.ametys.web.inputdata.InputData;
052import org.ametys.web.repository.page.Page;
053import org.ametys.web.repository.site.Site;
054import org.ametys.web.repository.site.SiteManager;
055
056/**
057 * This class generates an output with all existing filters defined on context's current page.
058 */
059public class FilteredContentsInputData extends AbstractLogEnabled implements InputData, Serviceable, Contextualizable, ThreadSafe, PluginAware
060{
061    /** The plugin name */
062    protected String _pluginName;
063    /** The source resolver */
064    protected SourceResolver _sourceResolver;
065    /** The repository */
066    protected AmetysObjectResolver _resolver;
067    /** The extension point for content types */
068    protected ContentTypeExtensionPoint _contentTypeEP;
069    /** The avalon context. */
070    protected Context _context;
071    /** The site manager */
072    protected SiteManager _siteManager;
073    /** The tag provider EP */
074    protected TagProviderExtensionPoint _tagProviderEP;
075
076    private ContentFilterHelper _filterHelper;
077    
078    @Override
079    public void service(ServiceManager smanager) throws ServiceException
080    {
081        _sourceResolver = (SourceResolver) smanager.lookup(SourceResolver.ROLE);
082        _resolver = (AmetysObjectResolver) smanager.lookup(AmetysObjectResolver.ROLE);
083        _contentTypeEP = (ContentTypeExtensionPoint) smanager.lookup(ContentTypeExtensionPoint.ROLE);
084        _filterHelper = (ContentFilterHelper) smanager.lookup(ContentFilterHelper.ROLE);
085        _siteManager = (SiteManager) smanager.lookup(SiteManager.ROLE);
086        _tagProviderEP = (TagProviderExtensionPoint) smanager.lookup(TagProviderExtensionPoint.ROLE);
087    }
088    
089    @Override
090    public boolean isCacheable(Site site, Page page)
091    {
092        return true;
093    }
094    
095    @Override
096    public void toSAX(ContentHandler contentHandler) throws SAXException, ProcessingException
097    {
098        Page page = (Page) ContextHelper.getRequest(_context).getAttribute(Page.class.getName());
099        String siteName = (String) ContextHelper.getRequest(_context).getAttribute("site");
100        String lang = (String) ContextHelper.getRequest(_context).getAttribute("sitemapLanguage");
101        
102        contentHandler.startDocument();
103        XMLUtils.startElement(contentHandler, "Model");
104        
105        try
106        {
107            List<WebContentFilter> filters = configureFilters();
108            for (WebContentFilter filter : filters)
109            {
110                saxFilter(contentHandler, filter, siteName, lang, page);
111            }
112        }
113        catch (IOException e)
114        {
115            throw new ProcessingException("An error occurred while performing search on filtered contents", e);
116        }
117        
118        XMLUtils.endElement(contentHandler, "Model");
119        contentHandler.endDocument();
120    }
121    
122    /**
123     * Retrieves the configured filters
124     * @return The list of filters
125     * @throws ProcessingException If an error occurred while parsing the file.
126     */
127    protected List<WebContentFilter> configureFilters () throws ProcessingException
128    {
129        List<WebContentFilter> filters = new ArrayList<>();
130        
131        Source source = null;
132        
133        try
134        {
135            source = _sourceResolver.resolveURI("template://filters/default.xml");
136            if (source.exists())
137            {
138                try (InputStream is = source.getInputStream())
139                {
140                    Configuration configuration = new DefaultConfigurationBuilder().build(source.getInputStream());
141                    Configuration[] filterConfiguration = configuration.getChildren();
142                    
143                    for (Configuration filterConf : filterConfiguration)
144                    {
145                        if ("content".equals(filterConf.getAttribute("target")))
146                        {
147                            StaticWebContentFilter filter = new StaticWebContentFilter (filterConf.getAttribute("id"), _resolver, _contentTypeEP, _siteManager, _tagProviderEP);
148                            filter.configure(filterConf);
149                            
150                            filters.add(filter);
151                        }
152                    }
153                }                
154            }
155            
156            return filters;
157        }
158        catch (SourceNotFoundException e)
159        {
160            return filters;
161        }
162        catch (Exception e)
163        {
164            throw new ProcessingException("Unable to parse filters file" , e);
165        }
166        finally
167        {
168            if (_sourceResolver != null && source != null)
169            {
170                _sourceResolver.release(source);
171            }
172        }
173    }
174    
175    /**
176     * SAX a filter
177     * @param contentHandler The content handler
178     * @param filter The filter to SAX
179     * @param siteName The current site name
180     * @param lang The current language
181     * @param page The current page
182     * @throws SAXException If an errors occurs while SAXing
183     * @throws IOException If an errors occurs
184     */
185    @SuppressWarnings("deprecation")
186    protected void saxFilter (ContentHandler contentHandler, WebContentFilter filter, String siteName, String lang, Page page)  throws SAXException, IOException
187    {
188        Request request = ContextHelper.getRequest(_context);
189        String currentSiteName = (String) request.getAttribute("site");
190        String currentSkinName = (String) request.getAttribute("skin");
191        String currentTemplateName = (String) request.getAttribute("template");
192        String currentLanguage = (String) request.getAttribute("renderingLanguage");
193        
194        // Issue CMS-3391
195        request.setAttribute(GetSiteAction.OVERRIDE_SITE_REQUEST_ATTR, currentSiteName);
196        request.setAttribute(GetSiteAction.OVERRIDE_SKIN_REQUEST_ATTR, currentSkinName);
197        
198        try
199        {
200            String id = filter.getId();
201            
202            XMLUtils.startElement(contentHandler, id);
203            _filterHelper.saxMatchingContents(contentHandler, filter, siteName, lang, page);
204            XMLUtils.endElement(contentHandler, id);
205        }
206        finally
207        {
208            request.removeAttribute(GetSiteAction.OVERRIDE_SITE_REQUEST_ATTR);
209            request.removeAttribute(GetSiteAction.OVERRIDE_SKIN_REQUEST_ATTR);
210            request.setAttribute("site", currentSiteName);
211            request.setAttribute("skin", currentSkinName);
212            request.setAttribute("template", currentTemplateName);
213            request.setAttribute("renderingLanguage", currentLanguage);
214        }
215    }
216    
217    @Override
218    public void contextualize(Context context) throws ContextException
219    {
220        _context = context;
221    }
222
223    @Override
224    public void setPluginInfo(String pluginName, String featureName, String id)
225    {
226        _pluginName = pluginName;
227    }
228}