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 */
016
017package org.ametys.cms.transformation.docbook;
018
019import java.io.InputStream;
020import java.util.ArrayList;
021import java.util.List;
022
023import javax.xml.transform.dom.DOMResult;
024import javax.xml.transform.sax.TransformerHandler;
025
026import org.apache.avalon.framework.service.ServiceException;
027import org.apache.avalon.framework.service.ServiceManager;
028import org.apache.avalon.framework.service.Serviceable;
029import org.apache.excalibur.source.Source;
030import org.apache.excalibur.source.SourceResolver;
031import org.apache.excalibur.xml.sax.SAXParser;
032import org.apache.excalibur.xml.xpath.XPathProcessor;
033import org.apache.excalibur.xml.xslt.XSLTProcessor;
034import org.w3c.dom.Element;
035import org.w3c.dom.Node;
036import org.w3c.dom.NodeList;
037import org.xml.sax.InputSource;
038
039import org.ametys.cms.content.references.OutgoingReferences;
040import org.ametys.cms.content.references.RichTextOutgoingReferencesExtractor;
041import org.ametys.plugins.repository.metadata.RichText;
042
043/**
044 * This impl extract outgoing references on docbook rich texts
045 */
046public class DocbookOutgoingReferencesExtractor implements RichTextOutgoingReferencesExtractor, Serviceable
047{
048    /** Avalon Role */
049    public static final String ROLE = DocbookOutgoingReferencesExtractor.class.getName();
050    
051    private SourceResolver _sourceResolver;
052    private XSLTProcessor _xsltProcessor;
053    private SAXParser _saxParser;
054    private XPathProcessor _xpathProcessor;
055    
056    public void service(ServiceManager manager) throws ServiceException
057    {
058        _xsltProcessor = (XSLTProcessor) manager.lookup(XSLTProcessor.ROLE + "/xalan");
059        _saxParser = (SAXParser) manager.lookup(SAXParser.ROLE);
060        _sourceResolver = (SourceResolver) manager.lookup(SourceResolver.ROLE);
061        _xpathProcessor = (XPathProcessor) manager.lookup(XPathProcessor.ROLE);
062    }
063
064    /**
065     * The uri to use for conversion to outgoing references format
066     * @return The uri
067     */
068    protected String _getXSLTURI()
069    {
070        return "docbookenhancement://docbook2outgoingreferences.xsl";
071    }
072    
073    /**
074     * Take the metadata stream and transform it using the xslt configured (_getXSLTURI)
075     * @param metadata The metadata to transform
076     * @return The root node of the result XML after the transformation
077     */
078    protected Node _getNodeAfterXSLT(RichText metadata)
079    {
080        DOMResult result = null;
081        
082        Source xsltSource = null;
083        try
084        {
085            xsltSource = _sourceResolver.resolveURI(_getXSLTURI());
086            TransformerHandler th = _xsltProcessor.getTransformerHandler(xsltSource);
087            
088            result = new DOMResult();
089            th.setResult(result);
090
091            try (InputStream is = metadata.getInputStream())
092            {
093                _saxParser.parse(new InputSource(is), th);
094            }
095        }
096        catch (Exception e)
097        {
098            throw new RuntimeException("Cannot find the xslt to extract rich text outgoing references", e);
099        }
100        finally
101        {
102            _sourceResolver.release(xsltSource);
103        }
104        
105        return result.getNode();
106    }
107    
108    @Override
109    public OutgoingReferences getOutgoingReferences(RichText metadata)
110    {
111        OutgoingReferences references = new OutgoingReferences();
112        
113        Node resultNode = _getNodeAfterXSLT(metadata);
114        NodeList referenceNodes = _xpathProcessor.selectNodeList(resultNode, "/references/reference");
115        
116        for (int i = 0; i < referenceNodes.getLength(); i++)
117        {
118            Element referenceNode = (Element) referenceNodes.item(i);
119            String type = referenceNode.getAttribute("type");
120            String value = referenceNode.getTextContent();
121            
122            List<String> referenceValues = references.get(type);
123            if (referenceValues == null)
124            {
125                referenceValues = new ArrayList<>();
126                references.put(type, referenceValues);
127            }
128            referenceValues.add(value);
129        }
130        
131        return references;
132    }
133}