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.velocity;
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.kernel.util.ArrayUtil;
022    import com.liferay.portal.template.AbstractTemplate;
023    import com.liferay.portal.template.TemplateContextHelper;
024    import com.liferay.portal.template.TemplateResourceThreadLocal;
025    import com.liferay.portal.util.PropsValues;
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 org.apache.velocity.Template;
034    import org.apache.velocity.VelocityContext;
035    import org.apache.velocity.app.VelocityEngine;
036    import org.apache.velocity.context.Context;
037    import org.apache.velocity.exception.ParseErrorException;
038    
039    /**
040     * @author Tina Tian
041     */
042    public class VelocityTemplate extends AbstractTemplate {
043    
044            public VelocityTemplate(
045                    TemplateResource templateResource,
046                    TemplateResource errorTemplateResource, VelocityContext velocityContext,
047                    VelocityEngine velocityEngine,
048                    TemplateContextHelper templateContextHelper) {
049    
050                    super(
051                            templateResource, errorTemplateResource, templateContextHelper,
052                            TemplateConstants.LANG_TYPE_VM,
053                            PropsValues.VELOCITY_ENGINE_RESOURCE_MODIFICATION_CHECK_INTERVAL);
054    
055                    if (velocityContext == null) {
056                            _velocityContext = new VelocityContext();
057                    }
058                    else {
059                            _velocityContext = new VelocityContext(velocityContext);
060                    }
061    
062                    _velocityEngine = velocityEngine;
063            }
064    
065            @Override
066            public Object get(String key) {
067                    return _velocityContext.get(key);
068            }
069    
070            @Override
071            public String[] getKeys() {
072                    Object[] keyObjects = _velocityContext.getKeys();
073    
074                    Context context = _velocityContext.getChainedContext();
075    
076                    Object[] innerKeyObjects = context.getKeys();
077    
078                    String[] keys = new String[keyObjects.length + innerKeyObjects.length];
079    
080                    ArrayUtil.combine(keyObjects, innerKeyObjects, keys);
081    
082                    return keys;
083            }
084    
085            @Override
086            public void put(String key, Object value) {
087                    if (value == null) {
088                            return;
089                    }
090    
091                    _velocityContext.put(key, value);
092            }
093    
094            @Override
095            protected void handleException(Exception exception, Writer writer)
096                    throws TemplateException {
097    
098                    put("exception", exception.getMessage());
099    
100                    if (templateResource instanceof StringTemplateResource) {
101                            StringTemplateResource stringTemplateResource =
102                                    (StringTemplateResource)templateResource;
103    
104                            put("script", stringTemplateResource.getContent());
105                    }
106    
107                    if (exception instanceof ParseErrorException) {
108                            ParseErrorException pee = (ParseErrorException)exception;
109    
110                            put("column", pee.getColumnNumber());
111                            put("line", pee.getLineNumber());
112                    }
113    
114                    try {
115                            processTemplate(errorTemplateResource, writer);
116                    }
117                    catch (Exception e) {
118                            throw new TemplateException(
119                                    "Unable to process Velocity template " +
120                                            errorTemplateResource.getTemplateId(),
121                                    e);
122                    }
123            }
124    
125            @Override
126            protected void processTemplate(
127                            TemplateResource templateResource, Writer writer)
128                    throws Exception {
129    
130                    TemplateResourceThreadLocal.setTemplateResource(
131                            TemplateConstants.LANG_TYPE_VM, templateResource);
132    
133                    try {
134                            Template template = AccessController.doPrivileged(
135                                    new TemplatePrivilegedExceptionAction(templateResource));
136    
137                            template.merge(_velocityContext, writer);
138                    }
139                    catch (PrivilegedActionException pae) {
140                            throw pae.getException();
141                    }
142                    finally {
143                            TemplateResourceThreadLocal.setTemplateResource(
144                                    TemplateConstants.LANG_TYPE_VM, null);
145                    }
146            }
147    
148            private VelocityContext _velocityContext;
149            private VelocityEngine _velocityEngine;
150    
151            private class TemplatePrivilegedExceptionAction
152                    implements PrivilegedExceptionAction<Template> {
153    
154                    public TemplatePrivilegedExceptionAction(
155                            TemplateResource templateResource) {
156    
157                            _templateResource = templateResource;
158                    }
159    
160                    @Override
161                    public Template run() throws Exception {
162                            return _velocityEngine.getTemplate(
163                                    getTemplateResourceUUID(_templateResource),
164                                    TemplateConstants.DEFAUT_ENCODING);
165                    }
166    
167                    private TemplateResource _templateResource;
168    
169            }
170    
171    }