001/*
002 *  Copyright 2013 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.plugins.thesaurus.search;
017
018import java.io.IOException;
019import java.util.LinkedHashSet;
020import java.util.List;
021import java.util.Locale;
022import java.util.Map;
023import java.util.Set;
024
025import javax.jcr.RepositoryException;
026
027import org.apache.avalon.framework.service.ServiceException;
028import org.apache.avalon.framework.service.ServiceManager;
029import org.apache.cocoon.ProcessingException;
030import org.apache.cocoon.generation.ServiceableGenerator;
031import org.apache.cocoon.xml.AttributesImpl;
032import org.apache.cocoon.xml.XMLUtils;
033import org.apache.commons.lang3.StringUtils;
034import org.xml.sax.SAXException;
035
036import org.ametys.cms.content.SAXContentHelper;
037import org.ametys.cms.contenttype.ContentType;
038import org.ametys.cms.contenttype.ContentTypeExtensionPoint;
039import org.ametys.cms.contenttype.ContentTypesHelper;
040import org.ametys.cms.contenttype.MetadataDefinition;
041import org.ametys.cms.contenttype.MetadataDefinitionReference;
042import org.ametys.cms.contenttype.MetadataManager;
043import org.ametys.cms.contenttype.MetadataSet;
044import org.ametys.cms.contenttype.MetadataType;
045import org.ametys.cms.repository.Content;
046import org.ametys.core.util.ServerCommHelper;
047import org.ametys.plugins.thesaurus.ThesaurusDAO;
048import org.ametys.plugins.thesaurus.content.ThesaurusItemContentType;
049
050/**
051 * SAX the contents indexed with one or more terms
052 *
053 */
054public class IndexedContentsGenerator extends ServiceableGenerator
055{
056    private ThesaurusDAO _thesaurusDAO;
057
058    private ContentTypeExtensionPoint _contentTypeExtensionPoint;
059    private MetadataManager _metadataManager;
060    private ContentTypesHelper _contentTypesHelper;
061    private ServerCommHelper _serverCommHelper;
062    private SAXContentHelper _saxContentHelper;
063    
064    @Override
065    public void service(ServiceManager smanager) throws ServiceException
066    {
067        super.service(smanager);
068        _contentTypeExtensionPoint = (ContentTypeExtensionPoint) smanager.lookup(ContentTypeExtensionPoint.ROLE);
069        _metadataManager = (MetadataManager) smanager.lookup(MetadataManager.ROLE);
070        _contentTypesHelper = (ContentTypesHelper) smanager.lookup(ContentTypesHelper.ROLE);
071        _serverCommHelper = (ServerCommHelper) smanager.lookup(ServerCommHelper.ROLE);
072        _saxContentHelper = (SAXContentHelper) smanager.lookup(SAXContentHelper.ROLE);
073        _thesaurusDAO = (ThesaurusDAO) smanager.lookup(ThesaurusDAO.ROLE);
074    }
075    
076    @Override
077    public void generate() throws IOException, SAXException, ProcessingException
078    {
079        Map<String, Object> jsParameters = _serverCommHelper.getJsParameters();
080        
081        @SuppressWarnings("unchecked")
082        List<String> termIds = (List<String>) jsParameters.get("termIds");
083
084        int begin = jsParameters.containsKey("start") ? (Integer) jsParameters.get("start") : 0; // Index of search
085        int offset = jsParameters.containsKey("limit") ? (Integer) jsParameters.get("limit") : Integer.MAX_VALUE; // Number of results to SAX
086        
087        String lang = (String) jsParameters.get("lang");
088        Locale defaultLocale = StringUtils.isNotEmpty(lang) ? new Locale(lang) : null;
089        
090        Set<Content> indexedContents = new LinkedHashSet<>();
091        
092        int index = 0;
093        for (String termId : termIds)
094        {
095            if (index == 0)
096            {
097                indexedContents.addAll(_thesaurusDAO.getIndexedContents(termId));
098            }
099            else
100            {
101                indexedContents.retainAll(_thesaurusDAO.getIndexedContents(termId));
102            }
103            index++;
104        }
105        
106        try
107        {
108            // SAX results between begin and begin + offset
109            contentHandler.startDocument();
110            contentHandler.startPrefixMapping("i18n", "http://apache.org/cocoon/i18n/2.1");
111
112            XMLUtils.startElement(contentHandler, "contents");
113            
114            index = 0;
115            for (Content content : indexedContents)
116            {
117                if (index >= begin && index < begin + offset)
118                {
119                    _saxContent(content, defaultLocale);
120                }
121                
122                index++;
123            }
124            
125            XMLUtils.createElement(contentHandler, "total", String.valueOf(indexedContents.size()));
126            XMLUtils.endElement(contentHandler, "contents");
127
128            contentHandler.endPrefixMapping("i18n");
129            contentHandler.endDocument();
130        }
131        catch (Exception e)
132        {
133            getLogger().error("Cannot search for contents : " + e.getMessage(), e);
134            throw new ProcessingException("Cannot search for contents : " + e.getMessage(), e);
135        }
136    }
137    
138    private void _saxContent (Content content, Locale defaultLocale) throws SAXException, RepositoryException, IOException
139    {
140        AttributesImpl attrs = new AttributesImpl();
141        
142        attrs.addCDATAAttribute("smallIcon", _contentTypesHelper.getSmallIcon(content));
143        attrs.addCDATAAttribute("mediumIcon", _contentTypesHelper.getMediumIcon(content));
144        attrs.addCDATAAttribute("largeIcon", _contentTypesHelper.getLargeIcon(content));
145        attrs.addCDATAAttribute("id", content.getId());
146        attrs.addCDATAAttribute("name", content.getName());
147        attrs.addCDATAAttribute("title", content.getTitle(defaultLocale));
148        
149        String contentLanguage = content.getLanguage();
150        if (contentLanguage != null)
151        {
152            attrs.addCDATAAttribute("language", contentLanguage);
153        }
154        
155        XMLUtils.startElement(contentHandler, "content", attrs);
156
157        // System properties
158        _saxSystemProperties(content);
159        
160        // Metadata
161        XMLUtils.startElement(contentHandler, "metadata");
162        XMLUtils.createElement(contentHandler, "title", content.getTitle(defaultLocale));
163        
164        MetadataSet metadataSet = getMetadataToSAX(content);
165        Locale locale = contentLanguage != null ? new Locale(contentLanguage) : defaultLocale;
166        _metadataManager.saxReadableMetadata(contentHandler, content, metadataSet, locale);
167        
168        XMLUtils.endElement(contentHandler, "metadata");
169        
170        XMLUtils.endElement(contentHandler, "content");
171    }
172    
173    /**
174     * Get the metadata set to sax
175     * @param content the content
176     * @return the metadata to sax
177     */
178    protected MetadataSet getMetadataToSAX (Content content)
179    {
180        MetadataSet metadataSet = new MetadataSet();
181        metadataSet.addElement(new MetadataDefinitionReference("title"));
182        
183        String[] ctypes = content.getTypes();
184        for (String ctype : ctypes)
185        {
186            ContentType contentType = _contentTypeExtensionPoint.getExtension(ctype);
187            
188            Set<String> metadataNames = contentType.getMetadataNames();
189            for (String metadataName : metadataNames)
190            {
191                MetadataDefinition metadataDefinition = contentType.getMetadataDefinition(metadataName);
192                if (MetadataType.CONTENT.equals(metadataDefinition.getType()) && ThesaurusItemContentType.ITEM_CONTENT_TYPE_ID.equals(metadataDefinition.getContentType()))
193                {
194                    MetadataDefinitionReference metadataRef = new MetadataDefinitionReference(metadataName);
195                    metadataSet.addElement(metadataRef);
196                }
197            }
198        }
199        
200        return metadataSet;
201    }
202    
203    private void _saxSystemProperties (Content content) throws SAXException, RepositoryException
204    {
205        _saxContentHelper.saxContentCurrentState (contentHandler, content);
206        _saxContentHelper.saxContentTypesAndMixins(contentHandler, content);
207        _saxContentHelper.saxLastModified(contentHandler, content);
208        _saxContentHelper.saxCreationDate(contentHandler, content);
209        _saxContentHelper.saxCreator(contentHandler, content);
210        _saxContentHelper.saxContributor(contentHandler, content);
211        _saxContentHelper.saxContentLanguage(contentHandler, content);
212    }
213}