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.freemarker;
016    
017    import com.liferay.portal.kernel.template.StringTemplateResource;
018    import com.liferay.portal.kernel.template.TemplateConstants;
019    import com.liferay.portal.kernel.template.TemplateException;
020    import com.liferay.portal.kernel.template.TemplateResource;
021    import com.liferay.portal.template.AbstractTemplate;
022    import com.liferay.portal.template.TemplateContextHelper;
023    import com.liferay.portal.template.TemplateResourceThreadLocal;
024    import com.liferay.portal.util.PropsValues;
025    
026    import freemarker.core.ParseException;
027    
028    import freemarker.template.Configuration;
029    import freemarker.template.Template;
030    
031    import java.io.Writer;
032    
033    import java.security.AccessController;
034    import java.security.PrivilegedActionException;
035    import java.security.PrivilegedExceptionAction;
036    
037    import java.util.HashMap;
038    import java.util.Map;
039    import java.util.Set;
040    
041    /**
042     * @author Mika Koivisto
043     * @author Tina Tian
044     */
045    public class FreeMarkerTemplate extends AbstractTemplate {
046    
047            public FreeMarkerTemplate(
048                    TemplateResource templateResource,
049                    TemplateResource errorTemplateResource, Map<String, Object> context,
050                    Configuration configuration,
051                    TemplateContextHelper templateContextHelper) {
052    
053                    super(
054                            templateResource, errorTemplateResource, templateContextHelper,
055                            TemplateConstants.LANG_TYPE_FTL,
056                            PropsValues.FREEMARKER_ENGINE_RESOURCE_MODIFICATION_CHECK_INTERVAL);
057    
058                    _context = new HashMap<String, Object>();
059    
060                    if (context != null) {
061                            for (Map.Entry<String, Object> entry : context.entrySet()) {
062                                    put(entry.getKey(), entry.getValue());
063                            }
064                    }
065    
066                    _configuration = configuration;
067            }
068    
069            public Object get(String key) {
070                    return _context.get(key);
071            }
072    
073            public String[] getKeys() {
074                    Set<String> keys = _context.keySet();
075    
076                    return keys.toArray(new String[keys.size()]);
077            }
078    
079            public void put(String key, Object value) {
080                    if (value == null) {
081                            return;
082                    }
083    
084                    _context.put(key, value);
085            }
086    
087            @Override
088            protected void handleException(Exception exception, Writer writer)
089                    throws TemplateException {
090    
091                    if ((exception instanceof ParseException) ||
092                            (exception instanceof freemarker.template.TemplateException)) {
093    
094                            put("exception", exception.getMessage());
095    
096                            if (templateResource instanceof StringTemplateResource) {
097                                    StringTemplateResource stringTemplateResource =
098                                            (StringTemplateResource)templateResource;
099    
100                                    put("script", stringTemplateResource.getContent());
101                            }
102    
103                            if (exception instanceof ParseException) {
104                                    ParseException pe = (ParseException)exception;
105    
106                                    put("column", pe.getColumnNumber());
107                                    put("line", pe.getLineNumber());
108                            }
109    
110                            try {
111                                    processTemplate(errorTemplateResource, writer);
112                            }
113                            catch (Exception e) {
114                                    throw new TemplateException(
115                                            "Unable to process FreeMarker template " +
116                                                    errorTemplateResource.getTemplateId(),
117                                            e);
118                            }
119                    }
120                    else {
121                            throw new TemplateException(
122                                    "Unable to process FreeMarker template " +
123                                            templateResource.getTemplateId(),
124                                    exception);
125                    }
126            }
127    
128            @Override
129            protected void processTemplate(
130                            TemplateResource templateResource, Writer writer)
131                    throws Exception {
132    
133                    TemplateResourceThreadLocal.setTemplateResource(
134                            TemplateConstants.LANG_TYPE_FTL, templateResource);
135    
136                    try {
137                            Template template = AccessController.doPrivileged(
138                                    new TemplatePrivilegedExceptionAction(templateResource));
139    
140                            template.process(_context, writer);
141                    }
142                    catch (PrivilegedActionException pae) {
143                            throw pae.getException();
144                    }
145                    finally {
146                            TemplateResourceThreadLocal.setTemplateResource(
147                                    TemplateConstants.LANG_TYPE_FTL, null);
148                    }
149            }
150    
151            private Configuration _configuration;
152            private Map<String, Object> _context;
153    
154            private class TemplatePrivilegedExceptionAction
155                    implements PrivilegedExceptionAction<Template> {
156    
157                    public TemplatePrivilegedExceptionAction(
158                            TemplateResource templateResource) {
159    
160                            _templateResource = templateResource;
161                    }
162    
163                    public Template run() throws Exception {
164                            return _configuration.getTemplate(
165                                    getTemplateResourceUUID(_templateResource),
166                                    TemplateConstants.DEFAUT_ENCODING);
167                    }
168    
169                    private TemplateResource _templateResource;
170    
171            }
172    
173    }