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