001
014
015 package com.liferay.portlet.journal.util;
016
017 import com.liferay.portal.kernel.io.unsync.UnsyncStringWriter;
018 import com.liferay.portal.kernel.util.GetterUtil;
019 import com.liferay.portal.kernel.util.HtmlUtil;
020 import com.liferay.portal.kernel.util.LocaleUtil;
021 import com.liferay.portal.kernel.util.StringPool;
022 import com.liferay.portal.kernel.util.StringUtil;
023 import com.liferay.portal.kernel.velocity.VelocityContext;
024 import com.liferay.portal.kernel.velocity.VelocityEngineUtil;
025 import com.liferay.portal.kernel.xml.Document;
026 import com.liferay.portal.kernel.xml.DocumentException;
027 import com.liferay.portal.kernel.xml.Element;
028 import com.liferay.portal.kernel.xml.Node;
029 import com.liferay.portal.kernel.xml.SAXReaderUtil;
030 import com.liferay.portal.model.Company;
031 import com.liferay.portal.security.permission.PermissionThreadLocal;
032 import com.liferay.portal.service.CompanyLocalServiceUtil;
033 import com.liferay.portal.theme.ThemeDisplay;
034 import com.liferay.portal.util.ContentUtil;
035 import com.liferay.portal.util.PropsValues;
036 import com.liferay.portal.velocity.VelocityResourceListener;
037 import com.liferay.portlet.journal.TransformException;
038 import com.liferay.util.PwdGenerator;
039 import com.liferay.util.xml.CDATAUtil;
040
041 import java.io.IOException;
042
043 import java.util.ArrayList;
044 import java.util.HashMap;
045 import java.util.List;
046 import java.util.Map;
047
048 import org.apache.velocity.exception.ParseErrorException;
049 import org.apache.velocity.exception.VelocityException;
050
051
056 public class VelocityTemplateParser extends BaseTemplateParser {
057
058 protected String doTransform(
059 ThemeDisplay themeDisplay, Map<String, String> tokens,
060 String viewMode, String languageId, String xml, String script)
061 throws Exception {
062
063 UnsyncStringWriter unsyncStringWriter = new UnsyncStringWriter();
064
065 boolean load = false;
066
067 try {
068 VelocityContext velocityContext =
069 VelocityEngineUtil.getWrappedRestrictedToolsContext();
070
071 Document doc = SAXReaderUtil.read(xml);
072
073 Element root = doc.getRootElement();
074
075 List<TemplateNode> nodes = extractDynamicContents(
076 themeDisplay, root);
077
078 for (TemplateNode node : nodes) {
079 velocityContext.put(node.getName(), node);
080 }
081
082 velocityContext.put("xmlRequest", root.element("request").asXML());
083 velocityContext.put(
084 "request", insertRequestVariables(root.element("request")));
085
086 long companyId = GetterUtil.getLong(tokens.get("company_id"));
087 Company company = CompanyLocalServiceUtil.getCompanyById(companyId);
088 long groupId = GetterUtil.getLong(tokens.get("group_id"));
089 String templateId = tokens.get("template_id");
090 String journalTemplatesPath =
091 VelocityResourceListener.JOURNAL_SEPARATOR + StringPool.SLASH +
092 companyId + StringPool.SLASH + groupId;
093 String randomNamespace =
094 PwdGenerator.getPassword(PwdGenerator.KEY3, 4) +
095 StringPool.UNDERLINE;
096
097 velocityContext.put("company", company);
098 velocityContext.put("companyId", String.valueOf(companyId));
099 velocityContext.put("groupId", String.valueOf(groupId));
100 velocityContext.put("journalTemplatesPath", journalTemplatesPath);
101 velocityContext.put("viewMode", viewMode);
102 velocityContext.put(
103 "locale", LocaleUtil.fromLanguageId(languageId));
104 velocityContext.put(
105 "permissionChecker",
106 PermissionThreadLocal.getPermissionChecker());
107 velocityContext.put("randomNamespace", randomNamespace);
108
109 script = injectEditInPlace(xml, script);
110
111 try {
112 String velocityTemplateId = companyId + groupId + templateId;
113
114 load = VelocityEngineUtil.mergeTemplate(
115 velocityTemplateId, script, velocityContext,
116 unsyncStringWriter);
117 }
118 catch (VelocityException ve) {
119 velocityContext.put("exception", ve.getMessage());
120 velocityContext.put("script", script);
121
122 if (ve instanceof ParseErrorException) {
123 ParseErrorException pe = (ParseErrorException)ve;
124
125 velocityContext.put(
126 "column", new Integer(pe.getColumnNumber()));
127 velocityContext.put(
128 "line", new Integer(pe.getLineNumber()));
129 }
130
131 String velocityTemplateId =
132 PropsValues.JOURNAL_ERROR_TEMPLATE_VELOCITY;
133 String velocityTemplateContent = ContentUtil.get(
134 PropsValues.JOURNAL_ERROR_TEMPLATE_VELOCITY);
135
136 load = VelocityEngineUtil.mergeTemplate(
137 velocityTemplateId, velocityTemplateContent,
138 velocityContext, unsyncStringWriter);
139 }
140 }
141 catch (Exception e) {
142 if (e instanceof DocumentException) {
143 throw new TransformException("Unable to read XML document", e);
144 }
145 else if (e instanceof VelocityException) {
146 VelocityException pex = (VelocityException)e;
147
148 throw new TransformException(
149 "Unable to parse velocity template: " +
150 HtmlUtil.escape(pex.getMessage()),
151 e);
152 }
153 else if (e instanceof IOException) {
154 throw new TransformException(
155 "Error reading velocity template", e);
156 }
157 else if (e instanceof TransformException) {
158 throw (TransformException)e;
159 }
160 else {
161 throw new TransformException("Unhandled exception", e);
162 }
163 }
164
165 if (!load) {
166 throw new TransformException(
167 "Unable to dynamically load velocity transform script");
168 }
169
170 return unsyncStringWriter.toString();
171 }
172
173 protected List<TemplateNode> extractDynamicContents(
174 ThemeDisplay themeDisplay, Element parent)
175 throws TransformException {
176
177 List<TemplateNode> nodes = new ArrayList<TemplateNode>();
178
179 Map<String, TemplateNode> prototypeNodes =
180 new HashMap<String, TemplateNode>();
181
182 for (Element el : parent.elements("dynamic-element")) {
183 Element content = el.element("dynamic-content");
184
185 String data = StringPool.BLANK;
186
187 if (content != null) {
188 data = content.getText();
189 }
190
191 String name = el.attributeValue("name", "");
192
193 if (name.length() == 0) {
194 throw new TransformException(
195 "Element missing \"name\" attribute");
196 }
197
198 String type = el.attributeValue("type", "");
199
200 TemplateNode node = new TemplateNode(
201 themeDisplay, name, CDATAUtil.strip(data), type);
202
203 if (el.element("dynamic-element") != null) {
204 node.appendChildren(extractDynamicContents(themeDisplay, el));
205 }
206 else if ((content != null) && (content.element("option") != null)) {
207 for (Element option : content.elements("option")) {
208 node.appendOption(CDATAUtil.strip(option.getText()));
209 }
210 }
211
212 TemplateNode prototypeNode = prototypeNodes.get(name);
213
214 if (prototypeNode == null) {
215 prototypeNode = node;
216
217 prototypeNodes.put(name, prototypeNode);
218
219 nodes.add(node);
220 }
221
222 prototypeNode.appendSibling(node);
223 }
224
225 return nodes;
226 }
227
228 protected String injectEditInPlace(String xml, String script)
229 throws DocumentException {
230
231 Document doc = SAXReaderUtil.read(xml);
232
233 List<Node> nodes = doc.selectNodes("
234
235 for (Node node : nodes) {
236 Element el = (Element)node;
237
238 String name = GetterUtil.getString(el.attributeValue("name"));
239 String type = GetterUtil.getString(el.attributeValue("type"));
240
241 if ((!name.startsWith("reserved-")) &&
242 (type.equals("text") || type.equals("text_box") ||
243 type.equals("text_area"))) {
244
245 script = wrapField(script, name, type, "data");
246 script = wrapField(script, name, type, "getData()");
247 }
248 }
249
250 return script;
251 }
252
253 protected Map<String, Object> insertRequestVariables(Element parent) {
254 Map<String, Object> map = new HashMap<String, Object>();
255
256 if (parent == null) {
257 return map;
258 }
259
260 for (Element el : parent.elements()) {
261 String name = el.getName();
262
263 if (name.equals("attribute")) {
264 map.put(el.elementText("name"), el.elementText("value"));
265 }
266 else if (name.equals("parameter")) {
267 name = el.element("name").getText();
268
269 List<Element> valueEls = el.elements("value");
270
271 if (valueEls.size() == 1) {
272 map.put(name, (valueEls.get(0)).getText());
273 }
274 else {
275 List<String> values = new ArrayList<String>();
276
277 for (Element valueEl : valueEls) {
278 values.add(valueEl.getText());
279 }
280
281 map.put(name, values);
282 }
283 }
284 else if (el.elements().size() > 0) {
285 map.put(name, insertRequestVariables(el));
286 }
287 else {
288 map.put(name, el.getText());
289 }
290 }
291
292 return map;
293 }
294
295 protected String wrapField(
296 String script, String name, String type, String call) {
297
298 String field = "$" + name + "." + call;
299 String wrappedField =
300 "<span class=\"journal-content-eip-" + type + "\" " +
301 "id=\"journal-content-field-name-" + name + "\">" + field +
302 "</span>";
303
304 return StringUtil.replace(
305 script, "$editInPlace(" + field + ")", wrappedField);
306 }
307
308 }