1
14
15 package com.liferay.portlet.journal.util;
16
17 import com.liferay.portal.kernel.io.unsync.UnsyncStringWriter;
18 import com.liferay.portal.kernel.util.GetterUtil;
19 import com.liferay.portal.kernel.util.HtmlUtil;
20 import com.liferay.portal.kernel.util.LocaleUtil;
21 import com.liferay.portal.kernel.util.StringPool;
22 import com.liferay.portal.kernel.util.StringUtil;
23 import com.liferay.portal.kernel.velocity.VelocityContext;
24 import com.liferay.portal.kernel.velocity.VelocityEngineUtil;
25 import com.liferay.portal.kernel.xml.Document;
26 import com.liferay.portal.kernel.xml.DocumentException;
27 import com.liferay.portal.kernel.xml.Element;
28 import com.liferay.portal.kernel.xml.Node;
29 import com.liferay.portal.kernel.xml.SAXReaderUtil;
30 import com.liferay.portal.model.Company;
31 import com.liferay.portal.security.permission.PermissionThreadLocal;
32 import com.liferay.portal.service.CompanyLocalServiceUtil;
33 import com.liferay.portal.util.ContentUtil;
34 import com.liferay.portal.util.PropsValues;
35 import com.liferay.portal.velocity.VelocityResourceListener;
36 import com.liferay.portlet.journal.TransformException;
37 import com.liferay.util.PwdGenerator;
38 import com.liferay.util.xml.CDATAUtil;
39
40 import java.io.IOException;
41
42 import java.util.ArrayList;
43 import java.util.HashMap;
44 import java.util.List;
45 import java.util.Map;
46
47 import org.apache.velocity.exception.ParseErrorException;
48 import org.apache.velocity.exception.VelocityException;
49
50
57 public class VelocityTemplateParser extends BaseTemplateParser {
58
59 protected String doTransform(
60 Map<String, String> tokens, String languageId, String xml,
61 String script)
62 throws Exception {
63
64 UnsyncStringWriter unsyncStringWriter = new UnsyncStringWriter(true);
65
66 boolean load = false;
67
68 try {
69 VelocityContext velocityContext =
70 VelocityEngineUtil.getWrappedRestrictedToolsContext();
71
72 Document doc = SAXReaderUtil.read(xml);
73
74 Element root = doc.getRootElement();
75
76 List<TemplateNode> nodes = extractDynamicContents(root);
77
78 for (TemplateNode node : nodes) {
79 velocityContext.put(node.getName(), node);
80 }
81
82 velocityContext.put("xmlRequest", root.element("request").asXML());
83 velocityContext.put(
84 "request", insertRequestVariables(root.element("request")));
85
86 long companyId = GetterUtil.getLong(tokens.get("company_id"));
87 Company company = CompanyLocalServiceUtil.getCompanyById(companyId);
88 long groupId = GetterUtil.getLong(tokens.get("group_id"));
89 String templateId = tokens.get("template_id");
90 String journalTemplatesPath =
91 VelocityResourceListener.JOURNAL_SEPARATOR + StringPool.SLASH +
92 companyId + StringPool.SLASH + groupId;
93 String randomNamespace =
94 PwdGenerator.getPassword(PwdGenerator.KEY3, 4) +
95 StringPool.UNDERLINE;
96
97 velocityContext.put("company", company);
98 velocityContext.put("companyId", String.valueOf(companyId));
99 velocityContext.put("groupId", String.valueOf(groupId));
100 velocityContext.put("journalTemplatesPath", journalTemplatesPath);
101 velocityContext.put(
102 "locale", LocaleUtil.fromLanguageId(languageId));
103 velocityContext.put(
104 "permissionChecker",
105 PermissionThreadLocal.getPermissionChecker());
106 velocityContext.put("randomNamespace", randomNamespace);
107
108 script = injectEditInPlace(xml, script);
109
110 try {
111 String velocityTemplateId = companyId + groupId + templateId;
112
113 load = VelocityEngineUtil.mergeTemplate(
114 velocityTemplateId, script, velocityContext,
115 unsyncStringWriter);
116 }
117 catch (VelocityException ve) {
118 velocityContext.put("exception", ve.getMessage());
119 velocityContext.put("script", script);
120
121 if (ve instanceof ParseErrorException) {
122 ParseErrorException pe = (ParseErrorException)ve;
123
124 velocityContext.put(
125 "column", new Integer(pe.getColumnNumber()));
126 velocityContext.put(
127 "line", new Integer(pe.getLineNumber()));
128 }
129
130 String velocityTemplateId =
131 PropsValues.JOURNAL_ERROR_TEMPLATE_VELOCITY;
132 String velocityTemplateContent = ContentUtil.get(
133 PropsValues.JOURNAL_ERROR_TEMPLATE_VELOCITY);
134
135 load = VelocityEngineUtil.mergeTemplate(
136 velocityTemplateId, velocityTemplateContent,
137 velocityContext, unsyncStringWriter);
138 }
139 }
140 catch (Exception e) {
141 if (e instanceof DocumentException) {
142 throw new TransformException("Unable to read XML document", e);
143 }
144 else if (e instanceof VelocityException) {
145 VelocityException pex = (VelocityException)e;
146
147 throw new TransformException(
148 "Unable to parse velocity template: " +
149 HtmlUtil.escape(pex.getMessage()),
150 e);
151 }
152 else if (e instanceof IOException) {
153 throw new TransformException(
154 "Error reading velocity template", e);
155 }
156 else if (e instanceof TransformException) {
157 throw (TransformException)e;
158 }
159 else {
160 throw new TransformException("Unhandled exception", e);
161 }
162 }
163
164 if (!load) {
165 throw new TransformException(
166 "Unable to dynamically load velocity transform script");
167 }
168
169 return unsyncStringWriter.toString();
170 }
171
172 protected List<TemplateNode> extractDynamicContents(Element parent)
173 throws TransformException {
174
175 List<TemplateNode> nodes = new ArrayList<TemplateNode>();
176
177 for (Element el : parent.elements("dynamic-element")) {
178 Element content = el.element("dynamic-content");
179
180 if (content == null) {
181 throw new TransformException(
182 "Element missing \"dynamic-content\"");
183 }
184
185 String name = el.attributeValue("name", "");
186
187 if (name.length() == 0) {
188 throw new TransformException(
189 "Element missing \"name\" attribute");
190 }
191
192 String type = el.attributeValue("type", "");
193
194 TemplateNode node = new TemplateNode(
195 name, CDATAUtil.strip(content.getText()), type);
196
197 if (el.element("dynamic-element") != null) {
198 node.appendChildren(extractDynamicContents(el));
199 }
200 else if (content.element("option") != null) {
201 for (Element option : content.elements("option")) {
202 node.appendOption(CDATAUtil.strip(option.getText()));
203 }
204 }
205
206 nodes.add(node);
207 }
208
209 return nodes;
210 }
211
212 protected String injectEditInPlace(String xml, String script)
213 throws DocumentException {
214
215 Document doc = SAXReaderUtil.read(xml);
216
217 List<Node> nodes = doc.selectNodes("//dynamic-element");
218
219 for (Node node : nodes) {
220 Element el = (Element)node;
221
222 String name = GetterUtil.getString(el.attributeValue("name"));
223 String type = GetterUtil.getString(el.attributeValue("type"));
224
225 if ((!name.startsWith("reserved-")) &&
226 (type.equals("text") || type.equals("text_box") ||
227 type.equals("text_area"))) {
228
229 script = wrapField(script, name, type, "data");
230 script = wrapField(script, name, type, "getData()");
231 }
232 }
233
234 return script;
235 }
236
237 protected Map<String, Object> insertRequestVariables(Element parent) {
238 Map<String, Object> map = new HashMap<String, Object>();
239
240 if (parent == null) {
241 return map;
242 }
243
244 for (Element el : parent.elements()) {
245 String name = el.getName();
246
247 if (name.equals("attribute")) {
248 map.put(el.elementText("name"), el.elementText("value"));
249 }
250 else if (name.equals("parameter")) {
251 name = el.element("name").getText();
252
253 List<Element> valueEls = el.elements("value");
254
255 if (valueEls.size() == 1) {
256 map.put(name, (valueEls.get(0)).getText());
257 }
258 else {
259 List<String> values = new ArrayList<String>();
260
261 for (Element valueEl : valueEls) {
262 values.add(valueEl.getText());
263 }
264
265 map.put(name, values);
266 }
267 }
268 else if (el.elements().size() > 0) {
269 map.put(name, insertRequestVariables(el));
270 }
271 else {
272 map.put(name, el.getText());
273 }
274 }
275
276 return map;
277 }
278
279 protected String wrapField(
280 String script, String name, String type, String call) {
281
282 String field = "$" + name + "." + call;
283 String wrappedField =
284 "<span class=\"journal-content-eip-" + type + "\" " +
285 "id=\"journal-content-field-name-" + name + "\">" + field +
286 "</span>";
287
288 return StringUtil.replace(
289 script, "$editInPlace(" + field + ")", wrappedField);
290 }
291
292 }