001    /**
002     * Copyright (c) 2000-2013 Liferay, Inc. All rights reserved.
003     *
004     * This library is free software; you can redistribute it and/or modify it under
005     * the terms of the GNU Lesser General Public License as published by the Free
006     * Software Foundation; either version 2.1 of the License, or (at your option)
007     * any later version.
008     *
009     * This library is distributed in the hope that it will be useful, but WITHOUT
010     * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
011     * FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License for more
012     * details.
013     */
014    
015    package com.liferay.portal.xsl;
016    
017    import com.liferay.portal.kernel.io.unsync.UnsyncStringWriter;
018    import com.liferay.portal.kernel.template.StringTemplateResource;
019    import com.liferay.portal.kernel.template.Template;
020    import com.liferay.portal.kernel.template.TemplateConstants;
021    import com.liferay.portal.kernel.template.TemplateException;
022    import com.liferay.portal.kernel.template.TemplateResource;
023    import com.liferay.portal.kernel.util.LocaleUtil;
024    import com.liferay.portal.kernel.util.StringBundler;
025    import com.liferay.portal.template.TemplateContextHelper;
026    
027    import java.io.Writer;
028    
029    import java.security.AccessController;
030    import java.security.PrivilegedActionException;
031    import java.security.PrivilegedExceptionAction;
032    
033    import java.util.HashMap;
034    import java.util.Locale;
035    import java.util.Map;
036    import java.util.Set;
037    
038    import javax.servlet.http.HttpServletRequest;
039    
040    import javax.xml.transform.Transformer;
041    import javax.xml.transform.TransformerFactory;
042    import javax.xml.transform.stream.StreamResult;
043    import javax.xml.transform.stream.StreamSource;
044    
045    /**
046     * @author Tina Tian
047     */
048    public class XSLTemplate implements Template {
049    
050            public XSLTemplate(
051                    XSLTemplateResource xslTemplateResource,
052                    TemplateResource errorTemplateResource,
053                    TemplateContextHelper templateContextHelper) {
054    
055                    if (xslTemplateResource == null) {
056                            throw new IllegalArgumentException("XSL template resource is null");
057                    }
058    
059                    if (templateContextHelper == null) {
060                            throw new IllegalArgumentException(
061                                    "Template context helper is null");
062                    }
063    
064                    _xslTemplateResource = xslTemplateResource;
065                    _errorTemplateResource = errorTemplateResource;
066                    _templateContextHelper = templateContextHelper;
067    
068                    _context = new HashMap<String, Object>();
069            }
070    
071            @Override
072            public Object get(String key) {
073                    return _context.get(key);
074            }
075    
076            @Override
077            public String[] getKeys() {
078                    Set<String> keys = _context.keySet();
079    
080                    return keys.toArray(new String[keys.size()]);
081            }
082    
083            @Override
084            public void prepare(HttpServletRequest request) {
085                    _templateContextHelper.prepare(this, request);
086            }
087    
088            @Override
089            public void processTemplate(Writer writer) throws TemplateException {
090                    TransformerFactory transformerFactory =
091                            TransformerFactory.newInstance();
092    
093                    String languageId = null;
094    
095                    XSLURIResolver xslURIResolver =
096                            _xslTemplateResource.getXSLURIResolver();
097    
098                    if (xslURIResolver != null) {
099                            languageId = xslURIResolver.getLanguageId();
100                    }
101    
102                    Locale locale = LocaleUtil.fromLanguageId(languageId);
103    
104                    XSLErrorListener xslErrorListener = new XSLErrorListener(locale);
105    
106                    transformerFactory.setErrorListener(xslErrorListener);
107    
108                    transformerFactory.setURIResolver(xslURIResolver);
109    
110                    StreamSource xmlSource = new StreamSource(
111                            _xslTemplateResource.getXMLReader());
112    
113                    Transformer transformer = null;
114    
115                    if (_errorTemplateResource == null) {
116                            try {
117                                    transformer = _getTransformer(
118                                            transformerFactory, _xslTemplateResource);
119    
120                                    transformer.transform(xmlSource, new StreamResult(writer));
121    
122                                    return;
123                            }
124                            catch (Exception e) {
125                                    throw new TemplateException(
126                                            "Unable to process XSL template " +
127                                                    _xslTemplateResource.getTemplateId(),
128                                            e);
129                            }
130                    }
131    
132                    try {
133                            UnsyncStringWriter unsyncStringWriter = new UnsyncStringWriter();
134    
135                            transformer = _getTransformer(
136                                    transformerFactory, _xslTemplateResource);
137    
138                            transformer.setParameter(
139                                    TemplateConstants.WRITER, unsyncStringWriter);
140    
141                            transformer.transform(
142                                    xmlSource, new StreamResult(unsyncStringWriter));
143    
144                            StringBundler sb = unsyncStringWriter.getStringBundler();
145    
146                            sb.writeTo(writer);
147                    }
148                    catch (Exception e1) {
149                            Transformer errorTransformer = _getTransformer(
150                                    transformerFactory, _errorTemplateResource);
151    
152                            errorTransformer.setParameter(TemplateConstants.WRITER, writer);
153                            errorTransformer.setParameter(
154                                    "exception", xslErrorListener.getMessageAndLocation());
155    
156                            if (_errorTemplateResource instanceof StringTemplateResource) {
157                                    StringTemplateResource stringTemplateResource =
158                                            (StringTemplateResource)_errorTemplateResource;
159    
160                                    errorTransformer.setParameter(
161                                            "script", stringTemplateResource.getContent());
162                            }
163    
164                            if (xslErrorListener.getLocation() != null) {
165                                    errorTransformer.setParameter(
166                                            "column", new Integer(xslErrorListener.getColumnNumber()));
167                                    errorTransformer.setParameter(
168                                            "line", new Integer(xslErrorListener.getLineNumber()));
169                            }
170    
171                            try {
172                                    errorTransformer.transform(xmlSource, new StreamResult(writer));
173                            }
174                            catch (Exception e2) {
175                                    throw new TemplateException(
176                                            "Unable to process XSL template " +
177                                                    _errorTemplateResource.getTemplateId(),
178                                            e2);
179                            }
180                    }
181            }
182    
183            @Override
184            public void put(String key, Object value) {
185                    if (value == null) {
186                            return;
187                    }
188    
189                    _context.put(key, value);
190            }
191    
192            private Transformer _getTransformer(
193                            TransformerFactory transformerFactory,
194                            TemplateResource templateResource)
195                    throws TemplateException {
196    
197                    try {
198                            StreamSource scriptSource = new StreamSource(
199                                    templateResource.getReader());
200    
201                            Transformer transformer = AccessController.doPrivileged(
202                                    new TransformerPrivilegedExceptionAction(
203                                            transformerFactory, scriptSource));
204    
205                            for (Map.Entry<String, Object> entry : _context.entrySet()) {
206                                    transformer.setParameter(entry.getKey(), entry.getValue());
207                            }
208    
209                            return transformer;
210                    }
211                    catch (PrivilegedActionException pae) {
212                            throw new TemplateException(
213                                    "Unable to get Transformer for template " +
214                                            templateResource.getTemplateId(),
215                                    pae.getException());
216                    }
217                    catch (Exception e) {
218                            throw new TemplateException(
219                                    "Unable to get Transformer for template " +
220                                            templateResource.getTemplateId(),
221                                    e);
222                    }
223            }
224    
225            private Map<String, Object> _context;
226            private TemplateResource _errorTemplateResource;
227            private TemplateContextHelper _templateContextHelper;
228            private XSLTemplateResource _xslTemplateResource;
229    
230            private class TransformerPrivilegedExceptionAction
231                    implements PrivilegedExceptionAction<Transformer> {
232    
233                    public TransformerPrivilegedExceptionAction(
234                            TransformerFactory transformerFactory, StreamSource scriptSource) {
235    
236                            _transformerFactory = transformerFactory;
237                            _scriptSource = scriptSource;
238                    }
239    
240                    @Override
241                    public Transformer run() throws Exception {
242                            return _transformerFactory.newTransformer(_scriptSource);
243                    }
244    
245                    private StreamSource _scriptSource;
246                    private TransformerFactory _transformerFactory;
247    
248            }
249    
250    }