Clover icon

magnolia-module-groovy 2.4.7

  1. Project Clover database Thu Dec 1 2016 10:48:40 CET
  2. Package info.magnolia.module.groovy.support.nodes

File MgnlGroovyNode.java

 

Coverage histogram

../../../../../../img/srcFileCovDistChart4.png
37% of files have more coverage

Code metrics

52
128
19
1
401
251
62
0.48
6.74
19
3.26

Classes

Class Line # Actions
MgnlGroovyNode 122 128 0% 62 130
0.3467336634.7%
 

Contributing tests

This file is covered by 6 tests. .

Source view

1    /**
2    * This file Copyright (c) 2003-2016 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.module.groovy.support.nodes;
35   
36    import groovy.lang.DelegatingMetaClass;
37    import groovy.lang.GroovySystem;
38    import groovy.lang.MetaClass;
39   
40    import info.magnolia.cms.core.Content;
41    import info.magnolia.cms.core.ItemType;
42    import info.magnolia.cms.core.MgnlNodeType;
43    import info.magnolia.cms.core.NodeData;
44    import info.magnolia.cms.security.AccessDeniedException;
45    import info.magnolia.cms.util.ContentWrapper;
46    import info.magnolia.jcr.RuntimeRepositoryException;
47   
48    import java.math.BigDecimal;
49    import java.util.Collection;
50    import java.util.Iterator;
51   
52    import javax.jcr.PathNotFoundException;
53    import javax.jcr.PropertyType;
54    import javax.jcr.RepositoryException;
55    import javax.jcr.Value;
56    import javax.jcr.ValueFormatException;
57   
58    import org.apache.commons.collections.IteratorUtils;
59    import org.apache.commons.lang.StringUtils;
60    import org.slf4j.Logger;
61    import org.slf4j.LoggerFactory;
62   
63    /**
64    * A special <em>groovish</em> implementation of Magnolia's {@link ContentWrapper}.
65    * This makes it possible, for example, navigating the nodes in a Magnolia repository
66    * with a <code>. (dot)</code> notation and access their properties with <code>.</code> or <code>.@</code> notation
67    * much like it happens when using the result of parsing an xml with groovy's {@link groovy.util.XmlSlurper#XmlSlurper}.
68    * For example, here is how, in a groovy
69    * script, one could navigate to and print the node data named <em>abstract</em>:
70    *
71    * <pre>
72    * hm = ctx.getHierarchyManager('website')
73    * node = hm.getContent(hm, '/demo-project')
74    * println node.about.history.abstract
75    * </pre>
76    *
77    * The above example can also be made more groovy-like by using the <code>@</code> notation to access the attribute
78    *
79    * <pre>
80    * node.about.history.@abstract
81    * </pre>
82    *
83    * As <code>node</code> is also a {@link Content}, you can call any of its
84    * methods. E.g.
85    *
86    * <pre>
87    * println node.metaData.template
88    * println node.about.children.title
89    * println node.about.parent <strong>(this can return null)</strong>
90    * </pre>
91    *
92    * <strong>IMPORTANT:</strong> The <code>.children</code> shortcut, unlikely {@link Content#getChildren()},
93    * <strong>always returns {@link ItemType#CONTENT}s AND {@link ItemType#CONTENTNODE}s </strong>.
94    * If you only need either type, then call directly one of the {@link Content#getChildren()} methods on the parent
95    * node. <br/>
96    * <br/>
97    * If you want to look at the <i>attributes</i> or <i>data</i> for a certain node you can simply call
98    *
99    * <pre>
100    * println node.about.nodeData
101    * </pre>
102    *
103    * It is also possible to assign values to node data or create new ones. E.g.
104    *
105    * <pre>
106    * node.boo = 3.14d
107    * node.coo = true
108    * node.foo = 'some text'
109    * node.doo = 100
110    * </pre>
111    *
112    * will assign the values on the right hand side to the node data on left hand side. Should those not exist, they will
113    * be automatically created. Furthermore, the correct type will be detected based on the value assigned (i.e. Boolean,
114    * String, Long or Double). <br/>
115    * <br/>
116    * <strong>IMPORTANT:</strong> All the above assignments will be in-memory only unless explicitly persisted via a call
117    * to <code>save()</code> on a parent node.
118    *
119    * @deprecated since 2.2, please use {@link MgnlGroovyJCRNode}.
120    */
121    @Deprecated
 
122    public class MgnlGroovyNode extends ContentWrapper {
123   
 
124  1 toggle static {
125    // wrap the standard MetaClass with the delegate
126  1 setMetaClass(GroovySystem.getMetaClassRegistry().getMetaClass(MgnlGroovyNode.class), MgnlGroovyNode.class);
127    }
128   
129    protected static final Logger log = LoggerFactory.getLogger(MgnlGroovyNode.class);
130   
131    private String name;
132   
 
133  16 toggle public MgnlGroovyNode(Content content) {
134  16 super(content);
135  16 this.name = content.getName();
136    }
137   
 
138  1 toggle protected static void setMetaClass(final MetaClass metaClass, Class nodeClass) {
139  1 final MetaClass newMetaClass = new DelegatingMetaClass(metaClass) {
140   
 
141  0 toggle @Override
142    public Object getAttribute(final Object object, final String attribute) {
143  0 MgnlGroovyNode n = (MgnlGroovyNode) object;
144  0 return n.get("@" + attribute);
145    }
146   
 
147  0 toggle @Override
148    public void setAttribute(final Object object, final String attribute, final Object newValue) {
149  0 MgnlGroovyNode n = (MgnlGroovyNode) object;
150  0 try {
151  0 n.setNodeData(attribute, newValue);
152    }
153    catch (AccessDeniedException e) {
154  0 log.error(e.getMessage());
155    }
156    catch (PathNotFoundException e) {
157  0 log.error(e.getMessage());
158    }
159    catch (RepositoryException e) {
160  0 log.error(e.getMessage());
161    }
162    }
163   
 
164  0 toggle @Override
165    public Object getProperty(Object object, String property) {
166  0 if (object instanceof MgnlGroovyNode) {
167  0 MgnlGroovyNode n = (MgnlGroovyNode) object;
168  0 return n.get(property);
169    }
170  0 return super.getProperty(object, property);
171    }
172   
 
173  0 toggle @Override
174    public void setProperty(Object object, String property, Object newValue) {
175  0 String attribute = null;
176  0 if (property.startsWith("@")) {
177  0 attribute = property.substring(1);
178    } else {
179  0 attribute = property;
180    }
181  0 MgnlGroovyNode n = (MgnlGroovyNode) object;
182  0 try {
183    // else you get java.lang.ClassCastException: java.lang.Integer cannot be cast to java.lang.Long
184  0 if (newValue instanceof Integer) {
185  0 newValue = ((Integer) newValue).longValue();
186    }
187  0 n.setNodeData(attribute, newValue);
188    }
189    catch (AccessDeniedException e) {
190  0 log.error(e.getMessage());
191    }
192    catch (PathNotFoundException e) {
193  0 log.error(e.getMessage());
194    }
195    catch (RepositoryException e) {
196  0 log.error(e.getMessage());
197    }
198    }
199    };
200  1 GroovySystem.getMetaClassRegistry().setMetaClass(nodeClass, newMetaClass);
201    }
202   
 
203  2 toggle public Iterator<Content> iterator() {
204  2 return getChainedChildrenIterator();
205    }
206   
 
207  0 toggle public String name() {
208  0 return name;
209    }
210   
211    /**
212    * Provides lookup of elements by non-namespaced name.
213    *
214    * @param key the name (or shortcut key) of the node(s) of interest
215    * @return the nodes which match key
216    */
 
217  8 toggle public Object get(String key) {
218  8 if (key != null && key.charAt(0) == '@') {
219  3 String attributeName = key.substring(1);
220  3 return getNodeDataValue(attributeName);
221    }
222  5 if ("parent".equals(key)) {
223  0 try {
224  0 return getParent();
225    } catch (RepositoryException e) {
226  0 return null;
227    }
228    }
229  5 if ("children".equals(key)) {
230  2 Collection<Content> retVal = getChildren();
231  2 if (!isContentNodeType()) {
232  0 retVal.addAll(getChildren(MgnlNodeType.NT_CONTENTNODE));
233    }
234  2 return retVal;
235    }
236  3 if ("metaData".equals(key)) {
237  0 return getMetaData();
238    }
239  3 if ("nodeData".equals(key)) {
240  0 return getNodeDataCollection();
241    }
242  3 if ("name".equals(key)) {
243  1 return name;
244    }
245  2 Content retVal = getByName(key);
246  2 if (retVal != null) {
247  0 return retVal;
248    }
249    // last attempt: lets assume the client requested for an attribute without the @ notation
250  2 return getNodeDataValue(key);
251    }
252   
 
253  10 toggle @Override
254    protected Content wrap(Content node) {
255  10 return new MgnlGroovyNode(node);
256    }
257   
258    /**
259    * Returns the value for the given attribute (nodeData).
260    * The Java types returned vary according to the underlying {@link PropertyType}.
261    * <ul>
262    * <li> {@link PropertyType#STRING} returns a {@link String}
263    * <li> {@link PropertyType#DATE} returns a {@link java.util.Calendar}
264    * <li> {@link PropertyType#DOUBLE} returns a {@link BigDecimal}
265    * <li> {@link PropertyType#LONG} returns a {@link BigDecimal}
266    * <li> {@link PropertyType#BINARY} returns the {@link info.magnolia.cms.core.BinaryNodeData} value.
267    * <li>All other property types will be returned as {@link String}(s)
268    * </ul>
269    */
 
270  5 toggle protected Object getNodeDataValue(String attributeName) {
271  5 Collection<NodeData> data = getNodeDataCollection(attributeName);
272  5 Iterator<NodeData> it = data.iterator();
273  5 if (!it.hasNext()) {
274  0 return null;
275    }
276  5 NodeData nodeData = it.next();
277  5 Value propertyValue = nodeData.getValue();
278  5 Object value = null;
279  5 if (propertyValue != null) {
280  5 try {
281  5 switch (propertyValue.getType()) {
282  3 case PropertyType.STRING:
283  3 value = propertyValue.getString();
284  3 break;
285  0 case PropertyType.BINARY:
286  0 value = propertyValue;
287  0 break;
288  0 case PropertyType.DATE:
289  0 value = propertyValue.getDate();
290  0 break;
291  0 case PropertyType.DOUBLE:
292  0 value = BigDecimal.valueOf(propertyValue.getDouble());
293  0 break;
294  2 case PropertyType.LONG:
295  2 value = BigDecimal.valueOf(propertyValue.getLong());
296  2 break;
297  0 default:
298  0 value = propertyValue.getString();
299    }
300    } catch (ValueFormatException e) {
301  0 log.warn(e.getMessage());
302    } catch (IllegalStateException e) {
303  0 log.warn(e.getMessage());
304    } catch (RepositoryException e) {
305  0 log.warn(e.getMessage());
306    }
307    }
308  5 return value;
309    }
310   
311    /**
312    * Provides lookup of elements by name.
313    *
314    * @param name the name of interest
315    * @return the nodes matching name
316    */
 
317  2 toggle protected Content getByName(String name) {
318  2 for (Iterator<Content> iter = getChainedChildrenIterator(); iter.hasNext();) {
319  0 Content childNode = iter.next();
320  0 String childNodeName = childNode.getName();
321  0 if (name.equals(childNodeName)) {
322  0 return childNode;
323    }
324    }
325  2 return null;
326    }
327   
 
328  0 toggle @Override
329    public String toString() {
330  0 StringBuilder retVal = new StringBuilder();
331  0 Iterator<Content> iterator = getChainedChildrenIterator();
332  0 retVal.append("(+) " + name + "\n");
333  0 while (iterator.hasNext()) {
334  0 Content c = iterator.next();
335  0 if (hasMoreChildren(c)) {
336  0 retVal.append("\t(+) ");
337    } else {
338  0 retVal.append("\t(-) ");
339    }
340  0 retVal.append(c.getName() + "\n");
341    }
342   
343  0 if (!getNodeDataCollection().isEmpty()) {
344  0 for (NodeData nodeData : getNodeDataCollection()) {
345  0 retVal.append("\t\t* " + nodeData.getName() + ": ["
346    + StringUtils.abbreviate(nodeData.getString(), 80)
347    + "]\n");
348    }
349   
350    }
351   
352  0 return retVal.toString();
353    }
354   
 
355  4 toggle @SuppressWarnings("unchecked")
356    private Iterator<Content> getChainedChildrenIterator() {
357  4 if (isContentNodeType()) {
358  4 return getChildren().iterator();
359    }
360  0 return IteratorUtils.chainedIterator(getChildren().iterator(), getChildren(ItemType.CONTENTNODE).iterator());
361    }
362   
 
363  0 toggle private boolean hasMoreChildren(Content c) {
364  0 return c.hasChildren() || c.hasChildren(ItemType.CONTENTNODE.getSystemName());
365    }
366   
 
367  0 toggle @Override
368    public int hashCode() {
369  0 final int prime = 31;
370  0 int result = 1;
371  0 result = prime * result + ((name == null) ? 0 : name.hashCode());
372  0 return result;
373    }
374   
 
375  0 toggle @Override
376    public boolean equals(Object obj) {
377  0 if (this == obj)
378  0 return true;
379  0 if (obj == null)
380  0 return false;
381  0 if (getClass() != obj.getClass())
382  0 return false;
383  0 MgnlGroovyNode other = (MgnlGroovyNode) obj;
384  0 if (name == null) {
385  0 if (other.name != null)
386  0 return false;
387  0 } else if (!getHandle().equals(other.getHandle()))
388  0 return false;
389  0 return true;
390    }
391   
 
392  6 toggle private boolean isContentNodeType() {
393  6 try {
394  6 return MgnlNodeType.NT_CONTENTNODE.equals(getItemType().getSystemName());
395   
396    } catch (RepositoryException e) {
397  0 throw new RuntimeRepositoryException(e);
398    }
399    }
400   
401    }