Clover icon

magnolia-module-groovy 2.4.2

  1. Project Clover database Thu Jan 14 2016 16:38:54 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
395
251
62
0.48
6.74
19
3.26

Classes

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