001/*
002 *  Copyright 2011 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;
018
019import java.io.IOException;
020import java.io.InputStream;
021import java.time.ZonedDateTime;
022import java.util.HashMap;
023import java.util.Map;
024
025import org.apache.avalon.framework.service.ServiceException;
026import org.apache.avalon.framework.service.ServiceManager;
027import org.apache.avalon.framework.service.Serviceable;
028import org.apache.commons.io.IOUtils;
029import org.apache.excalibur.source.Source;
030import org.apache.excalibur.source.SourceResolver;
031import org.apache.excalibur.xml.sax.SAXParser;
032import org.xml.sax.ContentHandler;
033import org.xml.sax.InputSource;
034import org.xml.sax.SAXException;
035
036import org.ametys.cms.data.RichText;
037import org.ametys.core.util.IgnoreRootHandler;
038import org.ametys.plugins.repository.AmetysRepositoryException;
039import org.ametys.runtime.model.type.DataContext;
040
041/**
042 * Abstract class for {@link RichTextTransformer}s relying on Cocoon pipelines to actually transform HTML to RichText back and forth.
043 */
044public abstract class AbstractRichTextTransformer implements RichTextTransformer, Serviceable
045{
046    private SourceResolver _sourceResolver;
047    private ServiceManager _manager;
048    
049    public void service(ServiceManager manager) throws ServiceException
050    {
051        _manager = manager;
052        _sourceResolver = (SourceResolver) manager.lookup(SourceResolver.ROLE);
053    }
054    
055    public void transform(String source, RichText dest) throws AmetysRepositoryException, IOException
056    {
057        Source xmlSource = null;
058        
059        try 
060        {
061            Map<String, Object> parameters = new HashMap<>();
062            parameters.put("source", source);
063            parameters.put("richText", dest);
064
065            xmlSource = _sourceResolver.resolveURI(_getSourceUriForHTML2RichText(), null, parameters);
066            
067            try (InputStream is = xmlSource.getInputStream())
068            {
069                dest.setMimeType("application/xml");
070                dest.setLastModificationDate(ZonedDateTime.now());
071                dest.setInputStream(is);
072            }
073        }
074        finally
075        {
076            _sourceResolver.release(xmlSource);
077        }
078    }
079    
080    /**
081     * Returns the internal {@link Source} URI used to process the HTML editor content. 
082     * @return the internal {@link Source} URI used to process the HTML editor content. 
083     */
084    protected abstract String _getSourceUriForHTML2RichText();
085    
086    public void transformForEditing(RichText source, DataContext dataContext, StringBuilder dest) throws AmetysRepositoryException, IOException
087    {
088        Source textSource = null;
089        
090        try (InputStream is = source.getInputStream())
091        {
092            Map<String, Object> parameters = new HashMap<>();
093            parameters.put("source", is);
094            parameters.put("dataContext", dataContext);
095            
096            textSource = _sourceResolver.resolveURI(_getSourceUriForRichText2HTML(), null, parameters);
097            
098            try (InputStream textSourceIs = textSource.getInputStream())
099            {
100                dest.append(IOUtils.toString(textSourceIs, "UTF-8"));
101            }
102        }
103        finally
104        {
105            _sourceResolver.release(textSource);
106        }
107    }
108    
109    /**
110     * Returns the internal {@link Source} URI used to process the RichText's InputStream. 
111     * @return the internal {@link Source} URI used to process the RichText's InputStream. 
112     */
113    protected abstract String _getSourceUriForRichText2HTML();
114
115    public void transformForRendering(RichText source, ContentHandler handler) throws AmetysRepositoryException, SAXException, IOException
116    {
117        SAXParser saxParser = null;
118        
119        try
120        {
121            saxParser = (SAXParser) _manager.lookup(SAXParser.ROLE);
122            
123            try (InputStream is = source.getInputStream())
124            {
125                saxParser.parse(new InputSource(is), new IgnoreRootHandler(handler));
126            }
127        }
128        catch (ServiceException e)
129        {
130            throw new AmetysRepositoryException("Unable to get SAX parser", e);
131        }
132        finally
133        {
134            _manager.release(saxParser);
135        }
136    }
137}