1   /**
2    * Copyright (c) 2000-2009 Liferay, Inc. All rights reserved.
3    *
4    * The contents of this file are subject to the terms of the Liferay Enterprise
5    * Subscription License ("License"). You may not use this file except in
6    * compliance with the License. You can obtain a copy of the License by
7    * contacting Liferay, Inc. See the License for the specific language governing
8    * permissions and limitations under the License, including but not limited to
9    * distribution rights of the Software.
10   *
11   * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
12   * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
13   * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
14   * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
15   * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
16   * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
17   * SOFTWARE.
18   */
19  
20  package com.liferay.portlet.journal.util;
21  
22  import com.liferay.portal.kernel.util.GetterUtil;
23  import com.liferay.portal.kernel.util.HtmlUtil;
24  import com.liferay.portal.kernel.util.LocaleUtil;
25  import com.liferay.portal.kernel.util.StringPool;
26  import com.liferay.portal.kernel.util.StringUtil;
27  import com.liferay.portal.kernel.velocity.VelocityContext;
28  import com.liferay.portal.kernel.velocity.VelocityEngineUtil;
29  import com.liferay.portal.kernel.xml.Document;
30  import com.liferay.portal.kernel.xml.DocumentException;
31  import com.liferay.portal.kernel.xml.Element;
32  import com.liferay.portal.kernel.xml.Node;
33  import com.liferay.portal.kernel.xml.SAXReaderUtil;
34  import com.liferay.portal.model.Company;
35  import com.liferay.portal.security.permission.PermissionThreadLocal;
36  import com.liferay.portal.service.CompanyLocalServiceUtil;
37  import com.liferay.portal.util.ContentUtil;
38  import com.liferay.portal.util.PropsValues;
39  import com.liferay.portal.velocity.VelocityResourceListener;
40  import com.liferay.portlet.journal.TransformException;
41  import com.liferay.util.PwdGenerator;
42  import com.liferay.util.xml.CDATAUtil;
43  
44  import java.io.IOException;
45  import java.io.StringWriter;
46  
47  import java.util.ArrayList;
48  import java.util.HashMap;
49  import java.util.List;
50  import java.util.Map;
51  
52  import org.apache.velocity.exception.ParseErrorException;
53  import org.apache.velocity.exception.VelocityException;
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 List<TemplateNode> extractDynamicContents(Element parent)
66          throws TransformException {
67  
68          List<TemplateNode> nodes = new ArrayList<TemplateNode>();
69  
70          for (Element el : parent.elements("dynamic-element")) {
71              Element content = el.element("dynamic-content");
72  
73              if (content == null) {
74                  throw new TransformException(
75                      "Element missing \"dynamic-content\"");
76              }
77  
78              String name = el.attributeValue("name", "");
79  
80              if (name.length() == 0) {
81                  throw new TransformException(
82                      "Element missing \"name\" attribute");
83              }
84  
85              String type = el.attributeValue("type", "");
86  
87              TemplateNode node = new TemplateNode(
88                  name, CDATAUtil.strip(content.getText()), type);
89  
90              if (el.element("dynamic-element") != null) {
91                  node.appendChildren(extractDynamicContents(el));
92              }
93              else if (content.element("option") != null) {
94                  for (Element option : content.elements("option")) {
95                      node.appendOption(CDATAUtil.strip(option.getText()));
96                  }
97              }
98  
99              nodes.add(node);
100         }
101 
102         return nodes;
103     }
104 
105     public static String transform(
106             Map<String, String> tokens, String languageId, String xml,
107             String script)
108         throws TransformException {
109 
110         StringWriter output = new StringWriter();
111 
112         boolean load = false;
113 
114         try {
115             VelocityContext velocityContext =
116                 VelocityEngineUtil.getWrappedRestrictedToolsContext();
117 
118             Document doc = SAXReaderUtil.read(xml);
119 
120             Element root = doc.getRootElement();
121 
122             List<TemplateNode> nodes = extractDynamicContents(root);
123 
124             for (TemplateNode node : nodes) {
125                 velocityContext.put(node.getName(), node);
126             }
127 
128             velocityContext.put("xmlRequest", root.element("request").asXML());
129             velocityContext.put(
130                 "request", insertRequestVariables(root.element("request")));
131 
132             long companyId = GetterUtil.getLong(tokens.get("company_id"));
133             Company company = CompanyLocalServiceUtil.getCompanyById(companyId);
134             long groupId = GetterUtil.getLong(tokens.get("group_id"));
135             String templateId = tokens.get("template_id");
136             String journalTemplatesPath =
137                 VelocityResourceListener.JOURNAL_SEPARATOR + StringPool.SLASH +
138                     companyId + StringPool.SLASH + groupId;
139             String randomNamespace =
140                 PwdGenerator.getPassword(PwdGenerator.KEY3, 4) +
141                     StringPool.UNDERLINE;
142 
143             velocityContext.put("company", company);
144             velocityContext.put("companyId", String.valueOf(companyId));
145             velocityContext.put("groupId", String.valueOf(groupId));
146             velocityContext.put("journalTemplatesPath", journalTemplatesPath);
147             velocityContext.put(
148                 "locale", LocaleUtil.fromLanguageId(languageId));
149             velocityContext.put(
150                 "permissionChecker",
151                 PermissionThreadLocal.getPermissionChecker());
152             velocityContext.put("randomNamespace", randomNamespace);
153 
154             script = injectEditInPlace(xml, script);
155 
156             try {
157                 String velocityTemplateId = companyId + groupId + templateId;
158 
159                 load = VelocityEngineUtil.mergeTemplate(
160                     velocityTemplateId, script, velocityContext, output);
161             }
162             catch (VelocityException ve) {
163                 velocityContext.put("exception", ve.getMessage());
164                 velocityContext.put("script", script);
165 
166                 if (ve instanceof ParseErrorException) {
167                     ParseErrorException pe = (ParseErrorException)ve;
168 
169                     velocityContext.put(
170                         "column", new Integer(pe.getColumnNumber()));
171                     velocityContext.put(
172                         "line", new Integer(pe.getLineNumber()));
173                 }
174 
175                 String velocityTemplateId =
176                     PropsValues.JOURNAL_ERROR_TEMPLATE_VELOCITY;
177                 String velocityTemplateContent = ContentUtil.get(
178                     PropsValues.JOURNAL_ERROR_TEMPLATE_VELOCITY);
179 
180                 load = VelocityEngineUtil.mergeTemplate(
181                     velocityTemplateId, velocityTemplateContent,
182                     velocityContext, output);
183             }
184         }
185         catch (Exception e) {
186             if (e instanceof DocumentException) {
187                 throw new TransformException("Unable to read XML document", e);
188             }
189             else if (e instanceof VelocityException) {
190                 VelocityException pex = (VelocityException)e;
191 
192                 throw new TransformException(
193                     "Unable to parse velocity template: " +
194                         HtmlUtil.escape(pex.getMessage()),
195                     e);
196             }
197             else if (e instanceof IOException) {
198                 throw new TransformException(
199                     "Error reading velocity template", e);
200             }
201             else if (e instanceof TransformException) {
202                 throw (TransformException)e;
203             }
204             else {
205                 throw new TransformException("Unhandled exception", e);
206             }
207         }
208 
209         if (!load) {
210             throw new TransformException(
211                 "Unable to dynamically load velocity transform script");
212         }
213 
214         return output.toString();
215     }
216 
217     protected static String injectEditInPlace(String xml, String script)
218         throws DocumentException {
219 
220         Document doc = SAXReaderUtil.read(xml);
221 
222         List<Node> nodes = doc.selectNodes("//dynamic-element");
223 
224         for (Node node : nodes) {
225             Element el = (Element)node;
226 
227             String name = GetterUtil.getString(el.attributeValue("name"));
228             String type = GetterUtil.getString(el.attributeValue("type"));
229 
230             if ((!name.startsWith("reserved-")) &&
231                 (type.equals("text") || type.equals("text_box") ||
232                  type.equals("text_area"))) {
233 
234                 script = wrapField(script, name, type, "data");
235                 script = wrapField(script, name, type, "getData()");
236             }
237         }
238 
239         return script;
240     }
241 
242     protected static Map<String, Object> insertRequestVariables(
243         Element parent) {
244 
245         Map<String, Object> map = new HashMap<String, Object>();
246 
247         if (parent == null) {
248             return map;
249         }
250 
251         for (Element el : parent.elements()) {
252             String name = el.getName();
253 
254             if (name.equals("attribute")) {
255                 map.put(el.elementText("name"), el.elementText("value"));
256             }
257             else if (name.equals("parameter")) {
258                 name = el.element("name").getText();
259 
260                 List<Element> valueEls = el.elements("value");
261 
262                 if (valueEls.size() == 1) {
263                     map.put(name, (valueEls.get(0)).getText());
264                 }
265                 else {
266                     List<String> values = new ArrayList<String>();
267 
268                     for (Element valueEl : valueEls) {
269                         values.add(valueEl.getText());
270                     }
271 
272                     map.put(name, values);
273                 }
274             }
275             else if (el.elements().size() > 0) {
276                 map.put(name, insertRequestVariables(el));
277             }
278             else {
279                 map.put(name, el.getText());
280             }
281         }
282 
283         return map;
284     }
285 
286     protected static String wrapField(
287         String script, String name, String type, String call) {
288 
289         String field = "$" + name + "." + call;
290         String wrappedField =
291             "<span class=\"journal-content-eip-" + type + "\" " +
292                 "id=\"journal-content-field-name-" + name + "\">" + field +
293                     "</span>";
294 
295         return StringUtil.replace(
296             script, "$editInPlace(" + field + ")", wrappedField);
297     }
298 
299 }