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.Date;
023import java.util.HashMap;
024import java.util.Map;
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.commons.io.IOUtils;
030import org.apache.excalibur.source.Source;
031import org.apache.excalibur.source.SourceResolver;
032import org.apache.excalibur.xml.sax.SAXParser;
033import org.xml.sax.ContentHandler;
034import org.xml.sax.InputSource;
035import org.xml.sax.SAXException;
036
037import org.ametys.cms.data.RichText;
038import org.ametys.core.util.IgnoreRootHandler;
039import org.ametys.plugins.repository.AmetysRepositoryException;
040import org.ametys.plugins.repository.metadata.ModifiableRichText;
041
042/**
043 * Abstract class for {@link RichTextTransformer}s relying on Cocoon pipelines to actually transform HTML to RichText back and forth.
044 */
045public abstract class AbstractRichTextTransformer implements RichTextTransformer, Serviceable
046{
047    private SourceResolver _sourceResolver;
048    private ServiceManager _manager;
049    
050    public void service(ServiceManager manager) throws ServiceException
051    {
052        _manager = manager;
053        _sourceResolver = (SourceResolver) manager.lookup(SourceResolver.ROLE);
054    }
055    
056    @SuppressWarnings("unchecked")
057    @Deprecated
058    public void transform(String source, ModifiableRichText dest) throws AmetysRepositoryException, IOException
059    {
060        Source xmlSource = null;
061        
062        try 
063        {
064            Map parameters = new HashMap();
065            parameters.put("source", source);
066            parameters.put("richText", dest);
067
068            xmlSource = _sourceResolver.resolveURI(_getSourceUriForHTML2RichText(), null, parameters);
069            
070            try (InputStream is = xmlSource.getInputStream())
071            {
072                dest.setMimeType("application/xml");
073                dest.setLastModified(new Date());
074                dest.setInputStream(is);
075            }
076        }
077        finally
078        {
079            _sourceResolver.release(xmlSource);
080        }
081    }
082    
083    public void transform(String source, RichText dest) throws AmetysRepositoryException, IOException
084    {
085        Source xmlSource = null;
086        
087        try 
088        {
089            Map<String, Object> parameters = new HashMap<>();
090            parameters.put("source", source);
091            parameters.put("richText", dest);
092
093            xmlSource = _sourceResolver.resolveURI(_getSourceUriForHTML2RichText(), null, parameters);
094            
095            try (InputStream is = xmlSource.getInputStream())
096            {
097                dest.setMimeType("application/xml");
098                dest.setLastModificationDate(ZonedDateTime.now());
099                dest.setInputStream(is);
100            }
101        }
102        finally
103        {
104            _sourceResolver.release(xmlSource);
105        }
106    }
107    
108    /**
109     * Returns the internal {@link Source} URI used to process the HTML editor content. 
110     * @return the internal {@link Source} URI used to process the HTML editor content. 
111     */
112    protected abstract String _getSourceUriForHTML2RichText();
113    
114    @Override
115    @Deprecated
116    public void transformForEditing(ModifiableRichText source, StringBuilder dest) throws AmetysRepositoryException, IOException
117    {
118        Source textSource = null;
119        
120        try (InputStream is = source.getInputStream())
121        {
122            Map<String, Object> parameters = new HashMap<>();
123            parameters.put("source", is);
124            
125            textSource = _sourceResolver.resolveURI(_getSourceUriForRichText2HTML(), null, parameters);
126            
127            try (InputStream textSourceIs = textSource.getInputStream())
128            {
129                dest.append(IOUtils.toString(textSourceIs, "UTF-8"));
130            }
131        }
132        finally
133        {
134            _sourceResolver.release(textSource);
135        }
136    }
137    
138    public void transformForEditing(RichText source, StringBuilder dest) throws AmetysRepositoryException, IOException
139    {
140        Source textSource = null;
141        
142        try (InputStream is = source.getInputStream())
143        {
144            Map<String, Object> parameters = new HashMap<>();
145            parameters.put("source", is);
146            
147            textSource = _sourceResolver.resolveURI(_getSourceUriForRichText2HTML(), null, parameters);
148            
149            try (InputStream textSourceIs = textSource.getInputStream())
150            {
151                dest.append(IOUtils.toString(textSourceIs, "UTF-8"));
152            }
153        }
154        finally
155        {
156            _sourceResolver.release(textSource);
157        }
158    }
159    
160    /**
161     * Returns the internal {@link Source} URI used to process the RichText's InputStream. 
162     * @return the internal {@link Source} URI used to process the RichText's InputStream. 
163     */
164    protected abstract String _getSourceUriForRichText2HTML();
165
166    @Override
167    @Deprecated
168    public void transformForRendering(org.ametys.plugins.repository.metadata.RichText source, ContentHandler handler) throws AmetysRepositoryException, SAXException, IOException
169    {
170        SAXParser saxParser = null;
171        
172        try
173        {
174            saxParser = (SAXParser) _manager.lookup(SAXParser.ROLE);
175            
176            try (InputStream is = source.getInputStream())
177            {
178                saxParser.parse(new InputSource(is), new IgnoreRootHandler(handler));
179            }
180        }
181        catch (ServiceException e)
182        {
183            throw new AmetysRepositoryException("Unable to get SAX parser", e);
184        }
185        finally
186        {
187            _manager.release(saxParser);
188        }
189    }
190    
191    public void transformForRendering(RichText source, ContentHandler handler) throws AmetysRepositoryException, SAXException, IOException
192    {
193        SAXParser saxParser = null;
194        
195        try
196        {
197            saxParser = (SAXParser) _manager.lookup(SAXParser.ROLE);
198            
199            try (InputStream is = source.getInputStream())
200            {
201                saxParser.parse(new InputSource(is), new IgnoreRootHandler(handler));
202            }
203        }
204        catch (ServiceException e)
205        {
206            throw new AmetysRepositoryException("Unable to get SAX parser", e);
207        }
208        finally
209        {
210            _manager.release(saxParser);
211        }
212    }
213}