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