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.cms.data.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    /** Avalon service manager */
052    protected ServiceManager _manager;
053    
054    private SourceResolver _sourceResolver;
055    private XSLTProcessor _xsltProcessor;
056    private XPathProcessor _xpathProcessor;
057    
058    public void service(ServiceManager manager) throws ServiceException
059    {
060        _manager = manager;
061        _xsltProcessor = (XSLTProcessor) manager.lookup(XSLTProcessor.ROLE + "/xalan");
062        _sourceResolver = (SourceResolver) manager.lookup(SourceResolver.ROLE);
063        _xpathProcessor = (XPathProcessor) manager.lookup(XPathProcessor.ROLE);
064    }
065
066    /**
067     * The uri to use for conversion to outgoing references format
068     * @return The uri
069     */
070    protected String _getXSLTURI()
071    {
072        return "docbookenhancement://docbook2outgoingreferences.xsl";
073    }
074    
075    /**
076     * Take the metadata stream and transform it using the xslt configured (_getXSLTURI)
077     * @param metadata The metadata to transform
078     * @return The root node of the result XML after the transformation
079     */
080    protected Node _getNodeAfterXSLT(RichText metadata)
081    {
082        DOMResult result = null;
083        Source xsltSource = null;
084        SAXParser saxParser = null;
085        
086        try
087        {
088            xsltSource = _sourceResolver.resolveURI(_getXSLTURI());
089            TransformerHandler th = _xsltProcessor.getTransformerHandler(xsltSource);
090            
091            result = new DOMResult();
092            th.setResult(result);
093
094            saxParser = (SAXParser) _manager.lookup(SAXParser.ROLE);
095            
096            try (InputStream is = metadata.getInputStream())
097            {
098                saxParser.parse(new InputSource(is), th);
099            }
100        }
101        catch (Exception e)
102        {
103            throw new RuntimeException("Cannot find the xslt to extract rich text outgoing references", e);
104        }
105        finally
106        {
107            _sourceResolver.release(xsltSource);
108            _manager.release(saxParser);
109        }
110        
111        return result.getNode();
112    }
113    
114    @Override
115    public OutgoingReferences getOutgoingReferences(RichText richText)
116    {
117        OutgoingReferences references = new OutgoingReferences();
118        
119        Node resultNode = _getNodeAfterXSLT(richText);
120        NodeList referenceNodes = _xpathProcessor.selectNodeList(resultNode, "/references/reference");
121        
122        for (int i = 0; i < referenceNodes.getLength(); i++)
123        {
124            Element referenceNode = (Element) referenceNodes.item(i);
125            String type = referenceNode.getAttribute("type");
126            String value = referenceNode.getTextContent();
127            
128            List<String> referenceValues = references.get(type);
129            if (referenceValues == null)
130            {
131                referenceValues = new ArrayList<>();
132                references.put(type, referenceValues);
133            }
134            referenceValues.add(value);
135        }
136        
137        return references;
138    }
139}