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