View Javadoc

1   /**
2    * This file Copyright (c) 2003-2011 Magnolia International
3    * Ltd.  (http://www.magnolia-cms.com). All rights reserved.
4    *
5    *
6    * This file is dual-licensed under both the Magnolia
7    * Network Agreement and the GNU General Public License.
8    * You may elect to use one or the other of these licenses.
9    *
10   * This file is distributed in the hope that it will be
11   * useful, but AS-IS and WITHOUT ANY WARRANTY; without even the
12   * implied warranty of MERCHANTABILITY or FITNESS FOR A
13   * PARTICULAR PURPOSE, TITLE, or NONINFRINGEMENT.
14   * Redistribution, except as permitted by whichever of the GPL
15   * or MNA you select, is prohibited.
16   *
17   * 1. For the GPL license (GPL), you can redistribute and/or
18   * modify this file under the terms of the GNU General
19   * Public License, Version 3, as published by the Free Software
20   * Foundation.  You should have received a copy of the GNU
21   * General Public License, Version 3 along with this program;
22   * if not, write to the Free Software Foundation, Inc., 51
23   * Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
24   *
25   * 2. For the Magnolia Network Agreement (MNA), this file
26   * and the accompanying materials are made available under the
27   * terms of the MNA which accompanies this distribution, and
28   * is available at http://www.magnolia-cms.com/mna.html
29   *
30   * Any modifications to this file must keep this entire header
31   * intact.
32   *
33   */
34  package info.magnolia.cms.gui.dialog;
35  
36  import freemarker.template.TemplateException;
37  import info.magnolia.cms.core.Content;
38  import info.magnolia.cms.core.ItemType;
39  import info.magnolia.cms.core.NodeData;
40  import info.magnolia.cms.gui.control.ControlImpl;
41  import info.magnolia.cms.gui.control.FreemarkerControl;
42  import info.magnolia.cms.security.AccessDeniedException;
43  import info.magnolia.cms.util.NodeDataUtil;
44  
45  import java.io.IOException;
46  import java.io.Writer;
47  import java.util.ArrayList;
48  import java.util.Collection;
49  import java.util.HashMap;
50  import java.util.Iterator;
51  import java.util.LinkedHashMap;
52  import java.util.List;
53  import java.util.Map;
54  
55  import javax.jcr.PathNotFoundException;
56  import javax.jcr.PropertyType;
57  import javax.jcr.RepositoryException;
58  import javax.servlet.http.HttpServletRequest;
59  import javax.servlet.http.HttpServletResponse;
60  
61  import org.apache.commons.lang.StringUtils;
62  import org.apache.commons.lang.exception.NestableRuntimeException;
63  import org.slf4j.Logger;
64  import org.slf4j.LoggerFactory;
65  
66  
67  /**
68   * A Magnolia dialog that renders by a freemarker template. There are two main properties for the dialog:<br/>
69   * <table>
70   * <tr>
71   * <td>path (required)</td>
72   * <td>Path to freemarker template: will be loaded from classpath or from filesystem</td>
73   * </tr>
74   * <tr>
75   * <td>multiple</td>
76   * <td>true / false. This property gives support to multiple field values storage.</td>
77   * </tr>
78   * </table>
79   * The dialog passes some parameters to freemarker template:
80   * <table>
81   * <tr>
82   * <td>name</td>
83   * <td>Dialog / field name</td>
84   * </tr>
85   * <tr>
86   * <td>value</td>
87   * <td>Field value (multiple = false)</td>
88   * </tr>
89   * <tr>
90   * <td>values</td>
91   * <td>field values (multiple = true)</td>
92   * </tr>
93   * <tr>
94   * <td>request</td>
95   * <td>current HttpServletRequest</td>
96   * </tr>
97   * <tr>
98   * <td>configuration</td>
99   * <td>Map of dialog configuration. This allows to pass to template complex dialog configuration.<br/> Eg.
100  *
101  * <pre>
102  * -+ Dialog node
103  *  |-- property 1 = value 1
104  *  |-+ subnode1
105  *  | |-- property 11 = value 11
106  *  | |-- property 12 = value 12
107  *  | |-+ subnode 11
108  *  |   |-- property 111 = value 111
109  *  |
110  *  |-- property 2 = value 2
111  *
112  * The map will contain:
113  * configuration = Map {
114  *    "property1" = "value1",
115  *    "subnode1"  = Map {
116  *        "property11" = "value11",
117  *        "property12" = "value12",
118  *        "subnode11"  =  Map {
119  *            "property111" = "value111"
120  *        }
121  *    },
122  *    "property2" = "value2"
123  * }
124  * </pre>
125  * </td>
126  * </tr>
127  * </table>
128  * @author Manuel Molaschi
129  * @version $Id: $
130  */
131 
132 public class DialogFreemarker extends DialogBox {
133 
134     /**
135      * Logger.
136      */
137     private static Logger log = LoggerFactory.getLogger(DialogFreemarker.class);
138 
139     private Map configuration;
140 
141     private String path;
142 
143     /**
144      * Sets the path.
145      * @param path the path to set
146      */
147     public void setPath(String path) {
148         this.path = path;
149     }
150 
151     /**
152      * Returns the configuration.
153      * @return the configuration
154      */
155     public Map getConfiguration() {
156         return configuration;
157     }
158 
159     /**
160      * Returns the path.
161      * @return the path
162      */
163     public String getPath() {
164         return path;
165     }
166 
167     /**
168      * {@inheritDoc}
169      */
170     protected List readValues() {
171 
172         List values = new ArrayList();
173 
174         if (this.getStorageNode() != null) {
175             try {
176                 // cycles on website content node to get multiple value
177                 int size = this.getStorageNode().getContent(this.getName()).getNodeDataCollection().size();
178                 for (int i = 0; i < size; i++) {
179                     NodeData data = this.getStorageNode().getContent(this.getName()).getNodeData("" + i);
180                     values.add(data.getString());
181                 }
182             }
183             catch (PathNotFoundException e) {
184                 // not yet existing: OK
185             }
186             catch (RepositoryException re) {
187                 log.error("can't set values", re);
188             }
189         }
190         return values;
191     }
192 
193     /**
194      * Get a recursive map view of a content node
195      * @param node content node
196      * @return recursive map view on content node properties and children
197      * @throws PathNotFoundException
198      * @throws RepositoryException
199      * @throws AccessDeniedException
200      */
201     protected Map getSubNodes(Content node) throws RepositoryException, AccessDeniedException {
202 
203         Map values = new LinkedHashMap();
204 
205         // cycles on properties and stores them in map
206         Collection properties = node.getNodeDataCollection();
207 
208         if (properties != null && properties.size() > 0) {
209             Iterator propertiesIt = properties.iterator();
210             while (propertiesIt.hasNext()) {
211                 NodeData property = (NodeData) propertiesIt.next();
212                 values.put(property.getName(), NodeDataUtil.getValueObject(property));
213             }
214         }
215 
216         // cycle on children
217         Collection children = node.getChildren(ItemType.CONTENTNODE);
218         if (children != null && children.size() > 0) {
219             Iterator childrenIt = children.iterator();
220             while (childrenIt.hasNext()) {
221                 Content child = (Content) childrenIt.next();
222 
223                 // gets sub map
224                 Map subValues = getSubNodes(child);
225                 // stores it in map
226                 values.put(child.getName(), subValues);
227             }
228         }
229 
230         return values;
231     }
232 
233     /**
234      * {@inheritDoc}
235      */
236 
237     public void init(HttpServletRequest request, HttpServletResponse response, Content websiteNode, Content configNode)
238         throws RepositoryException {
239         super.init(request, response, websiteNode, configNode);
240         configuration = this.getSubNodes(configNode);
241     }
242 
243     /**
244      * {@inheritDoc}
245      */
246     public void drawHtml(Writer out) throws IOException {
247         String ftlPath = StringUtils.defaultIfEmpty(this.getConfigValue("path"), path);
248         drawHtml(out, ftlPath);
249     }
250 
251     /**
252      * @param out Writer
253      * @param freemarkerTemplate path for the freemarker template
254      * @throws IOException
255      */
256     protected void drawHtml(Writer out, String freemarkerTemplate) throws IOException {
257         Map parameters = new HashMap();
258         parameters.put("name", this.getName());
259         parameters.put("value", this.getValue());
260         parameters.put("values", this.getValues());
261         parameters.put("request", this.getRequest());
262         parameters.put("configuration", this.configuration);
263 
264         this.drawHtmlPre(out);
265 
266         try {
267             FreemarkerControl control = new FreemarkerControl("multiple".equals(this.getConfigValue("valueType"))
268                 ? ControlImpl.VALUETYPE_MULTIPLE
269                 : ControlImpl.VALUETYPE_SINGLE);
270             control.setType(this.getConfigValue("type", PropertyType.TYPENAME_STRING));
271             control.setName(this.getName());
272             control.drawHtml(out, freemarkerTemplate, parameters);
273         }
274 
275         catch (TemplateException ex) {
276             log.error("Error processing dialog template:", ex);
277             throw new NestableRuntimeException(ex);
278         }
279 
280         this.drawHtmlPost(out);
281     }
282 
283 }