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