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.portlet.journal.util;
016    
017    import com.liferay.portal.kernel.io.unsync.UnsyncStringWriter;
018    import com.liferay.portal.kernel.templateparser.BaseTemplateParser;
019    import com.liferay.portal.kernel.templateparser.TemplateContext;
020    import com.liferay.portal.kernel.templateparser.TemplateNode;
021    import com.liferay.portal.kernel.templateparser.TransformException;
022    import com.liferay.portal.kernel.util.StringBundler;
023    import com.liferay.portal.kernel.util.StringPool;
024    import com.liferay.portal.kernel.velocity.VelocityContext;
025    import com.liferay.portal.kernel.velocity.VelocityEngineUtil;
026    import com.liferay.portal.kernel.xml.Element;
027    import com.liferay.portal.util.PropsValues;
028    import com.liferay.portal.velocity.VelocityResourceListener;
029    import com.liferay.util.ContentUtil;
030    import com.liferay.util.PwdGenerator;
031    
032    import java.util.ArrayList;
033    import java.util.HashMap;
034    import java.util.List;
035    import java.util.Map;
036    
037    import org.apache.velocity.exception.ParseErrorException;
038    import org.apache.velocity.exception.VelocityException;
039    
040    /**
041     * @author Alexander Chow
042     * @author Brian Wing Shun Chan
043     * @author Raymond Aug??
044     */
045    public class VelocityTemplateParser extends BaseTemplateParser {
046    
047            protected String getErrorTemplateContent() {
048                    return ContentUtil.get(PropsValues.JOURNAL_ERROR_TEMPLATE_VELOCITY);
049            }
050    
051            protected String getErrorTemplateId() {
052                    return PropsValues.JOURNAL_ERROR_TEMPLATE_VELOCITY;
053            }
054    
055            protected String getJournalTemplatesPath() {
056                    StringBundler sb = new StringBundler(5);
057    
058                    sb.append(VelocityResourceListener.JOURNAL_SEPARATOR);
059                    sb.append(StringPool.SLASH);
060                    sb.append(getCompanyId());
061                    sb.append(StringPool.SLASH);
062                    sb.append(getGroupId());
063    
064                    return sb.toString();
065            }
066    
067            @Override
068            protected TemplateContext getTemplateContext() throws Exception {
069                    return VelocityEngineUtil.getWrappedRestrictedToolsContext();
070            }
071    
072            @Override
073            protected List<TemplateNode> getTemplateNodes(Element element)
074                    throws Exception {
075    
076                    List<TemplateNode> templateNodes = new ArrayList<TemplateNode>();
077    
078                    Map<String, TemplateNode> prototypeTemplateNodes =
079                            new HashMap<String, TemplateNode>();
080    
081                    List<Element> dynamicElementElements = element.elements(
082                            "dynamic-element");
083    
084                    for (Element dynamicElementElement : dynamicElementElements) {
085                            Element dynamicContentElement = dynamicElementElement.element(
086                                    "dynamic-content");
087    
088                            String data = StringPool.BLANK;
089    
090                            if (dynamicContentElement != null) {
091                                    data = dynamicContentElement.getText();
092                            }
093    
094                            String name = dynamicElementElement.attributeValue("name", "");
095    
096                            if (name.length() == 0) {
097                                    throw new TransformException(
098                                            "Element missing \"name\" attribute");
099                            }
100    
101                            String type = dynamicElementElement.attributeValue("type", "");
102    
103                            TemplateNode templateNode = new TemplateNode(
104                                    getThemeDisplay(), name, stripCDATA(data), type);
105    
106                            if (dynamicElementElement.element("dynamic-element") != null) {
107                                    templateNode.appendChildren(
108                                            getTemplateNodes(dynamicElementElement));
109                            }
110                            else if ((dynamicContentElement != null) &&
111                                             (dynamicContentElement.element("option") != null)) {
112    
113                                    List<Element> optionElements = dynamicContentElement.elements(
114                                            "option");
115    
116                                    for (Element optionElement : optionElements) {
117                                            templateNode.appendOption(
118                                                    stripCDATA(optionElement.getText()));
119                                    }
120                            }
121    
122                            TemplateNode prototypeTemplateNode = prototypeTemplateNodes.get(
123                                    name);
124    
125                            if (prototypeTemplateNode == null) {
126                                    prototypeTemplateNode = templateNode;
127    
128                                    prototypeTemplateNodes.put(name, prototypeTemplateNode);
129    
130                                    templateNodes.add(templateNode);
131                            }
132    
133                            prototypeTemplateNode.appendSibling(templateNode);
134                    }
135    
136                    return templateNodes;
137            }
138    
139            @Override
140            protected boolean mergeTemplate(
141                            TemplateContext templateContext,
142                            UnsyncStringWriter unsyncStringWriter)
143                    throws Exception {
144    
145                    VelocityContext velocityContext = (VelocityContext)templateContext;
146    
147                    try {
148                            return VelocityEngineUtil.mergeTemplate(
149                                    getTemplateId(), getScript(), velocityContext,
150                                    unsyncStringWriter);
151                    }
152                    catch (VelocityException ve) {
153                            String errorTemplateId = getErrorTemplateId();
154                            String errorTemplateContent = getErrorTemplateContent();
155    
156                            velocityContext.put("exception", ve.getMessage());
157                            velocityContext.put("script", getScript());
158    
159                            if (ve instanceof ParseErrorException) {
160                                    ParseErrorException pee = (ParseErrorException)ve;
161    
162                                    velocityContext.put("column", pee.getColumnNumber());
163                                    velocityContext.put("line", pee.getLineNumber());
164                            }
165    
166                            unsyncStringWriter.reset();
167    
168                            return VelocityEngineUtil.mergeTemplate(
169                                    errorTemplateId, errorTemplateContent, velocityContext,
170                                    unsyncStringWriter);
171                    }
172            }
173    
174            @Override
175            protected void populateTemplateContext(TemplateContext templateContext)
176                    throws Exception {
177    
178                    super.populateTemplateContext(templateContext);
179    
180                    templateContext.put("journalTemplatesPath", getJournalTemplatesPath());
181    
182                    String randomNamespace =
183                            PwdGenerator.getPassword(PwdGenerator.KEY3, 4) +
184                                    StringPool.UNDERLINE;
185    
186                    templateContext.put("randomNamespace", randomNamespace);
187            }
188    
189            protected String stripCDATA(String s) {
190                    if (s.startsWith(StringPool.CDATA_OPEN) &&
191                            s.endsWith(StringPool.CDATA_CLOSE)) {
192    
193                            s = s.substring(
194                                    StringPool.CDATA_OPEN.length(),
195                                    s.length() - StringPool.CDATA_CLOSE.length());
196                    }
197    
198                    return s;
199            }
200    
201    }