1   /**
2    * Copyright (c) 2000-2008 Liferay, Inc. All rights reserved.
3    *
4    * Permission is hereby granted, free of charge, to any person obtaining a copy
5    * of this software and associated documentation files (the "Software"), to deal
6    * in the Software without restriction, including without limitation the rights
7    * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
8    * copies of the Software, and to permit persons to whom the Software is
9    * furnished to do so, subject to the following conditions:
10   *
11   * The above copyright notice and this permission notice shall be included in
12   * all copies or substantial portions of the Software.
13   *
14   * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
15   * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
16   * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
17   * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
18   * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
19   * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
20   * SOFTWARE.
21   */
22  
23  package com.liferay.portlet.journal.util;
24  
25  import com.liferay.portal.kernel.util.GetterUtil;
26  import com.liferay.portal.kernel.util.StringPool;
27  import com.liferay.portal.kernel.util.StringUtil;
28  import com.liferay.portal.util.PropsUtil;
29  import com.liferay.portal.velocity.VelocityResourceListener;
30  import com.liferay.portal.velocity.VelocityVariables;
31  import com.liferay.portlet.journal.TransformException;
32  import com.liferay.util.Html;
33  import com.liferay.util.PwdGenerator;
34  import com.liferay.util.xml.CDATAUtil;
35  
36  import java.io.IOException;
37  import java.io.StringReader;
38  import java.io.StringWriter;
39  
40  import java.util.ArrayList;
41  import java.util.HashMap;
42  import java.util.Iterator;
43  import java.util.List;
44  import java.util.Map;
45  
46  import org.apache.velocity.VelocityContext;
47  import org.apache.velocity.app.Velocity;
48  import org.apache.velocity.exception.VelocityException;
49  
50  import org.dom4j.Document;
51  import org.dom4j.DocumentException;
52  import org.dom4j.Element;
53  import org.dom4j.io.SAXReader;
54  
55  /**
56   * <a href="JournalVmUtil.java.html"><b><i>View Source</i></b></a>
57   *
58   * @author Alexander Chow
59   * @author Brian Wing Shun Chan
60   * @author Raymond Augé
61   *
62   */
63  public class JournalVmUtil {
64  
65      public static final String[] _TEMPLATE_VELOCITY_RESTRICTED_VARIABLES =
66          PropsUtil.getArray(
67              PropsUtil.JOURNAL_TEMPLATE_VELOCITY_RESTRICTED_VARIABLES);
68  
69      public static String transform(
70              Map tokens, String languageId, String xml, String script)
71          throws TransformException {
72  
73          StringWriter output = new StringWriter();
74  
75          boolean load = false;
76  
77          try {
78              VelocityContext context = new VelocityContext();
79  
80              SAXReader reader = new SAXReader();
81  
82              Document doc = reader.read(new StringReader(xml));
83  
84              Element root = doc.getRootElement();
85  
86              List nodes = _extractDynamicContents(root);
87  
88              Iterator itr = nodes.iterator();
89  
90              while (itr.hasNext()) {
91                  TemplateNode node = (TemplateNode)itr.next();
92  
93                  context.put(node.getName(), node);
94              }
95  
96              context.put(
97                  "request", _insertRequestVariables(root.element("request")));
98  
99              long companyId = GetterUtil.getLong(
100                 (String)tokens.get("company_id"));
101             long groupId = GetterUtil.getLong((String)tokens.get("group_id"));
102             String journalTemplatesPath =
103                 VelocityResourceListener.JOURNAL_SEPARATOR + StringPool.SLASH +
104                     companyId + StringPool.SLASH + groupId;
105             String randomNamespace =
106                 PwdGenerator.getPassword(PwdGenerator.KEY3, 4) +
107                     StringPool.UNDERLINE;
108 
109             context.put("companyId", String.valueOf(companyId));
110             context.put("groupId", String.valueOf(groupId));
111             context.put("journalTemplatesPath", journalTemplatesPath);
112             context.put("randomNamespace", randomNamespace);
113 
114             VelocityVariables.insertHelperUtilities(
115                 context, _TEMPLATE_VELOCITY_RESTRICTED_VARIABLES);
116 
117             script = _injectEditInPlace(xml, script);
118 
119             load = Velocity.evaluate(
120                 context, output, JournalVmUtil.class.getName(), script);
121         }
122         catch (Exception e) {
123             if (e instanceof DocumentException) {
124                 throw new TransformException("Unable to read XML document", e);
125             }
126             else if (e instanceof VelocityException) {
127                 VelocityException pex = (VelocityException)e;
128 
129                 throw new TransformException(
130                     "Unable to parse velocity template: " +
131                         Html.escape(pex.getMessage()),
132                     e);
133             }
134             else if (e instanceof IOException) {
135                 throw new TransformException(
136                     "Error reading velocity template", e);
137             }
138             else if (e instanceof TransformException) {
139                 throw (TransformException)e;
140             }
141             else {
142                 throw new TransformException("Unhandled exception", e);
143             }
144         }
145 
146         if (!load) {
147             throw new TransformException(
148                 "Unable to dynamically load velocity transform script");
149         }
150 
151         return output.toString();
152     }
153 
154     private static List _extractDynamicContents(Element parent)
155         throws TransformException {
156 
157         List nodes = new ArrayList();
158 
159         Iterator itr1 = parent.elementIterator("dynamic-element");
160 
161         while (itr1.hasNext()) {
162             Element element = (Element)itr1.next();
163 
164             Element content = element.element("dynamic-content");
165 
166             if (content == null) {
167                 throw new TransformException(
168                     "Element missing \"dynamic-content\"");
169             }
170 
171             String name = element.attributeValue("name", "");
172 
173             if (name.length() == 0) {
174                 throw new TransformException(
175                     "Element missing \"name\" attribute");
176             }
177 
178             String type = element.attributeValue("type", "");
179 
180             TemplateNode node = new TemplateNode(
181                 name, CDATAUtil.strip(content.getText()), type);
182 
183             if (element.element("dynamic-element") != null) {
184                 node.appendChildren(_extractDynamicContents(element));
185             }
186             else if (content.element("option") != null) {
187                 Iterator itr2 = content.elementIterator("option");
188 
189                 while (itr2.hasNext()) {
190                     Element option = (Element)itr2.next();
191 
192                     node.appendOption(CDATAUtil.strip(option.getText()));
193                 }
194             }
195 
196             nodes.add(node);
197         }
198 
199         return nodes;
200     }
201 
202     private static String _injectEditInPlace(String xml, String script)
203         throws DocumentException {
204 
205         SAXReader reader = new SAXReader();
206 
207         Document doc = reader.read(new StringReader(xml));
208 
209         Iterator itr = doc.selectNodes("//dynamic-element").iterator();
210 
211         while (itr.hasNext()) {
212             Element el = (Element)itr.next();
213 
214             String name = GetterUtil.getString(el.attributeValue("name"));
215             String type = GetterUtil.getString(el.attributeValue("type"));
216 
217             if ((!name.startsWith("reserved-")) &&
218                 (type.equals("text") || type.equals("text_box") ||
219                  type.equals("text_area"))) {
220 
221                 script = _wrapField(script, name, type, "data");
222                 script = _wrapField(script, name, type, "getData()");
223             }
224         }
225 
226         return script;
227     }
228 
229     private static Map _insertRequestVariables(Element parent) {
230         Map map = new HashMap();
231 
232         if (parent == null) {
233             return map;
234         }
235 
236         Iterator itr1 = parent.elements().iterator();
237 
238         while (itr1.hasNext()) {
239             Element el = (Element)itr1.next();
240 
241             String name = el.getName();
242 
243             if (name.equals("attribute")) {
244                 map.put(el.elementText("name"), el.elementText("value"));
245             }
246             else if (name.equals("parameter")) {
247                 name = el.element("name").getText();
248 
249                 List valueEls = el.elements("value");
250 
251                 if (valueEls.size() == 1) {
252                     map.put(name, ((Element)valueEls.get(0)).getText());
253                 }
254                 else {
255                     List values = new ArrayList();
256 
257                     Iterator itr2 = valueEls.iterator();
258 
259                     while (itr2.hasNext()) {
260                         Element valueEl = (Element)itr2.next();
261 
262                         values.add(valueEl.getText());
263                     }
264 
265                     map.put(name, values);
266                 }
267             }
268             else if (el.elements().size() > 0) {
269                 map.put(name, _insertRequestVariables(el));
270             }
271             else {
272                 map.put(name, el.getText());
273             }
274         }
275 
276         return map;
277     }
278 
279     private static String _wrapField(
280         String script, String name, String type, String call) {
281 
282         String field = "$" + name + "." + call;
283         String wrappedField =
284             "<span class=\"journal-content-eip-" + type + "\" " +
285                 "id=\"journal-content-field-name-" + name + "\">" + field +
286                     "</span>";
287 
288         return StringUtil.replace(
289             script, "$editInPlace(" + field + ")", wrappedField);
290     }
291 
292 }