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