001/*
002 *  Copyright 2018 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.execution.pipeline.impl;
017
018import java.io.OutputStream;
019import java.util.Map;
020import java.util.Properties;
021
022import javax.xml.transform.OutputKeys;
023import javax.xml.transform.TransformerException;
024import javax.xml.transform.sax.SAXResult;
025import javax.xml.transform.sax.TransformerHandler;
026
027import org.apache.commons.lang3.StringUtils;
028import org.apache.excalibur.xml.sax.ContentHandlerProxy;
029import org.apache.xml.serializer.OutputPropertiesFactory;
030import org.xml.sax.ContentHandler;
031import org.xml.sax.SAXException;
032
033import org.ametys.plugins.extraction.execution.pipeline.PipelineSerializerModel;
034import org.ametys.plugins.extraction.execution.pipeline.Pipelines;
035
036/**
037 * Model for XML pipeline serializers
038 */
039public class XmlPipelineSerializerModel implements PipelineSerializerModel
040{
041    @Override
042    public String getDefaultFileExtension()
043    {
044        return "xml";
045    }
046    
047    @Override
048    public PipelineSerializer newSerializer(TransformerHandler handler, OutputStream out, Map<String, String> outputParameters)
049    {
050        return new XmlPipelineSerializer(handler, out, outputParameters);
051    }
052    
053    private static final class XmlPipelineSerializer extends AbstractSerializerImpl
054    {
055        XmlPipelineSerializer(TransformerHandler handler, OutputStream out, Map<String, String> outputParameters)
056        {
057            super(handler, out);
058            // Strip whitespaces to avoid rich texts indentation if indent param is set to "no"
059            _wrapHandlerToStripEOL();
060            _setOutputProps(outputParameters);
061        }
062        
063        private void _wrapHandlerToStripEOL()
064        {
065            try
066            {
067                TransformerHandler transformerHandler = Pipelines.getSaxTransformerFactory().newTransformerHandler();
068                ContentHandler stripWhitespacesContentHandler = new StripEOLContentHandler(transformerHandler);
069                _handler.setResult(new SAXResult(stripWhitespacesContentHandler));
070                _handler = transformerHandler;
071            }
072            catch (TransformerException e)
073            {
074                throw new RuntimeException("Unable to strip EOL", e);
075            }
076        }
077        
078        private void _setOutputProps(Map<String, String> outputParameters)
079        {
080            Properties properties = new Properties();
081            properties.put(OutputKeys.METHOD, outputParameters.getOrDefault("method", "xml"));
082            properties.put(OutputKeys.ENCODING, outputParameters.getOrDefault("encoding", "UTF-8"));
083            properties.put(OutputKeys.INDENT, outputParameters.getOrDefault("indent", "yes"));
084            properties.put(OutputPropertiesFactory.S_KEY_INDENT_AMOUNT, outputParameters.getOrDefault("indent-amount", "4"));
085            _handler.getTransformer().setOutputProperties(properties);
086        }
087        
088        @Override
089        public void serialize() throws Exception
090        {
091            // Nothing
092        }
093    }
094    
095    private static class StripEOLContentHandler extends ContentHandlerProxy
096    {
097        StripEOLContentHandler(ContentHandler contentHandler)
098        {
099            super(contentHandler);
100        }
101        
102        @Override
103        public void characters(char[] ch, int start, int len) throws SAXException
104        {
105            String data  =  new String(ch, start, len).replaceAll("[\\r\\n]", StringUtils.EMPTY);
106            super.characters(data.toCharArray(), 0, data.length());
107        }
108    }
109}