001/*
002 *  Copyright 2017 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.extraction.component;
017
018import java.util.Collections;
019import java.util.HashSet;
020import java.util.Map;
021import java.util.Set;
022
023import org.apache.avalon.framework.configuration.Configuration;
024import org.apache.avalon.framework.configuration.ConfigurationException;
025import org.apache.avalon.framework.service.ServiceException;
026import org.apache.avalon.framework.service.ServiceManager;
027import org.apache.cocoon.xml.AttributesImpl;
028import org.apache.cocoon.xml.XMLUtils;
029import org.xml.sax.ContentHandler;
030
031import org.ametys.cms.contenttype.ContentType;
032import org.ametys.cms.repository.Content;
033import org.ametys.core.util.I18nUtils;
034import org.ametys.plugins.extraction.ExtractionConstants;
035import org.ametys.plugins.extraction.execution.ExtractionExecutionContext;
036import org.ametys.plugins.extraction.execution.ExtractionExecutionContextHierarchyElement;
037import org.ametys.plugins.repository.AmetysObjectIterable;
038import org.ametys.plugins.thesaurus.Thesaurus;
039import org.ametys.plugins.thesaurus.ThesaurusDAO;
040import org.ametys.runtime.i18n.I18nizableText;
041
042/**
043 * This class represents a thesaurus component of the extraction module
044 */
045public class ThesaurusExtractionComponent extends AbstractExtractionComponent
046{
047    private String _microThesaurusId;
048    private Thesaurus _thesaurus;
049    private ContentType _microThesaurus;
050    private int _maxLevel;
051    
052    private I18nUtils _i18nUtils;
053    
054    @Override
055    public void service(ServiceManager serviceManager) throws ServiceException
056    {
057        super.service(serviceManager);
058        _i18nUtils = (I18nUtils) serviceManager.lookup(I18nUtils.ROLE);
059    }
060    
061    @Override
062    public void configure(Configuration thesaurus) throws ConfigurationException
063    {
064        super.configure(thesaurus);
065        _microThesaurusId = thesaurus.getAttribute("microThesaurus");
066        _maxLevel = thesaurus.getAttributeAsInteger("max-level", -1);
067        
068        Set<String> ancestors = _contentTypesHelper.getAncestors(_microThesaurusId);
069        if (!ancestors.contains(ThesaurusDAO.MICROTHESAURUS_ABSTRACT_CONTENT_TYPE))
070        {
071            throw new IllegalArgumentException(getLogsPrefix() + "'" + _microThesaurusId + "' is not a valid microthesaurus id");
072        }
073        
074        _initializeThesaurus();
075    }
076
077    void _initializeThesaurus()
078    {
079        _microThesaurus = _contentTypeExtensionPoint.getExtension(_microThesaurusId);
080        _thesaurus = _thesaurusDAO.getParentThesaurus(_microThesaurus);
081        if (_thesaurus == null)
082        {
083            throw new IllegalArgumentException(getLogsPrefix() + "The microthesaurus '" + _microThesaurusId + "' has no attached thesaurus.");
084        }
085    }
086
087    @Override
088    public void executeComponent(ContentHandler contentHandler, ExtractionExecutionContext context) throws Exception
089    {
090        I18nizableText i18nLabel = _microThesaurus.getLabel();
091        String label = _i18nUtils.translate(i18nLabel, "en");
092        
093        AttributesImpl thesaurusAttributes = new AttributesImpl();
094        thesaurusAttributes.addCDATAAttribute("thesaurusLabel", _thesaurus.getLabel());
095        thesaurusAttributes.addCDATAAttribute("microThesaurusLabel", label);
096        thesaurusAttributes.addCDATAAttribute("microThesaurusId", _microThesaurusId);
097        XMLUtils.startElement(contentHandler, _tagName, thesaurusAttributes);
098        
099        AmetysObjectIterable<Content> children = _thesaurusDAO.getRootTerms(_microThesaurusId);
100        _processChildren(contentHandler, children, 1, context);
101        
102        XMLUtils.endElement(contentHandler, _tagName);
103    }
104    
105    public Set<String> getContentTypes()
106    {
107        return new HashSet<>(Collections.singletonList(_microThesaurusId));
108    }
109
110    private void _processChildren(ContentHandler contentHandler, AmetysObjectIterable<Content> children, int currentLevel, ExtractionExecutionContext context) throws Exception
111    {
112        long nbTermChildren = -1;
113        int currentChildIndex = 0;
114        if (getLogger().isDebugEnabled())
115        {
116            nbTermChildren = children.getSize();
117        }
118        
119        for (Content term : children)
120        {
121            if (getLogger().isDebugEnabled())
122            {
123                getLogger().debug(getLogsPrefix() + "executing term " + ++currentChildIndex + "/" + nbTermChildren + " at level " + currentLevel);
124            }
125            
126            AttributesImpl attributes = new AttributesImpl();
127            attributes.addCDATAAttribute("name", term.getTitle());
128            XMLUtils.startElement(contentHandler, "term", attributes);
129
130            if (_maxLevel < 0 || currentLevel < _maxLevel)
131            {
132                ExtractionExecutionContextHierarchyElement currentContext = new ExtractionExecutionContextHierarchyElement(this, Collections.singleton(term), false);
133                executeSubComponents(contentHandler, context, currentContext);
134                _processChildren(contentHandler, _thesaurusDAO.getChildTerms(_microThesaurusId, term.getId()), currentLevel + 1, context);
135            }
136            else
137            {
138                ExtractionExecutionContextHierarchyElement currentContext = new ExtractionExecutionContextHierarchyElement(this, Collections.singleton(term));
139                executeSubComponents(contentHandler, context, currentContext);
140            }
141            
142            XMLUtils.endElement(contentHandler, "term");
143        }
144    }
145    
146    @Override
147    public Map<String, Object> getComponentDetailsForTree()
148    {
149        Map<String, Object> details = super.getComponentDetailsForTree();
150        details.put("tag", ExtractionConstants.THESAURUS_COMPONENT_TAG);
151        
152        @SuppressWarnings("unchecked")
153        Map<String, Object> data = (Map<String, Object>) details.get("data");
154        data.put("thesaurusId", _thesaurus.getId());
155        data.put("microThesaurusId", getMicroThesaurusId());
156        data.put("maxLevel", this.getMaxLevel());
157        details.put("iconCls", "ametysicon-books");
158        
159        return details;
160    }
161
162    @Override
163    protected String getDefaultTagName()
164    {
165        return "thesaurus";
166    }
167
168    @Override
169    protected String getLogsPrefix()
170    {
171        return "Thesaurus component '" + _tagName + "': ";
172    }
173
174    /**
175     * Retrieves the component microthesaurus id
176     * @return The microthesaurus id
177     */
178    public String getMicroThesaurusId()
179    {
180        return _microThesaurusId;
181    }
182
183    /**
184     * Set the microthesaurus id
185     * @param microThesaurusId The microthesaurus id to set
186     */
187    public void setMicroThesaurusId(String microThesaurusId)
188    {
189        _microThesaurusId = microThesaurusId;
190    }
191
192    /**
193     * Retrieves the maximum level of specific terms to look at
194     * @return The maximum level
195     */
196    public int getMaxLevel()
197    {
198        return _maxLevel;
199    }
200
201    /**
202     * Set the maximum level of specific terms to look at
203     * @param maxLevel The maximum level to set
204     */
205    public void setMaxLevel(int maxLevel)
206    {
207        _maxLevel = maxLevel;
208    }
209}