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