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