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            @Override
070            public Object get(String key) {
071                    return _context.get(key);
072            }
073    
074            @Override
075            public String[] getKeys() {
076                    Set<String> keys = _context.keySet();
077    
078                    return keys.toArray(new String[keys.size()]);
079            }
080    
081            @Override
082            public void put(String key, Object value) {
083                    if (value == null) {
084                            return;
085                    }
086    
087                    _context.put(key, value);
088            }
089    
090            @Override
091            protected void handleException(Exception exception, Writer writer)
092                    throws TemplateException {
093    
094                    if ((exception instanceof ParseException) ||
095                            (exception instanceof freemarker.template.TemplateException)) {
096    
097                            put("exception", exception.getMessage());
098    
099                            if (templateResource instanceof StringTemplateResource) {
100                                    StringTemplateResource stringTemplateResource =
101                                            (StringTemplateResource)templateResource;
102    
103                                    put("script", stringTemplateResource.getContent());
104                            }
105    
106                            if (exception instanceof ParseException) {
107                                    ParseException pe = (ParseException)exception;
108    
109                                    put("column", pe.getColumnNumber());
110                                    put("line", pe.getLineNumber());
111                            }
112    
113                            try {
114                                    processTemplate(errorTemplateResource, writer);
115                            }
116                            catch (Exception e) {
117                                    throw new TemplateException(
118                                            "Unable to process FreeMarker template " +
119                                                    errorTemplateResource.getTemplateId(),
120                                            e);
121                            }
122                    }
123                    else {
124                            throw new TemplateException(
125                                    "Unable to process FreeMarker template " +
126                                            templateResource.getTemplateId(),
127                                    exception);
128                    }
129            }
130    
131            @Override
132            protected void processTemplate(
133                            TemplateResource templateResource, Writer writer)
134                    throws Exception {
135    
136                    TemplateResourceThreadLocal.setTemplateResource(
137                            TemplateConstants.LANG_TYPE_FTL, templateResource);
138    
139                    try {
140                            Template template = AccessController.doPrivileged(
141                                    new TemplatePrivilegedExceptionAction(templateResource));
142    
143                            template.process(_context, writer);
144                    }
145                    catch (PrivilegedActionException pae) {
146                            throw pae.getException();
147                    }
148                    finally {
149                            TemplateResourceThreadLocal.setTemplateResource(
150                                    TemplateConstants.LANG_TYPE_FTL, null);
151                    }
152            }
153    
154            private Configuration _configuration;
155            private Map<String, Object> _context;
156    
157            private class TemplatePrivilegedExceptionAction
158                    implements PrivilegedExceptionAction<Template> {
159    
160                    public TemplatePrivilegedExceptionAction(
161                            TemplateResource templateResource) {
162    
163                            _templateResource = templateResource;
164                    }
165    
166                    @Override
167                    public Template run() throws Exception {
168                            return _configuration.getTemplate(
169                                    getTemplateResourceUUID(_templateResource),
170                                    TemplateConstants.DEFAUT_ENCODING);
171                    }
172    
173                    private TemplateResource _templateResource;
174    
175            }
176    
177    }