001    /**
002     * Copyright (c) 2000-2012 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.TemplateException;
021    import com.liferay.portal.kernel.template.TemplateResource;
022    import com.liferay.portal.kernel.util.LocaleUtil;
023    import com.liferay.portal.kernel.util.StringBundler;
024    import com.liferay.portal.template.TemplateContextHelper;
025    
026    import java.io.Writer;
027    
028    import java.util.HashMap;
029    import java.util.Locale;
030    import java.util.Map;
031    
032    import javax.servlet.http.HttpServletRequest;
033    
034    import javax.xml.transform.Transformer;
035    import javax.xml.transform.TransformerFactory;
036    import javax.xml.transform.stream.StreamResult;
037    import javax.xml.transform.stream.StreamSource;
038    
039    /**
040     * @author Tina Tian
041     */
042    public class XSLTemplate implements Template {
043    
044            public XSLTemplate(
045                    XSLTemplateResource xslTemplateResource,
046                    TemplateResource errorTemplateResource, Map<String, Object> context,
047                    TemplateContextHelper templateContextHelper) {
048    
049                    if (xslTemplateResource == null) {
050                            throw new IllegalArgumentException("XSL template resource is null");
051                    }
052    
053                    if (templateContextHelper == null) {
054                            throw new IllegalArgumentException(
055                                    "Template context helper is null");
056                    }
057    
058                    _xslTemplateResource = xslTemplateResource;
059                    _errorTemplateResource = errorTemplateResource;
060                    _templateContextHelper = templateContextHelper;
061    
062                    _context = new HashMap<String, Object>();
063    
064                    if (context != null) {
065                            for (Map.Entry<String, Object> entry : context.entrySet()) {
066                                    put(entry.getKey(), entry.getValue());
067                            }
068                    }
069            }
070    
071            public Object get(String key) {
072                    return _context.get(key);
073            }
074    
075            public void prepare(HttpServletRequest request) {
076                    _templateContextHelper.prepare(this, request);
077            }
078    
079            public boolean processTemplate(Writer writer) throws TemplateException {
080                    TransformerFactory transformerFactory =
081                            TransformerFactory.newInstance();
082    
083                    String languageId = null;
084    
085                    XSLURIResolver xslURIResolver =
086                            _xslTemplateResource.getXSLURIResolver();
087    
088                    if (xslURIResolver != null) {
089                            languageId = xslURIResolver.getLanguageId();
090                    }
091    
092                    Locale locale = LocaleUtil.fromLanguageId(languageId);
093    
094                    XSLErrorListener xslErrorListener = new XSLErrorListener(locale);
095    
096                    transformerFactory.setErrorListener(xslErrorListener);
097    
098                    transformerFactory.setURIResolver(xslURIResolver);
099    
100                    StreamSource xmlSource = new StreamSource(
101                            _xslTemplateResource.getXMLReader());
102    
103                    Transformer transformer = _getTransformer(
104                            transformerFactory, _xslTemplateResource);
105    
106                    if (_errorTemplateResource == null) {
107                            try {
108                                    transformer.transform(xmlSource, new StreamResult(writer));
109    
110                                    return true;
111                            }
112                            catch (Exception e) {
113                                    throw new TemplateException(
114                                            "Unable to process XSL template " +
115                                                    _xslTemplateResource.getTemplateId(),
116                                            e);
117                            }
118                    }
119    
120                    try {
121                            UnsyncStringWriter unsyncStringWriter = new UnsyncStringWriter();
122    
123                            transformer.setParameter(WRITER, unsyncStringWriter);
124    
125                            transformer.transform(
126                                    xmlSource, new StreamResult(unsyncStringWriter));
127    
128                            StringBundler sb = unsyncStringWriter.getStringBundler();
129    
130                            sb.writeTo(writer);
131    
132                            return true;
133                    }
134                    catch (Exception e1) {
135                            Transformer errorTransformer = _getTransformer(
136                                    transformerFactory, _errorTemplateResource);
137    
138                            errorTransformer.setParameter(WRITER, writer);
139                            errorTransformer.setParameter(
140                                    "exception", xslErrorListener.getMessageAndLocation());
141    
142                            if (_errorTemplateResource instanceof StringTemplateResource) {
143                                    StringTemplateResource stringTemplateResource =
144                                            (StringTemplateResource)_errorTemplateResource;
145    
146                                    errorTransformer.setParameter(
147                                            "script", stringTemplateResource.getContent());
148                            }
149    
150                            if (xslErrorListener.getLocation() != null) {
151                                    errorTransformer.setParameter(
152                                            "column", new Integer(xslErrorListener.getColumnNumber()));
153                                    errorTransformer.setParameter(
154                                            "line", new Integer(xslErrorListener.getLineNumber()));
155                            }
156    
157                            try {
158                                    errorTransformer.transform(xmlSource, new StreamResult(writer));
159                            }
160                            catch (Exception e2) {
161                                    throw new TemplateException(
162                                            "Unable to process XSL template " +
163                                                    _errorTemplateResource.getTemplateId(),
164                                            e2);
165                            }
166    
167                            return false;
168                    }
169            }
170    
171            public void put(String key, Object value) {
172                    if (value == null) {
173                            return;
174                    }
175    
176                    _context.put(key, value);
177            }
178    
179            private Transformer _getTransformer(
180                            TransformerFactory transformerFactory,
181                            TemplateResource templateResource)
182                    throws TemplateException {
183    
184                    try {
185                            StreamSource scriptSource = new StreamSource(
186                                    templateResource.getReader());
187    
188                            Transformer transformer = transformerFactory.newTransformer(
189                                    scriptSource);
190    
191                            for (Map.Entry<String, Object> entry : _context.entrySet()) {
192                                    transformer.setParameter(entry.getKey(), entry.getValue());
193                            }
194    
195                            return transformer;
196                    }
197                    catch (Exception e) {
198                            throw new TemplateException(
199                                    "Unable to get Transformer for template " +
200                                            templateResource.getTemplateId(),
201                                    e);
202                    }
203            }
204    
205            private Map<String, Object> _context;
206            private TemplateResource _errorTemplateResource;
207            private TemplateContextHelper _templateContextHelper;
208            private XSLTemplateResource _xslTemplateResource;
209    
210    }