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.xml.Document;
31 import com.liferay.portal.kernel.xml.DocumentException;
32 import com.liferay.portal.kernel.xml.Element;
33 import com.liferay.portal.kernel.xml.Node;
34 import com.liferay.portal.kernel.xml.SAXReaderUtil;
35 import com.liferay.portal.model.Company;
36 import com.liferay.portal.security.permission.PermissionThreadLocal;
37 import com.liferay.portal.service.CompanyLocalServiceUtil;
38 import com.liferay.portal.util.ContentUtil;
39 import com.liferay.portal.util.PropsKeys;
40 import com.liferay.portal.util.PropsUtil;
41 import com.liferay.portal.util.PropsValues;
42 import com.liferay.portal.velocity.VelocityResourceListener;
43 import com.liferay.portal.velocity.VelocityVariables;
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 import java.io.StringWriter;
50
51 import java.util.ArrayList;
52 import java.util.HashMap;
53 import java.util.List;
54 import java.util.Map;
55
56 import org.apache.velocity.VelocityContext;
57 import org.apache.velocity.app.Velocity;
58 import org.apache.velocity.exception.ParseErrorException;
59 import org.apache.velocity.exception.VelocityException;
60
61
69 public class JournalVmUtil {
70
71 public static final String[] _TEMPLATE_VELOCITY_RESTRICTED_VARIABLES =
72 PropsUtil.getArray(
73 PropsKeys.JOURNAL_TEMPLATE_VELOCITY_RESTRICTED_VARIABLES);
74
75 public static String transform(
76 Map<String, String> tokens, String languageId, String xml,
77 String script)
78 throws TransformException {
79
80 StringWriter output = new StringWriter();
81
82 boolean load = false;
83
84 try {
85 VelocityContext context = new VelocityContext();
86
87 Document doc = SAXReaderUtil.read(xml);
88
89 Element root = doc.getRootElement();
90
91 List<TemplateNode> nodes = _extractDynamicContents(root);
92
93 for (TemplateNode node : nodes) {
94 context.put(node.getName(), node);
95 }
96
97 context.put("xmlRequest", root.element("request").asXML());
98 context.put(
99 "request", _insertRequestVariables(root.element("request")));
100
101 long companyId = GetterUtil.getLong(tokens.get("company_id"));
102 Company company = CompanyLocalServiceUtil.getCompanyById(companyId);
103 long groupId = GetterUtil.getLong(tokens.get("group_id"));
104 String journalTemplatesPath =
105 VelocityResourceListener.JOURNAL_SEPARATOR + StringPool.SLASH +
106 companyId + StringPool.SLASH + groupId;
107 String randomNamespace =
108 PwdGenerator.getPassword(PwdGenerator.KEY3, 4) +
109 StringPool.UNDERLINE;
110
111 context.put("company", company);
112 context.put("companyId", String.valueOf(companyId));
113 context.put("groupId", String.valueOf(groupId));
114 context.put("journalTemplatesPath", journalTemplatesPath);
115 context.put("locale", LocaleUtil.fromLanguageId(languageId));
116 context.put(
117 "permissionChecker",
118 PermissionThreadLocal.getPermissionChecker());
119 context.put("randomNamespace", randomNamespace);
120
121 VelocityVariables.insertHelperUtilities(
122 context, _TEMPLATE_VELOCITY_RESTRICTED_VARIABLES);
123
124 script = _injectEditInPlace(xml, script);
125
126 try {
127 load = Velocity.evaluate(
128 context, output, JournalVmUtil.class.getName(), script);
129 }
130 catch (VelocityException ve) {
131 context.put("exception", ve.getMessage());
132 context.put("script", script);
133
134 if (ve instanceof ParseErrorException) {
135 ParseErrorException pe = (ParseErrorException)ve;
136
137 context.put("column", new Integer(pe.getColumnNumber()));
138 context.put("line", new Integer(pe.getLineNumber()));
139 }
140
141 String errorTemplate = ContentUtil.get(
142 PropsValues.JOURNAL_ERROR_TEMPLATE_VELOCITY);
143
144 load = Velocity.evaluate(
145 context, output, JournalVmUtil.class.getName(),
146 errorTemplate);
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 output.toString();
179 }
180
181 private static List<TemplateNode> _extractDynamicContents(Element parent)
182 throws TransformException {
183
184 List<TemplateNode> nodes = new ArrayList<TemplateNode>();
185
186 for (Element el : parent.elements("dynamic-element")) {
187 Element content = el.element("dynamic-content");
188
189 if (content == null) {
190 throw new TransformException(
191 "Element missing \"dynamic-content\"");
192 }
193
194 String name = el.attributeValue("name", "");
195
196 if (name.length() == 0) {
197 throw new TransformException(
198 "Element missing \"name\" attribute");
199 }
200
201 String type = el.attributeValue("type", "");
202
203 TemplateNode node = new TemplateNode(
204 name, CDATAUtil.strip(content.getText()), type);
205
206 if (el.element("dynamic-element") != null) {
207 node.appendChildren(_extractDynamicContents(el));
208 }
209 else if (content.element("option") != null) {
210 for (Element option : content.elements("option")) {
211 node.appendOption(CDATAUtil.strip(option.getText()));
212 }
213 }
214
215 nodes.add(node);
216 }
217
218 return nodes;
219 }
220
221 private static String _injectEditInPlace(String xml, String script)
222 throws DocumentException {
223
224 Document doc = SAXReaderUtil.read(xml);
225
226 List<Node> nodes = doc.selectNodes("//dynamic-element");
227
228 for (Node node : nodes) {
229 Element el = (Element)node;
230
231 String name = GetterUtil.getString(el.attributeValue("name"));
232 String type = GetterUtil.getString(el.attributeValue("type"));
233
234 if ((!name.startsWith("reserved-")) &&
235 (type.equals("text") || type.equals("text_box") ||
236 type.equals("text_area"))) {
237
238 script = _wrapField(script, name, type, "data");
239 script = _wrapField(script, name, type, "getData()");
240 }
241 }
242
243 return script;
244 }
245
246 private static Map<String, Object> _insertRequestVariables(
247 Element parent) {
248
249 Map<String, Object> map = new HashMap<String, Object>();
250
251 if (parent == null) {
252 return map;
253 }
254
255 for (Element el : parent.elements()) {
256 String name = el.getName();
257
258 if (name.equals("attribute")) {
259 map.put(el.elementText("name"), el.elementText("value"));
260 }
261 else if (name.equals("parameter")) {
262 name = el.element("name").getText();
263
264 List<Element> valueEls = el.elements("value");
265
266 if (valueEls.size() == 1) {
267 map.put(name, (valueEls.get(0)).getText());
268 }
269 else {
270 List<String> values = new ArrayList<String>();
271
272 for (Element valueEl : valueEls) {
273 values.add(valueEl.getText());
274 }
275
276 map.put(name, values);
277 }
278 }
279 else if (el.elements().size() > 0) {
280 map.put(name, _insertRequestVariables(el));
281 }
282 else {
283 map.put(name, el.getText());
284 }
285 }
286
287 return map;
288 }
289
290 private static String _wrapField(
291 String script, String name, String type, String call) {
292
293 String field = "$" + name + "." + call;
294 String wrappedField =
295 "<span class=\"journal-content-eip-" + type + "\" " +
296 "id=\"journal-content-field-name-" + name + "\">" + field +
297 "</span>";
298
299 return StringUtil.replace(
300 script, "$editInPlace(" + field + ")", wrappedField);
301 }
302
303 }