1   /**
2    * Copyright (c) 2000-2007 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.velocity.VelocityResourceListener;
29  import com.liferay.portal.velocity.VelocityVariables;
30  import com.liferay.portlet.journal.TransformException;
31  import com.liferay.util.Html;
32  import com.liferay.util.PwdGenerator;
33  import com.liferay.util.xml.CDATAUtil;
34  
35  import java.io.IOException;
36  import java.io.StringReader;
37  import java.io.StringWriter;
38  
39  import java.util.ArrayList;
40  import java.util.HashMap;
41  import java.util.Iterator;
42  import java.util.List;
43  import java.util.Map;
44  
45  import org.apache.velocity.VelocityContext;
46  import org.apache.velocity.app.Velocity;
47  import org.apache.velocity.exception.VelocityException;
48  
49  import org.dom4j.Document;
50  import org.dom4j.DocumentException;
51  import org.dom4j.Element;
52  import org.dom4j.io.SAXReader;
53  
54  /**
55   * <a href="JournalVmUtil.java.html"><b><i>View Source</i></b></a>
56   *
57   * @author Alexander Chow
58   * @author Brian Wing Shun Chan
59   * @author Raymond Augé
60   *
61   */
62  public class JournalVmUtil {
63  
64      public static String transform(
65              Map tokens, String languageId, String xml, String script)
66          throws TransformException {
67  
68          StringWriter output = new StringWriter();
69  
70          boolean load = false;
71  
72          try {
73              VelocityContext context = new VelocityContext();
74  
75              SAXReader reader = new SAXReader();
76  
77              Document doc = reader.read(new StringReader(xml));
78  
79              Element root = doc.getRootElement();
80  
81              List nodes = _extractDynamicContents(root);
82  
83              Iterator itr = nodes.iterator();
84  
85              while (itr.hasNext()) {
86                  TemplateNode node = (TemplateNode)itr.next();
87  
88                  context.put(node.getName(), node);
89              }
90  
91              context.put(
92                  "request", _insertRequestVariables(root.element("request")));
93  
94              long companyId = GetterUtil.getLong(
95                  (String)tokens.get("company_id"));
96              long groupId = GetterUtil.getLong((String)tokens.get("group_id"));
97              String journalTemplatesPath =
98                  VelocityResourceListener.JOURNAL_SEPARATOR + StringPool.SLASH +
99                      companyId + StringPool.SLASH + groupId;
100             String randomNamespace =
101                 PwdGenerator.getPassword(PwdGenerator.KEY3, 4) +
102                     StringPool.UNDERLINE;
103 
104             context.put("companyId", String.valueOf(companyId));
105             context.put("groupId", String.valueOf(groupId));
106             context.put("journalTemplatesPath", journalTemplatesPath);
107             context.put("randomNamespace", randomNamespace);
108 
109             VelocityVariables.insertHelperUtilities(context);
110 
111             script = _injectEditInPlace(xml, script);
112 
113             load = Velocity.evaluate(
114                 context, output, JournalVmUtil.class.getName(), script);
115         }
116         catch (Exception e) {
117             if (e instanceof DocumentException) {
118                 throw new TransformException("Unable to read XML document", e);
119             }
120             else if (e instanceof VelocityException) {
121                 VelocityException pex = (VelocityException)e;
122 
123                 throw new TransformException(
124                     "Unable to parse velocity template: " +
125                         Html.escape(pex.getMessage()),
126                     e);
127             }
128             else if (e instanceof IOException) {
129                 throw new TransformException(
130                     "Error reading velocity template", e);
131             }
132             else if (e instanceof TransformException) {
133                 throw (TransformException)e;
134             }
135             else {
136                 throw new TransformException("Unhandled exception", e);
137             }
138         }
139 
140         if (!load) {
141             throw new TransformException(
142                 "Unable to dynamically load velocity transform script");
143         }
144 
145         return output.toString();
146     }
147 
148     private static List _extractDynamicContents(Element parent)
149         throws TransformException {
150 
151         List nodes = new ArrayList();
152 
153         Iterator itr1 = parent.elementIterator("dynamic-element");
154 
155         while (itr1.hasNext()) {
156             Element element = (Element)itr1.next();
157 
158             Element content = element.element("dynamic-content");
159 
160             if (content == null) {
161                 throw new TransformException(
162                     "Element missing \"dynamic-content\"");
163             }
164 
165             String name = element.attributeValue("name", "");
166 
167             if (name.length() == 0) {
168                 throw new TransformException(
169                     "Element missing \"name\" attribute");
170             }
171 
172             String type = element.attributeValue("type", "");
173 
174             TemplateNode node = new TemplateNode(
175                 name, CDATAUtil.strip(content.getText()), type);
176 
177             if (element.element("dynamic-element") != null) {
178                 node.appendChildren(_extractDynamicContents(element));
179             }
180             else if (content.element("option") != null) {
181                 Iterator itr2 = content.elementIterator("option");
182 
183                 while (itr2.hasNext()) {
184                     Element option = (Element)itr2.next();
185 
186                     node.appendOption(CDATAUtil.strip(option.getText()));
187                 }
188             }
189 
190             nodes.add(node);
191         }
192 
193         return nodes;
194     }
195 
196     private static String _injectEditInPlace(String xml, String script)
197         throws DocumentException {
198 
199         SAXReader reader = new SAXReader();
200 
201         Document doc = reader.read(new StringReader(xml));
202 
203         Iterator itr = doc.selectNodes("//dynamic-element").iterator();
204 
205         while (itr.hasNext()) {
206             Element el = (Element)itr.next();
207 
208             String name = GetterUtil.getString(el.attributeValue("name"));
209             String type = GetterUtil.getString(el.attributeValue("type"));
210 
211             if ((!name.startsWith("reserved-")) &&
212                 (type.equals("text") || type.equals("text_box") ||
213                  type.equals("text_area"))) {
214 
215                 script = _wrapField(script, name, type, "data");
216                 script = _wrapField(script, name, type, "getData()");
217             }
218         }
219 
220         return script;
221     }
222 
223     private static Map _insertRequestVariables(Element parent) {
224         Map map = new HashMap();
225 
226         if (parent == null) {
227             return map;
228         }
229 
230         Iterator itr1 = parent.elements().iterator();
231 
232         while (itr1.hasNext()) {
233             Element el = (Element)itr1.next();
234 
235             String name = el.getName();
236 
237             if (name.equals("attribute")) {
238                 map.put(el.elementText("name"), el.elementText("value"));
239             }
240             else if (name.equals("parameter")) {
241                 name = el.element("name").getText();
242 
243                 List valueEls = el.elements("value");
244 
245                 if (valueEls.size() == 1) {
246                     map.put(name, ((Element)valueEls.get(0)).getText());
247                 }
248                 else {
249                     List values = new ArrayList();
250 
251                     Iterator itr2 = valueEls.iterator();
252 
253                     while (itr2.hasNext()) {
254                         Element valueEl = (Element)itr2.next();
255 
256                         values.add(valueEl.getText());
257                     }
258 
259                     map.put(name, values);
260                 }
261             }
262             else if (el.elements().size() > 0) {
263                 map.put(name, _insertRequestVariables(el));
264             }
265             else {
266                 map.put(name, el.getText());
267             }
268         }
269 
270         return map;
271     }
272 
273     private static String _wrapField(
274         String script, String name, String type, String call) {
275 
276         String field = "$" + name + "." + call;
277         String wrappedField =
278             "<span class=\"journal-content-eip-" + type + "\" " +
279                 "id=\"journal-content-field-name-" + name + "\">" + field +
280                     "</span>";
281 
282         return StringUtil.replace(
283             script, "$editInPlace(" + field + ")", wrappedField);
284     }
285 
286 }